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

Posted

技术标签:

【中文标题】如何将多个 Git 提交(已推送)还原到已发布的存储库?【英文标题】:How can I revert multiple Git commits (already pushed) to a published repository? 【发布时间】:2012-06-02 13:26:11 【问题描述】:

git 新手,已经搞砸了。

我已提交并将一些更改推送到远程开发机器。 我需要恢复旧版本,但要保持“糟糕的进展”,以继续在单独的分支上工作;

我想这样做:

    创建一个本地分支,命名为:“tested-thing” 将本地存储库恢复到它工作的状态(希望有意义的提交会有所帮助)

    推送到远程

    完成测试对象的测试

    合并“测试的东西”进入开发 推送到远程

在第 3 步和第 5 步之间,其他开发人员可能会提交并推送,我担心这可能会导致“合并悲剧” - 无论如何,这可能是正确的方法吗?

更新:

这里的主要问题在于 2)

这里,关于主题:“将工作分解为主题分支” http://learn.github.com/p/undoing.html

他们建议:

    $ git 分支测试 $ git reset --hard a6b4c974

这样做,其他开发人员仍然可以:

$ git commit(在开发分支上)

我可以结帐以进行测试并解决它直到合并时间。

尽管您有所有选择,但这感觉是一种很好的方法。 但是,没有说明我们推送后是否可以这样做?

请注意以下几点:自从我进行了这些更改并将所有事情都搞砸了,到目前为止没有其他人在存储库上工作。所以,如果我恢复工作目录,没人会注意到。

【问题讨论】:

作为评论,您无法恢复合并提交,请检查这个有用的答案 ***.com/a/1470452/6891549 和 git checkout -f A -- 。解决方案 【参考方案1】:

问题

您可以使用多种工作流程。要点是不要在已发布的分支中破坏历史记录,除非您已与可能使用该分支并愿意对每个人的克隆进行手术的每个人进行了沟通。如果可以避免,最好不要这样做。

已发布分支的解决方案

您概述的步骤有优点。如果您需要 dev 分支立即稳定,请这样做。您有许多Debugging with Git 的工具可以帮助您找到正确的分支点,然后您可以恢复上次稳定提交和 HEAD 之间的所有提交。

要么以相反的顺序一次恢复提交一个,要么使用<first_bad_commit>..<last_bad_commit> 范围。哈希是指定提交范围的最简单方法,但还有其他表示法。例如,如果您推送了 5 个错误提交,您可以使用以下命令恢复它们:

# Revert a series using ancestor notation.
git revert --no-edit dev~5..dev

# Revert a series using commit hashes.
git revert --no-edit ffffffff..12345678

这将按顺序将反向补丁应用到您的工作目录,向您的已知良好提交反向工作。使用 --no-edit 标志,在应用每个反向补丁后,对工作目录的更改将自动提交。

有关更多选项,请参阅 man 1 git-revert,有关指定要恢复的提交的不同方式,请参阅 man 7 gitrevisions

或者,您可以分支 HEAD,按照需要的方式修复问题,然后重新合并。在此期间,您的构建将被破坏,但在某些情况下这可能是有意义的。

危险地带

当然,如果您绝对确定自从您的错误推送以来没有人从存储库中拉出,并且如果远程是一个裸存储库,那么您可以进行非快进提交。

git reset --hard <last_good_commit>
git push --force

这将使您的系统和上游主机上的 reflog 保持完整,但您的错误提交将从可直接访问的历史记录中消失,并且不会在拉取时传播。您的旧更改将一直保留,直到存储库被修剪,但只有 Git 忍者才能看到或恢复您错误地提交。

【讨论】:

如果人们已经克隆了错误推送,并且收到了通知 - 他们应该怎么做才能拥有与远程相同的分支?他们是否必须这样做git reset --hard &lt;last_good_commit&gt; 如果你使用提交标签,不是&lt;first_bad_commit&gt;..&lt;last_bad_commit&gt;,而是&lt;last_good_commit&gt;..&lt;last_bad_commit&gt;【参考方案2】:

如果您已经将内容推送到远程服务器(并且您有其他开发人员在同一个远程分支上工作),那么要记住的重要一点是您不想重写历史记录

不要使用 git reset --hard

您需要还原更改,否则任何在其历史记录中已删除提交的签出都将在下次推送时将它们添加回远程存储库;并且任何其他结帐将在此后的下一次拉动时将它们拉入。

如果您还没有将更改推送到遥控器,您可以使用

