CVS SVN VSS 使用对比

gongshijun00 2010-08-10

版本控制系统里团队开发不免要用上CVSSVNVSSClearCase等工具。至于选择上,则是根据开发团队搭建的平台,使用的编程语言相关联。

如果用.net平台开发,VSS无疑首选,尽管它曾经有不经时事的诟病,现在发展的功能也蛮强的。如果有服务器linux系统,则CVS,SVN都可以选择。现在SVN大有取代CVS之势。然而很多古老的程序员还是对CVS情有独钟。

如下节选一些网上的对比说明,我作以综述。当然,真正要弄懂这些版本控制系统,还是要花费巨大工夫学习研究,不可能在baidu或者google几下就能完成的。

一、Subversion包含绝大部分CVS功能

Subversion作为CVS的重写版和改进版,其目标就是作为一个更好的版本控制软件,取代目前流行的CVS。Subversion的主要开发人员都是业界知名的CVS专家。Subversion支持绝大部分的CVS功能/命令;Subversion的命令风格和界面也与CVS非常接近。当然,不同的地方正是对CVS的改进。

二、全局性的版本编号

一个新的版本,并得到一个自增量的版本号N+1,该版本号并不针对某个特定的文件,而是全局性的、针对整个版本库的。因此,我们可以将Subversion的版本库看作是一个文件系统或文件目录树的数组。

从技术的角度来说,在Subversion中,"文件foo.c的第5版本"这个说法是错误的;正确的说法应该是:"文件foo.c在版本库被修改了5次,即执行5次commit后是什么样子?"。显然,在Subversion中,版本库被修改5次后foo.c的内容,和被修改了6次后foo.c的内容很可能完全一样,因为版本库的第6次修改很可能只修改了版本库的其他部分,而并没有对foo.c的进行修改。相反,在CVS中,文件foo.c的第1.1版本和第1.2版本总是不同的。

Subversion的全局性版本编号为Subversion带来了诸多的优势:如对目录或文件执行拷贝,无论涉及多少文件,Subversion不需要对单个文件依次执行拷贝命令,仅仅需要建立一个指向相应的全局版本号的一个指针即可。

三、目录的版本控制

CVS只能对文件进行版本控制,不能对目录进行版本控制,因此CVS没有任何关于文件"移动"(move)操作的概念。当人为进行文件移动操作时,CVS只能注意到,一个文件在一个位置被删除了,而在一个新位置创建了另外一个文件。由于它不会连接两个操作,因此也很容易使文件历史轨迹丢失。设置CVS存储库时,必须非常谨慎地为每个文件选择准确的位置,因为在设置之后,几乎就要一直使用这个位置了。

同样由于CVS不记录目录的版本历史,CVS不支持对文件的"重命名"(rename),人为的对文件进行重命名会使得命名前后的文件失去历史联系,而记录历史本来是版本管理的主要目的。

还有,CVS不支持对文件的"拷贝"(copy),人为的拷贝对CVS而言,只能看到新的文件的增加,而不能记录拷贝源文件和目标文件之间的联系。

综上所述,缺乏对文件"移动"、"重命名"、"拷贝"的支持的根源在于CVS不能记录目录的版本历史,而这些操作在当前的软件开发过程中经常发生,这正是Subversion被开发并取代CVS的主要原因之一。

Subversion将目录作为一类特殊的文件来处理(事实上,从文件系统的角度来看,目录确实是一类特殊的文件,当目录中的子目录/文件被删除、重命名、或新的子目录/文件被创建时,目录的内容将发生改变)。因此,Subversion象记录普通文件的修改历史一样记录对目录的修改历史,当发生文件/目录的移动、重命名或拷贝操作时,Subversion能够准确记录操作前后的历史联系。同样,象对文件的不同历史版本进行比较一样,Subversion支持对目录的不同历史版本的比较,清晰展现目录的变化历史。

四、原子性提交

从使用者的角度来看,CVS和Subversion都支持对多个文件修改的批量提交,但二者在实现方式上存在本质的区别。

CVS采用线性、串行的批量提交,即依次地,一个接一个地执行提交,每成功提交一个文件,该文件的一个新的版本即被记录到版本库中,提交时用户提供的日志信息被重复地存储到每一个被修改的文件的版本历史中。

