原创作者: 蒋鑫   阅读:7694次   评论:1条   更新时间:2011-06-30    

书名:Git权威指南
ISBN:9787111349679
作者:蒋鑫
定价:89.00元
出版时间:2011年7月
出版社:机械工业出版社

 

内容简介  

      《Git权威指南》是Git领域的集大成之作,是一本关于Git的百科全书,在广度、深度和实战性上让同类作品望尘莫及。作者是国内顶尖的版本控制专家和咨询顾问之一,本书得到了Git官方维护者Junio C Hamano和ITeye创始人范凯(Robbin)先生等数位专家的高度认可和极力推荐,权威性毋庸置疑。

       全书一共9篇,共41章和4个附录,内容几乎涵盖了Git的所有方面。第1篇介绍了版本控制工具的演变历史、Git的各种优点,以及它在3种主流操作系统中的安装与配置。第2篇和第3篇既是本书的基础,又是本书的核心,不仅介绍了Git的操作和使用,而且还讲解了Git的原理。第2篇详细讲解了个人用户如何使用Git,包括Git初始化、日常操作、暂存区、对象、重置、检出、恢复进度、历史变更、克隆、库管理等;第3篇详细讲解了Git协议和团队如何使用Git,包括Git支持的协议、冲突解决、里程碑、分支、远程版本库和补丁文件交互等。第4篇全面介绍了Git的协同模型,即它在实际工作中的使用模式,包括各种经典的Git协同模型、Topgit协同模型、子模组协同模型、子树合并、Android多版本库协同、Git与SVN协同模型等。第5篇介绍了Git服务器的架设,首先讲解了HTTP协议、Git协议、SSH协议的使用,然后讲解了Gitolite、Gitosis、Gerrit等服务器的架设方法,最后还讲解了Git版本库的托管。第6篇介绍了版本库的迁移,包括如何从CVS、SVN、Hg等版本库迁移到Git,以及Git版本库整理等方面的内容。第7篇讲解了Git的其他应用,包括etckeeper、Gistore等的安装、配置和使用,以及补丁中的二进制文件和云存储等内容。第8篇介绍了Git的跨平台操作,以及它的钩子和模板、稀疏检出和浅克隆、嫁接和替换等重要特性。第9篇是附录,详细给出了Git的命令索引,以及CVS、SVN和Hg与Git的比较与命令对照,方便读者查阅。  

 

作者简介

        蒋鑫,国内顶尖的版本控制专家和咨询顾问之一,对Subversion和Git等版本控制工具有十分深入的研究,参与了Git以及Gitosis、Gitolite、Repo、Topgit、Gistore等与Git相关的开源软件的开发或创建,在大量实践中积累了丰富的经验。此外,他还是一位开源软件实践者,作为北京群英汇信息技术有限公司的创始人兼高级顾问,一直从事开源软件的定制以及面向研发团队的项目管理软件的推广和顾问咨询工作,致力于推动开源软件在中国的发展。

 

