Git commit cn
中文 Git 提交信息规范 Agent Skill — Conventional Commits + 从 diff 自动生成 commit 的决策逻辑
npx -y skills add nanami7777777/git-commit-cnAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use this skill when writing git commit messages, splitting changes into commits, generating changelogs, or deciding version numbers. It enforces Conventional Commits with Chinese scopes, provides decision trees for type/scope/body selection, demonstrates how to analyze diffs and produce correct commit messages, and includes rules for multi-commit splitting, changelog generation, and semantic versioning. Triggers on git commit, git add, changelog, release, or version bump tasks.
SKILL.md
9.1 KB, as published. Nobody here has run it
Git 提交信息规范
格式
<type>(<scope>): <subject>
<body>
<footer>
type 选择决策树
这次改动的效果是什么?
│
├── 用户能感知到新功能 → feat
├── 修复了用户能感知到的 bug → fix
├── 改了代码结构但行为不变 → refactor
├── 让某个操作变快了 → perf
├── 只改了测试代码 → test
├── 只改了文档/注释 → docs
├── 只改了代码格式(空格、分号、换行) → style
├── 改了构建配置/脚本/依赖版本 → chore
├── 改了 CI/CD 配置 → ci
└── 回滚了之前的提交 → revert
容易判断错的情况
| 改动 | 错误 type | 正确 type | 原因 |
|---|---|---|---|
| 给已有接口加了参数校验 | feat | fix | 缺少校验是 bug,加上是修复 |
| 把 var 改成 const | refactor | style | 没改逻辑,只是代码风格 |
| 升级 React 18 → 19 | chore | feat | 如果用了新特性就是 feat |
| 加了错误日志 | feat | fix | 缺少日志导致排查困难,是修复可观测性 |
| 删除了废弃代码 | fix | refactor | 没修 bug,只是清理 |
| 加了 loading 状态 | style | feat | 用户能感知到的 UI 变化是功能 |
| 把 any 改成具体类型 | refactor | style | 没改运行时行为 |
scope 规则
用中文业务域,不用文件名或路径:
✓ feat(用户): 支持手机号一键登录
✓ fix(订单): 修复取消订单后库存未恢复
✓ refactor(支付): 统一微信和支付宝的回调处理
✗ feat(src/views/user): ... ← 文件路径
✗ fix(UserService.ts): ... ← 文件名
✗ feat(user-module): ... ← 英文模块名
scope 选择规则
- 改动只涉及一个业务模块 → 用那个模块名
- 改动跨多个模块但有主次 → 用主要模块名
- 改动是基础设施(工具函数、配置、CI) → 省略 scope
- 改动是全局性的(升级框架、改构建配置) → 省略 scope
subject 规则
- 中文,不超过 50 字符
- 祈使语气:"添加"不是"添加了"
- 描述效果,不描述实现
✓ feat(购物车): 支持批量删除商品
✓ fix(登录): 修复验证码 60 秒倒计时结束后按钮未恢复可点击状态
✗ fix(登录): 修复 bug
✗ feat: 更新代码
✗ chore: 改了点东西
✗ fix(登录): 在 LoginForm.vue 的 handleSendCode 方法中将 disabled 状态在 setTimeout 回调里重置为 false
↑ 这是实现细节,不是效果描述
body 决策
需要写 body 吗?
│
├── 破坏性变更(改了接口、改了数据结构) → 必须写
├── 修复了一个不明显的 bug → 必须写根因
├── 改动超过 100 行 → 建议写
├── 有多种方案,选了其中一种 → 建议写为什么
├── 简单的功能添加或小修复 → 不用写
└── style/docs/chore 类型 → 通常不用写
body 模板
修复 bug 时:
fix(订单): 修复并发下单时库存超卖
根因:多个请求同时读取库存值后各自扣减,最后写回的值覆盖了其他请求的扣减。
方案:改用 UPDATE ... SET stock = stock - 1 WHERE stock > 0 的原子操作。
放弃方案:
- Redis 分布式锁:引入额外依赖,且有单点故障风险
- 数据库悲观锁:并发量大时性能差
重构时:
refactor(支付): 统一微信和支付宝的支付回调处理
动机:两个支付渠道的回调处理逻辑 80% 相同,但分散在两个文件里,
每次改业务逻辑要改两处,容易遗漏。
做法:抽取 PaymentCallbackHandler 基类,渠道差异通过策略模式处理。
影响:WechatPayCallback 和 AlipayCallback 的公共逻辑移到了基类。
破坏性变更时:
feat(API): 用户列表接口改为分页返回
BREAKING CHANGE: GET /api/users 返回格式变更
之前:
{ "users": [...] }
现在:
{ "list": [...], "total": 100, "page": 1, "pageSize": 20 }
迁移方式:
- 前端:将 response.users 改为 response.list
- 需要传分页参数:?page=1&pageSize=20
- 不传分页参数时默认返回前 20 条
从 diff 生成 commit message
当你看到一个 diff 需要生成 commit message 时,按这个流程:
步骤 1:扫描改动范围
- 改了几个文件?
- 改动集中在哪个业务模块?
- 有没有不相关的改动混在一起?(如果有,应该拆成多个 commit)
步骤 2:判断 type
看改动的效果,不是看改了什么代码:
- 加了新的 API endpoint →
feat - 修了一个条件判断 →
fix(如果修的是 bug)或refactor(如果只是优化写法) - 加了 try-catch →
fix(如果之前会崩溃)或refactor(如果只是改善错误处理)
步骤 3:写 subject
从调用方/用户的角度描述:
- 不要说"修改了 handleSubmit 函数" → 说"修复提交表单时的空指针错误"
- 不要说"添加了 isValid 变量" → 说"添加表单提交前的数据校验"
示例
diff:
- const price = item.price * item.quantity
+ const price = Math.round(item.price * item.quantity * 100) / 100
commit: fix(订单): 修复商品金额计算的浮点精度丢失
diff:
+ import { rateLimit } from 'express-rate-limit'
+
+ app.use('/api/auth', rateLimit({
+ windowMs: 60 * 1000,
+ max: 5,
+ message: { code: 429, message: '请求太频繁,请稍后再试' }
+ }))
commit: feat(认证): 登录接口添加频率限制(每分钟 5 次)
diff:
- async function getUser(id) {
- const user = await db.query('SELECT * FROM users WHERE id = ' + id)
+ async function getUser(id: string) {
+ const user = await db.query('SELECT * FROM users WHERE id = $1', [id])
commit:
fix(用户): 修复用户查询的 SQL 注入漏洞
根因:直接拼接用户输入到 SQL 语句中。
方案:改用参数化查询。
diff(多文件,跨模块):
# package.json
- "vue": "^3.3.0"
+ "vue": "^3.5.0"
# src/components/UserList.vue
- <script setup>
+ <script setup lang="ts">
# vite.config.ts
+ vue({ features: { propsDestructure: true } })
commit: chore: 升级 Vue 3.5 并启用 props 解构特性
(跨多个文件但都是同一件事:升级 Vue,所以是一个 commit)
什么时候拆成多个 commit
这些改动是同一件事吗?
│
├── 是 → 一个 commit
│ 例:修一个 bug 改了 3 个文件 → 一个 fix commit
│
└── 不是 → 拆成多个 commit
例:修了一个 bug + 顺手改了代码格式 → 一个 fix + 一个 style
例:加了新功能 + 补了测试 → 一个 feat + 一个 test(或合并为一个 feat)
拆分原则
- 每个 commit 应该能独立通过 CI(不能拆出一个编译不过的 commit)
- 修 bug 和加功能不要混在一个 commit
- 重构和功能变更不要混在一个 commit
- 如果不确定要不要拆,问自己:回滚这个 commit 时,会不会误伤其他改动?
Changelog 生成规则
从 commit history 生成 changelog 时:
feat→ 放在 "✨ 新功能" 下fix→ 放在 "🐛 修复" 下perf→ 放在 "⚡ 性能优化" 下BREAKING CHANGE→ 放在 "💥 破坏性变更" 下(最顶部,红色警告)docs/style/chore/ci/test→ 不出现在面向用户的 changelog 中
# v1.2.0 (2025-03-28)
## 💥 破坏性变更
- **API**: 用户列表接口改为分页返回 (#45)
## ✨ 新功能
- **用户**: 支持手机号一键登录 (#38)
- **购物车**: 支持批量删除商品 (#41)
## 🐛 修复
- **订单**: 修复并发下单时库存超卖 (#39)
- **登录**: 修复验证码倒计时结束后按钮未恢复 (#40)
## ⚡ 性能优化
- **列表**: 虚拟滚动优化长列表渲染 (#42)
版本号决策
有 BREAKING CHANGE 吗?
├── 是 → 主版本号 +1(1.x.x → 2.0.0)
└── 否 → 有 feat 吗?
├── 是 → 次版本号 +1(1.1.x → 1.2.0)
└── 否 → 修订号 +1(1.1.1 → 1.1.2)
注意:0.x.x 阶段(未正式发布)可以在次版本号上做破坏性变更。
不要做的事
- 不要一个 commit 混多种不相关改动
- 不要
git add .然后盲目提交,先git diff --staged看一眼 - 不要提交
.env文件或任何密钥 - 不要提交
console.log调试代码 - 不要写"修复 bug"、"更新代码"、"改了点东西"
- 不要用英文写完再机翻成中文
- 不要在 subject 里写实现细节(文件名、函数名、变量名)