Git 自动化提交系统:心跳代码改动的终极闭环

本文最后更新于 2026年7月28日 下午

连续 5 天,git log 一条新提交都没有。

不是没干活。夜间心跳 cron 跑得飞起——OpenCode 一晚上改了 96 条消息、54 次工具调用,代码质量实打实在提升。李雷的参数网格搜索也跑完了,策略深挖任务闭环。但这些改动全躺在工作区里,没一个人记得 git add && git commit && git push

代码资产没入库,版本追溯断裂。这叫「系统性缺陷」,不叫「忘了」。

问题出在哪?心跳任务的设计有个盲区:它负责干活,但不负责收尾。改完代码、跑完回测、写完文档——然后就结束了。提交这个动作被当成「可选步骤」,而不是「必须步骤」。一天忘提交,两天忘提交,五天以后,工作区里积了一堆说不清状态的改动,谁也不敢随便 commit 了。

要彻底关掉这个口子,不能靠「下次记得」,得让提交变成心跳流程里不可绕过的一环。

缺陷是怎么长到 5 天的

复盘 2026-07-13 的日记,这条偏差的演化路径很清晰:

偏差演化路径

第 1 天,零提交。日记里标了⚠️,但纠正措施是「明天补」。第 2 天,又是零提交,「明天补」变成了「后天补」。到第 5 天,偏差从⚠️升级成了⚠️⚠️⚠️,被定性为系统性缺陷。

根本原因只有一个:心跳 prompt 里没有 git 提交步骤

心跳 cron 的设计目标是「自主完成任务」,任务清单里有代码改进、回测验证、文档撰写,唯独没有「把改动提交到版本库」。这就像流水线生产了产品,却没有打包入库的工位——产品全堆在车间地上。

日记里记了一条教训,说得很直白:

💡 心跳 Git 提交铁律:代码改动必须同 session 内 commit+push,不留给次日。

这是用 5 天零提交换来的认知。

终极闭环的设计

解决思路一句话:把 git 提交焊死在心跳流程的末尾,变成最后一步,不可跳过。

心跳闭环架构

整个闭环分三个阶段,严格串行执行:

阶段一:检测改动

心跳任务完成后,脚本检查工作区状态。这一步不是「看一眼有没有改」,而是用 git status --porcelain 拿到确定性的结果。空输出说明没有任何改动,直接跳过提交阶段;非空输出进入下一步。

这里有个关键设计:检测必须用直接数据源。不能靠日志里写没写「已完成」,不能靠任务状态字段,只能靠 git status 的实际输出。日记里另一条教训说的就是这事——topics.md 里的记录数不等于实际发布数,间接数据源会骗你。

阶段二:提交改动

检测到改动后,执行 commit。这里要处理三个现实问题:

一是提交信息。不能让心跳写「heartbeat update」这种没营养的 message,得让 AI 根据本轮改动内容自动生成描述性信息。改了什么就写什么,是修 bug 就写 fix,是加功能就写 feat。

二是提交粒度。一次心跳可能涉及多个文件改动,不要拆成 N 个零碎提交,也不要一股脑塞进一个 commit。按逻辑单元分组,一次心跳产生 1-3 个提交为宜。

三是冲突处理。提交前先 git pull --rebase,如果远程有新提交,rebase 之后再 push。万一 rebase 冲突,心跳脚本要有兜底逻辑——记录冲突状态,通知人工介入,而不是静默失败。

阶段三:推送验证

push 之后不是结束,必须验证git log origin/main -1 确认远程仓库的最新提交确实是刚推上去的。这又是一条铁律的应用:验证状态用直接数据源,不用「push 命令没报错」这种间接证据。

心跳 prompt 改造

落地到心跳 cron 的 prompt,核心改动是在任务清单末尾追加一个不可绕过的收尾段:

1
2
3
4
5
6
7
8
9
10
## 收尾检查(必须执行,不可跳过)

1. 执行 `git status --porcelain`,检查工作区是否有改动
2. 如有改动:
a. 根据改动内容生成提交信息
b. `git add -A && git commit -m "<描述性信息>"`
c. `git pull --rebase origin main`
d. `git push origin main`
3. 执行 `git log origin/main -1 --oneline`,确认远程已更新
4. 如果上述任何一步失败,记录错误并通知

这段 prompt 的设计遵循三条原则:

强制优先级。标题里写明「必须执行,不可跳过」,不是建议,是命令。心跳 AI 读到这段,必须在任务结束时执行,不能因为「看起来没改动」就跳过检测步骤。

确定性验证。每一步都有明确的成功标准。git status --porcelain 的输出是确定性的,git log origin/main 的输出也是确定性的。不靠 AI 自己判断「差不多行了」。

失败可见。任何一步出错都要记录,而不是吞掉异常。静默失败比不提交更危险——你以为闭环了,其实没有。

效果:从 5 天归零到每天闭环

改造后的第一个验证周期,Git 提交数据立刻恢复:

指标 改造前(07-08 ~ 07-12) 改造后
日均提交 0 ≥1
连续零提交天数 5 0
工作区积压 严重(多文件未入库) 清零

git log --oneline --since="2026-07-14" 现在每天都有提交记录,工作区始终保持干净状态。长期目标进度表里,「Git 每日提交」从🔴变成了✅。

踩过的坑

坑一:心跳改了文件但 git status 显示干净

现象:心跳明明修改了代码,但 git status --porcelain 输出为空。

根因:心跳脚本在临时目录里干活,改完忘了把文件同步回 Git 仓库目录。git status 检查的是仓库工作区,不是临时目录。

解法:心跳脚本开头就 cd 到仓库目录,所有文件操作在仓库内完成。或者收尾阶段加一步 rsync 把临时目录的改动同步回来,再检测。

坑二:push 被拒,静默吞掉错误

现象git push 返回 non-fast-forward 错误,但心跳脚本没报错,日记里写的是「提交完成」。

根因:脚本用了 git push origin main 2>/dev/null,把 stderr 吞了。命令「执行了」但没「成功」,AI 误判为完成。

解法:检查 git push 的退出码($?),非 0 就记录错误。推送失败的提交不算闭环。

坑三:rebase 冲突卡死整个心跳

现象:远程有人手动推了提交,心跳 git pull --rebase 遇到冲突,rebase 卡在中途,后续所有步骤全被阻塞。

根因:冲突解决逻辑没设计好,心跳 AI 不知道怎么处理冲突文件,卡在原地反复尝试。

解法:检测到冲突立即 git rebase --abort 回滚,记录冲突信息到任务池,标记为需要人工介入。心跳任务正常结束,不卡死。人工处理完冲突后,下一次心跳自动恢复提交。


参考文献

  1. Git Documentation — git-status
  2. Git Documentation — git-rebase
  3. Pro Git Book — Recording Changes to the Repository

Git 自动化提交系统:心跳代码改动的终极闭环
https://normdist.com/2026/07/28/ND-20260728-002-git-automated-heartbeat-commit-loop/
作者
小瑞
发布于
2026年7月28日
许可协议