git - 恢复已添加到索引但随后被 git reset 删除的文件

标签 git git-commit git-reset git-add git-reflog

我在索引中添加了一些文件,但随后我错误地使用 git reset --hard 删除了它们。我如何恢复它们? 事情是这样的:

  1. 我使用 git add 添加了所有文件。
  2. 然后我 promise
  3. 当我查看状态时,还有一些文件没有包含在添加的提交中,这很奇怪
  4. 我再次添加了未跟踪的文件,这次成功了
  5. 但我希望所有内容都在一次提交中,所以我查找了如何取消暂存我刚刚提交的内容
  6. 我使用了 git reset --hard HEAD^ — 显然是个坏主意,所有文件都被删除了
  7. 然后我使用 git reflog 找到我离开的地方
  8. 然后我使用 git reflog ______ 回到我上次提交。
  9. 然后我使用 git reset HEAD 取消暂存提交(我本来应该做的)但是我在提交之后添加的文件(见上文)仍然没有了。

如何取回这些文件?

最佳答案

首先,对您的 Git 存储库进行完整备份!

当你git add一个文件,git 会从这个文件的内容中创建一个 blob,并将它添加到它的对象数据库 ( .git/objects/??/*)。

让我们一一查看您的命令:

I added all files using git add .

$ git add .

这会将当前目录及其子目录中包含的所有文件添加到 Git 的对象数据库中。与 .gitignore 中的模式匹配的未跟踪文件不会添加文件。树文件也将被写入。请看我回答的结尾。

I then committed

$ git commit -m'added all files'

这会将一个新的提交对象写入对象数据库。此提交将引用单个树。树引用 blob(文件)和其他树(子目录)。

When I checked the status, there were still files that weren't included in the commit from the add, which was strange

$ git status

我能想到发生这种情况的两种情况:某些东西修改了您的文件或在您的背后添加了新文件。

I added the untracked files again and it worked this time

$ git add .

我假设您使用了相同的 add再次命令,如步骤 1 所示。

But I wanted everything to be in 1 single commit so I looked up how to unstage what I just committed

我会在这个答案的最后告诉你一个更好的方法,它不需要用户发出有潜在危险的 reset

I used git reset --hard HEAD^ — bad idea obviously, all files were deleted

$ git reset --hard HEAD^

此命令会将您当前的工作树和索引设置为恰好在提交 HEAD^ 处(倒数第二个提交)。换句话说,它将丢弃任何本地未提交的更改并将分支指针移回一次提交。它不会触及未跟踪的文件。

so then I used git reflog to find where I left off

$ git reflog

这显示最近 checkout 的最后一次提交(与 git reflog HEAD 相同)。如果您指定分支名称,它将显示该分支最近指向的最后一次提交。

then I used git reflog __ to go back to my last commit.

不确定这个。 git reflog是(大部分)只读命令,不能用于“返回”提交。您只能使用它来查找指向的分支(或 HEAD)的提交。

then I used git reset HEAD to unstage the commit (what I should have originally done) but the files I added (see above) after the commit were still gone. $ git reset HEAD

这不会取消暂存此提交,但会取消暂存索引中所有已暂存(但未提交)的更改。最初(第一步),你想说 git reset HEAD^ (或 git reset --mixed HEAD^ )——这将使您的工作树保持不变,但设置索引以匹配由 HEAD^ 命名的提交指向的树.


现在,要取回您的文件,您必须使用 git fsck --full --unreachable --no-reflog .它将扫描 Git 对象数据库中的所有对象并执行可达性分析。你想找blob对象。还应该有一个 tree对象,描述第二次 git add . 之后的状态

git cat-file -p <object hash>将打印文件内容,因此您可以验证您是否拥有正确的对象。对于 blob,可以使用 IO 重定向将内容写入正确的文件名。对于树,您必须使用 git 命令 ( git read-tree )。如果只有几个文件,最好将它们直接写入文件。


这里有几点说明:

如果你想添加文件到最后一次提交(或编辑它的提交消息),你可以简单地使用 git commit --amend .它基本上是 git reset --soft HEAD^ && git commit -c HEAD@{1} 的包装器.

此外,使用 git add . 几乎不是一个好主意。 .通常,您只想在第一次创建新存储库时使用它。 更好的选择是 git add -u , git commit -a ,这将暂存对跟踪文件的所有更改。要跟踪新文件,最好明确指定它们。

关于git - 恢复已添加到索引但随后被 git reset 删除的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10782978/

相关文章:

git - 如何恢复/取消 git reset --soft HEAD~20

git - 如何从 gitlab 中完全删除提交?

Git 删除不需要的提交

git - 取消 git Push 并忽略附加文件夹

git - 如何别名 git checkout && git stash apply

Git pull 请求失败

git - 仅还原推送提交的单个文件

git - 我可以将 git 与 .dwg (autocad) 一起使用吗?

git 创建以 ~? 结尾的文件

git - 在本地跟踪文件,但绝不允许将它们推送到远程存储库