如何撤销一个 Git 合并操作,但保留历史记录?

11
我们的代码库有一个主分支,但似乎我们的一位同事有一个具有不同历史记录的主分支。昨天他将自己的主分支合并到了主要的主分支,并推送了代码。因此,今天有些人已经拉取并开始工作。当我们意识到问题时,已经过去了几个小时...

所以我的问题是,我如何撤消他的合并,但仍然保留今天所做的代码更改?左边是我们当前的状态,右边是我想要的状态。我应该使用rebase吗?还是有一种方法可以撤消合并?这里最佳的方法是什么?

enter image description here

编辑1:我认为这不是撤消尚未被推送的Git合并的重复,因为提交已经被推送到远程库,并且我在错误发生后有其他提交,我想要保留历史记录。

编辑2:我尝试过rebase,但问题是菜鸟正在过去的两周内将其合并到自己的主分支中...因此,即使我撤消,我也无法摆脱他创建的新的“时间线”...只要我摆脱了他的时间线,我就可以重新编写历史记录...

enter image description here

编辑3:

最终,我找到了一个未更改过的代码库版本,并重做了事故发生后所做的修改...


git status 说了什么? - Filip Bartuzi
当你说你想保留今天完成的工作时,你是指那些错误合并的分支上的工作,还是指不同提交中的工作? - Makoto
@Makoto 我想要保留从A开始的所有提交,以便将来(向上)继续进行这3个分支的工作。 - Mac
可能是撤销Git合并的重复问题。 - Makoto
特别注意:这个答案,可能是您使用情况下的理想解决方案(考虑到您已经推送)。 - Makoto
2个回答

6
我可以看到三个选项:回滚合并、变基或过滤。
回滚
"正确"的解决方案是回滚合并,正如其他人所主张的那样。这意味着你不会"重写历史",这通常被认为是一件好事,尤其是因为这意味着其他人在处理这段代码时不需要处理历史更改。
然而,你不能只使用git revert,因为它不知道要保留哪个分支的历史记录。解决方案很简单,只需向Git提供额外的信息即可。
git revert -m 2 <sha-of-B>

-m 2表示你想保留第二个父提交,即包含提交C的父提交;如果要选择另一种方案,请切换到-m 1

需要注意的是:如果你想将其他分支合并到主分支中,你会遇到问题,因为Git认为该分支已经在主分支中了。有几种解决方法,但最简单的(我认为)是将还原操作放在一个从主分支分出来的分支上,并将其合并到主分支和其他分支中。那个分支可能看起来像从哪个版本的主分支分出来的,此时你可以撤销还原操作,当你将来进行合并时,一切都会很好。

变基

变基可能是最简单的选项:git rebase <sha-of-B> master --onto <sha-of-C>

这将把从B到master的所有提交移动到C上。问题在于它将“线性化”合并历史记录。图像中的合并历史非常简单,但如果你想保留历史记录或者在更复杂的存储库上执行此操作,则可能会出现问题。

这也有一个缺陷,即它是“重写历史”,使用此存储库的其他人将发现他们正在处理与已还原的不同的代码分支,因为从 C 开始的每个更改都将具有不同的 sha1 哈希。
过滤
使用 git filter-branch 将允许您在图像中精确获取所需内容,即保留合并历史记录,但这是最复杂的选项,仍涉及重写历史。
实际上,您想要使用 git filter-branch 来过滤提交以保留除了那个瑕疵合并之外的所有内容。这样做非常复杂,我不会尝试编写说明; 您需要结合 --commit-filter 删除有问题的合并和 --tree-filter 来撤消合并的更改。
过滤 redux
好吧,这是第四种方法,我包括它是为了完整性。您可以只检出 C,然后逐个手动挑选和合并您想要在主分支中拥有的每个更改。
进一步阅读

Ok Rebase 看起来很好用,但是我失去了合并信息。也就是说,在 rebase 之后的所有合并看起来都是对主分支进行的更改。有没有办法保留它们? - Mac
@Mac 是的。我回答中的其他选项都会保留合并历史记录,而不是让它在您的主分支上呈线性。当然,它们会需要更多的工作。 - me_and
我喜欢第四个选项。如果您详细说明一下,我会使用它。这是一个共享的存储库,无法更改历史记录。从合并之前的提交中检出一个新分支,然后在我的其他分支上挑选以下工作是完美的。当主分支上的问题得到解决时,我可以将其合并到我的新分支上。 - blamb

1
我会做的是进行还原操作,即寻找您刚刚合并的增量的反向操作,然后提交该操作。将还原提交到您的C分支,然后在C分支上还原该提交并提交。双重否定将被取消,您将保存所有历史记录,并在下次合并时获得所需的结果。
Git扩展具有还原提交的功能,使此过程非常简单。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接