今天,我的同事差点丢失了他四天的工作成果。由于一个不正确的 git 命令,他丢弃了保存在 暂存区(stash) 中的更改。在这个令人难过的事件之后,我们寻找了一种方法来尝试恢复他的工作……我们做到了!
首先要警告的是:当您实施一个大型功能时,将其拆分成小块并定期提交。长时间工作而不提交更改不是一个好主意。
现在我们已经解决了这个问题,让我们演示如何恢复意外从暂存区(stash)丢弃的更改。
我的示例仓库只有一个源文件,main.c,看起来像这样

opensource.com
它只有一个提交,即初始提交

opensource.com
我们文件的第一个版本是

opensource.com
我将开始编写一些代码。对于这个例子,我不需要做很大的更改,只需要一些放入暂存区(stash)的东西,所以我将只添加一行新代码。git-diff 输出应该是

opensource.com
现在,假设我想从远程仓库拉取一些新的更改,但我还没有准备好提交我的更改。相反,我决定将它暂存(stash),拉取远程仓库的更改,然后将我的更改重新应用到主分支(master)。我执行以下命令将我的更改移动到暂存区(stash)
git stash
使用 git stash list 查看暂存区(stash),我可以看到我的更改在那里

opensource.com
我的代码在一个安全的地方,并且主分支(master)是干净的(我可以使用 git status 检查这一点)。现在我只需要拉取远程仓库的更改,然后将我的更改应用到主分支(master)上,我就应该完成了。
但我意外地执行了
git stash drop
这会删除暂存(stash),而不是
git stash pop
这会在从堆栈中删除暂存(stash)之前应用它。如果我再次执行 git stash list,我可以看到我从暂存区(stash)中丢弃了我的更改,而没有将其应用到主分支(master)上。天啊!谁能帮帮我?
好消息:git 没有删除包含我的更改的对象;它只是删除了对它的引用。为了证明这一点,我使用 git-fsck 命令,该命令验证数据库中对象的连接性和有效性。这是我在仓库上执行 git-fsck 命令后的输出

opensource.com
使用 --unreachable 参数,我要求 git-fsck 显示不可达的对象。正如你所看到的,它没有显示不可达的对象。在我丢弃暂存区(stash)中的更改后,我执行了相同的命令,并收到了不同的输出

opensource.com
现在有三个不可达的对象。但哪个是我的更改呢?实际上,我不知道。我必须通过执行 git-show 命令来查看每个对象来搜索它。

opensource.com
找到了!ID 95ccbd927ad4cd413ee2a28014c81454f4ede82c 对应于我的更改。现在我找到了丢失的更改,我可以恢复它了!一种解决方案是将 ID 检出(checkout)到一个新分支或直接应用提交。如果您有包含更改的对象的 ID,您可以决定将更改再次放到主分支(master)上的最佳方法。对于这个例子,我将使用 git-stash 将提交再次应用到我的主分支(master)上。
git stash apply 95ccbd927ad4cd413ee2a28014c81454f4ede82c
另一个需要记住的重要事项是 git 会定期运行其垃圾回收器。在执行 gc 后,您将无法再使用 git-fsck 查看不可达的对象。
本文最初发布在作者的博客上,并经许可转载。
6 条评论