README.md 3.29 KB

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/(镜像源码树的相对路径),核对后再拷回去, 不要让恢复脚本直接写源码树。

两个关键坑(都在脚本注释里写明了)

  1. 必须剔除失败的操作。 会话里 Edit 报错后助手会重试,失败的那次也留在 jsonl 里;照单全收会让重放内容和真实历史分叉。判据是 tool_result.is_error。 不剔除时 80 个里有 4 个重放失败(LoginLogTypeEnum/LoginResultEnum/ DataScopeEnum/RoleServiceImpl),剔除后 80/80 干净通过。

  2. 有的文件不是 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。