撤消混帐重置 – 在暂存区域中未提交的文件

我正在努力恢复我的工作。 我愚蠢地做了git reset --hard ,但在此之前我只做了get add . 并没有做git commit 。 请帮忙! 这是我的日志:

 MacBookPro:api user$ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # modified: .gitignore ... MacBookPro:api user$ git reset --hard HEAD is now at ff546fa added new strucuture for api 

是否有可能撤销git reset --hard在这种情况下?

你应该能够恢复你添加到索引的任何文件(例如,在你的情况下,使用git add . ),尽pipe它可能是一个工作。 为了添加一个文件到索引,git把它添加到对象数据库中,这意味着只要垃圾收集还没有发生就可以恢复。 在JakubNarębski的回答中,有一个如何做到这一点的例子:

  • 做git复位后恢复添加的文件 – 硬头^

不过,我在一个testing版本库上试了一下,发现有一些问题 – --cache应该是--cache ,我发现它实际上并没有创build.git/lost-found目录。 但是,下面的步骤为我工作:

 git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") 

这应该输出对象数据库中的所有对象,这些对象不能被任何ref,索引或reflog访问。 输出结果如下所示:

 unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3 unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03 

…对于每一个斑点,你可以这样做:

 git show 907b308 

输出文件的内容。


太多的输出?

更新回应sehe的评论如下:

如果您发现在该命令的输出中列出了许多提交和树,则可能希望从输出中除去未引用提交引用的任何对象。 (通常情况下,无论如何你都可以通过reflog返回这些提交 – 我们只是对添加到索引中的对象感兴趣,但不能通过提交来find)。

首先,保存命令的输出:

 git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > all 

现在,可以通过以下方式find那些不可达提交的对象名称:

 egrep commit all | cut -d ' ' -f 3 

所以你可以find已经添加到索引的树和对象,但是没有在任何时候提交:

 git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") \ $(egrep commit all | cut -d ' ' -f 3) 

这极大地减less了你不得不考虑的对象的数量。


更新:下面的菲利普·奥克利(Philip Oakley)提出了另一种减less需要考虑的对象数量的方法,即考虑最近修改的.git/objects文件。 你可以find这些:

 find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort 

(我发现这里 find调用。)该列表的结尾可能看起来像:

 2011-08-22 11:43:43.0234896770 .git/objects/b2/1700b09c0bc0fc848f67dd751a9e4ea5b4133b 2011-09-13 07:36:37.5868133260 .git/objects/de/629830603289ef159268f443da79968360913a 

在这种情况下,您可以看到这些对象:

 git show b21700b09c0bc0fc848f67dd751a9e4ea5b4133b git show de629830603289ef159268f443da79968360913a 

(请注意,您必须删除path末尾的/以获取对象名称。)

我只是做了一个git重置 – 很难并且失去了一个提交。 但是我知道提交哈希,所以我能够做到git cherry-pick COMMIT_HASH来恢复它。

我在失去提交的几分钟内就做到了这一点,所以对于你们中的一些人来说可能会有效。

感谢Mark Longair,我收回了我的东西!

首先我把所有的哈希值保存到一个文件中:

 git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes 

接下来,我把它们全部(删除“无法访问blob”的东西)列表中,并将数据全部放在新的文件中…你必须select你的文件,并重新命名他们,你需要…但我只需要一些文件..希望这可以帮助别人…

 commits = ["c2520e04839c05505ef17f985a49ffd42809f", "41901be74651829d97f29934f190055ae4e93", "50f078c937f07b508a1a73d3566a822927a57", "51077d43a3ed6333c8a3616412c9b3b0fb6d4", "56e290dc0aaa20e64702357b340d397213cb", "5b731d988cfb24500842ec5df84d3e1950c87", "9c438e09cf759bf84e109a2f0c18520", ... ] from subprocess import call filename = "file" i = 1 for c in commits: f = open(filename + str(i),"wb") call(["git", "show", c],stdout=f) i+=1 

在这个情况下@Ajedi32的解决scheme在评论中为我工作。

 git reset --hard @{1} 

请注意,所有这些解决scheme都依赖于没有git gc,其中一些可能会导致一个,所以我会压缩你的.git目录的内容之前尝试任何东西,以便你有一个快照回去,如果一个不为你工作。

天啊,我拉着头发,直到遇到这个问题和答案。 我相信所问的问题的正确和简洁的答案只有当你把上面的两个注释放在一起时才可用,所以在这里它们都在一个地方:

  1. 正如chilicuil提到的那样,运行'git reflog'来在那里标识你想要返回的提交哈希

  2. 正如akimsko所提到的,除非你只丢失了一个提交,否则你可能不想樱桃select,所以你应该运行'git reset –hard

egit Eclipse用户请注意:我找不到在egit中使用Eclipse执行这些步骤的方法。 closuresEclipse,从terminal窗口运行上面的命令,然后重新打开Eclipse对我来说工作得很好。

进入相同的问题,但没有将更改添加到索引。 所以上面的所有命令都没有把我带回想要的改变。

经过上述详尽的答案,这是一个天真的暗示,但也许会像我一样,保存一个没有想过的人。

在绝望中,我试图在我的编辑器(LightTable)中按CTRL-Z,在每个打开的选项卡中一次 – 这个幸运地恢复了该选项卡中的文件,到git reset --hard之前的最新状态。 HTH。