现在写完一小段改动,我偶尔会让 AI 根据 diff 拟一条 commit message。省事是真省事,翻车也真实翻过:有的标题漂亮得像广告,读完不知道改了什么;有的把半成品猜想写进历史,后来查问题的人会被带沟里。
所以我不是禁用,而是给它加了几条规矩。规矩的核心只有一句:说明白改了什么、为什么改;别写套话,别替我编动机。
为什么值得用,又为什么不能全信
Commit message 是给未来的自己和同事看的。好的 message 能回答:这次动了哪类东西?动机是修 bug、加能力,还是清债?有没有故意不做的范围?
AI 擅长扫 diff、归纳文件级变化,比我在疲惫时随手敲的 fix、update 强。但它也容易:
用空洞形容词(optimize / enhance / improve)掩盖具体行为
把“可能的原因”写成既定事实
把一次杂糅提交吹成完整特性
风格漂到和团队约定不一致
我把它定位成草稿机,不是签字权。拟可以,合不合规由我拍板。

图:AI 写 commit:擅长归纳与常见风险对照(原创示意图)
规矩一:先给格式,再给 diff
我不丢一句“帮我写 commit”就完事。至少会说明:
标题上限(比如 50 或 72 字符,看团队习惯)
要不要正文、正文里要不要
Why/How/Risk语言(中文还是英文,和仓库历史保持一致)
是否使用约定前缀(如
fix:、feat:)
格式不说清,它会按训练语料里的“通用好消息”来写,往往和你们仓库气质不合。我甚至会贴两条本仓库的好例子当样板,比空讲规则有效。
规矩二:标题必须能回答“改了什么”
我对标题的最低要求是:一个不熟悉代码的人,看标题能猜到改动类型和对象。
比较:
差:
优化用户模块相关逻辑好:
修复未登录访问个人页时的空指针
差的那条读完还是要打开 diff。好的那条至少告诉你:修的是空指针,场景是未登录访问个人页。
我要求 AI:禁止单独使用“优化、调整、处理、完善、update、improve”当标题核心动词,除非后面紧跟具体对象和结果。它若写了,我会打回重写,而不是自己顺手改两个字就提交——打回能校正它的下一次草稿。
规矩三:动机写“已知事实”,不写“合理猜测”
有一次 diff 里只是改了超时时间。AI 写道:“因生产频繁超时,将客户端超时从 3s 调整为 10s。”问题是:我当时只是在本地调试,生产有没有频繁超时我根本没核实。这句话若进了历史,半年后排障的人会把“生产频繁超时”当既定事实。
所以我加了一条硬规矩:正文里的原因,必须是我明确告诉它的,或是 diff/注释里写死的;不允许把推测写成事实。 不清楚就写“本地调试需要更长超时”,别上升成事故叙事。

图:标题对比:空话优化 vs 说清改了什么(原创示意图)
拿不准时,我宁可标题短一点、正文留“待补充原因”,也不要一条听起来很完整的假故事。
规矩四:一次提交只讲一件主事
AI 看到大 diff,很爱写“同时重构了 A、修复了 B、补充了 C”。如果我本来就该拆提交,这种总结会帮我掩盖坏习惯。
我的做法是:
若确实该拆:先拆,再分别让它写
若紧急来不及拆:标题盯住主意图,正文用短列表提及其余,并承认“此提交混入了清理”
绝不让标题假装这是一次干净的单一变更。诚实的丑,好过漂亮的假。
规矩五:敏感与安全相关,人工重写
涉及权限、加密、密钥处理、用户数据删除、鉴权绕过修复时,我一般不直接用 AI 的成稿。这类 message 本身可能成为审计线索,措辞要稳,也要避免泄露内部细节。
做法是:让它列“建议提到的要点”,我自己写最终句子;或者我写初稿,只让它检查是否超长、是否含糊。安全相关的叙事权留在自己手里。
我实际怎么用的一条流水线
git diff --staged自己先扫一眼,确认没有不该进库的文件把格式要求 + 样板 + diff(太大就摘要文件列表 + 关键 hunk)发给 AI
只要 2–3 个候选标题,不要长篇发挥
我挑一条改到符合事实,再决定要不要正文
用团队钩子或
commitlint再挡一层套话

