(转)svn树冲突

SVN 树冲突和目录丢失问题(1)
临下班了,一个老朋友 (之后用yzw代称) 在 MSN 上呼我。说他的 SVN 遇到问题了:

· 在执行分支合并时,一个目录发生了树冲突

· 直接在硬盘上将该目录删除

· 之后执行 svn update 该目录不能检出

· 不知道树冲突为何物,也不知道目录怎么变成了一团糟

好吧,谁让他公司的 SVN 是我给部署的呢?让他(yzw)执行 svn status 命令,看看显示什么信息,然后我在本地建立一个模型,争取重现并解决他的问题。

在已经一团糟的目录下,执行 svn 显示的信息如下:

$ svn st

M .

! + C somedir

> local add, incoming add upon update

看来他遇到的树冲突,是因为在两个分支同时创建了一个同名目录 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

看看目前的版本情况

1. 主线下执行 svn info

2. ~/tmp/svntf/trunk$ svn info

3. 路径: .

4. URL: file:///tmp/svnserver/trunk

5. 版本库根: file:///tmp/svnserver

6. 版本库 UUID: c0e3cb0f-81b0-40e5-9c35-42972dbc50aa

7. 版本: 4

8. 节点种类: 目录

9. 调度: 正常

10. 最后修改的作者: jiangxin

11. 最后修改的版本: 4

最后修改的时间: 2010-04-22 19:51:55 +0800 (四, 2010-04-22)

12. 主线下目录下的文件

13. ~/tmp/svntf/trunk$ svn ls -R

14. somedir/

somedir/trunk.txt

15. 主线的更改历史

16. ~/tmp/svntf/trunk$ svn log

17. ------------------------------------------------------------------------

18. r4 | jiangxin | 2010-04-22 19:51:55 +0800 (四, 2010-04-22) | 1 行

19.

20. to trunk, we add somedir/trunk.txt file.

21. ------------------------------------------------------------------------

22. r1 | jiangxin | 2010-04-22 19:48:57 +0800 (四, 2010-04-22) | 1 行

23.

24. initial

------------------------------------------------------------------------

25. 分支的中的文件列表

26. ~/tmp/svntf/trunk$ svn ls -R file:///tmp/svnserver/branches/0.x

27. somedir/

somedir/branch.txt

28. 分支的更改历史

29. ~/tmp/svntf/trunk$ svn log file:///tmp/svnserver/branches/0.x

30. ------------------------------------------------------------------------

31. r3 | jiangxin | 2010-04-22 19:51:21 +0800 (四, 2010-04-22) | 1 行

32.

33. to branch 0.x, we add somedir/branch.txt file.

34. ------------------------------------------------------------------------

35. r2 | jiangxin | 2010-04-22 19:50:27 +0800 (四, 2010-04-22) | 1 行

36.

37. trunk => branch/0.x

38. ------------------------------------------------------------------------

39. r1 | jiangxin | 2010-04-22 19:48:57 +0800 (四, 2010-04-22) | 1 行

40.

41. initial

------------------------------------------------------------------------

备份当前的 .svn 目录
直接拷贝 .svn 到 .svn-orignal,以便在出现意外的时候,进行参照。

~/tmp/svntf/trunk$ cp -a .svn .svn-orignal

Tips: 如果不想每次在执行 svn status 时显示 .svn-orignal 目录,设置svn属性 svn:ignore 值为 “.svn*”。(问题优点复杂化了,算了)

合并分支改动,引发异常
1. 执行合并操作,引发异常

2. ~/tmp/svntf/trunk$ svn merge file:///tmp/svnserver/branches/0.x

3. --- 正在合并 r2,经由 r4,到 “.”:

4. C somedir

5. 冲突概要:

树冲突:1

6. 删除 somedir 目录

~/tmp/svntf/trunk$ rm -rf somedir/

7. 执行 svn status 查看当前状态

8. ~/tmp/svntf/trunk$ svn st

9. M .

10. ? .svn-merge-conflict

11. ? .svn-orignal

12. ! C somedir

13. > 本地 增加,动作 增加,操作 合并

14. 虽然结果和yzw很像了,但是还不是完全一致。

o yzw 执行 svn status 显示的英文,最后一行翻译为中文是:

> 本地 增加,动作 增加,操作 更新

o 而我的结果是:

> 本地 增加,动作 增加,操作 合并

o 看来,还需要作些工作才能完全重现错误。

15. 这时我又备份了一下 .svn 目录,将 .svn 复制到 .svn-merge-conflict,以便后面比较

16. 执行 svn up 命令

17. ~/tmp/svntf/trunk$ svn up

18. 跳过“somedir”

19. D somedir

