git和svn是目前最常用的团队协作的版本控制系统。
本人起初用过git,后来用过svn。算是两个版本控制系统都用过了。夜深人静睡不着,特此来一发,论一论这两者。
下面我从版本控制系统的演进历史讲起。以下的1,2,3也正是版本控制的演进历史:
①本地版本控制系统:(解决个人的版本管理)
很多人的选择的版本控制方法是将文件复制到另一个目录(可能是一个时间标记的目录,如果他们是聪明)。这种做法是很常见的,因为它是如此简单,但是很容易出错,比如很容易忘了你是哪个目录,不小心写了错误的文件等等。
为了解决这个问题,程序员早就开发了VCSS具有该保留所有文件的更改版本控制下的一个简单的数据库。
缺点:但是这种版本控制会丢失。毕竟是本地的。
②集中式版本控制:(svn是这种形式)
人们遇到的下一个主要问题是,他们需要与其他系统上的开发者合作。为了解决这个问题,出现了集中式版本控制系统(CVCSs)的开发工作。集中式版本控制系统,如CVS,Subversion和Perforce的,有一个包含所有版本文件的单个服务器和一个数字(版本号),众多客户端从这个server上去检出文件(只是文件,本地没有仓库的概念)。 多年以来,这已经成为版本控制的标准。
缺点:集中式的版本控制有个严重的缺陷。就是中央服务器的单点故障。如果服务宕机一个小时,在这期间,没有任何人可以在正在工作的版本上很好的合作或者去保存某一个版本的改变。另外如果中央数据库的磁盘坏了,并且可能没有保存备份,那么将丢失所有的东西。你失去了绝对一切 - 除了单一的任何人的快照恰好有在本地计算机上项目的整个历史。当然本地的版本控制系统也有相同的问题。虽然,你能够把每个人的本地代码,进行合并得到一个相对完整的版本,但是当你把这个相对完整的版本重新部署到服务器的新仓库时,将会丢失所有的历史版本包括日志。
③分布式版本控制:(git是这种形式,GIT跟SVN一样有自己的集中式版本库或服务器)
这是在分布式版本控制系统(DVCSs)步在DVCS(如GIT中),客户端不只是检查出文件的最新快照:他们完全镜像的存储库(本地有仓库,这就是分布式的意义)。因此,如果出现上述问题,任何客户机库的可复制备份到服务器,以恢复它。每一个克隆确实是所有数据的完整备份(除了没有push的代码,这个也是理所当然的)。
那么针对于本地版本控制系统,和集中式版本控制系统的最严重的缺陷,就被分布式版本控制系统解决了。
另外类似git这样的分布式版本管理系统,能更好的去处理你在多个远程仓库上的工作。这样是你可以同时去和多个团队去写作开发。这允许您设置几种类型的工作流,这些集中式版本控制系统是做不到的。比如说分层模型。
git和svn的五个区别
1)GIT是分布式的,SVN不是:
这 是GIT和其它非分布式的版本控制系统,例如SVN,CVS等,最核心的区别。好处是跟其他同事不会有太多的冲突,自己写的代码放在自己电脑上,一段时间后再提交、合并,也可以不用联网在本地提交;如果你能理解这个概念,那么你就已经上手一半了。需要做一点声明,GIT并 不是目前第一个或唯一的分布式版本控制系统。还有一些系统,例如Bitkeeper, Mercurial等,也是运行在分布式模式上的。但GIT在这方面做的更好,而且有更多强大的功能特征。
GIT跟SVN一样有自己的 集中式版本库或服务器。但,GIT更倾向于被使用于分布式模式,也就是每个开发人员从中心版本库/服务器上chect out代码后会在自己的机器上克隆一个自己的版本库。可以这样说,如果你被困在一个不能连接网络的地方时,你仍然能够提交文件,查看历史版本记录,创建项 目分支等。
2)GIT把内容按元数据方式存储,而SVN是按文件:
所有的资源控 制系统都是把文件的元信息隐藏在一个类似.svn,.cvs等的文件夹里。如果你把.git目录的体积大小跟.svn比较,你会发现它们差距很大。因 为,.git目录是处于你的机器上的一个克隆版的版本库,它拥有中心版本库上所有的东西,例如标签,分支,版本记录等。
3)GIT分支和SVN的分支不同:
分支在SVN中一点不特别,就是版本库中的另外的一个目录。如果你想知道是否合并了一个分支,你需要手工运行像这样的命令svn propget svn:mergeinfo,来确认代码是否被合并。
然而,处理GIT的分支却是相当的简单和有趣。你可以从同一个工作目录下快速的在几个分支间切换。你很容易发现未被合并的分支,你能简单而快捷的合并这些文件。
Git鼓励分Branch,而SVN,说实话,我用Branch的次数还挺少的,SVN自带的Branch merge我还真没用过,有merge时用的是Beyond Compare工具合并后再Commit的;
4)GIT没有一个全局的版本号,而SVN有:
目前为止这是跟SVN相比GIT缺少的最大的一个特征。
5)GIT的内容完整性要优于SVN:
GIT的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。
6)Git下载下来后,在本地不必联网就可以看到所有的log,很方便学习,SVN却需要联网;
7)SVN在Commit前,我们都建议是先Update一下,跟本地的代码编译没问题,并确保开发的功能正常后再提交,这样其实挺麻烦的,有好几次同事没有先Updata,就Commit了,发生了一些错误,耽误了大家时间,Git可能这种情况会少些。
git和svn的基本操作对比
1)仓库创建初始化
在SVN中,仓库本身的管理和日常应用,使用的是两套不同的命令。仓库的创建和备份维护等使用的命令是 svnadmin, 使用svnadmin create来创建一个新的仓库
在git中,创建一个新的仓库,可以在一个空目录下,使用git init来实现,它将创建一个.git目录用来维护仓库数据。
在SVN中,创建仓库的地方并不是你日常使用的仓库的地方,你需要在别的地方checkout出特定的仓库路径作为你的日常工作的目录。在git中,仓库所在的目录也就是你的日常工作目录,没有服务器端和客户端之分。(严格的说 .git目录才是仓库,.git目录外的地方是你的工作目录,对于bare project来说,只有git目录下的内容,工作目录离得内容还是要checkout出来的)
2)Checkout仓库
在SVN中,使用SVN checkout(co)来checkout本地或远程仓库的代码
而对于git来说,尽管也有checkout命令,但是由于你需要在本地拥有仓库,所以通常从服务器上checkout代码的第一步是使用git clone来获取一个仓库的拷贝,默认的git clone操作同时还会checkout一份远程仓库上当前active的分支
在SVN中,其仓库的管理形式决定了你可以只checkout仓库中特定路径/分支下的子目录,而不是整个仓库,而git只能checkout整个分支。
3)将文件纳入版本管理
在SVN中,使用SVN add,这样在以后的commit过程中,每次在提交数据之前,svn都会自动根据这些add过的对象的修改情况,构建一个commit tree。
在git中,因为存在index的概念,要将一个文件纳入版本管理的范畴,首先是要用git-update-index –-add将文件纳入index的监控范围,只有更新到index中的内容才会在commit的时候被提交。另外,文件本身的改动并不会自动更新到index中,每次的任何修改都必须重新更新到index中去才会被提交。 当然,通常会用git add这样的封装脚本来调用git-update-index
4)检查当前状态
SVN Status 可以显示当前working tree的文件修改状态
在git中 git status 命令显示当前index的状态和working tree的状态。
5)提交文件
Git commit操作在git命令中属于相对简单的,需要注意的一点就是上面提到的,只有index中的内容才会比提交。
6)删除文件
在使用Svn rm删除一个目录的时候,因为每个目录下都存在.svn目录,记录了这个目录于服务器端仓库相关的信息,所以在commit之前,目录里的其它文件会被删除,但是目录及其子目录并不会被真正删除,只有commit以后,目录才会被删除。
在git中,同样,使用git rm 删除文件。但是git对目录的处理有些奇怪,如果某个目录下的所有文件都被删除以后,该目录就会被自动删除,也就是说你无法保留一个空的目录。你也无法添加一个空目录到仓库里。也就是说git 自动忽略空目录,不知道这样做的目的是什么?
7)查看log
svn log命令基本上就是用来查看版本提交时的所填写的log信息
git log可以做的事情会多很多,毕竟git log是对底层核心命令的再包装,通过它,不仅可以查看log信息,还可以输出特定版本的具体变更内容等等信息。
8)版本回溯
在SVN中,不提供任何从仓库中删除对象的机制,任何的修改都会导致版本的递增,所以,如果想丢弃一个修改,你需要做的事是反向diff你的修改,再提交一个新的版本。
在git中提供了重置committed tree对象索引的机制,所以,你可以通过例如git-reset这样的操作将当前分支的版本恢复到以前的某个状态。经常看见的例子就是回溯一个版本,然后修改内容,再次提交。不过这样做搞不好很容易出问题。包括在git-push之类的操作时会被reject,需要强行push之类的。
如果只是想放弃一个修改,git的文档推荐使用git-revert操作,这个操作基本上和SVN的思路是一样的了,就是提交一个新的版本将需要revert的版本的内容再反向修改回去,版本会递增,不影响之前提交的内容。
9)放弃当前修改
在SVN中,使用SVN revert对目录或文件操作都可以将当前工作树上特定路径的修改恢复到服务器上的版本,放弃当前的修改。
Git中,对特定文件使用不带其它参数的git checkout命令可以将文件恢复到index中的状态,如果你想恢复的特定的版本,那么类似: git checkout HEAD file这样的操作,将文件恢复到HEAD tree即最近一次提交的状态。
不过git checkout有个问题,不知道是否是故意这样设计的,就是即使用git rm删除的内容,如果没有提交,git checkout以后也会恢复,包括它在index中的状态。这点有些不理解。 理论上index上已经记录这个删除操作,不应该恢复才对。
Git中还有一种办法,可以快速彻底的放弃自从上次commit以来的所有变更,git reset –hard HEAD
10)代码合并
git merge能够自动记住以前merge过的位置和状态,这个比较容易理解,因为通过每个分支的head commit可以跟踪它的对象索引关系。另外,因为其对象管理机制的原因,只能以commit为单位,merge整个分支的所有修改。不能有选择的merge部分路径下的修改。Merge的时候要求index和HEAD是一致的,如果merge成功,内容会直接commit,而工作树上的修改仍会保持。(如果失败,会在工作树上将需要merge的内容和你已有的修改合并,大概不是你所希望的,所以最好不要这样做)
merge特定分支的特定版本之前的所有修改,可以通过merge那个版本对应的rev来实现,merge某一段版本区间的修改,考虑到commit需要完整的代码树关系,估计靠git merge来做是没有办法了,需要自己diff / patch代码来实现
SVN的Merge操作不会记住它的merge历史,换句话说,你可以多次merge同一份代码,但是他的好处是你可以自由的选择merge哪一部分、哪一段版本之间的代码,应该说他基本等同于是diff和patch的组合。不过因为SVN没有index的概念,所以merge的操作会和当前working tree上的修改合并在一起。
关于历史信息方面,因为svn的merge实际是patch文件内容本身,所以,不同分支上的历史信息不会在merge以后的主干上体现出来,而git的merge,如果没有冲突的话,实际是merge commit树的继承关系,所以,所有的历史信息在merge以后的commit中都能够被索引到。
11)获取单纯的代码
在svn中,如果不需要任何历史信息,只想要某个版本纯粹的代码(经常会有这种需求,这样做本地数据比较小) 那么,使用svn export命令即可以实现。
在git中,似乎没有这样的命令,不过,由于git的本地仓库信息完全维护在project根目录的.git目录下,(不像svn一样,每个子目录下都有单独的.svn目录)。所以,只要clone,checkout然后删除.git目录就可以了。
对比结果:
1.git是分布式的scm,svn是集中式的。(最核心)
2.git是每个历史版本都存储完整的文件,便于恢复,svn是存储差异文件,历史版本不可恢复。(核心)
3.git可离线完成大部分操作,svn则不能。
4.git有着更优雅的分支和合并实现。
5.git有着更强的撤销修改和修改历史版本的能力
6.git速度更快,效率更高。
基于以上区别,git有了很明显的优势,特别在于它具有的本地仓库。
附讨论一篇
Ghoststears:
任何事情,归根结底都是人的问题,工具只是工具。
SVN 是集中式的,会出现你说的耦合。但从另外一个方面来说,这也要求开发人员代码的规范:不要一个函数干很多事情,不要一个文件写很多个类。
另外,将不可运行的代码提交到任何版本控制系统中都是没有意义的。这也就是版本控制的核心思想之一。也就是提交的粒度:原子性。所谓的原子性,也就是完成 一件任务,这个任务可以是一个函数声明,也可以是一个函数的实现,亦或是一个子系统。但这个任务的完成的标志就是代码可以运行,不能运行的代码,最多也就 是完成了半个任务。这个是不符合版本控制思想的。试想,你 update 到某一个 version 的时候,代码竟然是不能运行的,是何心情???
将不能运行的代码提交,完全是开发人员素质或者公司管理流程、机制的问题。
另外,很多人都强调:我晚上下班了要在家里干活,不能提交!!!来抨击集中式版本控制工具。且不说对待工作和生活态度。先看看国内的企业,防员工如防贼的多的去了。有多少人能带着笔记本,把公司的源代码签出来呢???
版本控制系统中,工具只是其中一环。要结合公司的策略来选用合适的工具。版本控制 != 版本控制工具 !!!= 源代码管理。
最后,人各有喜好。上纲上线的,完全没有必要。
楼主观点:工具无好坏,存在意味着价值。各有各的优缺点,如上讨论:公司怕员工把代码带出去。如果公司用的是git,累死公司也管不住,相反,svn可以解决这个问题。侧面想想,这又何尝不是svn在这方面的有点呢?还是那句话,工具无好坏,用着顺手,适合场景即可。
参考文献:
https://blog.csdn.net/a117653909/article/details/8952183
http://wuzhangshu927.blog.163.com/blog/static/1142246872011621113641834/
http://www.cnblogs.com/qinfengxiaoyue/p/3450194.html
https://blog.csdn.net/bruce_6/article/details/38299677