Claude Code 覆盖了你未提交的改动:先用 /rewind,再用编辑器 local history 抢救

未提交的活儿被 agent 跑没了——先试 /rewind,再用编辑器 local history 和 reflog 抢救,最后用「跑 agent 前先 commit」+ deny 规则 + worktree 锁死。

你在 src/billing.ts 改了两小时——debug 日志、做一半的重构、一段写着推理的 TODO 注释——都没提交。让 Claude Code 跑了个”小修”。新的 diff 把整个文件替换了,你的改动从 working tree 里消失,而且你从没 commit 过。

先说最快的修法: 如果文件是在还开着的那个 Claude Code session 里被覆盖的,运行 /rewind(或在空的输入框里按两下 Esc),选这个 session 的第一个 checkpoint,再选 Restore code。Claude Code 会在每次改文件之前先捕一份快照,所以跑 agent 之前的内容通常还在。如果那个 session 已经关了,直接跳到编辑器 local history(Step 2),它能救回剩下的大部分情况。

这比你感觉的更经常可恢复。Claude Code 留 per-session checkpoint、编辑器留 local history、git 留 reflog,即便文件被完全覆盖,编辑器 buffer / swap 文件 / 备份 snapshot 里也常还有一份。下面是接下来 10 分钟的抢救路径,以及分层的「以后不再发生」设置。

先判断你属于哪种情况

