Git:在 merge 中切换分支

标签 git git-merge

我刚刚花了最后几个小时解决由 merge 引起的 merge 冲突 big-feature-branch-B进入 big-feature-branch-A .我终于完成了,我所有的决议都已上演并准备好 promise 。但是,我工作的过程是:

  • big-feature-branch-A 创建一个分支(我将把这个分支称为 AB-merge-branch )
  • merge big-feature-branch-B进入 AB-merge-branch
  • 为 merge 创建 PR AB-merge-branch进入 big-feature-branch-A ,以便决议可以通过代码审查。

  • 当我解决 merge 冲突的大部分时间时,我意识到我正在解决它们 big-feature-branch-A而不是 merge 分支。

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

    我相信答案很简单,通常我只会 stash 我的更改,切换分支,然后 pop 我的更改。但是,我从未在 merge 过程中这样做过,在这种情况下,我对“尝试”感到非常不安,因为我不想冒险再次解决所有这些冲突,而且我不是 super 对我的 git-fu 充满信心。我也读过类似 this 的恐怖故事(但也许我的情况不同,因为我已经解决了所有冲突,并且所有更改都已上演?),并且不想在这种情况下进行实验。谢谢!

    最佳答案

    简短的回答是你不能(切换分支......嗯,有点,虽然你可以,有点,但这是不可取的 - 它涉及直接与 Git 的内部进行猴子):

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

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

    你应该做的是继续完成 merge :这会给你你想要的 merge 结果。然后,您可以在您想要的分支中重新开始 merge ,并在必要时获取您刚刚提交的结果作为您想要的结果。然后完全丢弃原始 merge 提交(如有必要)。 (如果您不小心破坏了成功的 merge git checkout -b,这也是您需要做的,几乎如上所示。)

    在某些情况下——包括你的情况——原始 merge 的父链接是你想要的,这只是重新标记 merge 的问题。

    我会先展示配方,然后解释它为什么起作用:
    ... 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
    

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

    让我们绘制您第一次开始 merge 时的设置:
           o--...--o--o   <-- big-feature-branch-A (HEAD)
          /
    ...--*
          \
           o--...--o--o   <-- big-feature-branch-B
    

    也就是说,你是,作为 git status会说,“在分支 big-feature-branch-A 上”,一切都很好。每个o代表一个提交(我用星号标记了 merge 基础,用于 merge )。

    然后您打算运行 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 ,因冲突而失败。您解决了(大部分)冲突(您必须在继续之前解决所有冲突)。当您最终提交时,您将获得一个新的 merge 提交,这将移动当前分支(由 HEAD 记住的分支):
        o--...--o--o   <-- big-feature-branch-A
       /            \
    --*              M   <-- AB-merge-branch (HEAD)
       \            /
        o--...--o--o   <-- big-feature-branch-B
    

    这里没有显示(因为太难显示)是新 merge 的第一个父级 M是最右边(最新)的上一行提交,第二个是下一行。 (当有人想要遵循“主”分支与“已 merge 的侧功能”时,这第一个和第二个东西稍后很重要:根据定义,主分支始终是第一个父分支。)

    你忘了创建一个新的分支名称,所以现在发生的事情是这样的:
        o--...--o--o
       /            \
    --*              M   <-- big-feature-branch-A (HEAD)
       \            /
        o--...--o--o   <-- big-feature-branch-B
    

    第一个父级仍然是最顶部和最右侧的提交,第二个父级仍然是此类提交的底部。新的 merge 提交 M完全一样。只是标签移动了,指向新的 merge M , 是 big-feature-branch-A (那个是 HEAD),而不是不存在的 AB-merge-branch (这显然不是 HEAD)。

    所以你现在要做的就是创建你想要的标签。任何使新分支命名的东西 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要创建新分支,您当前的分支不受干扰:您仍在 big-feature-branch-A .

    无论如何,你想要这个big-feature-branch-A分支名称后退一步,到 M 的第一个父级,就好像从来没有前进到M首先。所以你回到(或留在)这个分支。一旦你在这个分支上,你可以使用 git reset --hard HEAD^实现这一后退一步。 HEAD^表示“找到 HEAD 的第一个父级”,如果 HEAD名称提交 M (确实如此)——表示最右边的上一行提交,这是您希望分支指向的位置。 git reset命令执行此分支的重新指向,并重新设置您的索引和工作树(以便所有内容都在新提交中干净利落)。

    关于Git:在 merge 中切换分支,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45340523/

    相关文章:

    Git merge 错误

    git - 如何摆脱 git 分支/pull 请求中不需要的更改?

    git - 如何从 "git rm -rf ."恢复并仍然保留未提交的更改?

    git - VS Code 提交撤消

    混帐/gitorious : Way to share certain branches/repositories with the customer

    git - merge 具有相似分支签名的分支

    git - 为什么 git merge 删除文件而不是移动它们?

    git - 结合 Git Bash 并在 CMDER 的当前文件夹中打开

    git - 在 gitconfig 中设置多个替代案例的脚本

    git - 重写 git 历史记录以扁平化 merge 提交