作者:Susan Potter,翻译:张吉
原文:http://www.aosabook.org/en/git.html
Git能够让不同的协作者通过一个点对点的仓库网络对数据内容(通常是代码,当然不仅限于代码)进行维护。它支持分布式的工作流程,能够让数据内容临时分离,并最终合并到一起。
本章将阐述Git的内部实现是如何提供以上功能的,以及它和其他版本控制系统(VCS)的区别。
为了更好地理解Git的设计思想,我们有必要先了解一下Git项目的发源地——Linux内核开发社区——所面临的问题。
Linux内核开发与其他商业软件项目有很大不同,因为它的开发者众多,且每个开发者的参与程度和对Linux内核代码的理解有很大差异。多年以来,内核代码一直都是以Tar压缩文件以及补丁的形式维护的,而当时的核心开发团队一直在寻找一个能够满足他们各方面需求的版本控制系统。
Git就是在这样的背景下于2005年作为一款开源软件诞生的。当时,Linux内核代码通过两种版本控制系统进行维护,BitKeeper和CVS,分别由两组核心开发团队使用。BitKeeper相较于当时颇为流行的CVS,提供了一种不同的历史展示方式。
当BitKeeper的所有者BitMover决定收回Linux内核开发人员的使用许可时,Linux Torvalds紧急开启了一个项目,也就是后来的Git。一开始,他通过编写一组Shell脚本来帮助他将邮件中的补丁按顺序应用到代码中。这组原始脚本能够在代码合并过程中迅速中断,让维护者能够进行人工干预,修改代码,然后继续合并。
从项目开始之初,Torvalds就为Git制定了一个目标——要和CVS的做法完全相反——同时还包含了以下三条设计目标:
这些设计目标都被实现了,我会在下文中通过解析Git的各种做法来阐述,包括在内容管理中使用有向无环图(DAG),头指针引用,对象模型,远程协议,以及Git如何追踪合并树。
虽然Git设计之初受到了很多BitKeeper的影响,但是两者还是有根本上的区别的,如Git提供了更多分布式和本地开发流程,这点是BitKeeper做不到的。Monotone,2003年启动的一个开源分布式版本控制系统,也对Git的早期开发产生了影响。
分布式版本控制系统在提供更灵活的工作流程的同时,往往会增加它的复杂程度。分布式模型的独特优点有:
在Git项目的开发期间,诞生了其他三个开源分布式版本控制系统(其中Mercurial可以参见《开源软件架构》的第一卷)。这些分布式版本控制系统(dVCS)都提供了非常灵活的工作流程,这是先前的集中式版本控制系统做不到的。注意:Subversion有一款插件名为SVK,由不同的开发者维护,提供了服务器之间的同步功能。
目前流行的dVCS包括Bazaar, Darcs, Fossil, Git, Mercurial, 以及Veracity。
现在让我们回过头来看看Git之外的其他版本控制系统是如何设计的。通过比较他们和Git之间的区别,可以帮助我们去理解Git在架构设计中的选择。
版本控制系统通常有三项核心功能(需求):
注意:第三项并不是所有版本控制系统的核心功能。
在VCS中保存内容,最普遍的做法是保存增量的修改,或使用有向无环图(DAG)。
增量修改可以反映出两个版本之间的内容差异,以及一些额外的信息。使用有向无环图保存内容则是将特定对象构造成一种树状结构,作为某一次提交的快照保存下来(树状结构中未发生变化的对象是可以重用的)。Git使用有向无环图来保存内容,它所使用的不同对象类型会在本文的“对象数据库”一节中有所描述。
在保存历史、记录变化方面,大部分VCS使用以下方式之一:
Git使用的还是有向无环图,这次则是用来保存历史。每次提交包含了它父节点的元信息——Git中的一次提交可以拥有0个或多个父节点(理论上没有个数限制)。例如,Git仓库的第一次提交就没有父节点,而一次三头合并则有三个父节点。
Git和SVN线性提交的另一个重要区别是Git可以直接进行分支的创建,并记录下大部分合并历史。