Git:在合并中切换分支

Git: switch branches mid-merge

我刚刚花了最后几个小时来解决因将 big-feature-branch-B 合并到 big-feature-branch-A 而导致的合并冲突。我终于完成了,我所有的决议都已上演并准备好投入使用。但是,我工作的流程是:

  1. 创建 big-feature-branch-A 的分支(我将此分支称为 AB-merge-branch
  2. big-feature-branch-B 合并到 AB-merge-branch
  3. 创建一个 PR 以将 AB-merge-branch 合并到 big-feature-branch-A,以便决议可以通过代码审查。

当我解决合并冲突的大部分过程时,我意识到我是在 big-feature-branch-A 而不是合并分支中解决它们。

我的问题是,如何在提交更改之前安全地更改分支?

我相信答案很简单,通常我只是隐藏我的更改,切换分支,然后弹出我的更改。但是,我从来没有在合并过程中这样做过,在这种情况下,我对 "trying it" 感到非常不安,因为我不想冒险不得不再次解决所有这些冲突,而且我也不是对我的 git-fu 超级自信。我也读过类似 this 的恐怖故事(但也许我的情况不同,因为我已经解决了所有的冲突,并且所有的变化都是上演的?),并且不想在这种情况下进行试验。谢谢!

首先,简单地完成合并和提交。这样你就不会丢失任何东西。
这是本地操作,不会被其他人看到。

从该提交中,您可以创建分支 AB-merge-branch

 git checkout -b AB-merge-branch

并且您可以将之前的 big-feature-branch-A 重置为其第一个父提交。

 git branch --force big-feature-branch-A big-feature-branch-A^1

简短的回答是你不能 (switch b运行ches ... Git):

$ git checkout -b newbr
foo.txt: needs merge
error: you need to resolve your current index first

您的索引处于这种特殊的 "merging" 状态,因此您也无法存储。幸运的是,没有必要这样做。 (如果你解决所有问题,然后 运行 git checkout -b newbr 并提交,你会得到一个 non-merge 提交。你可以使用它,但我们不要那样做。)

您应该做的是继续并完成合并:这将为您提供所需的合并 结果。然后你可以 re-start 在你想要的 b运行ch 合并,并获取你刚刚提交的结果作为 result 你想要,如果有必要的话。然后您完全丢弃原始合并提交(如果需要)。 (如果您不小心破坏了成功的合并 git checkout -b,这也是您需要做的,几乎如上所示。)

在某些情况下——包括你的情况——原始合并的parent链接就是你想要的,这只是重新[=79=的问题]标记合并。

我会先展示食谱,然后再解释为什么它有效:

... finish merging ...
$ git commit                         # commit the merge
$ git checkout -b AB-merge-branch    # create the merge branch
$ git checkout big-feature-branch-A  # get back to other branch
$ git reset --hard HEAD^             # take the merge off of it

为什么这是一个答案(有多种方式所以我不会说答案)

让我们画出您刚开始合并时的设置:

       o--...--o--o   <-- big-feature-branch-A (HEAD)
      /
...--*
      \
       o--...--o--o   <-- big-feature-branch-B

也就是说,正如 git status 所说的那样,您 "on branch big-feature-branch-A" 一切都很好。每个 o 代表一个提交(我用星号标记了合并基础,用于合并)。

然后您打算到运行git checkout -b AB-merge-branch。如果你这样做了,图片会是这样的:

    o--...--o--o   <-- big-feature-branch-A, AB-merge-branch (HEAD)
   /
--*
   \
    o--...--o--o   <-- big-feature-branch-B

您 运行 git merge,因冲突而失败。您解决了(大部分)冲突(您必须在继续之前解决所有冲突)。当您最终提交时,您将获得一个新的合并提交,这将移动 current b运行ch(HEAD 记住的那个):

    o--...--o--o   <-- big-feature-branch-A
   /            \
--*              M   <-- AB-merge-branch (HEAD)
   \            /
    o--...--o--o   <-- big-feature-branch-B

这里没有显示(因为太难显示)是新合并的firstparentM最右边(latest ) 上行提交,第二行是下行。 (第一和第二的东西以后很重要,如果有的话,当有人想关注 "main" b运行ch vs "side features that were merged in" 时:主要的 b运行ch 总是首先 parent,根据定义。)

您忘记创建一个新的 b运行ch name,所以现在发生的是:

    o--...--o--o
   /            \
--*              M   <-- big-feature-branch-A (HEAD)
   \            /
    o--...--o--o   <-- big-feature-branch-B

第一个 parent 是 仍然是 top-and-right-most 提交,第二个 parent 仍然是底部这样的提交。新的合并提交 M 完全相同 。只是 label 移动,指向新的合并 M,是 big-feature-branch-A(那个是 HEAD),而不是不存在的 AB-merge-branch(这显然不是 HEAD)。

所以您现在要做的就是创建您想要的标签。使新 b运行ch 名称 AB-merge-branch 指向 M 的任何内容都足以满足该部分的要求。您可以使用 git checkout -b AB-merge-branchgit branch AB-merge-branch 来做到这一点。

如果你确实使用 git checkout -b,你现在必须 返回 big-feature-branch-A 以使用 git reset 修复它(还有其他您可以使用的命令,但我在这里坚持使用 reset)。如果您使用 git branch 创建新的 b运行ch,您的 current b运行ch 不受干扰:您仍在 big-feature-branch-A.

无论如何,您希望这个 big-feature-branch-A b运行ch 名称后退一步,到 M 的第一个 parent,就好像它有一开始就没有前进到 M。所以你回到(或继续)这个 b运行ch。一旦你在这个 b运行ch 上,你可以使用 git reset --hard HEAD^ 来实现这个 moving-back-one-step。 HEAD^ 表示 "find the first parent of HEAD",如果 HEAD 命名提交 M(确实如此)- 表示最右边的上行提交,这是您想要 b运行ch指向。 git reset 命令执行 b运行ch 的 re-pointing,还有 re-sets 你的索引和 work-tree(这样一切都在新提交上干净利落) .