使用暂存区域中的未提交文件撤消git reset --hard

eis*_*ati 102 git undo git-add git-reset git-commit

我正在努力恢复我的工作.我愚蠢地做了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
Run Code Online (Sandbox Code Playgroud)

git reset --hard在这种情况下可以撤消吗?

Mar*_*air 164

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

但是,我在测试存储库上尝试了这一点,并且存在一些问题 - --cached应该是--cache,并且我发现它实际上并没有创建.git/lost-found目录.但是,以下步骤对我有用:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)")
Run Code Online (Sandbox Code Playgroud)

这应该输出对象数据库中的任何ref,索引或reflog都无法访问的所有对象.输出看起来像这样:

unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03
Run Code Online (Sandbox Code Playgroud)

......对于每个blob,你可以这样做:

git show 907b308
Run Code Online (Sandbox Code Playgroud)

输出文件的内容.


输出太多了?

更新响应sehe以下的评论:

如果您发现该命令的输出中列出了许多提交和树,您可能希望从输出中删除任何从未引用的提交引用的对象.(通常你可以通过reflog回到这些提交 - 我们只对已添加到索引但永远无法通过提交找到的对象感兴趣.)

首先,保存命令的输出,使用:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > all
Run Code Online (Sandbox Code Playgroud)

现在可以找到那些无法访问的提交的对象名称:

egrep commit all | cut -d ' ' -f 3
Run Code Online (Sandbox Code Playgroud)

因此,您可以找到已添加到索引但未在任何时间提交的树和对象,具有:

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

这极大地减少了你必须考虑的物体数量.


更新: 下面的Philip Oakley提出了另一种减少要考虑的对象数量的方法,即只考虑最近修改过的文件.git/objects.你可以找到这些:

find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort
Run Code Online (Sandbox Code Playgroud)

(我在这里发现了这个find调用.)该列表的结尾可能如下所示:

2011-08-22 11:43:43.0234896770 .git/objects/b2/1700b09c0bc0fc848f67dd751a9e4ea5b4133b
2011-09-13 07:36:37.5868133260 .git/objects/de/629830603289ef159268f443da79968360913a
Run Code Online (Sandbox Code Playgroud)

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

git show b21700b09c0bc0fc848f67dd751a9e4ea5b4133b
git show de629830603289ef159268f443da79968360913a
Run Code Online (Sandbox Code Playgroud)

(请注意,您必须删除/路径末尾的内容才能获取对象名称.)

  • 是不是可以查看晚于上次提交的最新对象的对象时间戳?或者我错过了什么. (3认同)
  • 不要在这里偷任何人的风头。但作为一个说明,因为我刚刚遇到了同样的问题,并认为我失去了所有的工作。**对于那些使用 IDE 的人**,IDE 通常有一个一键恢复解决方案。在 PHPstorm 的情况下,我只需要右键单击目录并选择显示本地历史记录,然后恢复到最后一个有效状态。 (3认同)
  • 伙计,太棒了!刚刚保存了我的@ $$.我学到了一些git science.更好地观察您添加到索引中的内容...... (2认同)
  • 19年后仍然存钱。我真的以为我现在已经搞砸了。设法恢复一切。 (2认同)

小智 58

我只是做了一个git reset --hard并丢失了一个提交.但我知道提交哈希,所以我能够做git cherry-pick COMMIT_HASH来恢复它.

我在丢失提交的几分钟内就这样做了,所以它可能适合你们中的一些人.

  • 可能值得一提的是你可以使用`git reflog`看到那些哈希,例如`git reset --hard` - >`git reflog`(查看HEAD @ {1}哈希),最后是`git cherry-pick COMMIT_HASH` (21认同)
  • 使用`git reset --hard`恢复提交的一行代码(假设你在该命令之后没有做任何其他事情)是`git reset --hard @ {1} (6认同)
  • 谢谢谢谢谢谢你通过这个答案管理恢复工作日 (5认同)
  • 你实际上可以重置"前进".因此,如果您已经重置了多次提交,那么执行另一次'git reset --hard <commit>'应该将整个提交链恢复到该点.(鉴于他们还没有GC) (4认同)
  • 读这个的人,要注意这只适用于单个提交哈希,如果有多个提交,它不会立即解决问题! (2认同)

Boy*_*Boy 13

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

首先,我将所有哈希保存到文件中:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes
Run Code Online (Sandbox Code Playgroud)

接下来我将它们全部放入(删除"无法访问的blob"的东西)并将数据全部放入新文件中...你必须选择你的文件并重新命名它们你需要的......但我只需要一些files..hope这有助于某人......

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
Run Code Online (Sandbox Code Playgroud)

  • 我发现像这样自动化它更容易:`mkdir lost; git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") | grep -Po '\s\S{40}$' | xargs -i echo "git show {} &gt; lost/{}.blob" | sh`。文件将以 `lost/*.blob` 结尾 (2认同)

Dun*_*gor 6

在这种情况下,@ Ajedi32在评论中的解决方案对我有用.

git reset --hard @{1}
Run Code Online (Sandbox Code Playgroud)

注意,所有这些解决方案依赖于那里是没有git的GC,其中一些可能导致一个,所以我拉上你的.git目录的内容尝试任何事情之前,让你有一个快照回去,如果没有按一个不适合你.


ola*_*nge 5

遇到了同样的问题,但没有将更改添加到索引中。所以上面的所有命令都没有给我带来所需的更改。

\n

在上面所有详尽的答案之后,这是一个天真的提示,但它可能会拯救那些像我一样首先没有考虑到这一点的人。

\n

绝望中,我尝试在编辑器(LightTable)中按 CTRL-Z,在每个打开的选项卡 \xe2\x80\x94 中按下一次 CTRL-Z,幸运的是,该选项卡中的文件恢复到了之前的最新状态。git reset --hard.

\n

  • 完全相同的情况,错过了添加索引并进行了硬重置,以上所有解决方案都不起作用。这是一个聪明的举动,感谢我按了 Ctrl+Z 并挽救了我的一天。我的编辑器:SublimeText。从我这边来一个! (2认同)