一、基本概念
1.1 集中式、分布式版本控制系统的区别
集中式、分布式(DVCS)版本控制系统的区别:
集中式版本控制系统(如CVS/SVN) 分布式版本控制系统(如 Git )
分布式版本控制 (DVCS) 不需要中心服务器就可以管理文件版本。但是它也可以使用中心服务器。更改可以被合并到 DVCS 的任何其他用户的系统中,因此可以实现非常灵活的工作流。
DVCS 的两个主要优点是:它比集中的版本控制更灵活,因为它除了支持传统的(集中式)工作流,还支持其他各种工作流;它比集中式服务器快得多,因为大多数操作在客户机本地进行,而不需要网络操作。
- 对于一个开源项目,从开发角度讲大体上分为两类人群,一类称为核心开发团队,他们可以向保存源代码的版本库提交,即对源代码的修改具有最终的决定权。另外一类称为贡献者,他们不属于核心开发团队,虽然也能看到源代码,但无权向版本库提交修改。
- 采用传统的集中式版本控制系统(如SVN)的开源项目,这两个群体的用户体验都不是太好。如左图所示,项目的贡献者(非核心成员)很不“高兴”,因为他们即便有修改源代码的能力和渴望,也不能直接向版本库提交,要想成为提交者需要一个很长的建立信任的过程。然而即便是核心开发团队的成员,体验也不是太好,因为凡是涉及到版本库的操作(检入、检出、查看日志等)都需要在联网的状态下进行,网络带宽对用户体验影响相当大。
- Git等分布式版本控制系统的出现,彻底颠覆了原有代码管理的组织模式。使用Git,不再依赖唯一的、集中式的版本库,而是每个开发者本地都拥有一份完整的版本库。Git并不排斥集中式的使用模式,但更倾向于将集中式版本库称为共享版本库。核心开发团队的成员和贡献者(非核心成员)都可以从共享版本库克隆一份本地版本库,但只有核心团队成员才可以将自己本地版本库的提交推送到共享版本库上。
1.2 Git与SVN的区别
最初 Git 的开发是为了辅助 Linux 内核开发的过程,但是现在在很多其他自由软件项目中也使用了Git。
Git 与 SVN 的区别:
(1)GIT是分布式的,SVN不是:
这是GIT和其它非分布式的版本控制系统,例如SVN,CVS等,最核心的区别。GIT并不是目前第一个或唯一的分布式版本控制系统,但GIT在这方面做的更好,而且有更多强大的功能特征。GIT跟SVN一样有自己的集中式版本库或服务器。但GIT更倾向于被使用于分布式模式,也就是每个开发人员从中心版本库/服务器上checkt out代码后会在自己的机器上克隆一个自己的版本库。如果你被困在一个不能连接网络的地方时,仍然能够提交文件,查看历史版本记录,创建项目分支等。对一些人来说,这好像没多大用处,但当你突然遇到没有网络的环境时,这个将解决你的大麻烦。同样,这种分布式的操作模式对于开源软件社区的开发来说也很重要,你不必再像以前那样做出补丁包,通过email方式发送出去。你只需要创建一个分支,向项目团队发送一个推请求。这能让你的代码保持最新,而且不会在传输过程中丢失。GitHub.com就是一个这样的优秀案例。
(2)GIT把内容按元数据方式存储,而SVN是按文件:
所有的资源控制系统都是把文件的元信息隐藏在一个类似.svn,.cvs等的文件夹里。如果你把.git目录的体积大小跟.svn比较,你会发现它们差距很大。因为,.git目录是处于你的机器上的一个克隆版的版本库,它拥有中心版本库上所有的东西,例如标签,分支,版本记录等。
(3)GIT分支和SVN的分支不同:
分支在SVN中一点不特别,就是版本库中的另外的一个目录。如果你想知道是否合并了一个分支,你需要手工运行像这样的命令svn propget svn:mergeinfo,来确认代码是否被合并。所以经常会发生有些分支被遗漏的情况。然而,处理GIT的分支却是相当的简单和有趣。你可以从同一个工作目录下快速的在几个分支间切换。你很容易发现未被合并的分支,你能简单而快捷的合并这些文件。
(4)GIT没有一个全局的版本号,而SVN有:
目前为止这是跟SVN相比GIT缺少的最大的一个特征。你也知道,SVN的版本号实际是任何一个相应时间的源代码快照。因为GIT和SVN从概念上就不同,可以使用GIT的SHA-1来唯一的标识一个代码快照。这个并不能完全的代替SVN里容易阅读的数字版本号。
(5)GIT的内容完整性要优于SVN:
GIT的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。
1.3 GitHub : 版本控制系统,基于Git托管网站。
早在2009年Github在国内的Ruby社区就很有名气了。之所以最近被更多人认识,是因为刚拿到1亿美元融资。GitHub的理念非常简单:社会化编程。像Twitter一样,每个人都可以在GitHub上发布自己的各种代码,以时间流的形式展现自己的开发进展,可以关注自己感兴趣的项目和开发者,发表评论,了解其最新的开发动态。但所谓的社会化,还不仅仅局限于此,GitHub 最重要的特征是以一种社交化、民主化的形式进行代码协作。GitHub的社会化编程理念可以说将开源的概念发挥到了极致:由于采用了Git这种分布式版本控制系统,所有人都可以对任意一个公共项目简单的进行分支开发,而不会对原项目有任何的影响;可以将自己对于项目的功能改进、漏洞修复、或有价值的代码提交给原开发者,一起对项目进行完善。
1.4 GitHub的亮点
(1)只用Git。
GitHub只支持Git格式的版本库托管,而不像其他开源项目托管平台还对CVS、SVN、Hg等格式的版本库进行托管。GitHub的哲学很简单,既然Git是最好的版本控制系统之一(对于很多喜欢Git和GitHub的人没有之一),没有必要为兼顾其他版本控制系统而牺牲Git某些独有特性。因此没有支持其他版本控制系统的历史负担,是GitHub成功的要素之一。
只用Git并不是说GitHub完全无视其他版本控制系统的使用者,相反GitHub面向SVN(Subversion)用户和Hg(Mercurial)用户开发了接口,让这些用户可以使用SVN或Hg的客户端工具访问Git版本库。
(2)对Git的完整支持。
相比其他开源项目托管平台,GitHub对Git版本库提供了完整的协议支持,支持HTTP智能协议、Git-daemon、SSH协议。相比只支持HTTP协议的GoogleCode,GitHub通过SSH协议可以实现版本库访问的无口令认证[1]。
(3)无处不在的Git。
除了在版本库托管上使用Git,Git还被GitHub应用到更多领域。维基使用Git,可以通过克隆维基所在的版本库,离线修改维基;在线粘贴数据的Gist网站使用Git,记录变更历史;以及在Jekyll应用的帮助下,用Git版本库维护个人网站和博客等。
(4)在线编辑文件。
GitHub提供了在线编辑文件的功能,不熟悉Git的用户也可以直接通过浏览器修改版本库里的文件。
(5)社交编程。
将社交网络引入项目托管平台是GitHub的创举。用户可以关注项目、关注其他用户进而了解项目和开发者动态。项目的派生(Fork)和拉拽请求(Pull Request)构成GitHub最独具一格的工作模式。对提交代码的逐行评注及Pull Request构成了GitHub特色的代码审核。
(6)商业上的成功。
GitHub通过私有版本库托管、面向企业的版本库托管和项目管理平台、人员招聘等付费服务获得了商业上的成功,这种成功使得GitHub不必以页面中嵌入广告的方式维持运营,最大的受益者还是用户。
(7)关注细节。
GitHub网站采用了Ruby on Rails架构,在Web设计中运用了大量的JavaScript、AJAX、HTML5等技术,支持对使用Markdown等标记语言的内容进行渲染和显示等。关注细节使得GitHub成为了项目托管领域的后起之秀。
(8)大量优秀的开源框架:
Ruby on Rail 框架、Hibernate、phpBB、Linux 内核、jQuery脚本、Homebrew 包管理系统、Bootstrap CSS 框架、Twitter和Facebook的开源项目。
二、基本操作原理(解决冲突的办法)
2.1 Git协同合并
传统集中式版本控制系统,所有的提交历史数据都在唯一的版本库中,各个提交是顺序进行的。为了防止多用户在提交时相互覆盖,集中式版本控制系统发明了很多方法。如SVN,允许多人同时编辑同一文件,但只有先进行提交的才能成功,后提交的会遇到“过时”错误,必须先获取版本库中的新增提交并和本地修改进行合并。即传统集中式版本控制系统,提交时必须和唯一的版本库所在的服务器保持连接,而且提交有可能会失败。
对于像Git这样的分布式版本控制系统,提交总是会成功,这是因为提交并不涉及和共享服务器的交互,是针对本地克隆版本库进行的本地操作。采用集中式的工作模式,共享版本库作为各个用户各自本地版本库数据交换、沟通的中介,只有在本地克隆版本库需要和共享版本库同步的时候才要和服务器建立连接。例如将本地所做的一个或多个提交推送到共享服务器,或者将服务器上新的提交获取到本地克隆版本库。
实际上无论采用分布式还是集中式的工作模式,Git都好像工作在一个独立的分支上(克隆即分支),即使共享版本库和本地克隆版本库的分支名都叫做master。如上图左上小图,三个用户克隆版本库后,各自在本地执行了一次或多次提交。三个用户各自的提交都会非常顺利,但是一旦决定将本地提交推送到共享服务器时就可能遇到麻烦。用户1先执行推送,会非常顺利。如上图右上小图所示。 而其他人就没有这么幸运了,会报告错误:遇到非快进式推送。Git的推送操作就像SVN等集中式版本控制系统的提交操作那样,先执行者成功,后执行者就悲剧了(要自动或手动解决冲突)。比如当用户1完成推送后,共享版本库以及三个用户的本地版本库上图右上小图所示。其中共享版本库变得和用户1的本地版本库相一致。此时如果用户2执行推送,会遇到错误。
此时正确的做法是获取共享版本库中新提交,并在本地版本库中和本地提交合并。获取和合并操作过程上图左下小图所示。
但是合并操作并不总是会成功,如果自动合并失败,会在暂存区对合并前后文件进行标识,工作区进入冲突解决状态,在冲突解决完成之前不能提交。Git支持多种图形工具帮助完成冲突解决,执行如下命令,即可自动调用已安装的冲突解决工具。
冲突解决完毕,执行提交即完成冲突解决。如果在冲突解决过程把本地文件搞乱,随时可以取消合并操作。取消冲突的合并让本地版本库回到合并之前的状态。完成推送后的版本库示意图如上图右下小图所示。
2.2 Git协同变基
合并并非多个开发者的工作成果融合的唯一选择,有时甚至并非最佳选择。一方面合并会产生除了合并双方(或多方)所有提交外的一个新提交,增加了代码审核的负担,另一方面本地多个提交混杂一起与远程分支合并会更困难。在特定情况下,变基是合并之外的另一个选择。上图展示用户3采用合并和变基两种不同解决方案的操作结果。图中右上是合并操作后的结果,右下是变基操作后的结果。
若用户 incredible 选择变基操作,首先获取远程版本库的提交到本地的远程分支,然后执行变基操作,将本地master分支的提交变基到新的远程分支中。如果一切顺利,变基后推送到共享版本库。推送后的版本库状态如上图所示。
三、合作流程总结(Git对比SVN)
(1)开发者在本地进行迭代开发,可以经常的做commit操作且不会影响他人。而且即使不在线也可以进行开发。只需要最后向中心库提交一次即可。
(2)更有利于在代码提交前做code review。以往用SVN,都是代码提交后才做code review。如果发生问题,也无法避免服务器上有不好的代码。但是用Git,真正向中心库commit前,都是在本地开发,可以方便的进行code review,然后才提交到中心库。更有利于代码质量。而且,可以感觉到,使用Git的过程中,更容易对代码进行code review,因为影响因素更小。
(3)创建多分支,更容易在开发中进行多种工作,而使工作间不会互相影响。比如user2对user1的代码进行code review时,就可以非常方便的保留当时的开发现场,并切换到user1的代码分支,在code review完毕后,也可以非常方便的切换会曾经被中断的工作现场。
四、推荐阅读
分布式版本控制系统入门
Git入门教程:
GitHub基础图文教程
GotGitHub
git - 简易指南(小清新风格,简单易懂)