规范你的git提交

缘起

公司的 git 提交比较乱,很多对应的 issue 没有链起来,不知道哪个是哪个,在这里尝试整理 git commit 的提交规范和应对措施。

规范是人定的,有一个人不遵守,到最后所有人都随便,破窗效应怎么办?自动化来做这件事。

什么是好的规范?

看看 angularvue 的 github 仓库提交。

Angular 提交历史

Vue 提交历史

Angular 还总结出一套规范,得到了社区的广泛认同:

1
2
3
4
5
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

type 的值很多,比如 featbuilddocsfix 等。

描述
feat 新增一个功能
fix 修复一个 Bug
docs 文档变更
style 代码格式(不影响功能,例如空格、分号等格式修正)
refactor 代码重构
perf 改善性能
test 测试
build 变更项目构建或外部依赖(例如 scopes: webpack、gulp、npm 等)
ci 更改持续集成软件的配置文件和 package 中的 scripts 命令,例如 scopes: Travis, Circle 等
chore 变更构建流程或辅助工具
revert 代码回退

你现在再回头看看 ng 和 vue 的提交记录应该就有感觉了。

项目里怎么用?

先了解规范,再使用规范,最终使用工具来辅助完成。

需要用到这几个npm插件:

  • commitizen commit 格式化
  • cz-conventional-changelog 社区流行的规范
  • cz-customizable 自定义规范
  • @commitlint/cli 校验规范
  • husky git 钩子
  • conventional-changelog 根据提交自动生成版本日志

版本日志都是自动生成的,是不是恍然大悟。

使用这些插件,可以一步一步来。

渐进使用

先自己用,先约束自己,同时不污染已有项目。

1
2
3
4
5
6
# 全局安装
npm i -g commitizen cz-conventional-changelog
# 用户目录写入配置
echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc
# git add file 然后执行提交
git-cz

有的喜欢在 feat 前面加个 emoji表情,或者想汉化怎么办,这就是自定义部分了

1
2
3
4
5
6
7
8
9
10
# 接上面
npm i -g cz-customizable
# 修改 ~/.czrc
{ "path": "cz-customizable" }
# 创建配置文件,后来发现windows放到用户目录不好使
# touch ~/.cz-config.js
# 放到项目目录就好了
touch ./.cz-config.js
# 修改自定义的配置
# https://github.com/leonardoanalista/cz-customizable/blob/master/cz-config-EXAMPLE.js

代码还是贴一下吧。

emoji 在这里找 https://gitmoji.carloscuesta.me/

file: .cz-config.js:

1
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
78
79
module.exports = {
types: [
{ value: "🎉feat", name: "feat: A new feature" },
{ value: "fix", name: "fix: A bug fix" },
{ value: "docs", name: "docs: Documentation only changes" },
{
value: "style",
name:
"style: Changes that do not affect the meaning of the code\n (white-space, formatting, missing semi-colons, etc)"
},
{
value: "refactor",
name:
"refactor: A code change that neither fixes a bug nor adds a feature"
},
{
value: "perf",
name: "perf: A code change that improves performance"
},
{ value: "test", name: "test: Adding missing tests" },
{
value: "chore",
name:
"chore: Changes to the build process or auxiliary tools\n and libraries such as documentation generation"
},
{ value: "revert", name: "revert: Revert to a commit" },
{ value: "WIP", name: "WIP: Work in progress" }
],

scopes: [
{ name: "accounts" },
{ name: "admin" },
{ name: "exampleScope" },
{ name: "changeMe" }
],

allowTicketNumber: false,
isTicketNumberRequired: false,
ticketNumberPrefix: "TICKET-",
ticketNumberRegExp: "\\d{1,5}",

// it needs to match the value for field type. Eg.: 'fix'
/*
scopeOverrides: {
fix: [

{name: 'merge'},
{name: 'style'},
{name: 'e2eTest'},
{name: 'unitTest'}
]
},
*/

// override the messages, defaults are as follows
messages: {
type: "Select the type of change that you're committing:",
scope: "\nDenote the SCOPE of this change (optional):",
// used if allowCustomScopes is true
customScope: "Denote the SCOPE of this change:",
subject: "Write a SHORT, IMPERATIVE tense description of the change:\n",
body:
'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
breaking: "List any BREAKING CHANGES (optional):\n",
footer:
"List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n",
confirmCommit: "Are you sure you want to proceed with the commit above?"
},

allowCustomScopes: true,
allowBreakingChanges: ["feat", "fix"],
// skip any questions you want
skipQuestions: ["body"],

// limit subject length
subjectLimit: 100
// breaklineChar: '|', // It is supported for fields body and footer.
// footerPrefix : 'ISSUES CLOSED:'
// askForBreakingChangeFirst : true, // default is false
}

这时候再执行 get-cz 就有自定义的内容了。

必要的话,可以把 .cz-config.js 放到 .gitignore 里面,这样就完成了在不污染项目的情况下,对自己进行了约束。

接下来,可以说:

  • 项目集成
  • commit校验
  • 自动生成版本日志

husky 一本通

1
yarn add husky@next -D

.huskyrc

1
2
3
4
5
6
7
8
9
10
{
"husky": {
"hooks": {
"pre-commit": "npm test",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-push": "npm test",
"...": "..."
}
}
}

1 简单用法

1
2
3
4
5
{
"scripts":{
"precommit": "eslint src/**/*.js"
}
}

会检测所有的文件。不是渐进式修改。

2 只检测本次修改的文件

git 路径:add -- staged -- commit

安装这个插件,在commit之前会检测 staged 的文件

1
yarn add lint-staged -D
1
2
3
4
{
"scripts":{"precommit":"lint-staged"},
"lint-staged":{"scr/**/*.js":"eslint"}
}

或者,lint完了再 add

1
2
3
4
5
6
7
8
{
"scripts": {
"precommit": "lint-staged"
},
"lint-staged": {
"src/**/*.js": ["eslint --fix", "git add"]
}
}

或者,使用 prettier

1
2
3
4
5
6
7
8
{
"scripts": {
"precommit": "lint-staged"
},
"lint-staged": {
"src/**/*.js": ["prettier --write", "git add"]
}
}

3 结合 commitlint

1
yarn add -D @commitlint/cli

ng风格和自定义风格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# ng
yarn add -D @commitlint/config-conventional

#
custome

yarn add -D commitlint-config-cz

#
配置文件

touch commitlint.config.js
# ng校验
module.exports = { extends: ['@commitlint/config-conventional'] };

#
custom 校验
module.exports = { extends: [ 'cz' ] };

#
git hooks 提交时候校验规则
"husky": { "hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } }

开发日志,先放着

1
yarn add -D conventional-changelog
1
2
3
{
"version": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md"
}

请我喝杯咖啡吧~