SVN分支/合并原理及最佳实践

SVN是一种常用的版本控制工具,一种典型的项目代码实践方式是:

存在一个代码基线(Base Line)或称主干,不同的模块使用各自的分支进行功能开发,在开发完毕后合并回主干,准备交付。


基本概念:

变化集合(ChangeSets)

SVN使用变化集来描述和管理托管对象的版本变更,这里变更可以是文件文本内容的变化,目录树的改变或者元数据(metadata,附加信息,包含权限或自定义属性等)的修改等。整个代码仓库(Repository)使用全局的数字来标识版本(revision)。它既是代码库提交次数的统计,也是某个变化集的隐式标识。

可以通过诸如

svn log -r 9238

来获取该版本的变化信息

或者

svn diff -c 9238

来查看详细的变化记录(patch)

SVN的合并操作也是使用这些变化的信息来完成修改的合并


最佳实践:(建议使用1.6系列的最新客户端)

分支定期同步主干修改

分支定期从主干同步修改有助于提早发现冲突,同时降低分支合并回主干时的风险(与其他业务功能的冲突)

使用如下命令实现

cd my-working-branch

svn merge http://my-repo/trunk

该命令负责把从创建该branch后,trunk上所有的修改复制一份,然后应用到本branch上,因此重复进行merge会导致冲突

执行merge命令后,通过svn st可以查看文件变化状态,例如

  M     .

M      source.c

注意到当前工作目录"."也发生了变化,并且M标记在第二列,表明该目录的元数据发生了变化。这里是merge命令修改或创建了目录的svn:mergeinfo属性(可通过svn diff查看),用来记录已经合并过的代码线和版本(务必不要擅自修改该属性),以便后面再进行merge时,选定起始版本。(备注:svn:mergeinfo是SVN 1.5版本引入的特性,需要确定客户端和服务器版本支持该特性)

确定合并无误后,使用svn ci -m “merge trunk changes to branch”来提交修改

或者svn revert . -R 来回滚所有的改变


随后可以通过定期执行svn merge http://my-repo/trunk 

来获取trunk上面的更新,由于有svn:mergeinfo信息的存在,merge命令会仅合并该分支上没有的修改(不会产生冲突)

此外,执行merge命令时,可以指定--dry-run参数来预览修改(不修改任何本地目录的文件)


分支合并回基线

当分支功能开发测试完毕后,将分支代码合并回主线

cd trunk

svn up

svn merge --reintegrate http://my-repo/my-working-branch

完成从分支代码合并回trunk的操作。由于branch曾经merge过trunk的一些修改,因此branch上的变化集既包括自身branch独有的修改,也包括trunk上的修改,并且独有的修改往往不是在连续的版本区间。此时,通过--reintegrate参数,可以仅从branch上合并该branch上独有的修改回trunk,避免产生合并冲突。


完成分支合并后,一般会立即删除该分支,以避免循环合并,可以参见

http://stackoverflow.com/questions/102472/subversion-branch-reintegration-v1-5

http://stackoverflow.com/questions/3309602/subversion-branch-reintegration-in-v1-6

http://blogs.collab.net/subversion/subversion-merg

问题主要出在reintergrate到trunk后的修改如何向分支合并:如仍然向分支合并,则会出现冲突;但如果不向分支合并,则可能丢失在reintegrate时比如为解决冲突而做的一些修改


如果一定继续在分支上开发,有一种可trick的方法,需要对分支的svn:mergeinfo进行处理,手动标记reintegrate回trunk时提交的版本在该branch上为已合并(通过--record-only参数)

http://svnbook.red-bean.com/nightly/en/svn.branchmerge.advanced.html#svn.branchmerge.advanced.reintegratetwice

$ cd my-calc-branch
$ svn update
Updating '.':
Updated to revision 393.
$ svn merge --record-only -c 391 ^/calc/trunk
--- Recording mergeinfo for merge of r391 into '.':
 U   .
