博主Flynt实测:git救不回未提交文件,仓库外备份才可靠
针对Claude Code误删文件事故,独立开发者Flynt在本地实测git恢复边界。结果显示git restore和stash无法找回未提交或未跟踪文件,且.git被删后常规命令全部失效。只有将仓库打包为bundle并存于仓库外,才能在目录全灭时实现逐字节恢复。
近日有开发者在Reddit发帖称,Claude Code在一次“重建项目镜像”的任务中,103秒内删除了其48,218个文件,连带把.git里的objects、refs、logs一起端掉。该帖子后来被作者删除,TechRadar等媒体进行了报道。由于目前仅有当事人自述加附件验证报告,没有独立取证,其真伪暂不考证。但这一事件引发了一个更实际的工程问题:如果类似的误删发生在你身上,git到底能救回多少?
独立开发者Flynt在本地环境(git 2.34.1,Linux)进行了一系列可复现的演练,试图打破“我有git,怕什么”的直觉。他首先模拟了最常见的灾难现场:工作区除.git外全被删除。使用标准恢复命令git restore .后,通过md5清单对比发现,下午刚写的未提交修改丢失,未跟踪的新文件也查无此人。结论很清晰:git只认提交过的内容,未提交和未跟踪的文件在它的恢复世界观里根本不存在。
接着,Flynt测试了git stash。在不带-u参数的情况下,stash同样收不走未跟踪文件。即使每次都用stash -u,stash的本体依然是.git目录下的一组对象。这就触及了事故真正的死因:.git并不是异地容灾的备份。当清理脚本从项目根目录往下删时,.git会一并陪葬。Flynt模拟删除.git/objects、.git/refs和.git/logs后,git status、git log、git fsck和git reflog四个命令全部报错“not a git repository”。因为fsck的工作方式就是遍历objects,仓库没了它就失业了。
既然.git靠不住,Flynt尝试自建快照。他利用GIT_INDEX_FILE、read-tree、add -A和commit-tree等git底层零件,把工作区当前状态固化成commit挂在自定义引用下。第一版脚本把临时index放在了工作区,结果被git add -A自己吸进了快照,导致恢复时多出垃圾文件。修正路径后,快照确实能记录未跟踪文件,但其commit和tree对象物理上依然躺在.git/objects里。一旦.git被端,这些快照照样陪葬。
最终能扛住全灭的方案是把保险柜搬出仓库:使用git bundle create。这条命令将所有引用连着对象库打包成单个文件写到仓库外。Flynt在拍完快照、打出bundle后,直接rm -rf整个仓库目录模拟最坏情况。随后通过git clone该bundle文件,再fetch快照引用并checkout,灾前灾后的md5清单diff显示一个字都没有——所有历史提交、未跟踪文件和最新修改均逐字节一致地恢复了。
按可靠程度排序,Flynt给出的建议是:推远程 > bundle到仓库外 > 本地快照 > stash > 裸奔。对于使用AI编码智能体的开发者而言,事前防线如权限白名单和沙箱模式固然重要,但agent的行为难以完全预测。这次演练证明,你能控制的只有“它删完之后你还能剩什么”,而仓库外的独立备份才是最后的底线。