
我见过太多项目的提交记录了第一条是“fix”第二条还是“fix”第三条终于变了——“update”。等到某天线上服务出问题你想通过 git log 定位是哪次改动引入了 bug对着那一屏的“fix”“update”复盘到想摔键盘。类似这种场景经历几次之后你就不会再觉得“commit 信息随便写写就行”是件无所谓的事了。今天想聊的就是一个极小但极实用的 Git 原生功能——commit.template也就是在每次提交时自动带入一套注释模板。配置好之后只要你执行 git commit编辑器里就会自动加载你写好的模板文件引导你把提交类型、改动范围、变更原因、关联 Issue 这些信息填完整。它不需要安装任何额外插件也不依赖特定的 Git 客户端一套配置团队通用几乎零成本就能把“随手写提交信息”变成“规范填提交信息”。这篇内容我会讲清楚它的原理、模板怎么设计、完整配置流程以及我把这套东西在多个团队里落地时踩过的坑。从零开始的话大概十五分钟就能搞定之后你每次提交都会有一个标准格式的引导框架。如果你正被乱七八糟的提交历史折磨或者想在团队里推行提交规范这篇文章应该能直接帮你落地。1. 提交信息这件事比你想象的重要很多开发者的习惯是代码写完git add 之后随手 git commit -m fix bug 就完事了。项目小的时候还好但一旦代码量上来、参与的人变多这种“欠债式”提交记录会让整个项目变得非常难维护。1.1 提交信息如何决定你对项目历史的可读性提交信息本质上是项目历史的“目录表”。你回滚代码、排查性能回归、做版本发布的时候都是靠它来定位每一次改动的。它写得好不好直接决定了三个月后的你——以及接手你代码的同事——能不能快速理解这次提交做了什么。我遇到过最典型的一次事故新同事入职接手一个维护了三年的老项目负责人让他先看一下 git log 了解项目演进。结果日志拉出来从 2023 到 2024 一整年提交信息基本就是“update”“fix”“dev”这几个词来回换。他根本不知道哪个版本引入了什么功能哪个提交修复了什么问题只能对着代码逐行猜。最后是重新梳理了整个里程碑才勉强上手。还有一个指标可以直接反映这个问题你上一次通过 git blame 找一行代码是谁在什么时候改的花了多少时间如果提交信息足够清晰定位到那次改动的上下文往往只需要几秒钟。否则你就要先看 diff再反查相关的合并记录再猜当时提交的人脑子里在想什么——这一套下来少说十分钟起步。1.2 从 commitlint、husky 到 commit.template先分清工具的分工不同的人听到“提交规范”这个主题可能会联想到不同的工具。这里先把概念理清楚它们解决的是不同环节的问题commitlint核心职能是“拦截”在提交后、push 前对提交信息做格式校验不符合规范就直接报错阻止提交。它解决的是“规范底线”的问题属于强制措施。huskyGit hooks 的管理工具本质是把你写的脚本挂到 Git 的事件上方便在 pre-commit、commit-msg 等阶段跑自动化任务是 commitlint 的“宿主”。commit.template核心职能是“引导”解决的是“不知道怎么填、随便填”的问题。它不会拦你只是在你提交时把模板自动展开到编辑器里提供一个填写框架。三者的关系可以用一个例子说清楚commit.template 是考试发草稿纸让你知道火箭怎么画commitlint 是监考老师看你画的到底像不像火箭。很多团队直接上 commitlint 强制校验但成员仍然经常写出“五花八门”的格式来根本原因在于大家不知道怎么写才算标准只记住了“要是不符合规范就会被拦下来”。要是先配好 commit.template在源头让每个人都看到该填什么后面的强制校验就会顺畅很多。所以我的建议是先配置好这个引导模板再考虑要不要加校验工具。2. 设计一套适合自己的提交模板commit.template 的原理很简单它就是一个文本文件里面是你要带入提交编辑器的“底稿”。真正要花心思的是模板内容本身——怎么设计才能既引导成员写出规范信息又不会让觉得填写成本太高反触发抵触情绪。2.1 提交类型怎么定才不过度设计方案一照搬社区流行的“Angular 约定”方案二自己在网上抄一段别人团队的模板。两种都可以但不一定适合你们团队。我见过有团队把 type 定义了二十几种提交一条代码要纠结半天该选哪种——这就是过度设计。我的建议是中小型团队保留八到十个最常见的类型就够了。下面是我在多个项目里稳定落地的一套feat新功能绝大多数新增需求都归这一类fix修复 bugdocs文档变更比如 README 更新、注释调整style不改变逻辑的样式调整比如空格、格式化、缺失分号refactor不改变功能行为的代码重构perf性能优化test测试用例的新增或修改chore构建与辅助工具的变动比如依赖升级、脚本调整ci持续集成相关的配置与脚本修改有些人会把 revert回滚和 build构建也放进来。我建议团队先别搞太多等确实出现了这类场景再讨论要不要补。模板的意义不是“穷举所有情况”而是给成员提供一个思考框架让他提交时想清楚“我这次改动到底属于哪一类”这就已经成功了。2.2 模板文件具体怎么写模板文件本身就是一个普通的纯文本文件你想加什么内容取决于你要引导团队填什么字段。这里给你一份可以直接用的版本type(scope): subject 空行 descriptions 空行 BREAKING CHANGE: description 空行 Refs: issue-id / link 空行 提交说明模板 type 可选feat / fix / docs / style / refactor / perf / test / chore / ci scope 可选本次改动影响的范围如模块名、服务名、组件名不填可以不写括号 subject一句话概述不超过 50 个字符祈使句、结尾不要加句号 descriptions详细描述说明为什么要做这个改动、怎么解决的、影响哪些地方 BREAKING CHANGE如果本次改动会破坏兼容性必须填写没有破坏性改动就留空 Refs关联的 Issue 或需求单链接没有就直接删掉这行用的时候成员进入编辑器后直接把尖括号里的内容替换成真实信息模板说明部分保留在正文区域下面也不会影响提交——Git 会过滤掉 # 开头的注释但等号这一行需要注意它前面没有井号会原样进到提交信息里。所以我特意把说明行都写在“”这个词的下方以免污染提交记录而等号这一行本身第一行是普通文本不会被过滤。等等这句“写在等号下方”的表述有点绕。实际上我给定的模板第一行就是 type 那行往下到 Refs 都是提交信息的正文而“ 提交说明模板 这一行及其下方才是给用户看的说明文字。由于 Git 只过滤以 # 开头的行这个等号模糊对齐不明确。更稳妥的做法是把所有说明都放在以 # 开头的注释里例如type(scope): subject descriptions BREAKING CHANGE: description Refs: issue-id / link # 提交说明 # type 可选feat / fix / docs / style / refactor / perf / test / chore / ci # scope 可选模块名、服务名、组件名不填可以不写括号 # subject一句话概述不超过 50 个字符祈使句结尾不要加句号 # descriptions详细描述说明为什么做这个改动、怎么解决的、影响哪些地方 # BREAKING CHANGE破坏兼容性变更时必填没有就留空 # Refs关联的 Issue 或需求单链接没有就删掉这行这样提交时所有说明都会以 # 开头自动被 Git 过滤完全不会污染提交记录同时又起到了引导作用。这一点也算替我踩过的坑做一个提醒。2.3 模板里的“引导技巧”让成员愿意填模板设计了但如果成员打开编辑器看到一堆要求第一反应可能是“这也太麻烦了干脆 -m 跳过”。要避免这种情况有几个技巧非常实用第一subject 字段给一个“字数提示”。比如在注释里写“不超过 50 个字符”比笼统的“写清楚”实用得多。50 个字符其实参考的是 Git 官方建议因为 GitHub 等平台在列表页和折叠 diff 时会截断过长的 subject超过 50 个字符的标题会让整个提交历史看起来非常局促。第二给出“填空示例”。你可以在注释里加一两行例子告诉大家一个高质量 subject 长什么样。比如这样# 好的示例fix(cart): 修复购物车在删除最后一件商品时报错 # 差的示例update cart logic这个效果比单纯写“请写清楚”要直接得多。人模仿示例的能力远高于抽象地照规则执行。第三descriptions 字段引导大家回答“为什么”而不只是“做了什么”。因为在 diff 里你要做的改动所有人都看得见真正看不到的是“为什么当时决定这么改”。让模板里的描述字段带上前缀提示比如“为什么改”成员自然就会照着这个思路填。3. 从安装到落地完整跑一遍配置流程下面进入实操环节。我假设你用的是全新环境顺带把 Git 安装、ssh 配置这些基础步骤也过一遍——因为很多人配置过程中卡住的点恰恰不在模板本身而在环境准备上。3.1 环境准备Git 的安装与基础配置不同系统的安装方式差异不大这里列一下核心的Windows 用户直接到 Git 官网下载安装包装完会自带 Git Bash。安装时默认选项基本够用但有两个地方我建议调整一是默认的编辑器我建议选 Visual Studio Code 或者 Notepad不要用 Vim不然装完第一次提交就直接卡在 Vim 操作上二是配置 home 路径时保持默认即可别手动乱改。macOS 用户如果装了 Homebrew一条命令就搞定brew install gitLinux 用户按发行版差异分别处理Debian/Ubuntu 用 aptsudo apt update sudo apt install git -y装完之后验证一下版本git --version接下来做全局基础配置这一步很多人会跳过后面提交的时候就被 Git 拦截——它需要知道你是谁git config --global user.name 你的名字 git config --global user.email 你的邮箱这里不建议用随便填的邮箱。Git 会把这串邮箱和提交绑定GitHub、GitLab 上也会对应到你的账号画像很多平台在用错了邮箱时会显示成“灰色 ghost”用户后续做代码归属统计和自动生成 changelog 时会出现一堆对不上人的记录。如果你在这个阶段遇到 ssh 认证失败的问题常见诱因有三个本机没有生成 ssh key、Git 平台没配置公钥、或者 ssh-agent 没启动。排查时可以先执行ssh -T gitgithub.com看具体报错然后顺手执行ssh-keygen -t ed25519 -C 你的邮箱生成完把公钥内容复制到 GitHub 或 GitLab 的 SSH keys 设置页里即可。然后就是很多人会在配置端遇到的问题——提交时被要求输入账号密码。这是远程仓库使用了 HTTPS 协议导致的Git 从某个版本开始强制要求走凭据管理器。建议直接改用 SSH 方式连接远程仓库在克隆时选 SSH 的地址避免每次 push 都弹一次认证。这一步配好之后后面提交模板的验证就会顺畅很多。3.2 模板文件与配置命令模板文件放在哪里完全随你但建议放在一个稳定路径下比如用户主目录下的~/.git-commit-templatevim ~/.git-commit-template把上面一节设计的模板内容粘贴进去保存退出。然后执行配置命令git config --global commit.template ~/.git-commit-template用--global是让这台机器上所有仓库都生效。如果你只想让某个仓库使用这个模板去掉--global并把命令放到仓库目录下执行即可。验证配置是否生效用下面的命令查看git config --global commit.template能打印出刚才写的路径就说明配置成功了。注意 Windows 下路径分隔符用反斜杠可能需要转义处理稳妥起见直接用正斜杠/写完整路径Git 在 Windows 下会自动处理好。3.3 第一次提交时模板是长什么样子的配置完来一次实际提交看效果。准备一个测试仓库mkdir demo-repo cd demo-repo git init git add README.md git commit注意这里要直接执行git commit不要加-m参数否则模板不会出现后面专门讲这个坑。执行后默认编辑器会打开里面的内容就是刚才模板文件的内容feat(demo): 初始化项目光标停在第一行引导你补充 type、scope 和 subject。填完之后保存退出提交记录就生成了。执行git log --stat查看提交信息你会发现那些以 # 开头的说明行完全不会出现在日志里提交历史干净清爽。这里有个细节如果你的默认编辑器是 Vim保存退出对应的是先按 Esc然后输入:wq回车很多新手在这一步把会话也关了提交也会被取消掉。这也侧面说明为什么我一开始建议在安装 Git 时把默认编辑器改成 VSCode。3.4 临时想跳过模板应该怎么做模板是给大家提供便利的不是制造枷锁。有些场景下——比如快速修复一个拼写错误、临时加个空文件——你确实不需要填一大段模板。此时直接加--no-template参数即可git commit --no-template -m docs: fix typo in README说实话我自己用这个参数频率不高因为我更习惯用-m加--no-template简写Git 不支持只有--no-template一个长选项。这里提醒一点-m和模板不冲突吗其实-m本身就等于绕过了模板。只要带-mGit 会直接拿这个参数作为提交信息模板根本不会渲染。所以“临时跳过”的真正可用场景反而是那些你会走进编辑器、但又不想被模板束缚的提交操作。如果你希望“强制所有人提交时必须用模板”可以在团队内约定禁止使用-m提交一律走编辑器。但说实话靠约定不如靠工具把检查逻辑做成脚本挂到 husky 里会比纯口头要求更可靠——这就是上面提到 commitlint 那一层的事情了。4. 常见问题与排查技巧实录工具越小坑越隐蔽。这套配置本身不难但我见过太多人在配置过程中踩到各种奇奇怪怪的问题下面把高频问题一次性讲透。4.1 配置了模板却不生效最常见的原因是配置写在了错误的作用域。比如你在一个仓库里执行git config --global commit.template配了模板但这个仓库在.git/config里可能已经存在相同 key 的本地配置本地配置优先于全局配置就会覆盖掉。排查命令很简单git config --show-origin --get commit.template加了--show-origin后Git 会明确告诉你这个配置项来自哪个文件是全局文件~/.gitconfig还是本地仓库的.git/config。确认来源之后再按需调整即可。还有一个原因容易被忽略模板文件路径写错了或者文件没有保存。Git 触发编辑器时如果发现模板文件不存在会表现为打开一个空白编辑器不报任何错误。很多人以为模板不生效实际是文件的绝对路径输错了。检查路径时注意不要用~有些配置解析器能处理有些不行统一写绝对路径最保险。4.2 编辑器打开乱码或者中文显示异常Windows 系统上比较常见。原因基本可以锁定为编码不一致模板文件保存成了 UTF-8但 Git 默认终端或编辑器按本地 ANSI 编码读取中文就变成了乱码或者是模板文件是 GBK 保存的跟 Git 内部读文件的 UTF-8 冲突。解决方案分两步第一保存模板文件时强制用 UTF-8带不带 BOM 都行但建议不带。VS Code 左下角选择编码为 UTF-8 保存。第二配置 Git 的属性防止它在读取时转码git config --global core.quotepath false git config --global i18n.commitencoding utf-8core.quotepath控制在 log 输出中文时是否转义成八进制序列配成 false 之后中文路径会正常显示。i18n.commitencoding告诉 Git 提交信息以 UTF-8 编码解析很多中文乱码问题都是这条配置解决的。4.3 Windows 与 macOS 换行符差异换行符这个坑非常隐蔽。Windows 上文本文件默认用CRLF回车加换行而 macOS 和 Linux 用LF换行。如果你在 Windows 上创建模板文件直接提交到仓库里团队成员在 macOS 上拉下来用的时候可能会看到模板每个字段后面多出一些看不见的符号影响使用体验。处理方式有两种第一种在仓库根目录添加.gitattributes文件声明模板文件使用LF.git-commit-template text eollf第二种直接提交前先转换一下换行符。用 VS Code 打开模板文件时右下角可以看到当前的行尾序列手动切换成 LF 再保存。这一步做完后模板文件在团队内就稳定了。提示如果你团队跨 Windows 和 macOS 协作建议在.gitattributes里统一声明关键文本文件的换行符策略这能避免大量无意义的 diff 干扰。4.4 命令行的 -m 参数会直接绕过模板这个前面提过但值得单独列一条因为它是最容易被误会的“模板不生效”场景。很多开发者习惯了git commit -m 提交说明这种一行提交方式。配置完模板之后他们仍然这么执行然后发现模板完全没有出现于是怀疑自己配置错了。其实-m这个参数在 Git 内部的处理机制是直接把参数内容写成提交信息整个编辑器和模板流程都会被跳过。这不是 bug而是设计如此。模板要生效要么直接执行git commit进入编辑器要么配合-e参数强制打开编辑器git commit -e -m message加了-e之后会打开编辑器并让你修改此时模板也会被加载你可以在模板基础上调整内容再保存。不过实际场景中我仍然建议团队的主流程直接走git commit让模板引导信息填写。4.5 IDE 内部提交和 submodule 仓库现在很多人在 IDE 里直接提交代码比如 VS Code 的源代码管理面板、IntelliJ IDEA 的 Commit 窗口。这些工具通常会自建提交界面不一定读取系统 Git 的 commit.template 配置即使全局配置了也不会在主界面里展示模板。解决方式有三条路一是给 IDE 的提交配置里手动指定模板文件比如 IntelliJ IDEA 在 Settings - Version Control - Commit 里可以设置模板路径指向同一个文件二是让 IDE 的终端环境老老实实用命令行提交三是通过 IDE 扩展或 hooks 实现但这已经是重度定制了投入产出比不高。我认为当前阶段让团队成员统一使用命令行提交或者统一在 IDE 里配置好模板路径就行两条路并行反而容易乱。submodule 的情况最好单独记一下子模块仓库默认使用自己的配置全局模板对它不一定生效。如果需要子模块也走模板必须进入子模块目录再设置一次 commit.template否则提交时打开的还是空白编辑器。5. 团队落地让模板真正成为协作的一部分把模板从个人配置变成团队协作基建才是这个功能最大的价值所在。下面是我在团队里推行这套规范时的一些操作心得。5.1 模板文件入库跟随仓库一起分发不要只把模板存在个人电脑上而是把模板文件提交到仓库根目录命名为.git-commit-template注意前面那个点让它在文件管理器中保持隐藏状态不污染项目根目录的视觉。这样每个成员克隆完仓库后只需要执行一条命令就能完成配置接入git config commit.template .git-commit-template注意这里不能用--global因为它是指向当前仓库根目录的相对路径。如果你用--global配置了绝对路径成员克隆新仓库后就得手动改一次很麻烦。建议在仓库 README 的“开发环境配置”章节写清楚这一条命令新成员三分钟即可完成接入。如果你还想更进一步可以把这条配置写进仓库的脚本或初始化命令里比如在项目根目录放一个setup.sh里面包含npm install、git config commit.template等步骤成员一条命令完成全部初始化。5.2 把模板和分支规范、自动化流程接在一起模板只是提交基础单靠它还不能构建完整的协作体验。我建议把提交规范跟分支约束结合起来比如分支命名规范采用feature/xxx、fix/xxx的结构模板里的 scope 字段可以直接跟分支名对应拉合并请求时在 MR 描述里引用关联 Issue 的链接配合一些自动化工具效果会放大如果你在.gitlab-ci.yml或 GitHub Actions 里配置了基于提交信息自动生成 changelog清晰的提交格式会让 changelog 的生成结果非常规整。例如 semantic-release 这类工具就极度依赖规范化的提交信息——它要求 feat 类型触发 minor 版本号更新fix 类型触发 patch 更新BREAKING CHANGE 触发 major 更新。如果提交信息写得不规范自动版本号计算就会出现偏差。5.3 和 Code Review 衔接时模板带来的实际收益Code Review 时审查者看到的不只是 diff还有提交信息。提交信息本身就是第一份“设计说明”。举个例子某次提交的信息是feat(order): 支持订单批量导出 为什么改运营反馈每天要手动导出大量订单人工操作效率太低 怎么解决新增批量导出接口前端增加批量选择和异步下载入口 影响范围订单列表页、导出服务 Refs: https://git.example.com/issues/182审查者看到这条信息后几乎不需要再问“为什么要做这个”直接进入 diff 评审。而如果模板里没有这一层引导审查的时候大概率要留言“请问这个导出的并发控制是怎么考虑的”——来回一轮沟通的成本就上去了。我在自己的项目里尝试过两种提交模式一种带完整模板一种不带。带模板的项目在 code review 阶段明显沟通更顺畅因为描述区已经把“为什么”和“影响范围”都解释清楚了审查者只需聚焦在“实现是否优雅”这个层面。这个体验变化是我坚持继续使用模板的最直接动力。5.4 团队常见的“模板抵抗情绪”怎么化解推行任何规范都会遇到阻力。有人觉得“写这么多太浪费时间”有人觉得“格式太死板限制自由”。我的应对经验是第一区分“必须填”和“可选填”。模板设计时只在 type、subject、descriptions 三个字段上做硬性要求其他字段允许留空。为了做到不填也能顺利提交注释里可以引入一个简单的校验但如果你的团队暂时没有挂 hooks就要接受“模板只做引导不做强制”的阶段目标。先让大家习惯这个格式再逐步引入 commitlint 强制约束阻力会小很多。第二展示收益案例。拿一段没有规范的历史和有规范的历史放在一起对比让每个成员直观感受哪个好用。这个比任何说教都有效。第三给特殊场景留出口。一行-m快速提交用于临时修复在团队内部达成一致紧急修复可先短信息提交之后补一次符合规范的重写提交。让规范和“灵活”并存优于一味的严格。结尾我从一开始相信“提交信息写规范点”不过是一句口号到自己亲手把 template 配好、用起来再到拉着整个团队一起规范之后回头看最大的感受是工具解决的是“记不住、做不到”的问题而不是“人不够自觉”的问题。你不需要靠意志力去记住每次提交都要写清楚——把模板配置好编辑器自动展开照着填写就行。这套机制省掉的不是那几秒钟打字时间而是后续定位问题、追溯需求、生成 changelog 时节省的数倍时间。最后再分享一个我自己的小技巧我会在模板的注释里放一句“如果这次改动是一次测试性代码请在 subject 后加上 [test] 标记”这样团队日志里能一眼区分临时试验和正式改动排查的时候非常有用。你也不妨想想你们团队最常遇到的“信息黑洞”是什么定制一条提示放到模板里——这个功能真正有趣的地方就是它完全属于你自己。