Torres-tao  

区别:

1、SVN是集中式的版本控制系统,而Git是分布式版本控制系统;

2、SVN是按照原始文件存储的,体积较大,而Git是按照元数据方式存储的,体积很小;

3、Git的分支操作不会影响其他开发人员,而SVN会影响

一、集中式vs分布式

Subversion:集中式的版本控制系统

集中式的版本控制系统都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连接到这台服务器,取出最新的文件或者提交更新。

SVN的特点概括起来主要有以下几点:

  • 每个版本库有唯一的URL,每个用户都从这个地址获取代码和数据
  • 获取代码的更新,也只能连接到这个唯一的版本库,同步以取得最新数据
  • 提交必须有网络连接(非本地版本库)
  • 提交需要授权,如果没有写权限,提交会失败
  • 提交并非每次都能够成功。如果有其他人先于你提交,会提示“改动基于过时的版本,先更新再提交”
  • 冲突解决是一个提交速度的竞赛:手快者,先提交,平安无事;手慢者,后提交,可能遇到麻烦的冲突解决

优点:每个人都可以一定程度上看到项目上的其他人正在做些什么,而管理员也可以轻松掌握每个开发者的权限

缺点:中央服务器的单点故障。若是宕机一小时,那么在这一小时内,谁懂无法提交更新、还原、对比等,也就无法协同工作。如果中央服务器的磁盘发生故障,并且没做过备份或者备份不及时的话,还会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录,被用户端提取出来的某些快照数据除外,但这样的话依旧是个问题,你不能保证所有的数据都已经有人提取出来。

Subversion原理上只关心文件内容的具体差异。每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容。

Git:分布式的版本控制系统

Git记录版本历史只关心数据的整体是否发生变化。Git不保存文件内容前后变化的差异数据

实际上,Git更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快照的索引。为提高性能,若文件没有变化,Git不会再次保存,而只对上次保存的快照作一连接。

在分布式版本控制系统中,客户端并不只提取最新版本的文件快照,而是把原始的代码仓库完整地镜像下来。这样子,任何一处协同工作用的服务器发送故障,事后都可以用任何一个镜像出来的本地仓库恢复。这类系统都可以指定和若干不同的远程代码仓库进行交互。藉此,你就可以在同一个项目组,分别和不同工作小组的人相互协作,可根据需要设定不同的协作流程。

Git具有以下特点:

  • Git中每个克隆(clone)的版本库都是平等的,你可以从任何一个版本库的克隆来创建属于你自己的版本库,同时你的版本库也可以作为源提供给他人
  • Git的每一次提取操作,实际上都是一次对代码仓库的完整备份
  • 提交完全在本地完成,无须别人给你授权,你的版本库你做主,并且提交总是会成功
  • 甚至基于旧版本的改动也可以成功提交,提交会基于旧的版本创建一个新的分支
  • Git的提交不会被打断,直到你的工作完全满意了,PUSH给他人或者他人PULL你的版本库,合并会发生在PULL和PUSH的过程中,不能自动解决的冲突会提示你手动完成
  • Git也可以模拟集中式的工作模式
  • Git版本库统一放在服务器中
  • 可以为Git版本库进行授权:谁能创建版本库、谁能向版本库PUSH、谁能够读取(克隆)版本库
  • 团队的成员先将服务器的版本库克隆到本地,并经常的从服务器的版本库拉取最新的更新
  • 团队的成员将自己的改动推到服务器的版本库中,当其他人和版本库同步时,会自动获取改变
  • Git的集中式工作模式非常灵活
  • 可在离线状态下,使用代码库
  • 只需在能够接入Git服务器所在网络时,PULL和PUSH即可完成和服务器同步以及提交
  • Git提供rebase命令,可让你的改动看起来是基于最新的代码实现的改动
  • Git有更多的工作模式可以选择,远非SVN可比

二、版本库与工作区

SVN的工作区和版本库是截然分开的,而Git的工作区和版本库是如影随形的

