开源版本控制SVN 树冲突、目录丢失问题及解决机制探讨
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
SVN 树冲突和目录丢失问题(1)
临下班了,一个老朋友(之后用yzw代称)在MSN 上呼我。
说他的SVN 遇到问题了:
∙在执行分支合并时,一个目录发生了树冲突
∙直接在硬盘上将该目录删除
∙之后执行svn update 该目录不能检出
∙不知道树冲突为何物,也不知道目录怎么变成了一团糟
好吧,谁让他公司的SVN 是我给部署的呢?让他(yzw)执行svn status 命令,看看显示什么信息,然后我在本地建立一个模型,争取重现并解决他的问题。
在已经一团糟的目录下,执行svn 显示的信息如下:
看来他遇到的树冲突,是因为在两个分支同时创建了一个同名目录somedir,然后在合并更新时出现树冲突。
重现问题的过程
版本库准备
1.创建svn 版本库于/tmp/svnserver
2.检出版本库到目录~/tmp/svntf 下(windows用户需要知道的是:~ 代表我的主目录
/home/jiangxin 是也)
3.创建SVN 三个顶级目录:trunk tags branches
4.创建分支branches/0.x
5.在branches/0.x 分支下创建目录somedir,并增加一个文件somedir/branch.txt
6.在主线trunk 下也创建一个目录somedir,并增加一个文件somedir/trunk.txt
看看目前的版本情况
备份当前的 .svn 目录
直接拷贝 .svn 到 .svn-orignal,以便在出现意外的时候,进行参照。
“.svn*”。
(问题优点复杂化了,算了)
合并分支改动,引发异常
o而我的结果是:
o看来,还需要作些工作才能完全重现错误。
15.这时我又备份了一下 .svn 目录,将 .svn 复制到 .svn-merge-conflict,以便后面比较
实际上,通过比较 .svn 目录和之前备份的 .svn-merge-conflict 可以看出端倪:
执行svn status,看到本地工作目录的冲突状态已经消失了,一切看起来正常了。
但是,慢着,此时somedir 目录没有了!
实际上,这时版本库中还有somedir 目录,我们可以用svn ls 命令查看:
但是本地的确已经没有了。
如果要刨根问底的话,可以比较一下 .svn 目录和我们之前创建的备份:
居然没有发生冲突。
yzw 这时后一定很欣喜,居然可以成功合并了。
再看看状态?
SVN 树冲突和目录丢失问题(2)
前面的博文《SVN 树冲突和目录丢失问题(1)》,介绍了重现update 导致树冲突的重现过程。
那么应该如何解决树冲突,以及如何找回丢失目录呢?首先我们需要了解:
什么是树冲突?
首先关于树冲突的概念,最好的参考是:SVN BOOK的有关树冲突的章节。
∙平时我们说的冲突,是因为对同一文件的不同修改造成的冲突。
∙树冲突,指的是由于目录(文件)树的改变,造成内容修改修改不能匹配在同一对象(目录/文件)上
∙例如:由于在一个分支中修改的目录和文件,在另外的分支出现了改名的操作。
∙或者像yzw 的例子,因为两个分支同时增加了一个同名的目录,导致了树冲突。
树冲突的解决,首先要说的是要最好使用svn 1.6 的客户端。
因为svn 1.5 的客户端对树冲突的处理不好,甚至根本发现不了树冲突,很容易忽略潜在的冲突,出现意想不到的结果。
SVN BOOK 中举了一个本地修改,远程重命名的例子。
例如svn 1.5 处理这种本地修改/远程文件改名的情况,可能会出现如下结果:
∙发现远程改名,则检查本地文件是否包含修改,若不包含修改直接删除。
∙结果因为远程改名的文件,本地包含修改,因此不删除,而是保留该文件,但是文件的状态变为未受版本控制状态。
∙本地会显示一个新增文件,实际上是本地修改文件的原始(修改前)版本重命名后的文件。
∙这时,如果不太细心(谁那有那么细心?),就会丢失本地的改动。
对于svn 1.5 最困难的是发现冲突,当然解决冲突也要靠手工比较完成:将本地文件改动在重命名后文件中再次改动一次!
对于svn1.6 来说,引入了树冲突的概念,看似复杂度增加了,实际上是解决了两个问题:
∙识别冲突的问题:
将本地修改的文件标记为树冲突
∙改动合并的问题:
将本地修改合并到远程改名后的文件中。
因为远程改名后的文件来自于本地修改的原始文件
当然对于远程重命名的例子,还要你最终的决定权还是在于你自己:
∙是否接受远程的文件重命名操作?
∙你需要手动将树冲突的状态予以解决:本地文件删除即接受远程重命名;
∙或者将远程添加的文件删除即不允许重命名。
∙对于前一种状况(即接受远程重命名),本地改动SVN 1. 6的客户端已经自动合并到远程改名后的文件中了。
那么对于yzw 的情况呢?
本地和远程同时添加目录?
yzw 遇到的树冲突,是因为本地和远程同时添加了相同的目录。
实际上,我们在上一个博客中已经看到了两种不同的解决方案影子:
∙本地添加somedir 目录并提交后,执行合并,显示:“合并引发的树冲突”
o这时,如果执行svn resolve –accept working somedir 命令解决冲突的话,
o就相当于说:“采用我增加的somedir 目录,他增加的somedir 目录不算数”
o然后提交即可
∙树冲突发生后:
o还原冲突
o删除主线中的目录。
潜台词是:我本地的修改不要了,而是使用远程(分支)添加的目录
o然后再执行从分支到主线的合并操作
o合并成功,提交。
o也就是说,采用的策略是:“采用他增加的somedir 目录,我增加的somedir 目录不算数”
看看实际操作的例子:
接受我的修改,远程的修改不算数
∙使用svn resolve –accept working 解决冲突:
~/tmp/svntf/trunk$ svn resolve –accept working somedir
“somedir”的冲突状态已解决
~/tmp/svntf/trunk$ svn st
M .
? .svn-merge-conflict
? .svn-update-conflict
? .svn-orignal
接受远程的修改,我的修改不算数
上一个博文中,我几经尝试,进入到了由于更新引发的树冲突。
但是在上一个博客示例最后的更新引发树冲突的状态,虽然也可以用svn resolve 命令解决树冲突,但是无法提交。
总是报错
无论你如何执行svn update,解决过时错误,也仍然不能提交。
会陷入一个无穷无尽的冲突解决==>过时冲突的循环中。
一个撤销本地修改,接受远程分支修订的解决的办法是:
出来。
如果先执行–set-depth 为其他,在执行–set-depth infinity 倒是能够找回somedir。
但
是这个方法太过奇怪,好像是SVN 的一个BUG,通过奇怪的操作绕过去了一样。
我用下面的命令找回丢失的somedir 目录:
中间出现了一次过时问题,是因为目录属性修改,而目录的版本号尚未更新。
这其实是svn 混杂版本号造成的,已经超出本博文的内容。
总结
好了,通过这个例子,我介绍了增加同名目录引发的树冲突的解决方案。
∙如何保留本地修改,取消远程修改
∙如何取消本地修改,保留远程修改
∙怎样的操作,会使svn 进入一个无法解决的冲突合并状态,以及如何解决
∙发现了一个SVN 本地目录丢失无法通过svn update 找回的问题,以及两种解决方法:o一个很古怪:分别使用不同的–set-depth 值执行多次update,不过最终会成功
o另外一个却需要知道丢失的目录名称,如果不知道本地有哪个目录缺失,就很难操作了最后,要向老杨的致谢,是他间接的为我们网站增加了两个博客。
老杨是我见过的最牛的程序员,但是他的CVS 的死忠和对SVN 的憎恨让我觉得异常诧异。
可能他和Linus Torvalds 很想像,但又有不同,因为Linus 对CVS 和SVN 同样憎恨。
我估计老杨一旦有时间(刚刚结婚,可能很难有时间),一旦掌握了Git,他就会把CVS (还有SVN?)扔到九霄云外。
不过我估计他还得需要SVN 和GIT 接合使用,因为毕竟他现在做的是商业软件开发,还需要精细的代码授权(至少是对别人授权)。
后记:
睡醒一觉后,发现俺的闺女小雪已经学会了one, two, three, four!真的不是吹的,2岁5个月的小孩,千字文已经可以从“天地玄黄背”到“如松之胜”,上个月开始莫名的喜欢英文歌,今天早晨居然会说one, two, three, four! “姑娘,别累坏了,不过要是你喜欢,…”
欣喜之余,想到给yzw 的博文莫不如扩充到one, two, three, four。
于是就有了下面两个博文:
∙《SVN 树冲突和目录丢失问题(3)》
一个更加简单重现yzw 问题的方法
∙《SVN 树冲突和目录丢失问题(4)》
一个更有意义和技术含量的冲突解决办法,可以让合并的双方不是“你死我活”的争斗,而是“谐和”SVN 树冲突和目录丢失问题(3)
昨天在《SVN 树冲突和目录丢失问题(1)》中重现yzw遇到的“更新导致树冲突”,实际上可以有更简单的重现方法。
大概的方法是:
∙将主线trunk 更新到老的版本,该老的版本尚不包含somedir 的提交
∙然后从branches/0.x 分支合并到主线
∙提交会引发过时错误
∙执行svn 更新
∙更新引发树冲突
具体的操作是:
1.查看当前主线的log
38.执行svn 更新,引发树冲突
43.查看树冲突的状态
解决目录重名的树冲突,可以参照“SVN 树冲突导致和目录丢失问题(2)”中介绍的方法。
∙采用分支的修改,抛弃本地(主线)的修改
本地还原到trunk 最新提交==> 删除somedir 目录==> 提交==> 执行更新以免由于目录属性修改导致过时错误==> 将分支0.x 合并到主线==> 合并成功,没有冲突==> 提交合并结果到主线
∙采用本地(主线的修改),抛弃分支的修改
还原到trunk 最新提交==> 将分支0.x 合并到主线==> 引发合并导致的树冲突==> 用svn resolve –accept working 标记somedir 的树冲突已经解决==> 提交合并结果到主线
可是在实际的情况下,上面的两个方法还是不够的,这就需要在对SVN合并机制充分理解的基础上,用一点小巧门。
我们下篇文章介绍一个更加具有现实意义的合并方法。
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会帮助你跳过已经完成合并的版本
警告:对于一个公司来说,为了避免由于低于 1.5 版本的SVN 客户端合并时破坏svn:mergeinfo 机制,应该配置SVN 的钩子,禁止低于1.5 版本的SVN 客户端访问。
一个更加现实的例子
分析和设计合并路线
现在的合并需求是:
∙将分支中增加的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
操作如下:
手工完成r3 到主线r4 的内容合并
分支0.x 的r3增加了一个新文件,复制到主线的somedir 目录中,我们就完成了r3 和r4 的内容合
执行分支到主线合并操作,将分支历史带入主线
看看合并后的历史
参数“-v ” 可以查看提交的文件统计信息;参数“-g” 可以查看合并源的日志信息
好了,这个关于 SVN 树冲突的系列博客就告一段落了。
我正在考虑是不是写一个 Git 相关的冲突解决机制,或者让 yzw 代劳?
总有人跟我抱怨SVN使用不方便,总出现各种各样的问题,尤其是上百人的研发团队。
我可以负责任的说,目前,SVN+GIT(GIT主要解决异地研发团队问题)是最好的,在版本控制上足够用了。
其实,这充分的体现了一句话:没有免费的午餐。
开源不意味着免费,只是软件下载是免费的,但安装,部署,使用,维护绝对不是没有成本的,建议找专业开源技术支持服务公司来处理该问题,比如SVN的使用,如果是几十人的团队,不自行开发管理后台或者使用专业公司的管理后台的话,授权问题基本都不能解决,何谈使用,免费的给你,你真就省钱了吗?
北京群英汇信息技术有限公司第21 页。