首先,对您的 Git 存储库进行完整备份!
当你git add
创建一个文件时,git 会从这个文件的内容中创建一个 blob 并将其添加到它的对象数据库(.git/objects/??/*
)中。
让我们一一看看你的命令:
我使用 git add 添加了所有文件。
$ git add .
这会将当前目录及其子目录中包含的所有文件添加到 Git 的对象数据库中。.gitignore
将不会添加与文件中的模式匹配的未跟踪文件。树文件也将被写入。请看我回答的结尾。
然后我承诺
$ git commit -m'added all files'
这会将一个新的提交对象写入对象数据库。此提交将引用一棵树。树引用 blob(文件)和其他树(子目录)。
当我检查状态时,仍然有文件未包含在 add 的提交中,这很奇怪
$ 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重置头
这不会取消暂存此提交,但会取消暂存索引中所有已暂存(但未提交)的更改。最初(第 1 步),您想说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
,它将暂存对跟踪文件的所有更改。要跟踪新文件,最好明确指定它们。