cz代码提交规范的工作流
# commit规范
commit message的格式
// Header
<type>(scope): <subject>
// 空一行
Body
// 空一行
Footer
2
3
4
5
6
不管是哪一个部分,任何一行都不得超过72个字符(或100个字符),这是为了避免自动换行影响美观(我的测试是不能超过72字符)
Header:是必需的
(1) 注意冒号后面有空格,不能以大写字母开头;
(2) 包括三个字段:type(必需)、scope(可选)和subject(必需)
- type:用于说明 commit 的类型,被指定在 commitlint.config.js 的 type-enum feat:新功能(feature) fix:修补bug docs:文档 style: 格式(不影响代码运行的变动) refactor:重构(即不是新增功能,也不是修改bug的代码变动) test:增加测试 chore:构建过程或辅助工具的变动 revert: 回滚到上一个版本
有一种比较特殊的情况: revert
如果当前 commit 用于撤销以前的 commit,则必须以revert:开头,后面跟着被撤销 Commit 的 Header。
revert: feat(pencil): add 'graphiteWidth' option
This reverts commit
2
- scope: 可以省略;用于说明 commit 的影响范围,比如数据层、控制层、视图层等等,视项目不同而不同
- subject:subject 是 commit 目的的简短描述,不超过50个字符 以动词开头,使用第一人称现在时,比如change,而不是changed或changes 第一个字母小写 结尾不加句号(.)
Body:可省略; body 部分是对本次 commit 的描述,可以分成多行
有两个注意点。
(1)使用第一人称现在时,比如使用change而不是changed或changes。
(2)应该说明代码变动的动机,以及与以前行为的对比。
Footer:可省略; footer 用于不兼容变动和关闭ISSUE (1)不兼容变动
如果当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。例如:
BREAKING CHANGE: isolate scope bindings definition has changed.
To migrate the code follow the example below:
Before:
scope: {
myAttr: 'attribute',
}
After:
scope: {
myAttr: '@',
}
The removed `inject` wasn't generaly useful for directives so there should be no code using it.
2
3
4
5
6
7
8
9
10
11
(2)关闭 Issue
如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue 。
Closes #234
也可以一次关闭多个 issue
Closes #123, #245, #992
测试完整commit message
//使用git commit 方便输入多行的commit message
$ git commit
//输入完整的commit message: header + body +footer
test(): 测试完成commit message
I just change string to test
完整的commit message
添加了一个 测试字符串
Closes #111
//输入完成后
husky > commit-msg (node v10.13.0)
⧗ input: test(): 测试完成commit message
✔ found 0 problems, 0 warnings[master 7ac378a] test(): 测试完成commit message
1 file changed, 1 insertion(+), 1 deletion(-)
//查看最近一个提交记录
git log -n 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 格式化 commit message
commit message
的重要性我就不在这强调了,我们常规提交代码都是通过git commit -m "xxx"
附上一句话来描述此次代码的改动,这样的方式对于一些影响范围大或者broken
式的改动来说太过于简单随意。每个人都有自己习惯的提交代码方式,所以我们需要借助一个工具来生成符合规范的commit message
并约束提交的人。
commitizen (opens new window)是一个格式化commit message
的工具,可以约束提交者按照制定的规范一步一步的填写commit message
。
# 局部安装
npm i -D commitizen
# 配置
package.json
中写入:
"script": {
...,
"commit": "git-cz",
}
2
3
4
这样我们就可以借助commitizen
提供的git-cz
,用npm run commit
命令来替代git commit
命令。
# 采用团队代码提交规范
我们已经把可以生成指定commit message
的工具commitizen
安装好了,接下来要做的就是为commitizen
制定一套填写规范。
cz-conventional-changelog (opens new window) is a commitizen adapter for the angular preset of conventional-changelog (一套适用于commitizen
的团队规范)。目前采用比较广泛,那我们就直接给commitizen
引用这套规范了。
# 局部安装
npm i -D cz-conventional-changelog
# 配置
package.json
中写入:
"config": {
"commitizen": {
"path": "node_modules/cz-conventional-changelog"
}
}
2
3
4
5
安装配置好以后,执行npm run commit
就会出现如下引导式填写:
# 校验 commit message
虽然之前两步已经约束了一套代码提交规范,但是还是有人不按照规范提交代码怎么办呢?这个时候就需要commitlint (opens new window)来帮助我们校验commit message
,拒绝不符合规范的commit message
。
与eslint
类似,commitlint
也需要一份校验的配置。别着急,这里有一份与cz-conventional-changelog
规范(angular
团队规范)配套的校验配置@commitlint/config-conventional (opens new window)来帮助我们检验commit message
的合规性。
# 局部安装
npm i -D @commitlint/config-conventional @commitlint/cli
# 配置
安装完成以后,同时需要在项目根目录下创建配置文件commit.config.js
或者.commitlintrc.js
并写入:
module.exports = {
extends: [
'@commitlint/config-conventional'
]
}
2
3
4
5
或者在package.json
中写入:
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
2
3
4
5
commitlint
就可以运用config-conventional
这套校验配置。
# 代码提交
统一使用约定式提交 (opens new window),常用以下前缀:
feat:
表示有新功能增加。fix:
表示修复BUG。docs:
表示补充文档和说明等内容。build:
表示修改构建脚本等。test:
表示增加或修改测试。ci:
表示修改CI/CD相关内容,如代码检查等。chore:
表示日常维护,如升级依赖等。refractor:
表示对功能和BUG没有影响的内部重构,包括增加注释等。
# 说明
可通过
Git CZ Emoji
实现快速提交;
类型 | emji | 描述 |
---|---|---|
feat | ✨ | 引入新功能 |
fix | 🐛 | 修复 bug |
style | 💄 | 更新 UI 样式文按键 |
format | 🥚 | 格式化代码 |
docs | 📝 | 添加/更新文档 |
perf | 👌 | 提高性能/优化 |
init | 🎉 | 初次提交/初始化项目 |
test | ✅ | 增加测试代码 |
refactor | 🎨 | 改进代码结构/代码格式 |
patch | 🚑 | 添加重要补丁 |
file | 📦 | 添加新文件 |
publish | 🚀 | 发布新版本 |
tag | 📌 | 发布新版本 |
config | 🔧 | 修改配置文件 |
git | 🙈 | 添加或修改.gitignore 文件 |
部分规则不适用:
# 编码规范
暂时统一使用@ecomfe/eslint-config (opens new window)作为规则集,由reskript (opens new window)提供检测能力,后续讨论后再调整相应的规则。
具体当前的编码规范参考:https://github.com/ecomfe/spec
# 配置校验时机
到了第三步我们的代码提交约束规范已经基本成型了,最后一步要做的就是配置触发commit message
校验的时机。
校验commit message
的最佳姿势是git hook (opens new window)和husky (opens new window)的结合。
husky
(哈士奇)是个什么东西呢?简单来说就是个能让你在每个git钩子中配置相应行为的一个工具。
# 局部安装
npm install husky --save-dev
# 配置
安装完成以后,同时需要在项目根目录下创建配置文件.huskyrc
或者.huskyrc.js
文件并写入:
{
"husky": {
"hooks": {
...,
"commit-msg": "commitlint -e $GIT_PARAMS"
}
}
}
2
3
4
5
6
7
8
或者在package.json
中写入:
"husky": {
"hooks": {
...,
"commit-msg": "commitlint -e $GIT_PARAMS"
}
}
2
3
4
5
6
在git commit-msg
这个钩子中会触发commitlint
的操作。
# 自动化代码检查
经过前三步已经打造好了基于angular
团队代码提交规范的工作流了,但是如果我们还想在校验commit message
的规范性的同时,校验此次提交代码的正确性呢?
借助 lint-staged (opens new window) 可以让你每次只对你此次提交所在暂存区的文件(git add
后的文件)进行一系列的检查、修复、格式化操等作。
# 局部安装
npm install -D lint-staged
#yarn add -D standard lint-staged
2
# 配置
安装完成以后,同时需要在项目根目录下创建配置文件.lintstagedrc
并写入:
{
"*.{js,vue}": [
"eslint --fix",
"git add"
],
"*.{html,vue,css,sass,scss}": [
"stylelint --fix",
"git add"
]
}
2
3
4
5
6
7
8
9
10
或者在package.json
中写入:
"lint-staged": {
"*.{js,vue}": [
"eslint --fix",
"git add"
],
"*.{html,vue,css,sass,scss}": [
"stylelint --fix",
"git add"
]
}
2
3
4
5
6
7
8
9
10
在第三步创建的husky
配置文件进行补充:
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -e $GIT_PARAMS"
}
}
2
3
4
5
6
在pre-commit
这个钩子中,lint-staged
会执行.lintstagedrc
配置的操作(列出来的配置的意思是对本次提交的js
或者vue
文件进行eslint
检查并修复,并且把修复过后的文件再重新提交到暂存区)。
# 版本发布
对于每次项目新版本的发布,我们需要更新相应的版本号并记录其中的改变。可以借助 standard-changelog (opens new window) 工具,来配合npm run version
,并自动生成CHANGELOG
。
# 局部安装
npm install standard-changelog --save-dev
lerna项目时:
yarn add -D commitizen
yarn add -D cz-lerna-changelog
2
# 配置
"scripts": {
"version": "standard-changelog -f && git add CHANGELOG.md",
...
}
2
3
4
执行npm run version
指令实际执行了五个动作:
- 修改
package.json
中的版本号 - 修改
package-lock.json
中的版本号 - 生成
CHANGELOG.md
文件 - 提交
package.json
、package-lock.json
、CHANGELOG.md
文件 - 给这次提交记录打上
tag
一般项目要上线新版本的时候,需要把
release
分支合到master
,合完分支以后执行npm run version
指令给这次发布打上tag
并记录修改是一个良好的维护版本迭代的好习惯。
# 总括配置及步骤
"scripts": {
"lint:style": "stylelint \"src/**/*.less\" --syntax less",
"lint:prettier": "check-prettier lint",
"lint": "eslint --ext .js src mock tests && npm run lint:style && npm run lint:prettier",
"lint:fix": "eslint --fix --ext .js src mock tests && npm run lint:style",
"lint-staged": "lint-staged",
"lint-staged:js": "eslint --ext .js",
"tslint": "npm run tslint:fix",
"tslint:fix": "tslint --fix 'src/**/*.ts*'",
"prettier": "node ./scripts/prettier.js",
"fix": "npm run lint -- --fix",
"changelog": "standard-changelog -f && git add CHANGELOG.md",
"commit": "git-cz"
},
"devDependencies": {
"@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0",
"commitizen": "^4.2.1",
"cz-conventional-changelog": "^3.3.0",
"standard-changelog": "^2.0.24",
#"cz-lerna-changelog": "^2.0.2",
#"lerna": "^3.15.0"
},
"config": {
"commitizen": {
"path": "node_modules/cz-conventional-changelog"
# "path": "./node_modules/cz-lerna-changelog"
}
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
],
"rules": {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"test",
"chore",
"revert"
]
],
"subject-full-stop": [
0,
"never"
],
"subject-case": [
0,
"never"
]
}
},
"lint-staged": {
"**/*.{js,ts,tsx,json,jsx,less}": [
"node ./scripts/lint-prettier.js",
// "eslint --fix --ext .js",
"git add"
],
// "**/*.{js,jsx}": "npm run lint-staged:js",
// "**/*.less": "stylelint --syntax less",
"*.{html,vue,css,sass,scss}": [
"stylelint --fix",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -e $GIT_PARAMS"
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77