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(-)
