撤销合并所做的更改

30

这位开发者在修改两个文件时,遇到了合并冲突,导致很多东西被删除(可能是因为没有最新的版本)。然后该提交被推送到共享仓库,并且其他开发者进行了其他的提交。

现在我们注意到这次合并删除了重要的文件,并希望将其还原。
如何在不丢失下一个提交更改的情况下进行还原?

我尝试使用 git revert commitsha,但它没有恢复更改。我需要还原 mergesha 吗?如何确定这个值?


你尝试过使用cherry-pick吗? - IgorGanapolsky
4个回答

44

git revert --mainline

通常情况下:

git revert --mainline 1 dd8cbe3e4

位置:

  • dd8cbe3e4是你想要撤消的错误合并提交,
  • --mainline告诉你要恢复的多个先前提交中的哪一个(记住,合并提交有多个父提交,你只能保留其中之一)。
    • 我找不到关于1意味着什么的好解释,但我猜1,2,3...对应于在dd8cbe3e4之前立即提交的提交的映射列表,按升序时间顺序排序(最旧的优先 - 这通常是您想要还原的内容)。

来源:

http://thezencoder.com/2013/09/05/how-to-correctly-revert-a-bad-merge-in-git/


4
我相信你对于主干的说法是正确的——文档地址:https://git-scm.com/docs/git-revert#git-revert--mparent-number - Mark Fox
--mainline 对我有效,但 -m 不行。会出现“fatal: bad revision '1'”错误。 - Noah Gary
很遗憾我们不得不猜测1的含义。关于你的猜测:你认为时间顺序是按照提交日期还是作者日期? - Don Hatch

10
简而言之,警告:除了将分支重置到合并之前的提交,没有真正的安全的方法来撤销合并。
让我解释一下,并浏览现有的参考资料。 引用链接答案中的内容:如何撤销错误的git合并提交

基本上,撤销合并将撤消数据更改,但不会撤消历史记录(图形)更改。因此,预计撤销错误的合并不会产生任何影响。

当然,将分支重置为最简单的方法,但如果合并的结果已经被推送到共享存储库中,则会有缺点(因为您实际上正在重写已发布的历史记录)。
这是详细说明。
  • git merge <someref> to merge (optionally commit after resolving conflicts)
  • If you find out right away that you want to reset the branch to before the merge:

    git reset HEAD@{1} 
         # optionally pass --hard to reset the working tree too
    
  • if you found out only later,

    • per-use the reflog to find the point before the merge. (HEAD@{1} is short for the previous value of the current head reference, but the reflog tracks a limited history of values for the head reference)

      git reflog
      
    • reset the branch

      git reset HEAD@{n} # substitute reflog entry index
      
    • optionally rebase/cherry-pick the commits done after the merge

      git cherry-pick HEAD@{1} # just an example. interactive tools will make this easier
      

谢谢sehe,这已经足够接近了!当然,由于其他错误,它并不能正常工作。我希望有一天会有一个版本控制系统,不需要单独的硕士学位,开发人员可以专注于开发,而不是花费数天时间来弄清楚一个既安全又混乱的系统。我从第一天开始就不喜欢git,但这并没有改变,尽管它在不断发展,总有一天会变得更好:( - Yatko
2
重置而不是还原的问题在于,如果您已经推送了错误的合并,并且其他人已经拉取了它,那么这将为他们的生活带来麻烦。一旦您推送了,通常应该创建补偿性的新提交,而不是删除提交。 - Sridhar Sarnobat
这是更改已发布历史记录时一直存在的问题。这不是重置的问题,而是已发布历史记录的问题 :) - sehe
没错,但是在你重置到最后一个好的提交之后,你该怎么做呢?这类似于在分布式系统中同步时钟。你永远不应该回到过去。 - Sridhar Sarnobat
你最后一条消息中不应该有“但是”的说法:它只是在重申你已经说过的内容。自从 2011年11月30日 以来,我的回答中就包含了同样的观点。我想你可以将这个答案作为理由来(a)避免合并,而是使用 pull --rebase;(b)永远不要在合并提交中编辑合并冲突;(c)不要破坏合并;(d)启用 git-rerere - sehe
1
是的,你说得对,我没有完整地阅读你的原始答案(其他人看到它可能也不会)。 - Sridhar Sarnobat

6
另一种更安全的方法是创建上一个正常版本和当前文件版本之间的差异,然后通过复制粘贴来恢复丢失的部分。这种方法始终有效,不需要任何奇怪的命令行选项,并且不会干扰您应该保留的内容 :-)
例如,Eclipse具有良好的工具,可以挑选每个单独的差异并将其复制到任一版本中。只需使用“比较”菜单打开两个版本并排放置即可。

很遗憾,你是对的。作为一种预防措施,重新定位比合并更好。 - Sridhar Sarnobat

1
简而言之,您可以执行git reset --soft <commit>,其中提交可以是HEAD^(上一个)、HEAD~2(当前-2)、SHA等。
使用--soft,所有更改都将准备好提交,因此您实际上可以更改提交。使用--hard,所有更改都将丢失。
在更改提交后,您必须使用git push --force强制推送更改到共享存储库。
请注意,您需要告诉其他开发人员他们应该将其存储库变基到共享存储库上(使用git pull --rebase)。但是,他们可能会遇到一些合并冲突... 请记住这一点。

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