20. 更新到版本 4。

21. 冲突概要:

22. 跳过的路径:1

23. ~/tmp/svntf/trunk$ svn up

版本 4。

24. 以上执行了两次 svn up ,结果不一致,说明 svn 干了些什么。
实际上,通过比较 .svn 目录和之前备份的 .svn-merge-conflict 可以看出端倪:

25. ~/tmp/svntf/trunk$ diff -r .svn-merge-conflict .svn

26. diff -r .svn-merge-conflict/entries .svn/entries

27. 38,40d37

28. < somedir

29. < dir

<

30. 执行 svn 恢复操作,再执行 svn up,发现 somedir 没有了:

31. ~/tmp/svntf/trunk$ svn revert -R .

32. 已恢复“somedir”

33. ~/tmp/svntf/trunk$ svn up

34. 版本 4。

执行 svn status,看到本地工作目录的冲突状态已经消失了,一切看起来正常了。

~/tmp/svntf/trunk$ svn st

? .svn-merge-conflict

? .svn-orignal

但是,慢着,此时 somedir 目录没有了!

~/tmp/svntf/trunk$ ls

实际上,这时版本库中还有 somedir 目录,我们可以用 svn ls 命令查看:

~/tmp/svntf/trunk$ svn ls -R

somedir/

somedir/trunk.txt

但是本地的确已经没有了。如果要刨根问底的话,可以比较一下 .svn 目录和我们之前创建的备份:

~/tmp/svntf/trunk$ diff -r .svn-orignal .svn

diff -r .svn-orignal/entries .svn/entries

38,40d37

< somedir

< dir

<

35. 这时如果再执行从分支合并,合并的过程就很有意思了
居然没有发生冲突。yzw 这时后一定很欣喜,居然可以成功合并了。

36. ~/tmp/svntf/trunk$ svn merge file:///tmp/svnserver/branches/0.x

37. --- 正在合并 r2,经由 r4,到 “.”:

38. A somedir

A somedir/branch.txt

39. 但是慢着,这个合并是假的。不信提交看一看

40. ~/tmp/svntf/trunk$ svn st

41. M .

42. ? .svn-merge-conflict

43. ? .svn-orignal

44. A + somedir

45. A + somedir/branch.txt

46. ~/tmp/svntf/trunk$ svn ci -m "merge from branch 0.x"

47. 正在发送 trunk

48. 增加 trunk/somedir

49. svn: 提交失败(细节如下):

svn: 目录 “/trunk/somedir” 已经过时

50. 提交过时?很简单,SVN 的经典问题:服务器有更新的版本,更新之

51. ~/tmp/svntf/trunk$ svn up

版本 4。

52. 执行 svn update 没有反应?带目录执行 svn update 试试,果然发生冲突了:

53. ~/tmp/svntf/trunk$ svn up somedir

54. C somedir

55. 版本 4。

56. 冲突概要:

树冲突:1

57. 查看冲突的状态,是不是和 yzw 的一致了

58. ~/tmp/svntf/trunk$ svn st

59. M .

60. ? .svn-merge-conflict

61. ? .svn-orignal

62. A + C somedir

63. > 本地 增加,动作 增加,操作 更新

A + somedir/branch.txt

64. 不太一样?删掉 somedir 先。然后看状态:

~/tmp/svntf/trunk$ rm -rf somedir

再看看状态?

~/tmp/svntf/trunk$ svn st

M .

? .svn-merge-conflict

? .svn-orignal

! + C somedir

> 本地 增加,动作 增加,操作 更新

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 目录不算数”

看看实际操作的例子:

接受我的修改,远程的修改不算数
· 合并引发树冲突状态

· ~/tmp/svntf/trunk$ svn st

· M .

· ? .svn-merge-conflict

· ? .svn-update-conflict

· ? .svn-orignal

· C 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:merge-info 属性

· ~/tmp/svntf/trunk$ svn pl -v .

· “.” 上的属性:

· svn:mergeinfo

· /branches/0.x:2-4

· 提交合并的结果

· ~/tmp/svntf/trunk$ svn ci -m "忽略分支 0.x 的改动,我的增加是对的。"

· 正在发送 trunk

·

· 提交后的版本为 5。

· ~/tmp/svntf/trunk$ svn st

· ? .svn-merge-conflict

· ? .svn-update-conflict

· ? .svn-orignal

· ~/tmp/svntf/trunk$ svn pl -v .

· “.” 上的属性:

· svn:mergeinfo

/branches/0.x:2-4

接受远程的修改,我的修改不算数
上一个博文中,我几经尝试,进入到了由于更新引发的树冲突。但是在上一个博客示例最后的更新引发树冲突的状态,虽然也可以用 svn resolve 命令解决树冲突,但是无法提交。

