如何撤消git重置--hard HEAD~1?

是否可以撤消以下命令引起的更改?如果是,如何撤消?

git reset --hard HEAD~1
708041 次浏览

您要做的是指定要还原的提交的sha1。您可以通过检查reflg(git reflog)然后执行以下操作来获取sha1

git reset --hard <sha1 of desired commit>

但是不要等太久……几周后,git最终会将该提交视为未引用并删除所有blob。

Pat Notz是正确的。只要它在几天内就可以取回提交。git只有垃圾收集大约一个月左右,除非你明确告诉它删除更新的blob。

$ git initInitialized empty Git repository in .git/
$ echo "testing reset" > file1$ git add file1$ git commit -m 'added file1'Created initial commit 1a75c1d: added file11 files changed, 1 insertions(+), 0 deletions(-)create mode 100644 file1
$ echo "added new file" > file2$ git add file2$ git commit -m 'added file2'Created commit f6e5064: added file21 files changed, 1 insertions(+), 0 deletions(-)create mode 100644 file2
$ git reset --hard HEAD^HEAD is now at 1a75c1d... added file1
$ cat file2cat: file2: No such file or directory
$ git reflog1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEADf6e5064... HEAD@{1}: commit: added file2
$ git reset --hard f6e5064HEAD is now at f6e5064... added file2
$ cat file2added new file

您可以在示例中看到file2由于硬重置而被删除,但在我通过reflg重置时被放回原位。

如果Git还没有垃圾回收,则可以恢复它。

使用fsck获得悬空提交的概述:

$ git fsck --lost-founddangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

使用rebase恢复悬空提交:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

如果您还没有对存储库进行垃圾回收(例如,使用git repack -dgit gc,但请注意,垃圾回收机制也可以自动发生),那么您的提交仍然存在-它不再可以通过HEAD访问。

您可以尝试通过查看git fsck --lost-found的输出来找到您的提交。

较新版本的Git有一个叫做“reFlog”的东西,它记录了对引用所做的所有更改(而不是对存储库内容所做的更改)。因此,例如,每次您切换HEAD时(即每次您执行git checkout切换分支时)都会被记录下来。当然,您的git reset也操纵了HEAD,因此它也会被记录下来。您可以通过类似于访问存储库旧状态的方式访问引用的旧状态,通过使用@符号而不是~符号,如git reset HEAD@{1}

我花了一段时间才明白HEAD@{1}和HEAD~1之间的区别,所以这里有一点解释:

git initgit commit --allow-empty -mOnegit commit --allow-empty -mTwogit checkout -b anotherbranchgit commit --allow-empty -mThreegit checkout master # This changes the HEAD, but not the repository contentsgit show HEAD~1 # => Onegit show HEAD@{1} # => Threegit reflog

因此,HEAD~1表示“在HEAD当前指向的提交之前转到提交”,而HEAD@{1}表示“在HEAD当前指向的位置之前转到HEAD指向的提交”。

这将很容易让你找到丢失的提交并恢复它。

答案隐藏在上面的详细回复中,你可以简单地做:

$> git reset --hard HEAD@{1}

(参见git reflg显示的输出)

如果你真的很幸运,像我一样,你可以回到你的文本编辑器,点击“撤消”。

我知道这不是一个正确的答案,但它节省了我半天的工作,所以希望它能为别人做同样的事情!

IRL案例示例:

$ git fsck --lost-found

Checking object directories: 100% (256/256), done.Checking objects: 100% (3/3), done.dangling blob 025cab9725ccc00fbd7202da543f556c146cb119dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1bdangling blob 85f4d1a289e094012819d9732f017c7805ee85b4dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98dangling blob 9183b84bbd292dcc238ca546dab896e073432933dangling blob 1448ee51d0ea16f259371b32a557b60f908d15eedangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbddangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66dangling blob 333e76340b59a944456b4befd0e007c2e23ab37bdangling blob b87163c8def315d40721e592f15c2192a33816bbdangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133dangling blob 4a71f9ff8262701171d42559a283c751fea6a201dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2dangling blob 724d23914b48443b19eada79c3eb1813c3c67feddangling blob 749ffc9a412e7584245af5106e78167b9480a27bdangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a    <- it's this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5aAuthor: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>Date:   Wed Aug 15 08:41:30 2012 +0200
*MY COMMIT MESSAGE IS DISPLAYED HERE*
diff --git a/Some.file b/Some.filenew file mode 100644index 0000000..15baeba--- /dev/null+++ b/Some.file*THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it...Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.

我知道这是一个古老的线程……但由于许多人都在寻找在Git中撤消东西的方法,我仍然认为在这里继续提供提示可能是一个好主意。

当您在git gui中执行“git add”或从左上角移动任何内容时,文件的内容存储在blob中,并且可以从该blob中恢复文件内容。

因此,即使未提交但必须添加,也可以恢复文件。

git initecho hello >> test.txtgit add test.txt

现在创建了blob,但它被索引引用,因此在我们重置之前,它不会与git fsck一起列出。所以我们重置…

git reset --hardgit fsck

你会得到一个悬挂的blob ce013625030ba8dba906f756967f9e9ca394464a

git show ce01362

会给你文件内容“你好”回来

为了找到未引用的提交,我在某个地方找到了一个提示。

gitk --all $(git log -g --pretty=format:%h)

我把它作为git gui中的一个工具,它非常方便。

制作了一个小脚本,使其更容易找到正在寻找的提交:

git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'

是的,它可以用awk或类似的东西做得更漂亮,但它很简单,我只是需要它。可能会节省别人30秒。

