tools/recover —— 误删源码的恢复工具
事故
2026-10-09,执行 tools/p2_import_legacy.py 把老 zteits-clouds 的核心模块搬进
parking-cloud/ 时,parking-module-system 与 parking-module-api 的
src/main/java 被整个 shutil.rmtree 删掉——这两个模块既装老代码,又装 P1
手写的新代码,而当时的脚本为了「可重复执行」一律先删目标目录。
删除清单:96 个文件(parking-module-system 92 + parking-module-api 4),
全部是 com.zteits.parking.* 包(新工程自己的包名,老工程里根本不存在)。
为什么差点不可恢复:parking-cloud/ 不是 git 仓库,
IntelliJ LocalHistory 里也没有这些路径。仅剩 target/classes 下的 .class。
恢复配方
| 脚本 | 恢复什么 | 依据 |
|---|---|---|
scan.py |
只是盘点:列出会话里有哪些文件可恢复、各有几个操作 | — |
restore_p1.py |
80 个文件 | Claude Code 会话 jsonl 里的 Write/Edit 按序重放 |
regen_derived.py |
12 个 Mapper + 4 个 apibase 文件 | 当时用的是 bash 生成器与 sed,规则确定性,可重算 |
合计 96 个,与 target/classes 里的 96 个 .class 一一对应(脚本会自校验)。
cd /Users/wangbiao/IdeaProjects/parking/parking-cloud
# 1) 重放工具写过的文件 -> tools/recover/out/
python3 -I tools/recover/restore_p1.py \
~/.claude/projects/-Users-wangbiao-IdeaProjects-parking-zteits-clouds/a887c773-a75a-45d4-9ea4-4406d3a1991b.jsonl
# 2) 重算生成器/sed 产出的文件 -> 同一个 out/
python3 -I tools/recover/regen_derived.py
# 3) 与 .class 对账(期望「缺 0 / 多 0」),确认无误后回拷源码树
# 实际执行时用的是 git 式的「目标已存在且内容不同就拒绝覆盖」,不会盖掉现有代码
产物先落 tools/recover/out/(镜像源码树的相对路径),核对后再拷回去,
不要让恢复脚本直接写源码树。
两个关键坑(都在脚本注释里写明了)
必须剔除失败的操作。 会话里
Edit报错后助手会重试,失败的那次也留在 jsonl 里;照单全收会让重放内容和真实历史分叉。判据是tool_result.is_error。 不剔除时 80 个里有 4 个重放失败(LoginLogTypeEnum/LoginResultEnum/DataScopeEnum/RoleServiceImpl),剔除后 80/80 干净通过。有的文件不是 Write 写的。 12 个 Mapper 出自一句 bash 函数 + heredoc, 4 个 apibase 出自
sed改包名,都不在 Write 记录里。它们必须按当时的同样规则 重算,而不是手写一个"看起来对"的版本——regen_derived.py里连生成器第 4 个参数extra(三个关联表被误传成*、'*',随后被sed '/^\*$/d'删掉)都如实保留, 就是为了和当时的最终文件逐字节一致;该校验用会话里现成的一次cat UserRoleMapper.java输出做过 diff,结果无差异。
别再犯
根因是「为了幂等而先删目录」。tools/p2_import_legacy.py 已改成
默认只增不删,--prune 也只删「老工程镜像过来的相对路径」,
并有 PROTECTED_PREFIXES 兜底 com/zteits/parking/**。
详见 AGENTS.md 的坑 12 与 p2_import_legacy.py 的模块 docstring。