CVS串行批量提交模式的弊端在于-当任何原因造成批量操作的中断时(典型原因包括:网络中断、客户端死机等),版本库往往处于一个不一致的状态:原本应该全部入库的文件只有一部分入库,很有可能版本库中的最新版本不能顺利编译,更为严重的是,随着其他的用户执行cvsupdate操作,该不一致性将迅速在开发团队中扩散,从而严重影响团队的开发效率,并存在质量隐患。另外,假如该批量提交的中断没有被及时发现,开发团队往往要花更多的时间进行软件调试和排错。

CVS即使在批量提交不发生中断时也会造成不一致:假设用户A启动一个需要较长时间才能完成的批量提交;与此同时,用户B执行cvsupdate操作。此时,用户B很有可能得到一个不一致的更新,即用户B通过"更新"操作,得到用户A的部分修改文件。

Subversion彻底消除了CVS的以上弊端。无论批量提交包含多少文件修改,只有当全部文件修改都成功入库,该提交才变得有效,才对其他用户可见;否则,无论任何原因造成中断,Subversion都会自动执行"回滚"(rollback)操作。换一个说法,Subversion保证所有的修改要么全部入库生效,要么一个也不入库,即对版本库不作任何的修改。这就是Subversion的原子性提交(atomiccommit)。

由于Subversion的原子性提交特性和全局版本编号方式,当提交成功完成时,一个唯一的、新的全局版本编号产生,而提交时用户提供的日志信息与该新的版本编号关联,只进行一次存储(区别于CVS的按文件重复存储)。

五、支持变更集概念

由于Subversion的所有提交是原子性的,每次成功提交形成的唯一的全局版本号对应此次批量提交的所有文件修改,也就是说,一个Subversion版本号其实对应了一个逻辑上的变更集(changeset),该变更集可能对应于对一个BUG的修复,或者对应于对一个已有功能的改进,或者对应于一个新功能的实现。可以说,变更集是一个软件开发活动的逻辑结果,该变更集可以通过其对应的版本号在软件开发的其他过程中(如软件合并/集成过程,软件发布管理,变更管理系统,缺陷追踪系统)被引用。因此,Subversion将版本管理从单纯的、单个的文件修改的层次通过逻辑上的抽象,上升到更便于理解和交流的开发活动的层次。

六、差异化的二进制文件处理

由于历史原因,CVS主要是为早期的程序员设计的,CVS能够有效处理文本文件(或ASCII文件,源代码文件),可以对文本文件进行差异化的存储、新旧版本的比较,文件合并等;但对于二进制文件,CVS则明显力不从心。在CVS的版本库中,对于二进制文件的历史版本,CVS唯一能做的就是对不同的版本进行独立的、冗余的存储,哪怕版本之间其实只存在微小的差异。举例而言,一个10M的二进制文件(照片、图形文件、机械设计文件、电子设计文件)假如每周修改一次,无论每次修改的大小,一年下来,仅该文件就要消耗500M以上的存储空间。而且,客户端每次获取该文件的新版本都要消耗10M的网络流量。

对于目前的开发团队,无论是软件开发,Web站点的开发,手机等电子产品的研发,需要进行版本管理的不仅是源代码等文本文件,还需要管理需求文档、设计文档、测试文档、用户手册,图形图像文件,机械/电子设计文件等诸多的二进制文件,CVS显然不是一个好的选择。

与CVS不同,Subversion采用统一的二进制差异算法(binarydifferencingalgorithm),即对文本文件和二进制文件采用相同的差异比较算法,并以相同的方式在版本库中进行存储:每次提交后版本库中只存储相对于先前版本的差异,从而可以节省大量的存储空间。

该二进制差异算法不仅应用在版本的存储上,更为重要的是,Subversion对二进制文件与文本文件一视同仁,当客户端需要获取新的版本时(如执行svnupdate),在网络上只有版本的差异被传输,从而大大减少对网络带宽的消耗。更多细节参见"七、双向的差异化-压缩网络传输"。

七、双向的差异化-压缩网络传输

如上所述,CVS对二进制文件不能进行有效的差异化处理。对于文本文件,CVS仅仅支持单向的差异化传输:从CVS到客户端的传输是差异化的,即执行cvsupdate时,只有差异的部分从服务器传输到客户端;而当执行cvscommit时,无论代码变化多少,CVS都需要从客户端向服务器完整传输被修改文件的全部内容,不能只传输差异。

相反,无论是文本文件还是二进制文件,Subversion都进行双向的差异化传输,并且差异化内容还要进行压缩/解压缩的过程:在服务器端获取差异显而易见,与CVS类似;Subversion在客户端获取差异的秘密在于—Subversion在客户端的工作拷贝中隐含了每个文件的一个"只读的、干净的"副本(该副本隐藏在隐含目录.svn里,通常不可见,该副本还有更多的妙用,参见"十二、更多的本地/离线操作"),通过比较用户在客户端的修改和该隐含的副本,Subversion获取需要真正传送到服务器的差异,并对差异进行压缩后才进行网络传输。

