cz代码提交规范的工作流

# commit规范

commit message的格式

// Header
<type>(scope): <subject>
// 空一行
Body
// 空一行
Footer
1
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 
1
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.
1
2
3
4
5
6
7
8
9
10
11

(2)关闭 Issue

如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue 。

Closes #234
1

也可以一次关闭多个 issue

Closes #123, #245, #992
1

测试完整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
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
1

# 配置

package.json中写入:

"script": {
    ...,
    "commit": "git-cz",
}
1
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
1

# 配置

package.json中写入:

"config": {
    "commitizen": {
        "path": "node_modules/cz-conventional-changelog"
    }
}
1
2
3
4
5

安装配置好以后,执行npm run commit就会出现如下引导式填写:

img

img

# 校验 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
1

# 配置

安装完成以后,同时需要在项目根目录下创建配置文件commit.config.js或者.commitlintrc.js并写入:

module.exports = { 
    extends: [
        '@commitlint/config-conventional'
    ]
}
1
2
3
4
5

或者在package.json中写入:

"commitlint": {
    "extends": [
        "@commitlint/config-conventional"
    ]
  },
1
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 文件

部分规则不适用:

image-20201014182108437

# 编码规范

暂时统一使用@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
1

# 配置

安装完成以后,同时需要在项目根目录下创建配置文件.huskyrc或者.huskyrc.js文件并写入:

{
    "husky": {
        "hooks": {
            ...,
            "commit-msg": "commitlint -e $GIT_PARAMS"
        }
    }
}
1
2
3
4
5
6
7
8

或者在package.json中写入:

"husky": {
    "hooks": {
        ...,
        "commit-msg": "commitlint -e $GIT_PARAMS"
    }
}
1
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
1
2

# 配置

安装完成以后,同时需要在项目根目录下创建配置文件.lintstagedrc并写入:

{
  "*.{js,vue}": [
    "eslint --fix",
    "git add"
  ],
  "*.{html,vue,css,sass,scss}": [
    "stylelint --fix",
    "git add"
  ]
}
1
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"
  ]
}
1
2
3
4
5
6
7
8
9
10

在第三步创建的husky配置文件进行补充:

"husky": {
    "hooks": {
        "pre-commit": "lint-staged",
        "commit-msg": "commitlint -e $GIT_PARAMS"
    }
}
1
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
1

lerna项目时:

yarn add  -D commitizen
yarn add  -D cz-lerna-changelog
1
2

# 配置

"scripts": {
   "version": "standard-changelog -f && git add CHANGELOG.md",
    ...
 }
1
2
3
4

执行npm run version指令实际执行了五个动作:

  1. 修改package.json中的版本号
  2. 修改package-lock.json中的版本号
  3. 生成CHANGELOG.md文件
  4. 提交package.jsonpackage-lock.jsonCHANGELOG.md文件
  5. 给这次提交记录打上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"
    }
  }
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
上次更新: 2022/04/15, 05:41:30
×