SVN的版本库和工作区是分离的

  • SVN的工作区和版本库物理上分开:SVN的版本库和工作区是存储在不同路径下,一般是在不同的主机中,SVN的企业家部署中,版本库在服务器上,只能通过https、http、svn等协议访问,而不能直接被用户接触到
  • SVN的工作区是一份版本库在某个历史状态下的快照,如:版本库最新的数据检出到工作区
  • SVN的工作区中每一个目录下都包含一个名为.svn的控制目录(隐藏的目录),该目录的作用是:
    • 标识工作区和版本库的对应关系
    • 包含一份该子目录下检出文件的原始拷贝。当文件改动的差异比较或本地改动的回退时,可以直接参考原始拷贝而无须通过网络访问远程版本库
  • SVN的.svn控制目录会引入很多麻烦:
    • .svn下的文件原始拷本,会导致在目录下按照文件内容搜索时,多出一倍的搜索时间和搜索结果
    • .svn很容易在集成时,引入产品中,尤其是Web应用,将.svn目录带入Web服务器会导致安全隐患。因为一个不允许目录浏览的Web目录,可以通过.svn/entries文件查看该目录下可能存在的文件

Git的版本库和工作区如影随形

  • Git的版本库和工作区在同一个目录下,工作区的根目录有一个.git的子目录,这个名为.git的目录就是版本库本身,它是Git用来保存元数据和对象数据库的地方。该目录十分重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据。
  • 工作区中其他文件为工作区文件,可能是从.git检出的,或者是要检入的,或者是运行产生的临时文件等
  • 版本库可以脱离工作区而存在,成为bare(赤裸)版本库。可以用-bare参数来创建。但是工作区不能脱离版本库而存在,即工作区的根目录下必须有一个名为.git的版本库克隆库。
  • Git的版本库因为在工作区中,能直接被用户接触到
    • 用户可以编辑.git/config文件,修改配置,增添新的源
    • 用户可以编辑.git/info/exclude文件,创建本地忽略
  • Git的工作区中只在工作区的根目录下有一个.git目录,此外再无任何控制目录。Git工作区下唯一的.git目录是版本库,并非.svn的等价物,如果删除了.git目录,而又没有该版本的其他镜像的话,版本库也永远的失去了
  • Git在本地的.git版本库,提供了完整的改动历史。除了和其他人数据交换外,任何版本库相关的操作都在本地完成,更多的本地操作,避免了冗长的网络延迟,大大节省了时间。例如:查看log,切换到任何历史版本等操作都无需连接网络。
  • Git如何保证安全:本地创建一个Git库,因为工作区和库是在用一个目录中,如果工作区删除了,或者所在的磁盘分区格式化了,数据不就全都没有了么?可这样处理:
    • 在一个磁盘分区中创建版本库(最好用-bare参数创建),然后在另外的磁盘分区中克隆一个新的作为工作区。在工作区的提交要不时地PUSH到另外分区的版本库,这样就实现了本地的数据镜像。甚至可以在本地创建更多的版本库镜像,安全性要比SVN的一个库加一个工作区安全
    • 此外,还可以将版本库共享给他人,当他人克隆了你的版本库时,你就拥有了一个异地备份。

三、全局版本号和全球版本号

SVN的全局版本号和CVS的每个文件都独立维护一套版本号相比,是一个非常大的进步。在看似简单的全局版本号的背后,是SVN提供对于事务处理的支持,每一个事务处理(即一次提交)都具有整个版本库全局唯一的版本号。

Git的版本号则更进一步,版本号是全球唯一的。Git对于每一次提交,通过对文件的内容或目录的结构计算出一个SHA-1哈希值,得到一个40位的十六进制字符串,Git将此字符串作为版本号。