对CVS而言,操作的成本(网络带宽消耗是最大的操作成本)与被修改的文件的大小成比例,而与修改本身的大小无关;对Subversion而言,操作成本只与修改本身的大小成比例,而与被修改的文件的大小无关。因此,与CVS相比,Subversion消耗更少的网络带宽(以客户端的存储空间换取更少的带宽消耗在目前的计算环境下应该是个相当不错的选择!)。Subversion更加适合基于互联网(或广域网)进行协作开发的地理上分布的团队—版本服务器集中、单一;客户端广泛分布。

八、高效、快捷创建分支和基线

CVS和Subversion都支持分支(branch)和基线(tag),通过分支与合并,可以有效支持大项目的并行开发模式;通过基线管理,可以准确标识一组文件的版本,有效进行软件发布管理和必要时的历史回溯。

但CVS和Subversion在实现分支和基线的方式上存在很大的不同。CVS在创建分支的时候,需要对所有进行分支的文件进行依次的操作,因此分支的建立成本(主要是建立分支所需的时间,或消耗的计算资源)与参与分支的文件数量成比例,项目越大,版本库越大,文件越多,分支的建立成本越高;基线(tag)的建立与此类似。

Subversion的分支和基线是通过执行"拷贝"来建立的:回想一下在没有引入版本管理工具的时候我们是如何进行所谓的"分支"和"基线"管理的?答案显然是"拷贝"—我们通过"拷贝"或"备份"来建立基线;同样,为支持多个开发人员可以同时进行开发,我们为每个开发人员创建一份"拷贝"。由此看来,Subversion通过"拷贝"来建立分支和基线显得非常自然,有点"返朴归真"的意思。

由于Subversion的全局版本号特性,Subversion中分支或基线的创建过程,或Subversion中的"拷贝"过程,真正的操作是在版本库中创建一个到某一全局版本号的指针(pointer),不再需要针对众多的单个文件依次执行操作。因此,该操作的成本为一个很小的常数,与项目大小,版本库大小,文件数目的多少无关;并且,分支或基线的建立不需要进行版本的冗余存储,新建立的分支或基线基本不占用版本库空间,分支的后续存储空间的开销也只与修改的大小有关。

九、集成ApacheWebServer,提供更多的特性

Subversion通过与ApacheWebServer的集成,可以提供基于http/https协议的版本库访问机制,从而支持Subversion跨越防火墙的安全访问。除此以外,Subversion还可以利用更多的Apache特性,包括但不限于:Apache丰富的用户认证机制(包括通过LDAP服务器如WindowsActiveDirectory服务器的用户认证),基于目录路径的精细粒度的访问控制,对传输的网络流量进行压缩/解压缩,浏览版本库目录结构等等。

十、支持WebDAV

WebDAV(Web-basedDistributedAuthoringandVersioning)是一种基于HTTP1.1协议的通信协议.它扩展了HTTP1.1,在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法,使应用程序可直接对WebServer直接读写,并支持写文件锁定(Locking)及解锁(Unlock),还可以支持文件的版本控制。

Microsoftwindows2000/XP及IE,Office还有Adobe/MicroMedia的DW等都支持WebDAV,这又大大增强了Web应用的价值,以及效能。对于需要大量发布内容的用户而言,应用WebDAV可以降低对CMS系统的依赖,而且能够更自由的进行创作。上传、下载变得轻松自如。

Subversion通过与ApacheWebServer的集成,支持WebDAV协议,使得业务用户(businessusers)或非技术用户在不安装任何版本管理客户端的情况下轻松访问Subversion版本库,不改变业务用户已有使用习惯,支持分布的业务用户对文档的评审、修改并实现版本控制,真正将软件开发的生命周期从开发/技术团队扩展到项目的全部干系人(stakeholder),避免通过电子邮件传递文档的混乱与无序、通过Windows操作系统共享造成的安全漏洞、病毒攻击、历史版本被覆盖或丢失、审计困难等诸多典型问题。

十一、更好的冲突标识与处理

CVS和Subversion都支持通过分支与合并进行并行开发,并可以自动检测到合并时的冲突(conflicts),并在合并结果中以<<<<<<…>>>>>>标识合并的冲突部分。

