我刚刚花了最后几个小时解决由 merge 引起的 merge 冲突 big-feature-branch-B
进入 big-feature-branch-A
.我终于完成了,我所有的决议都已上演并准备好 promise 。但是,我工作的过程是:
big-feature-branch-A
创建一个分支(我将把这个分支称为 AB-merge-branch
)big-feature-branch-B
进入 AB-merge-branch
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-branch
或 git 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/