git提交规范
标准流程
遵循 Conventional Commits(Angular 风格):
<type>(<scope>): [:emoji:] <subject>
<body>
<footer>
type取下面十一类之一,不可自造scope是模块名,可省略emoji可选,但一旦写了就必须与type相符(见下表)subject末尾不加标点
emoji 一律用 gitmoji 短代码(:bug:)而不是 Unicode 字面量(🐛):短代码是纯 ASCII,
终端、diff 工具、git log --oneline 的列对齐都不会因为宽字符而错位。
语义以 gitmoji.dev 官方定义为准。同一个 emoji 允许对应多个
type——:necktie:(业务逻辑)新写是feat、改错是fix、只挪不改行为是refactor, 三种都成立。但:bug:只能是fix、:sparkles:只能是feat,这类没有第二种读法。
feat
添加了新功能/特性
| emoji | 含义 | 也可用于 |
|---|---|---|
:sparkles: | 引入新特性 | — |
:boom: | 破坏性变更 | refactor |
:globe_with_meridians: | 国际化与本地化 | fix |
:chart_with_upwards_trend: | 添加或更新分析、埋点代码 | — |
:speech_balloon: | 添加或更新文案与字面量 | docs / style |
:triangular_flag_on_post: | 添加、更新或删除特性开关 | chore |
:label: | 添加或更新类型 | refactor / chore |
:necktie: | 添加或更新业务逻辑 | fix / refactor |
:safety_vest: | 添加或更新校验相关代码 | fix / refactor |
:passport_control: | 授权、角色与权限相关代码 | fix |
:stethoscope: | 添加或更新健康检查 | chore |
:card_file_box: | 数据库相关变更 | fix / chore |
:loud_sound: | 添加或更新日志 | chore |
:goal_net: | 捕获错误 | fix |
:thread: | 多线程与并发相关代码 | fix / perf / refactor |
:wheelchair: | 提升可访问性 | fix |
:seedling: | 添加或更新种子数据 | chore |
:egg: | 添加或更新彩蛋 | — |
fix
修复错误
| emoji | 含义 | 也可用于 |
|---|---|---|
:bug: | 修复 bug | — |
:ambulance: | 关键热修复 | — |
:adhesive_bandage: | 非关键问题的简单修复 | — |
:pencil2: | 修复拼写错误 | docs |
:lock: | 修复安全或隐私问题 | — |
:rotating_light: | 修复编译器或 linter 告警 | style / chore |
:alien: | 因外部 API 变更而修改代码 | refactor |
:green_heart: | 修复 CI 构建 | ci |
perf
优化,提升性能/体验
| emoji | 含义 | 也可用于 |
|---|---|---|
:zap: | 提升性能 | — |
:mag: | 改进 SEO | feat |
:children_crossing: | 改善用户体验与可用性 | feat / fix |
:thread: | 优化多线程与并发代码 | feat / fix / refactor |
⚠️
perf只放真的让程序更快或更省的改动。重构、删死代码、移动文件、 改注释都不是 perf——它们不改变运行时开销,只改变代码的样子。
refactor
既不是新增功能,也不是修复 bug 的代码变动
| emoji | 含义 | 也可用于 |
|---|---|---|
:recycle: | 重构代码 | — |
:building_construction: | 架构变更 | — |
:art: | 改进代码结构与格式 | style |
:truck: | 移动或重命名资源 | chore |
:coffin: | 删除死代码 | chore |
:fire: | 删除代码或文件 | chore |
:wastebasket: | 弃用需要清理的代码 | chore |
:mute: | 删除日志 | chore |
:bulb: | 添加或更新源码注释 | docs |
style
不影响语义的格式与 UI 样式变动
| emoji | 含义 | 也可用于 |
|---|---|---|
:lipstick: | 添加或更新 UI 与样式文件 | feat |
:iphone: | 响应式设计 | feat |
:dizzy: | 添加或更新动画与过渡 | feat |
test
添加、修改测试代码
| emoji | 含义 |
|---|---|
:white_check_mark: | 添加、更新或让测试通过 |
:test_tube: | 添加一个失败的测试(TDD) |
:clown_face: | mock 数据 |
:camera_flash: | 添加或更新快照 |
docs
文档修改
| emoji | 含义 | 也可用于 |
|---|---|---|
:memo: | 添加或更新文档 | — |
:bulb: | 添加或更新源码注释 | refactor |
:page_facing_up: | 添加或更新许可证 | chore |
:busts_in_silhouette: | 添加或更新贡献者 | chore |
:money_with_wings: | 添加赞助或资金相关 | chore |
build
影响构建系统或外部依赖的变动
| emoji | 含义 | 也可用于 |
|---|---|---|
:heavy_plus_sign: | 添加依赖 | — |
:heavy_minus_sign: | 移除依赖 | — |
:arrow_up: | 升级依赖 | — |
:arrow_down: | 降级依赖 | — |
:pushpin: | 将依赖锁定到指定版本 | — |
:package: | 添加或更新编译产物与分发包 | — |
:bricks: | 基础设施相关变更 | chore / feat |
:wrench: | 添加或更新配置文件 | chore |
:hammer: | 添加或更新开发脚本 | chore |
ci
CI 配置文件与脚本的变动
| emoji | 含义 | 也可用于 |
|---|---|---|
:construction_worker: | 添加或更新 CI 构建系统 | — |
:green_heart: | 修复 CI 构建 | fix |
:rocket: | 部署 | chore |
revert
还原之前的修改
| emoji | 含义 |
|---|---|
:rewind: | 回退变更 |
chore
以上都不是的杂项
| emoji | 含义 | 也可用于 |
|---|---|---|
:closed_lock_with_key: | 添加或更新密钥 | — |
:see_no_evil: | 添加或更新 .gitignore | — |
:construction: | 工作进行中 | — |
:twisted_rightwards_arrows: | 合并分支 | — |
:alembic: | 进行实验 | feat |
:monocle_face: | 数据探查与检查 | — |
:technologist: | 改善开发者体验 | — |
:tada: | 初始化项目 | feat |
:poop: | 写下待改进的糟糕代码 | fix |
:bento: | 添加或更新静态资源 | feat |
:seedling: | 添加或更新种子数据 | feat |
落地:commitlint 校验
光有文档没用,得让 git commit 真的拦得住。参考 ecommerce 仓库的做法:
commitlint.config.mjs # 规则 + emoji↔type 白名单
package.json(仓库根) # devDeps: @commitlint/cli + config-conventional
frontend/.vite-hooks/commit-msg # pnpm exec commitlint --edit "$1"
配置里除了 extends: ['@commitlint/config-conventional'],关键是一条自定义规则:
从 subject 开头抓 :xxx:,没有就放行,有就查白名单并核对 type 是否在允许集合里。
装钩子的人不一定是 husky。ecommerce 的前端用 vite-plus,它自带一套和 husky 同构的
钩子 shim,pnpm install 时的 prepare: "vp config" 会把 core.hooksPath 设成
frontend/.vite-hooks/_。而 core.hooksPath 是仓库级设置,所以后端 Go 的提交
同样受这套校验管——一个前端工具链顺手接管了整个仓库的钩子。
几个真踩过的坑
- 别把安装命令抄成钩子内容。 husky 的文档教你写
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'—— 这是要在终端执行的命令。我那份文档结尾原样留着这行,后来照抄时把它写进了.husky/commit-msg文件里,于是那个钩子的全部内容变成echo "..." > .husky/commit-msg:每次提交它只是把自己重写一遍然后退出 0。 文件在、可执行位在、git 也确实调用了它,唯独它什么都没做。这种最难发现。 core.hooksPath必须指向真实存在的目录。 指到一个不存在的路径,git 不报错, 只是静默地一个钩子都不跑。工具链换代时特别容易撞上:老目录删了、新工具的接管守卫 又因为老值「看起来还像自己人」而选择跳过,core.hooksPath就留在了半空中。pnpm exec不要加--no。 pnpm 11 已经不认这个 exec 参数,会报Command "--no" not found,等于把校验变成永远失败(而commit --no-verify一旦成为肌肉记忆,等于没校验)。rules: {}且没有extends是零规则,不是默认规则。配置文件存在不代表有约束。
这四条曾经同时成立,结果是校验从搭起来到被发现,九个月里一次都没生效过, 而仓库 README 一直写着「已配置提交信息校验」。
所以真正的规矩只有一条:装完立刻用一条故意写错的消息验证它真的拦得住, 再用一条正确的验证它不是「什么都拦」。
git commit --allow-empty -m "wip: 随便写点" # 必须失败
git commit --allow-empty -m "feat: :bug: 走错 emoji" # 必须失败
git commit --allow-empty -m "feat: :sparkles: 正确的" # 必须成功
pnpm exec commitlint --from HEAD~10 --to HEAD # 回放既有提交
静默失效的钩子比没有钩子更危险——它给了一种虚假的安全感,文档还会跟着一起说谎。
修订记录
2026-08-02 按 gitmoji 官方语义重新归类,修掉约 20 处错误。较大的几处:
| 原分类 | emoji | 问题 | 现分类 |
|---|---|---|---|
| perf | :ambulance: | 官方语义是「关键热修复」,与性能无关 | fix |
| perf | :art: | 官方语义是「改进代码结构与格式」,不是性能 | refactor / style |
| perf | :recycle: | 重构不改变运行时开销;且与 refactor 段重复 | refactor |
| perf | :coffin: :truck: :bulb: :alien: :passport_control: :technologist: | 删死代码 / 移动资源 / 写注释 / 跟外部 API / 权限代码 / 开发体验,都不是性能优化 | refactor、docs、fix、chore |
| perf | :poop: | 含义写反了——官方是「写下需要改进的糟糕代码」,不是「改进垃圾代码」 | chore |
| perf | :arrow_down: | 与 build 段重复;降级依赖是构建变动 | build |
| fix | :necktie: | 写成「添加业务逻辑」——添加业务逻辑是 feat | feat / fix / refactor |
| fix | :fire: | 「删除代码」不是修 bug | refactor / chore |
| build | :tada: | 官方是「初始化项目」,不是「发布项目」 | chore |
| build | :rocket: | 部署不是构建组件的变动 | ci |
| chore | :construction_worker: | 同一 emoji 重复列了两行;且属于 CI | ci |
| chore | :stethoscope: | 写成「添加测试成功的代码」——官方是「健康检查」 | feat / chore |
| chore | :alembic: | 「完成实验」→ 官方是「进行实验」 | chore / feat |
| test | :white_check_mark: :test_tube: | 措辞不准,官方分别是「添加/更新/让测试通过」和「添加一个失败的测试」 | test |
| — | — | 整个 ci 类型缺失,Angular 十一类里少了一类 | 已补 |
| feat/style | :dizzy: :iphone: | 跨段重复且含义分裂(「JS 响应式」vs「CSS 响应式」) | style 为主,feat 兼容 |