在CVS中,经常会出现由于用户的疏忽(如,没有注意到冲突,或没有完全处理好冲突)而将仍然带有<<<<<<…>>>>>>冲突标识符号的文件直接进行提交(commit),从而在版本库中产生垃圾版本。

Subversion有效解决了CVS的以上问题:Subversion记录并保持文件的冲突状态,只有当用户明确执行svnresolved命令后,该冲突状态标识才被复位,该文件才能被提交,从而大大减少了将仍然带有<<<<<<…>>>>>>冲突标识符号的文件直接进行提交的可能性。

十二、更多的本地/离线操作

众所周知,CVS客户端的工作拷贝中包含了一个隐含目录CVS,该目录中记录了客户端需要的一些管理信息;与此类似,Subversion的客户端工作拷贝中也包含了一个隐含目录.svn,该目录中同样记录了客户端需要的一些管理信息,如版本库URL,当前访问版本号等。

与CVS不同的是,Subversion的.svn目录中还包含了工作拷贝中每一个文件的一个"只读的、干净的"副本。正是由于该副本的存在,使得Subversion与CVS相比,可以执行更多的本地/离线操作,即某些操作不需要访问版本库服务器,因此不需要存在从客户端到服务器的网络链接,当然也不消耗任何网络带宽,这进一步增强了Subversion对广域网的友好支持。

Subversion的以下命令可以进行离线操作:

svnstatus-显示工作拷贝上的本地修改概况;

svndiff-显示工作拷贝上的本地修改细节,比较修改前后的内容;

svnrevert-撤销工作拷贝上的本地修改;

十三、对符号链接进行版本管理

在Unix文件系统中,符号链接(symboliclinks,包括硬链接和软链接)是一种重要的文件系统元素。CVS不能对符号链接进行版本管理;Subversion则可以对符号链接进行版本管理。

十四、元数据管理

与CVS相比,Subversion增加了元数据(metadata)管理机制。即可以对版本库中的文件或目录附加任意的"属性"(property),并记录属性的变化历史,也就是对元数据进行版本管理。一个Subversion属性是一个"属性名称/属性值"的二元组,如"BugNumber=100"就是一个属性,可以将该属性附加到版本N上,以说明版本N改正了编号为100的BUG。

Subversion元数据的目的是提供附件的信息以满足流程或过程自动化的需要,以增强Subversion的管理能力和自动化程度。Subversion自身就通过"属性"来存储一些特殊的信息。一个使用Subversion元数据的例子:可以在一些批处理的脚本程序或Subversion的钩子程序(hooks)中创建、访问、修改"属性"元数据来满足流程自动化的要求。

十五VSSCVS比较

VSS适合小团队使用,基本的配置管理功能都有。VSS最大的特点就是部署比较简单,上手比较快。VSS最大的缺点就是安全性问题,目录共享、文件方式存储等。当然VSS还只能在Windows下使用。

CVS了解过,应该说特点也很鲜明。首先CVS是开源软件,根据长期的流传,已经演变了很多版本,适合于不同的平台。因此,在CVS客户端上是多种多样的。其次,CVS的部署稍微复杂点,现对VSS来说,这是其一缺点。最后,CVS在配置管理的理念上,比VSS有所进步。

十六Vss与Svn的对比

1.SVN支持重命名,这对Java开发来说非常重要。

为了得到更好的代码,开发中需要经常进行重构,重构就经常涉及到文件的重构名,而重命名中VSS中是不被支持的。

2.开发的时候不一定要锁定。

一方面导致重构不方便,另一方面,不能离线开发,使用SVN就不同,可以带回家继续开发,回来后,提交就行了。

3.多平台。

可以支持多个平台下的操作

4.更好的客户端支持。

Eclipse中的VSSPlugin不如它的SVNPlugin好用。一个在Windows下用的SVN客户端TortoiseSVN也比VSS的客户端好用(VSS只有微软提供的一个GUI客户端)。

5.更好地与外围工具集成。

各种各样的外围工具(主要是服务器端),满足多种需要。如果有需要,也可以自己写插件或管理脚本,开放的架构,允许我们这样做。

6.方便。

一个例子:部署应用的时候,以前的做法是找出一个项目中修改过的文件,更新到服务器上去,现在可以在服务器上执行svnexport命令,把代码库中的最新版本导出,完成部署(也可以替换回老版本)。

7.速度与稳定性看起来都不错。

学习它的管理、它的工作方式,是值得的。而VSS是一个已经被逐渐抛弃的软件。如果时间不是多得没处用,那么就把时间花在最值得花的东西上面。

相关推荐

xylin / 0评论 2014-03-26