【IT168 技术文章】
虽然我使用传统SCM(软件配置管理,或者叫RCS——版本控制系统)软件已经有很多年,从那个垃圾一般的VSS到功能强大的CVS和SVN都用过 一段时间,短则半年(VSS),长则数年(SVN)。但是对于分布式版本控制系统(DRCS),我也是刚接触不久,发现它们的确很不错,相比传统SCM来 说,是一种质的变化。
所谓DRCS是相对于传统集中式的SCM而言的。对于传统SCM来说,Repository是集中在唯一的一个地方, 所有的用户进行commit或update以及其它的相关操作基本上都需要能够直接连接到这个Repository才能进行。这就会存在一些比较麻烦的问 题,就我个人的体会来说,常见的麻烦事在于(以下仅以CVS和SVN为例,至于VSS——不能为rubbish浪费时间):
1、并不是所有的开发者都总能连接到Repository服务器,比如在没有网络连接或是网络连接受限的情况——当然SVN提供的HTTP访问方式部分解决了这种困难,但仍然不够。
2、在团队协作开发中,当变更冲突增加以后,处理起来会比较麻烦。
3、分支管理方面的功能还较弱。
4、安全性问题。不论是用独立服务器方式还是HTTP方式,用户认证方式都相对简单,当然也可以配置得更安全,但比较麻烦。
5、最后一个小问题就是:不论是CVS还是SVN,都会在工作目录的每个子目录里创建一个隐藏目录记录本地状态信息,比较烦人。
而DRCS的目标就是尽可能解决传统SCM存在的不足之处——包括但不限于我上面所说的那些。就我目前试用过的两个DRCS——Bazaar和Mercurial——来说,上面的问题都解决得比较好:
1、都可以在本地提供全部的版本控制功能,可以只在必要的时候合并更新到公共Repository中。
2、因为是针对分布式开发设计,变更合并功能强大。
3、分支管理功能同样强大。
4、Bazaar支持SFTP方式的push,而Mercurial支持SSH方式的push,二者都是基于安全的通讯协议并且使用系统的用户管理机制,在保证安全性的同时保持了使用上的简单性。
5、只在工作目录的顶层生成一个隐藏目录——就是本地Repository,保持了工作目录的清爽。
显然,DRCS天生是为了开源项目而量身定制的——因为开源项目的开发者往往都是在地理上极度分散的,但又需要对源码进行有效的版本管理。但是对于其它的软件项目来说,DRCS也同样是个好东西,特别是其变更合并功能和分支管理功能。
后面我会简单介绍一下我最近试用过的两款比较流行的DRCS——Bazaar和Mercurial。
其实这两款DRCS在命令定义方面都是继承传统的,所以学习起来并没有太大的复杂性,并且具有很多的共性——二者除了程序名不一样以外,常用的命令和参数定义都几乎是完全一样的,甚至一些配置文件都是类似的。
本篇介绍Bazaar
我知道Bazaar是从livid那里看到的,他这篇介绍基本上就是翻译Bazaar官方的一个快速入门文档,强烈推荐参考一下。
Bazaar的优点在于功能强大并且安装使用很方便。因为是用Python写的,只要在安装了Python之后,再安装一下Bazaar就可以使用了。需要注意的是,它的SFTP功能使用了两个包: pycrypto和paramiko。这是需要额外安装一下的。刚好我安装Bazaar的时候两个包的官方网站都不太正常(难道是RPWT?),最后只好通过GOOGLE找到别的镜像才下载到。
Bazaar 的缺点是速度太慢。它的慢倒不是像云风所说的那样,对大项目太慢,而是因为它是纯python的程序,在windows下每次运行都要启动python环 境,所以每次输入命令都要等上一会儿才执行,对于像我这种经常用status命令检查的人或是那些用小步迭代的XP方式开发的人来说,比较难以忍受。
据 说也有一个类似TortoiseSVN的ToroiseBZR,但是鉴于我对TSVN的使用经验来说,Windows的Explorer已经很不稳定了, 再加这个东东就不稳定得受不了了。所以我还是不用Tortoise了,再说用惯了命令行操作在很多时候比用Tortoise还方便。
基本的使用方法参见前面链接的那篇livid翻译的快速入门吧。我这里只说一下远程Repository操作方面的问题。
把本地Repository的更新提交到远程Repository可以通过SFTP,这也就意味着服务端是免安装免配置的,这一点我觉得实在是太方便了。
bzr push sftp://jod@jod.example.com/public_html/foobar.joe/
如果要从远程Repository取得一个本地副本,理论上也可以通过SFTP:
bzr branch sftp://jod@jod.example.com/public_html/foobar.joe/
不 过试用下来我碰到一个问题,通过SFTP作push是没有问题,但是如上面的命令作checkout或branch操作时,却只会下载一个本地 Repository的副本(.bzr目录),不会生成工作目录和文件。即使再用update也不行,不知道是不是我RPWT,还是下来的这个.bzr本 身就有问题。但换成HTTP就可以了:
bzr branch http://jod.example.com/foobar.joe/
但 这样就麻烦一些,一个是安全性的问题,当然可以用HTTP-Auth加上身份验证,但毕竟没有SFTP安全;另一个是需要在服务端作Web Server配置,允许通过HTTP访问远程Repository;第三个问题是HTTP是只读的,这样上传和下载需要使用不同的URL。
Web Server端的配置倒不复杂,标准的WEB静态页面访问配置即可。例如(包含HTTP-Auth身份验证):
Alias /bzr /home/bzr
<Directory /home/bzr>
Options FollowSymLinks
AllowOverride FileInfo Indexes Limit
Order allow,deny
Allow from all
AuthType Basic
AuthName "Bazaar Repository Files"
AuthUserFile /home/svn/svn-auth-dev
Require valid-user
</Directory>
另外,可以使用.bzrignore文件从工作目录中忽略不需要加入管理的文件,参见这个介绍,这一点比以前用TortoiseSVN时要方便很多。用如下命令可以列出项目工作目录中被忽略掉的文件:
bzr ignored
还有,据云风说,Bazaar有一个巨大的优点就是智能重命名,避免了大量文件的remove/add操作,这的确是一个很大的优点,特别是对于大项目来说。
本篇介绍Mercurial。
因为这是我现在用得最多的SCM——最近一个月来几个程序都在用它——所以会说得详细一些。
我是从云风的BLOG里看到关于Mercurial的介绍,他在文章中介绍了常用的几种DRCS,他个人推荐的是Darcs,但我却看中了Mercurial。
Mercurial 的优点在于功能强大并且速度超快(相对Bazaar而言,与SVN相比似乎也快一些),看源码Mercurial也是用Python写的,只不过发布版像 是用PY2EXE等工具编译成的EXE,不知道为什么速度会这么快。缺点是操作远程Repository的功能需要一些服务端的安装配置工作,这点不如 Bazaar方便。
关于Mercurial的使用推荐参考这里的两页文档,很实用。Mercurial的操作命令虽然跟Bazaar差不多,但是设计思路比Bazaar更加“分布”一些,与传统SCM差别较大,可能需要一段时间适应。
安装很简单,在这里下载最新版本的安装程序安装一下就好了。
不过要在Windows下通过SSH使用远程Repository的话,需要一些额外的安装配置工作。如果你使用的不是Windows或者在Windows上已经安装了带有ssh命令的Cygwin,可以跳过下面这一部分,直接到后面的“Mercurial的使用”部分。
首先在这里下载一个PuTTY的工具程序:plink.exe。
然后在Mercurial的安装目录下找到mercurial.ini文件,用编辑器打开,找到[ui]段增加如下两行:
ssh = D:\tools\plink.exe -ssh -pw password
username = username<username@sitename.com>
username项很好理解,就相当于Bazaar里的whoami命令——我不知道为什么Mercurial没有这个命令,而是默认使用loginname@hostname的形式来标记当前用户,大概它觉得这只是标志,没有什么关系,反正它拥有超强的分支/合并功能。
ssh 项就是与SSH有关的配置项目了。按照参考文档中所说的,Mercurial通过ssh操作远程Repository时可以交互提示输入登录密码,但是我 在Windows下试验失败,可能是plink的问题。所以在第一次从远程Repository上clone到本地repository时需要在这里用- pw选项输入登录密码(不过用完就可以去掉这一项了——因为不同的项目可能使用不同的远程Repository,所以就可能使用不同的用户和密码,那个时 候可以配置到项目的.hgrc里,详见后面的说明)。
Mercurial的使用:
完成必要的安装配置工作以后就可以开始使用了。
Mercurial的命令是hg——就是汞。不过说实话,我看到Mercurial这个词想到的是水星。
开始一个项目有两种情况:一是还没有任何Repository的全新项目;二是加入一个已经有的项目——通常已经创建了一个公共的远程Repository。
第一种情况的流程大致是这样:
1、创建本地Repository。在项目的工作目录下运行:
hg init
将会创建一个.hg的目录。
2、配置项目目录(可选)。主要内容有两项,一个是配置.hgignore,把不需要加入管理的文件排除掉;另一个是配置.hgrc,主要是配置ssh(此项仅针对在Windows下用plink进行SSH连接的情况):
.hgignore文件放在项目的根目录上,其内容举例如下:
syntax: glob
*.py[co]
*.swp
*~
使用方法一看就明了,就不解释了。
.hgrc文件放在.hg目录中,其内容举例如下:
[paths]
default = ssh://username@remotehost//home/username/projname
default-push = ssh://username@remotehost//home/username/projname
[ui]
ssh = D:\tools\plink.exe -ssh -pw password
其中paths段里的default/default-push分别是对远程下载上传的默认url,这样在作pull/push操作时可以不必每次输入这个URL。如果SSH不是配置在标准的22端口上,可以在remotehost后面加上(:port)指定端口号。
ui段里的配置与Mercurial.ini是一样的格式和含义。在Windows下使用plink连接SSH需要在这里用-pw选项配置登录密码,以使pull/push操作能够正常工作。
3、检查项目状态。命令为:
hg status
将会列出所有未commit的有效项目文件及其状态——如果在commit以后项目文件未任何修改,此操作将无反馈信息。
比如在刚初始化完以后进行检查,将会列出所有项目文件(被.hgignore排除的文件将不显示),并在前面有一个?标志,表示这些文件尚未被版本管理。
在作完第一次add操作以后检查,则?标志将变为A标志,表示是新增的文件。
如果在commit以后有文件被修改过,则状态检查会列出这些被修改过的文件,并加上M标志。
如果在commit以后有文件被删除或改名,则状态检查会把这些文件加上!标志——改名后的新文件则会作为未管理的新文件而加上?标志。
需要从本地Repository里删除!标志文件则需要使用remove命令,详见后面的说明。
4、将项目文件加入本地Repository。命令很简单:
hg add
即可将项目目录中除了在.hgignore中被排除的文件以外的所有文件都加入到本地Repository中(当然不包括.hg目录,但是会包括.hgignore文件本身)。
5、将变更提交到本地Repository。命令为:
hg commit -m "关于本次提交的说明文本"
6、提交到远程Repository。这里只介绍通过SSH提交的方法,通过HTTP的方法请自行参考相关文档。
首先需要在服务端安装Mercurial,如果是用Linux服务器的话,参考各发行版说明,ubuntu下的安装是很简单的,直接用:
sudo apt-get install mercurial
即可。
然后在服务端的项目目录下创建一个空的Repository(bazaar不需要这样的步骤,它可以用SFTP直接在空目录里远程创建):
cd /home/username/projname
hg init
最后就可以在客户端推送Repository了,在项目目录下运行:
hg push ssh://username@remotehostname//home/username/projname
如果配置了.hgrc里的paths段的default-push,则可以直接用:
hg push
如果提交失败,请检查.hgrc和/或mercurial.ini里是否正确地配置了plink的pw选项,或者是SSH的端口号是否正确。如果配置无误仍然失败,可以用debug选项看一下详细出错信息:
hg push --debug
再来看第二种情况,即已经存在远程公共Repository的情况。
1、首先创建本地的副本:
hg clone ssh://username@remotehostname//home/username/projname
注意,在Windows+plink的情况下,必须先在mercurial.ini里配置plink的pw选项,否则不能正常工作——此时还没有.hgrc可以配置,所以只能用mercurial.ini这个全局配置。
正常执行以后将在当前目录下创建一个projname的子目录,其中包含了本地Repository(.hg目录)和工作目录的全部内容。
2、通常还是需要配置一下.hgrc(可选),不过.hgignore会一起被clone下来,一般不必再配置。
3、status/add/commit/push等命令与第一种情况相同。
现在再来看两种情况都需要的一些别的操作:
1、删除文件:
hg remove path/filename
删除后的文件在status命令结果里将被标志为R。需要用通配符删除多个文件时,可以使用-I选项:
hg remove -I path/wildcard .
2、从远程Repository取得别人加入的更新:
hg pull ssh://username@remotehostname//home/username/projname
同样,如果配置了.hgrc,就可以不用输入URL,直接用:
hg pull
取得更新。不过此操作只是更新本地Repository,你还需要用:
hg update
来更新工作目录下的文件。
如果发生变更冲突,此操作会自动进行merge,对于不能自动merge的部分,会弹出默认编辑器(可以在mercurial.ini里配置)要求手工处理。处理完成后会在本地Repository实现自动合并。
3、关于push的补充:
当向一个远程repository作push操作时,如果之前有别人的push内容,本次push将自动产生一个分支,你需要作一次pull操作把所有分支下载到本地repository进行merge。
4、除了status检查工作目录状态以外,还有几个命令用于检查本地Repository状态:
hg head
hg heads
hg log
其中head命令显示当前本地Repository中工作分支的最新版本的提交信息。heads命令显示当前本地Repository中所有未合并分支的最新版本的提交信息。log命令则是显示提交的历史记录。
Mercurial 还有一套很强的变更打包解包功能,即一个开发者可以把自己本地Repository中的变更记录打包发给别人,别的开发者得到这个变更包以后,可以解包到 自己的Repository里,这样就可以连公共的远程Repository也不需要。这样的“分布式”真是太彻底了。
本篇作一个简单的总结。
先看一下DRCS与传统SCM之间的比较。虽然DRCS有很多优势,但是完全取代集中式的SCM还是不太可能的,毕竟是两个完全不同的思路。
我 曾经乐观地认为DRCS会取代传统SCM,但这只是我个人的体会,我可以很轻松地把SVN换成Mercurial,但是并不表示这对所有人都是合适的。令 狐就指出,在他们公司,因为在VSS的基础上有一整套自己的管理工具和规范,即使明知有更好的选择,也不太可能就把它换掉的。
除了这种情况以外,对于公司模式的开发团队来说,还是需要对源代码有一个集中管理的约束,在这样的情况下,集中式SCM还是大有作为的。
但是对于个人、小团队、分布式团队、特别是开源的开发团队来说,DRCS还是具有传统SCM不可比拟的优势。而且DRCS中的很多优点也是很值得传统SCM借鉴的。比如灵活方便的分支/合并功能。SVN的分支合并功能实在是太弱了,用过的都知道。
再比较一下Bazaar和Mercurial。虽然前几篇中也零散地提到,这里汇总一下。二者在常用功能的操作方面几乎都是秉承传统SCM的操作方式,包括几乎完全相同的操作命令和参数,以及相似的配置文件项目。所以这方面就不说了,只说说二者不同的方面。
Bazaar 的优点是智能重命名,这个在大项目中进行目录重命名时会有优势,但是这个功能毕竟不常用。Mercurial的重命名与传统SCM是一样的,都是删除后重 新添加。在操作性能上Mercurial完胜Bazaar,在安装方便性上也是Mercurial胜出——Bazaar在使用SSH方式进还需要自己安装 额外的依赖软件包。
两种DRCS最大的区别还是在于对远程Repository的操作方面。二者都支持通过HTTP和SSH两种方式访问远程Repository,但实现方式有所不同。
Bazaar的HTTP方式很简单,只要在Web Server里配置一个Directory项目,允许通过HTTP访问Repository中的.bzr目录即可。不过Bazaar的HTTP方式只提供读操作功能,这是它的不足之处。
需 要进行远程Repository的读写操作,还是要用SFTP——FTP over SSH——方式。当然这种访问方式的实现也很简单,只要服务器支持SFTP即可使用。甚至不需要在服务端安装Bazaar,远程Repository的操 作(包括初始创建)也全都是在客户端进行。
Mercurial的情况则要麻烦一些。它的远程Repository操作的前提是必须在服务端安装一个Mercurial,远程Repository也必须在服务端使用init命令创建才可以使用。
首 先是HTTP方式,这需要在服务端运行serve命令,在特定端口上提供HTTP服务,然后由实际的Web Server通过mod_proxy等方式代理一下使用。这样的代价就是需要在服务端消耗额外的资源,但换来的好处是可以提供更强大的功能,而不是像 Bazaar那样只能读访问。
但是Mercurial的SSH方式就有一点不太方便,当然也是因为Windows的缘故,在Linux下还是很方便的。详细的情况参见上一篇。
结论就是没有结论~~冏rz
SVN,Bazaar,Mercurial都很不错,用哪个就看你的实际情况需要了。另,就算是要三个一起用,也不会有什么大的冲突。
个人的推荐是:SVN+任何一个你喜欢的DRCS配合着用是个好办法——用DRCS作小步迭代式的开发,在需要的时候分支或合并,按自己觉得方便的方式(比如固定的周期)进行SVN提交。