为什么有时 GitHub 会进行循环合并?

Why does sometimes GitHub do circular merge?

前几天我做了一个合并:

  1. 我在 GitHub
  2. 上打开了一个拉取请求
  3. 我点击了 GitHub
  4. 上的合并按钮
  5. GitHub告诉我有冲突,所以我按照他们的指示:
    1. git checkout A
    2. git merge B
    3. git checkout B
    4. git merge --no-ff A
    5. git push origin B

后来发现分支A成功合并到分支B.

但是当我切换回分支 A 时,我意识到分支 B 也被合并到了分支 A 中。

为什么会这样?

一起来看看吧

您有两个分支,AB,合并它们会产生冲突。这可能看起来像这样:

*---*---*---* [A]
     \
      *---*   [B]

您在 GitHub 上创建拉取请求以将 B 合并到 A(或将 A 合并到 B,这并不重要这个案例)。 GitHub 告诉您合并会产生必须解决的冲突,因此无法自动完成。

按照 GitHub 的说明,您可以 运行 在本地执行以下命令:

  1. git checkout A
  2. git merge B
  3. 解决冲突并完成合并

现在您的本地副本看起来像这样:

*---*---*---*---x [A]
     \         /
      *-------*   [B]

这里x是一个新提交,解决了AB之间的冲突。然后你 运行 以下命令:

  1. git checkout B
  2. git merge --no-ff A

由于 x 是尚未包含在 B 中的新提交(尤其是因为您已经包含 --no-ff),因此会生成一个新提交 y

*---*---*---*---x   [A]
     \         / \
      *-------*---y [B]

在不创建此 "circular merge" 的情况下解决冲突的另一种选择是将 B 变基到 A 并以这种方式解决冲突:

  1. git checkout B
  2. git rebase A
  3. 解决冲突并完成变基

这会生成类似

的内容
*---*---*---*         [A]
             \
              o---o   [B]

B 中标记为 o 的两个最新提交是新的(它们的哈希值已更改)因此您必须强制将 B 推回到 GitHub使用 --force-with-lease,但现在您可以使用 GitHub 的拉取请求 UI 完成合并,而无需创建 "circular merge".

在执行此操作之前,请务必阅读有关 implications of rewriting commits 和强制推送(o 此处)的信息,尤其是当您在团队中工作时。