基础知识
git
的提交说明可以分为三个部分: Header
, Body
, Footer
Header
Header
: 包括三个字段: type(必需)
、scope(可选)
、subject(必需)
<type>(<scope>): <subject>
example:
feat(登录模块): 初始化登录页面
// 忽略scope(模块范围)
fix: 修复bug `#1024`
type
用于说明
commit
的提交类型
值 | 描述 |
---|---|
feat | 新增一个功能 |
fix | 修复bug |
docs | 文档变更 |
style | 代码格式(对功能无影响, 例如空格, 分号, 单引双引等) |
refactor | 代码重构 |
perf | 改善性能 |
test | 测试 |
build | 变更项目构建或外部依赖 |
ci | 更新持续集成相关配置或package.json中scripts 命令 |
chore | 变更构建流程或辅助工具??? |
revert | 代码回退 |
scope
说明commit
的影响范围, 或者说功能模块, 且可以省略
subject
是对commit
的概要
Body
对commit
详细说明
Footer
如果提交的代码是不兼容变更 或 关闭Issues, 则Footer
是必须的, 否则可以省略 不兼容变更: 当前代码与上一个版本不兼容, 则Footer
以BREAKING CHANGE
开头, 后面是对变动的描述以及变动的理由和迁移方法 提交Demo:
相关库介绍
Commitizen
一个提交的命令行工具库, packageName为: commitizen
, 地址为commitizen/cz-cli 启动命令为cz
或者git cz
npx cz
cz的默认适配器是streamich/git-cz 执行cz
命令会使用streamich/git-cz adapter
执行git cz
命令只是同git commit
一样工作 什么是适配器呢? 我认为就是一个提交的约定规范, 如上面的Header
下的type
类型, 就是AngularJS
的提交规范.
Commitizen适配器
cz-conventional-changelog
可以生成AngularJS提交规范的适配器, 可直接使用以下命令使用:
commitizen init cz-conventional-changelog --save --save-exact
上面的命令做了三件事:
- 安装
cz-conventional-changelog
- 将适配器包名保存在
package.json
的devDependencies
- 将 config.commitizen 键添加到 package.json 文件的根目录,如下所示:
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
}
上面命令执行成功之后就可以执行cz
命令, 提交符合AngularJS
规范的提交说明
cz-customizable
这个适配器可自定义项目的提交规范
安装: npm install cz-customizable --save-dev
在package.json
中更改Commitzen
的适配器路径:
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"
}
}
到根目录下新建.cz-config.js
, 这是cz-customizable
的配置文件,可在其中自定义提交规范 下面是一个简单的.cz-config.js
示例, 官方示例请点击这里
module.exports = {
// 可选类型
types: [
{ value: 'feat', name: 'feat: 新功能' },
{ value: 'fix', name: 'fix: 修复' },
{ value: 'docs', name: 'docs: 文档变更' },
{ value: 'style', name: 'style: 代码格式(不影响代码运行的变动)' },
{
value: 'refactor',
name: 'refactor: 重构(既不是增加feature,也不是修复bug)'
},
{ value: 'perf', name: 'perf: 性能优化' },
{ value: 'test', name: 'test: 增加测试' },
{ value: 'chore', name: 'chore: 构建过程或辅助工具的变动' },
{ value: 'revert', name: 'revert: 回退' },
{ value: 'build', name: 'build: 打包' }
],
// 消息步骤
messages: {
type: '请选择提交类型:',
customScope: '请输入修改范围(可选):',
subject: '请简要描述提交(必填):',
body: '请输入详细描述(可选):',
footer: '请输入要关闭的issue(可选):',
confirmCommit: '确认使用以上信息提交?(y/n/e/h)'
},
// 跳过问题
skipQuestions: ['body', 'footer'],
// subject文字长度默认是72
subjectLimit: 72
}
之后就可以使用cz
命令进行提交.
Commitizen提交校验
commitlint
: 检验提交说明是否符合规范, packageName: @commitlint/cli
@commitlint/config-conventional
: 符合AngularJS
风格的校验规则 安装:
npm i -D @commitlint/cli @commitlint/config-conventional
在根目录下新建commitlint.config.js
, 设置校验规则如下:
module.exports = {
extends: ['@commitlint/config-conventional']
};
测试commitlint: echo 'foo: bar' | commitlint
结果如下:
之后可以放在
husky
的HOOKS
:commit-msg
中进行使用, 具体请看后面章节: #提交时自动格式化代码
规范化提交
czg版
- 安装
npm i -D czg
- (可选) 添加配置文件
commitlint.config.js
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const scopes = fs
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name.replace(/s$/, ''));
// precomputed scope
const scopeComplete = execSync('git status --porcelain || true')
.toString()
.trim()
.split('\n')
.find((r) => ~r.indexOf('M src'))
?.replace(/(/)/g, '%%')
?.match(/src%%((\w|-)*)/)?.[1]
?.replace(/s$/, '');
/** @type {import('cz-git').UserConfig} */
module.exports = {
ignores: [(commit) => commit.includes('init')],
extends: ['@commitlint/config-conventional'],
rules: {
'body-leading-blank': [2, 'always'],
'footer-leading-blank': [1, 'always'],
'header-max-length': [2, 'always', 108],
'subject-empty': [2, 'never'],
'type-empty': [2, 'never'],
'subject-case': [0],
'type-enum': [
2,
'always',
[
'feat',
'fix',
'perf',
'style',
'docs',
'test',
'refactor',
'build',
'ci',
'chore',
'revert',
'wip',
'workflow',
'types',
'release',
],
],
},
prompt: {
/** @use `yarn commit :f` */
alias: {
f: 'docs: fix typos',
r: 'docs: update README',
s: 'style: update code format',
b: 'build: bump dependencies',
c: 'chore: update config',
},
customScopesAlign: !scopeComplete ? 'top' : 'bottom',
defaultScope: '',
scopes: [...scopes, 'mock'],
allowEmptyIssuePrefixs: false,
allowCustomIssuePrefixs: false,
// English
// typesAppend: [
// { value: 'wip', name: 'wip: work in process' },
// { value: 'workflow', name: 'workflow: workflow improvements' },
// { value: 'types', name: 'types: type definition file changes' },
// ],
// 中英文对照版
messages: {
type: '选择你要提交的类型 :',
scope: '选择一个提交范围 (可选):',
customScope: '请输入自定义的提交范围 :',
subject: '填写简短精炼的变更描述 :\n',
body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
footerPrefixsSelect: '选择关联issue前缀 (可选):',
customFooterPrefixs: '输入自定义issue前缀 :',
footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
confirmCommit: '是否提交或修改commit ?',
},
types: [
{ value: 'feat', name: 'feat: 新增功能' },
{ value: 'fix', name: 'fix: 修复缺陷' },
{ value: 'docs', name: 'docs: 文档变更' },
{ value: 'style', name: 'style: 代码格式' },
{ value: 'refactor', name: 'refactor: 代码重构' },
{ value: 'perf', name: 'perf: 性能优化' },
{ value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
{ value: 'build', name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' },
{ value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
{ value: 'revert', name: 'revert: 回滚 commit' },
{ value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' },
{ value: 'wip', name: 'wip: 正在开发中' },
{ value: 'workflow', name: 'workflow: 工作流程改进' },
{ value: 'types', name: 'types: 类型定义文件修改' },
],
// emptyScopesAlias: 'empty: 不填写',
// customScopesAlias: 'custom: 自定义',
},
};
- 在
package.json
中添加scripts
{
"scripts": {
"cz": "git add . && npx czg"
}
}
然后就可以使用了, npm run cz
cz-git版:
- 安装依赖
npm i -D commitizen @commitlint/cli @commitlint/config-conventional cz-git
- 添加
commitlint.config.js
作为@commitlint/cli
和cz-git
的配置文件
// commitlint.config.js
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const scopes = fs
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name.replace(/s$/, ''));
// precomputed scope
const scopeComplete = execSync('git status --porcelain || true')
.toString()
.trim()
.split('\n')
.find((r) => ~r.indexOf('M src'))
?.replace(/(/)/g, '%%')
?.match(/src%%((\w|-)*)/)?.[1]
?.replace(/s$/, '');
/** @type {import('cz-git').UserConfig} */
module.exports = {
ignores: [(commit) => commit.includes('init')],
extends: ['@commitlint/config-conventional'],
rules: {
'body-leading-blank': [2, 'always'],
'footer-leading-blank': [1, 'always'],
'header-max-length': [2, 'always', 108],
'subject-empty': [2, 'never'],
'type-empty': [2, 'never'],
'subject-case': [0],
'type-enum': [
2,
'always',
[
'feat',
'fix',
'perf',
'style',
'docs',
'test',
'refactor',
'build',
'ci',
'chore',
'revert',
'wip',
'workflow',
'types',
'release',
],
],
},
prompt: {
/** @use `yarn commit :f` */
alias: {
f: 'docs: fix typos',
r: 'docs: update README',
s: 'style: update code format',
b: 'build: bump dependencies',
c: 'chore: update config',
},
customScopesAlign: !scopeComplete ? 'top' : 'bottom',
defaultScope: '',
scopes: [...scopes, 'mock'],
allowEmptyIssuePrefixs: false,
allowCustomIssuePrefixs: false,
// English
// typesAppend: [
// { value: 'wip', name: 'wip: work in process' },
// { value: 'workflow', name: 'workflow: workflow improvements' },
// { value: 'types', name: 'types: type definition file changes' },
// ],
// 中英文对照版
messages: {
type: '选择你要提交的类型 :',
scope: '选择一个提交范围 (可选):',
customScope: '请输入自定义的提交范围 :',
subject: '填写简短精炼的变更描述 :\n',
body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
footerPrefixsSelect: '选择关联issue前缀 (可选):',
customFooterPrefixs: '输入自定义issue前缀 :',
footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
confirmCommit: '是否提交或修改commit ?',
},
types: [
{ value: 'feat', name: 'feat: 新增功能' },
{ value: 'fix', name: 'fix: 修复缺陷' },
{ value: 'docs', name: 'docs: 文档变更' },
{ value: 'style', name: 'style: 代码格式' },
{ value: 'refactor', name: 'refactor: 代码重构' },
{ value: 'perf', name: 'perf: 性能优化' },
{ value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
{ value: 'build', name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' },
{ value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
{ value: 'revert', name: 'revert: 回滚 commit' },
{ value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' },
{ value: 'wip', name: 'wip: 正在开发中' },
{ value: 'workflow', name: 'workflow: 工作流程改进' },
{ value: 'types', name: 'types: 类型定义文件修改' },
],
// emptyScopesAlias: 'empty: 不填写',
// customScopesAlias: 'custom: 自定义',
},
};
- 在
package.json
中添加配置
{
"scripts": {
"cz": "git add . && cz"
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
},
}
- 运行
npm run cz
传统版
- 安装依赖
npm i commitizen cz-customizable -D
- 配置
package.json
{
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"
}
}
}
- 创建提交规范文件
.cz-config.js
module.exports = {
// 可选类型
types: [
{ value: 'feat', name: 'feat: 新功能' },
{ value: 'fix', name: 'fix: 修复' },
{ value: 'docs', name: 'docs: 文档变更' },
{ value: 'style', name: 'style: 代码格式(不影响代码运行的变动)' },
{
value: 'refactor',
name: 'refactor: 重构(既不是增加feature,也不是修复bug)'
},
{ value: 'perf', name: 'perf: 性能优化' },
{ value: 'test', name: 'test: 增加测试' },
{ value: 'chore', name: 'chore: 构建过程或辅助工具的变动' },
{ value: 'revert', name: 'revert: 回退' },
{ value: 'build', name: 'build: 打包' }
],
// 消息步骤
messages: {
type: '请选择提交类型:',
customScope: '请输入修改范围(可选):',
subject: '请简要描述提交(必填):',
body: '请输入详细描述(可选):',
footer: '请输入要关闭的issue(可选):',
confirmCommit: '确认使用以上信息提交?(y/n/e/h)'
},
// 跳过问题
skipQuestions: ['body', 'footer'],
// subject文字长度默认是72
subjectLimit: 72
}
- 安装依赖
npm i -D @commitlint/config-conventional @commitlint/cli
- 根目录下创建
commitlint.config.js
,注意, 是UTF8格式
.
module.exports = {
extends: ['@commitlint/config-conventional'],
roles: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'chore',
'revert',
'build'
]
],
'subject-case': [0]
}
}
提交时自动格式化代码
- 安装
husky
, 生成配置文件
npm i husky -D
安装完成之后, 在控制台执行下面代码:
npx husky install
husky
安装完成后, 执行以下命令添加husky
钩子
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
commit-msg
这个hook
会在提交信息时使用 commitlint
进行校验, 至此, 不规范的 commit
信息将不可被提交.
- 继续添加
husky
钩子
npx husky add .husky/pre-commit "npx eslint --ext .js,.vue src"
husky
的pre-commit
会在commit
前对src
下的js, vue
文件进行eslint
校验, 如有eslint error
, 则会中止提交, 抛出错误. 此时存在两个问题:
- 只是修改了个别文件, 却检测了所有代码文件
- 只抛出错误, 需手动修改无实际意义的格式问题(如
;``空格
等)
eslint
错误自动修复
a. 安装依赖插件, 该插件可以只更新本次修改的代码, 并且在出现错误的时候, 自动修复并且推送
npm i lint-staged -D
b. package.json
添加配置
{
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"package.json": [
"prettier --write"
],
"*.vue": [
"eslint --fix",
"prettier --write"
],
"*.{scss,less,styl,html}": [
"prettier --write"
],
"*.md": [
"prettier --write"
]
}
}
c. 修改.husky/pre-commit
文件
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
以上操作完成之后, 执行npm run cz
, 则会自动进行eslint校验``prettier格式化代码``commit msg 信息是否符合标准
三重校验.
相关参考:
juejin.cn/post/684490…
github.com/commitizen/…
cz-git.qbb.sh/zh/