Git 执行记忆:任务即分支(P1-8)¶
目标:让 agent 的每一次任务执行都拥有独立、可回放、可安全遗弃的 git 轨道—— 任务即分支,分支即 worktree,步骤即提交。失败时整条 worktree 删掉,主树零污染。
心智模型¶
主树 (main, 干净)
└── task/<slug>/ ← 每次任务 begin 出来的独立 worktree(独立分支)
├── step commit 1 (绿测后 auto-commit)
├── step commit 2 (绿测后 auto-commit)
└── …
- 任务即分支:
task_begin(task)把自由文本任务 id slug 成task/<slug>分支, 并用git worktree add切出隔离工作区。主树的工作区与 HEAD 全程不被触碰。 - 步骤即提交:每个有意义的小步完成后,
task_step_commit自动检测工作区变更并提交。 - 失败即遗弃:
task_finish(success=False)强制删除 worktree 并丢弃任务分支, 主树分支、主树文件、主树 status 全部保持原样。
三个接口(spark.git_memory)¶
| 接口 | 作用 |
|---|---|
task_begin(sb, TaskBeginArgs(task=…, base=None)) |
建 task/<slug> 分支 + worktree,返回 branch 与 worktree_path |
task_step_commit(sb, TaskStepCommitArgs(worktree=…, step=…, run_tests=True)) |
检测变更 → (可选)绿测门控 → 自动提交 |
task_finish(sb, TaskFinishArgs(worktree=…, branch=…, success=…)) |
成功:保留 worktree 并给合并指引;失败:force 删 worktree + 删分支 |
它们全部复用 spark.tools.gitops 既有的 worktree_create / worktree_remove /
git_commit / run_tests / detect_test_command,不重写其行为,只在其上串自动循环。
Auto-commit 策略:测试通过才提交(aider 范式)¶
本项采用「绿测才落盘」(test-gated auto-commit)。
task_step_commit 的决策表:
| 情形 | 行为 | test_gate |
|---|---|---|
| 工作区无变更 | 不提交,committed=False |
disabled |
| 检测到测试入口且通过 | git add -A 后用 step 作 subject 提交 |
passed |
| 检测到测试入口且失败 | 不提交,工作区留红供下一轮修复,返回测试输出 | failed |
开了 run_tests 但仓库无测试入口 |
无法门控,照常提交并标注 | not-detected |
run_tests=False |
步骤级即时 checkpoint,跳过测试 | disabled |
为什么是绿测门控,而不是每步无脑提交:
- aider 的核心契约就是「测试绿了才落盘」——可运行的中间状态才配进历史, 红色中间态留在工作区给下一轮修,而不是污染分支历史。
- worktree 已经提供了「失败整体删除」的隔离;若在 worktree 里也把破损状态提交, 分支历史会堆满红色 checkpoint,回溯与合并成本反而变高。
- 仓库没有测试入口时自动降级为「无门可守,照常提交并标注」,不会卡死任务。
step描述直接成为 commit subject,每一条提交都带任务语义、可独立git bisect。
成功 vs 失败¶
- 成功:
task_finish(success=True)保留 worktree 与分支,返回合并指引 (git merge <branch>→ 验收后git worktree remove)。本层绝不自动 merge/push, 合并是人的决定。 - 失败:
task_finish(success=False)先worktree remove --force,再git branch -D丢弃分支,并在返回里记录被遗弃的分支 tip。主树的 HEAD、tracked 文件、status 均不变。
注:沙箱化的 worktree API 要求 worktree 位于主 checkout 之内,因此保留型 worktree 会在 主树
git status里以?? task/(已注册目录)出现——那是 worktree 本身,不是 tracked 文件污染;失败遗弃后该目录被删除,主树 status 完全干净。
快速验证¶
python3 -m pytest tests/test_p1_08_gitmemory.py -q
端到端在临时真实 git 仓库里跑:建 worktree → 绿测提交循环 → 红步被拦截 → 失败清理 → 主树 HEAD 与文件零变化。不依赖网络。