专家推荐:

       2009年9月,我出版了一本针对日本读者的Git专著,当Linus收到我赠送的签名本时,他对我说:“除了截图和命令行示例外,其他我什么也看不懂”(Linus不懂日文)。因为同样的原因,虽然我不能了解蒋鑫这本书的全部内容,但是我可以看出这本书涵盖了非常广泛的主题,并且可以看出蒋鑫对这本书的用心。我非常高兴能够看到这本书的出版,感谢向世界传播Git。——Junio C Hamano  Git维护者(2005年7月至今)

 

       仔细拜读了本书前三篇共20章的内容,感觉这本书极好。作者在软件版本控制系统方面有超过10年的经验,对版本控制系统有非常深入的认识。尤为难得的是,本书文笔很流畅,虽然是技术书籍,但是作者娓娓道来,阅读体验很好。Git的学习门槛较高,包括我们公司在内的很多企业都将版本控制系统转向了Git,强烈推荐大家看一看。——范凯(Robbin) CSDN平台开发总监/ITeye(www.iteye.com )创始人

 

       这是我读过的最好的关于Git的书。将复杂的Git解释得清晰而透彻绝非易事,蒋鑫做到了,更让人惊喜的是,他还分享了大量的经验总结。我几年来累积下来的诸多疑惑都在读罢该书后一一得以解开。如果你正在使用,或者打算使用Git,本书当然是必备的。你也可以抱着Subversion或CVS不放,不过,如果哪一天有人拿起这本书敲你的头时可别怪我没提醒过你。——许晓斌(Juven Xu) 资深Maven专家/著有畅销书《Maven实战》

 

       Git是当前开源社区最流行的版本控制系统,代表了版本控制的未来。每一位有志于从事软件开发的学习者都应该学习和掌握这一工具,它不但可用于追踪编程者的思考过程,还是打开开源软件世界的金钥匙,更可以通过版本控制掌握与他人协同工作的技能。本书是一本耐读的原创著作,因为其涵盖的内容之广足以让每一位程序员在成长的不同阶段都可以从中汲取丰富营养。—— 冯铃  清华大学计算机科学与技术系“长江学者”兼特聘教授

 

       目前市面上关于Git的书不在少数,但迄今为止,国内外还没有一本书能在广度和深度上达到本书的水平,也许在今后相当长的一段时间内也不会有。如果你是一位软件开发者,强烈建议你学习并使用Git;如果你要学习Git,本书无疑是你最佳的选择。——徐继哲 哲思社区(http://www.zeuux.org/ )创始人

目 录 [ - ]

  1. 《Git权威指南》前言
  2. 《Git权威指南》目录
  3. 第1篇 初识Git
  4. 第1章 版本控制的前世和今生
  5. 1.1 黑暗的史前时代
  6. 1.2 CVS—开启版本控制大爆发
  7. 1.3 SVN—集中式版本控制集大成者
  8. 第2章 爱上 Git 的理由
  9. 2.1 每日工作备份
  10. 2.2 异地协同工作
  11. 2.3 现场版本控制
  12. 2.4 避免引入辅助目录
  13. 2.5 重写提交说明
  14. 2.6 想吃后悔药
  15. 2.7 更好用的提交列表
  16. 2.8 更好的差异比较
  17. 2.9 工作进度保存
  18. 2.10 代理SVN提交实现移动式办公
  19. 2.11 无处不在的分页器
  20. 2.12 快
  21. 第3章 Git的安装和使用
  22. 3.1 在Linux 下安装和使用 Git
  23. 3.1.1 包管理器方式安装
  24. 3.1.2 从源代码进行安装
  25. 3.1.3 从Git版本库进行安装
  26. 3.1.4 命令补齐
  27. 3.1.5 中文支持
  28. 3.2.1 以二进制发布包的方式安装
  29. 3.2.2 安装 Xcode
  30. 3.2.3 使用 Homebrew 安装 Git
  31. 3.2.4 从Git源码进行安装
  32. 3.2.5 命令补齐
  33. 3.2.6 其他辅助工具的安装
  34. 3.2.7 中文支持
  35. 3.3 在Windows 下安装和使用 Git(Cygwin篇)
  36. 3.3.1 安装 Cygwin
  37. 3.3.2 安装 Git
  38. 3.3.3 Cygwin 的配置和使用
  39. 3.3.4 Cygwin 下 Git 的中文支持
  40. 3.3.5 Cygwin 下 Git 访问 SSH 服务
  41. 3.4 Windows 下安装和使用 Git(msysGit篇)
  42. 3.4.1 安装 msysGit
  43. 3.4.2 msysGit 的配置和使用
  44. 3.4.3 msysGit中shell环境的中文支持
  45. 3.4.4 msysGit中Git的中文支持
  46. 3.4.5 使用 SSH 协议
  47. 3.4.6 TortoiseGit 的安装和使用
  48. 3.4.7 TortoiseGit 的中文支持

《Git权威指南》前言 Top

      版本控制是管理数据变更的艺术,无论数据变更是来自同一个人,还是来自不同的人(一个团队)。版本控制系统不但要忠实地记录数据的每一次变更,还要能够帮助还原任何一次历史变更,以及实现团队的协同工作等。Git 就是版本控制系统中的佼佼者。 
      我对版本控制系统的兴趣源自于我的个人知识管理实践,其核心就是撰写可维护的文档,并保存于版本控制系统中。可维护文档的格式可以是 DocBook、FreeMind、reStructuredText 等。我甚至还对 FreeMind 加以改造以便让其文档格式更适合于版本控制系统,这就是我的第一个开源实践:托管于 SourceForge 上的 FreeMind-MMX 项目①。文档书写格式的问题解决之后,就是文档的存储问题了。通过版本控制系统,很自然地就可以实现对文档历史版本的保存,但是如何避免因为版本控制系统瘫痪而导致数据丢失呢?Git 用其崭新的分布式的版本控制设计提供了最好的解决方案。使用 Git,我的知识库不再只有唯一的版本库与之对应,而是可以通过克隆操作分发到不同的磁盘或主机上,克隆的版本库之间通过推送(PUSH)和拉回(PULL)等操作进行同步,数据安全得到了极大的提升。在版本控制系统的忠实呵护下,我的知识库中关于Git的 FreeMind 脑图在日积月累中变得越来越翔实,越来越清晰,最终成为本书的雏形。 
       版本控制能决定项目的成败,甚至是公司的生死,此言不虚。我在推广开源项目管理工具和为企业提供咨询服务的过程中看到,有很多团队因为版本控制系统管理的混乱导致项目延期、修正的 Bug 重现、客户的问题不能在代码中定位……无论他们使用的是什么版本控制系统(开源的或是商业的)都是如此。这是因为传统的集中式版本控制系统不能有效地管理分支和进行分支间合并。集中管理的版本库只有唯一的分支命名空间,需要专人管理,从而造成分支创建的不自由;分支间的合并要么因为缺乏追踪导致重复合并、引发严重冲突,要么因为版本控制系统本身蹩脚的设计导致分支合并时效率低下和陷阱重重。Git凭借其灵活的设计让项目摆脱分支管理的梦魇。
       我的公司也经历过代码管理的生死考验。因为公司的开发模式主要是基于开源软件的二次开发,所以最早在使用SVN(Subversion)做版本控制时,很自然地使用了SVN卖主分支模型来管理代码。随着增加和修改的代码越来越多,我们开发的软件与开源软件上游的偏离也越来越远,当上游有新版本发布时,最早可能只用几个小时就可以将改动迁移过去,但是如果对上游的改动多达几十甚至上百处时,迁移的过程就会异常痛苦,基本上和重新做一遍差不多。那时似乎只有一种选择:不再与上游合并,不再追踪上游的改动,而这与公司的价值观“发动全球智慧为客户创造价值”相违背。迷茫之中,分布式版本控制系统飘然而至,原来版本控制还可以这么做。
       我最先尝试的分布式版本控制系统是 Hg(Mercurial),当发现Hg和 MQ(Hg 的一个插件)这一对宝贝儿的时候,我如获至宝。逐渐地,公司的版本库都迁移到了Hg上。但随着新的开发人员的加入,问题又出现了,一个人使用Hg和MQ很好,但多个人使用时则会出现难以协同的问题。于是我们大胆地采用了 Git,并在实践中结合 Topgit 等工具进行代码的管理。再一次,也许是最后一次,我们的代码库迁移到了 Git。
       最早认识分布式版本控制,源自于我们看到了众多开源项目的版本控制系统大迁移,这场迁移还在进行中。
       MoinMoin 是我们关注的一个开源的维基软件,2006 年,它的代码库从SVN迁移到了Hg。
       Mailman 同样是我们关注的一个开源邮件列表软件。2007 年,它的代码库从SVN迁移到了 Bazaar。
       Linux 采用Git作为版本控制系统(一点都不奇怪,因为Git就是 Linus Torvalds 开发的)。
       Android 是目前最为流行的开源项目之一,因为潜在市场巨大,已经吸引了越来越多的开发者进入这个市场,而Android就是用Git维护的。
       当开源软件纷纷倒向分布式版本控制系统大旗(尤其是Git)的时候,很多商业公司也在行动了,尤其是涉及异地团队协同和Android核心代码定制开发的公司。对于那些因保守而不敢向Git靠拢的公司,Git也可以派上用场,因为Git可以与现在大多数公司部署的SVN很好地协同,即公司的服务器是 SVN,开发者的客户端则使用 Git。相信随着Git的普及,以及公司在代码管理观念上的改进,会有更多的公司拥抱 Git。

本书的组织 
       本书共分为9篇,前8篇是正文,一共41章,第9篇是附录。
       第1篇讲解了Git的相关概念,以及安装和配置的方法,共3章。第1章介绍了版本控制的历史。第2章用十几个小例子介绍了Git的一些闪亮特性,期待这些特性能够让你爱上Git。第3章则介绍了Git在三种主要操作系统平台上的安装和使用。在本书的写作过程中,我70%的时间使用的是Debian Linux操作系统,Linux用户可以毫无障碍地完成本书列举的所有实践操作。在2010年年底,当得知有出版社愿意出版这本书后,我向妻子阿巧预支了未来的部分稿费购买了我的第一台 MacBook Pro,于是本书就有了较为翔实的如何在Mac OS X下安装和使用Git的内容,以及在本书第22章中介绍的关于Topgit在Mac OS X上的部署和改进相关的内容。在本书的编辑和校对过程中因为要使用 Word 格式的文稿,所以本书后期的很多工作是在运行于 VirtualBox 下的 Windows 虚拟机中完成的,即使是使用运行于资源受限的虚拟机中的 Cygwin,Git 依然完美地完成了工作。
       第2篇和第3篇详细讲解了Git的使用方法,是本书的基础和核心,大约占据了全书40%的篇幅。这两篇的内容架构方式是我在进行SVN培训时就已经形成的习惯,即以“独奏”指代一个人的版本控制所要讲述的知识点,以“和声”指代团队版本控制涉及的话题。在第2篇“Git独奏”中,本书将Git的设计原理穿插在各章之中讲解,因为唯有了解真相(Git原理),才有可能自由(掌握Git)。在第3篇“Git和声”中,本书讲解了团队版本控制必须掌握的里程碑和分支等概念,以及如何解决合并中遇到的冲突。
       第4篇细致地讲解了Git在实际工作中的使用模式。除了传统的集中式和分布式使用模式之外,第22章还介绍了 Topgit 在定制开发中的应用,这也是我公司在使用Git时采用的最主要的模式。这一章还讲解了我对 Topgit 所做的部分改进,相关的具体介绍最早出现在我公司的博客上①。第23~25章介绍了多版本库协同的不同方法,其中第25章介绍的一个独辟蹊径的解决方案是由 Android 项目引入的名为repo的工具实现的,我对其进行改造后可以让这个工具脱离Gerrit代码审核服务器,直接操作Git服务器。第26章介绍了git-svn这一工具,该工具不但可以实现从SVN版本库到Git版本库的迁移,还可以实现以Git作为客户端向SVN提交。
       第5篇介绍了Git服务器的架设。本篇是全书最早开始撰写的部分,这是因为我给客户做的Git培训讲义的相关内容不够详细,于是应客户要求针对Gitolite等服务器的架设撰写了详细的管理员手册,即本书的第30章。第32章介绍了Android项目在Git管理上的又一大创造,即Gerrit,它实现了一个独特的集中式Git版本库管理模型。
       第6篇讲解了Git版本库的迁移。其中第34章详细介绍了从CVS版本库到Git版本库的迁移,其迁移过程也可以作为从CVS到SVN迁移的借鉴。本篇还介绍了从SVN和Hg版本库到Git的迁移。对于其他类型的版本库,介绍了一个通用的需要编程来实现的方法。在本篇的最后还介绍了一个Git版本库整理的利器,可以理解为一个Git库转换为另外一个Git库的方法。
       第7篇是关于Git的其他应用,其主要内容介绍了我在etckeeper启发下开发的一款备份工具 Gistore,该工具可以运行于Linux和Mac OS X下。
       第8篇是Git杂谈。其中第40章的内容可供跨平台的项目组借鉴。第41章介绍了一些在前面没有涉及的Git的相关功能和特性。
       第9篇是附录。首先介绍了完整的Git命令索引,然后分别介绍了CVS、SVN、Hg与Git之间的比较和命令对照,对于有其他版本控制系统使用经验的用户而言,这一部分内容颇具参考价值。

适用读者
       本书适合所有翻开它的人,因为我知道这本书在书店里一定是放在计算机图书专柜。本书尤其适合以下几类读者阅读。
     1.被数据同步困扰的“电脑人”
        困扰“电脑人”的一个常见问题是,有太多的数据需要长久保存,有太多的电脑设备需要数据同步。可能有的人会说:“像Dropbox一样的网盘可以帮助我呀”。是的,云存储就是在技术逐渐成熟之后应运而生的产品,但是依然解决不了如下几个问题:多个设备上同时修改造成的冲突;冗余数据传输造成的带宽瓶颈;没有实现真正的、完全的历史变更数据备份。具体请参见本书第7篇第39章的内容。
        Git可以在数据同步方面做得更好,甚至只需借助小小的U盘就可以实现多台电脑的数据同步,并且支持自动的冲突解决。只要阅读本书第1篇和第2篇,就能轻易掌握相关的操作,实现数据的版本控制和同步。
2.学习计算机课程的学生
        我非常后悔没有在学习编程的第一天就开始使用版本控制,在学校时写的很多小程序和函数库都丢失了。直到使用了CVS和SVN对个人数据进行版本控制之后,才开始把每一天的变更历史都保留了下来。Git在这方面可以比CVS和SVN等做得更好。
        在阅读完本书的前3篇掌握了Git的基础知识之后,可以阅读第5篇第33章的内容,通过 Github 或类似的服务提供商建立自己的版本库托管,为自己的数据找一个安全的家。
3. 程序员
       使用Git会让程序员有更多的时间休息,因为可以更快地完成工作。分布式版本控制让每一个程序员都能在本地拥有一个完整的版本库,所以几乎所有操作都能够脱离网络执行而不受带宽的限制。加之使用了智能协议,版本库间的同步不但减少了数据传输量,还能显示完成进度。
       Git帮助程序员打开了进入开源世界的大门,进而开阔视野,提升水平,增加择业的砝码。看看使用Git作为版本控制的开源软件吧:Linux kernel、Android、Debian、Fedora、GNOME、KDevelop、jQuery、Prototype、PostgreSQL、Ruby on Rails……不胜枚举。还有,不要忘了所有的SVN版本库都可以通过Git方式更好地访问。
       作为一个程序员,必须具备团队协同能力,本书第3篇应该作为学习的重点。
4.Android程序员
       如果你是谷歌Android项目的参与者,尤其是驱动开发和核心开发的参与者,必然会接触Git、repo和Gerrit。对于只是偶尔参考一下Android核心代码的Android应用开发人员而言,也需要对repo有深入的理解,这样才不至于每次为同步代码而耗费一天的时间。
       repo是Android为了解决Git多版本库管理问题而设计的工具,在本书第4篇第25章有详细介绍。
       Gerrit是谷歌为了避免因分布式开发造成项目分裂而开发的工具,打造了Android独具一格的集中式管理模式,在本书第5篇第32章有详细介绍。
       即使是非Android 项目,也可以使用这两款工具为自己的项目服务。我还为repo写了几个新的子命令以实现脱离Gerrit提交,让repo拥有更广泛的应用领域。
5.定制开发程序员
       当一个公司的软件产品需要针对不同的用户进行定制开发时,就需要在一个版本库中建立大量的特性分支,使用SVN的分支管理远不如使用Git的分支管理 那么自然和方便。还有一个应用领域就是对第三方代码进行维护。当使用SVN进行版本控制时,最自然的选择是卖主分支,但随着定制开发的逐渐深入,与上游的偏离也会越大,于是与上游代码的合并也将越来越令人痛苦。
       第4篇第22章介绍Topgit这一杀手级的工具,这是这个领域最佳的解决方案。
6.SVN用户
       商业软件的研发团队因为需要精细的代码授权,所以不会轻易更换现有的SVN版本控制系统,这种情况下Git依然大有作为。无论是出差在外,或是在家办公,或是开发团队分处异地,都会遇到SVN版本控制服务器无法访问或速度较慢的情况。这时git-svn这一工具会将Git和SVN完美地结合在一起,既严格遵守SVN的授权规定,又可以自如地进行本地提交,当能够连接到SVN服务器时,可以在悠闲地喝着绿茶的同时,等待一次性批量提交的完成。
       我有几个项目(pySvnManager、Freemind-MMX)托管在 SourceForge 的SVN服务器上,现在都是先通过 git-svn 将其转化为本地的Git库,然后再使用的。以这样的方式访问历史数据、比较代码或提交代码,再也不会因为网速太慢而望眼欲穿了。
       本书第4篇第26章详细介绍了Git和SVN的互操作。
7. 管理员
       Git在很大程度上减轻了管理员的负担:分支的创建和删除不再需要管理员统一管理,因为作为分布式版本控制系统,每一个克隆就是一个分支,每一个克隆都拥有独立的分支命名空间;管理员也不再需要为版本库的备份操心,因为每一个项目成员都拥有一个备份;管理员也不必担心有人在服务器上篡改版本库,因为Git版本库的每一个对象(提交和文件等)都使用SHA1哈希值进行完整性校验,任何对历史数据的篡改都会因为对后续提交产生的连锁反应而原形毕露。
       本书第7篇第37章介绍了一款我开发的基于Git的备份工具,它使得 Linux 系统的数据备份易如反掌。本书第5篇介绍的Git服务器搭建,以及第6篇介绍的版本库迁移方面的知识会为版本控制管理员的日常维护工作提供指引。
8. 开发经理
      作为开发经理,你一定要对代码分支有深刻的理解,不知本书第18章中的“代码管理之殇”是否能引起你的共鸣。为了能在各种情况下恰当地管理开发团队,第4篇“Git协同模型”是项目经理应该关注的重点。你的团队是否存在着跨平台开发,或者潜在着跨平台开发的可能?本书第8篇第40章也是开发经理应当关注的内容。

排版约定
    本书使用的排版格式约定如下:
1. 命令输出及示例代码
    执行一条Git命令及其输出的示例如下:
    $ git --version
    git version 1.7.4
2. 提示符($)
    命令前面的 $ 符号代表命令提示符。
3. 等宽字体(Constant width)
    用于标示屏幕输出的字符 、示例代码,以及正文中出现的命令、参数、文件名和函数名等。
4. 等宽粗体(Constant width bold)
    用于表示由用户手工输入的内容。
5. 占位符(<Constant width>)
    用尖括号扩起来的内容,表示命令中或代码中的占位符,读者应当用实际值将其替换。
在线资源
     官方网站:http://www.ossxp.com/doc/gotgit/
在本书的官方网站上,大家可以了解到与本书相关的最新信息,查看本书的勘误,以及下载与本书相关的资源。官网是以Git方式维护的,人人都可以参与其中。
     新浪微博:http://weibo.com/GotGit
    欢迎大家通过新浪微博与作者交流,也欢迎大家通过新浪微博将你们的宝贵意见和建议反馈给作者。

致谢
    感谢 Linus Torvalds、Junio C Hamano 和Git项目的所有贡献者,是他们带给我们崭新的版本控制体验。
    本书能够出版要感谢机械工业出版社华章公司,华章公司对中文原创计算机图书的信任让中国的每一个计算机从业者都有可能圆自己出书的梦想。作为一个新人,拿着一个新的选题,遇到同样充满激情的编辑,我无疑是幸运的。这个充满激情的编辑,就是华章公司的杨福川编辑。甚至没有向我索要样章,在看过目录之后就“冒险”和我签约,他的激情让我不敢懈怠。同样要感谢王晓菲编辑,她的耐心和细致让我吃惊,也正是因为她的工作本书的行文才能更加流畅,本书也才能够更快问世。还有张少波编辑,感谢她在接到我的电话后帮我分析选题并推荐给杨福川编辑。
    本书的部分内容是由我的Git培训讲义扩展而来的,在此感谢朝歌数码的蒋宗贵,是他的鼓励和鞭策让我完善了本书中的与服务器架设的相关章节。还要感谢王彦宁,正是通过她的团队我才认识了 Android,才有了本书关于 repo 和 Gerrit 的相关章节。
    感谢群英汇的同事们,尤其要感谢王胜,正是因为我们在使用 Topgit 0.7 版本时遇到了严重的冲突,才使我下定决心研究 Git。
    感谢上海爱立信研发中心的高级技术专家蔡煜,他对全书尤其是git-svn和Gitolite相关章节做了重点评审,他的意见和建议修正了本书的很多不当之处。因为时间的关系,他的一些非常好的观点没有机会在这一版中体现,争取在改版时弥补遗憾。
    中国科学院软件研究所的张先轶、比蒙科技的宋伯润和杨致伟、摩博科技的熊军、共致开源的秦红胜,以及王胜等人为本书的技术审校提供了帮助,感谢他们的宝贵意见和建议。来自中国台湾的PyLabs 团队纠正了本书在对Hg的认识上的偏颇,让本书附录中的相关内容更加准确和客观,在此向他们表示感谢。
    因为写书亏欠家人很多,直到最近才发现女儿小雪是多么希望拥有一台儿童自行车。感谢妻子阿巧对我的耐心和为家庭的付出。感谢岳父、岳母这几年来对小雪和我们整个家庭的照顾,让我没有后顾之忧。还要感谢我的父母和妹妹,他们对我事业的支持和鼓励是我前进的动力。在我写作本书的同时,老爸正在富春江畔代表哈尔滨电机厂监督发电机组的制造,而且也在写一本监造手册方面的书,抱歉老爸,我先完成了。

蒋鑫(http://www.ossxp.com/)
2011年4月

 

《Git权威指南》目录 Top

前 言
第1篇 初识Git
第1章 版本控制的前世和今生/ 2
1.1 黑暗的史前时代/ 2
1.2 CVS—开启版本控制大爆发/ 5
1.3 SVN—集中式版本控制集大成者/ 7
1.4 Git—Linus 的第二个伟大作品/ 9
第2章 爱上 Git 的理由/ 11
2.1 每日工作备份/ 11
2.2 异地协同工作/ 12
2.3 现场版本控制/ 13
2.4 避免引入辅助目录/ 15
2.5 重写提交说明/ 15
2.6 想吃后悔药/ 16
2.7 更好用的提交列表/ 17
2.8 更好的差异比较/ 18
2.9 工作进度保存/ 18
2.10 代理SVN提交实现移动式办公/ 19
2.11 无处不在的分页器/ 20
2.12 快/ 21
第3章 Git的安装和使用/ 22
3.1 在Linux 下安装和使用 Git/ 22
3.1.1 包管理器方式安装/ 22
3.1.2 从源代码进行安装/ 23
3.1.3 从Git版本库进行安装/ 23
3.1.4 命令补齐/ 25
3.1.5 中文支持/ 25
3.2 在Mac OS X 下安装和使用 Git/ 26
3.2.1 以二进制发布包的方式安装/ 26
3.2.2 安装 Xcode/ 27
3.2.3 使用 Homebrew 安装 Git/ 29
3.2.4 从Git源码进行安装/ 29
3.2.5 命令补齐/ 30
3.2.6 其他辅助工具的安装/ 30
3.2.7 中文支持/ 31
3.3 在Windows 下安装和使用 Git(Cygwin篇)/ 31
3.3.1 安装 Cygwin/ 32
3.3.2 安装 Git/ 36
3.3.3 Cygwin 的配置和使用/ 37
3.3.4 Cygwin 下 Git 的中文支持/ 40
3.3.5 Cygwin 下 Git 访问 SSH 服务/ 41
3.4 Windows 下安装和使用 Git(msysGit篇)/ 45
3.4.1 安装 msysGit/ 46
3.4.2 msysGit 的配置和使用/ 48
3.4.3 msysGit中shell环境的中文支持/ 49
3.4.4 msysGit中Git的中文支持/ 50
3.4.5 使用 SSH 协议/ 51
3.4.6 TortoiseGit 的安装和使用/ 52
3.4.7 TortoiseGit 的中文支持/ 55
第2篇 Git独奏
第4章 Git 初始化/ 58
4.1 创建版本库及第一次提交/ 58
4.2 思考:为什么工作区根目录下有一个 .git 目录/ 60
4.3 思考:git config 命令的各参数有何区别/ 63
4.4 思考:是谁完成的提交/ 65
4.5 思考:随意设置提交者姓名,是否太不安全/ 67
4.6 思考:命令别名是干什么的/ 68
4.7 备份本章的工作成果/ 69
第5章 Git 暂存区/ 70
5.1 修改不能直接提交吗/ 70
5.2 理解 Git 暂存区(stage)/ 76
5.3 Git Diff 魔法/ 78
5.4 不要使用 git commit -a/ 81
5.5 搁置问题,暂存状态/ 82
第6章 Git对象/ 83
6.1 Git对象库探秘/ 83
6.2 思考:SHA1 哈希值到底是什么,是如何生成的/ 88
6.3 思考:为什么不用顺序的数字来表示提交/ 90
第7章 Git 重置/ 93
7.1 分支游标master探秘/ 93
7.2 用 reflog 挽救错误的重置/ 95
7.3 深入了解git reset命令/ 96
第8章 Git 检出/ 99
8.1 HEAD 的重置即检出/ 99
8.2 挽救分离头指针/ 102
8.3 深入了解 git checkout 命令/ 103
第9章 恢复进度/ 105
9.1 继续暂存区未完成的实践/ 105
9.2 使用 git stash/ 108
9.3 探秘 git stash/ 109
第10章 Git 基本操作/ 114
10.1 先来合个影/ 114
10.2 删除文件/ 114
10.2.1 本地删除不是真的删除/ 115
10.2.2 执行 git rm 命令删除文件/ 116
10.2.3 命令git add -u快速标记删除/ 117
10.3 恢复删除的文件/ 118
10.4 移动文件/ 119
10.5 一个显示版本号的 Hello World/ 120
10.6 使用 git add -i 选择性添加/ 122
10.7 Hello World 引发的新问题/ 124
10.8 文件忽略/ 125
10.9 文件归档/ 129
第11章 历史穿梭/ 130
11.1 图形工具:gitk/ 130
11.2 图形工具:gitg/ 131
11.3 图形工具:qgit/ 135
11.4 命令行工具/ 140
11.4.1 版本表示法:git rev-parse/ 141
11.4.2 版本范围表示法:git rev-list/ 144
11.4.3 浏览日志:git log/ 146
11.4.4 差异比较:git diff/ 150
11.4.5 文件追溯:git blame/ 151
11.4.6 二分查找:git bisect/ 152
11.4.7 获取历史版本/ 156
第12章 改变历史/ 157
12.1 悔棋/ 157
12.2 多步悔棋/ 159
12.3 回到未来/ 161
12.3.1 时间旅行一/ 162
12.3.2 时间旅行二/ 167
12.3.3 时间旅行三/ 171
12.4 丢弃历史/ 174
12.5 反转提交/ 177
第13章 Git 克隆/ 179
13.1 鸡蛋不装在一个篮子里/ 179
13.2 对等工作区/ 180
13.3 克隆生成裸版本库/ 183
13.4 创建生成裸版本库/ 184
第14章 Git库管理/ 187
14.1 对象和引用哪里去了/ 187
14.2 暂存区操作引入的临时对象/ 189
14.3 重置操作引入的对象/ 191
14.4 Git管家:git-gc/ 193
14.5 Git管家的自动执行/ 196
第3篇 Git和声
第15章 Git协议与工作协同/ 200
15.1 Git 支持的协议/ 200
15.2 多用户协同的本地模拟/ 202
15.3 强制非快进式推送/ 203
15.4 合并后推送/ 207
15.5 禁止非快进式推送/ 208
第16章 冲突解决/ 210
16.1 拉回操作中的合并/ 210
16.2 合并一:自动合并/ 212
16.2.1 修改不同的文件/ 212
16.2.2 修改相同文件的不同区域/ 214
16.2.3 同时更改文件名和文件内容/ 215
16.3 合并二:逻辑冲突/ 217
16.4 合并三:冲突解决/ 218
16.4.1 手工编辑完成冲突解决/ 221
16.4.2 图形工具完成冲突解决/ 221
16.5 合并四:树冲突/ 225
16.5.1 手工操作解决树冲突/ 227
16.5.2 交互式解决树冲突/ 228
16.6 合并策略/ 230
16.7 合并相关的设置/ 231
第17章 Git 里程碑/ 233
17.1 显示里程碑/ 234
17.2 创建里程碑/ 236
17.2.1 轻量级里程碑/ 237
17.2.2 带说明的里程碑/ 238
17.2.3 带签名的里程碑/ 239
17.3 删除里程碑/ 242
17.4 不要随意更改里程碑/ 243
17.5 共享里程碑/ 243
17.6 删除远程版本库的里程碑/ 246
17.7 里程碑命名规范/ 247
第18章 Git 分支/ 253
18.1 代码管理之殇/ 253
18.1.1 发布分支/ 253
18.1.2 特性分支/ 256
18.1.3 卖主分支/ 257
18.2 分支命令概述/ 258
18.3 “Hello World”开发计划/ 259
18.4 基于特性分支的开发/ 260
18.4.1 创建分支 user1/getopt/ 261
18.4.2 创建分支 user2/i18n/ 262
18.4.3 开发者 user1 完成功能开发/ 263
18.4.4 将 user1/getopt 分支合并到主线/ 264
18.5 基于发布分支的开发/ 265
18.5.1 创建发布分支/ 266
18.5.2 开发者 user1 工作在发布分支/ 267
18.5.3 开发者 user2 工作在发布分支/ 268
18.5.4 开发者 user2 合并推送/ 270
18.5.5 发布分支的提交合并到主线/ 271
18.6 分支变基/ 275
18.6.1 完成 user2/i18n 特性分支的开发/ 275
18.6.2 分支 user2/i18n 变基/ 277
第19章  远程版本库/ 284
19.1 远程分支/ 284
19.2 分支追踪/ 287
19.3 远程版本库/ 290
19.4 PUSH 和 PULL 操作与远程版本库/ 292
19.5 里程碑和远程版本库/ 294
19.6 分支和里程碑的安全性/ 294
第20章 补丁文件交互/ 296
20.1 创建补丁/ 296
20.2 应用补丁/ 297
20.3 StGit 和 Quilt/ 300
20.3.1 StGit/ 300
20.3.2 Quilt/ 304
第4篇 Git协同模型
第21章 经典Git协同模型/ 308
21.1 集中式协同模型/ 308
21.1.1 传统集中式协同模型/ 309
21.1.2 Gerrit 特殊的集中式协同模型/ 310
21.2 金字塔式协同模型/ 311
21.2.1 贡献者开放只读版本库/ 312
21.2.2 以补丁方式贡献代码/ 313
第22章 Topgit 协同模型/ 314
22.1 作者版本控制系统的三个里程碑/ 314
22.2 Topgit 原理/ 316
22.3 Topgit 的安装/ 317
22.4 Topgit 的使用/ 319
22.5 用Topgit方式改造Topgit/ 330
22.6 Topgit 使用中的注意事项/ 334
第23章 子模组协同模型/ 336
23.1 创建子模组/ 336
23.2 克隆带子模组的版本库/ 339
23.3 在子模组中修改和子模组的更新/ 340
23.4 隐性子模组/ 343
23.5 子模组的管理问题/ 345
第24章 子树合并/ 347
24.1 引入外部版本库/ 347
24.2 子目录方式合并外部版本库/ 349
24.3 利用子树合并跟踪上游改动/ 351
24.4 子树拆分/ 353
24.5 git-subtree 插件/ 353
第25章 Android 式多版本库协同/ 356
25.1 关于 repo/ 357
25.2 安装 repo/ 357
25.3 repo和清单库的初始化/ 359
25.4 清单库和清单文件/ 360
25.5 同步项目/ 361
25.6 建立 Android 代码库本地镜像/ 363
25.7 repo 的命令集/ 365
25.8 repo 命令的工作流/ 370
25.9 好东西不能 Android 独享/ 371
25.9.1 repo+Gerrit 模式/ 371
25.9.2 repo 无审核模式/ 371
25.9.3 改进的 repo 无审核模式/ 372
第26章 Git 和 SVN 协同模型/ 378
26.1 使用 git-svn 的一般流程/ 380
26.2 git-svn 的奥秘/ 386
26.2.1 Git 库配置文件的扩展及分支映射/ 387
26.2.2 Git工作分支和 Subversion 如何对应/ 388
26.2.3 其他辅助文件/ 390
26.3 多样的 git-svn 克隆模式/ 390
26.4 共享 git-svn 的克隆库/ 393
26.5 git-svn 的局限/ 394
第5篇 搭建Git服务器
第27章 使用 HTTP 协议/ 398
27.1 哑传输协议/ 398
27.2 智能 HTTP 协议/ 400
27.3 Gitweb 服务器/ 401
27.3.1 Gitweb的安装/ 402
27.3.2 Gitweb的配置/ 403
27.3.3 版本库的 Gitweb 相关设置/ 404
27.3.4 即时Gitweb服务/ 405
第28章 使用 Git 协议/ 406
28.1 Git 协议语法格式/ 406
28.2 Git 服务软件/ 406
28.3 以 inetd 方式配置运行/ 406
28.4 以 runit 方式配置运行/ 407
第29章 使用 SSH 协议/ 409
29.1 SSH 协议语法格式/ 409
29.2 服务架设方式比较/ 409
29.3 关于 SSH 公钥认证/ 411
29.4 关于 SSH 主机别名/ 411
第30章 Gitolite 服务架设/ 413
30.1 安装Gitolite/ 414
30.1.1 服务器端创建专用账号/ 414
30.1.2 Gitolite 的安装/升级/ 415
30.1.3 关于 SSH 主机别名/ 417
30.1.4 其他的安装方法/ 418
30.2 管理 Gitolite/ 419
30.2.1 管理员克隆 gitolite-admin 管理库/ 419
30.2.2 增加新用户/ 420
30.2.3 更改授权/ 422
30.3 Gitolite 授权详解/ 423
30.3.1 授权文件的基本语法/ 423
30.3.2 定义用户组和版本库组/ 424
30.3.3 版本库ACL/ 424
30.3.4 Gitolite 授权机制/ 426
30.4 版本库授权案例/ 427
30.4.1 对整个版本库进行授权/ 427
30.4.2 通配符版本库的授权/ 428
30.4.3 用户自己的版本库空间/ 429
30.4.4 对引用的授权:传统模式/ 430
30.4.5 对引用的授权:扩展模式/ 430
30.4.6 对引用的授权:禁用规则的使用/ 431
30.4.7 用户分支/ 431
30.4.8 对路径的写授权/ 432
30.5 创建新版本库/ 432
30.5.1 在配置文件中出现的版本库,即时生成/ 433
30.5.2 通配符版本库,管理员通过推送创建/ 434
30.5.3 直接在服务器端创建/ 435
30.6 对 Gitolite 的改进/ 435
30.7 Gitolite 功能拓展/ 436
30.7.1 版本库镜像/ 436
30.7.2 Gitweb 和 Git daemon 支持/ 438
30.7.3 其他功能拓展和参考/ 439
第31章 Gitosis 服务架设/ 441
31.1 安装 Gitosis/ 442
31.1.1 Gitosis 的安装/ 442
31.1.2 服务器端创建专用账号/ 442
31.1.3 Gitosis 服务初始化/ 443
31.2 管理 Gitosis/ 443
31.2.1 管理员克隆 gitolit-admin 管理库/ 443
31.2.2 增加新用户/ 444
31.2.3 更改授权/ 446
31.3 Gitosis 授权详解/ 447
31.3.1 Gitosis 默认设置/ 447
31.3.2 管理版本库 gitosis-admin/ 447
31.3.3 定义用户组和授权/ 448
31.3.4 Gitweb 整合/ 449
31.4 创建新版本库/ 449
31.5 轻量级管理的 Git 服务/ 450
第32章 Gerrit 代码审核服务器/ 452
32.1 Gerrit 的实现原理/ 452
32.2 架设 Gerrit 的服务器/ 456
32.3 Gerrit 的配置文件/ 461
32.4 Gerrit 的数据库访问/ 462
32.5 立即注册为 Gerrit 管理员/ 464
32.6 管理员访问 SSH 的管理接口/ 467
32.7 创建新项目/ 468
32.8 从已有的 Git 库创建项目/ 472
32.9 定义评审工作流/ 473
32.10 Gerrit 评审工作流实战/ 477
32.10.1 开发者在本地版本库中工作/ 477
32.10.2 开发者向审核服务器提交/ 478
32.10.3 审核评审任务/ 478
32.10.4 评审任务没有通过测试/ 480
32.10.5 重新提交新的补丁集/ 482
32.10.6 新修订集通过评审/ 483
32.10.7 从远程版本库更新/ 485
32.11 更多 Gerrit 参考/ 486
第33章 Git 版本库托管/ 487
33.1 Github/ 487
33.2 Gitorious/ 489
第6篇 迁移到Git
第34章 CVS版本库到Git的迁移/ 492
34.1 安装cvs2svn(含 cvs2git)/ 492
34.1.1 Linux下cvs2svn的安装/ 492
34.1.2 Mac OS X 下 cvs2svn 的安装/ 493
34.2 版本库转换的准备工作/ 494
34.2.1 版本库转换注意事项/ 494
34.2.2 文件名乱码问题/ 494
34.2.3 提交说明乱码问题/ 494
34.3 版本库转换/ 496
34.3.1 配置文件解说/ 496
34.3.2 运行cvs2git完成转换/ 500
34.4 迁移后的版本库检查/ 501
第35章 更多版本控制系统的迁移/ 502
35.1 SVN版本库到Git的迁移/ 502
35.2 Hg 版本库到Git的迁移/ 503
35.3 通用版本库迁移/ 505
35.4 Git 版本库整理/ 511
35.4.1 环境变量过滤器/ 513
35.4.2 树过滤器/ 513
35.4.3 暂存区过滤器/ 513
35.4.4 父节点过滤器/ 514
35.4.5 提交说明过滤器/ 514
35.4.6 提交过滤器/ 515
35.4.7 里程碑名字过滤器/ 516
35.4.8 子目录过滤器/ 516
第7篇 Git的其他应用
第36章 etckeeper/ 518
36.1 安装 etckeeper/ 518
36.2 配置 etckeeper/ 519
36.3 使用 etckeeper/ 519
第37章 Gistore/ 520
37.1 Gistore 的安装/ 520
37.1.1 软件依赖/ 520
37.1.2 从源码安装 Gistore/ 521
37.1.3 用 easy_install 安装/ 521
37.2 Gistore 的使用/ 522
37.2.1 创建并初始化备份库/ 522
37.2.2 Gistore 的配置文件/ 523
37.2.3 Gistore 的备份项管理/ 524
37.2.4 执行备份任务/ 525
37.2.5 查看备份日志/ 525
37.2.6 查看及恢复备份数据/ 527
37.2.7 备份回滚及设置/ 528
37.2.8 注册备份任务别名/ 529
37.2.9 自动备份:crontab/ 529
37.3 Gistore 双机备份/ 529
第38章 补丁中的二进制文件/ 531
38.1 Git 版本库中二进制文件变更的支持/ 531
38.2 对非 Git 版本库中二进制文件变更的支持/ 535
38.3 其他工具对 Git 扩展补丁文件的支持/ 536
第39章 云存储/ 538
39.1 现有云存储的问题/ 538
39.2 Git 式云存储畅想/ 539
第8篇 Git杂谈
第40章 跨平台操作 Git/ 542
40.1 字符集问题/ 542
40.2 文件名大小写问题/ 543
40.3 换行符问题/ 545
第41章 Git 的其他特性/ 549
41.1 属性/ 549
41.1.1 属性定义/ 549
41.1.2 属性文件及优先级/ 550
41.1.3 常用属性介绍/ 552
41.2 钩子和模板/ 557
41.2.1 Git 钩子/ 557
41.2.2 Git 模板/ 562
41.3 稀疏检出和浅克隆/ 563
41.3.1 稀疏检出/ 563
41.3.2 浅克隆/ 566
41.4 嫁接和替换/ 568
41.4.1 提交嫁接/ 568
41.4.2 提交替换/ 568
41.5 Git 评注/ 570
41.5.1 评注的奥秘/ 570
41.5.2 评注相关命令/ 573
41.5.3 评注相关配置/ 574
第9篇 附录
附录A  Git 命令索引/ 576
A.1 常用的Git命令/ 576
A.2 对象库操作相关命令/ 578
A.3 引用操作相关命令/ 578
A.4 版本库管理相关命令/ 579
A.5 数据传输相关命令/ 579
A.6 邮件相关命令/ 580
A.7 协议相关命令/ 580
A.8 版本库转换和交互相关命令/ 581
A.9 合并相关的辅助命令/ 581
A.10 杂项/ 582
附录B Git 与 CVS 面对面/ 583
B.1 面对面访谈录/ 583
B.2 Git  和CVS 命令对照/ 585
附录C Git 与 SVN 面对面/ 587
C.1 面对面访谈录/ 587
C.2  Git 和SVN 命令对照/ 589
附录D Git 与 Hg 面对面/ 592
D.1 面对面访谈录/ 592
D.2 Git和Hg  命令对照/ 593

第1篇 初识Git Top

      Git是一款分布式版本控制系统,有别于CVS和SVN等集中式版本控制系统,Git可以让研发团队更加高效地协同工作,从而提高生产率。使用Git,开发人员的工作不会因为频繁地遭遇提交冲突而中断,管理人员也无须为数据的备份而担心。经过Linux这样的庞大项目的考验之后,Git被证明可以胜任任何规模的团队,即便团队成员分布于世界各地。
      Git 是开源社区奉献给每一个人的宝贝,用好它不仅可以实现个人的知识积累、保护好自己的数据,而且还能与他人分享自己的成果。这在其他的很多版本控制系统中是不可想象的。你会为个人的版本控制而花费高昂的费用去购买商业版本控制工具吗?你会去使用必须搭建额外的服务器才能使用的版本控制系统吗?你会把“鸡蛋”放在具有单点故障、服务器软硬件有可能崩溃的唯一的“篮子”里吗?如果你不会,那么选择Git,一定是最明智的选择。
本篇我们首先用一章的内容来回顾一下版本控制的历史,并以此向版本控制的前辈CVS和SVN致敬。第2章会通过一些典型的版本控制实例向您展示Git独特的魅力,让您爱上Git。在本篇的最后一章会介绍Git在Linux、Mac OS X及Windows下的安装和使用,这是我们进一步研究Git的基础。
      在这里有必要纠正一下Git的发音。一种错误是按照单个字母来发音,另外一种更为普遍的错误是把整个单词读作“技特”,实际上Git中字母G的发音与下列单词中的G类似:GOD、 GIVES、GREAT、GIFT。因此Git正确的发音应该听起来像是“歌易特”。本书的英文名为《Got Git》,当面对这样的书名时您还会把Git读错吗?

 

第1章 版本控制的前世和今生 Top

    除了茫然未知的宇宙,几乎任何事物都是从无到有,从简陋到完善。随着时间车轮的滚滚向前,历史被抛在身后逐渐远去,如同我们的现代社会,世界大同,到处都是忙碌和喧嚣,再也看不到已经远去的刀耕火种、男耕女织的慢生活岁月。
    版本控制系统是一个另类。虽然其历史并不短暂,也有几十年,但是它的演进进程却一直在社会的各个角落重复着,而且惊人的相似。有的人从未使用甚至从未听说过版本控制系统,他和他的团队就像停留在黑暗的史前时代,任由数据自生自灭。有的人使用着有几十年历史的CVS或其改良版Subversion,让时间空耗在网络连接的等待中。以Git为代表的分布式版本控制系统已经风靡整个开源社区,正等待你的靠近。

1.1 黑暗的史前时代 Top

       谈及远古,人们总爱以“黑暗”来形容。黑暗实际上指的是秩序和工具的匮乏,而不是自然。如果以自然环境而论,由于工业化和城市化对环境的破坏,现今才是最黑暗的年代。对于软件开发来说也是如此,在C语言一统天下的日子里我们的选择很简单,如今面临Java、 .Net和脚本语言时,我们的选择变得复杂起来,但是从工具和秩序上讲,过去的年代是黑暗的。
回顾一下我经历的版本控制的“史前时代”吧。在大学里,代码分散地拷贝在各个软盘中,最终我被搞糊涂,不知道哪个软盘中的代码是最优的,因为最新并非最优,失败的重构会毁掉原来尚能运作的代码。在我工作的第一年,代码的管理并未得到改善,还是以简单的目录拷贝进行数据的备份,三四个程序员利用文件服务器的共享目录进行协同,公共类库和头文件在操作过程中相互覆盖,痛苦不堪。很明显,那时我尚不知道版本控制系统为何物。我的版本控制史前时代一直延续到2000年,那时CVS已经诞生了14年,而我在那时对 CVS 还一无所知。
       实际上,即便是在CVS出现之前的“史前时代”,也已经有了非常好用的用于源码比较和打补丁的工具:diff和patch,它们今天生命力依然顽强。大名鼎鼎的 Linus Torvalds 先生(Linux之父)也对这两个工具偏爱有加,在 1991~2002年之间,Linus一直顽固地使用 diff 、patch和tar包管理着Linux的代码,虽然不断有人提醒他有CVS的存在①。
       那么来看看diff和patch,熟悉它们将对理解版本控制系统(差异存储)和使用版本控制系统(代码比较和冲突解决)都有莫大的好处。

1.用diff命令比较两个文本文件或目录的差异
先来构造两个文件:
文件hello 文件world
应该杜绝文章中的错别子①。

但是无论使用
* 全拼,双拼
* 还是五笔

是人就有可能犯错,软件更是如此。

犯了错,就要扣工资!

改正的成本可能会很高。
应该杜绝文章中的错别字。

但是无论使用
* 全拼,双拼
* 还是五笔

是人就有可能犯错,软件更是如此。

改正的成本可能会很高。

但是“只要眼球足够多,所有Bug都好捉”,这就是开源的哲学之一。

对这两个文件执行 diff 命令,并通过输出重定向,将差异保存在 diff.txt 文件中。
$ diff -u hello world > diff.txt
上面执行 diff 命令的 -u 参数很重要,使得差异输出中带有上下文。打开文件diff.txt,会看到其中的差异比较结果。为了说明方便,为每一行增添了行号。
1 --- hello       2010-09-21 17:45:33.551610940 +0800
2 +++ world       2010-09-21 17:44:46.343610465 +0800
3 @@ -1,4 +1,4 @@
4 -应该杜绝文章中的错别子。
5 +应该杜绝文章中的错别字。

7  但是无论使用
8  * 全拼,双拼
9 @@ -6,6 +6,7 @@
10 
11  是人就有可能犯错,软件更是如此。
12 
13 -犯了错,就要扣工资!
14 -
15  改正的成本可能会很高。
16 +
17 +但是“只要眼球足够多,所有Bug都好捉”,
18 +这就是开源的哲学之一。

上面的差异文件,可以这么理解:
第1行和第2行分别记录了原始文件和目标文件的文件名及时间戳。以三个减号(---)开始的行标识的是原始文件,以三个加号(+++)开始的行标识的是目标文件。
在比较内容中,以减号(-)开始的行是只出现在原始文件中的行,例如:第4、13、14行。
在比较内容中,以加号(+)开始的行是只出现在目标文件中的行,例如:第5行和16-18行。
在比较内容中,以空格开始的行,是在原始文件和目标文件中都出现的行,例如:第6-8、10-12和第15行。这些行是用作差异比较的上下文。
第3-8行是第一个差异小节。每个差异小节以一行差异定位语句开始。第3行就是一条差异定位语句,其前后分别用两个@ 进行标识。
第3行定位语句中 -1,4 的含义是:本差异小节的内容相当于原始文件的从第1行开始的4行。而第4、6、7、8行是原始文件中的内容,加起来刚好是4行。
第3行定位语句中 +1,4 的含义是:本差异小节的内容相当于目标文件的从第1行开始的4行。而第5、6、7、8行是目标文件中的内容,加起来刚好是4行。
因为命令diff是用于行比较的,所以即使改正了一个字,也显示为一整行的修改(参见差异文件第4、5行)。Git 对 diff 进行了扩展,并且还提供一种逐词比较的差异比较方法,参见本书第2篇的第11.4.4小节。
第9-18行是第二个差异小节。第9行是一条差异定位语句。
第9行定位语句中 -6,6 的含义是:本差异小节的内容相当于原始文件的从第6行开始的6行。第10-15行是原始文件中的内容,加起来刚好是6行。
第9行定位语句中 +6,7 的含义是:本差异小节的内容相当于目标文件的从第6行开始的7行。而第10-12、15-18行是目标文件中的内容,加起来刚好是7行。
2. 命令 patch 相当于 diff 的反向操作
有了 hello 和 diff.txt 文件,可以放心地将 world 文件删除或用 hello 文件将 world 文件覆盖。用下面的命令可以还原 world 文件:
$ cp hello world
$ patch world < diff.txt
也可以保留 world 和 diff.txt 文件,删除 hello 文件或用 word 文件将hello 文件覆盖。用下面的命令可以恢复 hello 文件:
$ cp world hello
$ patch -R hello < diff.txt
命令 diff 和 patch 还可以对目录进行比较操作,这也就是 Linus 在 1991~2002 年用于维护 Linux 不同版本间差异的办法。在没有版本控制系统的情况下,可以用此命令记录并保存改动前后的差异,还可以将差异文件注入版本控制系统(如果有的话)。
标准的 diff 和 patch 命令存在一个局限,就是不能对二进制文件进行处理。对二进制文件的修改或添加会在差异文件中缺失,进而丢失对二进制文件的改动或添加。Git 对差异文件格式提供了扩展支持,支持二进制文件的比较,解决了这个问题。这一点可以参考本书第7篇第38章的相关内容。

 

1.2 CVS—开启版本控制大爆发 Top

      CVS(Concurrent Versions System)①诞生于 1985 年,是由荷兰阿姆斯特丹 VU 大学的 Dick Grune 教授实现的。当时 Dick Grune 和两个学生共同开发一个项目,但是三个人的工作时间无法协调到一起,迫切需要一个记录和协同开发的工具软件。于是Dick Grune通过脚本语言对 RCS (一个针对单独文件的版本管理工具)进行封装,设计出有史以来第一个被大规模使用的版本控制工具。Dick教授的网站上介绍了 CVS 的这段早期历史。②
“在1985年的一个糟糕的秋日里,我在校汽车站等车回家,脑海里一直纠结着一件事—如何处理RCS 文件、用户文件(工作区)和 Entries 文件的复杂关系,有的文件可能会缺失、冲突、删除,等等。我的头有些晕了,于是决定画一个大表,将复杂的关联画在其中,看看出来的结果是什么样的……”
1986年 Dick 通过新闻组发布了 CVS,1989 年 Brian Berliner 用C语言将 CVS进行了重写。
      从 CVS 的历史可以看出, CVS 不是设计出来的,而是被实际需要“逼”出来的,因此根据“实用为上”的原则,借用了已有的针对单一文件的版本管理工具 RCS。CVS 采用客户端/服务器架构设计,版本库位于服务器端,实际上就是一个 RCS 文件容器。每一个 RCS 文件以 “,v” 作为文件名后缀,用于保存对应文件的每一次更改历史。RCS 文件中只保留一个版本的完全拷贝,其他历次更改仅将差异存储其中,使得存储变得非常有效率。我在 2008 年设计了一个 SVN 管理后台 pySvnManager③,实际上也采用了 RCS 作为 SVN 授权文件的变更记录的“数据库”。
      图1-1展示了CVS版本控制系统的工作原理,可以看到作为RCS文件容器的CVS版本库和工作区目录结构的一一对应关系。
CVS 这种实现方式的最大好处就是简单。把版本库中任意一个目录拿出来就可以成为另外一个版本库。如果将版本库中的一个 RCS 文件重命名,工作区检出的文件名也会相应地改变。这种低成本的服务器管理模式成为很多 CVS 粉丝至今不愿离开 CVS 的原因。 
      CVS 的出现让软件工程师认识到了原来还可以这样工作。CVS 成功地为后来的版本控制系统确立了标准,像提交说明(commit log)、检入(checkin)、检出(checkout)、里程碑(tag)、分支(branch)等概念在 CVS 中早就已经确立。CVS 的命令行格式也被后来的版本控制系统竞相模仿

 

      在 2001 年,我正为使用 CVS 激动不已的时候,公司领导要求采用和美国研发部门同样的版本控制解决方案。于是,我的项目组率先进行了从 CVS 到该商业版本控制工具的迁移①。虽然商业版本控制工具有更漂亮的界面及更好的产品整合性,但是就版本控制本身而言,商业版本控制工具存在着如下缺陷。
      采用黑盒子式的版本库设计。让人捉摸不透的版本库设计,最主要的目的可能就是阻止用户再迁移到其他平台。
      缺乏版本库整理工具。如果有一个文件(如记录核弹引爆密码的文件)检入到版本库中,就无法再彻底移除它。
      商业版本控制工具很难为个人提供版本控制解决方案,除非个人愿意花费高昂的许可证费用。
      商业版本控制工具注定是小众软件,新员工的培训成本不可忽视。
而上述商业版本控制系统的缺点恰恰是 CVS 及其他开源版本控制系统的优点。但在经历了最初的成功之后,CVS 也尽显疲态:
      服务器端松散的 RCS 文件导致在建立里程碑或分支时效率不高,服务器端文件越多,速度越慢。
      分支和里程碑不可见,因为它们被分散地记录在服务器端的各个RCS文件中。
      合并困难重重,因为缺乏对合并的追踪,从而导致重复合并,引发严重冲突。
      缺乏对原子提交的支持,会导致客户端向服务器端提交不完整的数据。
      不能优化存储内容相同但文件名不同的文件,因为在服务器端每个文件都是单独进行差异存储的。
      不能对文件和目录的重命名进行版本控制,虽然直接在服务器端修改RCS文件名可以让改名后的文件保存历史,但是这样做实际上会破坏历史。
CVS 的成功导致了版本控制系统的大爆发,各式各样的版本控制系统如雨后春笋般诞生了。新的版本控制系统或多或少地解决了 CVS 版本控制系统存在的问题。在这些版本控制系统中,最典型的就是 Subversion(SVN)。

1.3 SVN—集中式版本控制集大成者 Top

      Subversion①,由于其命令行工具名为svn,因此通常被简称为 SVN。SVN 由 CollabNet 公司于 2000 年资助并开始开发,目的是创建一个更好用的版本控制系统以取代 CVS。SVN的前期开发使用 CVS 做版本控制,到了 2001 年,SVN 已经可以用于自己的版本控制了②。
我开始真正关注 SVN 是在 2005 年,那时 SVN 正经历着后端存储上的变革,即从BDB(简单的关系型数据库)到 FSFS(文件数据库)的转变。相对于 BDB 而言,FSFS具有稳定、免维护和实现的可视性高等优点,于是我马上就被 SVN 吸引了。图1-2展示了SVN版本控制系统的工作原理。



       SVN 的每一次提交,都会在服务器端的 db/revs 和 db/revprops 目录下各创建一个以顺序数字编号命名的文件。其中,db/revs 目录下的文件(即变更集文件)记录了与上一个提交之间的差异(字母A表示新增,M表示修改,D表示删除)。在 db/revprops 目录下的同名文件(没有在图1-2中体现)则保存着提交日志、作者、提交时间等信息。这样设计的好处有:
 拥有全局版本号。每提交一次, SVN 的版本号就会自动加一。这为 SVN 的使用提供了极大的便利。回想 CVS 时代,每个文件都拥有各自独立的版本号(RCS版本号),要想获得全局版本号,只能通过手工不断地建立里程碑来实现。
 实现了原子提交。SVN 不会像 CVS 那样出现文件的部分内容被提交而其余的内容没有被提交的情况。
 文件名不受限制。因为服务器端不再需要建立和客户端文件相似的文件名,于是,文件的命名就不再受服务器操作系统的字符集和大小写的限制。
 文件和目录重命名也得到了支持。
SVN 最具有特色的功能是轻量级拷贝,例如将目录 trunk 拷贝为 branches/v1.x 只相当于在 db/revs 目录中的变更集文件中用特定的语法做了一下标注,无须真正的文件拷贝。SVN 使用轻量级拷贝的功能,轻松地解决了 CVS 存在的里程碑和分支的创建速度慢又不可见的问题,使用 SVN 创建里程碑和分支只在眨眼之间。
SVN 在版本库授权上也有改进,不再像 CVS 那样依赖操作系统本身对版本库目录和文件进行授权,而是采用授权文件的方式来实现。
SVN 还有一个创举,就是在工作区跟踪目录下(.svn目录)为当前目录中的每一个文件都保存一份冗余的原始拷贝。这样做的好处是部分命令不再需要网络连接,例如文件修改的差异比较,以及错误更改的回退等。
正是由于这些闪亮的功能特性,才使得 SVN 在 CVS 之后诞生的诸多版本控制系统中脱颖而出,成为开源社区一时的新宠,也成为当时各个企业进行版本控制的最佳选择之一。
      但是,相对于CVS,SVN在本质上并没有突破,都属于集中式版本控制系统。即一个项目只有唯一的一个版本库与之对应,所有的项目成员都通过网络向该服务器进行提交。这样的设计除了容易出现单点故障以外,在查看日志和提交数据等操作时的延迟,会让基于广域网协同工作的团队抓狂。
除了集中式版本控制系统固有的问题外,SVN 的里程碑和分支的设计也被证明是一个错误,虽然这个错误的设计使得 SVN 拥有了快速创建里程碑和分支的能力,但是这个错误的设计也导致了如下的更多问题。
 项目文件在版本库中必须按照一定的目录结构进行部署,否则就可能无法建立里程碑和分支。
 我在项目咨询过程中见过很多团队,直接在版本库的根目录下创建项目文件。这样的版本库布局,在需要创建里程碑和分支时就无从下手了,因为根目录是不能拷贝到子目录中的。所以 SVN 的用户在创建版本库时必须遵守一个古怪的约定:先创建三个顶级目录 /trunk、/tags 和 /branches 。
 创建里程碑和分支会破坏精心设计的授权。
 SVN 的授权是基于目录的,分支和里程碑也被视为目录(和其他目录没有分别)。因此每次创建分支或里程碑时,就要将针对 /trunk 目录及其子目录的授权在新建的分支或里程碑上重建。随着分支和里程碑数量的增多,授权愈加复杂,维护也愈加困难。
 分支太随意从而导致混乱。SVN 的分支创建非常随意:可以基于 /trunk 目录创建分支,也可以基于其他任何目录创建分支,因此 SVN 很难画出一个有意义的分支图。再加上一次提交可以同时包含针对不同分支的文件变更,使得事情变得更糟。
 虽然 SVN在1.5版之后拥有了合并追踪功能,但这个功能会因为混乱的分支管理而被抵消。
2009 年年底,SVN 由 CollabNet 公司交由 Apache 社区管理,至此 SVN 成为了 Apache 组织的一个子项目①。这对 SVN 到底意味着什么?是开发的停滞?还是新的开始?结果如何我们将拭目以待。
1.4 Git—Linus 的第二个伟大作品
Linux 之父 Linus是坚定的 CVS 反对者,他也同样地反对 SVN。这就是为什么在 1991-2002 这十余年间,Linus 宁可以手工修补文件的方式维护代码,也迟迟不愿使用 CVS的原因。我想在当时要想劝说 Linus 使用 CVS 只有一个办法:把 CVS 服务器请进 Linus 的卧室,并对外配以千兆带宽。
 2002年至2005 年, Linus 顶着开源社区精英们口诛笔伐的压力,选择了一个商业版本控制系统 BitKeeper 作为 Linux 内核的代码管理工具②。BitKeeper不同于 CVS和SVN等集中式版本控制工具,而是一款分布式版本控制工具。
分布式版本控制系统最大的反传统之处在于,可以不需要集中式的版本库,每个人都工作在通过克隆建立的本地版本库中。也就是说每个人都拥有一个完整的版本库,查看提交日志、提交、创建里程碑和分支、合并分支、回退等所有操作都直接在本地完成而不需要网络连接。每个人都是本地版本库的主人,不再有谁能提交谁不能提交的限制,加上多样的协同工作模型(版本库间推送、拉回,以及补丁文件传送等)让开源项目的参与度有爆发式增长。
2005年发生的一件事最终导致了 Git 的诞生。在2005年4月,Andrew Tridgell(即大名鼎鼎的 Samba 的作者)试图对 BitKeeper 进行反向工程,以开发一个能与 BitKeeper 交互的开源工具。这激怒了 BitKeeper 软件的所有者 BitMover 公司,要求收回对 Linux 社区免费使用 BitKeeper 的授权③。迫不得已,Linus选择了自己开发一个分布式版本控制工具以替代 BitKeeper。以下是Git诞生过程中的大事记④:
 2005年4月3日,开始开发 Git。
 2005年4月6日,项目发布。
 2005年4月7日,Git就可以作为自身的版本控制工具了。
 2005年4月18日,发生第一个多分支合并。
 2005年4月29日,Git的性能就已经达到了 Linus 的预期。
 2005年6月16日,Linux内核2.6.12 发布,那时 Git 已经在维护 Linux 核心的源代码了。
Linus以一个文件系统专家和内核设计者的视角对 Git 进行了设计,其独特的设计让 Git 拥有非凡的性能和最为优化的存储能力。完成原型设计后,在2005年7月26日,Linus功成身退,将 Git 的维护交给另外一个 Git 的主要贡献者 Junio C Hamano①,直到现在。
最初的 Git 除了一些核心命令以外,其他的都用脚本语言开发,而且每个功能都作为一条独立的命令,例如克隆操作用 git-clone ,提交操作用 git-commit 。这导致 Git 拥有庞大的命令集,使用习惯也和其他版本控制系统格格不入。随着 Git 的开发者和使用者的增加,Git 也在逐渐演变,例如到 1.5.4 版本时,将一百多个独立的命令封装为一个 git 命令,使它看起来更像是一个独立的工具,也使Git更贴近于普通用户的使用习惯。
经过短短几年的发展,众多的开源项目都纷纷从 SVN 或其他版本控制系统迁移到 Git。虽然版本控制系统的迁移过程是痛苦的,但是因为迁移到Git会带来开发效率的极大提升,以及巨大的效益,所以很快就会忘记迁移的痛苦过程,而且很快就会适应新的工作模式。在Git的官方网站上列出了几个使用 Git 的重量级项目,每一个都是人们耳熟能详的,除了 Git 和 Linux 内核外,还有Perl、Eclipse、Gnome、KDE、Qt、Ruby on Rails、Android、PostgreSQL、Debian、X.org,当然还有 GitHub 的上百万个项目。
Git 虽然是在 Linux 下开发的,但现在已经可以跨平台运行在所有主流的操作系统上,包括 Linux、Mac OS X 和 Windows 等。可以说每一个使用计算机的用户都可以分享 Git 带来的便利和快乐。

 

 

第2章 爱上 Git 的理由 Top

   本章将通过一些典型应用展示 Git 作为版本控制系统的独特用法,不熟悉版本控制系统的读者可以通过这些示例对版本控制拥有感性的认识。如果是有经验的读者,示例中Git和SVN的对照可以让您体会到 Git 的神奇和强大。本章将列举 Git 的一些闪亮特性,期待能够让您爱上 Git。

2.1 每日工作备份 Top

      当我开始撰写本书时才明白写书真的是一个辛苦活。如何让辛苦的工作不会因为笔记本硬盘的意外损坏而丢失?如何防范灾害而不让一个篮子里的鸡蛋都毁于一旦?下面就介绍一下我在写本书时是如何使用 Git 进行文稿备份的,请看图2-1。



 如图2-1所示,我的笔记本在公司局域网里的IP地址是 192.168.0.100,公司的Git服务器的IP地址是 192.168.0.2。公司使用动态IP上网因而没有固定的外网IP,但是公司在数据中心有托管服务器,拥有固定的IP地址,其中一台服务器用作Git服务器镜像。
我的写书习惯大概是这样:在写完一个小节或是画完一张图后,我会执行下面的命令提交一次。每一天平均提交3-5次。提交是在本地完成的,因此在图中没有表示出来。
$ git add -u    # 如果创建了新文件,可以执行 git add -i 命令。
$ git commit
下班后,我会执行一次推送操作,将我在本地Git版本库中的提交同步到公司的Git服务器上。相当于图2-1中的步骤① 。
$ git push
因为公司的Git服务器和异地数据中心的Git服务器建立了镜像,所以每当我向公司内网服务器推送的时候,就会自动触发从内网服务器到外网Git服务器的镜像操作。这相当于图2-1中的步骤②,步骤②是自动执行的,无须人工干预。图2-1中标记为 mirror 的版本库就是Git镜像版本库,该版本库只向用户提供只读访问服务,而不能对其进行写操作(推送)。
从图2-1中可以看出,我的每日工作保存有三个拷贝,一个在笔记本中,一个在公司内网的服务器上,还有一个在外网的镜像版本库中。鸡蛋分别装在了三个篮子里。
关于如何架设可以实时镜像的 Git 服务器,会在本书第5篇第30章中详细介绍。

2.2 异地协同工作 Top

    为了能够加快写书的进度,熬夜是必须的,这就出现了在公司和家里两地工作同步的问题。图2-2用于说明我是如何解决两地工作同步问题的。

 

       我在家里的电脑IP地址是 10.0.0.100(家里也有一个小局域网)。如果在家里有时间工作的话,首先要做的就是图2-2中步骤③的操作:将mirror版本库中的数据同步到本地。只需要一条命令就好了:
$ git pull mirror master
然后在家里的电脑上继续编写书稿并提交。当准备完成一天的工作后,就执行下面的命令,相当于图2-2中步骤④的操作:将在家中的提交推送到标记为 home 的版本库中。
$ git push home
为什么还要再引入另外一个名为 home 的版本库呢?使用 mirror 版本库不好么?不要忘了 mirror 版本库只是一个镜像库,不能提供写操作。
当一早到公司,开始动笔写书之前,先要执行图2-2中步骤⑤的操作,从home版本库将家里做的提交同步到公司的电脑中。
$ git pull home master
公司的小崔是我这本书的忠实读者,每当有新章节完成,他都会执行图2-2中步骤⑥的工作,从公司内网服务器获取我最新的文稿。
$ git pull
一旦发现文字错误,小崔会直接在文稿中修改,然后推送到公司的服务器上(图2-2中步骤⑦)。当然他的这个推送也会自动同步到外网的 mirror 版本库。
$ git push
而我只要执行 git pull 操作就可以获得小崔对文稿的修订(图2-2中的步骤⑧)。采用这种工作方式,文稿竟然分布在5台电脑上拥有6个拷贝,真可谓狡兔三窟。不,比狡兔还要多三窟。
在本节中,出现在 Git 命令中的mirror和home是和工作区关联的远程版本库。关于如何注册和使用远程版本库,请参见本书第3篇第19章中的内容。

2.3 现场版本控制 Top

      所谓现场版本控制,就是在客户现场或在产品部署的现场进行源代码的修改,并在修改过程中进行版本控制,以便在完成修改后能够将修改结果甚至修改过程一并带走,并能够将修改结果合并至项目对应的代码库中。

1. SVN 的解决方案
如果使用 SVN 进行版本控制,首先要将服务器上部署的产品代码目录变成 SVN 工作区,这个过程不仅不简单,而且会显得很繁琐,最后将改动结果导出也非常不方便,具体操作过程如下。
(1)在其他位置建立一个 SVN 版本库。
$ svnadmin create /path/to/repos/project1
(2)在需要版本控制的目录下检出刚刚建立的空版本库。
$ svn checkout file:///path/to/repos/project1 .
(3)执行添加文件操作,然后执行提交操作。这个提交将是版本库中编号为1的提交。
$ svn add *
$ svn ci -m "initialized"
(4)开始在工作区中修改文件并提交。
$ svn ci
(5)如果对修改结果满意,可以通过创建补丁文件的方式将工作成果保存并带走。但是 SVN 很难针对每次提交逐一创建补丁,一般用下面的命令与最早的提交进行比较,以创建出一个大补丁文件。
$ svn diff -r1 > hacks.patch
上面用 SVN 将工作成果导出的过程存在一个致命的缺陷,就是 SVN 的补丁文件不支持二进制文件,因此采用补丁文件的方式有可能丢失数据,如新增或修改的图形文件会丢失。更为稳妥但也更为复杂的方式可能要用到 svnadmin 命令将版本库导出。命令如下:
$ svnadmin dump --incremental -r2:HEAD \
/path/to/repos/project1/ > hacks.dump
将svnadmin命令创建的导出文件恢复到版本库中也非常具有挑战性,这里就不再详细说明了。还是来看看 Git 在这种情况下的表现吧。

2. Git 的解决方案
与SVN将产品部署目录转化为SVN的工作区相比, Git 要更为简单,而且使用 Git导出提交历史也更为简单和实用,具体操作过程如下。
(1)创建现场版本库。直接在需要版本控制的目录下执行 Git 版本库初始化命令。
$ git init
(2)添加文件并提交。
$ git add -A
$ git commit -m "initialized"
(3)为初始提交建立一个里程碑:“v1”。
$ git tag v1
(4)开始在工作区中工作—修改文件并提交。
$ git commit -a
(5)当对修改结果满意并想将工作成果保存带走时,可以通过下面的命令将从 v1 开始的历次提交逐一导出为补丁文件。转换的补丁文件都包含一个数字前缀,并提取提交日志信息作为文件名,而且补丁文件还提供对二进制文件的支持。下面命令的输出摘自本书第3篇第20章中的实例。
$ git format-patch v1..HEAD
0001-Fix-typo-help-to-help.patch
0002-Add-I18N-support.patch
0003-Translate-for-Chinese.patch
(6)通过邮件将补丁文件发出。当然,也可以通过其他方式将补丁文件带走。
$ git send-email *.patch
Git 创建的补丁文件使用了 Git 扩展格式,因此在导入时为了避免数据遗漏,要使用 Git 提供的命令而不能使用 GNU的patch 命令。即使要导入的不是 Git 版本库,也可以使用 Git 命令,具体操作请参见本书第7篇第38章中的相关内容。

 

2.4 避免引入辅助目录 Top

     很多版本控制系统都要在工作区中引入辅助目录或文件,如SVN要在工作区的每一个子目录下都创建.svn目录,CVS要在工作区的每一个子目录下都创建CVS目录。
这些辅助目录如果出现在服务器上,尤其是Web服务器上是非常危险的,因为这些辅助目录下的 Entries 文件会暴露出目录下的文件列表,让管理员精心配置的禁止目录浏览的努力全部白费。
还有,SVN的 .svn 辅助目录下还存在文件的原始拷贝,在文件搜索时结果会加倍。如果你曾经在SVN的工作区用过 grep 命令进行内容查找,就会明白我指的是什么。
     Git没有这个问题,不会在子目录下引入讨厌的辅助目录或文件(.gitignore 和 .gitattributes 文件不算)。当然,Git还是要在工作区的顶级目录下创建名为.git的目录(版本库目录),不过,如果你认为唯一的一个 .git 目录也过于碍眼,可以将其放到工作区之外的任意目录。一旦这么做了,在执行Git命令时,就要通过命令行(--git-dir)或环境变量GIT_DIR为工作区指定版本库目录,甚至还要指定工作区目录。
     Git 还专门提供了一个 git grep 命令,这样在工作区根目录下执行查找时,目录.git也不会对搜索造成影响。
     关于辅助目录的详细讨论请参见本书第2篇第4.2节中的内容。

2.5 重写提交说明 Top

很多人可能像我一样,在敲下回车之后才发现提交说明中有错别字,或忘记了写关联的 Bug ID,此时就需要重写提交说明。

1. SVN 的解决方案
在默认情况下,SVN的提交说明是禁止更改的,因为SVN的提交说明属于不受版本控制的属性,一旦修改就不可恢复。我建议SVN的管理员只有在配置了版本库更改的外发邮件通知之后,再开放提交说明更改的功能。我发布于 SourceForge 上的 pySvnManager 项目提供了SVN版本库图形化的钩子管理,会简化管理员的配置工作。
即使SVN管理员启用了允许更改提交说明的设置,修改提交说明也还是挺复杂的,看看下面的命令:
$ svn ps --revprop -r <REV> svn:log "new log message..."

2. Git 的解决方案
Git 修改提交说明很简单,而且提交说明的修改也是被追踪的。Git 修改最新提交的提交说明最为简单,使用一条名为修补提交的命令即可。
$ git commit --amend
这个命令如果不带-m参数,会进入提交说明编辑界面,修改原来的提交说明,直到满意为止。
如果要修改某个历史提交的提交说明,Git 也可以实现,但要用到另外一个命令:变基命令。例如,要修改 <commit-id> 所标识的提交的提交说明,执行下面的命令,并在弹出的变基索引文件中修改相应提交前面的动作的关键字。
$ git rebase -i <commit-id>^
关于如何使用交互式变基操作更改历史提交的提交说明,请参见本书第2篇第12章中的内容。

 

2.6 想吃后悔药 Top

假如提交的数据中不小心包含了一个不应该检入的虚拟机文件—大约有1个GB!这时候,您会多么希望这个世界上有后悔药卖啊。

1. SVN 的解决方案
SVN 遇到这个问题该怎么办呢?删除错误加入的大文件后再提交,这样的操作是不能解决问题的。虽然表面上去掉了这个文件,但是它依然存在于历史中。
管理员可能是受影响最大的人,因为他要负责管理服务器的磁盘空间占用及版本库的备份。实际上这个问题也只有管理员才能解决,所以你必须向管理员坦白,让他帮你在服务器端彻底删除错误引入的大文件。我要告诉你的是,对于管理员,这并不是一个简单的活。
(1)如果SVN管理员没有历史备份,只能重新用svnadmin dump导出整个版本库。
(2)再用svndumpfilter命令过滤掉不应检入的大文件。
(3)然后用svnadmin load重建版本库。
上面的操作描述中省略了一些窍门,如果要把窍门讲清楚,这本书就不是讲 Git,而是讲 SVN 了,故本书中不进行深入探讨。

2. Git 的解决方案
如果你用Git,一切就会变得非常简单,而且你也不必去乞求管理员,因为使用 Git,每个人都是管理员。
如果是最新的提交引入了不该提交的大文件:winxp.img,操作起来会非常简单,还是用修补提交命令。
$ git rm --cached winxp.img
$ git commit --amend
如果是历史版本,例如是在<commit-id>所标识的提交中引入的文件,则需要使用变基操作。
$ git rebase -i <commit-id>^
执行交互式变基操作抛弃历史提交,版本库还不能立即瘦身,具体原因和解决方案请参见本书第2篇第14章中的内容。除了使用变基操作,Git 还有更多的武器可以实现版本库的整理操作,具体请参见本书第6篇第35.4节的内容。

2.7 更好用的提交列表 Top

正确的版本控制系统的使用方法是,一次提交只干一件事:或是完成了一个新功能,或是修改了一个Bug、或是写完了一节的内容,或是添加了一幅图片,就执行一次提交。不要在下班时才想起来要提交,那样的话版本控制系统就被降格为文件备份系统了。
但有时在同一个工作区中可能要同时做两件事情:一个是尚未完成的新功能,另外一个是解决刚刚发现的 Bug。很多版本控制系统没有提交列表的概念,要么需要在命令行中指定要提交的文件,要么默认把所有修改内容全部提交,破坏了一次提交只干一件事的原则。

1. SVN 的解决方案
SVN 1.5开始提供变更列表(change list)的功能,是通过引入一个新的命令svn changelist 来实现的。但是我从来就没有真正用过,因为:
定义一个变更列表太麻烦。例如,没有一个快捷命令将当前所有改动的文件加入列表,也没有快捷命令将工作区中的新文件全部加入列表。
一个文件不能同时属于两个变更列表。两次变更不许有文件交叉,这样的限制不合理。
变更列表是一次性的,提交之后自动消失。这样的设计没有问题,但是相比定义列表时的繁琐,以及提交时必须指定列表的繁琐,使用变更列表未免得不偿失。
因为 Subversion 的提交不能撤销,如果在提交时忘了提供变更列表名称以针对特定的变更列表进行提交,错误的提交内容将无法补救。
总之,SVN 的变更列表尚不如鸡肋,食之无味,弃之不可惜。

2. Git 的解决方案
Git 通过提交暂存区实现对提交内容的定制,非常完美地实现了对工作区的修改内容进行筛选提交:
执行git add命令将修改内容加入提交暂存区。执行 git add -u 命令可以将所有修改过的文件加入暂存区,执行 git add -A命令可以将本地删除文件和新增文件都登记到提交暂存区,执行git add -p命令甚至可以对一个文件内的修改进行有选择性的添加。
一个修改后的文件被登记到提交暂存区后,可以继续修改,继续修改的内容不会被提交,除非对此文件再执行一次 git add 命令。即一个修改的文件可以拥有两个版本,在提交暂存区中有一个版本,在工作区中有另外一个版本。
执行 git commit 命令提交,无须设定变更列表,直接将登记在暂存区中的内容提交。
Git 支持撤销提交,而且可以撤销任意多次。
只要使用 Git,就会时刻与隐形的提交列表打交道。本书第2篇第5章会详细介绍 Git 的这一特性,相信你会爱上 Git 的这个特性。

2.8 更好的差异比较 Top

     Git 对差异比较进行了扩展,支持对二进制文件的差异比较,这是对GNU的diff和patch命令的重要补充。而且Git 的差异比较除了支持基于行的差异比较外,还支持在一行内逐字比较的方式,当向 git diff 命令传递 --word-diff 参数时,就会进行逐字比较。
上面介绍了工作区的文件修改可能会有两个不同的版本:一个在提交暂存区,一个在工作区。因此,在执行 git diff 命令时会遇到令 Git 新手费解的现象。
     修改后的文件在执行 git diff 命令时会看到修改造成的差异。
     修改后的文件通过 git add 命令提交到暂存区后,再执行 git diff 命令将看不到该文件的差异。
     继续对此文件进行修改,再次执行 git diff 命令会看到新的修改显示在差异中,而看不到旧的修改。
     执行 git diff --cached 命令才可以看到添加到暂存区中的文件所做出的修改。
Git 差异比较的命令充满了魔法,本书第5.3节会带您破解 Git 的 diff 魔法。一旦您习惯了,就会非常喜欢 git diff 的这个行为。

2.9 工作进度保存 Top

如果在工作区的修改尚未完成时忽然有一个紧急的任务,需要从一个干净的工作区开始新的工作,或要切换到别的分支进行工作,那么如何保存当前尚未完成的工作进度呢?

1. SVN 的解决方案
如果版本库规模不大,最好重新检出一个新的工作区,在新的工作区进行工作。否则,可以执行下面的操作。
$ svn diff > /path/to/saved/patch.file
$ svn revert -R
$ svn switch <new_branch>
在新的分支中工作完毕后,再切换回当前分支,将补丁文件重新应用到工作区。
$ svn switch <original_branch>
$ patch -p1 < /path/to/saved/patch.file
但是切记 SVN 的补丁文件不支持二进制文件,这种操作方法可能会丢失对二进制文件的更改!

2. Git 的解决方案
Git 提供了一个可以保存和恢复工作进度的命令 git stash 。这个命令非常方便地解决了这个难题。
在切换到新的工作分支之前执行 git stash 保存工作进度,工作区就会变得非常干净,然后就可以切换到新的分支中了。
$ git stash
$ git checkout <new_branch>
新的工作分支修改完毕后,再切换回当前分支,调用 git stash pop 命令则可恢复之前保存的工作进度。
$ git checkout <orignal_branch>
$ git stash pop
本书第2篇第9章会为您揭开 git stash 命令的奥秘。

2.10 代理SVN提交实现移动式办公 Top

      使用像SVN一样的集中式版本控制系统,要求使用者和版本控制服务器之间要有网络连接,如果因为出差在外或在家办公访问不到版本控制服务器就无法提交。Git 属于分布式版本控制系统,不存在这样的问题。
当版本控制服务器无法实现从SVN到Git的迁移时,仍然可以使用Git进行工作。在这种情况下,Git作为客户端来操作SVN服务器,实现在移动办公状态下的版本提交(当然是在本地Git库中提交)。当能够连通SVN服务器时,一次性将移动办公状态下的本地提交同步到SVN服务器。整个过程对于SVN来说是透明的,没有人知道你是使用Git在进行提交。
使用Git来操作SVN版本控制服务器的一般工作流程为:
(1)访问SVN服务器,将SVN版本库克隆为一个本地的Git库,一个货真价实的Git库,不过其中包含针对SVN的扩展。
$ git svn clone <svn_repos_url>
(2)使用Git命令操作本地克隆的版本库,例如提交就使用 git commit 命令。
(3)当能够通过网络连接到SVN服务器,并想将本地提交同步到SVN服务器时,先获取SVN服务器上最新的提交,然后执行变基操作,最后再将本地提交推送给SVN服务器。
$ git svn fetch
$ git svn rebase
$ git svn dcommit
本书第4篇第26章会详细介绍这一话题。

2.11 无处不在的分页器 Top

虽然拥有图形化的客户端,但 Git 的主要操作还是以命令行的方式完成的。使用命令行方式的好处一个是快,另外一个是可以防止鼠标手的出现。Git 的命令行加入了大量的人性化设计,包括命令补全、彩色字符输出①等,不过最具特色的还是无处不在的分页器。
在操作其他版本控制系统的命令行时,如果命令的输出超过了一屏,为了能够逐屏显示,需要在命令的后面加上一个管道符号将输出交给一个分页器。例如:
$ svn log | less
而 Git 则不用如此麻烦,因为每个 Git 命令自动带有一个分页器,默认使用 less 命令(less -FRSX )进行分页。当一屏显示不下时启动分页器,这个分页器支持带颜色的字符输出,对于太长的行则采用截断方式处理。因为 less 分页器在翻屏时使用了 vi 风格的热键,如果您不熟悉 vi 的话,可能会遇到麻烦。下面是分页器中常用的热键:
字母 q :退出分页器。
字母 h :显示分页器帮助。
按空格下翻一页,按字母 b 上翻一页。
字母 d 和 u :分别代表向下翻动半页和向上翻动半页。
字母 j 和 k :分别代表向上翻一行和向下翻一行。
如果行太长被截断,可以用左箭头和右箭头使窗口内容左右滚动。
输入/pattern :向下寻找和 pattern 匹配的内容。
输入?pattern :向上寻找和 pattern 匹配的内容。
字母n或N:代表向前或向后继续寻找。
字母g:跳到第一行;字母 G:跳到最后一行;输入数字再加字母g:则跳转到对应的行。
输入 !<command> :可以执行 Shell 命令。
如果不习惯分页器的长行截断模式而希望能够自动换行,可以通过设置 LESS 环境变量来实现。LESS 环境变量设置如下:
$ export LESS=FRX
或者使用 Git 的方式,通过定义 Git 配置变量来改变分页器的默认行为。例如设置 core.pager 配置变量如下:
$ git config --global core.pager 'less -+$LESS -FRX'

2.12 快 Top

     您有项目托管在 sourceforge.net 的 CVS 或 SVN 服务器上么?是否会因为公司的SVN服务器部署在另外一个城市而需要经过互联网才能访问?
使用传统的集中式版本控制服务器时,如果遇到上面的情况,而且网络带宽没有保证,那么使用起来时一定会因为速度慢而让人痛苦不堪。Git 作为分布式版本控制系统彻底解决了这个问题,几乎所有的操作都在本地进行,而且速度还不是一般的快。
     还有很多其他的分布式版本控制系统,如Hg和Bazaar 等,与这些分布式版本控制系统相比,Git在速度上也有优势,这得益于Git独特的版本库设计。第2篇的相关章节会向您展示 Git 独特的版本库设计。
其他很多的版本控制系统,当输入检出、更新或克隆等命令后,只能双手合十,然后望眼欲穿,因为整个操作过程不知道什么时候才能够完成。而 Git 在版本库克隆及与版本库同步的时候,能够实时地显示完成的进度,这不但是非常人性化的设计,更体现了 Git 的智能。Git 的智能协议源自于会话过程中在客户端和服务器端各自启用了一个会话的角色,用于按需传输和获取进度。

第3章 Git的安装和使用 Top

      Git 源自 Linux,现在已经可以部署在所有的主流平台之上,包括 Linux、Mac OS X 和 Windows。我们在开始 Git 之旅之前,首先要做的就是安装 Git。

3.1 在Linux 下安装和使用 Git Top

     Git 诞生于 Linux 平台并作为版本控制系统率先服务于Linux内核,因此在 Linux 上安装 Git 是非常方便的。可以通过两种不同的方式在 Linux 上安装 Git:一种方法是通过 Linux 发行版的包管理器安装已经编译好的二进制格式的Git软件包,另外一种方式就是从 Git 源码开始安装。

3.1.1 包管理器方式安装 Top

用 Linux 发行版的包管理器安装 Git最为简单,而且会自动配置好命令补齐等功能,但安装的 Git 可能不是最新的版本。还有一点要注意,Git软件包在有的 Linux 发行版中可能不叫 git,而叫 git-core。这是因为有一款名为 GNU 交互工具①(GNU Interactive Tools)的 GNU 软件,在 Git 之前就在一些 Linux 发行版(Deian lenny)中占用了 git 这个名称。为了以示区分,作为版本控制系统的 Git ,其软件包在这些平台就被命名为 git-core。不过,因为作为版本控制系统的 Git 太有名了,所以一些 Linux 发行版在最新的版本中将 GNU Interactive Tools 软件包的名称由 git 改为了 gnuit,将 git-core 改为了 git。因此在下面介绍的在不同的 Linux 发行版中安装 Git 时,会看到有 git 和 git-core 两个不同的名称。
Ubuntu 10.10(maverick)或更新的版本、Debian(squeeze)或更新的版本:
$ sudo aptitude install git
$ sudo aptitude install git-doc git-svn git-email git-gui gitk
其中 git 软件包包含了大部分 Git 命令,是必装的软件包。
软件包 git-svn、git-email、git-gui、gitk 本来也是 Git 软件包的一部分,但是因为有着不一样的软件包依赖(如更多的 perl 模组和tk等),所以单独作为软件包发布。
软件包 git-doc 则包含了 Git 的 HTML 格式文档,可以选择安装。如果安装了 Git 的 HTML 格式的文档,则可以通过执行 git help -w <sub-command> 命令来自动用 Web 浏览器打开相关子命令 <sub-command> 的 HTML 帮助。
Ubuntu 10.04(lucid)或更老的版本、Debian(lenny)或更老的版本:
在老版本的 Debian 中,软件包 git 实际上是指 GNU Interactive Tools,而非作为版本控制系统的 Git。作为版本控制系统的 Git 在软件包 git-core 中。
$ sudo aptitude install git-core
$ sudo aptitude install git-doc git-svn git-email git-gui gitk
RHEL、Fedora、CentOS:
$ yum install git
$ yum install git-svn git-email git-gui gitk
在其他发行版中安装 Git 的过程和上面介绍的方法类似。Git 软件包在这些发行版里或称为 git,或称为 git-core。

3.1.2 从源代码进行安装 Top

访问 Git 的官方网站:http://git-scm.com/ 。下载 Git 源码包,例如:git-1.7.4.1.tar.bz2①。安装过程如下:
(1)展开源码包,并进入到相应的目录中。
$ tar -jxvf git-1.7.4.1.tar.bz2
$ cd git-1.7.4.1/
(2)安装方法写在INSTALL文件中,参照其中的指示即可完成安装。下面的命令将 Git 安装在/usr/local/bin中。
$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install
(3)安装 Git 文档(可选)。
编译的文档主要是 HTML 格式的文档,方便通过git help -w <sub-command> 命令查看。实际上,即使不安装 Git 文档,也可以使用 man 手册查看 Git 帮助,使用命令git help <sub-command>或git <sub-command> --help即可。
编译文档依赖 asciidoc,因此需要先安装 asciidoc(如果尚未安装的话),然后编译文档。在编译文档时要花费很多时间,要有耐心。
$ make prefix=/usr/local doc info
$ sudo make prefix=/usr/local install-doc install-html install-info
安装完毕之后,就可以在/usr/local/bin下找到git命令。

3.1.3 从Git版本库进行安装 Top

如果在本地克隆一个 Git 项目的版本库,就可以用版本库同步的方式获取最新版本的 Git,这样在下载不同版本的 Git 源代码时实际上采用了增量方式,非常节省时间和空间。当然使用这种方法的前提是已经用其他方法安装好了 Git,具体操作过程如下。
(1)克隆 Git 项目的版本库到本地。
$ git clone git://git.kernel.org/pub/scm/git/git.git
$ cd git
(2)如果本地已经克隆过一个 Git 项目的版本库,直接在工作区中更新,以获得最新版本的 Git。
$ git fetch
(3)执行清理工作,避免前一次编译的遗留文件对编译造成影响。注意,下面的操作将丢弃本地对 Git 代码的改动。
$ git clean -fdx
$ git reset --hard
(4)查看 Git 的里程碑,选择最新的版本进行安装,例如 v1.7.4.1 。
$ git tag
...
v1.7.4.1
(5)检出该版本的代码。
$ git checkout v1.7.4.1
(6)执行安装。例如,安装到/usr/local目录下。
$ make prefix=/usr/local all doc info
$ sudo make prefix=/usr/local install \
  install-doc install-html install-info
我在撰写本书的过程中,就是通过 Git 版本库的方式安装的,在/opt/git目录下安装了多个不同版本的 Git,以测试 Git 的兼容性。可以使用类似下面的脚本来批量安装不同版本的 Git。
#!/bin/sh

for ver in      \
    v1.5.0      \
    v1.7.3.5    \
    v1.7.4.1    \
; do
    echo "Begin install Git $ver.";
    git reset --hard
    git clean -fdx
    git checkout $ver || {
        echo "Checkout git $ver failed."; exit 1
    }
    make prefix=/opt/git/$ver all && \
    sudo make prefix=/opt/git/$ver install || {
        echo "Install git $ver failed."; exit 1
    }
    echo "Installed Git $ver."
done

3.1.4 命令补齐 Top

Linux 的 shell 环境(bash)通过 bash-completion 软件包提供命令补齐功能,在录入命令参数时按一次或两次TAB 键可实现参数的自动补齐或提示。例如输入 git com 后按下 TAB 键,会自动补齐为 git commit 。
如果通过包管理器方式安装 Git,一般都已经为 Git 配置好了自动补齐,但是如果是以源码编译的方式安装 Git,就需要为命令补齐多做些工作,具体操作过程如下。
(1)将 Git 源码包中的命令补齐脚本复制到 bash-completion 对应的目录中。
$ cp contrib/completion/git-completion.bash \
      /etc/bash_completion.d/
(2)重新加载自动补齐脚本,使之在当前的 shell 中生效。
$ . /etc/bash_completion
(3)为了能够在终端开启时自动加载bash_completion脚本,需要在系统配置文件/etc/profile①及本地配置文件~/.bashrc ②中添加下面的内容。
if [ -f /etc/bash_completion ]; then
  . /etc/bash_completion
fi

3.1.5 中文支持 Top

Git 的本地化做得并不完善,命令的输出及命令的帮助还只能输出英文,也许在未来的版本中会使用 gettext 实现本地化,就像目前对 git-gui 命令所做的那样。
中文用户最关心的问题还有:是否可以在提交说明中使用中文?是否可以使用中文文件名或目录名?是否可以使用中文来命名分支或里程碑?简单地说,可以在提交说明中使用中文,但是需要对 Git进行设置。至于用中文来命名文件、目录和引用,只有在使用 UTF-8 字符集的环境下(Linux、Mac OS X、Windows下的Cygwin)才可以,否则应尽量避免使用。
1. UTF-8 字符集
Linux 平台的中文用户一般会使用 UTF-8 字符集,Git在 UTF-8 字符集下可以工作得非常好:
在提交时,可以在提交说明中输入中文。
显示提交历史,能够正常显示提交说明中的中文字符。
可以添加名称为中文的文件,并可以在同样使用UTF-8字符集的 Linux 环境中克隆和检出。
可以创建带有中文字符的里程碑名称。
但是,在默认设置下,中文文件名在工作区状态输出、查看历史更改概要,以及在补丁文件中,文件名中的中文不能正确地显示,而是显示为八进制的字符编码,如下:
$ git status -s
?? "\350\257\264\346\230\216.txt"
$ printf "\350\257\264\346\230\216.txt\n"
说明.txt
通过将Git配置变量 core.quotepath 设置为 false ,就可以解决中文文件名在这些 Git 命令输出中的显示问题。
$ git config --global core.quotepath false
$ git status -s
?? 说明.txt
2. GBK 字符集
如果 Linux 平台采用非 UTF-8 的字符集,例如,用 zh_CN.GBK 字符集编码(有人这么做吗?),就要另外再做些工作了。
将显示提交说明所使用的字符集设置为gbk,这样使用 git log 查看提交说明时才能够正确显示其中的中文。
$ git config --global i18n.logOutputEncoding gbk
设置录入提交说明时所使用的字符集,以便在 commit 对象中正确标注字符集。
Git 在提交时并不会对提交说明进行从 GBK 字符集到 UTF-8 的转换,但是可以在提交说明中标注所使用的字符集,因此在非 UTF-8 字符集的平台中录入中文时需要用下面的指令设置录入提交说明的字符集,以便在 commit 对象中嵌入正确的编码说明。
$ git config --global i18n.commitEncoding gbk
3.2 在Mac OS X 下安装和使用 Git
Mac OS X 被称为最人性化的操作系统之一,工作在 Mac 上是件非常惬意的事情,工作中又怎能没有 Git呢?

3.2.1 以二进制发布包的方式安装 Top

Git 在 Mac OS X 中也有好几种安装方法。最简单的方式是安装 .dmg 格式的安装包。
访问 git-osx-installer 的官方网站:http://code.google.com/p/git-osx-installer/,下载 Git 安装包。安装包带有 .dmg 扩展名,是苹果磁盘镜像(Apple Disk Image)格式的软件发布包。从官方网站上下载文件名格式为 git-<version>-<arch>-leopard.dmg 的安装包文件,例如:git-1.7.4-x86_64-leopard.dmg 是 64 位的安装包,git-1.7.4-i386-leopard.dmg 是 32 位的安装包。建议选择 64 位的软件包,因为 Mac OS X 10.6(雪豹)完美地兼容 32 位和 64位(开机按住键盘数字3和2进入32位系统,按住6和4进入64位系统),即使内核的架构是32位的,也可以放心地运行64位的软件包。
苹果的.dmg格式的软件包实际上是一个磁盘映像,安装起来非常方便,点击该文件就可以直接挂载到 Finder 中,打开后如图3-1所示。


图3-1中显示为拆包图标的文件(扩展名为 .pkg)就是 Git 的安装程序,另外的两个脚本程序,一个用于应用的卸载(uninstall.sh),另外一个带有长文件名的脚本在 Git 安装后再执行,为非终端应用注册 Git 的安装路径,这是因为 Git 部署在标准的系统路径之外 /usr/local/git/bin 。
点击扩展名为 .pkg 的安装程序,开始 Git 的安装(以安装Git1.7.3.5版本为例),根据提示按步骤完成安装,如图3-2所示。
安装完毕后,Git 会被安装到 /usr/local/git/bin/ 目录下。重启终端程序,这样/etc/paths.d/git 文件为 PATH 环境变量中添加的新路径注册才能生效,然后就可以在终端直接运行 git 命令了。

3.2.2 安装 Xcode Top

Mac OS X 基于 Unix 内核开发,因此也可以很方便地通过源码编译的方式进行安装,但是默认安装的 Mac OS X 缺乏相应的开发工具,需要安装苹果提供的 Xcode 软件包。在 Mac 随机附送的光盘(Mac OS X Install DVD)的可选安装文件夹下就有 Xcode 的安装包(如图3-3所示),通过随机光盘安装 Xcode 可以省去网络下载的麻烦,要知道 Xcode的大小在3GB以上。




3.2.3 使用 Homebrew 安装 Git Top

Mac OS X 有好几个包管理器,用于管理一些开源软件在 Mac OS X 上的安装和升级。有传统的 MacPorts①、Fink②,还有更为简单易用的 Homebrew③。下面就介绍一下如何通过 Homebrew 包管理器来以源码包编译的方式安装 Git。
Homebrew 用Ruby语言开发,支持千余种开源软件在 Mac OS X 中的部署和管理。Homebrew 项目托管在 Github 上,网址为:https://github.com/mxcl/homebrew。
首先是安装 Homebrew,执行下面的命令:
$ ruby -e \
  "$(curl -fsSL https://gist.github.com/raw/323731/install_homebrew.rb)"
安装完成后,Homebrew 的主程序安装在 /usr/local/bin/brew 中,在目录 /usr/local/Library/Formula/ 下保存了Homebrew 支持的所有软件的安装指引文件。
执行下面的命令,通过Homebrew安装Git。
$ brew install git
使用 Homebrew 方式安装,Git 被安装在 /usr/local/Cellar/git/<version>/ 中,可执行程序自动在 /usr/local/bin 目录下创建符号连接,可以直接在终端程序中访问。
通过 brew list 命令可以查看安装的开源软件包。
$ brew list
git
也可以查看某个软件包安装的详细路径和安装内容。
$ brew list git
/usr/local/Cellar/git/1.7.4.1/bin/gitk
...

3.2.4 从Git源码进行安装 Top

如果需要安装历史版本的 Git 或是尚在开发中的未发布版本的 Git,就需要从源码安装或通过克隆 Git 源码库的方式进行安装。既然 Homebrew 就是通过源码编译方式安装 Git 的,那么也应该可以直接从源码进行安装,但是使用 Homebrew 安装 Git 和直接通过 Git 源码安装并不完全等同,例如 Homebrew 安装 Git文档是通过下载已经编译好的 Git 文档包进行安装,而非从头对文档进行编译。
直接通过源码安装 Git 软件及文档,遇到的主要问题就是对文档的编译,因为 Xcode 没有提供 Git 文档编译所需要的相关工具。但是,这些工具可以通过 Homebrew 进行安装。安装工具软件的过程可能会遇到一些小麻烦,不过大多可以通过参考命令输出予以解决。
$ brew install asciidoc
$ brew install docbook2x
$ brew install xmlto
当编译源码及文档的工具部署完成后,就可以通过源码编译 Git。
$ make prefix=/usr/local all doc info
$ sudo make prefix=/usr/local install \
  install-doc install-html install-info

3.2.5 命令补齐 Top

Git 通过 bash-completion 软件包实现命令自动补齐,在 Mac OS X 下可以通过 Homebrew 进行安装。
$ brew search completion
bash-completion
$ brew install bash-completion
...
Add the following lines to your ~/.bash_profile file:
if [ -f 'brew --prefix'/etc/bash_completion ]; then
  . 'brew --prefix'/etc/bash_completion
fi
...
根据 bash-completion 在安装过程中的提示,修改配置文件 ~/.bash_profile和~/.bashrc,并在其中加入如下内容,以便在终端加载时自动启用命令补齐。
if [ -f 'brew --prefix'/etc/bash_completion ]; then
  . 'brew --prefix'/etc/bash_completion
fi
将 Git 的命令补齐脚本拷贝到 bash-completion 对应的目录中。
$ cp contrib/completion/git-completion.bash \
      'brew --prefix'/etc/bash_completion.d/
不用重启终端程序,只需要运行下面的命令即可立即在当前的 shell 中加载命令补齐。
. 'brew --prefix'/etc/bash_completion

3.2.6 其他辅助工具的安装 Top

本书中还会用到一些常用的 GNU 或其他开源软件,在 Mac OS X 下也可以通过 Homebrew 进行安装。这些软件包括:
gnupg:数字签名和加密工具,在为 Git 版本库建立签名里程碑时会用到。
md5sha1sum:生成 MD5 或 SHA1 摘要,在研究 Git 版本库中的对象时会用到。
cvs2svn:CVS 版本库迁移到 SVN 或 Git 的工具,在版本库迁移时会用到。
stgit:Git 的补丁和提交管理工具。
quilt:一种补丁管理工具,在介绍 StGit 时会用到。
在 Mac OS X 下能够使用到的 Git 图形工具除了 Git 软件包自带的gitk和git gui之外,还有GitX。下载地址为:
GitX 的原始版本:http://gitx.frim.nl/。
GitX 的一个分支版本,提供增强的功能:https://github.com/brotherbard/gitx/downloads。
Git 的图形工具一般需要在本地克隆版本库的工作区中执行,为了能与 Mac OS X 更好地整合,可以通过插件实现与 Finder 的整合。在 git-osx-installer 的官方网站: http://code.google.com/p/git-osx-installer/上有两个以 OpenInGitGui- 和 OpenInGitX- 为前缀的软件包,可以分别实现与 git gui和gitx 的整合:在 Finder 中进入工作区目录,点击对应插件的图标,启动 git gui 或 gitx。

3.2.7 中文支持 Top

       由于 Mac OS X 采用 Unix 内核,在中文支持上与 Linux 相近,具体内容请参照第3.1.5节介绍的在Linux下安装Git的相关内容。

3.3 在Windows 下安装和使用 Git(Cygwin篇) Top

       在Windows下安装和使用 Git 有两种不同的方案:通过安装 msysGit①或Cygwin②来使用 Git。在这两种不同的方案下,Git 的使用与 Linux 环境下完全一致。还可以通过 msysGit 的图形界面软件TortoiseGit③(也就是在 CVS 和 SVN 时代就已经广为人知的 Tortoise 系列软件的 Git 版本)来使用Git。TortoiseGit 可与资源管理器整合,从而提供 Git 操作的图形化界面。
       首先介绍通过 Cygwin 来使用Git,并不是因为这是最便捷的方法。如果需要在 Windows 中快速安装和使用 Git,下一节介绍的 msysGit 才是最便捷的方法。之所以将 Cygwin 放在前面介绍是因为本书在介绍 Git 原理和其他 Git 相关的软件时用到了大量的开源工具,在 Cygwin 下很容易获得这些开源工具,而 msysGit 的 MSYS④(Minimal SYStem,最简系统)则不能满足我们的需求。因此,我建议 Windows 平台下的读者在跟随本书学习 Git 的过程中   首选 Cygwin,当对Git有了一定的了解后,无论是 msysGit 还是 TortoiseGit,您都会应对自如。
Cygwin 是一款伟大的软件,通过一个小小的DLL(cygwin1.dll)建立了 Linux 与 Windows 之间的系统调用和API之间的转换,使得 Linux 下的绝大多数软件能向 Windows 迁移。Cygwin 通过 cygwin1.dll 所建立的中间层与VMWare①、VirtualBox② 等虚拟机软件完全不同,不会独占系统资源。像 VMWare 等虚拟机,只要启动一个虚拟机(操作系统),即使不在其中执行任何命令,同样也会占用大量的内存和CPU时间等系统资源。
Cygwin 还提供了一个强大易用的包管理工具(setup.exe),使得几千个开源软件包能在 Cygwin 下便捷地安装和升级,Git 便是其中的一员。
我对 Cygwin 有着深厚的感情,Cygwin 让我能在 Windows 平台下用 Linux 的方式更有效率地工作,使用 Linux 风格的控制台替换 Windows 黑乎乎的、冷冰冰的、由 cmd.exe 提供的命令行。Cygwin 帮助我逐渐摆脱对 Windows 的依赖,当我完全转换到 Linux 平台时,没有感到一丝的障碍。

 

3.3.1 安装 Cygwin Top

Cygwin 的安装非常简单,先在其官方网站 http://www.cygwin.com/下载安装程序—一个只有几百KB的setup.exe文件,然后即可开始安装。
安装过程中会让用户选择安装模式:通过网络安装、下载后安装或者通过本地软件包缓存(安装时自动在本地目录下建立的软件包缓存)安装。
(1)如果是第一次安装 Cygwin,因为本地尚没有软件包缓存,当然只能选择从网络安装,如图3-4所示。


(2)选择安装目录,默认为 C:\cygwin ,如图3-5所示。这个目录将作为 Cygwin shell 环境的根目录(根卷),Windows 的各个盘符将挂载在根卷的一个特殊目录之下。


(3)设置本地软件包缓存目录,默认为setup.exe 所处的目录,如图3-6所示。


(4)设置网络连接方式是否使用代理等,如图3-7所示。默认会选择第一项:“直接网络连接”。如果一个团队有很多人要使用 Cygwin,架设一个能够提供软件包缓存的 HTTP 代理服务器会节省大量的网络带宽和大量的时间。在 Debian/Ubuntu 下用 apt-cacher-ng①就可以非常简单地搭建一个软件包代理服务器。图3-7显示的就是我在公司内网中安装 Cygwin 时使用内网的服务器 bj.ossxp.com 作为 HTTP 代理的情形,端口设置为 9999,因为这是 apt-cacher-ng 的默认端口。




(5)选择一个 Cygwin 源,如图3-8所示。如果在上一个步骤中选择使用 HTTP 代理服务器,就必须选择 HTTP 协议的 Cygwin 源。


(6)从所选的 Cygwin 源下载软件包索引文件,然后显示软件包管理器界面,如图3-9所示。

 

 Cygwin 的软件包管理器非常强大,而且易于使用(如果习惯了其界面)。软件包归类于各个分组中,点击分组前的加号就可以展开分组。在展开的 Admin 分组中,如图3-10所示(这个截图不是首次安装 Cygwin 的截图),有的软件包(如 libattr1)已经安装过了,因为没有新版本而标记为“Keep”(保持),没有安装过并且不准备安装的软件包则标记为 “Skip”(跳过)。



 (7)点击分组名称后面的动作名称(文字“Default”),会进行软件包安装动作的切换。例如图3-11,将 Admin 分组的安装动作由“Default”(默认)切换为“Install”(安装),会看到 Admin 分组下的所有软件包都标记为安装(显示具体要安装的软件包版本号)。也可以通过鼠标点击,单独为软件包进行安装动作的设定:可以强制重新安装、安装旧版本,或者不安装。



 (8)当通过软件包管理器对要安装的软件包定制完毕后,点击下一步,开始下载软件包、安装软件包和软件包后处理(postinstall),直至完成安装。根据选择的软件包的多少、网络情况,以及是否架设有代理服务器等情况的不同,首次安装 Cygwin 的时间可能从几分钟到几个小时不等。

3.3.2 安装 Git Top

默认安装的 Cygwin 没有安装 Git 软件包。如果在首次安装过程中忘记通过包管理器选择安装 Git 或其他相关软件包,可以在安装后再次运行 Cygwin 的安装程序 setup.exe 。当再次进入 Cygwin 包管理器界面时,在搜索框中输入 git,如图3-12所示。
从图3-12中可以看出在 Cygwin 中包含了很多与 Git 相关的软件包,把这些 Git 相关的软件包全部都安装上吧,如图3-13所示。
需要安装的其他软件包还有:
git-completion:提供 Git 命令的自动补齐功能。安装该软件包时会自动安装其所依赖的 bash-completion 软件包。
openssh:SSH 客户端,为访问 SSH 协议的版本库提供支持。
vim:Git 默认的编辑器。

 

 

 

3.3.3 Cygwin 的配置和使用 Top

运行 Cygwin后会进入 shell 环境并见到熟悉的 Linux 提示符,如图 3-14 所示。
可以通过执行 cygcheck 命令来查看 Cygwin 中安装的软件包的版本。例如,查看 Cygwin 软件包本身的版本:
$ cygcheck -c cygwin
Cygwin Package Information
Package              Version        Status
cygwin               1.7.7-1        OK


1. 如何访问 Windows 的盘符
刚刚接触 Cygwin 的用户遇到的头一个问题就是:Cygwin 如何访问 Windows 的各个磁盘目录,以及在 Windows 平台下如何访问 Cygwin 中的目录。
执行 mount 命令后可以看到 Windows 下的盘符被映射到 /cygdrive 特殊目录下。
$ mount
C:/cygwin/bin on /usr/bin type ntfs (binary,auto)
C:/cygwin/lib on /usr/lib type ntfs (binary,auto)
C:/cygwin on / type ntfs (binary,auto)
C: on /cygdrive/c type ntfs (binary,posix=0,user,noumount,auto)
D: on /cygdrive/d type ntfs (binary,posix=0,user,noumount,auto)
也就是说,在 Cygwin 中以路径 /cygdrive/c/Windows来访问Windows 下的 C:\Windows 目录。实际上, Cygwin 提供 cygpath 命令来实现 Windows 平台和 Cygwin 之间目录名称的变换,如下所示:
$ cygpath -u C:\\Windows
/cygdrive/c/Windows

$ cygpath -w ~/
C:\cygwin\home\jiangxin\
从上面的示例也可以看出,Cygwin 下的用户主目录(即 /home/jiangxin/ )相当于 Windows 下的 C:\cygwin\home\jiangxin\ 目录。
2. 用户主目录不一致的问题
如果某些其他软件(如msysGit)为 Windows 设置了 HOME 环境变量,会影响到 Cygwin 中用户主目录的设置,甚至会造成在 Cygwin 中不同的命令有不同的用户主目录的情况。例如:Cygwin下Git 的用户主目录被设置为 /cygdrive/c/Documents and Settings/jiangxin,而 SSH 客户端软件的主目录被设置为 /home/jiangxin,这会给用户造成困惑。
之所以出现这种情况,是因为 Cygwin 确定用户主目录有几个不同的依据,要按照顺序确定主目录:首先查看系统的 HOME 环境变量,其次查看 /etc/passwd 中为用户设置的主目录。有的软件遵照这个原则,而有些 Cygwin 应用如 SSH,却没有使用 HOME 环境变量而是直接使用 /etc/passwd 中的设置。要想避免在同一个 Cygwin 环境下有两个不同的用户主目录设置,可以采用下面两种方法。
方法1:修改 Cygwin 启动的批处理文件(如:C:\cygwin\Cygwin.bat ),在批处理的开头添加如下的一行代码,就可以防止其他软件在 Windows 引入的 HOME 环境变量被带入到 Cygwin 中。
set HOME=
方法2:如果希望使用 HOME 环境变量指向的主目录,则可通过手工编辑 /etc/passwd 文件,将其中的用户主目录修改成 HOME 环境变量所指向的目录①。
3. 命令行补齐忽略文件名大小写
Windows 的文件系统忽略文件名的大小写,在 Cygwin 下最好对命令行补齐进行相关设置,以忽略大小写,这样使用起来更方便。
编辑文件 ~/.inputrc ,在其中添加设置“set completion-ignore-case on”,或者取消已有的相关设置前面的井(#)号注释符。修改完毕后,再重新进入 Cygwin,这样就可以实现命令行补齐对文件名大小写的忽略。
4. 忽略文件权限的可执行位
Linux、UNIX、Mac OS X通过文件权限中的可执行位判断文件是否可执行,而Windows是通过文件扩展名进行判断的。Git提供对类UNIX系统文件权限的支持,在版本库中建立对可执行文件的追踪。对于Windows平台,Git的这个特性用处不大,甚至有害。因为,虽然 Cygwin 可以模拟 Linux 下的文件授权并对文件的可执行位提供支持,但为支持文件权限而调用Cygwin的stat()函数和lstat()函数会比调用 Windows 自身的 Win32 API 要慢一半②,而且非跨平台的项目也没有必要对文件权限位进行跟踪,甚至 Windows 下的其他工具及操作可能会破坏文件的可执行位,从而导致 Cygwin 下的 Git 认为文件的权限更改需要重新提交。通过下面的配置可以禁止 Git 对文件权限的跟踪:
$ git config --system core.fileMode false
在此模式下,当已添加到版本库中的文件的权限的可执行位改变时,该文件不会显示有改动。版本库中新增的文件,无论文件本身是否设置为可执行,都以 100644 的权限(忽略可执行位)进行添加。
关于 Cygwin 的更多内容,请参见网址http://www.cygwin.com/cygwin-ug-net/中的信息。

3.3.4 Cygwin 下 Git 的中文支持 Top

Cygwin 的当前版本是1.7.x,对中文的支持非常好。无需任何配置就可以在 Cygwin 的窗口内输入中文,执行 ls 命令就可以显示中文的文件名。这与六七年前的 Cygwin 1.5.x 完全不一样了,老版本的 Cygwin 还需要进行一些配置才能在控制台输入中文和显示中文,但是最新版本的 Cygwin 已经完全不需要了。后面要介绍的 msysGit 的 shell 环境仍然需要进行相关的配置(同老版本 Cygwin)才能够正常显示和输入中文。
Cygwin 默认使用 UTF-8 字符集,并能巧妙地与 Windows 系统的字符集进行转换。在 Cygwin 下可执行 locale命令查看Cygwin下正在使用的字符集:
$ locale
LANG=C.UTF-8
LC_CTYPE="C.UTF-8"
LC_NUMERIC="C.UTF-8"
LC_TIME="C.UTF-8"
LC_COLLATE="C.UTF-8"
LC_MONETARY="C.UTF-8"
LC_MESSAGES="C.UTF-8"
LC_ALL=
正因为如此,Cygwin 下的 Git 对中文的支持也非常出色。虽然中文的 Windows 本身使用 GBK 字符集,但是在 Cygwin 下,Git 就如同工作在采用 UTF-8 字符集的 Linux 下,对中文的支持非常的好:
 在提交时,可以在提交说明中输入中文。
 显示提交历史时,能够正常显示提交说明中的中文字符。
 可以添加文件名称为中文的文件,并可以在使用UTF-8 字符集的 Linux 环境中克隆和检出。
 可以创建带有中文字符的里程碑名称。
但是和 Linux 平台一样,在默认设置下,文件名称中包含中文的文件,在工作区状态输出、查看历史更改概要,以及在补丁文件中,文件名中的中文不能正确地显示,而是用若干八进制字符编码来显示,如下:
$ git status -s
?? "\350\257\264\346\230\216.txt"
$ printf "\350\257\264\346\230\216.txt"
说明.txt
配置变量 core.quotepath 设置为 false 就可以解决中文文件名在这些 Git 命令输出中的显示问题。
$ git config --global core.quotepath false
$ git status -s
?? 说明.txt

 

3.3.5 Cygwin 下 Git 访问 SSH 服务 Top

在本书第5篇第29章中介绍的以公钥认证的方式访问 Git 服务,是实现 Git 写操作的最重要的服务。以公钥认证方式访问 SSH 协议的 Git 服务器时无须输入口令,而且更安全。使用公钥认证就涉及如何创建公钥/私钥对,以及在 SSH 连接时应该选择哪一个私钥的问题(如果建立有多个私钥)。
Cygwin 下的 openssh 软件包提供的 ssh 命令和 Linux 下的ssh命令没有什么区别,也提供了 ssh-keygen 命令来管理 SSH 公钥/私钥对。但是,Cygwin 当前的 openssh(版本号:5.7p1-1)有一个 Bug,使用 Git 克隆采用 SSH 协议的版本库时偶尔会中断,从而无法完成版本库的克隆。示例如下:
$ git clone git@bj.ossxp.com:ossxp/gitbook.git
Cloning into gitbook...
remote: Counting objects: 3486, done.
remote: Compressing objects: 100% (1759/1759), done.
fatal: The remote end hung up unexpectedly MiB | 3.03 MiB/s
fatal: early EOFs:  75% (2615/3486), 13.97 MiB | 3.03 MiB/s
fatal: index-pack failed
如果您也遇到同样的问题,建议使用 PuTTY 提供的 plink.exe 作为 SSH 客户端,替代 Cygwin 自带的 ssh 命令。
1. 安装 PuTTY
PuTTY 是 Windows 下的一个开源软件,提供 SSH 客户端服务,还包括公钥管理的相关工具。访问 PuTTY 的主页(http://www.chiark.greenend.org.uk/~sgtatham/putty/),下载并安装 PuTTY。安装完毕会发现 PuTTY 软件包包含了多个可执行程序,下面几个命令用于与Git 的整合。
Plink:即 plink.exe,是命令行的 SSH 客户端,用于替代 ssh 命令。默认安装于 C:\Program Files\PuTTY\plink.exe 路径中。
PuTTYgen:用于管理 PuTTY 格式的私钥,也可以用于将 openssh 格式的私钥转换为 PuTTY 格式的私钥。
Pageant:SSH 认证代理,运行于后台,负责为 SSH 连接提供私钥访问服务。
2. PuTTY 格式的私钥
PuTTY 使用专有格式的私钥文件(扩展名为.ppk),而不能直接使用 openssh 格式的私钥。也就是用 openssh 的 ssh-keygen 命令创建的私钥不能直接被 PuTTY 拿过来使用,必需经过转换,程序 PuTTYgen 可以实现私钥格式的转换。
运行 PuTTYgen 程序,如图3-15所示。


PuTTYgen 既可以重新创建私钥文件,又可以通过点击加载按钮(load)读取 openssh 格式的私钥文件,从而可以将其转换为 PuTTY 格式的私钥。点击加载按钮,会弹出文件选择对话框,选择 openssh 格式的私钥文件(如文件id_rsa),如果转换成功,会显示如图3-16的界面。
然后点击“Save private key”(保存私钥),就可以将私钥保存为 PuTTY 的 .ppk 格式,例如将私钥保存到文件 ~/.ssh/jiangxin-cygwin.ppk 中。
3. Git 使用 Pageant 进行公钥认证
Git 在使用命令行工具 Plink(plink.exe)作为 SSH 客户端访问 SSH 协议的版本库服务器时,如何选择公钥呢?使用 Pageant 是一个非常好的选择。Pageant 是 PuTTY 软件包中的代理软件,为各个 PuTTY 应用提供私钥请求,当 Plink 连接 SSH 服务器需要请求公钥认证时,Pageant 就会给 Plink 提供相应的私钥。

运行 Pageant ,启动后会在托盘区显示一个图标,在后台运行。使用鼠标右键单击 Pageant 的图标,就会弹出相关的菜单,如图3-17所示。


点击弹出菜单中的“Add Key”(添加私钥)按钮,会弹出文件选择框,选择扩展名为 .ppk 的 PuTTY 格式的公钥,即完成了 Pageant 的私钥准备工作。
接下来,还需要对 Git 进行设置,设置 Git 使用 plink.exe 作为 SSH 客户端,而不是默认的ssh命令。通过设置 GIT_SSH 环境变量即可实现:
$ export GIT_SSH=/cygdrive/c/Program\ Files/PuTTY/plink.exe
上面在设置 GIT_SSH 环境变量的过程中使用了 Cygwin 格式的路径,而非 Windows 格式的,因为 Git 是在 Cygwin 的环境中调用 plink.exe 命令的,所以要使用 Cygwin 能够理解的路径。
这样就可以用 Git 访问 SSH 协议的 Git 服务器了。运行在后台的 Pageant 会在需要的时候为plink.exe提供私钥访问服务,但在首次连接一个使用 SSH 协议的 Git 服务器的时候,很可能会因为远程SSH服务器的公钥没有经过确认而导致 git 命令执行失败。例如:
$ git clone git@bj.ossxp.com:ossxp/gitbook.git
Cloning into gitbook...
The server's host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 49:eb:04:30:70:ab:b3:28:42:03:19:fe:82:f8:1a:00
Connection abandoned.
fatal: The remote end hung up unexpectedly
这是因为在首次连接 SSH 服务器时要对其公钥进行确认(以防止被钓鱼),而运行于 Git 下的 plink.exe 没有机会从用户那里获取输入,以建立对该SSH服务器公钥的信任,因此 Git 访问失败。解决办法非常简单,直接运行plink.exe连接一次远程 SSH 服务器,并对公钥确认进行应答即可。操作如下:
$ /cygdrive/c/Program\ Files/PuTTY/plink.exe git@bj.ossxp.com
The server's host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 49:eb:04:30:70:ab:b3:28:42:03:19:fe:82:f8:1a:00
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n)
输入“y”,将公钥保存在信任链中,以后再和该主机连接时就不会弹出该确认应答了。当然,Git 命令也就可以成功执行了。
4. 使用自定义 SSH 脚本取代 Pageant
使用 Pageant 时还要在它每次启动时手动选择私钥文件,这比较麻烦。实际上,可以创建一个脚本对 plink.exe 进行封装,在封装的脚本中使用 -i 参数指定私钥文件。
例如,创建脚本 ~/bin/ssh-jiangxin,文件内容如下:
#!/bin/sh

/cygdrive/c/Program\ Files/PuTTY/plink.exe -T -i \
    c:/cygwin/home/jiangxin/.ssh/jiangxin-cygwin.ppk $*
设置该脚本为可执行脚本。
$ chmod a+x ~/bin/ssh-jiangxin
使用下面的命令通过该脚本与远程 SSH 服务器连接:
$ ~/bin/ssh-jiangxin git@bj.ossxp.com
Using username "git".
hello jiangxin, the gitolite version here is v1.5.5-9-g4c11bd8
the gitolite config gives you the following access:
     R          gistore-bj.ossxp.com/.*$
     R          gistore-ossxp.com/.*$
  C  R  W       ossxp/.*$
     R  W       test/repo1
     R  W       test/repo2
     R  W       test/repo3
    @R @W       test/repo4
@C @R  W       users/jiangxin/.+$
设置 GIT_SSH 变量,使之指向新建立的脚本,然后就可以脱离 Pageant 来连接 SSH 协议的 Git 库了。
$ export GIT_SSH=~/bin/ssh-jiangxin

3.4 Windows 下安装和使用 Git(msysGit篇) Top

        运行在 Cygwin 下的 Git 不直接使用 Windows 的系统调用,而是通过二传手 cygwin1.dll 来进行的。虽然Cygwin中的 Git 能够在 Windows 下的cmd.exe命令窗口中运行良好,但 Cygwin 下的 Git 并不能被看作是 Windows 下的原生程序。相比 Cygwin 下的 Git,msysGit 才是原生的 Windows 程序,msysGit 下运行的 Git 是直接通过 Windows 的系统调用来运行的。
        msysGit 名字前面的四个字母来源于 MSYS① 项目。MSYS 项目源自于 MinGW②(Minimalist GNU for Windows,最简GNU工具集),通过增加一个 bash 提供的shell 环境及其他相关的工具软件组成了一个最简系统(Minimal SYStem),简称 MSYS。利用 MinGW 提供的工具和 Git 针对 MinGW 的一个分支版本,在 Windows 平台为 Git 编译出一个原生应用,结合 MSYS 就组成了 msysGit。

3.4.1 安装 msysGit Top

安装 msysGit 非常简单,访问 msysGit 的项目主页(http://code.google.com/p/msysgit/),下载 msysGit。最简单的方式是下载名为 Git-<VERSION>-preview<DATE>.exe 的软件包,如Git-1.7.3.1-preview20101002.exe 。如果您有时间和耐心,想观察 Git 是如何在 Windows 上被编译为原生应用的,也可以下载带msysGit-fullinstall-前缀的软件包。
点击安装程序(如 Git-1.7.3.1-preview20101002.exe )开始安装,如图3-18所示。


默认安装到 C:\Program Files\Git 目录中,如图3-19所示。
在安装过程中会询问是否修改环境变量,如图3-20所示。默认选择“Use Git Bash Only”,即只在 msysGit 提供的 shell 环境(类似 Cygwin)中使用 Git,不修改环境变量。注意,如果选择最后一项,会将 msysGit 所有的可执行程序全部加入 Windows 的 PATH 路径中,有的命令会覆盖 Windows 相同文件名的程序(如find.exe和sort.exe)。而且,如果选择最后一项,还会为 Windows 添加 HOME 环境变量,如果安装有 Cygwin,Cygwin 就会受到 msysGit 引入的 HOME 环境变量的影响(参见前面 3.3.3 节的相关讨论)。



还会询问换行符的转换方式,使用默认设置就可以了,如图3-21所示。关于换行符转换的内容,请参见本书第8篇的相关章节。


根据提示完成 msysGit 的安装。

3.4.2 msysGit 的配置和使用 Top

完成 msysGit 的安装后,点击 Git Bash 图标,启动 msysGit,如图3-22。会发现 Git Bash 的界面和 Cygwin 的非常相像。


1. 如何访问 Windows 的盘符
在 msysGit 下访问 Windows 的各个盘符要比 Cygwin 简单,直接通过“/c”即可访问 Windows 的C盘,用“/d”即可访问 Windows 的D盘。
$ ls -ld /c/Windows
drwxr-xr-x  233 jiangxin Administ        0 Jan 31 00:44 /c/Windows
msysGit 的根目录实际上就是 msysGit 的安装目录,如“C:\Program Files\Git”。
2. 命令行补齐和忽略文件大小写
msysGit 默认已经安装并启用了 Git 的命令行补齐功能,是通过在文件 /etc/profile 中加载相应的脚本实现的。
. /etc/git-completion.bash
msysGit还支持在命令行补齐时忽略文件名的大小写,这是因为 msysGit 已经在配置文件/etc/inputrc中包含了下列的设置:
set completion-ignore-case on

3.4.3 msysGit中shell环境的中文支持 Top

在介绍 Cygwin时曾经提到过,msysGit 的 shell 环境的中文支持情况与老版本的 Cygwin①类似,需要配置才能够录入中文和显示中文。
1. 中文录入问题
默认安装的 msysGit 的 shell 环境中无法输入中文。为了能在 shell 界面中输入中文,需要修改配置文件 /etc/inputrc ,增加或修改相关的配置如下:
# disable/enable 8bit input
set meta-flag on
set input-meta on
set output-meta on
set convert-meta off
关闭 Git Bash 再重启,就可以在 msysGit 的 shell 环境中输入中文了。
$ echo 您好
您好
2. 分页器中文输出问题
对 /etc/inputrc 进行正确的配置之后就能够在 shell 环境下输入中文了,但是执行下面的命令时会显示乱码。这显然是 less 分页器命令导致的问题。
$ echo 您好 | less
<C4><FA><BA><C3>
通过管道符调用分页器命令 less 后,原本的中文输出变成了乱码显示。因为 Git 使用了大量的 less 命令作为分页器,这导致 Git 的很多命令的输出都出现了中文乱码的问题。之所以less命令会导致出现乱码,是因为该命令没有把中文当作正常的字符,可以通过设置 LESSCHARSET 环境变量将 UTF-8 编码字符视为正常的字符,于是中文就能正常显示了。下面的操作可以使 less 分页器中的中文正常显示:
$ export LESSCHARSET=utf-8
$ echo 您好 | less
您好
编辑配置文件 /etc/profile ,将对环境变量 LESSCHARSET 的设置加入其中,以便 于msysGit 的 shell 环境启动时就加载。
declare -x LESSCHARSET=utf-8
3. ls 命令显示中文文件名
最常用的用于显示目录和文件名列表的命令 ls 在显示中文文件名的时候也有问题。下面的命令创建了一个中文名称的文件,文件内容中的中文在显示时没有问题,但是文件名却显示为一串问号。
$ echo 您好 > 您好.txt

$ cat \*.txt
您好

$ ls \*.txt
????.txt
实际上,只要在 ls 命令后添加参数 --show-control-chars 即可正确显示中文:
$ ls --show-control-chars *.txt
您好.txt
为方便起见,可以为 ls 命令设置一个别名,这样就不必在输入 ls 命令时输入长长的参数了。
$ alias ls="ls --show-control-chars"

$ ls \*.txt
您好.txt
将上面的 alias 命令添加到配置文件 /etc/profile 中,可实现在每次运行 Git Bash 时自动加载。

3.4.4 msysGit中Git的中文支持 Top

非常遗憾的是,msysGit 中的 Git 对中文支持不如 Cygwin 中的 Git ,msysGit 中的 Git 对中文的支持情况与前面讨论过的使用了 GBK 字符集的Linux环境下的 Git 相当。
(1)使用未经配置的 msysGit提交,如果提交说明中包含中文,从 Linux 平台或其他 UTF-8 字符集平台上查看提交说明时会显示为乱码。
(2)同样,从 Linux 平台或其他使用 UTF-8 字符集平台进行的提交,若提交说明包含中文,在未经配置的 msysGit 中也会显示为乱码。
(3)如果使用 msysGit 向版本库中添加带有中文文件名的文件,在 Linux(或其他 UTF-8)平台检出文件名时会显示为乱码,反之亦然。
(4)不能创建带有中文字符的引用(里程碑和分支等)。
如果希望版本库中出现使用中文文件名的文件,最好不要使用 msysGit,而应该使用 Cygwin 下的 Git。如果只是想在提交说明中使用中文,对msysGit进行一定的设置后还是可以实现的。
为了解决提交说明显示为乱码的问题,msysGit 要为 Git 设置参数i18n.logOutputEncoding,将提交说明的输出编码设置为 gbk:
$ git config --system i18n.logOutputEncoding gbk
Git 在提交时并不会对提交说明进行从 GBK 字符集到 UTF-8 字符集的转换,但是可以在提交说明中标注所使用的字符集。因此,如果在非 UTF-8 字符集的平台中录入中文,需要用下面的指令设置录入提交说明的字符集,以便在 commit 对象中嵌入正确的编码说明。
$ git config --system i18n.commitEncoding gbk
同样,为了让带有中文文件名的文件在工作区状态输出、查看历史更改概要,以及在补丁文件中能够正常显示,要为 Git 设置 core.quotepath 配置变量,将其设置为 false。但是要注意,如果在 msysGit 中添加文件名包含中文的文件,就只能在 msysGit 环境中正确显示,而在其他环境(如Linux、Mac OS X、Cygwin)中文件名会显示为乱码。
$ git config --system core.quotepath false
$ git status -s
?? 说明.txt
注意 如果同时安装了 Cygwin 和 msysGit(可能配置了相同的用户主目录),或者因为中文支持问题而需要单独为 TortoiseGit 准备一套 msysGit 时,为了保证不同的 msysGit 之间,以及与 Cygwin 之间的配置互不影响,需要在配置 Git 环境时使用 --system 参数。这是因为不同的 msysGit 安装及 Cygwin的系统级配置文件的位置不同,但是用户级配置文件的位置却可能重合。

3.4.5 使用 SSH 协议 Top

       msysGit 软件包包含的 ssh 命令和 Linux 下的ssh命令没有什么区别,也提供 ssh-keygen 命令管理 SSH 公钥/私钥对。在使用 msysGit 的 ssh 命令时,没有遇到 Cygwin 中的 ssh 命令(版本号:5.7p1-1)不稳定的问题,即 msysGit 下的 ssh 命令可以非常稳定地工作。
如果需要与 Windows 更好地整合,希望使用图形化工具管理公钥,也可以使用 PuTTY 提供的plink.exe作为 SSH 客户端。关于如何使用 PuTTY,请参见 3.3.5 节中 Cygwin 和 PuTTY 整合的相关内容。 
 

3.4.6 TortoiseGit 的安装和使用 Top

TortoiseGit 可以让 Git 与 Windows 资源管理器进行整合,为 Git 提供了图形化操作界面。像其他 Tortoise 系列产品(TortoiseCVS、TortoiseSVN)一样,在资源管理器中显示的 Git 工作区目录和文件的图标附加了标识版本控制状态的图像,这样可以非常直观地看到哪些文件被更改了并需要提交。通过扩展后的右键菜单,可以非常方便地在资源管理器中操作 Git 版本库。
TortoiseGit 是对 msysGit 命令行的封装,因此需要先安装 msysGit。安装 TortoiseGit 非常简单,访问网站 http://code.google.com/p/tortoisegit/ ,下载安装包,然后根据提示完成安装。
安装过程中会询问要使用的 SSH 客户端,如图3-23,默认使用内置的 TortoisePLink(来自 PuTTY 项目)作为 SSH 客户端。

 TortoisePLink 和 TortoiseGit 的整合性更好,可以直接通过对话框设置 SSH 私钥(PuTTY格式),而无须再到字符界面去配置 SSH 私钥和其他配置文件。如果安装过程中选择了 OpenSSH,可以在安装完之后通过 TortoiseGit 的设置对话框重新选择 TortoisePLink作为默认 SSH 客户端,如图3-24所示。



 当使用 TortoisePLink 作为默认的 SSH 客户端后,在执行克隆操作时,可以在TortoiseGit操作界面中选择一个 PuTTY 格式的私钥文件进行认证,如图3-25所示。

 如果需要更换连接服务器的 SSH 私钥,可以通过 Git 远程服务器配置界面对私钥文件进行重新设置,如图3-26所示。




如果系统中安装有多个 msysGit 的拷贝,可以通过 TortoiseGit 的配置界面进行选择,如图3-27所示。


   

3.4.7 TortoiseGit 的中文支持 Top

虽然TortoiseGit 在底层调用了 msysGit,但是 TortoiseGit 的中文支持与 msysGit 是有区别的。前面在介绍 msysGit 的中文支持时所进行的配制会破坏 TortoiseGit。
TortoiseGit 在提交时会将提交说明转换为 UTF-8 字符集,因此无须对i18n.commitEncoding变量进行设置。相反,如果将i18n.commitEncoding设置为 gbk 或其他字符集,则在提交对象中会包含错误的编码设置,有可能会给提交说明的显示带来麻烦。
TortoiseGit 在显示提交说明时认为所有的提交说明都是 UTF-8 编码,会转换为合适的 Windows 本地字符集显示,而无须设置i18n.logOutputEncoding变量。因为当前版本的 TortoiseGit 没有对提交对象中的 encoding 设置进行检查,所以使用 GBK 字符集的提交说明中的中文不能正常显示。
因此,如果需要同时使用 msysGit 的文字界面 Git Bash 和 TortoiseGit,而且需要在提交说明中使用中文,可以安装两套 msysGit,并确保 TortoiseGit 关联的 msysGit 没有对i18n.commitEncoding进行设置。
与msysGit一样,TortoiseGit 对使用中文命名的文件和目录的支持,也存在缺陷,因此应当避免在 msysGit 和 TortoiseGit 中添加用中文命名的文件和目录,如果确实需要,可以使用 Cygwin。
  • 大小: 5 KB
  • 大小: 35.2 KB
  • 大小: 21.1 KB
  • 大小: 39.7 KB
  • 大小: 27.6 KB
  • 大小: 41 KB
  • 大小: 29.4 KB
  • 大小: 41.3 KB
  • 大小: 26.2 KB
  • 大小: 44.6 KB
  • 大小: 29.8 KB
  • 大小: 25 KB
  • 大小: 28.9 KB
  • 大小: 32.3 KB
  • 大小: 36.9 KB
  • 大小: 36 KB
  • 大小: 43.8 KB
  • 大小: 45.9 KB
  • 大小: 28.7 KB
  • 大小: 40.6 KB
  • 大小: 70.6 KB
  • 大小: 33 KB
  • 大小: 11.2 KB
  • 大小: 34 KB
  • 大小: 51.8 KB
  • 大小: 55.3 KB
  • 大小: 27.8 KB
  • 大小: 20.5 KB
  • 大小: 48.6 KB
  • 大小: 42.3 KB
  • 大小: 51 KB
  • 大小: 45.2 KB
评论 共 1 条 请登录后发表评论
1 楼 inspire_xg 2011-07-08 13:49
开玩笑,上传了一个winxp.img

评论被关闭

文章信息

  • hzbook在2011-06-28创建
  • hzbook在2011-06-30更新
  • 标签: 开源, Linux, Git, 版本控制, 系统迁移
Global site tag (gtag.js) - Google Analytics