如何“取消还原”已还原的 Git 提交?

Posted

技术标签:

【中文标题】如何“取消还原”已还原的 Git 提交?【英文标题】:How do I "un-revert" a reverted Git commit? 【发布时间】:2021-09-08 15:56:36 【问题描述】:

假设更改已使用commit 提交,然后使用revert 恢复,那么撤消该恢复的最佳方法是什么?

理想情况下,这应该通过新的提交来完成,以免重写历史记录。

【问题讨论】:

How can I fix a reverted git commit?的可能重复 @phuclv 评论可能存在重复,点这里。一份必须标记为原始,一份必须标记为重复 @JohnDemetriou 没有,有更好答案的问题应该保持开放。时间在这里无关紧要How should duplicate questions be handled? 我没有说时间。我只是碰巧对这两个问题中的一个发表了评论 【参考方案1】:

git cherry-pick <original commit sha> 将复制原始提交,实质上是重新应用提交

还原 revert 会做同样的事情,但提交信息更混乱:git revert <commit sha of the revert>

这两种方式都可以让您git push 不覆盖历史记录,因为它会在还原后创建一个新的提交。 输入提交 sha 时,通常只需要前 5 或 6 个字符:git cherry-pick 6bfabc

【讨论】:

这很容易成为 OPs 问题最优雅、最完整的解决方案。比公认的答案要好得多,因为它假设还原提交位于提交树的头部。该操作还特别要求提供一种不会重写历史的解决方案,因此在接受的答案中提供的硬解决方案是完全错误的。 @Timo 澄清一下,接受的答案包含我使用的解决方案(“reverting the revert”),并在我提出问题的几个小时内发布 - 很明显 3 年前 比这个答案。因此,复选标记。 @JimmidyJoo 我知道我迟到了 3 年,我只是想让人们从谷歌搜索到这里看到更好的答案 @Stephan 是的,但再次澄清一下——这是一个更好的答案,而不是我用来解决问题的答案。我只是在评论为什么复选标记在它所在的位置。所有人的问题:SO 惯例是否规定我应该“保留”我过去的问题并在新答案出现时重新分配复选标记? @JimmidyJoo 我不知道 SO 约定。但作为一个谷歌搜索者,我真的更喜欢看到更好的答案。并且会感谢任何人为维护他们过去的问题所做的努力。【参考方案2】:

如果您还没有推动该更改,git reset --hard HEAD^

否则,还原还原完全没问题。

另一种方法是先git checkout HEAD^^ -- .,然后再git add -A && git commit

【讨论】:

请注意,如果您想在不立即将原始更改应用到 master 分支的情况下取消还原,您可以 (1) 还原原始分支(如果已删除),(2) 单击“还原”如 Adam 所述,在恢复分支上,然后 (3) 在生成的 PR 的标题中单击“编辑”并将目标分支更改为原始分支而不是 master。现在您的原始分支可以重新合并以实现先前还原的更改。 请注意,这将删除工作树和索引中的所有更改。使用 git stash 保存您不想丢失的任何更改。 checkout && commit 方法有什么好处?在一般情况下,git cherry-pickgit revert 似乎是最直接的还原方式。 我认为展示如何:Otherwise, reverting the revert is perfectly fine.,然后解释git checkout HEAD^^ -- . 在做什么会很有帮助。 天哪,不要使用git add -A ...除非您想将每个文件都添加到版本控制中,这很可能不是您想要的。【参考方案3】:

恢复提交就像 git 中的任何其他提交一样。意思是,您可以还原它,如下所示:

git revert 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746

这显然只有在推送更改后才有意义,尤其是当您无法强制推送到目标分支时(这对于您的 ma​​ster 分支来说是个好主意)。如果尚未推送更改,只​​需按照其他帖子进行挑选、还原或简单地删除还原提交。

在我们的团队中,我们有一个规则,即对在主分支中提交的 Revert 提交使用 revert,主要是为了保持历史记录干净,以便您可以查看哪个提交还原了什么:

      7963f4b2a9d   Revert "Revert "OD-9033 parallel reporting configuration"
      "This reverts commit a0e5e86d3b66cf206ae98a9c989f649eeba7965f.
                    ...
     a0e5e86d3b6    Revert "OD-9055 paralel reporting configuration"
     This reverts commit 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746.
                ...
     Merge pull request parallel_reporting_dbs to master* commit 
    '648d7d808bc1bca6dbf72d93bf3da7c65a9bd746'

这样,您可以追溯历史并找出整个故事,甚至那些不了解遗产的人也可以自己解决。然而,如果你 cherry-pickrebase 东西,这些有价值的信息就会丢失(除非你在评论中包含它)。

