封面

Git误操作reset --hard恢复教程:reflog与fsck使用指南

原文:https://dev.to/rbonweb/i-ran-git-reset-hard-in-the-wrong-window-2ihd(作者 @rbonweb)

git reset --hard HEAD~3 —— 在错误的终端窗口执行了这条命令,时间是下午6:40。紧接着是一阵特有的沉默,发生在你意识到自己刚刚做了什么,而大脑还没完全处理完这个事实的时候。三个提交的工作成果,在不到一秒内从工作目录中消失了。

首要事实:数据很可能还在

git reset --hard 移动分支指针并重置工作目录,但 Git 不会仅仅因为某些提交不再被引用就真正删除它们——它们会留在对象数据库中,处于未被引用状态,直到垃圾回收最终清理它们。对于大多数仓库,垃圾回收很少发生,“最终”可能意味着几周之后。

git reflog


a1b2c3d HEAD@{0}: reset: moving to HEAD~3
e4f5g6h HEAD@{1}: commit: add retry logic to payment webhook
7h8i9j0 HEAD@{2}: commit: fix currency rounding
k1l2m3n HEAD@{3}: commit: initial webhook handler


引用日志是 HEAD 最近指向位置的本地日志。它能从重置操作中幸存,因为重置只是在其中添加了新条目,而非擦除之前的条目。

git reset --hard e4f5g6h


工作目录被完全恢复到重置之前的状态,所有三个提交都回来了,耗时仅相当于你读完这句话的时间。

当引用日志不够用时

如果提交根本从未被创建——你是在真正未提交的更改上执行了 reset --hard——那么引用日志就帮不上忙了,因为它只跟踪 HEAD 和分支曾经指向的位置,而不跟踪从未被提交的文件内容。这是真正的损失,而对抗它的唯一真正防线就是尽早且经常提交,包括那些你打算稍后压缩的、一次性的“wip”提交。原因是未提交的更改根本没有恢复路径。

如果提交已被创建,但对应的引用日志条目已过期——Git 默认保留不可达的引用日志条目90天,可达的条目保留时间更长——git fsck --unreachable 有时仍能直接找到悬挂提交对象:

git fsck --unreachable --no-reflog | grep commit
git show <hash>  # 先检查,确认是否是你想要的


现在,我为何在执行破坏性 Git 操作前先测试

引用日志挽救了这次具体错误,也教会了我不要在下午6:40的压力下依赖于“记得有这么个东西”。真正养成的习惯是:对于任何真正破坏性且不熟悉的操作——跨越长历史的交互式变基、filter-branch,任何包含 --hard--force 的命令——我都会先在一个仓库的可丢弃克隆上运行它,确认它确实如我所想那样执行,然后才真正运行。

# 在不会造成任何伤害的地方预演高风险操作
krova cubes create git-rehearsal --cpu 1 --ram 2 --disk 10
# 克隆,尝试操作,检查结果,然后无论如何都将其销毁


在可丢弃的 Krova Cube 上进行预演花费几分钟时间,几乎零成本。之后销毁它意味着无需执行任何可跳过的清理步骤——一旦我得到答案,环境就简单地停止存在。我运营 Krova,因此请将此具体工作流程视为知情推荐而非中立陈述,但核心准则——在可丢弃的环境中预演破坏性 Git 操作,然后再在你关心的仓库上执行——无论你用什么工具来预演,都值得采纳。

我会首先检查什么

在假定丢失的工作确实丢失之前,运行 git reflog 并完整阅读它——你想要的提交很可能就以某个你尚未查看的哈希值藏在里面。在你执行下一个真正破坏性的 Git 命令之前,考虑一下在可丢弃环境中预演它,相比硬着陆(发现搞砸了)的代价,是否真的会给你带来任何损失。

原文:https://dev.to/rbonweb/i-ran-git-reset-hard-in-the-wrong-window-2ihd(作者 @rbonweb)

发布评论
全部评论(0)