我在索引中添加了一些文件,但后来我错误地用git reset --hard
删除了它们。 如何恢复它们?事情是这样的:
- 我使用
git add .
添加了所有文件 - 然后我承诺
- 当我检查状态时,仍然有文件未包含在添加的提交中,这很奇怪
- 我再次添加了未跟踪的文件,这次它有效
- 但是我希望所有内容都在 1 个单一提交中,所以我查找了如何取消我刚刚提交的内容
- 我用了
git reset --hard HEAD^
- 显然是个坏主意,所有文件都被删除了 - 所以后来我用
git reflog
找到我离开的地方 - 然后我用
git reflog ______
回到我上次提交。 - 然后我使用
git reset HEAD
来取消暂存提交(我最初应该做的),但我在提交后添加的文件(见上文)仍然消失了。
如何找回这些文件?
首先,对你的 Git 存储库进行完整备份!
当您git add
文件时,git 将从该文件的内容中创建一个 blob 并将其添加到其对象数据库 ( .git/objects/??/*
)。
让我们一一看一下您的命令:
我使用 git add 添加了所有文件。
$ git add .
这会将当前目录及其子目录中包含的所有文件添加到 Git 的对象数据库中。不会添加与.gitignore
文件中的模式匹配的未跟踪文件。还将写入树文件。请看我的回答的结尾。
然后我承诺
$ git commit -m'added all files'
这会将一个新的提交对象写入对象数据库。此提交将引用单个树。树引用 blob(文件)和其他树(子目录)。
当我检查状态时,仍然有文件未包含在添加的提交中,这很奇怪
$ git status
我可以想到发生这种情况的两种情况:某些内容修改了您的文件或在您背后添加了新文件。
我再次添加了未跟踪的文件,这次它有效
$ git add .
我假设您再次使用相同的add
命令,如步骤 1 所示。
但是我希望所有内容都在 1 个单一提交中,所以我查找了如何取消我刚刚提交的内容
我将在此答案末尾告诉您一种更好的方法,该方法不需要用户发出潜在的危险reset
我使用了 git reset --hard HEAD^ — 显然是个坏主意,所有文件都被删除了
$ git reset --hard HEAD^
此命令会将当前的工作树和索引设置为完全位于提交HEAD^
(倒数第二个提交)。换句话说,它将丢弃任何本地未提交的更改,并将分支指针移回一个提交。它不会触及未跟踪的文件。
所以然后我使用 git reflog 找到我离开的地方
$ git reflog
这显示了最近签出的最后提交(与git reflog HEAD
相同)。如果指定分支名称,它将显示此分支最近指向的最后一次提交。
然后我使用 git reflog __ 回到我的最后一次提交。
不确定这个。 git reflog
(大部分)是一个只读命令,不能用于"返回"提交。您只能使用它来查找分支(或HEAD
)指向的提交。
然后我使用 git reset HEAD 来取消暂存提交(我最初应该做的事情),但我在提交后添加的文件(见上文)仍然消失了。 $ git 重置头
这不会取消暂存此提交,但会取消暂存索引中的所有暂存(但未提交)更改。最初(第一步),你想说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
,它将暂存对跟踪文件的所有更改。要跟踪新文件,最好明确指定它们。
我有一个类似的问题,但我的仓库中有很多悬空的斑点和树,所以我最终过滤了grep
所有悬空斑点的输出并打印匹配的斑点。 假设${UNIQUE_CODE}
是索引中文件所特有的一些代码,那么这应该会为你提供要查找的 blob 的哈希:
for b in $(git fsck --lost-found | grep blob | awk '{print $3}'); do git cat-file -p $b | grep -q ${UNIQUE_CODE} && echo $b; done