Git八爪鱼合并多个分支的顺序

40

我在使用Git时遇到了一件有趣的事情,想知道是否有人能够解释一下,以便我更好地理解。

在合并多个分支(A,B)时,

git merge A B

在非快进模式下失败,但是

git merge B A

运行良好。这是为什么呢?


1
你遇到了什么样的冲突?我认为一般情况下这是因为B所做的更改使得A更容易合并,例如A试图修补一个文件,但在B中被重命名为另一个名称。 - Cascabel
1个回答

49
假设A是当前分支的一个严格的直接子节点。然后假设B是A的一个严格的直接子节点

章鱼合并按从左到右给定的头处理,相对于树来说是递增的,但是相对于索引独立。如果它尝试应用B然后是A,则成功地进行了合并,但是如果反过来,则会遇到冲突。

根据 git-merge 手册,第合并策略部分:

octopus
   This resolves cases with more than two heads, but refuses to do a
   complex merge that needs manual resolution.

例如:
 ~                 $ git init testdir && cd testdir && echo "This is C" > myfile
 Initialized empty Git repository in /home/huitseeker/testdir/.git/

 ~/testdir         $ git add myfile && git commit -m "C" 
 [master (root-commit) f0c8c82] C
  1 files changed, 1 insertions(+), 0 deletions(-)
  create mode 100644 myfile

 ~/testdir(master) $ git checkout -b "A" && echo "This is A1" > myfile
 Switched to a new branch 'A'
 ~/testdir(A)      $ git commit -m "A1" myfile
 [A ac5b51c] A1
  1 files changed, 1 insertions(+), 1 deletions(-)

 ~/testdir(A)      $ git checkout -b "B" && echo "This is B1" >> myfile
 Switched to a new branch 'B'
 ~/testdir(B)      $ git commit -m "B1" myfile
 [B 5bc838c] B1
  1 files changed, 1 insertions(+), 0 deletions(-)

 ~/testdir(B)      $ git checkout master
 Switched to branch 'master'
 ~/testdir(master) $ git merge B A
 Fast-forwarding to: B
 Already up-to-date with A
 Merge made by octopus.
  myfile |    3 ++-
  1 files changed, 2 insertions(+), 1 deletions(-)

 ~/testdir(master) $ git reset --hard HEAD^^^
 HEAD is now at f0c8c82 C
 ~/testdir(master) $ git merge A B
 Fast-forwarding to: A
 Fast-forwarding to: B
 error: Entry 'myfile' would be overwritten by merge. Cannot merge.
 Merge with strategy octopus failed.

 ~/testdir(master) $ cat myfile
 This is A1

实际上,当快进到A时,主分支的标签并没有向前推进,尽管树已经推进了。

 ~/testdir(master) $ git status
 # On branch master
 # Changes to be committed:
 #   (use "git reset HEAD <file>..." to unstage)
 #
 #  modified:   myfile
 #

如果我手动执行这个八爪鱼合并操作的代码(参考上面的哈希值):
 ~/testdir(master) $ git reset --hard f0c8c82
 HEAD is now at f0c8c82 C     
 ~/testdir(master) $ git read-tree -u -m f0c8c82 ac5b51c
 ~/testdir(master) $ git read-tree -u -m f0c8c82 5bc838c
 error: Entry 'myfile' would be overwritten by merge. Cannot merge.

在另一个方向上(合并B A),现在,如果您再次查看merge-octopus的代码,它会尝试检测我们正在尝试添加的分支是否已经存在于树中(for循环的第二个case)。确实,在合并A时,它看到ac5b51c(也称为A的头)是A和B的公共祖先,并在不进行第二个read-tree的情况下中止。

这种行为与git的最新版本一致:尽管我指向了v.1.3.1,但我的版本仍然发生了这种情况。

 ~/testdir(master) $ git --version
 git version 1.7.5.4

简单来说:你想让你的章鱼合并分支触及不同的文件。


1
你的链接并没有真正解释你所说的“直接上游”是什么意思。我最好的猜测是,你的意思是合并将会是一个快进,也就是说B是A的“严格、直接的上游”,这意味着A是B的祖先。在这种情况下,你的例子是不起作用的。在第一种情况下,两个合并都是快进的,一切都很好,在第二种情况下,第一个是快进的,第二个已经合并,因此不需要操作,不会导致合并冲突。 - Cascabel
5
你说得对,我表述不够准确。我已经修改了我的答案以反映你的评论,并添加了重要的指示,即八达通在合并应用程序之间不会更新头索引,并包括了一个最简示例。 - Francois G
太棒了,这才是一个答案。 - Cascabel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接