如何从 git 错误中恢复

不要让 git 命令中的错误抹去几天的工作。
397 位读者喜欢这个。
Bubble hands

Opensource.com

今天我的同事几乎丢失了他四天的工作成果。 由于一个不正确的 git 命令,他丢弃了他在 stash 中保存的更改。 在这个令人难过的事件之后,我们寻找一种方法来尝试恢复他的工作……我们做到了!

首先警告:当您实现一个大的功能时,将其分成小块并定期提交。 长时间不提交您的更改不是一个好主意。

现在我们已经解决了这个问题,让我们演示如何恢复意外从 stash 中删除的更改。

我的示例存储库,只有一个源文件 main.c,看起来像这样

Repository with one source file

opensource.com

它只有一个提交,即初始提交

One commit

opensource.com

我们的文件的第一个版本是

First version of the file

opensource.com

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

git-diff output

opensource.com

现在,假设我想从远程存储库中拉取一些新的更改,但我还没有准备好提交我的更改。 相反,我决定 stash 它,拉取远程存储库的更改,然后将我的更改应用回 master。 我执行以下命令将我的更改移动到 stash

git stash

使用 git stash list 查看 stash,我可以看到我的更改在那里

Output of changes in our 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 命令后的输出

Output after executing the git-fsck command on the repository

opensource.com

使用 --unreachable 参数,我要求 git-fsck 向我显示无法访问的对象。 正如您所见,它没有显示无法访问的对象。 在我删除 stash 上的更改后,我执行了相同的命令,并收到了不同的输出

Output after dropping changes on stash

opensource.com

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

Output after executing the git-show command

opensource.com

找到了! ID 95ccbd927ad4cd413ee2a28014c81454f4ede82c 对应于我的更改。 现在我找到了丢失的更改,我可以恢复它了! 一种解决方案是将 ID 检出到新分支或直接应用提交。 如果您有包含您的更改的对象的 ID,您可以决定将更改再次放在 master 分支上的最佳方法。 对于此示例,我将使用 git-stash 再次将提交应用到我的 master 分支。

git stash apply 95ccbd927ad4cd413ee2a28014c81454f4ede82c

另一个要记住的重要事项是 git 定期运行其垃圾收集器。 在执行 gc 后,您将无法再使用 git-fsck 查看无法访问的对象。

本文最初发表在作者的博客上,并经许可转载。 

标签
User profile image.
我是 José Guilherme Vanz,来自巴西南部。 担任软件工程师。 我热爱开源和编程

6 条评论

我认为如果用户可以配置 Git 在执行可能导致数据丢失的操作之前始终要求确认(即使有些像这里显示的那样是可恢复的,大多数用户永远不会发现这一点),那将非常有趣。 有一次我记得丢失了一个完整的提交,不得不全部重写。 我很幸运,我的脑海中仍然有部分代码。

好建议。 您应该在 git 社区中提出这个建议。 也许,他们可以实现您的想法。

回复 作者 teresaejunior (未验证)

唯一没有撤消的地方是 git reset --hard,其中工作目录。 请改用 git stash -u。

很高兴知道。 谢谢你的提示。 当我写这篇文章时,我不知道这一点。 所以,我找到了一个艰难的解决方案。 ;)

回复 作者 Adam Dymitruk (未验证)

有趣,但你为什么不使用 "git reflog"? 它可以让你从几乎任何情况中解脱出来。

实际上,'git stash' 是使用 reflog 实现的,而删除 stash 条目意味着从实现 stash 的 reflog 中删除条目。

如果你的意思是 'master' 或 'HEAD' 的 reflog - 是的,这是一个好问题。

回复 作者 Jacopo (未验证)

Creative Commons License本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.