---
name: 提交规范 & 规范校验
---

[TOC]

## 提交日志规范

​	在多人协作项目中，保持代码风格统一、代码提交日志规范，更便于代码维护以及Bug处理等。这里主要介绍下该如何来建立提交规范（围绕git commit 展开），以及在`git push` 代码之前检测`commit messages`。

---

### 规范格式

目前主流的Commit message格式基本上都采用**Angular规范**，比较合理和系统化，并且有配套的工具。

![Git-vue-commitMsg](https://img-blog.csdn.net/2018051117492049?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpZ2FuZzI1ODUxMTY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

​	Git commit日志参考案例：

- [angular](https://github.com/angular/angular)
- [commit-message-test-project](https://github.com/cpselvis/commit-message-test-project)
- [babel-plugin-istanbul](https://github.com/istanbuljs/babel-plugin-istanbul)
- [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog)

### 格式说明

​	Commit message一般包括三部分：Header、Body和Footer。Header 是必需的，Body 和 Footer 可以省略。[参考文档](http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html)

```
// Header
<type>(scope): <subject>
空行
Body
空行
Footer
```

#### Header：标题行

Header只有一行，包括type、scope和subject三个字段。

```	
<type>(scope): <subject>          // 冒号后面有空格
```

##### type【必需】

​	用于说明 commit 的类别，常见类别如下：

- `feat`：新增功能（feature）
- `fix`：修复补丁（bug）
- `docs`：修订文档，如Readme, Change Log, Contribute等
- `refactor`：代码重构，未新增任何功能和修复任何bug
- `style`： 仅调整空格、格式缩进等（不改变代码逻辑的变动）
- `perf`：优化相关，改善性能和体验的修改
- `test`：测试用例的增加/修改
- `chore`：非 src 和 test 的修改
- `merge`：合并分支或冲突等
- `revert`： 回滚到上一个版本
- build：改变构建流程，新增依赖库、工具等（例如webpack修改）
- ci：自动化流程配置修改

> *如果type为`feat`和`fix`，则该 commit 将肯定出现在` Change log` 之中。*

##### scope【可选】

​	用于说明 commit 的影响范围，可以是页面名，组件名等，可以省略。

##### subject【必需】

​	本次提交的简要描述，不超过50个字符，且结尾不加句号（.）。

#### Body：主体内容

对本次 commit 更详细的描述，可以分成多行，建议72个字符以内。 需要描述的信息包括:

+ 为什么提交这个变更?  它可能是用来修复一个bug，增加一个feature，提升性能、可靠性、稳定性等等
+ 如何解决这个问题? 具体描述解决问题的步骤
+ 是否存在副作用、风险? 

#### Footer：尾部

- 不兼容变动：需要描述相关信息
- 关闭指定Issue：输入Issue信息
- 其他：可以添加一个链接到issue地址或者其它文档

---

### 规范校验

目前主流的几种方案：

+ [commitlint](https://marionebl.github.io/commitlint/#/) [采用主流规范]
+ [yorkie](https://github.com/yyx990803/yorkie) [可自定义]
+ [validate-commit-msg](https://github.com/conventional-changelog-archived-repos/validate-commit-msg) [早期方案]

#### 安装[husky](https://github.com/typicode/husky) 

​	husky继承了Git下所有的hook，在触发`git hook`时，husky可以阻止不合法的 commit,push 等等。

```
// 安装husky@latest
cnpm install --save-dev husky@latest  //安装husky最新版，不用配置 scripts 脚本
```

> **使用husky前，必须先将代码放到git 仓库中，否则本地没有.git文件，就无法继承钩子。**

#### commitlint

​	commitlint 搭配 husky 的 commit message 钩子后，每次提交 git 版本信息的时候，会根据配置的规则进行校验，若不符合规则会 commit 失败，并提示相应信息。

##### 安装 `commitlint`  依赖

```
// 安装commitlint
cnpm install --save-dev @commitlint/config-conventional @commitlint/cli
```

##### 制定commit message规范

```js
// 在根目录生成配置文件
echo module.exports = {extends: ['@commitlint/config-conventional']}; > commitlint.config.js

// 修改commitlint.config.js
module.exports = {
    extends: ['@commitlint/config-conventional'],
    rules: {
        'type-enum': [
            2,
            'always',
            ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'chore', 'merge', 'revert'],
        ],
        'scope-empty': [2, 'never'],
        'subject-full-stop': [0, 'never'],
        'subject-case': [0, 'never'],
    },
};

// package.json配置husky钩子
"husky": {
    "hooks": {
      "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS"
    }
},
```

##### 执行提交操作

​	当执行git commit操作时，会触发 `commlint` 。如果不符合提交规范，会展示如下信息：

```cmd
> git add .
> git commit -m "新增商品列表页面"
husky > commit-msg (node v10.1.0)

⧗   input: 
foo: 新增商品列表页面

✖   type must be one of [feat, fix, docs, style, refactor, perf, test, chore, merge, revert] [type-enum]
✖   found 1 problems, 0 warnings 
    (Need help? -> https://github.com/marionebl/commitlint#what-is-commitlint)

husky > commit-msg hook failed (add --no-verify to bypass)
```

​	修整提交信息后，再次提交即可commit成功。

```
>git commit -m "feat: 新增商品列表页面"
husky > npm run -s commitmsg (node v8.6.0)

⧗   input: feat: 新增商品列表页面
✔   found 0 problems, 0 warnings

[develop 9b2a837] feat: 新增商品列表页面
 7 file changed, 1 insertion(+)
```

##### commitlint 官方的规则扩展

`@commitlint/config-conventional` 提供了官方的规则扩展：

```
build：主要目的是修改项目构建系统(例如 glup，webpack，rollup 的配置等)的提交
ci：主要目的是修改项目继续集成流程(例如 Travis，Jenkins，GitLab CI，Circle等)的提交
docs：文档更新
feat：新增功能
merge：分支合并 Merge branch ? of ?
fix：bug 修复
perf：性能, 体验优化
refactor：重构代码(既没有新增功能，也没有修复 bug)
style：不影响程序逻辑的代码修改(修改空白字符，格式缩进，补全缺失的分号等，没有改变代码逻辑)
test：新增测试用例或是更新现有测试
revert：回滚某个更早之前的提交
chore：不属于以上类型的其他类型
```

##### 问题汇总

1. git commit后可能报错相关`‘regenerator-runtime’`模块找不到；解决方式：`cnpm install regenerator-runtime –save`。

   

#### yorkie

[yorkie](https://www.npmjs.com/package/yorkie)用于执行git-hooks，fork 自husky，并集成了提交日志校验的功能。

```
 cnpm i -D yorkie
```
```js
// 在package.json中增加相关配置
"gitHooks": {
    "commit-msg": "node git-hooks/verify-commit-msg.js"
}

// verify-commit-msg.js
const chalk = require('chalk')
const msgPath = process.env.GIT_PARAMS
const msg = require('fs').readFileSync(msgPath, 'utf-8').trim()

const commitRE = /^(revert: )?(feat|fix|polish|docs|style|refactor|perf|test|workflow|ci|chore|types|build)(\(.+\))?: .{1,50}/

if (!commitRE.test(msg)) {
    console.error(
        `  ${chalk.bgRed.white(' ERROR ')} ${chalk.red(`invalid commit message format.`)}\n\n` +
        chalk.red(`  Proper commit message format is required for automated changelog generation. Examples:\n\n`) +
        `    ${chalk.green(`feat(compiler): add 'comments' option`)}\n` +
        `    ${chalk.green(`fix(v-model): handle events on blur (close #28)`)}\n\n` +
        chalk.red(`  You can also use ${chalk.cyan(`npm run commit`)} to interactively generate a commit message.\n`)
    )
    process.exit(1)
}
```

参考地址：[自定义Git-Git钩子](https://git-scm.com/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-Git-%E9%92%A9%E5%AD%90)



#### validate-commit-msg

[validate-commit-msg](https://github.com/kentcdodds/validate-commit-msg) 用于检查 Node 项目的 Commit message 是否符合格式。

```
cnpm i -D validate-commit-msg
```
```json
// 在工程根目录新建.vcmrc文件
{
    "types": [
      "feat",
      "fix",
      "docs",
      "test",
      "chore",
      "refactor",
      "perf",
      "revert",
      "custom"
    ],
    "warnOnFail": false,
    "maxSubjectLength": 100,
    "subjectPattern": ".+",
    "subjectPatternErrorMsg": "请输入message信息!",
    "helpMessage": "Commit message 格式错误， 			http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html"
}

// package.json
"husky": {
    "hooks": {
      "commit-msg": "validate-commit-msg"
    }
},
```



---

### 命令行工具校验

​	很多喜欢使用命令行工具的用户，可以借助一些工具来规范提交。最著名的应该是[commitizen](https://github.com/commitizen/cz-cli) 。通过该工具，选择更新的 type 和填写必要的信息，即可自动生成规范的提交日志。[参考文档](https://www.jianshu.com/p/36d970a2b4da)

#### 安装 commitizen

```
cnpm install -g commitizen   // 也可以全局安装
```

#### 安装adapter

​	commitizen 根据不同的`adapter`配置commit message。

##### cz-conventional-changelog

`	cz-conventional-changelog`，采用Angular的commit message格式：

```
cnpm install -g cz-conventional-changelog
```

##### cz-customizable

​	[**cz-customizable**](https://github.com/leonardoanalista/cz-customizable)和`cz-conventional-changelog`一样，也是commitizen的adapter，不过支持一定程度上的自定义。

```
cnpm install -g cz-customizable
```

​	在home目录下创建 **.cz-config.js** 文件,根据`node_modules/cz-customizable/cz-config-EXAMPLE.js`配置git cz时弹出的message和对应的输入或者选项。

​	如果想要进一步进行配置，直接修改`node_modules/cz-customizable`下的**questions.js**和**buildCommit.js**。

​	buildCommit.js中生成最终commit message：

![](https://segmentfault.com/img/remote/1460000014742185)

​	questions.js中message配置部分：

![](https://segmentfault.com/img/remote/1460000014742186)

#### 编写配置文件

```json
// 根目录中生成.czrc
{
	"path": "cz-customizable"
}
或
{
	"path": "cz-conventional-changelog" 
}
```

​	现在，进入任何git repository, 使用git cz代替`git commit`提交`，并根据提示来生成符合格式的 Commit message。

​	或者可以增加友好的npm命令，通过`yarn commit`进行提交！

```json
// package.json
"script": {
    "commit": "git-cz"
    ...
}
```



---

### 跳过校验

使用`git commit`命令的 `--no-verify` 参数可以跳过检验规则。

```
git add . && git commit --no-verify -m "代码规范强制提交测试"
```