SVN与Git版本号比较

  • git中所有保存在Git数据库中的数据都是用此40位的哈希值作为索引,而不是靠文件名
  • 使用哈希值做版本号的好处就是对于一个分布式的版本控制系统,每个人每次提交后形成的版本号都不会出现重复;另一好处是保证数据的完整性,因为哈希值是根据内容或目录结构计算出来的,所以我们还可以据此来判断数据内容是否被篡改
  • SVN的版本号是连续的,可以预判下一个版本号,而Git的版本号不是。因为svn是集中式版本控制,很容易实现版本号的连续性,Git是分布式的版本控制系统,每个人的提交都是各自独立完成的,没有先后之分(即使提交有先后之分,也由于pish/pull的方向和时机而不同)。git的版本号虽然不连续,但是是有线索的,即每一个版本都有对应的父版本,进而可以形成一个复杂的提交链。
  • Git的版本号简化:Git可以使用从左边开始任意长度的字串作为简化版本号,一般采用7位的短版本号。

四、部分检出

SVN可以将整个库检出到工作区,也可以将某个目录检出到工作区。对于要使用一个庞大、臃肿的版本库的用户来说,部分检出是非常方便和实际的。但是对于Git而言,它只支持全部检出,不支持按照目录进行部分检出。

SVN的部分检出

  • 在SVN中,从仓库checkout的一个工作树,每个子目录下都维护着自己的.svn目录,记录着该目录文件的修改情况以及和服务器端仓库的对应关系。所以SVN可以checkout部分路径下的内容,而不用checkout整个版本库或分支
  • SVN中有一条命令:svn export,可以将svn版本库的一个目录下所有内容导出到指定的目录下。SVN需要svn export命令是因为该命令可以导出一个干净的目录,即不包含.svn目录(包含配置文件和文件原始拷贝)

Git的检出

  • Git没有部分检出,这并不是说只有将整个库克隆下来才能查看文件。有很多git工具,提供直接浏览git库的功能,例如gitweb、trac的git版本库浏览、redmine的git版本库浏览。
  • Git-submodule可以实现版本库的模块化:Git通过子模块处理这个问题
  • Git为何没有实现svn export的功能?原因在于:git的本地仓库信息完全维护在project根目录的.git目录下(不像svn一样,每个子目录下都有单独的.svn目录)。所以,只要clone,然后删除.git目录就可以了。

五、更新和提交

更新操作

在SVN中,因为只有一个中心仓库,所以所谓的远程更新,也就是svn update,通过此命令来使工作区和版本库保持同步

对于git而言,别人的改动是存在于远程仓库上的,所以git checkout命令尽管在某些功能上和svn的update类似(例如取仓库特定版本的内容),但是在远程更新这一点上,还是不同的,不属于git checkout的功能覆盖范围。Git使用git fetch和git pull来完成远程更新任务,fetch操作只是将远程数据库的object拷贝至本地,然后更新remotes head的refs,git pull的操作则是在git fetch的基础上对当前分支外加merge操作。

SVN中的commit命令

对于SVN来说,由于是中心式的仓库管理形式,所以并不存在特殊的远程提交的概念,所有的commit操作都可以认为是对远程仓库的更新操作。在工作区对文件进行添加、修改、删除操作要同步到版本库,必须使用commit命令。

  • add命令,是将未标记为版本控制状态的文件标记为添加状态,并在下次提交时入库。
  • delete命令,是通过SVN来删除文件,并在下次提交后有效。

SVN有提交列表功能,即把某些文件加入到一个修改列表,提交可以只提交处于该列表的文件。

Git中的暂存区(stage)

Git管理项目时,文件在三个工作区域流转:Git的本地数据目录、工作目录以及暂存区域。暂存区域是介于workcopy和版本库 HEAD版本的一种中间状态。所谓的暂存区域只不过是个简单的文件,一般都放在git目录中。有时候人们会把这个文件叫做索引文件,不过标准说法还是叫暂存区域。

要将一个文件纳入版本管理的范畴,首先是要用git add将文件纳入stage的监控范围,只有更新到stage中的内容才会在commit的时候被提交。另外,文件本身的改动并不会自动更新到stage中去才会被提交。对于工作区直接删除的文件,需要使用git rm命令进行标记,在下次提交时,在版本库中删除。

  • 工作区的文件改动(新增、修改和删除),必须用git add或者git rm命令标识,使得改动进入stage
  • 提交仅针对加入stage的改动进行提交
  • 如果一个文件改动加入stage后再次改动,则后续改动不该懂stage。即该文件的改动有两个状态,一个是标记到stage中并在下次提交时入库的改动,另外的后续改动则不被提交,除非再次使用git add命令将改动加入到stage中
  • Git的stage让你在提交的时候清楚的知道git将要提交哪些改动。除非提交的时候使用-a参数