git reset --hard <hash>

如果您推送了更改,但确定没有人拉取更改,您可以使用

git reset --hard
git push -f

如果您推送了更改,并且有人将其拉入结帐,您仍然可以这样做,但其他团队成员/结帐需要协作:

(you) git reset --hard <hash>
(you) git push -f

(them) git fetch
(them) git reset --hard origin/branch

但一般来说,这会变成一团糟。所以,还原:

要移除的提交是最新的

这可能是最常见的情况,你做了一些事情——你把它们推出来,然后意识到它们不应该存在。

首先,您需要确定要返回的提交,您可以这样做:

git log

只需在更改之前查找提交,并记下提交哈希。您可以使用-n 标志将日志限制为最近的提交:git log -n 5

然后将您的分支重置为您希望其他开发人员看到的状态:

git revert  <hash of first borked commit>..HEAD

最后一步是创建您自己的本地分支以重新应用您恢复的更改:

git branch my-new-branch
git checkout my-new-branch
git revert <hash of each revert commit> .

继续在my-new-branch 工作直到完成,然后将其合并到您的主开发分支中。

要移除的提交与其他提交混合在一起

如果您要还原的提交不是全部在一起,则单独还原它们可能是最简单的。再次使用 git log 找到您要删除的提交,然后:

git revert <hash>
git revert <another hash>
..

然后,再次创建您的分支以继续您的工作:

git branch my-new-branch
git checkout my-new-branch
git revert <hash of each revert commit> .

然后,当你完成后,再次破解并合并。

您最终应该会在my-new-branch 上获得如下所示的提交历史记录

2012-05-28 10:11 AD7six             o [my-new-branch] Revert "Revert "another mistake""
2012-05-28 10:11 AD7six             o Revert "Revert "committing a mistake""
2012-05-28 10:09 AD7six             o [master] Revert "committing a mistake"
2012-05-28 10:09 AD7six             o Revert "another mistake"
2012-05-28 10:08 AD7six             o another mistake
2012-05-28 10:08 AD7six             o committing a mistake
2012-05-28 10:05 Bob                I XYZ nearly works

Better way®

特别是既然您已经意识到多个开发人员在同一个分支中工作的危险,请考虑在您的工作中始终使用功能分支。这意味着在分支中工作直到完成某些事情,然后才将其合并到您的主分支。还可以考虑使用 git-flow 等工具以一致的方式自动创建分支。

【讨论】:

+1 for git reset 没有 --hard 标志,但我认为大多数人不会理解您正在重置工作目录和 HEAD,这将导致 ! [rejected] master -&gt; master (non-fast-forward)在推。此外,如果大量文件已被更改,即使您强制提交,它也会产生一个非常全面的补丁。 @AD7Six:感谢 Better Way 注册商标插件。实际上,分支是如此便宜,以至于我在做了这个愚蠢的举动之后就想到了。通过知道除了我之外没有其他人接触存储库,因为我已经完成了所有这些混乱,可能有助于在我的问题更新中使用该方法? @CodeGnome 你是对的,我已经很久没有找到自己的位置了:] @MEM 是否没有其他人更新 repo 无关紧要 - 自从提交“错误”以来,如果有人更新了他们的结帐,这很重要。因为如果他们有,当他们拉出时,他们的结帐仍将包含您强行删除的提交,并与任何新更改合并。如果你在你的特性分支中使用git reset --hard,当你合并它时,你很可能会因为你删除的提交被重新应用而发生冲突——基本上,不,这样做可能不是一个好主意。【参考方案3】:
git revert HEAD -m 1

在上面的代码行中。 "最后一个参数代表"

1 - 恢复一个提交。 2 - 恢复上次提交。 n - 恢复最后 n 提交

git reset --hard siriwjdd

【讨论】:

抛出错误:提交 a17dc423957324b2b537c1caa9d9476c9b443f48 没有父 n,其中 n 是最后一个参数 如果 HEAD 是合并提交,则代码有效。但是,对此的描述是不正确的。 -m 实际上指定了哪个父提交来自 mainline 分支。 -m 2 会将您恢复到功能分支顶端的版本,并丢弃所有主线更改,因为您的功能分支与主线分歧。

以上是关于如何将多个 Git 提交(已推送)还原到已发布的存储库?的主要内容,如果未能解决你的问题,请参考以下文章

Git学习

Git学习

Git学习

如何在 git 中编辑不正确的提交消息(我已推送)?

为啥我不能在 github 中推送还原的提交?

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