【转自freefalcon的个人专栏】
原文地址:http://blog.csdn.net/freefalcon/archive/2006/11/23/1406616.aspx
Subversion快速指南
Subversion(简写为SVN)作为开源社区贡献的新一代版本控制系统,已经得到越来越广泛的使用。我用过CVS(Concurent Version System,SVN的前身)和微软的VSS(Visual SourceSafe),相比之下,SVN具有更强大的功能和更简单的操作特性。
网上已有一些文章介绍SVN的安装和使用,不过我在第一次配置时仍然遇到了几个问题。这里,我按照自己的思路来进行讲解,以期对那些初次使用SVN并且对一些问题存在疑问的朋友有所帮助。
1. SVN简介
光说SVN好,那SVN究竟有什么优点呢?在SVN的手册里有着详细的说明,下面简单介绍几个重要方面:
1) 基于目录的版本控制
传统的CVS或VSS都是基于单个文件进行版本控制的,这实际上满足不了实际需求,因为在实际应用中,我们都希望按照项目或者工程进行管理,例如假设我们想要取出某个历史时间点的整个项目文件,那么基于文件的版本控制系统就存在弊端,只能单个单个文件的处理。而SVN则能很方便的做到这一点,你可以随意的取出任何一个文件、任何一个目录的任何一个历史版本。
SVN还允许对文件和目录进行增加、删除以及复制和重命名等操作,这些都会被记录到历史信息中,实现真正的版本控制功能。
2) 原子提交
SVN里的每次操作都是原子的,要么全部成功,要么全部失败。假设你要提交多个文件,如果有一个存在冲突,那么其它修改都不会被提交。
3) 高效的分支(branching)与标签(tagging)功能
先说标签功能,通俗的讲,标签就是某个时间点的快照(snapshot),我们可以在项目进行到一些重要的里程碑之时为之建立标签,这样可以方便以后随时取出这些历史版本。我想你会有一个疑问:SVN不是本身就有随意取出任何一个历史版本的功能吗?是的,标签的作用主要是为了给这些特定的历史版本取一个友好的名字,以方便使用和维护。
分支则是用于创建多个并行的工作线,比如,当我们的一个项目需要为某个用户提供一些特殊的功能时,那么就可以为之创建一个分支,这样能够保正大部分代码的共用,也使得整个项目变得容易维护和管理。
SVN对于分支和标签的实现都是一样的,并且采用了与Unix/Linux硬链接(Hard-Link)类似的机制,即是说,当我们创建分支或标签时,SVN并不会立即为之创建一份拷贝,而是创建一个链接,只有当这些文件以后被修改时才会真正产生一份副本。这种“缓式拷贝”方法是一种常见的优化方法,能够有效的节约空间。
那分支和标签又有什么不同呢?不同之处仅仅在于其“约定成俗”的含义,标签意味着你不会再对其进行修改,而分支意味着你会对它进行开发。
4) 多种访问方式
SVN提供了一个抽象的网络访问层,可以通过不同的协议来对其进行访问。首先,SVN提供了自定义的svn协议访问方式,通过形如svn://host/repository的URL就能使用。再有,SVN还提供了与Apache Web服务器相集成的功能,这样,我们就可以通过http://host/repository的方式来访问SVN了。
5) 对二进制文件的支持
CVS虽然对二进制文件也有支持,但实现得并不完善,你或许遇到过文本文件里有中文字符而被认为是二进制文件的事情,SVN则提供了对二进制文件全面的支持,使得非文本文件也能跟文本文件一样进行良好的版本控制。
6) Windows下与资源管理器集成的客户端:TortoiseSVN
SVN本身只提供命令行的操作方式,TortoiseSVN是第三方开发的图形化界面,它的出现使Windows下的版本管理变得非常方便。不过,由于是嵌入到资源管理器中,它可能会影响系统的速度——微乎其微,你可以自己评测一下。
7) 平台无关
SVN秉承了开源软件的一贯优点,无论是Windows还是Linux平台,都可以相互访问SVN服务器。
如果你过去是VSS用户,那么这里还要提一点,与VSS相比,SVN还有一个理念不一样,VSS将版本冲突控制放在操作之前,你要操作某个项目必须先执行CheckOut以进行锁定、防止他人同时修改。SVN提供了同样的Lock功能,但通常情况下,我们只需各自独立的进行修改而无需锁定项目,如果有冲突在提交的时候再做处理,也就是说,SVN是将冲突控制放在操作之后、提交之时。也许你会觉得VSS更合理,但实际情况却相反,因为在我们的实际使用中经常发生有人将整个项目CheckOut后忘了CheckIn,或者未选择Recursive忘了将子目录中的文件CheckIn,这就让其他人无法修改,于是不得不人为的通知其本人,非常麻烦。
2. SVN服务器搭建
本节是针对管理员写的,普通用户可以跳过本节。我这里只以Windows上的安装为例,Linux上可按类似方式进行(有些配置参数会存在差别,具体参考帮助手册)。
1) 安装SVN服务器
a. 下载
SVN的官方网站为http://subversion.tigris.org/,当前最新版本为1.4.2。Windows下的二进制安装包分为两种,一种是以setup结尾的安装文件,另一种是普通的压缩包文件,setup文件会自动注册一些信息,比如环境变量以及服务等,这些都是可以自己手动实现的。在我写这篇文章时,官方网站上就只有普通二进制文件,估计setup文件稍晚些时候会出来。特别注意,下载时要详细阅读注意事项,看清与之配套的软件的版本号,避免出现问题。
我选择的版本为svn-win32-1.4.2.zip
b. 安装
将svn-win32-1.4.2.zip解压缩到安装目录下,我选择的是C:/Program Files/Subversion,如果是setup文件,直接运行安装文件即可。对于压缩包,我们可以将bin路径添加到系统环境变量中,以方便操作。可以看到,bin目录下主要有如下几个文件:
svnadmin:仓库管理工具,包括创建、修复和备份等操作。
svnlook:仓库查看工具,包括信息、日志和锁定状态等内容,不会造成仓库的改动。
svnserve:svn服务程序,允许通过svn网络协议来访问仓库。
svn:SVN客户端,用于访问仓库,对项目进行版本管理。
svnversion:客户端工具,用于查看本地拷贝的修订信息。
c. 创建仓库(Repository)
SVN是以仓库为版本控制单位的,一个SVN服务器可以管理多个仓库,每个仓库拥有独立的修订号(REVISION),仓库中的任何一次更新都会带来修订号的递增。你可以根据需要选择建立一个或者多个仓库,这里,我以创建多个仓库为例子,假设我们将仓库都放到D:/SVN_REPOS目录下,下面的命令将会在该目录下创建一个Test仓库:
svnadmin create D:/SVN_REPOS/Test
如果创建成功,D:/SVN_REPOS/下将会多一个Test目录。
2) 搭建svnserve访问方式
svn和http是两种并列的访问方式,你可以选择其中一种,也可以都采用。
a. 注册服务
为了让SVN服务程序每次开机后自动运行,我们需要将其注册为服务。在控制台中执行如下命令:
sc create svnservice binPath= "\"C:\Program Files\Subversion\bin\svnserve.exe\" --service -r D:/SVN_REPOS" start= auto
注意,上述命令均在一行中。sc.exe是Windows 2000以后系统自带的一个工具,2000下没有,可以从XP上拷过来。svnservice为服务名称,后面的参数格式有严格要求,等号前面没有空格而后面有。binPath本身带有多个参数,因此用引号括起来,而由于路径里面又有空格,因此又加上了一层引号。 --service和-r均为svnserve.exe的参数,前者要求它作为服务运行,后者指明了仓库的根路径(多仓库为仓库的父目录)。
带安装包的SVN会自动注册服务,这时我们可能需要修改-r参数,命令如下:
sc config svnservice binPath= "\"C:\Program Files\Subversion\bin\svnserve.exe\" --service -r D:/SVN_REPOS"
b. 访问
注册完后,通过运行sc start svnservice或者服务管理器(service.msc)启动服务。
接下来,我们就可以通过下面的命令来测试系统是否工作正常:
svn info svn://localhost/Test
如果正确的显示出仓库的相关信息,那么就大功告成了,否则请检查服务的参数是否配置正确,比如,如果未在服务参数中指定正确的-r值,就会得到如下错误:
No repository found in 'svn://localhost/Test'
如果安装了TortoiseSVN,则可以直接在浏览器中输入svn://localhost/Test,这样会调出TortoiseSVN的Repos-Browser。到此,你就可以通过TortoiseSVN来导入工程进行版本管理了(参见后文)。
c. 权限配置
在进行权限配置前,所有的用户都能进行任何操作,在很多情况下是不允许的。在创建仓库时,仓库目录下都会生成好几个文件夹,其中conf里面存储的是配置信息,包括三个文件:
authz:访问权限配置
passwd:用户名和密码配置
svnserve.conf:基本配置信息
先配置svnserve.conf,将里面几项配置前的注释去掉,最后的内容如下:
[general]
anon-access = read
auth-access = write
password-db = passwd
authz-db = authz
这些参数的含义文件里都有详细说明,其中,anon-access和auth-access分别是对匿名用户以及认证用户的访问控制,password-db指明用户密码文件路径,authz-db指明权限配置文件路径。另外还有一个参数realm用于指明仓库所属的认证域,默认情况下每个仓库位于不同的域(每个仓库有一个唯一的uuid),因此我们可以不设置该项,除非多个仓库需要共用同一份passwd配置。
passwd文件的配置很简单,格式如下(等号前面为用户名,后面为密码):
[users]
harry = 123
sally = 123
guest = 123
authz则可以创建用户组并精确配置某个用户或用户组对某个文件或目录的访问权限,下面是一个例子:
[groups]
harry_and_sally = harry,sally
[/]
* = r
[/project1]
* =
harry = rw
sally = r
[/project1/foo]
sally =
[/project2]
@harry_and_sally = rw
guest = r
文件内容其实很简单易懂,groups用于定义用户组,后面便是对资源的具体访问控制,/表示仓库根目录,*表示所有用户,用户组前面需加上@符号,r表示可读,w表示可写,等号右边为空则表示没有权限。注意对于目录结构,当用户访问某个资源时,SVN会先看有没有直接针对该资源的访问控制,如果没有找到,则会继承上一级目录的访问权限,如此递推。
再提一点,当我们有多个仓库时,我们会发现这些仓库的用户帐号在大多数情况下都是相同的,因此,我们可以将passwd文件放到公共的地方,然后将所有仓库的password-db配置都指向该文件。相应的,authz-db也可以共用一个文件,不过需要在配置具体的访问控制时指明所属的仓库,如下:
[/]
* = r
[repos1:/project1]
* = r
harry = rw
[repos2:/project1]
* = r
sally = rw
上述配置表明,所有人对所有仓库的根目录都有读权限,但只有harry对仓库repos1里的project1有读写权限,只有sally对仓库repos2里的project1有读写权限。
3) 搭建HTTP访问方式
SVN可以通过Apache实现Web访问方式,但这不是必需的,除非你有此需求。
a) 下载
Apache的官方网站为http://www.apache.org/,注意不要使用最新的2.2.x,而要选择2.0.x,这一点在SVN官方网站上有特别说明,当初我就没有注意到这一点,而导致Apache2.2启动时无法加载SVN的模块,出现“perhaps this is not an Apache module DSO”错误。
我下载的版本为apache_2.0.59-win32-x86-no_ssl.msi
b) 安装和注册
执行Apache安装程序。由于2.0的版本不会自动注册为服务,因此我们需要手工处理。运行cmd.exe,进入apache安装目录下的bin文件夹,执行如下命令即可:
apache -k install
更多的命令可以通过apache help查看。
注册完后,就可以通过系统托盘里的Apache Monitor来启动服务。如果80端口未被占用,那么服务器应正常启动,通过http://127.0.0.1就能看到Apache的测试页面。
c) 配置
Apache是通过conf目录中的httpd.conf文件进行配置的,比如,默认的监听端口为80,在文件中搜索Listen 80,将80改成你所需的其它端口即可。配置完后必须重起Apache才能生效。更多关于Apache的配置说明请参见其帮助手册或google之。下面网站为帮助手册的中文版本。
为了让Apache支持SVN,比如增加一些配置项,一个典型的配置如下:
# 加载mod_dav模块,它是对WebDAV(Web-based Distributed Authoring and Versioning)协议的支持,由Apache自带
LoadModule dav_module modules/mod_dav.so
# 加载mod_dav_svn模块,它与mod_dav通信,使Apache支持SVN,它位于SVN的bin目录下。
LoadModule dav_svn_module "D:/Program Files/Subversion/bin/mod_dav_svn.so"
# 加载mod_authz_svn模块,用于进行权限管理
LoadModule authz_svn_module "D:/Program Files/Subversion/bin/mod_authz_svn.so"
# 配置SVN的访问路径以及相关相关参数
<Location /svn/> # 通过http://HOST/svn/访问SVN服务器
DAV svn # 必需
SVNParentPath D:/SVN_REPOS # 说明D:/SVN_REPOS下的所有目录均为仓库
SVNListParentPath on # 在网页中列出D:/SVN_REPOS下的所有仓库
AuthType Basic # 基本的用户名密码验证方式
AuthName "SVN REPOS" # 认证名称,作提示用
AuthUserFile D:/SVN_REPOS/users # 用户名密码文件
AuthzSVNAccessFile D:/SVN_REPOS/authz # 权限控制文件
Require valid-user # 只有通过认证才能访问网页
</Location>
# 重定向处理,用于将http://HOST/svn地址重定向为http://HOST/svn/
RedirectMatch ^(/svn)$ $1/
下面对几个重要的地方作以说明:
i. 网上很多文章提到将mod_dav_svn.so和mod_authz_svn.so两个文件直接拷贝到Apache的modules目录下,当初我按照这种方法做时结果在一台Windows 2000 Server上无法启动Apache服务,为此折腾了半天。后来才明白,这些模块文件其实就是一些动态链接库,它需要依赖SVN的bin目录下的其它几个dll文件(可以把后缀改为dll,然后通过VC带的depends查看其依赖关系),因此如果没有设置环境变量,那么Apache加载这些模块时就会失败,当然也可以把所有依赖文件(主要是libdb43.dll )拷贝过去。实际上,我们只需要通过绝对路径来引用这些模块即可,这样SVN升级后也不用再次拷贝。
ii. URL的访问路径为/svn/而不是/svn,因为后者可能有问题,导致通过http://HOST/svn访问出现如下错误信息
iii. SVNParentPath用于有多个仓库的情况,如果只有单个仓库,可以直接用SVNPath指明仓库路径。
iv. AuthUserFile指明用户名密码文件,但它与前面提到的SVN仓库下的passwd文件不是同一个文件,AuthUserFile是Apache的认证文件格式,二者的区别主要是用户名和密码的分割符不同,passwd是等号,这里的users是冒号,当初我就是把它们当成一个文件而造成客户端无法访问(为什么SVN不把passwd的格式定义成和AuthUserFile的一样呢?这样二者可以共用一个文件)。如果要对密码加密,那么users文件需通过Apache附带的htpasswd工具生成,实际上我们也可直接采用明文方式。
v. 权限控制文件AuthzSVNAccessFile与前面SVN里的authz一样,因此可以共用。
4) 其它管理功能
a. 备份
b. 修复
3. SVN客户端使用
本节针对客户端用户,主要介绍一些常用的操作方法。
1) 客户端安装
客户端可以采用命令行方式,也可以采用TortoiseSVN图形化方式,个人认为还是后者方便些。
TortoiseSVN从http://tortoisesvn.tigris.org/上获取,注意版本应与服务器保持一致。如果是命令行方式的话,那么从http://subversion.tigris.org/下载一个SVN二进制包就行了,此处不多讲。
TortoiseSVN属于图形化的客户端软件,其实前面的SVN安装包里已经含有客户端程序,只不过是命令行方式的,你可以根据需要选择是否安装。TortoiseSVN的官方网站为http://tortoisesvn.tigris.org/,同样,注意选择与SVN服务器配套的版本。
我这里使用的版本为TortoiseSVN-1.4.0.7501-win32-svn-1.4.0.msi
安装完后,会提示重起机器,实际上不用重起就能直接使用,只不过重起后会更新SVN文件图标的显示。下图是SVN工作区的右键菜单内容:
2) 主要操作
TortoiseSVN使用起来很简单,所有操作都通过右键菜单来完成。命令内容也很直观,而且有非常详细的帮助手册,这里只简单的介绍一下。
a) 导入项目(Import)
首先要把需要进行版本管理的工程(目录)整理好,去掉不必要的文件,比如编译器生成的临时文件。然后在最上层文件夹上单击右键,选择“TortoiseSVN -> Import...”,输入要存放的SVN服务器路径,确认即可。这样就将本地的项目导入到了服务器上。
命令行:svn import [PATH] URL
b) 检出项目(Checkout)
项目初次导入成功后,刚才本地的内容就没有用了,我们需要建立一个新的工作区,重新从SVN服务器下载受控的项目文件,执行“TortoiseSVN -> Checkout...”,选择或者输入项目的URL,确认即可,以后的工作都应在这个工作区里进行。
默认是获取项目的最新版本(HEAD),如果要获取历史版本,指定相应的修订号(Revision)即可。
命令行:svn checkout URL[@REV]... [PATH]
c) 更新与提交(Update and Commit)
他人修改了项目,我们需要从服务器下载最新版本,这通过“SVN Update”右键菜单实现。
命令行:svn update [PATH...]
如果是自己本地作了修改,则应及时将修改更新到服务器上去,这通过“SVN Commit...”实现。一个好的习惯是每次提交都应注明修改内容,以方便日后查证。
命令行:svn commit [PATH...]
d) 增加和删除文件(Add and Delete)
如果我们要向一个受控项目中添加新文件或文件夹,只需在目标上执行“TortoiseSVN -> Add”操作。注意,这里只是本地添加,要提交到服务器,还必须执行Commit才行。
命令行:svn add PATH...
同样,要删除受控文件或文件夹只需执行“TortoiseSVN -> Delete”操作。
命令行:svn delete PATH/URL...
TortoiseSVN还提供了一个重命名操作“TortoiseSVN -> Rename”,这其实是添加和删除的组合。
e) 撤销操作(Revert)
有时候,我们可能进行了错误的修改或者增加和删除,只要未进行提交,我们都可以通过“TortoiseSVN -> Revert”命令来撤销本地的所有更改。
命令行:svn revert PATH...
f) 查看信息
SVN提供了几种信息查看方式,其中Show log用于显示每次版本变更的日志信息,Repo-brower是仓库浏览器,类似于资源管理器,Revision graph则以图形化的方式让我们很直观的看到版本的变更情况,尤其是对于分支和标签管理很有帮助。
3) 其它操作
a) 冲突解决(Resolved)
如果我们本地进行了修改,而别人又把他的修改提交到了服务器上,这时我们执行Update就可能出现冲突(Conflict)。Resolved的作用不是解决冲突,它不进行任何合并,而是忽略掉他人的修改,允许我们将自己的版本提交到服务器上。
简单的说,Revent是撤销本地修改,而Resolved是保留本地修改。
b) 清除异常状态(Cleanup)
如果在执行某个命令的时候出现异常,比如服务器突然挂了,本地的工作区就会处于一种异常状态,通过Cleanup能够清除这种状态,使工作区不受到影响。
c) 锁定(Get lock)和解锁(Release lock)
冲突都是由于不同的开发人员同时修改了同一份文件造成的,因此,为了避免这种情况,我们可以强行锁定自己要修改的内容,这样其他人在我们解锁前就无法提交其修改。
d) 分支和标签(Branch/tag)
本文最开始就有说明,分支的目的是为了创建并行的工作线,标签的作用是为了保存项目某个版本的快照。二者在实现上却是一样的,都是通过Branch/tag命令执行。
e) 导出(Export)
为了实现版本管理,SVN会在工作区的每个目录下都生成一个隐藏的.svn文件夹,而我们有时却希望得到一个干净的没有.svn文件夹的项目结构,比如发布软件时,这种情况下就可以使用Export功能。
f) 重定向(Relocate)
有时候,SVN服务器的IP地址可能会发生变动,如果遇到这种情况,我们每个人的本地工作区都要重新下载吗?不用,只需通过Relocate重新配置一下本地工作区所对应的服务器地址就可以。
g) 补丁管理(patch)
不要被patch的名称迷惑,实际上它不属于SVN版本管理的范畴。这里所谓的patch是指那些对项目没有写权限(Commit)的人所作的修改,通过“TortoiseSVN -> Create Patch”生成,然后他们采用电子邮件等方式将patch发给项目管理员,由管理员执行“TortoiseSVN -> Apply Patch”并确认修改内容后再进行提交。该功能主要用于开源项目的管理。