版本控制工具演进(RVS、CVS、SVN、Git)

本文介绍了几种版本控制系统。RCS对文件集中管理,避免多人冲突;CVS继承RCS理念,采用复制 - 修改 - 合并模式,但存在合并非原子操作等问题;SVN沿袭CVS,在多方面改进;Git由Linus开发,是分布式VCS,保存文件本身,能快速查阅历史版本,鼓励按需创建分支。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RCS (Revision Control System)

早在70年代末80年代初,VCS的概念已经存在,比如UNIX平台的RCS (Revision Control System)。RCS是由Walter F. Tichy使用C开发。RCS对文件进行集中式管理,主要目的是避免多人合作情况下可能出现的冲突。如果多用户同时写入同一个文件,其写入结果可能相互混合和覆盖,从而造成结果的混乱。你可以将文件交给RCS管理。RCS允许多个用户同时读取文件,但只允许一个用户锁定(locking)并写入文件 (类似于多线程的mutex)。这样,当一个程序员登出(check-out,见RCS的co命令)某个文件并对文件进行修改的时候。只有在这个程序完成修改,并登入(check-in,见RCS的ci命令)文件时,其他程序员才能登出文件。基本上RCS用户所需要的,就是co和ci两个命令。在co和ci之间,用户可以对原文件进行许多改变(change, or file delta)。一旦重新登入文件,这些改变将保存到RCS系统中。通过check-in将改变永久化的过程叫做提交(commit)

CVS (Concurrent Versions System)

1986年,Dick Grune写了一系列的shell脚本用于版本管理,并最终以这些脚本为基础,构成了CVS (Concurrent Versions System)。CVS后来用C语言重写。CVS是开源软件。在当时,Stallman刚刚举起GNU的大旗,掀起开源允许的序幕。CVS被包含在GNU的软件包中,并因此得到广泛的推广,最终击败诸多商业版本的VCS,呈一统天下之势。

 

CVS继承了RCS的集中管理的理念。在CVS管理下的文件构成一个库(repository)。与RCS的锁定文件模式不同,CVS采用复制-修改-合并(copy-modify-merge)的模式,来实现多线开发。CVS引进了分支(branch)的概念。多个用户可以从主干(也就是中心库)创建分支。分支是主干文件在本地复制的副本。用户对本地副本进行修改。用户可以在分支提交(commit)多次修改。用户在分支的工作结束之后,需要将分支合并到主干中,以便让其他人看到自己的改动。所谓的合并,就是CVS将分支上发生的变化应用到主干的原文件上。

 

CVS也有许多常常被人诟病的地方,比如下面几条:

1、合并不是原子操作(atomic operation):如果有两个用户同时合并,那么合并结果将是某种错乱的混合体。如果合并的过程中取消合并,不能撤销已经应用的改变。

2、文件的附加信息没有被追踪:一旦纳入CVS的管理,文件的附加信息(比如上次读取时间)就被固定了。CVS不追踪它所管理文件的附加信息的变化。

3、主要用于管理ASCII文件:不能方便的管理Binary文件和Unicode文件

4、分支与合并需要耗费大量的时间:CVS的分支和合并非常昂贵。分支需要复制,合并需要计算所有的改变并应用到主干。因此,CVS鼓励尽早合并分支。

SVN(Subversion)

Subversion的开发者Karl Fogel和Jim Blandy是长期的CVS用户。赞助开发的CollabNet, Inc.希望他们写一个CVS的替代VCS。这个VCS应该有类似于CVS的工作方式,但对CVS的缺陷进行改进,并提供一些CVS缺失的功能。这就好像刘备从曹营拉出来单干的刘备一样。

 

总体上说,Subversion在许多方面沿袭CVS,也是集中管理库,通过记录改变来追踪历史,允许分支和合并,但并不鼓励过多分支。Subversion在一些方面得到改善。Subversion的合并是原子操作。它可以追踪文件的附加信息,并能够同样的管理Binary和Unicode文件。但CVS和Subversion又有许多不同:

 

与CVS的,v文件存储模式不同,Subversion采用关系型数据库来存储改变集。VCS相关数据变得不透明。

CVS中的版本是针对某个文件的,CVS中每次commit生成一个文件的新版本。Subversion中的版本是针对整个文件系统的(包含多个文件以及文件组织方式),每次commit生成一个整个项目文件系统树的新版本

Git

git的作者是Linus Torvald。对,就是写Linux Kernel的那个Linus Torvald。Linus在贡献了最初的Linux Kernel源代码之后,一直领导着Linux Kernel的开发。Linus Torvald本人相当厌恶CVS(以及Subversion)。然而,操作系统内核是复杂而庞大的代码“怪兽” (2012年的Linux Kernel有1500万行代码,Windows的代码不公开,估计远远超过这一数目)。Linux内核小组最初使用.tar文件来管理内核代码,但这远远无法匹配Linux内核代码的增长速度。Linus转而使用BitKeeper作为开发的VCS工具。BitKeeper是一款分布式的VCS工具,它可以快速的进行分支和合并。然而由于使用证书方面的争议(BitKeeper是闭源软件,但给Linux内核开发人员发放免费的使用证书),Linus最终决定写一款开源的分布式VCS软件:git。

 

对于一个开发项目,git会保存blob, tree, commit和tag四种对象。

1、文件被保存为blob对象。

2、文件夹被保存为tree对象。tree对象保存有指向文件或者其他tree对象指针。

上面两个对象类似于一个UNIX的文件系统,构成了一个文件系统树。

3、一个commit对象代表了某次提交,它保存有修改人,修改时间和附加信息,并指向一个文件树。这一点与Subversion类似,即每次提交为一个文件系统树。Commit是文件集的改动。

4、一个tag对象包含有tag的名字,并指向一个commit对象。Tag是给Commit的标签。

 

可以看到,与CVS,Subversion保存改变(file delta)的方式形成对照,git保存的不是改变,而是此时的文件本身。由于不需要遵循改变路径来计算历史版本,所以git可以快速的查阅历史版本。git可以直接提取两个commit所保存的文件系统树,并迅速的算出两个commit之间的改变。

 

在整个开发过程中,可能会有许多次提交(commit)。每次commit的时候,git并不总是复制所有的对象。git会检验所有对象的HASH值。如果该对象的HASH值已经存在,说明该对象已经保存过,并且没有发生改变,所以git只需要调整新建tree或者commit中的指针,让它们指向已经保存过的对象就可以了。git在commit的时候,只会新建HASH值发生改变的对象。如下图所示,我们创建新的commit的时候,只需要新建一个commit对象,一个tree对象和一个blob对象就足够了,而不需要新建整个文件系统树。

 

由于git创建、合并和删除分支的成本极为低廉,所以git鼓励根据需要创建多个分支。实际上,如果分支位于不同的站点(site),属于不同的开发者,那么就构成了分布式的多分支开发模式。每个开发者都在本地复制有自己的库,并可以基于本地库创建多个本地分支工作。开发者可以在需要的时候,选取某个本地分支与远程分支合并。git可以方便的建立一个分布式的小型开发团队。比如我和朋友两人各有一个库,各自开发,并相互拉对方的库到本地库合并(如果上面master,develop代表了两个属于不同用户的分支,就代表了这一情况)。当然,git也允许集中式的公共仓库存在,或者多层的公共仓库,每个仓库享有不同的优先级。git的优势不在于引进了某种开发模式,而是给了你设计开发模式的自由。

Git:

菜鸟教程:https://www.runoob.com/git/git-tutorial.html

官方教程:https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git

参考:https://www.cnblogs.com/vamei/archive/2013/02/21/2918069.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值