通过 "git reset --hard" 恢复丢失的未提交更改

673

如何从git reset --hard HEAD中恢复未提交的更改到工作目录?


5
不涉及“撤销git reset --hard HEAD~1”的问题,因为这里原帖作者试图恢复未提交的更改。 - user456814
23个回答

769
对于之前已经提交的更改(来自这个SO):
$ git reflog show

4b6cf8e (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: reset: moving to origin/master
295f07d HEAD@{1}: pull: Merge made by the 'recursive' strategy.
7c49ec7 HEAD@{2}: commit: restore dependencies to the User model
fa57f59 HEAD@{3}: commit: restore dependencies to the Profile model
3431936 HEAD@{4}: commit (amend): restore admin
033f5c0 HEAD@{5}: commit: restore admin
ecd2c1d HEAD@{6}: commit: re-enable settings app

# assuming you want to get back to 7c49ec7 (restore dependencies to the User model)

$ git reset HEAD@{2}

67
补充一下这个答案,这会帮助那些通过硬重置丢失了已提交更改的人。 - murki
13
很好 - 但在我的情况下,文件完全消失了。使用 git checkout HEAD@{19} 命令可以让我以分离状态检出已丢失的文件,然后使用 git checkout -b 新分支名 命令将它们以“附加”的状态添加回仓库。 - NightOwl888
3
在Git中,当你在任何不是分支的东西上使用checkout命令时,它会进入一个特殊的“游离头”模式。这意味着你实际上没有指向一个分支,但你可以查看实体状态(在这种情况下是reflog条目)中检查的内容。从那个状态开始,你可以通过使用git checkout -b 新分支名称将其变成一个“真正”的分支,以便再次返回。《Pragmatic Version Control Using Git》这本书用简单易懂的语言很好地解释了Git。 - NightOwl888
5
Ken和@NightOwl888你们刚刚帮我节省了三天的时间!祝你们幸福和繁荣! - Daniiar Abdiev
6
这个答案似乎是不正确的。OP问的是是否有可能恢复未提交的更改。这只能恢复孤立的已提交更改。 - Catskul
显示剩余7条评论

624

通常情况下,您无法恢复未提交的更改。

先前暂存(git add)的更改应该可以从索引对象中恢复,因此如果您这样做了,请使用git fsck --lost-found定位与其相关的对象。(这会将对象写入.git/lost-found/目录; 然后你可以使用git show <filename>查看每个文件的内容。)

如果没有,那么答案是:查看您的备份。也许您的编辑器/IDE在/tmp或C:\TEMP之类的位置存储临时副本。 [1]

git reset HEAD@{1}
这将恢复到先前的 HEAD。
[1] 例如,vim 可以选择性地存储持久化撤消,eclipse IDE 存储本地历史记录;这些功能可能会拯救你。

22
Eclipse 的本地历史记录,此外,由于某些更改早于6天,我也备份了 Eclipse 本地历史记录的 Time Machine!由于某种原因,由 Git 管理的文件夹的 Time Machine 备份并未包含我之前的更改。 - christianbrodbeck
16
IDE(IntelliJ)将更改存储在本地,这拯救了我们。感谢您的提示! - progonkpa
3
在powershell终端中,git reset HEAD@{1}导致了一个错误,结果是error: unknown switch ``e'。解决方法是用单引号转义花括号,像这样:git reset 'HEAD@{1}',因为花括号对于powershell有不同的含义。 - Batu
11
在Eclipse(或者在我的情况下是Intellij)中,了解本地历史记录可以帮助恢复误操作而丢失的文件。有关Intellij的说明请参见此文档:https://blog.jetbrains.com/idea/2008/01/using-local-history-to-restore-deleted-files/。 - Richard
2
用于查看已添加到暂存区但从未提交的任何文件的Shell代码片段:for fname in $(ls .git/lost-found/other/); do echo $fname:; cat .git/lost-found/other/$fname; read -n 1 -p "Continue?"; echo; done - ncoghlan
显示剩余12条评论

366
今天我在有未提交更改的情况下,不小心运行了git reset --hard命令。为了恢复数据,我使用了git fsck --lost-found命令,该命令将所有未引用的blob写入到<path to repo>/.git/lost-found/目录下。由于文件没有被提交,所以我在<path to repo>/.git/lost-found/目录下的other目录中找到了它们。从这里,我可以使用git show <filename>命令查看未提交的文件,复制出blob并将其重命名。
注意:只有当你把需要保存的文件添加到索引(使用git add .命令)时,此方法才有效。如果文件未在索引中,那么它们将无法恢复。

4
我只得到了在“lost-found”中提交引用的文件。但我可以使用“git show”命令获取文件内容。 - Mitar
17
只是为了节省时间 #!/bin/bash cd PATH_TO_PROJECT/.git/lost-found/other FILES=* COUNTER = 0 for f in $FILES do echo "正在处理 $f 文件..." git show $f > "PATH_TO_RECOVERY_DIRECTORY/$COUNTER.m" let COUNTER=COUNTER+1 done - rwolst

319

不只是未提交的更改,但您可以在Git中执行硬重置后恢复之前提交的更改。

用法:

git reflog

获取您提交的标识符。 然后使用:

git reset --hard <commit-id-retrieved-using-reflog>

这个技巧曾经救过我几次大难。

你可以在这里找到reflog的文档。


19
到目前为止,我认为这是最好和最简洁的答案。使用另一个 git reset --hard 来恢复 git reset --hard 可能看起来反直觉,但如果你不使用 --hard 选项,你的工作区将留下条目,这些条目会有效地撤消你刚刚恢复的工作。 - Ryan H.
14
这个回答是不正确的。这种方法只能恢复之前已经提交(committed)的更改,无法恢复未提交(uncommitted)的更改(而这正是这个问题所涉及的)。 - Alderath
1
这就是为什么被接受的回答以“通常情况下无法恢复未提交的更改”开头的原因。虽然我认为这可能仍然对某些人有用。 :) - Gabe
也许在回答中指明这只恢复已提交的更改! - Karolina Hagegård
1
这对那些不小心提交并进行了硬重置的人来说非常有用。非常感谢,你节省了我过去三个小时的 C++ 调试工作。 - Vimuth

