Git还会恢复已发布的提交,同时保持未来合并的能力吗?

时间:2014-01-15 17:01:51

标签: git

我们有两个分支同时存在,如下:

A--B---C--------D--H---> (Branch A)
    \             /
     \---E--F--G-/--> (Branch B)

问题是我们决定我们不想将分支B合并到分支A中,这是一个错误。

因此,我们(在分支A上)恢复了合并提交:

git checkout branch-a
git revert H

导致:

A--B---C--------D--H--I--> (Branch A)
    \             /
     \---E--F--G-/--> (Branch B)

将分支A恢复到正常状态。 (通过还原提交I)然后我们在两个分支上做了更多的工作,现在想再次合并:

A--B---C--------D--H--I--J--K------?> (Branch A)
    \             /               /
     \---E--F--G-/---L---M----N--/ (Branch B)

问题是根据Git,当我们进行合并时,还原提交I比提交EF更新,并且G,并且比合并提交H更新,因此它不会从分支B添加新文件(和更改)。

我们可以快速恢复还原(yikes),但我们希望将来阻止这种情况发生。是否有适当的解决方案来撤消合并(到公共存储库),同时仍然保持将该分支合并到将来的能力?

编辑:这篇Git博客文章:http://git-scm.com/blog/2010/03/02/undoing-merges.html表明我们应该像我们正在做的那样“恢复还原”。但是,如果可能的话,我们希望找到一种更好的方法来撤消合并,同时保持将来重新合并分支的能力 - 而不必记住我们在过去的某个时间恢复了类似的合并。

1 个答案:

答案 0 :(得分:2)

撤消合并的简单方法

撤消合并的更好方法是使用git reset。如果您不关心保存合并的任何结果,并假设一份干净的工作副本,您可以执行以下操作,将分支A签出到您的工作副本。

git reset --hard D

如果工作区不干净,或者您想出于某种原因保存合并结果,则可以执行以下操作:

git reset --mixed D # actually, you don't have to specify 'mixed', as this is the default

这两个命令都会离开你的图形:

A--B---C--------D---> (Branch A)
    \             
     \---E--F--G--> (Branch B)

但是,第二个命令将在工作副本中保留更改。有关详细信息,请参阅git help reset联机帮助页。以下是关键部分:

git reset [<mode>] [<commit>]
           This form resets the current branch head to <commit> and possibly updates the index (resetting it to the tree of <commit>) and
           the working tree depending on <mode>. If <mode> is omitted, defaults to "--mixed". The <mode> must be one of the following:

--mixed
               Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) and reports what
               has not been updated. This is the default action.

--hard
               Resets the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded.

这样做会使未来的合并完全正常,因为没有回归历史。就git而言,下一次合并将是第一次,你的生活将继续。

作为旁注,原始合并提交H仍将实际保留在您的存储库中 - 但是:如果您设置了gc.auto,那么some commands将导致一个gc,修剪来自你的存储库的无法访问的提交,其中包括H.如果由于某种原因想要挂起到合并提交,你需要创建另一个分支来保存对它的引用或关闭{ {1}}并记下其提交ID的前7-8个字符,以便您可以再次找到它。

哦,废话,我是在公共分支上做到的

Official guidance可以避免不惜一切代价避免在已发布的分支上重写历史记录。我认为考虑它的正确方法是评估您的成本。你有多少个下游克隆?他们中的任何人真的贡献了工作,还是他们只是镜子?是否真的会在你的日志历史中重复提交那么多(只有一次,希望如此)?

问题的坚果:

  

是否有适当的解决方案来撤消合并(对公众而言)   存储库),同时仍然保持合并该分支的能力   回到未来?

没有一个漂亮而整洁的答案。一种方法是按建议还原合并,留下提交I:

gc.auto

为了使这一点更加明显,让我们将恢复版重新标记为H&#39;。当您准备再次合并时,首先启用rerere(A--B---C--------D--H--I--> (Branch A) \ / \---E--F--G-/--> (Branch B) ),然后还原还原:

rerere.enabled

如果存在冲突,请尽可能通过它们进行处理,然后重新记录结果(有关详细信息以及如何正确操作,请参见手册页。)

Junio Hamano和Linus Torvalds wrote a thorough explanation of this "revert-the-revert" scenario,自从写完这个答案后,我认为&#34;还原 - 还原&#34;是您的方案的正确答案。