16.5 合并四:树冲突

    如果一个用户将某个文件改名,另外一个用户将同样的文件改为另外的名字,当这两个用户的提交进行合并操作时,Git显然无法替用户做出裁决,于是就产生了冲突。这种因为文件名修改造成的冲突,称为树冲突。这种树冲突的解决方式比较特别,因此专题介绍。

    仍旧使用前面的版本库进行此次实践。为确保两个用户的本地版本库和共享版本库状态一致,先分别对两个用户的本地版本库执行拉回操作。


    $git pull

    下面就分别以两个用户的身份执行提交,将同样的一个文件改为不同的文件名,制造一个树冲突,具体操作过程如下。

    (1)用户user1将文件doc/README.txt改名为readme.txt,提交并推送到共享版本库。


    $cd/path/to/user1/workspace/project $git mv doc/README.txt readme.txt $git commit-m "rename doc/README.txt to readme.txt" [master 615c1ff]rename doc/README.txt to readme.txt 1 files changed,0 insertions(+),0 deletions(-) rename doc/README.txt=>readme.txt(100%) $git push Counting objects:3,done. Delta compression using up to 2 threads. Compressing objects:100%(2/2),done. Writing objects:100%(2/2),282 bytes,done. Total 2(delta 0),reused 0(delta 0) Unpacking objects:100%(2/2),done. To file:///path/to/repos/shared.git 7f7bb5e..615c1ff master->master

    (2)用户user2将文件doc/README.txt改名为README,并做本地提交。


    $cd/path/to/user2/workspace/project $git mv doc/README.txt README $git commit-m "rename doc/README.txt to README" [master 20180eb]rename doc/README.txt to README 1 files changed,0 insertions(+),0 deletions(-) rename doc/README.txt=>README(100%)

    (3)用户user2执行git pull操作,遇到合并冲突。


    $git pull remote:Counting objects:3,done. remote:Compressing objects:100%(2/2),done. remote:Total 2(delta 0),reused 0(delta 0) Unpacking objects:100%(2/2),done. From file:///path/to/repos/shared 7f7bb5e..615c1ff master->origin/master CONFLICT(rename/rename):Rename "doc/README.txt"->"README" in branch "HEAD" rename "doc/README.txt"->"readme.txt" in "615c1ffaa41b2798a56854259caeeb1020c51721" Automatic merge failed;fix conflicts and then commit the result.

    因为两个用户同时更改了同一文件的文件名并且改成了不同的名字,于是引发冲突。此时查看状态会看到:


    $git status #On branch master #Your branch and 'refs/remotes/origin/master' have diverged, #and have 1 and 1 different commit(s)each,respectively. # #Unmerged paths: #(use "git add/rm<file>…" as appropriate to mark resolution) # #added by us:README #both deleted:doc/README.txt #added by them:readme.txt # no changes added to commit(use "git add" and/or "git commit-a")

    此时查看一下用户user2本地版本库的暂存区,可以看到因为冲突在编号为1、2、3的暂存区出现了相同SHA1哈希值的对象,但是文件名各不相同。


    $git ls-files-s 100644 463dd451d94832f196096bbc0c9cf9f2d0f82527 2 README 100644 463dd451d94832f196096bbc0c9cf9f2d0f82527 1 doc/README.txt 100644 463dd451d94832f196096bbc0c9cf9f2d0f82527 3 readme.txt 100644 430bd4314705257a53241bc1d2cb2cc30f06f5ea 0 team/user1.txt 100644 a72ca0b4f2b9661d12d2a0c1456649fc074a38e3 0 team/user2.txt

    其中在暂存区1中是改名之前的doc/README.txt,在暂存区2中是用户user2改名后的文件名README,而暂存区3是其他用户(user1)改名后的文件readme.txt。

    此时的工作区中存在两个相同的文件README和readme.txt分别是用户user2和user1对doc/README.txt重命名之后的文件。


    $ls-l readme.txt README -rw-r—r—1 jiangxin jiangxin 72 12月27 12:25 README -rw-r—r—1 jiangxin jiangxin 72 12月27 16:53 readme.txt

    16.5.1 手工操作解决树冲突

    这时user2应该和user1商量一下到底应该将该文件改成什么名字。如果双方最终确认应该采用user2重命名的名称,则user2应该进行下面的操作完成冲突解决,具体操作过程如下。

    (1)删除文件readme.txt。

    在执行git rm操作过程时会弹出三条警告,说共有三个文件待合并。


    $git rm readme.txt README:needs merge doc/README.txt:needs merge readme.txt:needs merge rm 'readme.txt'

    (2)删除文件doc/README.txt。

    执行删除过程,弹出的警告少了一条,因为前面的删除操作已经将一个冲突文件撤出暂存区了。


    $git rm doc/README.txt README:needs merge doc/README.txt:needs merge rm 'doc/README.txt'

    (3)添加文件README。


    $git add README

    (4)这时查看一下暂存区,会发现所有文件都在暂存区0中。


    $git ls-files-s 100644 463dd451d94832f196096bbc0c9cf9f2d0f82527 0 README 100644 430bd4314705257a53241bc1d2cb2cc30f06f5ea 0 team/user1.txt 100644 a72ca0b4f2b9661d12d2a0c1456649fc074a38e3 0 team/user2.txt

    (5)提交完成冲突解决。


    $git commit-m "fixed tree conflict." [master e82187e]fixed tree conflict.

    (6)查看一下最近三次提交日志,看到最新的提交是一个合并提交。


    $git log—oneline—graph-3-m—stat *e82187e(from 615c1ff)fixed tree conflict. |\ ||README|4++++ ||readme.txt|4—— ||2 files changed,4 insertions(+),4 deletions(-) |*615c1ff rename doc/README.txt to readme.txt ||doc/README.txt|4—— ||readme.txt|4++++ ||2 files changed,4 insertions(+),4 deletions(-) *|20180eb rename doc/README.txt to README |/ |README|4++++ |doc/README.txt|4—— |2 files changed,4 insertions(+),4 deletions(-)