Vibe Coding 原子提交:一项行为变化一份可验证历史
AI 一次会话常同时改业务、重构、依赖和格式,提交后却很难独立审查或撤销。本文用单一行为声明、完整依赖和提交级验证,把生成结果切成语义原子。
本文要点
- 主题聚焦:AI、Vibe Coding、DevOps
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
Agent 收到“增加导出按钮并顺便清理相关代码”后,可能修改组件、API、迁移、锁文件、测试、命名和全仓格式。把这些变化一次提交并不会使它们自动成为一个功能;reviewer 无法判断哪些行是必要依赖,回滚一个缺陷也会连带撤掉无关修复。原子提交的单位不是会话、文件或 Prompt,而是一个可独立陈述的行为变化。
本文不讨论怎样让 AI 写漂亮的 commit message,那是AI commit message 与 PR 描述的搜索意图;也不讨论 rebase 或 cherry-pick 等综合命令。这里关心的是:进入 Git index 的这棵候选树,是否只包含一个完整、可验证且能单独撤销的语义。
先写提交声明,再决定文件集合
每个候选提交先写一句 claim,结构为“在什么前提下,哪个可观察行为从什么变为什么”。例如:
当有导出权限的成员请求已完成报告时,API 返回带稳定列顺序的 CSV;无权限请求仍返回既有拒绝结果。
这句话可以同时需要路由、授权、序列化和测试,因此“一个提交只能改一个文件”并不成立。反过来,一个组件文件里可能同时有行为修复和无关格式化,它们也不该因为路径相同就混在一起。用需求验收追踪给 claim 分配稳定 ID,再列出使它成立的最小文件与测试。
提交边界至少满足四个条件:
- 完整:实现所需的测试、Schema、迁移或生成源没有留在下一提交;
- 单一:删除其中任一主要 hunk 会破坏同一个 claim,而不是暴露第二项无关工作;
- 可构建:从父提交应用后,仓库仍能执行约定的快速门禁;
- 可逆:撤销该提交时,依赖它的后续变化可识别,不把数据留在无法解释的中间态。
先画提交图,避免按生成顺序入库
AI 的编辑顺序通常是探索顺序,不是评审顺序。它可能先改调用方、再补类型、最后修测试。提交前把当前 diff 重新分成候选图:无行为变化的准备性重构;业务行为及其测试;数据或接口迁移;清理与文档。只有确实能在父提交上独立通过的节点才分开,否则宁可保留一个完整原子,也不要制造中间必红的历史。
测试与实现是否分成两个提交取决于用途。用于证明旧行为缺陷的 characterization test 可以先独立提交,因为它在旧实现上有确定结果;只为新能力编写且在父提交必然失败的测试,通常和实现放在同一原子中更诚实。数据库变化则要按可部署顺序设计,例如先加入向后兼容字段和双写,再切读,最后清理;不能把一个不可运行的大迁移强称为“原子”。
依赖升级的 manifest 与 lockfile 属于同一决策,生成文件与其源也应同行。若生成器会产生大量噪声,先在单独候选中证明生成命令和产物一致,再叠加业务变化。Definition of Done决定每类提交需要哪些门,而不是让“最终 PR 会变绿”替中间提交兜底。
让 AI 提议分组,但不替所有者暂存
Agent 可以读取完整 diff,输出 claim -> hunks -> dependencies -> tests -> risks 的分组建议。它不应默认执行 git add .,也不能把工作树中来源不明的修改归到最相似的 claim。共享文件按 hunk 处理,无法拆开的同一行先交给所有者;具体操作使用选择性暂存与 Diff 自审。
每组暂存后重新读取 git diff --cached,从零复述它改变的行为。如果复述必须说“以及顺手……”,通常还可拆分。然后检查未暂存区:候选提交是否遗漏一个运行必需文件,或只是因为测试在混合工作树上运行才通过?Git 的 commit 记录 index 内容,日常测试却通常读取 working tree,这个差异必须显式处理。
一种可靠验收方式是在隔离副本中检出候选提交,使用声明的依赖和最小 fixture 运行门禁。做不到隔离时,至少保证受影响路径没有依赖未暂存 hunk,并在证据里披露限制。验证回执绑定候选 tree 或提交对象;之后再修改内容,旧回执失效。
对特殊改动使用更严格的原子定义
纯重命名与行为变化混在一起会放大 diff,优先先提交无行为重命名并用测试证明;大规模 formatter 也应独立,且只能在获准范围运行。安全修复不要和“顺便升级所有依赖”组合,因为审阅者需要单独判断漏洞边界。删除代码必须同时删除或迁移对应调用、配置和文档承诺,不能把编译错误留给下一提交。
如果一个提交已进入共享历史且发现问题,是否撤销由Revert 与 Reflog 恢复流程按公开影响分类。原子性会让撤销更容易,但不保证业务副作用自动倒转;已经发送的消息、执行的迁移和外部写入仍需单独补偿。
完成一组提交后,从父提交依次重放并检查每一步,而不只检查最终 HEAD。reviewer 应能为每个对象回答:它承诺了什么、为什么需要这些行、运行了哪些证据、单独撤销会留下什么。Vibe Coding 的生成速度只有被切成这种可理解历史,才会成为团队可以维护的速度。
Related