我们可以从文件所处的位置来判断其状态:如果是git目录中保存着的特定版本文件,就属于已提交状态;如果做了修改并已放入暂存区域,就属于已暂存状态;如果自上次取出后,做了修改但还没放到暂存群玉,就属于已修改状态;如果取出后未进行修改则是未修改状态。

在git中,因为由本地仓库和remote仓库之分,所以也就区别于commit操作,存在额外的push命令,用于将本地仓库的数据更新到远程仓库中去。git push可以选择需要提交的、更新的分支以及制定该分支在远程仓库上的命令。

六、分支和合并

Git和SVN的分支实现机制完全不同,这也直接导致了SVN在分支合并中困难重重。尽管在SVN 1.5之后,通过svn:mergeinfo属性引入;鹅合并追踪机制,但是在特定情况下,合并仍会出现很多困难。

SVN的分支合并

当在一个分支上工作数周之后,主干的修改也同时在进行着,两条线的开发会千差万别,当你向合并分支回主干,可能因为太多冲突,已经无法轻易合并你的分支和主干的修改。

另外一个问题,SVN不会记录任何合并操作,当你提交本地修改,版本库并不能判断出你是通过svn merge还是手工修改的这些文件,所以你必须手工记录这些信息(说明合并的特定版本号或是版本号的范围)

需解决以上的问题只有通过有规律的将主干合并到分支来避免,指定这样一个政策:每周将上周的修改合并到分支,注意这样做时需要小心,你必须手工记录合并的过程,以避免重复的合并,你需要小心的撰写合并的日志信息,精确的描述合并包括的范围。这样做耗时耗力

SVN的版本号是连续的版本号。每一次新的提交,版本号都会+1,无论这个提交是在哪个分支中进行的。SVN一个提交可以同时修改不同分支的不同文件,因为提交命令就可以在/trunk,/branches,/tags的上一级目录执行。

  • SVN的提交是单线索的,每一个提交(最原始的提交0除外)都只有一个父节点(版本号小一个的提交节点)
  • SVN的提交链只有一条,仅从版本号和提交说明,我们无法获得分支图
  • SVN的分支图在某些工具(如乌龟SVN)可以提供,那是需要对提交内容进行检查,对目录拷贝动作视为分支,对svn:mergeinfo的改动视为合并,但这会由于目录管理的灵活性,导致千奇百怪的分支图表。

Git的分支合并

在git版本库中创建分支的成本几乎为零,所以,不必吝啬多创建几个分支。当首次执行git init时,系统就会创建一个名为master的分支。而其他分支则通过手工创建。以下是一些常见的分支策略:

  1. 创建一个属于自己的个人工作分支,以避免对主分支master造成太多的干扰,也方便与他人交流协作
  2. 当进行高风险的工作时,创建一个试验性的分支,扔掉一个烂摊子总比收拾一个烂摊子好得多
  3. 合并别人修改的时候,最好创建一个临时的分支用来合并,合并完成后再“fatch”到自己的分支

七、撤销操作

提交的撤销

在SVN中一旦完成向服务器的数据提交,你就没有办法再从客户端追回,只能在后续的提交者修正(回退或修改)等。因为SVN作为集中式的版本控制,不能允许个人对已提交的数据进行篡改。SVN具有一个非常重要的特性就是它的信息从不丢失,即使当你删除了文件或目录,它也许从最新版本中消失了,但这个对象依然存在于历史的早期版本中。

Git则不同,Git是分布式版本控制系统,代码库是属于个人,允许任意修改。Git通过对提交建立数字摘要来保证提交的唯一性和不可更改性,通过版本库在多人之间的多份拷贝来保障数据的安全性。Git可以丢弃最新的一个或多个提交,使用git reset --hard命令可以永远丢弃最新的一个或几个提交。

提交说明的修改

