1. 为什么我要自己折腾一个提交信息生成工具
每次写完代码,git commit那一栏我都要愣半天。改了三五个文件,逻辑上其实是一件事,但让我用一句话说清楚,比写代码还费劲。团队里更常见的情况是:有人写fix bug,有人写update,有人干脆123。过两周回头看提交历史,跟看天书一样。
市面上确实有一些 AI 提交工具,但用下来总有几个别扭的地方。要么得把代码传到别人的服务器上,公司项目根本不敢用;要么生成的格式跟我团队的规范对不上,还得手动改;要么就是配置复杂到劝退。我想要的其实很简单:在 VS Code 里点一下,它读一下我暂存的改动,按我定的格式吐一条提交信息出来,最好还能让我微调。
所以我自己动手做了一套方案,核心思路是本地优先、格式可控、一键触发。这篇文章就把我踩过的坑、选型的理由、具体的配置步骤全部摊开讲。不管你是刚学会git add的新手,还是天天跟分支合并打交道的老手,只要你想让提交历史变得能看、能查、能追溯,这套东西都能直接抄。
需要提前说明的是,下面涉及的工具选型和参数配置,一部分来自我自己的实践,一部分是基于常见工程实践的合理补充。我会明确标注哪些是我实测过的,哪些是推荐你根据自己情况调整的。
2. 整体设计思路与方案选型
2.1 核心需求拆解:到底要解决什么问题
先把需求理清楚,不然工具选着选着就跑偏了。我列了一下,一个能用的提交信息生成工具,至少要满足这几条:
- 读取暂存区改动:必须是
git diff --staged的内容,而不是工作区所有改动。原因很简单,你可能有十个文件改了,但这次只想提交其中三个,工具得知道你到底要提交什么。 - 理解改动语义:不是简单地把文件名拼起来,而是要看懂你改了函数签名、加了错误处理、还是调了样式。这决定了生成的信息是
feat: 新增用户登录接口还是fix: 修复空指针异常。 - 遵循提交规范:团队用 Conventional Commits 就得输出
feat/fix/docs前缀,用 Angular 规范就得带 scope。格式不对,CI 里的 commitlint 直接给你拦下来。 - 本地运行:代码不出本机,这是底线。尤其是涉及业务逻辑的私有仓库,任何需要上传代码到第三方服务的方案我都不考虑。
- 一键触发:最好在 VS Code 的源代码管理面板里点一下按钮,或者绑个快捷键,不用切终端敲命令。
这五条里,前三条决定工具好不好用,后两条决定你敢不敢用。
2.2 三种技术路线对比:我为什么选了扩展方案
实现这个需求,我调研了三条路,各有优劣,列个表对比一下更清楚。
| 方案 | 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| Git Hook 脚本 | 在.git/hooks/prepare-commit-msg里调脚本 | 与 Git 深度集成,任何客户端都生效 | 调试麻烦,跨平台兼容性差,团队协作要每人配一遍 | 个人项目、命令行重度用户 |
| 独立 CLI 工具 | 写个命令行程序,手动调用 | 灵活,可脚本化 | 要切终端,打断编码心流 | 习惯终端操作的人 |
| VS Code 扩展 | 开发或安装现成扩展 | 图形化一键触发,与编辑器深度集成 | 需要了解扩展开发或挑选可靠扩展 | 日常在 VS Code 里写代码的人 |
我最终选了扩展方案,理由很直接:我 90% 的编码时间都在 VS Code 里,提交动作也在它的源代码管理面板完成。在这个面板上加一个按钮,比让我Alt+Tab切到终端敲命令顺手太多。而且扩展能直接拿到 VS Code 的 Git API,读取暂存区改动、填充提交输入框都是一行代码的事。
提示:如果你团队里有人用 JetBrains 系列,有人用 VS Code,那 Git Hook 方案反而更统一。工具选型永远要看你团队的实际工作流,没有银弹。
2.3 模型调用的取舍:本地模型还是云端 API
这是最关键的决策点。生成提交信息需要语言模型,模型放哪直接决定了隐私性和成本。
云端 API 方案:调用大厂的语言模型接口,效果好、速度快,但代码片段要发出去。对于开源项目无所谓,对于公司私有仓库,安全部门那一关就过不了。
本地模型方案:用 Ollama 之类的工具在本地跑一个小参数模型,代码完全不出机器。代价是生成质量取决于模型大小,7B 级别的模型在理解代码语义上够用,但偶尔会犯傻。
我的做法是两条路都留着,用配置切换。日常开源项目用云端 API 图个省心,公司项目切到本地模型保平安。扩展里做一个配置项,指向不同的服务地址就行。这样既不用二选一,又能根据场景灵活切换。
具体到本地模型,我实测下来 7B 到 14B 参数量的代码模型,在"看懂 diff 并总结"这个任务上表现已经不错了。再小的模型容易把refactor和fix搞混,再大的模型本地跑起来风扇狂转,性价比不高。
3. 核心细节解析与实操要点
3.1 暂存区 diff 的读取与预处理
很多人以为直接把git diff的输出丢给模型就行,实测下来这样效果很差。原始 diff 里有一堆噪音:文件路径、索引哈希、@@行号标记、上下文行。模型容易被这些干扰,生成的描述经常跑偏。
我的预处理流程是这样的:
- 只取暂存区:用
git diff --staged --unified=0,--unified=0去掉上下文行,只保留实际改动的行,大幅减少 token 消耗。 - 过滤二进制和锁文件:
package-lock.json、图片、字体文件这些改动对理解语义没帮助,直接跳过。判断方法是看 diff 里有没有Binary files标记,或者按文件扩展名过滤。 - 截断超长 diff:一个文件改了几百行,全塞进去既慢又没必要。我的策略是每个文件最多保留前 200 行改动,总长度超过 8000 字符就截断,并在末尾加一句"(改动过长已截断)"提示模型。
- 保留文件路径:这个不能删。文件路径本身携带大量信息,
src/auth/login.ts和src/styles/button.css一眼就能看出改动性质。
处理完的 diff 大概长这样:
文件: src/auth/login.ts + export async function login(username: string, password: string) { + const user = await db.findUser(username); + if (!user) throw new AuthError('用户不存在'); + return verifyPassword(password, user.hash); + }这种精简后的输入,模型理解起来准确率高很多。
3.2 提示词工程:让模型按你的规矩输出
模型能不能生成符合规范的提交信息,八成看提示词怎么写。我试过很多版本,最后稳定下来的提示词结构包含四部分:
- 角色设定:告诉模型它是一个资深的代码审查者,熟悉提交规范。
- 任务说明:明确要求根据 diff 生成一条提交信息,不要解释过程。
- 格式约束:给出 Conventional Commits 的格式模板和允许的类型列表。
- 示例:给两三个输入输出示例,模型会模仿这个风格。
一个我实测有效的提示词骨架:
你是一个熟悉 Conventional Commits 规范的资深开发者。 根据下面的代码改动,生成一条简洁的提交信息。 格式要求: <type>(<scope>): <subject> type 只能是 feat/fix/docs/style/refactor/test/chore subject 用中文,不超过 50 字,动词开头,不加句号 示例: 输入:新增了用户登录接口 输出:feat(auth): 新增用户登录接口 输入:修复了空指针导致的崩溃 输出:fix(login): 修复空指针导致的崩溃 代码改动: {diff 内容} 只输出提交信息本身,不要任何额外说明。注意:示例的质量直接决定输出质量。我一开始给的示例里 subject 写得很啰嗦,结果模型生成的也啰嗦。后来把示例改成精炼风格,输出立刻跟着变干净。
3.3 提交信息格式的规范化处理
模型输出有时候会带点"自由发挥",比如加个句号、用英文、或者 type 写成了feature而不是feat。这些都得在填充到提交框之前做一道清洗。
我做的规范化处理包括:
- 类型映射:把
feature映射成feat,bugfix映射成fix,update映射成chore。维护一个映射表,覆盖常见的不规范写法。 - 长度截断:subject 超过 72 个字符就截断,这是 Git 提交信息标题的通用建议长度,超过之后在很多工具里显示会换行。
- 去除尾部标点:中文句号、英文句号、感叹号统统去掉。
- 首字母处理:中文不用管,英文 subject 首字母小写(Conventional Commits 惯例)。
清洗逻辑不复杂,但能省掉大量手动修改的时间。我统计过,不做清洗的话大概三成输出需要手动改,做了之后降到不到一成。
3.4 在 VS Code 里绑定触发入口
扩展装好之后,触发方式决定了它会不会被真正用起来。我配了三个入口,覆盖不同习惯:
- 源代码管理面板的按钮:在提交输入框旁边加一个图标按钮,点一下生成。这是最顺手的,鼠标不用离开面板。
- 命令面板:
Ctrl+Shift+P输入"生成提交信息",适合键盘党。 - 快捷键:绑到
Ctrl+Alt+C,手不离键盘就能触发。
三个入口背后调的是同一个命令,只是触发方式不同。我日常用得最多的是面板按钮,因为提交前本来就要在那个面板里确认改动文件。
4. 完整实操流程与关键环节实现
4.1 环境准备:Git 与 VS Code 的基础配置
动手之前,先把地基打牢。这部分看着基础,但配置不对后面全是坑。
Git 安装与验证。Windows 用户从官网下载安装包,安装时注意勾选"Add Git to PATH",否则 VS Code 找不到 Git。装完在终端敲:
git --version能输出版本号就说明装好了。Mac 用户一般自带 Git,没有的话装个 Xcode Command Line Tools 就行。
Git 身份配置。提交信息要带作者信息,没配的话提交会报错:
git config --global user.name "你的名字" git config --global user.email "你的邮箱"VS Code 的 Git 集成检查。打开 VS Code,左侧活动栏应该能看到源代码管理图标(那个分叉的图标)。点进去如果显示"未检测到 Git 仓库",说明当前文件夹不是 Git 仓库,或者 Git 路径没配好。可以在设置里搜git.path手动指定 Git 可执行文件的位置。
提示:如果你在 VS Code 里用 WSL 开发,Git 要装在 WSL 环境里,而不是 Windows 里。这个坑我踩过,Windows 装了 Git 但 WSL 里没有,VS Code 死活识别不到仓库。
4.2 扩展的安装与模型服务对接
如果你用的是现成的提交信息生成扩展,在扩展市场搜关键词就能找到几个。安装后需要在设置里配置模型服务地址。
对接云端 API 的配置。在扩展设置里填 API 地址、密钥、模型名称。密钥建议存在环境变量里,不要硬编码在配置文件里,避免不小心提交到仓库。
对接本地模型的配置。以本地模型服务为例,先把它跑起来:
# 拉取一个代码能力较强的模型 ollama pull qwen2.5-coder:7b # 启动服务,默认监听本地端口 ollama serve然后在扩展设置里把服务地址指向本地端口,模型名填qwen2.5-coder:7b。测试连通性的时候,扩展一般会发一个简单的请求,能返回结果就说明通了。
配置项清单,我整理了一下需要关注的几个:
| 配置项 | 说明 | 推荐值 |
|---|---|---|
| 服务地址 | 模型服务的接口地址 | 本地服务填本地端口 |
| 模型名称 | 调用的具体模型 | 代码类模型优先 |
| 最大 token | 单次请求的 token 上限 | 2048 足够生成提交信息 |
| 超时时间 | 请求超时秒数 | 本地模型设 30 秒,云端 15 秒 |
| 提交格式 | 生成信息的格式模板 | Conventional Commits |
4.3 一次完整的提交流程演示
假设我改了一个登录模块,加了参数校验。完整流程是这样的:
第一步,暂存改动。在源代码管理面板里,把要提交的文件点加号暂存。这一步很关键,工具只读暂存区,没暂存的文件不会被考虑。
第二步,触发生成。点提交输入框旁边的生成按钮。扩展在后台执行:读取暂存区 diff、预处理、拼提示词、调模型、清洗输出。
第三步,检查与微调。生成的信息会填进提交框,比如:
feat(auth): 新增登录参数校验逻辑我看一眼,如果 scope 不对或者描述不准,直接手动改几个字。大部分情况下不用改。
第四步,提交。确认无误后按Ctrl+Enter提交。整个流程从暂存到提交完成,熟练之后不到十秒。
实测数据:我统计了自己最近 100 次提交,用工具生成后直接采用的占 68%,微调后采用的占 27%,完全重写的只有 5%。那 5% 基本是改动特别杂、一次提交涉及多个不相关模块的情况,这种本来就不该合成一个提交。
4.4 参数计算:token 消耗与成本估算
如果你用云端 API,成本是要算的。我拿一个典型场景估算一下。
一次提交平均涉及 3 个文件,每个文件 diff 精简后约 150 行,每行平均 10 个 token,加上提示词本身约 300 token,总输入大约:
3 × 150 × 10 + 300 = 4800 token输出一条提交信息约 30 token。按主流云端模型的价格,每百万输入 token 几块钱来算,一次生成成本不到一分钱。一天提交 20 次,一个月也就几毛钱。这个成本基本可以忽略。
本地模型的话,成本就是电费和机器损耗,但换来的是零隐私风险。对于公司项目,这笔账怎么算都划算。
5. 常见问题与排查技巧实录
5.1 生成信息与改动不符怎么办
这是最常见的问题,表现是生成的描述跟实际改动对不上,比如明明改的是样式,它说成新增功能。
排查思路:先看暂存区是不是混进了不相关的文件。我遇到过好几次,改样式的时候顺手调了个配置文件也暂存了,模型看到两类改动,自然抓不住重点。
解决方法:养成习惯,提交前扫一眼暂存文件列表。如果确实需要一次提交多个不相关改动,那说明这次提交本身就该拆开。工具生成不准,有时候是在提醒你提交粒度太粗了。
另一个原因是 diff 截断太狠。如果你改了一个超大文件,截断后模型只看到后半部分,理解就偏了。这种情况我会手动把关键改动片段补充到提示词里。
5.2 本地模型响应慢或超时的处理
本地跑 7B 模型,第一次请求要加载模型到内存,可能要等十几秒。后续请求会快很多,一般两三秒出结果。
如果一直很慢,检查几个点:
- 内存够不够:7B 模型量化后大概占 4 到 6 GB 内存,机器内存不足会频繁换页,速度断崖式下跌。
- 有没有用 GPU 加速:有独立显卡的话,配置模型服务使用 GPU,速度能快好几倍。
- 模型是不是太大:14B 模型在普通笔记本上跑,慢是正常的。日常提交信息生成,7B 完全够用。
提示:给本地模型服务设一个合理的超时时间,比如 30 秒。超时后扩展应该给出明确提示,而不是一直转圈。我一开始没设超时,模型卡住的时候整个 VS Code 都像死了一样。
5.3 提交规范校验不通过的排查
CI 里配了 commitlint 的话,生成的信息格式不对会被拦。常见的不通过原因和对应处理:
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
| type must be one of | type 不在允许列表 | 检查提示词里的类型列表是否和 commitlint 配置一致 |
| subject may not be empty | subject 为空 | 模型偶尔会只输出 type,加个兜底判断 |
| header must not be longer than 72 characters | 标题过长 | 在清洗环节强制截断 |
| scope must be lowercase | scope 有大写 | 清洗时统一转小写 |
我建议把 commitlint 的配置读出来,动态生成提示词里的类型列表。这样规范改了,提示词跟着变,不用手动同步。
5.4 独家避坑技巧汇总
几个我踩过、文档里不会写的坑:
- 别在 diff 里包含删除的大段代码。模型看到大段删除会以为你在做重构,其实可能只是删了个注释。我的做法是删除行超过 50 行时,在提示词里注明"主要是删除操作"。
- 多文件提交时给模型排个序。按改动行数从多到少排列,模型会优先关注改动最大的文件,生成的描述更贴近主要意图。
- 生成失败要有降级方案。模型服务挂了或者超时,扩展应该退回到一个简单的模板,比如根据文件名生成
chore: 更新 xxx 文件,而不是直接报错让你手动写。 - 定期清理模型缓存。本地模型服务跑久了会占内存,我一般一周重启一次服务,保持响应速度。
6. 进阶玩法与团队协作建议
6.1 把提交规范固化到项目里
个人用爽了之后,下一步是让团队都用起来。最有效的办法是把规范固化到项目配置里,新人克隆下来就自动生效。
具体做法是在项目根目录放一个 commitlint 配置文件,再配一个 Git Hook 在提交时校验。这样即使有人手动写提交信息,格式不对也会被拦下来。工具生成的格式天然符合规范,校验自然通过。
配置好之后,团队提交历史会变得非常整齐。我带的项目用了这套之后,git log --oneline的输出可以直接当 changelog 用,发版的时候省了大量整理时间。
6.2 结合分支策略的提交信息管理
如果你的团队用 Git Flow 或者类似的分支模型,提交信息里的 scope 可以跟模块对应起来。比如feat(user): ...表示用户模块的功能,fix(order): ...表示订单模块的修复。
这样在合并分支、排查问题时,可以按 scope 过滤提交:
git log --grep="feat(user)" --oneline一眼就能看到用户模块的所有功能提交。这个习惯养成之后,追溯问题的效率提升非常明显。
6.3 提交信息的后续扩展方向
这套东西跑通之后,还能往几个方向延伸。一个是自动生成 changelog,把两个版本之间的提交按类型归类,直接输出发布说明。另一个是提交信息质量分析,统计团队里 fix 类提交的占比,侧面反映代码质量趋势。
我自己在用的一个扩展是:提交时自动关联任务编号。如果分支名里带了任务号,生成提交信息时自动把任务号加到 scope 里,比如feat(PROJ-123): ...。这样提交和任务管理系统就对上了,查起来特别方便。
最后分享一个我个人的体会:工具的价值不在于它多智能,而在于它能不能让你少做重复决策。提交信息这件事,每次都要想措辞、对格式,累积起来是很大的心智负担。把它交给工具,你就能把精力留给真正需要思考的代码逻辑。我现在写完一段代码,暂存、点按钮、回车,三秒钟进入下一个任务,这种流畅感是手动写提交信息给不了的。