为什么分支B在第一次合并提交之后,从A到B的所有合并提交中都有冲突?

时间:2018-10-15 19:20:01

标签: git git-merge shared git-branch-sculpting git-history

我有一个历史悠久的初级开发分支(A)。 A中的所有版本提交都被标记为此类。我签出了A的根提交,并分支到测试(B)中。

因此,我有一个主要分支A,分支B的头部指向A的根提交。我的目标是通过合并从A到B的每个带标记的提交来创建所有版本的历史记录。

从A到B的第一次合并按预期进行,没有冲突。

$git checkout B
$git merge [release-commit-ID] --squash
$git commit -m "release#"

第一个提交工作得很好,但是所有其他提交都将所有合并提交视为完全冲突。我看到B的根与A的根相同,但是从A中的第一个发布提交到B中的第一个压缩合并提交之后,没有共享历史被识别。是什么引起冲突以及如何获取共享历史被认可?

1 个答案:

答案 0 :(得分:1)

  

是什么导致冲突?如何识别共享历史记录?

没有共享的历史记录(或者说不够)。没有什么可识别的,这就是为什么存在冲突。

关键是--squash标志:

$ git checkout B
$ git merge [release-commit-ID] --squash

第一步是将您的HEAD附加到分支名称B上,检查出B所标识的提交名称:

...--*--C--D--E   <-- B (HEAD)
      \
       F--G--H   <-- somebranch

这里的名称B标识提交E(每个字母代表真实的哈希ID)。提交*(我将其命名为B,但您使用了该名称作为分支)是两个开发流分开的地方,这意味着当我们向后工作时(如Git所做的那样)这是他们聚在一起的关键。现在,您运行git merge --squash <hash>,其中<hash>标识提交FGH,因此Git将提交*的内容与提交E的内容以了解您所做的更改:

git diff --find-renames <hash-of-*> <hash-of-E>   # what we changed

并重复G

git diff --find-renames <hash-of-*> <hash-of-G>   # what they changed

Git现在将这两组更改合并,将合并的更改应用于*的内容,并进行新的提交。

如果您使用--squash,则Git会记录有两个父母的新提交:

...--*--C--D--E--I   <-- B (HEAD)
      \         /
       F-------G--H   <-- somebranch

,两行之间的最新公共起点是提交G。但是,如果您使用使用--squash,则Git仅使用一个父级记录新提交:

...--*--C--D--E--I   <-- B (HEAD)
      \
       F--G--H   <-- somebranch

,现在通用起点不变。 G中的所有工作都在提交I中,但是提交I不能记住 为什么。提交git merge以后的H必须从提交*重新开始。

Git不会阻止您在分支somebranch上进行开发,但是通常,在git merge --squash之后,您应该将合并 from 的分支视为“已死” ”,然后完全停止使用它。将Ggit merge --squash合并后,我们应该完全停止使用FG。这意味着我们还必须完全停止使用H。如果H有用,我们应该将其复制到新的不同提交中:

$ git checkout -b newbranch B

给予我们

...--*--C--D--E--I   <-- B, newbranch (HEAD)
      \         /
       F-------G--H   <-- somebranch

其次:

$ git cherry-pick somebranch   # or <hash of H>

要将H复制到非常相似但不完全相同的地方,请提交H'

                   H'   <-- newbranch (HEAD)
                  /
...--*--C--D--E--I   <-- B
      \         /
       F-------G--H   <-- somebranch

我们现在可以丢弃somebranch

$ git branch -D somebranch

,如果愿意,可以将newbranch重命名为somebranch

(请注意,我们可以使用git rebase --ontogit checkout somebranch; git rebase --onto B <hash of G>使用git cherry-pick一步完成此带有名称移动的操作。尽管如此,请注意{{1 }}无法复制合并提交,并且正在使用我们要杀死的提交的任何人-在F-G-H链上-必须这样做,然后再将其复制保存东西。因此,在使用--squash之前,请确保您了解所有含义。)