背景与目标
今天做的是 code-cleaner 清理任务的收尾与升级。起因:.git 目录膨胀到 2.2GB(git count-objects 实测:loose 590.83MiB + pack 1.57GiB),而仓库没有远端、磁盘只剩 186GB。目标两层:
- 工作区垃圾清干净(根目录杂物、屎山代码处置);
.git本身不再虚胖——只删当前文件不重写历史,旧体积永远在。
红线:磁盘数据一个字节不能丢(gongwen/、inbox/ 等数据目录全程只动 git,不动文件)。
过程回顾
阶段 1:快照与工作区清理(16:55-17:02)
- 先打快照 commit(f88186a)再动手,坏了解决不至于伤到无备份状态;
- 删 1167 个文件:误建的 Chrome profile(1160 文件/114MB,路径拼接错误产物)、stackdump、0 字节文件、空壳 summary、21 处
__pycache__等; .gitignore补根目录兜底 3 条 → 提交 0a5ffbe。
阶段 2:屎山代码审计与处置(至 17:29)
- 派 general 子代理只读审计 177 个代码文件 → 5 高置信 / 5 疑似 / 167 保留,报告落
reports/20260928_屎山代码审计.md; - 军师独立复核三条证据(grep 零引用命中/仅自引用)全部对上才动手;
- 删 3 个一次性死脚本 + 0 字节误入库
ip.db(真库data/ip.db3.4MB 未动),归档 2 份过期文档 → 提交 e3c2978。
阶段 3:.git 元凶调查
count-objects -vH + git-filter-repo 的 analyze 报告(packed 体积=真实占用),按路径排出来:
| 路径 | packed 体积 | 占比 | 处置 |
|---|---|---|---|
gongwen/ 公文(docx/pdf/dwg/jpg…) |
1.39GB | 58% | 出历史,文件留磁盘 |
inbox/ 原始产出(oppo 便签附件即 196MB) |
260MB | 11% | 出历史,文件留磁盘 |
output/ 产物(含在售产品包) |
219MB | 9% | 保留(产品内容资产) |
ipms/packages 发布包 |
174MB | 7% | 保留(产线事实源) |
notes/ 笔记 |
126MB | 5% | 保留 |
| 误建 chrome profile 历史残留 | ~107MB | 4% | 出历史(磁盘已删) |
tools/wechat_watch/build |
81MB | 3% | 出历史 |
结论:公文和原始数据占七成——正是"数据不该进 git"的典型结构。
阶段 4:备份与数据剥离(17:48 提交)
- 镜像备份:
git clone --mirror出D:\code\thinking_git_backup_20260928.git(全量 2.2GB,回滚唯一凭据); - 记磁盘基线(清完必须逐字节对上):gongwen 691 文件/1304032487 字节,inbox 970 文件/290685589 字节;
.gitignore补 4 条(/gongwen/*例外台账、/inbox/、/.pachong_ws/等)+git rm --cached移出 1854 项 → 提交 e12aa01。只出索引,文件零删除。
阶段 5:历史重写(18:23 前完成)
- 先删 2 个指向 tree 的无效 codex ref(重写会卡);
git filter-repo --force --invert-paths清 5 个路径族,269 个 commit 全部重写,18.12 秒;- 结果:
.git= 371.34 MiB(loose≈15、garbage 0),git fsck退出码 0,历史 268→269(含重写后的补提交)完整; - 副作用处理(见踩坑 1):台账 7 文件从备份原样找回 → 提交 2d91a81。
阶段 6:验证与顺手修存量(至 18:32)
- 状态干净、数据基线逐字节一致、config_lint P0=0、kb 可检索;
- pytest 暴露 1 失败 → 快照 worktree 复现定位为存量过期测试(见踩坑 3)→ 修复 → 189 passed → 提交 62c730d。
关键踩坑
坑 1:filter-repo 把台账从工作区清走了
- 现象:重写后 gongwen 从 691 文件变 684,台账 7 文件(161609 字节)消失。
- 根因:执行前只预演了"历史里会清什么",没预演"旧 HEAD 仍被跟踪的文件会被重写同步清出工作区"——剥离提交里台账还是跟踪态,于是中招。
- 解决:从镜像备份
git show按文件取回,逐字节对基线(1304032487/691,零误差)后重新入库。 - 改进:重写类操作前先列"哪些文件在旧 HEAD 仍被跟踪",要么先剥离再重写,要么准备找回路径。
坑 2:另一条线正在同一个仓里干活
- 现象:准备重写时发现
docs/config-ledger.md(17:37)、docs/config-writing-standard.md(17:35)刚被别人修改,而我没写过它们——处置卡那条线在并行作业。 - 根因:全仓级操作(历史重写改所有 commit hash)与并发写入互相踩会丢东西;此前只顾自己任务卡,没做"在途改动"检查。
- 解决:当场停下问本人拍板("已收口,立即重写"),拿到确认才执行;我自己的三次提交全部只含本人暂存内容,别人的在途改动一行未卷入。结果:重写前后 git log 无他人提交交错,零冲突。
- 教训:全仓级操作(历史重写/批量改名/force 操作)执行前必查在途改动并让本人拍板,这条以后是固定动作。
坑 3:pytest 冒出 1 失败——快照复现法证明是存量,不是清理伤的
- 现象:全量跑出
test_geo_first_para_too_long失败;而此前验证记录写的是"163 passed"。 - 定位:①三份相关文件(测试/闸门/规则)自快照以来 diff 为空=我没碰;②
189 - 163 = 26恰等于该测试文件的用例数=此前记录漏收集了整个文件;③在快照 commit 的临时 worktree 里跑同一测试同样失败=问题在我动手之前就存在。三步把"是不是我干的"钉死。 - 根因:GEO 闸口径 9-26 已收敛(
answer_len60→220),旧回归测试还写死"80 字必拦",而 80 落在现行[40,220]合法区间内——配置改了,同批回归用例没跟。 - 解决:测试改为从 CFG 动态取上限+20,口径再变也不会过期;189 passed。
- 连带纠错:承认此前"pytest 163 passed"的验证记录口径有误(只记了 passed 数没记 collected 数,不可比)——验证记录从此必须带 collected。
坑 4(小):删除命令的"空输出"差点误判成功
第一次删 codex ref 用了通配 pattern 没匹配上,PowerShell 输出被编码搅成乱码,我把空输出误读为"已删"——复核 for-each-ref 才发现 ref 还在。改成显式 refname 删除并复核到"只剩 master"。教训:删除类命令一律二次复核,以复核结果为准,不以命令跑完为准。
最终方案(产出清单)
.git:2.2GiB → 371.34 MiB(约 -83%),fsck 0、garbage 0;- 数据处置:1854 项移出索引+历史,磁盘文件逐字节零损失;台账是 gongwen 下唯一保留跟踪目录;
- 防复发:gitignore 四条数据目录规则,新数据从此进不了 git;
- 备份:
D:\code\thinking_git_backup_20260928.git(裸仓,可整体回滚,旧 hash 全在); - 附带:屎山审计报告入库、3 死脚本删除、2 文档归档、1 存量过期测试修复;
- 代价(知情拍板):全部 commit hash 变化,文档里旧 hash 字面失效(本仓无远端、无兄弟仓依赖)。
做得好的地方
- 先备份再重写:镜像备份是敢动手的前提,坑 1 全靠它兜底;
- 数据红线用逐字节校验兑现:不靠"应该没动",拿基线数字对;
- 验收全部机器可判定:fsck/count-objects/pytest/lint 退出码当证据,不写"感觉没问题";
- 并发冲突主动叫停不硬上:发现第一现场(两个文件 mtime)就停下来拍板,没有赌"应该没事";
- 存量问题不甩锅不掩饰:快照复现法先证清白,顺手修掉,连同自己的记录口径错误一起纠正。
复盘与改进
- 重写类操作必做副作用预演清单(历史清什么/工作区动谁/refs 动谁)——坑 1 的根治;
- 全仓级操作前置检查在途改动——坑 2 的制度化;
- 验证记录必带 collected 数——"passed 163"这种半截数字以后不出现;
- 配置口径变更必须同批改回归用例——坑 3 的根治(这次是口径 9-26 改的,测试没跟)。
个人成长评估
目的先于打分:沉淀"什么指令带来什么结果"的可验证经验。分数是索引,指令实证是本体。
五维评分(10 分制,只对事)
| 维度 | 分 | 证据 |
|---|---|---|
| 指令与提示词 | 8 | 两处拍板(question 双答"已收口,立即重写/确认执行")一次到位零纠偏;起手方向纠偏 1 次("要清理的要清理",按 rubric 主干清晰+1-2 次小纠偏=8) |
| 判断与结论 | 8 | 并发收口判断与 hash 变更后果均知情拍板;但并发风险是 AI 先发现的,非本人预判 |
| 思维方式 | 8.5 | "要清理的要清理"突破"工作区干净=清完"的默认,直指历史体积——一句话把工作范围从删文件升级到重写 269 个 commit |
| 最终结果与产出 | 9 | 2.2GiB→371.34MiB 实测、零数据损失(逐字节校验)、189 passed、备份可回滚 |
| AI 协作 | 8.5 | question 两次全给关键信息,执行窗口未被中途打断;未预立"全仓操作前查在途"的规则(靠 AI 会话内发现) |
低分项改进(指令维 8):拍板"在途已收口"这类事实断言时,先让 AI 打印在途改动清单核验再执行,把口头确认变成机器核验。
指令实证(2 条)
- 原话"要清理的要清理" → 行为改变:清理范围从"删工作区垃圾"升级为".git 历史一并瘦身"立项 → 证据:e12aa01 剥离 + filter-repo 重写 + count-objects 2.2GiB→371.34MiB;
- 原话"已收口,立即重写"(question 拍板) → 行为改变:并发暂停点解除,全仓历史重写在零交错窗口执行 → 证据:
git log 2d91a81..62c730d仅含军师两次提交,无他人插入。
AI 自评(同场失分点)
- 验证记录口径错:"pytest 163 passed"漏收集 test_zhijian_check.py 26 例,今天实测 189 才暴露——半截数字入了 commit message,已纠错并立规则(必带 collected);
- 重写副作用无预演:台账被清出工作区属预判不足,靠备份兜底,应在执行前列出;
- codex ref 首删误判成功:空输出被乱码搅浑差点错过,靠复核抓回——删除类命令复核纪律从这次立。
素材点(可复用/可对外)
- filter-repo 会同步清"旧 HEAD 仍跟踪"的文件——历史瘦身前的预演清单模板;
- "快照 worktree 复现法":证明一个失败是存量还是新伤,三步(文件 diff 为空→测试计数差→旧 commit 复跑);
- "数据不入库两层论":gitignore 挡新增 + 历史重写清存量,缺一层体积永远在;
- 验证记录格式:测试数必须 collected/passed 成对记;
- 本次数字全部可复现:count-objects、filter-repo analyze、逐字节基线对账。
