省流:
这套规范叫 Conventional Commits
常用格式:
type(scope): description
feat = 新功能
fix = 修 bug
scope 可选:
feat: add login
feat(auth): add login
不要写:
feat(): add login
破坏性变更:
feat(api)!: change user endpoint
好家伙,
今天整理 Git 提交信息规范。
这套写法来自 Conventional Commits 1.0.0 官方规范,不是 Git 强制语法,而是一套社区约定。
它的价值很简单:
让人一眼看懂这次提交做了什么。
也让工具能根据提交信息生成 changelog 或判断版本号。
Conventional Commits 官方规范也说明,它很大程度上受 Angular Commit Guidelines 启发。
0.为什么提交信息也要有规范
先说一个很现实的问题。
如果一个项目的提交记录长这样:
update
fix
修改
再改一下
临时提交
bug fix
过两周再回头看,基本等于没写。
你只能一个个点开 diff 猜:
这次到底改了什么?
是加功能?
是修 bug?
是改文档?
还是只是格式化?
提交信息规范要解决的就是这个问题。
它不是为了装专业。
它是为了让提交记录能被人看懂,也能被工具识别。
比如:
feat
fix
docs
refactor
test
chore
这些词放在提交信息最前面,相当于给每次提交打了一个类型标签。
以后看日志时,就能快速知道:
哪些提交是新功能
哪些提交是修 bug
哪些提交只是文档或测试
哪些提交可能影响版本号
1.先看基本格式
Conventional Commits 的基本格式可以先记成这样:
():
更完整一点是:
[optional scope][!]:
[optional body]
[optional footer(s)]
先别被完整格式吓到。
日常最常用的就是第一行。
比如:
feat(blog): add draft import command
fix(publish): avoid duplicate image upload
docs(readme): add setup guide
可以看这张图:
Conventional Commits结构
里面最关键的是四块:
type: 这次改动是什么类型
scope: 这次影响哪个模块,可选
!: 是否是破坏性变更,可选
description: 一句话说明做了什么
所以不要把它理解成复杂语法。
它本质上就是:
用固定格式说清楚这次提交的性质。
2.feat是什么
feat 表示:
新增功能。
比如你给项目加了一个之前没有的能力:
feat(auth): add password login
feat(blog): support markdown import
feat(api): add user profile endpoint
这些都属于 feat。
我现在的判断方法是:
用户或调用方能感知到一个新能力,大概率就是 feat。
比如在这个博客项目里:
支持导入 Markdown 文件
支持上传图片到博客园
支持生成发布预览
这些都算功能。
所以可以写:
feat(draft): import markdown file
feat(publish): upload local images
feat(preview): generate cnblogs publish preview
3.fix是什么
fix 表示:
修复 bug。
比如之前功能已经存在,但是有问题:
fix(publish): handle png upload failure
fix(parser): keep code block indentation
fix(cli): show readable error on missing token
我现在的判断方法是:
原来应该能正常工作,但实际不正常,这次把它修好了,就是 fix。
比如:
图片路径没有被替换成远程地址
发布时重复上传同一张图片
Markdown 表格渲染错位
命令报错信息不清楚
这些都更适合写 fix。
4.scope是什么
scope 就是括号里的部分。
比如:
feat(auth): add password login
fix(publish): retry image upload
docs(readme): add install steps
这里的:
auth
publish
readme
就是 scope。
它表示这次提交主要影响哪个范围。
scope 不是必须的。
如果不用 scope,就直接写:
feat: add markdown import
fix: avoid empty title
注意这里有一个容易写错的地方:
feat(): add markdown import
这种写法不推荐。
因为 scope 是可选的。
如果没有 scope,就把括号整个省掉:
feat: add markdown import
如果有 scope,再写括号:
feat(draft): add markdown import
也就是说:
有范围 -> feat(scope): xxx
没范围 -> feat: xxx
不要写空括号。
5.除了feat和fix,还有哪些常见type
一开始不用背太多。
先把这些常见的用准就行:
常见提交type
我现在会这样记:
| type | 什么时候用 | | — | — | | feat | 新增功能 | | fix | 修复 bug | | docs | 只改文档 | | style | 只改格式,不影响逻辑 | | refactor | 重构代码,行为不变 | | test | 新增或修改测试 | | chore | 杂项维护 | | perf | 性能优化 | | build | 构建系统相关 | | ci | CI/CD 流水线相关 |