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的分支却是相当的简单和有趣。你可以从同一个工作目录下快速的在几个分支间切换。你很容易发现未被合并的分支,你能简单而快捷的合并这些文件。
4)GIT没有一个全局的版本号,而SVN有:
目前为止这是跟SVN相比GIT缺少的最大的一个特征。
5)GIT的内容完整性要优于SVN:
GIT的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。
2、SVN和GIT基本操作对比
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目录就可以了。