资讯动态

Commit AI 插件开发实录:让 VSCode 用大模型生成规范 git 提交信息

发布时间:2026/10/6 15:24:30 来源:尧图企业网站定制
说实话我写代码这么多年最烦的事情之一就是提交 commit 的时候想 message。代码写得再快到了git commit这一步总要卡一下写“fix bug”太敷衍写太详细又费时间团队规范严一点的还要按 Conventional Commits 的格式来。后来我干脆自己动手在 VSCode 里做了个 Commit AI 插件让 AI 直接读 git diff 生成提交信息一键插进提交框。这篇文章就把这个项目的设计思路、核心实现和实际踩坑记录完整拆一遍如果你也想做类似的工具或者单纯想用 AI 帮自己写提交信息应该能省不少事。先说结论这个插件不是“能生成一句话”就算完真正好用需要解决几个关键问题——diff 怎么截取、prompt 怎么写、结果怎么展示、生成错了怎么改。下面按我自己的实现路径一步步讲。1. 先说清楚Commit AI 到底解决了什么问题1.1 手动写提交信息的真实痛苦很多人觉得 commit message 是小事但真到项目里它就变成了大事。我见过团队里最常见的几种提交信息update、fix、add——完全看不出改了啥回滚的时候只能靠猜写了一大段但全是废话比如“修复了一些问题并优化了代码结构”每个人都按自己的习惯来有人用中文有人用英文有人带 issue 号有人不带。更麻烦的是写提交信息这个动作本身会打断心流。你可能改完一个功能脑子还在想下一段逻辑怎么写突然要切换到“总结这段改动”的语境里这种上下文切换非常消耗精力。AI 生成提交信息最直接的价值就是把这两件事解耦代码你负责写总结交给 AI你看一眼结果对的话就直接提交。1.2 现有方案为什么不够用市面上不是没有现成的工具。VSCode 插件市场里搜“commit”能搜出一堆Conventional Commits 插件只能帮你套模板还是得自己填内容一些收费的 AI 插件也能生成 commit message但我在实际使用中碰到几个痛点生成速度慢有的插件是先生成再弹窗口遇到大 diff 要等十几秒体验很割裂对中文支持差很多模型默认输出英文 commit message团队如果要求中文提交说明还得加参数调不可控有些工具直接把 message 写进暂存区用户没法先编辑确认生成错了很被动隐私顾虑很多团队不允许把代码片段发送到外部接口这个限制直接卡死了不少方案。我想要的不是“最智能的提交信息生成器”而是“能在 VSCode 里无缝衔接 git 工作流、结果可预览可编辑、团队可配置”的工具。所以决定自己写一个。1.3 这个项目的核心目标拆解下来Commit AI 需要满足以下几条一键从当前 git diff 生成提交信息结果先预览不直接写入默认输出符合团队的提交规范比如 Conventional Commits支持自定义 prompt 和模型接口代码不落盘本地可控处理常见异常没有暂存文件、diff 过大、网络超时、权限不足。这几个目标听起来简单真正实现的时候每一环都有坑。下面从设计到实现逐一展开。2. 核心设计拆解从裸 diff 到规范提交信息2.1 整体流程让 AI 只做“总结”这一件事整个插件的核心流程并不复杂一句话可以概括拿到 git diff拼进 prompt发给模型拿到结果展示给用户确认。但其中有三个关键决策点决定了这个工具好不好用。第一个决策是只处理暂存区staged的 diff而不是全部工作区改动。这样做的原因是git 的提交语义就是“把暂存的内容固化到历史里”AI 生成的 message 必须严格对应暂存区的改动。如果有没暂存的文件混进来生成的 message 和实际提交内容就对不上。用户的操作习惯应该是先把要提交的文件git add再调用 Commit AI 生成信息最后git commit。这个流程符合 git 本身的逻辑也让 AI 的输入更干净。第二个决策是结果先预览、可编辑再确认。很多同类插件直接生成并写入我坚持做成“预览-编辑-提交”三步。理由很简单AI 会有幻觉比如根据 diff 推测了一个修复原因但那个原因在代码里其实看不出来。如果直接写入用户还得手动 amend反而更麻烦。让用户先看一遍改一改再提交既保留 AI 的效率也保留人的判断力。第三个决策是生成过程要异步不能卡 UI。模型调用可能要几秒甚至几十秒如果同步阻塞VSCode 的界面会直接卡死用户只能干等着。这里用 VSCode 的window.withProgress加异步请求让用户知道进度同时不打断其他操作。2.2 Prompt 设计是整个项目的大脑prompt 写得好不好直接决定生成结果的质量。我最早的 prompt 特别简单就是“你是一个代码提交助手请根据以下 diff 生成 commit message”结果生成的 message 非常泛什么“fix bugs and improve performance”这种毫无信息量的话都出来了。后来我把 prompt 拆分成了几个部分每一部分都有明确的目的角色设定告诉模型它是什么约束它的行为边界任务说明明确要做什么、输入是什么、输出格式是什么格式约束要求使用 Conventional Commits 格式并给出示例内容范围限定只能根据 diff 中的改动来描述不能脑补语言设置可配置中文或英文输出完整 prompt 大概是这样的这是简化版实际实现比这长一倍你是一名资深 Git 提交信息撰写专家。请根据用户提供的 git diff 生成一条符合 Conventional Commits 规范的提交信息。 要求 1. type 只能从 feat、fix、refactor、docs、test、chore、style、perf、build 中选择 2. 描述要具体说明改了什么、为什么改不要使用 优化代码、修复问题 这类空泛描述 3. 如果 diff 包含多个逻辑改动只总结主要的、有代表性的改动次要改动可以在正文中说明 4. 使用中文描述可通过配置切换 5. 只输出提交信息本身不要输出任何解释性文字 6. 如果有对应的关联 issue可以使用 close #编号 格式但不要在无依据的情况下编造编号 以下是 git diff ${diff}这里 n 是关键限定输出格式比告诉模型“好好写”有效得多。模型是概率生成你给它越具体的约束它越容易遵循。我还踩过一个坑如果不限制标题长度模型经常生成超长的主题行而 git 的惯例是主题行不超过 50 个字符。所以 prompt 里我会加一句“标题不超过 50 个字符”实测效果好了很多。2.3 模型选型与调用参数模型接入方面我做了两层设计默认支持通用的 OpenAI 兼容接口同时考虑通过 Ollama 这类方案接入本地模型。平台方只提供一个“模型名”和“API Key”的配置这样用户可以自由切换。调用参数上有几个值得注意的地方temperature 要调低。commit message 生成不是创意写作是提取式总结温度太高会导致输出不稳定、风格飘忽。我实测在 OpenAI 风格的接口里temperature 调到 0.2 左右效果最好既保留了一点灵活性又不至于跑偏。max_tokens 要限制。commit message 一般不会超过 200 个 token设置 300 足够同时避免模型输出奇怪的冗长内容。timeout 要设置合理值。大模型接口在高峰期可能响应很慢我设置了 30 秒超时超过就报错提示用户重试避免一直转圈。2.4 控制 diff 规模token 预算计算大项目提交时diff 可能特别大直接把整个 diff 塞给模型会撞上 token 上限或者生成质量下降。我在实现里加了一个简单的 token 估算逻辑Diff 的字符数大约按照 4 个字符等于 1 个 token 进行估算模型上下文较大的按 16k 估算小模型的按 8k 估算预留出输出空间。当 diff 超过预算时插件会给出两种处理方式自动截取 diff 的前 N 行N 根据 token 预算换算并在 prompt 里注明“由于 diff 过大当前只提供了部分内容”提示用户手动选择要提交的文件缩小 diff 范围。实际使用下来第一种方式虽然粗暴但大多数情况下够用。因为 commit message 只需要概括主要的改动AI 看前面的 diff 基本能猜个大概。当然也有猜错的时候这就是为什么“预览-编辑”流程是必须的。3. 实操过程从插件原型到真正能用3.1 VSCode 扩展的基础结构做 VSCode 插件本质上是在写一个 Node.js 项目入口是extension.ts通过package.json里的contributes.commands注册命令。我最早的版本只注册了一个命令commit-ai.generateMessage。命令注册好之后在activate函数里绑定执行逻辑。关键代码结构大致这样import * as vscode from vscode; export function activate(context: vscode.ExtensionContext) { const disposable vscode.commands.registerCommand( commit-ai.generateMessage, async () { const diff await getStagedDiff(); if (!diff) { vscode.window.showWarningMessage(没有暂存文件的改动请先 git add); return; } const message await generateCommitMessage(diff); if (message) { await vscode.env.clipboard.writeText(message); vscode.window.showInformationMessage(提交信息已生成已复制到剪贴板); } } ); context.subscriptions.push(disposable); }这里有个小细节我一开始的实现是生成后直接复制到剪贴板让用户自己到 SCM 面板粘贴。但后来发现这个交互太绕了用户在 SCM 面板和剪贴板之间来回切换很繁琐。于是迭代了第二个版本用 QuickPick 展示结果让用户选择“复制”“插入到输入框”或“重新生成”。3.2 获取并处理 git diff比想象中麻烦获取暂存区 diff 在命令行里很容易git diff --cached但在 VSCode 插件里执行 shell 命令需要处理好路径、环境变量、特殊字符编码。我这里用的是 Node.js 的child_process.exec指定cwd为当前工作区目录。有几个隐藏问题中文路径和中文文件名Windows 下如果工作区路径包含中文或者 diff 内容包含中文exec 回传可能乱码。解决方式是设置encoding: utf8并且在exec的环境变量里显式加上LANGen_US.UTF-8macOS/Linux或chcp 65001Windows。非 UTF-8 源码某些老项目是 GBK 编码diff 出来的内容直接带乱码。这个问题没法完美解我的处理是生成 message 之后提醒用户“diff 存在无法识别的编码内容”但尽力保留可读的信息。没有 git 仓库在非 git 项目里调用命令会报错需要提前用git rev-parse --is-inside-work-tree判断。还有一个贴心的小特性如果暂存区没内容但工作区有改动我会给用户一个选项“暂存所有改动再生成”相当于自动执行git add -A。这个在使用中很顺手但也容易误操作所以默认是关闭的需要用户在配置里手动开启。3.3 把 AI 结果优雅地展示给用户提交信息生成出来后怎么展示是另一个影响体验的点。我的方案是用vscode.QuickPick做成一个可选项列表第一项是生成的标题行subject展开后可以查看完整的正文body用户选择一个选项后再进入编辑确认阶段。更贴合场景的做法是把生成的内容写入 SCM 输入框。这就不能直接用 VSCode 提供的通用 API 了需要模拟用户在提交输入框里输入内容。我在实现时通过vscode.commands.executeCommand(workbench.scm.focus)聚焦到 SCM 面板同时把生成的 message 复制到剪贴板然后模拟一次粘贴操作。这个方案不算最优但对 VSCode 的扩展 API 来说已经是实际可行的办法了。实际操作中我发现 QuickPick 有另一个好处它可以展示多行内容。生成结果可能有标题 正文 footer指关联 issueQuickPick 的多行展示可以让用户一眼看清楚完整结构再决定要不要插入。3.4 配置项设计让团队能落地一个好的工具必须可配置尤其在企业团队里“默认行为”和“团队规范”经常不一致。我在插件的配置里开放了这些选项provider.baseUrl模型服务地址provider.apiKeyAPI Key存在 VSCode 的SecretStorage里不写入配置文件provider.model模型名称language中文或英文prompt.customPrompt允许用户覆盖默认 promptgit.autoStage是否允许自动暂存全部改动message.typeScope是否在标题中强制带上 type 和 scope其中API Key 的存储方式值得单独说。很多插件图省事直接存进配置文件同步到 GitHub 后等于是公开泄露。VSCode 提供了context.secrets这个安全存储接口我一开始没注意后来发现配置文件会被提交进仓库才改成了SecretStorage。这也是给所有写 VSCode 插件的人提个醒凡是涉及密钥、token 的都走系统的安全存储。3.5 让模型更懂你的仓库补充上下文纯靠 diff 生成 message 有个天花板diff 里只有改动没有全局视野。比如某次提交把函数foo改名成bardiff 里显示的是删除一堆、新增一堆AI 没有上下文的话会生成“delete useless function”这种完全错误的信息。我后期在 prompt 组装时加入了几个可选的上下文内容当前分支名可以推断这是 feature 还是 hotfix最近几条提交信息让模型模仿本仓库已有的 commit 风格当前项目的语言框架比如检测package.json推断是前端还是后端项目。这些信息不要每次全塞进去而是做“自适应”当 diff 的 token 占用仍然很少时补充上下文当 diff 已经很大时优先保证 diff 完整。这个平衡在工程上很受用。4. 常见问题与排查技巧实录4.1 “没有暂存文件的改动”误报这个最好排查但最频繁。我自己的使用习惯是在 VSCode 里改完代码直接点“源码管理”面板的加号暂存然后再调插件。但有些用户习惯 checkbox 未选中就点命令自然不会有输出。后来我在命令里做了兼容如果暂存区为空就弹出一个选项让用户选择“暂存所有更改”或“取消”。用了这个交互之后误报率直线下降。实现上要注意git add -A会把所有未跟踪文件也加进来如果用户有.env之类的文件没配.gitignore会出现误提交风险。所以我在 UI 上明确提示会执行的操作不悄咪咪做。4.2 AI 生成的提交信息不符合格式最常见的问题有两个type 不在约定的集合里比如生成了chore(deps)但我们团队不用这个 scope或者格式不标准比如没有冒号。这通常不是模型笨而是 prompt 约束不够。我的排查思路是分三步检查是否用了自定义 prompt团队规范是否在 prompt 中明确列出检查温度是否过高超过 0.5 时格式漂移概率大增生成后加一层本地校验用正则检查消息格式不满足就直接提示用户“格式不符”并给一个重新生成选项。其中第三点是最可靠的兜底。格式校验规则可以简单理解为type(scope): subject这个模式可选项根据团队规范配置。4.3 模型响应超时或报错模型接口不稳定是不可控因素。我实现的策略是请求失败后自动重试一次间隔 2 秒如果仍然失败就把错误信息展示给用户并建议检查 API Key 或网络连通性。这里有一个容易遗漏的点错误信息里不应该包含敏感内容。有些接口报错会把请求体里的 diff 一起带回来直接展示给用户有可能泄露代码片段。我处理时会对报错信息做截断只保留错误码和简要原因。网络问题在部分网络环境下可能导致访问外部接口失败但这不是插件能解决的我在 README 里写明了使用条件。团队如果要求代码不出内网更合适的方案是部署本地模型服务接口风格可以兼容VSCode 插件只需要改一个baseUrl配置即可。4.4 和git commit --amend配合使用这个场景我一开始完全没考虑到是用了两周后才意识到的用户生成的信息提交后发现漏改了一个文件就会git commit --amend补进去。这时候 amend 之后暂存区已经空了再点 Commit AI 就会提示“没有暂存文件的变动”。这里有一个细节--amend本身会保留原提交信息不需要重新生成所以插件报“没有暂存改动”其实没错。但我加了一个增强当检测到暂存区为空且当前 HEAD 存在时询问用户是否“基于本次未提交的新改动生成追加说明”。这个功能需要额外小心因为过度自动化反而容易把提交信息搞乱。最终的实现是仅提示用户“建议先 add 需要补充的文件再手动 amend”不自动帮用户修改已有提交信息。4.5 多语言团队的约定问题有的团队要求 commit message 必须用英文有的必须中文还有的混合用。模型默认输出什么语言其实跟 prompt 的措辞强相关。我实测下来prompt 里用中文写“请使用英文输出”模型大概率会切成英文。但如果只有“语言English”这种暗示模型可能还是输出中文。这里我给一个稳定技巧在 prompt 里加“翻译”指令的变体比如请将 commit message 的全部内容翻译为中文。这比“用中文写”更有效因为“翻译”二字隐含了原文的转换动作模型的执行力更强。4.6 生成前忘记先暂存所有需要的文件这是使用习惯问题但每个新手都会踩。解决思路是在命令面板里增加第二个命令commit-ai.stageAndGenerate一键完成“暂存所有改动 → 生成提交信息 → 插入 SCM 输入框”。这条命令在个人项目里非常舒服但在多文件大仓库里要慎重容易把不想提交的文件一起带进去。我自己平时只在小改动场景用这条命令大改动还是手动git add后再生成。最后分享一点我自己的使用心得这套插件我实际用了快两个月最大的体会是AI 生成提交信息不是代替你思考而是替你把“表达”的负担卸掉。代码改动是我自己写的我比模型更清楚为什么这么改所以生成的 message 我通常都会读一遍改一改 scope或者补充一下关联 issue。真正舒服的使用节奏是改完代码、git add、点一下命令、看预览、顺手微调、提交。整个过程从原来的“卡壳十分钟”变成“二十秒收工”。如果你也想做类似的东西我的建议是别一开始就追求大而全。先把“diff → prompt → 生成 → 预览”这条主链路跑通再逐步加上格式校验、团队配置、安全存储这些细节。工具这东西永远是先解决自己的问题顺手解决同行的共同烦恼。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