1.前言
在git commit中提交信息中,如果能找按照规范写好,能提高可读性以及项目维护效率。本文针对message的规范和提交检测工具进行介绍。
2.参考的规范:Angular Team Commit Specification
详细的提交信息可以让人知道本次提交对原项目进行哪方面的修改。是修复bug、添加组件或模块、修改代码风格还是重构。从message中也可以知道针对哪部分的文档或模块进行修改。
但这个message到底要怎么去写比较好?这里可以参考Angular团队的git-commit-guidelines。以下为该团队对message做出的规范格式:
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
每一次提交信息都包含着header、body和footer。头部包括type,scope和subject。
如果本次提交时是对上一次的提交进行回滚,则header需要以revert:
开头,在body里需要写明:This reverts commit .hash指的是每次commit提交后git生成的SHA值。每次提交的SHA值可以通过git log查看到:
1.header
在header中,type和subject是必填项,scope是选填项。下面对头部这三个部分进行详细介绍:
(1)type
必填项,用于说明本次提交做出哪种类型的修改,必须是以下任意一值:
- feat: A new feature(新功能)
- fix: A bug fix(bug的修复)
- docs: Documentation only changes(修改项目中的文档)
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)(不影响代码逻辑下的样式修改,通常是风格修改,例如空格、格式、分号方面的修改等)
- refactor: A code change that neither fixes a bug nor adds a feature(重构,不包括修复bug和添加新功能)
- perf: A code change that improves performance(性能优化)
- test: Adding missing or correcting existing tests(添加或者修改测试代码)
- chore: Changes to the build process or auxiliary tools and libraries such as documentation generation(对构建过程或辅助工具和库(如文档生成)的更改)
(2)scope
选填项,用于说明本次提交中改动的位置。国内通常以项目名/模块名
为格式。一次提交中如果有多处修改,官方说可以用*
去缺省。但个人倾向于每次提交都是针对单处修改,这样子阅读提交信息会更详细。
(3)subject
必填项,用于简要地描述本次提交中所做出的修改。而且需要满足格式:
- 如果用英文描述,则英文单词只能是一般现在时或者祈使语气
- 首字母不能大写
- 不能以
.
作为结尾
2.body
选填项,相对于上述的subject,body用于更加详细的描述本次提交中所做出的修改。其中需要包括本次修改的动机以及对比于修改之前的改进之处。
3.footer
选填项,主要包括以下两点:
- break changes:任何关于与上个版本不兼容的更改(breaking change)的信息,例如版本升级、数据字段更改、接口参数变化等。如果存在breaking change,则需要以
BREAKING CHANGE:
开头后接空格或者两行新行后,写清楚更改的内容。 - affect issues:指明本次修改是否针对某次issues。
3.提交信息预格式化工具
(1)commitizen
官方推荐的用于编写合格的提交信息的工具,用于替代git commit
指令。详细配置可看:commitizen。我本人没有用到这个工具,是因为vscode提交已经习惯了用按钮去提交,如果项目中用到commitizen,则之后提交需要用git cz
替代git commit
指令进行提交。会改变整个操作流程,在团队里推广不了。
(2)Commit Message Editor
这里我选择了一款VSCode中的生成格式化提交信息的工具Commit Message Editor,操作可看下图:
(1)普通操作时
(2)使用Angular格式提交信息时
4.提交信息检查工具
1.安装
npm install -D @commitlint/config-conventional @commitlint/cli husky
husky:一个git hooks工具。
commitlint:一个用于检测提交信息格式(commit message format)的工具
2.配置
(1).huskyrc
首先配置husky方面,在根目录新建一个名为.huskyrc
(也可以是.huskyrc.json
)的文件,写入以下内容:
//.huskyrc
{
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
上述代码目的是为了在git执行commit和merge之前,先执行commitlint -E HUSKY_GIT_PARAMS。从而使commitlint检测提交信息。
**拓展:**git hooks有很多个周期函数,更多可点击查看githooks。有人会问为什么不用"pre-commit"
和"pre-commit-msg"
。
我们可以在刚刚附注的githooks网址里查看"pre-commit"
的解释:
This hook is invoked by git-commit[1], and can be bypassed with the
--no-verify
option. It takes no parameters, and is invoked before obtaining the proposed commit log message and making a commit. Exiting with a non-zero status from this script causes thegit commit
command to abort before creating a commit.
看打粗部分的解释,"pre-commit"
是在获取已提交的commit log message之前触发的。因此不能检测提交信息。
再看以下"pre-commit-msg"
的解释:
This hook is invoked by git-commit[1] right after preparing the default log message, and before the editor is started.
对比以下"commit-msg"
的解释:
This hook is invoked by git-commit[1] and git-merge[1], and can be bypassed with the
--no-verify
option. It takes a single parameter, the name of the file that holds the proposed commit log message. Exiting with a non-zero status causes the command to abort.
可以知道,"pre-commit"
和"pre-commit-msg"
都是在因git commit触发的,而"commit-msg"是因git commit和git merge触发的,在多人合作项目中避免不了git merge指令,因此我们选择"commit-msg"
周期函数。
(2)commitlint.config.js
其后配置commitlint的参数,写入以下内容:
//commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'scope-case': [0]
}
}
上面代码意思为指定提交信息的检测规则为'@commitlint/config-conventional'。
检测规则有很多类,最常用的是上面采用的Conventional Commits specification。此规则是根据上文所说的Angular Team Commit Specification衍生出来的。commitlint更多规则可看:Shared configuration。
**拓展:**上面网址的规则中有两个比较类似的规则:
自己对比看了一下,'@commitlint/config-angular'
是几乎满足了本文第二点中介绍的header、body、footer中所有的规则。然后添加了header中的type和scope必须为小写的规则。
而'@commitlint/config-conventional'
是继承'@commitlint/config-angular'
的全部规则上还有一些小的约束,例如:
- header最大长度为100个字符
- body和footer每行的最大长度为100个字符,注意这里是每行,即可以换行。
添加了以上两个配置后,每次git commit前就会根据规则检查,如果不符合规则,则会中断,例如:
我提交的信息为:ci(.huskyrC): test
,因为scope
存在大写字母,所以被截止了不能提交。
5.rules的编写
和eslint的规则一样,rules中定义的规则的优先级是最高的。所以当@commitlint/config-conventional里面的部分检测规则不适用于自己的项目时,就可以通过rules
改写。如下所示:
"rules": {
"header-max-length": [0, "always", 72],
}
rules
中定义的每一条规则由名称header-max-length
和配置数组[0, "always", 72]
组成。
配置数组中有三个元素,分别为:
- Level:为0,1,2三个数的其中一值。0代表让本规则无效;1代表以警告提示,不影响编译运行;2代表以错误提示,阻止编译运行。以上面的例子则代表该规则不会起作用。
- Applicable :为
always
和never
其中一值。never
代表反转规则,相当于!取反。 - Value:适用于该规则的值。以上面的例子则代表
header
最大的字数只能为72。
针对我自己的项目,因为scope
我用于写修改的文件夹名称,所以会存在大写的情况,所以我针对此处用rules修改如下所示:
rules: {
'scope-case': [0]
}
意为不再让scope的大小写规则校验生效。如果我这时候再次以ci(.huskyrC): test
提交,则不会报错。
6.拓展:添加type
针对实际的开发场景中,Angular Team Commit Specification中定义的type可能满足不了开发者应对的修改类型。就如自己的项目开发,有些修改是因为UI的改动而调整组件css样式。因此,团队商量后添加了一个名为ui的type类型。
改动如下:
//commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'scope-case': [0],
'type-enum': [
2,
'always',
[
'build',
'chore',
'ci',
'docs',
'feat',
'fix',
'perf',
'refactor',
'revert',
'style',
'test',
'ui' //针对css方面的改变新增的类型
]
]
}
}
rules
中添加针对type-enum
的检测,其中的第三个参数value
列表中除了原有的类型外,还添加ui
作为新的类型。
针对VSCode的插件Commit Message Editor,添加type类型可以在setting.json中添加下面一段:
"commit-message-editor.tokens": [
{
"label": "Type",
"name": "type",
"type": "enum",
"options": [
{
"label": "---",
"value": ""
},
{
"label": "build",
"description": "Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)"
},
{
"label": "chore",
"description": "Updating grunt tasks etc; no production code change"
},
{
"label": "ci",
"description": "Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)"
},
{
"label": "docs",
"description": "Documentation only changes"
},
{
"label": "feat",
"description": "A new feature"
},
{
"label": "fix",
"description": "A bug fix"
},
{
"label": "perf",
"description": "A code change that improves performance"
},
{
"label": "refactor",
"description": "A code change that neither fixes a bug nor adds a feature"
},
{
"label": "revert"
},
{
"label": "style",
"description": "Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)"
},
{
"label": "test",
"description": "Adding missing tests or correcting existing tests"
},
{
"label": "ui",
"description": "Modify css"
}
],
"description": "Type of changes"
},
{
"label": "Scope",
"name": "scope",
"description": "A scope may be provided to a commit’s type, to provide additional contextual information and is contained within parenthesis, e.g., <code>feat(parser): add ability to parse arrays</code>.",
"type": "text",
"multiline": false,
"prefix": "(",
"suffix": ")"
},
{
"label": "Short description",
"name": "description",
"description": "Short description in the subject line.",
"type": "text",
"multiline": false
},
{
"label": "Body",
"name": "body",
"description": "Optional body",
"type": "text",
"multiline": true
},
{
"label": "Breaking change",
"name": "breaking_change",
"type": "boolean",
"value": "BREAKING CHANGE: ",
"default": false
},
{
"label": "Footer",
"name": "footer",
"description": "Optional footer",
"type": "text",
"multiline": true
}
]
主要是以下这段红框里的代码:
此时使用Commit Message Editor就可以选择名为ui
的type,如下所示: