跳转至

Git 提交规范

怎么写 commit message 才清晰、可检索、方便协作。命令见 Git 命令集;本地校验见 Gitignore 与 Hooks

相关文档Git 命令集 · Gitignore 与 Hooks · 协作流程


阅读指引

  1. 概念:提交说明由哪几部分组成、为什么要约定
  2. 总览:常见格式、type 表、相关命令
  3. 场景:按实际写法与踩坑展开,含正反例
  4. 文末速查:现象 → 建议

提交说明是什么

每次 git commit 都会留下一条 提交说明(commit message),包含 标题(subject,通常第一行)和可选的 正文(body)、页脚(footer / trailer)。

一句话:「给这次改动贴标签,让未来的自己和队友能看懂 改了什么、为什么改。」

效果:说明随 commit 永久保存在 Git 历史里;git log、PR、changelog、自动化发版都会读到它。写得好不好,直接影响 code review 和排障效率。


总览

常见格式一览

格式 适用 示例首行 场景
祈使句单行 个人项目、小改动 Fix login redirect loop 最低要求
Conventional Commits 开源 / 团队 / 自动化 changelog feat(auth): add OAuth callback Conventional
带正文多行 复杂改动、需要解释「为什么」 首行 + 空行 + 段落 多行正文
Breaking change 不兼容 API 变更 feat!: drop Node 16 或 footer 破坏性变更
Trailer 页脚 署名、联合作者、Issue 关联 Closes #42 Trailer

Conventional Commits 规范 被 Angular、Semantic Release 等广泛采用;团队可以裁剪(例如只要 type: 不要 scope),但结构清晰比死记标准更重要。

Conventional Commits:type 速查

type 含义 示例首行
feat 新功能 feat: add export to CSV
fix 修复 bug fix: handle null user id
docs 仅文档 docs: update install steps
style 格式(不影响逻辑) style: format with prettier
refactor 重构(非新功能非修 bug) refactor: extract auth middleware
perf 性能 perf: cache config parse result
test 测试 test: add login API cases
build 构建 / 依赖 build: bump webpack to 5.94
ci CI 配置 ci: add matrix for Node 20/22
chore 杂项维护 chore: update gitignore
revert 回滚某 commit revert: feat(auth): add OAuth

可选 scope(括号内模块名):feat(api): ...fix(ui): ...
表示 不兼容变更 时在 type 后加 !feat(api)!: remove v1 endpoints

本篇相关 Git 命令

命令 干什么 场景 命令集
git commit -m '...' 单行说明 单行 git commit
git commit(无 -m 打开编辑器写多行 多行正文 git commit
git commit --amend 改最近一次说明 amend git commit
git commit --amend --no-edit 并入改动、说明不变 amend git commit
git revert <hash> 用新 commit 撤销历史 已 push git revert
git log --oneline 看历史标题 写 revert 时找 hash git log
git commit --no-verify 跳过 commit hook hooks 文档 git commit

写好标题的通用原则

原则 建议
语气 祈使句(英文:Add 不是 Added;中文可用「添加」「修复」)
长度 首行约 50 字符内(软限制,超出可换行写 body)
内容 做了什么,细节和动机放正文
标点 首行末尾 一般不加句号
粒度 一个 commit 一个完整意图;WIP 不要直接进 main

场景:团队没定规范时的最低要求

常见场景:个人仓库、小团队尚未写 CONTRIBUTING。

一句话:「首行让人 5 秒内看懂这次改动目的。」

# 可以:动词开头、具体
git commit -m "Fix crash when profile avatar is missing"

# 可以:中文项目
git commit -m "修复头像为空时个人页崩溃"

# 避免:太泛
git commit -m "update"
git commit -m "fix bug"
git commit -m "WIP"

# 避免:把 issue 号当唯一说明
git commit -m "#123"

场景:Conventional Commits 怎么写

常见场景:开源项目、需要自动生成 changelog、PR 标题与 commit 对齐。

# 新功能 + scope
git commit -m "feat(billing): support annual subscription"

# 修 bug
git commit -m "fix: prevent double submit on checkout"

# 文档-only
git commit -m "docs: add API rate limit section"

# 依赖升级(别和功能混在一起)
git commit -m "build: upgrade eslint to 9.x"

效果:工具可按 feat / fix 分类发版;reviewer 从 git log 快速过滤类型。

Note

进仓库前 先看该项目CONTRIBUTING.md、PR 模板或已有 git log --oneline -20,跟现有风格一致比照搬全网标准更重要。


场景:多行说明 — 标题 + 正文

常见场景:重构、行为变更、需要交代 为什么 而不是 改了哪些文件

一句话:「首行摘要,空一行,正文写动机、取舍、风险。」

git commit -m "$(cat <<'EOF'
fix(auth): reject expired refresh tokens

Previously expired tokens still passed middleware when
clock skew was under 30s. Align with OAuth spec and
return 401 with clear error code.

Refs #8842
EOF
)"

或用编辑器(不设 -m):

git commit
# 编辑器中:
# fix(auth): reject expired refresh tokens
#
# Previously expired tokens still passed...

效果git log 默认只显示首行;git log -pgit show 能看到正文。


场景:改最近一次说明(还没 push)

常见场景:commit 完发现 typo、漏 git add 某个文件。

# 只改说明
git commit --amend

# 说明写在一行
git commit --amend -m "feat: add password reset email"

# 补文件进上一次 commit,说明不变
git add forgotten.ts
git commit --amend --no-edit

一句话:「最后一笔账还没 push,可以涂改。」

效果:commit hash 会变;仅适用于尚未 push 或仅你使用的分支

Warning

已经对 共享远程分支 push 过的 commit,不要用 amend 改历史(除非团队明确允许并配合 force push)。见 已 push 场景


场景:已经 push 到远程了

常见场景:说明写错、功能要撤回,但 commit 已在 origin/main 上。

情况 建议 示例
仅说明有错、改动正确 新开 commit 修正描述,或团队允许时 revert 再重做 docs: fix typo in previous commit message(空 commit 慎用)
要撤销整次改动 git revert(保留历史) git revert abc1234
个人 feature 分支、无人基于它开发 rebase/amend + push --force-with-lease 协作流程
# 推荐:用 revert 生成「反向」commit
git revert HEAD
git commit  # 编辑器里默认有 revert 说明,可改

# 不推荐在 shared main 上:
# git reset --hard HEAD~1 && git push --force

一句话:「公共历史已发布,优先 追加 新 commit,而不是改旧账。」


场景:破坏性变更(Breaking Change)

常见场景:删 API、改配置项默认值、主版本号升级。

# 方式 1:type 后加 !
git commit -m "$(cat <<'EOF'
feat(api)!: remove legacy /v1 users endpoint

BREAKING CHANGE: clients must use /v2/users. v1 removed
after deprecation period noted in 2025-Q4 changelog.
EOF
)"

# 方式 2:footer 里写 BREAKING CHANGE:
git commit -m "feat: switch default TLS to 1.3

BREAKING CHANGE: TLS 1.0/1.1 no longer supported."

效果:发版工具可据此 bump 主版本号;使用者能在 log 里搜 BREAKING CHANGE


场景:Trailer 与 Issue 关联

Trailer 是 message 末尾 的标准化行(Key: Value),常见于开源与 GitHub/GitLab 集成。

Trailer 用途 示例
Closes #123 / Fixes #123 合并后关 Issue GitHub 自动识别
Refs #123 仅关联不关 部分完成
Co-authored-by: Name <email> 联合作者 多人 pair / squash 前
Signed-off-by: Name <email> DCO 签署 Linux 基金会等项目
Reviewed-by: Name <email> 记录 review 部分企业规范
git commit -m "$(cat <<'EOF'
fix: validate upload MIME type

Co-authored-by: Alex Chen <alex@example.com>
Closes #456
EOF
)"

常见场景

  • PR Squash merge 时把多位作者的 Co-authored-by 写进最终 commit
  • IDE / AI 工具 自动插入 trailer — 提交前看一眼,去掉不需要或违反项目政策的行

Note

是否允许某种 trailer 以 目标仓库 的 CONTRIBUTING / DCO 为准;本文只介绍常见写法,不代替项目政策。


场景:PR 合并后 commit 长什么样

常见场景:在 GitHub/GitLab 上 merge PR,本地 history 出现 merge commit 或 squash commit。

合并方式 典型 log 表现 说明怎么写
Merge commit Merge pull request #99 from ... 保留分支上各 commit;PR 标题常作 merge 说明
Squash merge 一条 feat: ... (#99) PR 标题 往往变成最终 commit 首行 — 开 PR 时就按规范写标题
Rebase merge 分支上多条线性 commit 每个 commit 仍应保持原子、说明清晰

一句话:「在平台上 merge 时,PR 标题 ≈ 未来的 commit 标题(尤其 squash)。」


场景:与 commit-msg hook 配合

团队可在 commit-msg hook 里校验格式(例如必须 feat: 开头、首行非空)。示例与安装见 Gitignore 与 Hooks — commit-msg

效果:不合规时在本地 commit 失败,比 push 后 CI 打回更早。

Warning

不要习惯性 git commit --no-verify 绕过校验;hook 报错应修 message 或按团队流程申请例外。


场景:好 vs 差 — 对照示例

原因
update code fix(ui): prevent modal focus trap 具体、可检索
fix bug and add feature 拆成两个 commit 一个 commit 一件事
Fixed the thing. fix: handle timeout in payment webhook 祈使句、无句号、有范围
正文粘贴 200 行 diff 正文写 whytrade-off diff 在 git show 里已有
feat: ... + 无关 chore: bump deps 混提交 依赖升级单独 build: commit 便于 revert / bisect

速查:现象 → 建议

现象 建议
不知道写什么 首行:做了什么 + 哪里;正文:为什么
改动跨很多模块 拆 commit,或 scope 写主模块
commit 完发现漏文件 未 push → git add + commit --amend --no-edit
说明 typo 已 push 到 main 不要 amend main;必要时 revert 或 follow-up commit
项目有 CONTRIBUTING 以项目文档为准,本篇作通用参考
hook 拒绝提交 读报错改格式;见 hooks 文档
要写联合作者 Co-authored-by trailer;merge 策略与平台文档一致

更多命令:Git 命令集 — git commit