如何将 Git 存储库还原到先前的提交?

如何从当前状态恢复为特定提交时创建的快照?

如果执行git log ,则得到以下输出:

$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <me@me.com>
Date:   Thu Nov 4 18:59:41 2010 -0400

blah blah blah...

commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <me@me.com>
Date:   Thu Nov 4 05:13:39 2010 -0400

more blah blah blah...

commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <me@me.com>
Date:   Thu Nov 4 00:55:06 2010 -0400

And yet more blah blah...

commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <me@me.com>
Date:   Wed Nov 3 23:56:08 2010 -0400

Yep, more blah blah.

我如何从 11 月 3 日恢复到提交,即 commit 0d1d7fc

答案

这在很大程度上取决于您所说的 “还原”。

暂时切换到其他提交

如果您想暂时回到它,四处闲逛,然后回到自己的位置,那么您所要做的就是检查所需的提交:

# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32

或者,如果您想在此处进行提交,请继续并在其上创建一个新分支:

git checkout -b old-state 0d1d7fc32

要回到原来的位置,只需再次检查您所在的分支即可。 (如果您进行了更改,则一如往常,在切换分支时,您必须对其进行适当的处理。您可以重置以将其丢弃;可以隐藏,签出,隐藏弹出以随身携带它们;可以提交如果您要在那儿分支,请把它们送到那儿。)

硬删除未发布的提交

另一方面,如果您想真正摆脱之后的所有工作,则有两种可能性。一个,如果您尚未发布任何这些提交,只需重置:

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

如果您搞砸了,您已经放弃了本地更改,但是至少可以通过重新设置回到原来的状态。

用新提交撤消已发布的提交

另一方面,如果您发布了作品,则可能不想重置分支,因为这实际上是在重写历史记录。在这种情况下,您确实可以还原提交。使用 Git,还原具有非常特殊的含义:使用反向补丁创建提交以将其取消。这样,您就不会重写任何历史记录。

# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053

# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD

#Similarly, you can revert a range of commits using commit hashes:
git revert a867b4af..0766c053 

# Reverting a merge commit
git revert -m 1 <merge_commit_sha>

# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .

# Then commit. Be sure and write a good message describing what you just did
git commit

git-revert实际上在其描述中涵盖了很多内容。另一个有用的链接是git-scm.com 讨论 git-revert 的部分

如果您决定根本不希望还原,则可以还原该还原(如此处所述),也可以还原到还原之前的状态(请参阅上一节)。

在这种情况下,您可能还会发现此答案很有帮助:
如何将 HEAD 移回先前的位置? (独立头)

这里有许多复杂而危险的答案,但实际上很简单:

git revert --no-commit 0766c053..HEAD
git commit

这会将所有内容从 HEAD 还原回提交哈希,这意味着它将在工作树中重新创建该提交状态, 就好像回溯了所有提交以来。然后,您可以提交当前树,它将创建一个全新的提交,该提交基本上等同于您 “还原” 到的提交。

--no-commit标志可让 git 一次还原所有提交,否则,系统会提示您输入该范围内的每个提交消息,并用不必要的新提交来填充历史记录。)

这是回滚到先前状态安全,简便的方法 。历史记录不会被销毁,因此可以用于已公开的提交。

流氓编码器?

自己工作,只想工作吗?请按照下面的说明进行操作,它们已经为我和许多其他人可靠地工作了多年。

与他人合作? Git 很复杂。在您轻率做某事之前,请阅读此答案下面的评论。

将工作副本还原为最新提交

要恢复为先前的提交,而忽略任何更改:

git reset --hard HEAD

HEAD 是您当前分支中的最后一个提交

将工作副本还原为较早的提交

要恢复到比最近提交更早的提交:

# Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced 

# Moves pointer back to previous HEAD
git reset --soft HEAD@{1}

git commit -m "Revert to 56e05fced"

# Updates working copy to reflect the new commit
git reset --hard

积分会转到类似的堆栈溢出问题, 还原为 Git 中的 SHA 哈希提交?

对我以及其他人而言,最好的选择是 Git reset 选项:

git reset --hard <commidId> && git clean -f

这对我来说是最好的选择!简单,快速,有效!


** 注意:** 如注释中所述,如果您要与拥有旧提交副本的其他人共享分支,则不要这样做

同样从评论中,如果您想要一种不太 “笨拙” 的方法,则可以使用

git clean -i

在回答之前,让我们添加一些背景,解释什么是HEAD

