SVN 树冲突和目录丢失问题(4)
前面《SVN 树冲突和目录丢失问题(2)》中介绍的冲突解决机制,是“你死我活”(vice versa)式的冲突合并,在实际环境中,可能会有“你中有我,我中有你”式的合并。
- 主线和分支的同名目录中的内容都需要保留
- 分支中同名的目录包含多次提交,需要合并后保留分支的提交历史
关于 svn:mergeinfo 属性
首先,我们需要知道 svn 1.5 版本增加的 svn:mergeinfo 属性。- 在 SVN1.5 版本之前,SVN 的合并操作不会比 CVS 强多少,这也是很多有识之士痛贬 SVN 的原因
- SVN 痛定思痛,终于在 1.5 版本设计出来 svn:mergeinfo 属性。这多亏了 SVN 的目录和文件属性的强大功能
- svn:mergeinfo 属性取代了程序员自己手工维护的合并记录单。
- 就是说,之前为了避免重复合并,程序员往往需要将每一次合并的操作记录在一个本本中。CVSer都是这么做的,对么 yzw?
- svn 1.5 会把合并结果记录在目录的 svn:mergeinfo 属性中,这样在合并的时候,可以不必再提供合并的版本范围,SVN会帮助你跳过已经完成合并的版本
一个更加现实的例子
- 分支中创建了 somedir 目录,并包含多次提交。让我们看看分支 somedir 的提交历史:
~/tmp/svntf/trunk$ svn log file:///tmp/svnserver/branches/0.x -v ------------------------------------------------------------------------ r6 | jiangxin | 2010-04-23 09:19:17 +0800 (五, 2010-04-23) | 1 行 改变的路径: A /branches/0.x/somedir/README.txt add README.TXT ------------------------------------------------------------------------ r5 | jiangxin | 2010-04-23 09:18:57 +0800 (五, 2010-04-23) | 1 行 改变的路径: M /branches/0.x/somedir/branch.txt in branch 0.x, add one line to branch.txt. ------------------------------------------------------------------------ r3 | jiangxin | 2010-04-22 19:51:21 +0800 (四, 2010-04-22) | 1 行 改变的路径: A /branches/0.x/somedir A /branches/0.x/somedir/branch.txt to branch 0.x, we add somedir/branch.txt file. ------------------------------------------------------------------------ r2 | jiangxin | 2010-04-22 19:50:27 +0800 (四, 2010-04-22) | 1 行 改变的路径: A /branches/0.x (从 /trunk:1) trunk => branch/0.x ------------------------------------------------------------------------ r1 | jiangxin | 2010-04-22 19:48:57 +0800 (四, 2010-04-22) | 1 行 改变的路径: A /branches A /tags A /trunk initial ------------------------------------------------------------------------
- 主线也创建了 somedir 目录并包含文件
~/tmp/svntf/trunk$ svn log -v file:///tmp/svnserver/trunk ------------------------------------------------------------------------ r4 | jiangxin | 2010-04-22 19:51:55 +0800 (四, 2010-04-22) | 1 行 改变的路径: A /trunk/somedir A /trunk/somedir/trunk.txt to trunk, we add somedir/trunk.txt file. ------------------------------------------------------------------------ r1 | jiangxin | 2010-04-22 19:48:57 +0800 (四, 2010-04-22) | 1 行 改变的路径: A /branches A /tags A /trunk initial ------------------------------------------------------------------------
分析和设计合并路线
现在的合并需求是:- 将分支中增加的 somedir 目录合并到主线的 somedir 目录中
- 在合并后的主线中,保留分支 0.x 的 r5 和 r6 的提交历史
- 分支 0.x 的 r3 版本增加了目录 somedir
- 主线的 r4 版本也增加了目录 somedir
- 所以 r3 和 r4 会造成树冲突
不合并仅标记合并,即手工标记合并成功
所谓标记合并,就是说我们不真正合并,而只是在 svn:mergeinfo 中进行标记:“我已经合并了分支0.x 的版本3”。你当然可以直接用 svn propset 命令设置 svn:mergeinfo 属性,但是我还是建议你使用 svn merge 命令,不过要带一个 --record-only 参数。 该参数(--record-only),在乌龟SVN中的图形界面中叫做“仅标识”,就是说不执行 merge 操作,而是在 svn:mergeinfo 中标记上已经合并了相应的提交。那么我们为主线标记上:已合并了分支的提交3
操作如下:~/tmp/svntf/trunk$ svn merge --record-only -r 2:3 file:///tmp/svnserver/branches/0.x . ~/tmp/svntf/trunk$ svn st M . ~/tmp/svntf/trunk$ svn pl -v . “.” 上的属性: svn:mergeinfo /branches/0.x:3 ~/tmp/svntf/trunk$ svn ci -m "标记已合并分支 0.x 的提交3" 正在发送 trunk 提交后的版本为 7。
手工完成 r3 到主线 r4 的内容合并
分支 0.x 的r3增加了一个新文件,复制到主线的 somedir 目录中,我们就完成了 r3 和 r4 的内容合并~/tmp/svntf/trunk$ svn cp -r 3 file:///tmp/svnserver/branches/0.x/somedir/branch.txt somedir/ A somedir/branch.txt ~/tmp/svntf/trunk$ svn st A + somedir/branch.txt ~/tmp/svntf/trunk$ svn ci -m "合并分支0.x的r3 提交的内容到 somedir。" 增加 trunk/somedir/branch.txt 提交后的版本为 8。合并后的主线的 somedir 目录包含了主线和分支 somedir 中全部的内容
~/tmp/svntf/trunk$ ls somedir/ branch.txt trunk.txt
执行分支到主线合并操作,将分支历史带入主线
别忘了在合并操作前,先对主线目录执行更新操作,以免发生过时错误。~/tmp/svntf/trunk$ svn up 版本 8。 ~/tmp/svntf/trunk$ svn st -v 8 8 jiangxin . 8 8 jiangxin somedir 8 4 jiangxin somedir/trunk.txt 8 8 jiangxin somedir/branch.txt执行分支到主线的合并操作,因为 r3已经标识为已合并,所以会跳过 r3 进行合并
~/tmp/svntf/trunk$ svn merge file:///tmp/svnserver/branches/0.x --- 正在合并 r4,经由 r8,到 “.”: A somedir/README.txt U somedir/branch.txt ~/tmp/svntf/trunk$ svn st M . M somedir/branch.txt A + somedir/README.txt ~/tmp/svntf/trunk$ svn ci -m "继续合并分支 0.x 到主线。" 正在发送 trunk 增加 trunk/somedir/README.txt 正在发送 trunk/somedir/branch.txt 传输文件数据. 提交后的版本为 9。 ~/tmp/svntf/trunk$ svn pl -v . “.” 上的属性: svn:mergeinfo /branches/0.x:2-8
看看合并后的历史
参数“-v ” 可以查看提交的文件统计信息;参数 "-g" 可以查看合并源的日志信息~/tmp/svntf/trunk$ svn log -v -g ------------------------------------------------------------------------ r9 | jiangxin | 2010-04-23 10:06:42 +0800 (五, 2010-04-23) | 1 行 改变的路径: M /trunk A /trunk/somedir/README.txt (从 /branches/0.x/somedir/README.txt:8) M /trunk/somedir/branch.txt 继续合并分支 0.x 到主线。 ------------------------------------------------------------------------ r6 | jiangxin | 2010-04-23 09:19:17 +0800 (五, 2010-04-23) | 1 行 改变的路径: A /branches/0.x/somedir/README.txt 合并通过: r9 add README.TXT ------------------------------------------------------------------------ r5 | jiangxin | 2010-04-23 09:18:57 +0800 (五, 2010-04-23) | 1 行 改变的路径: M /branches/0.x/somedir/branch.txt 合并通过: r9 in branch 0.x, add one line to branch.txt. ------------------------------------------------------------------------ r2 | jiangxin | 2010-04-22 19:50:27 +0800 (四, 2010-04-22) | 1 行 改变的路径: A /branches/0.x (从 /trunk:1) 合并通过: r9 trunk => branch/0.x ------------------------------------------------------------------------ ------------------------------------------------------------------------ r8 | jiangxin | 2010-04-23 10:00:21 +0800 (五, 2010-04-23) | 1 行 改变的路径: A /trunk/somedir/branch.txt (从 /branches/0.x/somedir/branch.txt:3) 合并分支0.x的r3 提交的内容到 somedir。 ------------------------------------------------------------------------ r7 | jiangxin | 2010-04-23 09:55:44 +0800 (五, 2010-04-23) | 1 行 改变的路径: M /trunk 标记已合并分支 0.x 的提交3 ------------------------------------------------------------------------ r3 | jiangxin | 2010-04-22 19:51:21 +0800 (四, 2010-04-22) | 1 行 改变的路径: A /branches/0.x/somedir A /branches/0.x/somedir/branch.txt 合并通过: r7 to branch 0.x, we add somedir/branch.txt file. ------------------------------------------------------------------------ r4 | jiangxin | 2010-04-22 19:51:55 +0800 (四, 2010-04-22) | 1 行 改变的路径: A /trunk/somedir A /trunk/somedir/trunk.txt to trunk, we add somedir/trunk.txt file. ------------------------------------------------------------------------ r1 | jiangxin | 2010-04-22 19:48:57 +0800 (四, 2010-04-22) | 1 行 改变的路径: A /branches A /tags A /trunk initial ------------------------------------------------------------------------好了,这个关于 SVN 树冲突的系列博客就告一段落了。我正在考虑是不是写一个 Git 相关的冲突解决机制,或者让 yzw 代劳?