$ svn commit -m "Block revision 391 from being merged into my-calc-branch."
Sending        .

Committed revision 394.


其中r391为reintegrate回trunk时的提交。

一般不建议这样使用,因为一旦r391中包含了非reintegrate造成的修改,那么这个修改就会丢失。所以倒不如删除分支再建立一个同名的分支继续使用。

鉴于此,强烈不建议对svn:mergeinfo信息进行操作,除非可以确定不会造成修改的丢失


SVN合并管理机制

svn通过元数据属性svn:mergeinfo来管理分支间的合并操作

通过 svn propget svn:mergeinfo .         来获取当前目录的合并记录

此外,可以通过如下命令查看当前分支从另一分支的合并记录

cd my-repo/my-working-branch

svn mergeinfo http://my-repo/trunk

将展示如

r3

r4

r5

此外,可以通过--show-revs参数来展示其他信息,如--show-revs eligible 来显示适合从trunk合并过来的版本

如果需要,可以通过svn merge命令中的参数 --record-only 来将某些版本(通过-r指定)标记为已合并,这是一种通过工具来操作svn:mergeinfo的方法,比自己直接修改要可靠


使用svn merge来取消提交的修改

svn merge的一种极端用法是用来回滚已经提交的修改,即反向修改,例如想要取消r303的提交,可以指定--revision 303:302 或者--change -303

即:

cd trunk

svn merge -c -303 http://my-repo/trunk     来实现反向merge

确认无误后,使用svn commit来提交本地修改

注意:

假设提交后的版本是r350,那么通过r303-r349取出的仍然会是包含错误提交内容的文件(因为我们在r350进行的修改回滚),由于svn的使命是保证所有提交的信息不丢失,而且目前无法对已经提交的信息进行抹除(也许日后会提供svnadmin obliterate命令来进行永久删除操作),好在一般只关注一个文件的HEAD版本


恢复历史文件

一般来说,当一个分支完成开发并合并回trunk后,就可以删除了(svn delete URL -m "msg"),这时当需要恢复某些文件时,可以使用

svn log 

-v 输出附加信息

-l 限制输出的条目

--stop-on-copy 查看历史时不跨越不同的分支副本

当找到删除文件的revision后(包括文件修改状态为D的标识),假设在r808删除了source.c,则可以通过svn copy命令来进行恢复

cd some-working-copy

svn copy http://my-repo/trunk/source.c@807 ./source.c

通过svn st可以看到

A   +  source.c

通过这种方法,source.c会继承已删除文件原有的log(通过svn log可以持续追溯)(+表明重新加入SVN的版本调度),如果不希望再继承历史记录,则可以使用

svn cat http://my-repo/trunk/source.c@807 > ./source.c

svn add source.c

来全新添加这个文件


上述两种方式仅在本地工作副本生效(在提交之前),可以通过如下命令直接在代码仓库生效:

svn copy http://my-repo/trunk/source.c@807 http://my-repo/trunk/ -m "restore deleted file"


最后,还可以通过svn merge命令来回滚删除操作修改,通过这种方式的问题在于,如果删除文件的版本还包括其他修改,那么通过merge命令的回滚无法只对变化集的一部分进行操作(即在同一次提交中,不能只回滚其中文件删除的修改)


参考文献:

http://www.subversion.org.cn/svnbook/nightly/svn.branchmerge.basicmerging.html

http://renial.iteye.com/blog/761183

http://www.cnblogs.com/cnblogsfans/archive/2011/02/16/1955808.html

http://svnbook.red-bean.com/nightly/en/svn.branchmerge.advanced.html#svn.branchmerge.advanced.reintegratetwice


关于reintegrate后分支能否继续使用的讨论

http://stackoverflow.com/questions/102472/subversion-branch-reintegration-v1-5

http://stackoverflow.com/questions/3309602/subversion-branch-reintegration-in-v1-6

http://blogs.collab.net/subversion/subversion-merg



你可能感兴趣的:(SVN,SVN,merge)