SVN(Subversion)
<wbr></wbr>
特点
<wbr></wbr>
- 不但能版本化文件,还能版本化目录。
- 每个文件和目录都可根据需要建立多个属性,每个属性是一组键/值对。属性也在版本控制之下。
- 可对文件或目录进行拷贝,改名和移动等操作,这些操作均在版本控制之下。这同时也解决了同名而无关的文件之间的历史联系问题。
- 全局版本号。SVN的版本号针对整个目录树,而非单个文件。每一个版本号代表了一次提交后版本库整个目录树的特定状态。一个文件的修订版本N和M并不必有所不同。<wbr></wbr>
<wbr></wbr>
<wbr></wbr>
- 同时支持拷贝-修改-合并和锁定-修改-解锁两种操作模式。拷贝-修改-合并模式更有利于协助,但锁定-修改-解锁模式在某些情况下更适合。
- 使用一个二进制差异算法描述文件的变化,对于文本(可读)和二进制(不可读)文件其操作方式是一致的。这两种类型的文件压缩存储在版本库中,而差异信息在网络上双向传递。
- 原子提交(All or None)。
- 使用类似链接的方式拷贝分支和标签,节省空间。
- 在本地维护一个原始的版本缓存(text-base),可使本地直接查看区别和恢复修改而不必访问网络,并且可使提交只传递修改的部分而非整个文件。
- 版本库的访问设计为接口,可使用各种方式访问,如本地文件直接访问,通过Subversion-aware Apache服务器WebDAV协议的HTTP和HTTPS,通过svnserve服务器的svn和svn+ssh协议。
<wbr></wbr>
架构图
<wbr></wbr>
<wbr></wbr>
组件
svn:命令行客户端程序。
svnversion:显示版本的工具。
svnlook:查看版本库的工具。
svnadmin:创建,修改,恢复版本库的工具。
svndumpfilter:过滤版本库转储数据流的工具。
mod_dav_svn:Apache HTTP服务器的插件,使得版本库可通过HTTP或HTTPS协议访问。
svnserve:单独运行的服务器,可作为守护进程或由SSH调用。使得版本库可通过svn或svn+ssh协议访问。
svnsync:通过网络增量镜像版本库的程序。
<wbr></wbr>
内置版本关键字
<wbr></wbr>
HEAD:最新的版本。
BASE:工作拷贝检出或更新时的版本。
COMMITTED:每个文件或目录最新的版本。
PREV:COMMITTED的前一个版本。
<wbr></wbr>
PREV,BASE和COMMITTED只在引用工作拷贝路径时使用,不能用于版本库URL,HEAD则可用于两种路径类型。
<wbr></wbr>
SVN常用命令
<wbr></wbr>
import:将未版本化的文件纳入版本控制并提交。在导入之后,原来的目录树并没有转化成工作拷贝,为开始工作,还是需要运行checkout导出一个工作拷贝。<wbr></wbr>
checkout:从版本库中检出一个版本,创建本地工作拷贝。
update:更新工作拷贝。
add,delete,copy,move:增,删,复制,移动文件或目录。
status:检查状态差异。
diff:检查文件行级详细差异。
revert:恢复。
resolve:解决冲突。
switch:切换工作拷贝对应的版本库分支。
log:查看历史记录。
list:显示文件目录。
cat:查看某个文件内容。
<wbr></wbr>
解决冲突
<wbr></wbr>
本地未修改且是最新版本:commit不做任何事情,update不做任何事情。
本地已修改且是最新版本:commit会成功提交,update不做任何事情。
本地未修改且不是最新版本:commit不做任何事情,update更新最新版本到本地。
本地已修改且不是最新版本:commit报“out-of-date”错误,update试图合并最新版本到本地。如不能自动合并,需要人工解决冲突。
<wbr></wbr>
解决冲突,需要先执行update,合并最新版本到本地。对于不能自动合并的文件,需要人工解决冲突,并执行resolve。最后执行commit提交。
<wbr></wbr>
无法自动解决冲突的文件,update时,如果选择postpone,SVN会放置三个额外的未版本化文件到工作拷贝。
filename.mine:更新前的文件,没有冲突标志,只是你最新更改的内容。(如果Subversion认为这个文件不可以合并,.mine文件不会创建,因为它和工作文件相同。)
filename.rOLDREV:更新前的BASE版本文件,即上次更新之后未作更改的版本。
filename.rNEWREV:服务器上的最新版本,对应版本库的HEAD版本。
resolve命令会删掉三个临时文件,并接受指定的文件为最新无冲突的版本。
只有使用resolve命令后才能提交。<wbr></wbr>
<wbr></wbr>
分支和标签
<wbr></wbr>
分支和标签在实现上均是拷贝。
SVN自身只知道拷贝而并不了解其涵义。一个复制的目录之所以是标签是因为人们决定这样使用它,只要没有人修改这个目录,它永远是一个快照,但如果开始修改,它就变成了分支。
每个分支都可追踪其历史版本到主干的根部。在分开的部分,则各自看不到其它分支的版本。
<wbr></wbr>
<wbr></wbr>
将主干合并到分支:执行merge命令,分支即可直接使用,如有冲突需先解决。
将分支合并到主干:先获取主干最新版本的本地工作拷贝,在其上执行merge --reintegrate,解决冲突后执行commit提交。
<wbr></wbr>
分支相关常用命令
<wbr></wbr>
分支合并相关命令 | 描述 |
svn copy URL1 URL2 | 基于URL1创建一个分支或标签 |
svn switch URL | 切换working copy对应的路径 |
svn merge trunkURL; svn commit | 合并主干到分支 |
svn mergeinfo target [--from-source=URL] | 查看合并历史或相应的changesets |
svn merge --reintegrate branchURL svn commit | 合并分支到主干 |
svn merge -c REV URL svn commit | 合并指定的版本 |
svn merge -r REV1:REV2 URL svn commit | 合并指定范围的版本 |
svn merge -c REV --record-only URL svn commit | 设定某版本的合并标志以阻止合并该版本 |
svn merge URL --dry-run | 合并预览 |
svn revert -R . | 放弃合并,恢复 |
svn copy URL@REV local-path | 复活 |
svn merge -c -REV URL svn commit | 撤销已提交的合并 |
svn log -g; svn blame -g | 查看合并相关历史 |
svn copy . tagURL | 基于working copy创建一个分支或标签 |
svn mv URL1 URL2 | 移动一个分支或标签 |
svn rm URL | 删除一个分支或标签 |
<wbr></wbr>
<wbr></wbr>
版本库布局最佳实践
<wbr></wbr>
如下图创建目录结构
- 所有项目放在一个版本库中。
- 每个项目创建自己的目录,其下各自创建trunk,branches和tags三个目录。
- trunk目录存放开发主线。
- branches目录存放分支拷贝。
- tags目录存放标签拷贝。<wbr></wbr>
<wbr></wbr>
典型生命周期
- 开发和bug修正均每日提交到主干上。
- 将测试的版本拷贝到测试分支。如/branches/1.0。
- 并行工作,测试组对测试分支进行测试,开发组在主干上继续工作。
- 如果一个bug在任何一个位置被发现,错误在主干上修正,然合并到分支上。
- 测试结束,/branches/1.0拷贝到/tags/1.0.0,发布给客户。
- 发布后的bug修正继续提交到主干上,并从主干合并到/branches/1.0。
- 当积累了足够的bug修正,拷贝/branches/1.0到/tags/1.0.1,发布版本1.0.1。
- 主干的2.0开发完成,一个新的2.0分支被创建,测试、打标签和最终发布。
- 经过许多年,版本库结束了许多版本发布,进入了“维护”模式,许多标签代表了最终的发布版本。
<wbr></wbr>
使用分支进行特性开发
- 特性开发是使用分支进行组件独立开发,最终合并的方式。
- 开发周期一般为折衷模式。如果工作独立性较强,修改量较大,应该使用特性分支。
- 应每周一次从主干合并更新到分支,以防止与主干差异性过大。