在大多数情况下,是的。

根据您运行命令时存储库所处的状态,git reset --hard的效果可以从微不足道到撤消,再到基本上不可能。

下面我列出了一系列不同的可能情况,以及如何从中恢复。

我的所有更改都已提交,但现在提交已消失!

这种情况通常发生在您使用参数运行git reset时,如git reset --hard HEAD~。别担心,这很容易恢复!

如果你刚刚运行了git reset并且从那以后没有做任何其他事情,你可以回到你使用这个单行代码的地方:

git reset --hard @{1}

这将重置当前分支在上次修改之前的任何状态(在您的情况下,对分支的最新修改将是您试图撤消的硬重置)。

但是,如果您在重置后对您的分支进行了其他修改,则上面的一行程序将不起作用。相反,您应该运行#0#1以查看最近对您的分支所做的所有更改(包括重置)的列表。该列表将如下所示:

7c169bd master@{0}: reset: moving to HEAD~3ae5027 master@{1}: commit: Changed file27c169bd master@{2}: commit: Some change5eb37ca master@{3}: commit (initial): Initial commit

在此列表中找到要“撤消”的操作。在上面的示例中,它将是第一行,上面写着“重置:移动到HEAD~"。然后复制该操作的提交之前(下面)的表示。在我们的例子中,那将是master@{1}(或3ae5027,它们都代表相同的提交),然后运行git reset --hard <commit>将您当前的分支重置回该提交。

我用git add暂存了我的更改,但从未提交。现在我的更改消失了!

git确实有您添加的文件的副本,但由于这些副本从未绑定到任何特定的提交,您无法一次还原所有更改。相反,您必须在git的数据库中找到各个文件并手动还原它们。您可以使用#0做到这一点。

有关详细信息,请参阅撤消git重置--hard暂存区中未提交的文件

我对工作目录中的文件进行了更改,我从未使用git add暂存,也从未提交。现在我的更改消失了!

啊哦。我不想告诉你这个,但你可能不走运。git不会存储你没有添加或提交的更改,根据留档#0

--硬

重置索引和工作树。自#0以来对工作树中跟踪文件的任何更改都将被丢弃。

您可以使用某种磁盘恢复实用程序或专业的数据恢复服务来恢复您的更改,但在这一点上,这可能比它的价值更麻烦。

据我所知,--hard将丢弃未提交的更改。因为git不会跟踪这些更改。但是你可以撤消discarded commit

$ git reflog

将列出:

b0d059c HEAD@{0}: reset: moving to HEAD~14bac331 HEAD@{1}: commit: added level introduction........

其中4bac331discarded commit

现在只需将头部移动到该提交:

$ git reset --hard 4bac331

我刚刚在错误的项目上做了一个艰难的重置。救了我一命的是Eclipse的本地历史。据说IntelliJ Idea也有一个,你的编辑也是,值得检查:

  1. 本地历史的Eclipse帮助主题
  2. http://wiki.eclipse.org/FAQ_Where_is_the_workspace_local_history_stored%3F

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

First of all what is HEAD?

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

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


detached HEAD

如果您不在最新的提交上-这意味着HEAD指向历史上的先前提交,则称为#1

在此处输入图片描述

在命令行上,它看起来像this-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 commitgit checkout -b <branch name>

git reflog

您也可以随时使用reflog
git reflog 将显示更新了HEAD的任何更改,并签出所需的reflg条目将HEAD设置回此提交。

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

git refloggit 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 stashgit reset --hard 0d1d7fc32git 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 revert <sha-1>

"撤消"给定的提交或提交范围。
重置命令将“撤消”在给定提交中所做的任何更改。
将提交带有撤消补丁的新提交,而原始提交也将保留在历史记录中。

# add new commit with the undo of the original one.# the <sha-1> can be any commit(s) or commit rangegit revert <sha-1>

这个模式说明了哪个命令做什么。
如你所见,reset && checkout修改HEAD

在此处输入图片描述

git reflog

  • 在列表中找到您的提交sha,然后将其复制并粘贴到以下命令中:

git cherry-pick <the sha>

如果您使用的是JetBrains IDE(任何基于IntelliJ的东西),您甚至可以通过其“本地历史记录”功能恢复未提交的更改。

右键单击文件树中的顶级目录,在上下文菜单中找到“本地历史记录”,然后选择“显示历史记录”。这将打开一个可以找到您最近编辑的视图,一旦找到要返回的版本,右键单击它并单击“恢复”。

我的问题几乎相似。在我输入git reset --hard之前,我有未提交的文件。

谢天谢地。我设法跳过了所有这些资源。在我注意到我可以撤消(ctrl-z for windows/linuxcmd-shift-z for mac)之后。😊我只想将此添加到上面的所有答案中。

注意。无法撤消未打开的文件。

你救了我的命:https://medium.com/@CarrieGuss/how-to-recover-from-a-git-hard-reset-b830b5e3f60c

基本上你需要运行:

for blob in $(git fsck --lost-found | awk ‘$2 == “blob” { print $3 }’); do git cat-file -p $blob > $blob.txt; done

然后手动经历痛苦,将文件重新组织到正确的结构。

注意:永远不要使用git reset --hard如果你不完全100%理解它是如何工作的,最好不要使用它。

git reflog并返回到最后一个HEAD6a56624(HEAD->master)HEAD@{0}:重置:移动到HEAD~31a9bf73 HEAD@{1}:提交:在模型中添加更改生成二进制

git重置--hard-您可以使用它来恢复一个页面,然后您可以再次隐藏或从原点提取所有内容