症状最可能的原因去哪一步
覆盖发生在还开着的那个 session 里Claude 重写了文件,存在 checkpointStep 1(/rewind
session 关了,但编辑器还开着buffer / local history 里还留着你的改动Step 2-3
agent 在覆盖之后自动 commit 了commit 捕的是覆盖之后的状态Step 2 + Step 4(reflog)
你切分支前 stash 过stash 在错的分支或根本没 popStep 4(git stash list
两个 agent(或 Claude + Cursor)改了同一个文件后写者赢Step 2,再用 Step 6(worktree)预防

常见原因

按命中率从高到低排列。

1. 跑 agent 时 working tree 是脏的

Agent 的 Read 捕到了你脏的状态,随后的 Write 用它自己版本的改动替换了整个文件。你的未提交改动没进 diff,因为 agent 没有保留它们。如果 session 处在 acceptEdits 模式(改动自动应用、不再弹确认),这种情况会更常见——而这恰恰也是你最不容易注意到整文件 write 的时候。

如何判断:看 agent 的 tool 调用。如果它用的是 Write(不是 Edit)并替换了整个文件,你的未提交改动就被静默覆盖了。

2. 多个 agent 同时动同一个文件

两个 Claude Code session,或者一个 Claude 加一个 Cursor,同改一个文件。后写者赢,先写者的改动消失。

如何判断git log src/billing.ts 看不出异常,但文件内容只匹配一个 agent 的 intent——另一个 agent 的活儿没了。

3. Agent 用了整文件 write 而非 Edit/patch

大改动时 agent 有时会整文件重写。你在文件里加的 inline debug log 在 Claude 重写时,如果没被当成任务的一部分,就不会被保留。

如何判断:diff 显示整个文件都改了(每行都动),而不是局部 hunk——这就是整文件重写。

4. 你以为保存了,其实没保存

改动还在未保存的 buffer 里。关闭或重启编辑器丢掉了 buffer,磁盘上是 agent 保存的版本。

如何判断:你不记得 agent 跑之前按过 Cmd+S——磁盘上没有改动,但编辑器 recovery 里可能还有。

5. Agent commit 了一个 checkpoint,把它的覆盖也一起提交了

Claude 被 prompt 要求干完活后 commit。它的 commit 捕的是覆盖之后的状态。你的改动没进 git——但可能还在 /rewind checkpoint 或编辑器 local history 里。

如何判断git log -1 --stat 显示近期有个 agent commit,而你的改动不在任何 commit 里。

6. Stash 应用错了,或在错的分支 pop 了

你 stash 了改动,为了 agent 任务切了分支,stash 在错的分支被 pop 了——或者根本没 pop。

如何判断git stash list 显示有你没意识到还挂着的 stash,或者你的分支缺了你记得 stash 过的改动。

最短修复路径

按紧迫度排列。在核完 checkpoint 和 local history 之前,不要关 Claude Code session 或编辑器。

Step 1:先试 Claude Code 的 /rewind(如果 session 还开着)

从 2025 年底起,Claude Code 会自动给你的代码打 checkpoint。按官方 checkpointing 文档的说法,它会”在每次改动之前捕获代码状态”,每个 prompt 都会创建一个 checkpoint,checkpoint 跨 session 保留、30 天后自动清理。因为 agent 改的正是你未提交工作所在的那个文件,改动之前的内容通常就在第一个 checkpoint 里。

1. 在 Claude Code session 里运行 /rewind
   (或在输入框为空时按两下 Esc)
2. 菜单会列出本 session 你发过的每个 prompt——选覆盖任务之前的那个点
3. 选 "Restore code"(只回退文件,保留对话)
   - "Restore code and conversation" 会连聊天一起回退
   - "Restore conversation" 保留当前代码——这里不要选它

文档里有两个重要限制:

  • Bash 改动不被追踪。 如果 Claude 是用 mvcp 或重定向(> file)这类命令覆盖文件,而不是它的文件编辑工具,/rewind 救不了,要走 Step 2-4。
  • 外部改动不被追踪,除非它们改的是本 session 也改过的文件。你手动改的 src/billing.ts 之所以能被捕到,只是因为 Claude 后来也改了同一个文件。一个你改过、但 Claude 从没碰过的文件不会出现在 checkpoint 里。

如果 /rewind 里显示的内容不对,或者 session 已经关了,往下走。Checkpoint 是本地的 undo,不能替代 git。

Step 2:查编辑器 local history

现代编辑器都保留独立于 git 的文件历史,在 Claude session 已经没了的时候,这是回收率最高的恢复手段:

VS Code / Cursor / Windsurf:

Explorer 里文件右键 -> Open Timeline
或:View -> Timeline

里面有「Saved 15 min ago」之类的条目——点进去 diff 或 restore。(VS Code 的 Timeline 汇总了内置的 Local History provider,即便文件在磁盘上被覆盖,条目也还在。)

JetBrains(IntelliJ、WebStorm、PyCharm):

文件右键 -> Local History -> Show History

Sublime Text: 装「Local History」插件,没有内置等价功能。

这一步能救回大多数「agent 覆盖了我的改动」的情况。在做任何破坏性操作之前先试它。

Step 3:用 Cmd+Z 检查未保存的 buffer

如果文件还在编辑器里开着、且你没重启过,buffer 的 undo 历史可能还留着你的改动:

1. 在编辑器里打开受影响的文件
2. 点击文件,聚焦 buffer
3. 反复按 Cmd+Z(或 Ctrl+Z)——看 diff 一步步回退到你的改动
4. 改动恢复了就停
5. 立刻保存(Cmd+S)

如果 Cmd+Z 跳过了你的改动,或者 undo 历史被一次 reload 清掉了,退回 local history(Step 2)。

Step 4:查 git reflog、stash 和备份文件

即便你的改动从没正式 commit,也可能存在 checkpoint commit 或备份:

# 找丢失的 commit,包括 Claude Code 的自动 commit
git reflog --all | head -30

# 找所有分支上的 stash
git stash list

# 编辑器 swap / 备份文件(vim、emacs)和 merge 备份
ls -la .*.sw[opq] 2>/dev/null
find . -name "*.orig" -o -name "*~" 2>/dev/null

如果某个 reflog 条目里有你的改动,只把那个文件取回来,不动 working tree 的其余部分:

git checkout <hash> -- src/billing.ts

Step 5:真丢了就重写,并立「跑 agent 前 commit」规矩

如果所有恢复路径都试过还没回来,把改动重写一遍,然后立规矩,让它不再复发:

# 跑 agent 前的仪式
git status                             # 确认有哪些未提交内容
git add -A && git commit -m "wip"      # 给所有改动打 checkpoint
# 现在再跑 agent

一个之后再 squash 的 wip commit,远比丢两小时的工作便宜。

Step 6:多 agent / 并行工作用 git worktree

如果你经常一边跑 agent 一边手动改,给每个 agent 一个独立的 working tree,写操作就撞不到一起:

# 给 agent 工作在独立分支上建一个 worktree
git worktree add ../project-agent -b agent-task

# 或者让 Claude Code 帮你创建并管理:
claude -w

之后在 project/ 里手改,在 project-agent/ 里跑 agent。各自有独立的 working tree,agent 的写永远盖不掉你手动的改动。截至 2026 年中,团队普遍能稳定跑每人 4-8 个并行 worktree。agent 完事后,按你的节奏把它的分支 merge 回来。

怎么确认已经修好

恢复之后,继续干活之前先验证:

git diff src/billing.ts        # 你的改动回到 working tree 里了
git status                     # 确认文件按预期处于 staged / modified 状态

打开文件,对一下你记得的几个标记(那段 TODO 注释、那行 debug log)。然后立刻打一个 wip commit,让恢复出来的活儿进到 git 里,而不只是停在磁盘上。

预防建议

  • 「跑 agent 前 commit」是硬规矩。 你在乎的脏 working tree,绝不要直接跑 agent。

  • 探索性 wip 不想 commit,就用 git stash,之后用 git stash list 复核。

  • 并行的「agent + 手动编辑」用 git worktree(或 claude -w)——working tree 分开就不会撞。

  • 高风险任务用 Plan Mode。 让 session 在 plan 权限模式下启动(用 Shift+Tab 循环切换模式,或 --permission-mode plan);Claude 会探索并给出方案,但在你批准之前不改源文件。

  • 用 deny 规则保护特定文件,而不是只在 prompt 里好言相劝。在 .claude/settings.json 里,deny 规则遵循 gitignore 规范,由 Claude Code(而非模型)强制执行:

    \{
      "permissions": \{
        "deny": ["Edit(/src/billing.ts)"]
      \}
    \}

    Edit(...) 规则覆盖 Claude 所有的文件编辑工具(以及它识别的 Bash 文件命令,比如 sed)。对于任意脚本,再配一个 PreToolUse「block edits to protected files」hook 或 OS 沙箱。

  • 在 agent prompt 里也点名 Claude 不能动的文件:「不要改 src/billing.ts,里面有未提交的活儿。」(这只塑造意图、不构成强制边界——要强制就用 deny 规则。)

  • 编辑器开自动保存并设短 debounce,让未保存的 buffer 状态尽量少出现。

  • CLAUDE.md 里要求 Claude 对局部改动优先用 Edit 式 patch,不要整文件 Write

常见问题

/rewind 能撤销 agent 通过 shell 命令做的改动吗? 不能。Checkpoint 只追踪通过 Claude 文件编辑工具改的文件。任何由 Bash 命令改动的东西——rmmvcp、重定向,或某个脚本——都不会被捕获,也不能用 /rewind 回退。要退回 git reflog、local history 或备份。

我的 session 关了,还能用 checkpoint 吗? Checkpoint 跨 session 保留 30 天,所以恢复同一个 session(claude --resume)能把 rewind 菜单调回来。但如果 working tree 之后又往前走了,restore 可能会盖掉更新的工作——先 diff。拿不准就改用编辑器 local history(Step 2)。

Claude 为什么用整文件 Write 而不是 Edit 对于大的或结构性的改动,agent 有时会整文件重写而不是逐 hunk 打 patch。这是预期行为,不是 bug——但这也正是为什么文件里没纳入任务的未提交改动会被抹掉。先 commit,或对那个路径 deny Edit,都能避免。

先 commit 真能挡住这种事吗? 能。有一个干净的 commit,最坏情况也只是 git restoregit checkout 回那个 commit——你的活儿永久进了 git 历史,而不只是停在 working tree。这是杠杆最高的一个习惯,也是为什么 checkpoint 是「补充而非替代」版本控制。

deny 规则没挡住那次编辑,怎么回事? 检查路径锚点对不对:/src/billing.ts 是相对于项目根目录的,而 //src/billing.ts 才是绝对文件系统路径。用 /permissions 确认规则已加载。deny 规则覆盖 Claude 的内置工具和它识别的 Bash 文件命令,但不覆盖自己打开文件的自定义脚本——那种情况要用沙箱做 OS 级强制。

相关阅读

标签: #排查 #Claude Code #排查 #覆盖