83

当我在处理本地项目时,我想将其移动到GitHub并创建一个新的存储库。当我尝试使用.gitignore将所有这些文件添加到新的存储库中时,我不小心添加了一个错误的文件,然后尝试清除它。

我运行了git reset --hard origin/master

然后我的所有本地文件都被删除了,因为该存储库是空的。我以为一切都消失了。

这对我有用:

git reflog show
git reset HEAD@{1} 
git push 

64
如果你使用类似IntelliJ这样的工具:
在上下文菜单中,选择“本地历史”,然后在子菜单中点击“显示历史”:
项目或文件夹的本地历史视图将显示你在过去几天内所做的所有操作。在对话框的下部的“操作”列中,选择你想要回滚的操作。这样做,对话框的上部将显示已更改文件的树形视图。如果你只想恢复已删除的文件,而不考虑此后所做的其他更改,你可以在树形视图中选择“Lost.txt”文件,然后点击“还原”按钮。

http://blog.jetbrains.com/idea/2008/01/using-local-history-to-restore-deleted-files/


7
这绝对是适用于IntelliJ用户的最佳答案!非常感谢,这很完美地解决了我的问题。我尝试了其他所有解决方案,但都没有很好地工作。git reflog不起作用,因为我没有提交更改。git fsck --lost-found可以恢复已暂存的文件,但并没有暂存所有文件。IntelliJ的本地历史记录完美地恢复了我的未保存文件,我非常感激这个功能。 - Denes Papp

48

我刚刚执行了git reset --hard命令,导致所有未提交的更改都丢失了。幸运的是,我使用的是编辑器(IntelliJ),并且我能够从本地历史记录中恢复这些更改。Eclipse应该也能够让你做同样的事情。


2
在Visual Studio Code中,同样的事情也适用于我。时间轴功能在这种情况下非常有帮助。 - Vlad Moisuc

23

根据定义,git reset --hard会丢弃未提交的更改,Git没有任何方法可以恢复它们(您的备份系统可能有所帮助,但不包括在Git内)。

实际上,很少有情况下git reset --hard是一个好主意。在大多数情况下,有一个更安全的命令可以完成同样的事情:

  • 如果您想要放弃未提交的更改,请使用git stash。它将保留这些更改的备份,在运行git gc后一段时间后过期。如果您99.9%确定您永远不需要这些更改,则git stash仍然是您0.1%的好朋友。如果您100%确定,则git stash仍然是您的好朋友,因为这100%具有测量误差 ;-).

  • 如果您想要移动HEAD和当前分支的最新历史记录,则git reset --keep是您的好朋友。它将执行与git reset --hard相同的操作,但不会丢弃本地更改。

  • 如果您既想要放弃未提交的更改,又想要移动HEAD和当前分支的最新历史记录,则git stash && git reset --keep是您的好朋友。

教导您的手指不要使用git reset --hard,这将在某一天得到回报。


如果一个人执行 git stash && git reset --hard,那么这将清除任何已经存储的内容,对吗? - jxramos
1
不,git reset --hard 不会丢弃暂存区。git stashgit reset --hard 的替代品,因为它可以从您的工作区中移除未提交的更改,但是它会将这些更改安全保留,而不是永久地丢弃它们。 - Matthieu Moy
或者在你进行硬重置之前提交你的更改,它们仍将保留在你的本地存储库中。 - ThaJay

15

如果我丢了一些更改,这就是我通常做的事情。

git reflog
git checkout <commit id> // now you are in where you want but you cannot push from detached branch to master
manually copy and paste changes from detached branch to master or working branch
git reset --hard HEAD // if needed
git add ... > git commit ... > git push ...

要将指针移回到以前的提交,但保留最新提交中迄今为止所做的更改,请使用git reset --soft dadada命令。


14

IntelliJ具有可通过历史命令访问的临时文件夹:

  1. 在导航窗格中选择要还原文件的文件夹
  2. 双击Shift键(shift-shift)
  3. 在弹出的输入框中键入“本地历史记录”并按Enter键
  4. 选择“显示历史记录”
  5. 现在,您可以还原所需版本。

4
我欠你一个人情。 - MrD
1
你救了我的命 <3 - CodeTalker

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