总是报错

~/tmp/svntf/trunk$ svn st

M .

A + C somedir

> 本地 增加,动作 增加,操作 更新

A + somedir/branch.txt

~/tmp/svntf/trunk$ ls somedir

branch.txt

~/tmp/svntf/trunk$ svn resolve --accept working somedir

“somedir”的冲突状态已解决

~/tmp/svntf/trunk$ svn st

M .

A + somedir

A + somedir/branch.txt

~/tmp/svntf/trunk$ svn ci -m "删除我的增加的目录,分支 0.x 的增加是对的。"

增加 somedir

svn: 提交失败(细节如下):

svn: 目录 “/trunk/somedir” 已经过时

无论你如何执行 svn update,解决过时错误,也仍然不能提交。会陷入一个无穷无尽的冲突解决==>过时冲突的循环中。

一个撤销本地修改,接受远程分支修订的解决的办法是:

1. 还原

2. ~/tmp/svntf/trunk$ svn revert -R .

3. 已恢复“.”

4. 已恢复“somedir”

5. ~/tmp/svntf/trunk$ svn up

6. 版本 4。

7. ~/tmp/svntf/trunk$ svn st

? somedir

8. 找回在 .svn/entries 中已经丢弃的 somedir我使用 svn up –set-depth infinity 但是并不能更新出来。如果先执行 –set-depth 为其他,在执行 –set-depth infinity 倒是能够找回 somedir。但是这个方法太过奇怪,好像是 SVN 的一个 BUG,通过奇怪的操作绕过去了一样。我用下面的命令找回丢失的 somedir 目录:

9. ~/tmp/svntf/trunk$ rm -rf somedir/

10. ~/tmp/svntf/trunk$ svn up

11. 版本 4。

12. ~/tmp/svntf/trunk$ svn up somedir

13. A somedir

A somedir/trunk.txt

14. 用 svn 命令删除 somedir目录,并提交

15. ~/tmp/svntf/trunk$ svn rm somedir/

16. D somedir/trunk.txt

17. D somedir

18.

19. ~/tmp/svntf/trunk$ svn ci -m "丢弃我的改动"

20. 删除 trunk/somedir

21.

提交后的版本为 5。

22. 然后将分支 0.x 合并到主线,因为本地目录已经不在,合并不会出现冲突了

23. ~/tmp/svntf/trunk$ svn merge file:///tmp/svnserver/branches/0.x

24. --- 正在合并 r2,经由 r5,到 “.”:

25. A somedir

26. A somedir/branch.txt

27. ~/tmp/svntf/trunk$ svn st

28. M .

29. A + somedir

30. A + somedir/branch.txt

31. ~/tmp/svntf/trunk$ svn ci -m "删除我的增加的目录,分支 0.x 的增加是对的。"

32. 正在发送 trunk

33. svn: 提交失败(细节如下):

34. svn: 目录 “/trunk” 已经过时

35. ~/tmp/svntf/trunk$ svn up

36. 版本 5。

37. ~/tmp/svntf/trunk$ svn ci -m "删除我的增加的目录,分支 0.x 的增加是对的。"

38. 正在发送 trunk

39. 增加 trunk/somedir

40. 增加 trunk/somedir/branch.txt

41.

42. 提交后的版本为 6。

中间出现了一次过时问题,是因为目录属性修改,而目录的版本号尚未更新。这其实是 svn 混杂版本号造成的,已经超出本博文的内容。

总结
好了,通过这个例子,我介绍了增加同名目录引发的树冲突的解决方案。

· 如何保留本地修改,取消远程修改

· 如何取消本地修改,保留远程修改

· 怎样的操作,会使 svn 进入一个无法解决的冲突合并状态,以及如何解决

· 发现了一个 SVN 本地目录丢失无法通过 svn update 找回的问题,以及两种解决方法:

o 一个很古怪:分别使用不同的 –set-depth 值执行多次 update,不过最终会成功

o 另外一个却需要知道丢失的目录名称,如果不知道本地有哪个目录缺失,就很难操作了

老杨是我见过的最牛的程序员,但是他的 CVS 的死忠和对 SVN 的憎恨让我觉得异常诧异。可能他和Linus Torvalds 很想像,但又有不同,因为 Linus 对 CVS 和 SVN 同样憎恨。

我估计老杨一旦有时间,一旦掌握了 Git,他就会把 CVS (还有SVN?)扔到九霄云外。不过我估计他还得需要 SVN 和 GIT 接合使用,因为毕竟他现在做的是商业软件开发,还需要精细的代码授权(至少是对别人授权)。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值