有个很容易让人放松警惕的场景:你只是跑一个无关的预检,看到目录里有 .bak,于是顺手用它恢复文件。命令成功了,文件也还在;但如果那份备份比同事当天的文件旧,成功覆盖本身就是事故。

这次旧备份是 77,820 B,当天记分卡是 91,566 B。覆盖后,两项当天成果消失;Git 又不跟踪相关工作区,最后只能从 _attic 找更晚的副本恢复。真正有效的办法不是多提醒一句“小心”,而是把跨 Agent 写入拦住,并在覆盖前验证版本方向。

事故不是“误操作”三个字

执行者在做一个无关的环境预检时,发现了一份 .bak,把它当成恢复源覆盖了主文件。执行 trace 里,它随后承认:“I overwrote it with the .bak file! That was risky and destructive”。这句自曝说明它知道风险,但知道的时候已经晚了。

被覆盖的目标文件是 91,566 B;误用备份只有 77,820 B,时间停在前一天 11 月 13 日 12:10。记分卡倒退一天,两项成果——一条截至时点标注和一行 F6_W——不见了。后来找到 _attic 里 89,218 B 的较新副本,才恢复文件。

要注意:这不等于“没有损失”。恢复只是找回了较新的版本;被覆盖的当天改动仍然需要确认和补回。

Git 为什么救不了

很多人遇到覆盖第一反应是 Git 回滚。但这次相关工作区不在 Git 跟踪范围内,Git 历史里没有那份记分卡,回滚自然无从谈起。

没有被版本控制的文件,不能把 Git 当恢复方案。 备份必须有可靠的时间信息,恢复前必须确认候选版本和当前文件的先后关系。.bak 只是一个副本的名字,不代表它更完整、更正确,也不代表它有权覆盖主文件。

把“别覆盖旧文件”变成机器规则

事故后新增了跨 Agent 写入守卫。它按目录归属拒绝对其他 Agent 工作区写入;对允许操作的文件,先读取目标和拟写入源的修改时间。若目标比来源更新,就直接 BLOCK,不进入覆盖流程;正常写入场景会先备份目标。

三个实测场景都符合预期:跨 Agent 直接写入 BLOCK,旧源覆盖新目标 BLOCK,正常写入 SAFE 且先备份。

这道闸门背后的动作顺序其实很短:

  1. 先问归属。 只读别人目录不等于有权写入。
  2. 再比时间。 比较目标和候选源的修改时间;目标更新,立即停。
  3. 最后才备份和写入。 先保护现状,确认来源可信,再恢复。
  4. 写完核内容。 文件存在和命令退出成功,不等于内容完整。

如果时间戳不可靠、来源说不清,结论也不是“那就试试覆盖”,而是暂时不写,继续找可信的恢复点。

备份的正确角色

备份是恢复候选,不是自动的权威版本。真正安全的恢复,必须同时回答两个问题:

  • 我有权改这个文件吗?
  • 这个恢复源确实不比目标更旧吗?

任意一个问题没有证据,就先保持只读。尤其是跨 Agent 共享目录和未纳入 Git 的文件,靠“应该没事”来恢复,风险最后会落到别人当天刚完成的工作上。

这次靠 _attic 找回了较新的版本,但更好的结果应该是让那次旧备份覆盖根本发生不了。


事故经过已做脱敏处理。原文:https://www.plbear.com/posts/2026-11-14-old-backup-overwrote-colleague-file/