提交后如果对提交说明不满意,如何实现对提交说明的修改:

Git可以使用命令git commit -amend修改提交说明

  • Git可以修改最后一次提交说明,并不是说不能修改历史版本的提交说明,只是修改最后一个版本提交说明拥有最简单的命令
  • Git修改提交说明,会改变提交的commit-id。即修改提交说明后,将会产生一个新的提交
  • Git可以通过git reset --hard,git commit -amend,git rebase onto等命令来实现对历史提交的修改
  • 使用stg工具可以更为简单的修改历史提交的提交说明,包括提交内容

SVN也可以修改提交说明,是通过修改提交的svn:log版本属性来实现的:

  • 不但可以修改最后一次提交的说明,并且可以修改历史提交的提交说明
  • SVN修改提交说明是不可逆的操作,可能会造成说明被恶意修改
  • SVN缺省关闭修改提交说明的功能。管理员在设置了提交说明更改的邮件通知后,才可以打开该功能。

修改和重构历史提交

Git可以修改和重构历史提交:使用Git本身的reset以及rebase命令可以修改或重整/重构历史提交,非常灵活。使用强大的stg可以使得历史提交的重构更为简洁,如果对stg或Hg/MQ熟悉的话。

SVN修改历史提交,只能由管理员完成。

SVN是集中式版本控制系统,从客户端一旦完成提交,就没有办法从客户端撤销提交。但是管理员可以在服务器端完成提交的撤销和修改,但是操作过程和代价较大。

八、权限管理

SVN通过对文件目录授权来实现权限管理,子目录默认继承父目录的权限。但是也有缺憾,即权限不能再分支中继承,不能对单个文件授权。例如为/trunk及其子目录的授权,不能继承到分支或标签中相应的目录下。

Git的授权做不到SVN那么精细。Git的授权模型只能实现非零即一式的授权,要么拥有全部的写权限,要么没有写权限,要么拥有整个版本库的读权限,要么禁用。

从技术上讲,Git可能永远也做不到类似SVN的路径授权:

  • 如果允许按照路径授权,则各个克隆的关系将不再是平等的关系,有的内容多,有的内容少,分布式的理念被破坏。
  • 如果只有部分路径可读,则克隆出来的提交和原始提交的提交ID可能不同。因为提交ID和提交内容有关,克隆中提交的部分内容被丢弃,势必提交的ID也要重新计算
  • 允许全部代码可读,只允许部分代码可写,在版本控制的管理下,是没有多大实际意义的,而且导致了提交的逻辑上的不完整

那有什么办法来解决授权问题呢?

  1. 公司内部代码开放。即代码在公司内部,对项目组成员一视同仁的开放
  2. 公司对代码库进行合理分解,对每个代码库分别授权,即某个代码库对团队成员完全开放,对其他团队成员完全封闭
  3. 公司使用SVN做集中式的版本控制,个人或团队使用Git-SVN。这样在无法改变公司版本控制策略时,程序员可以采用的变通之法
  4. Git服务器的部署实际上可以使用钩子对分支和路径进行写授权,即可以控制谁能够创建分支,能够写特定文件。

九、优缺点比较

SVN优缺点

优点:

1、管理方便,逻辑明确,符合一般人思维习惯

2、易于管理,集中式服务器更能保证安全性

3、代码一致性非常高

4、适合开发人数不多的项目开发

缺点:

1、服务器压力太大,数据库容量暴增

2、如果不能连接上服务器上,基本上不可以工作

3、不适合开源开发。但是一般集中式管理的有非常明确的权限管理机制(如分支访问限制),可以实现分层管理,从而很好的解决开发人数众多的问题。

Git优缺点

优点:

1、适合分布式开发,强调个体

2、公共服务器压力和数据量都不会太大

3、速度快、灵活

4、任意两个开发者之间可以很容易的解决冲突

5、离线工作

缺点:

1、学习周期相对而言比较长

2、不符合常规思维

3、代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息

转自:https://www.cnblogs.com/Sungeek/p/9152223.html

posted on 2022-05-16 18:39  雷子锅  阅读(401)  评论(0编辑  收藏  举报