Per-TODO Squash(单 TODO 独立 revert)
Z3 全文↑ Z2 条目
术-操作 · 术层 skill 全文
本页是 <code>rules/skills/bestpractice_per_todo_squash.md</code> 的逐字投影(仅隐私清洗,零改写)。
时点提示:本页是仓内文件 rules/skills/bestpractice_per_todo_squash.md 的逐字投影(仅做隐私清洗:仓库根绝对路径→相对路径、家目录→~/;除此零改写)。若源文件后续有修订,以仓内真源为准。
Skill: Per-TODO Squash(单 TODO 独立 revert)
When to Use
需要把一个 feature/task 分支的变更「按 TODO 粒度」落到 main,使每个 TODO 对应一个独立 squash commit。典型触发:
- 一整晚跑完几十个 TODO,希望随时可
git revert单个 TODO 的影响 - TODO 之间互相无依赖,回滚一个不应影响其他
- 想让
git log --grep='TODO-ID: T001'直接定位到对应的 squash
不需要时(默认行为):feature 分支所有 commit 合成一个 squash,不区分 TODO。继续用不带 flag 的 snapshot_merge.sh <task> <branch>。
Prerequisites
tools/git/snapshot_merge.sh本体可用(Level 3 D2 起支持--per-todo)- feature 分支上的 commit 有
TODO-ID:trailer prepare-commit-msghook 在session/todo-或todo/分支会自动注入- 手动 commit 可通过
git commit --trailer "TODO-ID: T001"追加 - 没有 trailer 的 commit 归入
TODO-ID: none组,也独立构成一个 squash
调用
tools/git/snapshot_merge.sh --per-todo <task-name> <branch>不加 --per-todo 时行为完全不变(单一大 squash)。
行为
- 读取
main..<branch>的 commit 列表 - 按 commit 消息里的
TODO-ID:trailer 分组;相同 TODO-ID 的 commit 聚到同一组;无 trailer 的 commit 聚到TODO-ID: none - 分组顺序 = 第一次遇到该 TODO-ID 的 commit 所在位置
- 对每组依次在 main 上做一次
git cherry-pick --no-commit+ 单次commit_wrapper.sh产生一个 squash commit - 每个 squash commit 带
TODO-ID: <id>trailer(或TODO-ID: none),commit subject 形如snapshot: <task> todo=T001 (+<n> commits) - feature 分支 + worktree 不删除,继续存活
失败模式
- 任一组的 cherry-pick 冲突:main 回滚到冲突前、
pending_merges.md记录、退出 1。feature 分支保留 - primary worktree 有 staged 改动:拒绝开始(同默认模式),
pending_merges.md记录「per-todo: primary dirty before group <id>」
验证
成功后手测:
git log --oneline main..HEAD # 看到 N 个新 squash
git log -1 --format=%B <squash-sha> | grep 'TODO-ID: T001'
git revert --no-edit <T001-squash> # 回滚仅 T001自动化测试:tests/e2e/per_todo_squash_smoke.sh(mktemp 隔离,验证分组 + 独立 revert)
已知局限
- 组间 commit 若修改同一个文件(不同 TODO 改同一文件),后面组的 squash 可能与主干冲突;需要走 pending_merges 人工解决
- TODO-ID 匹配是纯字符串;无法识别同一个 TODO 跨多个 id 的别名
- 不改变默认 snapshot 行为;想全仓迁移须显式加
--per-todo
相关
- 实现:
tools/git/snapshot_merge.sh(PER_TODO=true路径) - E2E:
tests/e2e/per_todo_squash_smoke.sh - 触发设计:
config/build_logs/GIT_V2_01_LEVEL_3_PLAN_20260418.md§3.4 D2 - 用户需求:04-07 "80 TODO 随时撤销某一个修改不应影响其他 commit"