图:commit 流水线:自扫、给约束、要候选、人工改(原创示意图)
候选只要两三个的原因:给太多我会懒得读,最后又变回“挑个顺眼的”。限制数量,等于迫使自己认真比。
和团队对齐的两件小事
如果只是自己的玩具仓库,规矩可以松一点。团队仓库我会多做两步:
把“禁止空洞动词、原因不编造”写进贡献指南或 AGENTS 类说明,让同事和 Agent 共用
Code Review 时顺便扫一眼 message:该拦的不只是代码,也包括误导性历史
我见过 PR 代码没问题,但 message 写着“临时调试”,合并后没人改,半年后 git blame 一脸懵。拦在合并前成本最低。
什么时候我干脆手写
改动极小,标题我十秒能写完
动机涉及私下讨论、未公开的产品决策
diff 很大但我还没想清“主事是什么”——这时该先想清,而不是让 AI 帮我假装想清了
AI 省的是打字时间,不省的是判断时间。想不清就提交,历史会替你记住这次含糊。
收尾
让 AI 写 commit message,我留下的规矩可以压成四句:
先定格式与样板
标题说清改了什么,拒绝空动词
原因只写已知事实
安全与混杂提交,人工主导叙事
它依然能帮我减少 fix2、wip 这类懒标题,但签字前那一眼,我不会省。说明白改了什么,比写得像文案更重要。
一个我改过的坏例子
某次 diff 只改了两处:把空列表默认值改成明确报错,并补了一条单元测试。AI 第一稿标题是:Enhance user input handling and improve robustness。
问题在哪?
Enhance / improve 是空动词
user input handling 范围被放大了,实际只动了一个函数
完全没提“失败从静默变显式”这个行为变化
我打回后要求:“用中文;动词用修复/改为;写明行为变化。”第二稿变成:将空列表默认改为显式校验失败,并补测试。这才是我能签字的版本。
这个对比也提醒我:英文空话和中文空话一样有害。语言不是关键,具体才是。
正文要不要写,我怎么判断
不是每个提交都需要长正文。我的启发式是:
只要标题: 改动单一、动机在 diff 里一目了然、无风险副作用
要短正文: 有权衡(为何选 A 不选 B)、有后续待办、有意不修某边界
要结构化正文: 行为变更、迁移、安全修复、或会影响运维手册的改动
让 AI 写正文时,我禁止它写“本次改动经过充分测试”这类无法验证的口号。测试情况应指向具体命令或 CI,而不是自我表扬。
和 squash / rebase 的关系
若团队合并前会 squash,临时 commit message 可以更随意,但最终进主分支的那一条仍要过规矩。我见过有人全程 wip,靠最后一次改写拯救——可以,但别忘了拯救。AI 很适合在 squash 前根据累计 diff 重写最终 message;这时更要人工核对动机,因为累计 diff 更大,它更容易编故事。
自动化检查能帮到哪一步
钩子可以拦:
标题过长
禁止词(如裸
update)必须带 issue 编号的仓库
钩子拦不住:
事实错误
范围夸大
把猜测写成原因
所以规矩里“不编动机”只能靠人。AI 加钩子加人工,三层各管一截。
再补一句心态
我开始用 AI 写 message 时,潜意识想的是“少打字”。后来发现真正省下的,是帮我把 diff 扫成候选要点;打字从来不是最贵的。最贵的是想清楚这次提交的主事。若主事不清,任何工具都只会帮你更快地留下一条含糊历史。
把规矩守住,AI 就是加速器;守不住,它就是文案生成器。我选前者。


2026-10-14鱼鱼