很明显,如果一个提交多次恢复并重新恢复,那会变得非常混乱。

【讨论】:

【参考方案4】:

还原revert就可以了

例如,

如果abcdef 是您的提交并且ghijkl 是您在恢复提交abcdef 时的提交,则运行:

git revert ghijkl

这将还原还原

【讨论】:

这是正确答案。它还阐明了还原是可以还原的提交本身。【参考方案5】:

我是这样做的: 如果分支 my_branchname 包含在已还原的合并中。我想取消回复my_branchname

我首先从my_branchname 做一个git checkout -b my_new_branchname。 然后我做一个git reset --soft $COMMIT_HASH 其中$COMMIT_HASH 是提交权的提交哈希之前my_branchname 的第一次提交(见git log) 然后我做了一个新的提交git commit -m "Add back reverted changes" 然后我推新分支git push origin new_branchname 然后我对新分支提出了拉取请求。

【讨论】:

当有太多“樱桃采摘”要做时,该走的路。我不明白为什么这个答案的赞成票这么少【参考方案6】:

如果你不喜欢“reverting a revert”的想法(尤其是当这意味着丢失许多提交的历史信息时),你可以随时前往关于 "Reverting a faulty merge" 的 git 文档。

鉴于以下起始情况

 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E   <-- fixed-up topic branch

(W 是您对合并 M 的初始还原;D 和 E 是对您最初损坏的功能分支/提交的修复)

您现在可以简单地重放提交 A 到 E,这样它们都不会“属于”恢复的合并:

$ git checkout E
$ git rebase --no-ff P

您的分支的新副本现在可以再次合并到master

   A'---B'---C'------------D'---E'  <-- recreated topic branch
  /
 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E

【讨论】:

好主意,感谢您的文档链接。我们通常在重新合并之前使用 master 进行 rebase,但是 git 然后似乎认识到 A'、B'、C' 与之前的相同,并且我现在在 W 之后有 D、E(pastebin)。关于如何解决这个问题的建议?【参考方案7】:

或者你可以在git checkout -b &lt;new-branch&gt;git cherry-pick &lt;commit&gt; 之前和git rebase 放弃revert 提交。像以前一样发送拉取请求。

【讨论】:

【参考方案8】:

要取回提交后恢复的未暂存和暂存更改:

git reset HEAD@1

要恢复所有未暂存的删除:

git ls-files -d | xargs git checkout --

【讨论】:

【参考方案9】:

我遇到了一个问题,有人将我的分支恢复为 master,但我需要能够再次合并它,但问题是恢复包含了我的所有提交。 让我们看看我们从 M1 创建功能分支的案例,我们在 M3 中合并我们的功能分支并在 RM3 中恢复它

M1 -> M2 -> M3 -> M4- > RM3 -> M5
 \.         /
  F1->F2 -

如何让F2能够合并到M5?

git checkout master
git checkout -b brach-before-revert
git reset --hard M4
git checkout master
git checkout -b new-feature-branch
git reset --hard M1 
git merge --squash brach-before-revert

【讨论】:

【参考方案10】:

在意外删除我所有文件的最初恐慌之后,我使用以下方法取回了我的数据

git reset HEAD@1         
git fsck --lost-found      
git show 
git revert <sha that deleted the files>

【讨论】:

【参考方案11】:

我看到响应包括命令git reset --hard HEAD,没有任何谨慎。由于选项--hard,您应该小心使用该命令。它会重置您的索引和远程存储库,但大多数情况下,它还会重置您的本地存储库,并且所有未推送到远程但尚未从本地存储库和索引中提交的提交都将丢失。切勿使用该标志--hard,除非您确定还想将所有本地工作从当前提交重置到您选择的哈希值。 如果无论如何你做错了,运行git reflog 来检索你的~hash 然后git reset --hard ~hash 来恢复你的文件。

【讨论】:

【参考方案12】:

在我的情况下,我需要在还原后提交更改,然后才能挑选原始提交而不会失败。

git commit -m "Make changes (original commit)."
git revert <original commit hash>
git commit -m "Revert original commit."
git cherry-pick <original commit hash>

【讨论】:

以上是关于如何“取消还原”已还原的 Git 提交?的主要内容,如果未能解决你的问题,请参考以下文章

如何将多个 Git 提交(已推送)还原到已发布的存储库?

在 Git 中,如何恢复在提交之前还原的暂存文件?

无论如何都可以查看所有以前的 GIT 还原

如何修复还原的 git 提交?

如何 git 还原一个特定文件的更改,而我的提交更改也涉及其他文件? [复制]

如何还原某些用户在 GIT 存储库中所做的更改