1.3 SVN——集中式版本控制集大成者

Subversion[1],由于其命令行工具名为svn,因此通常被简称为SVN。SVN由CollabNet公司于2000年资助并开始开发,目的是创建一个更好用的版本控制系统以取代CVS。SVN的前期开发使用CVS做版本控制,到了2001年,SVN已经可以用于自己的版本控制了[2]

我开始真正关注SVN是在2005年,那时SVN正经历着后端存储上的变革,即从BDB(简单的关系型数据库)到FSFS(文件数据库)的转变。相对于BDB而言,FSFS具有稳定、免维护和实现的可视性高等优点,于是我马上就被SVN吸引了。图1-2展示了SVN版本控制系统的工作原理。

1.3 SVN——集中式版本控制集大成者 - 图1

图 1-2 SVN版本控制系统示意图

SVN的每一次提交,都会在服务器端的db/revs和db/revprops目录下各创建一个以顺序数字编号命名的文件。其中,db/revs目录下的文件(即变更集文件)记录了与上一个提交之间的差异(字母A表示新增,M表示修改,D表示删除)。在db/revprops目录下的同名文件(没有在图1-2中体现)则保存着提交日志、作者、提交时间等信息。这样设计的好处有:

拥有全局版本号。每提交一次,SVN的版本号就会自动加一。这为SVN的使用提供了极大的便利。回想CVS时代,每个文件都拥有各自独立的版本号(RCS版本号),要想获得全局版本号,只能通过手工不断地建立里程碑来实现。

实现了原子提交。SVN不会像CVS那样出现文件的部分内容被提交而其余的内容没有被提交的情况。

文件名不受限制。因为服务器端不再需要建立和客户端文件相似的文件名,于是,文件的命名就不再受服务器操作系统的字符集和大小写的限制。

文件和目录重命名也得到了支持。

SVN最具有特色的功能是轻量级拷贝,例如将目录trunk拷贝为branches/v1.x只相当于在db/revs目录中的变更集文件中用特定的语法做了一下标注,无须真正的文件拷贝。SVN使用轻量级拷贝的功能,轻松地解决了CVS存在的里程碑和分支的创建速度慢又不可见的问题,使用SVN创建里程碑和分支只在眨眼之间。

SVN在版本库授权上也有改进,不再像CVS那样依赖操作系统本身对版本库目录和文件进行授权,而是采用授权文件的方式来实现。

SVN还有一个创举,就是在工作区跟踪目录下(.svn目录)为当前目录中的每一个文件都保存一份冗余的原始拷贝。这样做的好处是部分命令不再需要网络连接,例如文件修改的差异比较,以及错误更改的回退等。

正是由于这些闪亮的功能特性,才使得SVN在CVS之后诞生的诸多版本控制系统中脱颖而出,成为开源社区一时的新宠,也成为当时各个企业进行版本控制的最佳选择之一。

但是,相对于CVS,SVN在本质上并没有突破,都属于集中式版本控制系统。即一个项目只有唯一的一个版本库与之对应,所有的项目成员都通过网络向该服务器进行提交。这样的设计除了容易出现单点故障以外,在查看日志和提交数据等操作时的延迟,会让基于广域网协同工作的团队抓狂。

除了集中式版本控制系统固有的问题外,SVN的里程碑和分支的设计也被证明是一个错误,虽然这个错误的设计使得SVN拥有了快速创建里程碑和分支的能力,但是这个错误的设计也导致了如下的更多问题。

项目文件在版本库中必须按照一定的目录结构进行部署,否则就可能无法建立里程碑和分支。

我在项目咨询过程中见过很多团队,直接在版本库的根目录下创建项目文件。这样的版本库布局,在需要创建里程碑和分支时就无从下手了,因为根目录是不能拷贝到子目录中的。所以SVN的用户在创建版本库时必须遵守一个古怪的约定:先创建三个顶级目录/trunk、/tags和/branches。

创建里程碑和分支会破坏精心设计的授权。

SVN的授权是基于目录的,分支和里程碑也被视为目录(和其他目录没有分别)。因此每次创建分支或里程碑时,就要将针对/trunk目录及其子目录的授权在新建的分支或里程碑上重建。随着分支和里程碑数量的增多,授权愈加复杂,维护也愈加困难。

分支太随意从而导致混乱。SVN的分支创建非常随意:可以基于/trunk目录创建分支,也可以基于其他任何目录创建分支,因此SVN很难画出一个有意义的分支图。再加上一次提交可以同时包含针对不同分支的文件变更,使得事情变得更糟。

虽然SVN在1.5版之后拥有了合并追踪功能,但这个功能会因为混乱的分支管理而被抵消。

2009年年底,SVN由CollabNet公司交由Apache社区管理,至此SVN成为了Apache组织的一个子项目[3]。这对SVN到底意味着什么?是开发的停滞?还是新的开始?结果如何我们将拭目以待。

[1]http://subversion.apache.org/

[2]http://svnbook.red-bean.com/en/1.5/svn.intro.whatis.html#svn.intro.history

[3]http://en.wikipedia.org/wiki/Apache_Subversion