First of all what is HEAD?

HEAD只是对当前分支上当前提交(最新)的引用。在任何给定时间( git worktree )只能有一个HEAD

HEAD的内容存储在.git/HEAD ,它包含当前提交的 40 个字节的 SHA-1。


detached HEAD

如果您不在最新提交上,这意味着HEAD指向历史记录中的先前提交,则称为detached HEAD

在此处输入图片说明

在命令行上,它将看起来像这样 - SHA-1 而不是分支名称,因为HEAD并不指向当前分支的尖端:

在此处输入图片说明


有关如何从分离的 HEAD 中恢复的几种选择:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

这将签出指向所需提交的新分支。该命令将签出给定的提交。

此时,您可以创建一个分支,并从此开始工作:

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

您也可以始终使用refloggit reflog将显示任何更新了HEAD更改,并且签出所需的 reflog 条目会将HEAD设置为此提交。

每次修改 HEAD 时, reflog都会有一个新条目

git reflog
git checkout HEAD@{...}

这将使您回到所需的提交

在此处输入图片说明


git reset HEAD --hard <commit_id>

将您的头 “移动” 回所需的提交。

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

该模式说明了哪个命令可以执行什么操作。如您所见, reset && checkout修改了HEAD

在此处输入图片说明

如果要 “取消提交”,擦除最后的提交消息,然后将修改后的文件放回暂存中,则可以使用以下命令:

git reset --soft HEAD~1
  • --soft表示未提交的文件应保留为工作文件,而--hard则将其丢弃。
  • HEAD~1是最后一次提交。如果要回滚 3 次提交,则可以使用HEAD~3 。如果要回滚到特定的修订版号,也可以使用其 SHA 哈希值来完成。

在您执行错误的操作并且您要撤消上一次提交的情况下,这是一个非常有用的命令。

资料来源: http//nakkaya.com/2009/09/24/git-delete-last-commit/

您可以通过以下两个命令执行此操作:

git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f

它将删除您之前的 Git 提交。

如果要保留更改,也可以使用:

git reset --soft [previous Commit SHA id here]

然后它将保存您的更改。

我尝试了很多方法来还原 Git 中的本地更改,并且如果您只想还原到最新的提交状态,这似乎是最好的方法。

git add . && git checkout master -f

简短的介绍:

  • 它不会像git revert那样创建任何提交。
  • 它不会像git checkout <commithashcode>那样分离您的 HEAD。
  • 自分支中的最后一次提交以来,它将覆盖您的所有本地更改并删除所有添加的文件。
  • 它仅适用于分支名称,因此您只能以这种方式还原到分支中的最新提交。

我发现了一种更方便,更简单的方法来实现上述结果:

git add . && git reset --hard HEAD

HEAD 指向您当前分支的最新提交。

它与 boulder_ruby 建议的代码相同,但是我添加了git add .git reset --hard HEAD之前,擦除自上一次提交以来创建的所有新文件,因为这是大多数人在还原为最新提交时所希望的。

好的,回到上一个 git 提交很容易...

还原但不保留更改:

git reset --hard <commit>

恢复并保留更改:

git reset --soft <commit>

说明:使用 git reset,您可以将其重置为特定状态,如上所示,通常将其与提交哈希一起使用。

但是,您看到的区别是使用了两个标志--soft--hard ,默认情况下git reset使用--soft标志,但这是一个始终使用该标志的好习惯,我将解释每个标志:


- 柔软的

所说明的默认标志(无需提供该标志)不会更改工作树,而是会添加所有准备提交的更改文件,因此您将返回到提交状态,即对文件的更改将被撤消。


- 硬

小心此标志,它将重置工作树,并且对跟踪文件的所有更改都将消失!


我还创建了下面的图像,在使用 git 的现实生活中可能会发生这种情况:

git重置为提交

假设您在谈论 master 以及该分支上的内容(也就是说,这可能是您关心的任何工作分支):

# Reset local master branch to November 3rd commit ID
git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50

# Reset remote master branch to November 3rd commit ID
git push -f origin 0d1d7fc32e5a947fbd92ee598033d85bfc445a50:master

我在博客文章中找到了答案(现已不存在)

请注意,这是 “重置并强制更改到遥控器”,因此,如果您团队中的其他人已经被 git pull 了,则会给他们带来麻烦。您正在破坏变更历史记录,这是人们首先使用 git 的重要原因。

最好使用还原(请参阅其他答案)而不是重置。如果您是一个单人团队,那么这可能并不重要。