# Git 提交规范

# 约定式提交规范

参考 约定式提交规范 (opens new window)

提交规范格式如下:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

--------  翻译 -------------

<类型>[可选 范围]: <描述>

[可选 正文]

[可选 脚注]


类型:feat、bug... 更改的代码形式
范围:用 lerna 做项目管理时,比如修改的时项目A,feat(proA): xx;又或者标注修改的哪个文件,feat(Home.vue):xxx
描述:修改的功能信息描述

# commitizen

上述只是一个提交规范的格式约束,需要人为自觉的手动执行,显然是很痛苦的。于是,就出现了 git 提交规范化工具 ——— commitizen就是其中之一。

commitizen 仓库名为 cz-cli (opens new window),它提供了 git cz 的指令用于代替 git commit,也就是说:使用 commitizen 进行代码提交(git commit)时,commitizen 会校验提交时所有必须的提交字段

TIP

全局安装:npm install -g commitizen

当前版本:4.2.4

commitizen 需要全局安装,个人理解它是一个 git 的插件,因为它相当于为 git commit 提供了一个替代方案:git cz

项目依赖安装:yarn add cz-customizable -D

当前版本:6.3.0

package.json 中配置 commitizen,配置信息如下:


  "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,
};

经过上述配置之后,通过执行 git cz 来代替执行 git commit 这一步时:

  • 会先触发 commitizen 的提交规范
  • 通过 commitizen 就找到了 package.json 中的 config 配置,进而找到 cz-customizable 这个可以自定义提交配置信息的第三方依赖中
  • cz-customizable 就会找到为其定义的配置文件 .cz-config.js,进而触发 commit 信息选择

就能看到如下的提示内容了: An image

当前项目的 package.json 信息:


























 









 
 
 
 
 








{
  "name": "vue3-solution",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "prepare": "husky install"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^3.0.0",
    "vue-router": "^4.0.0-0",
    "vuex": "^4.0.0-0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.15",
    "@vue/cli-plugin-eslint": "~4.5.15",
    "@vue/cli-plugin-router": "~4.5.15",
    "@vue/cli-plugin-vuex": "~4.5.15",
    "@vue/cli-service": "~4.5.15",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-standard": "^5.1.2",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-import": "^2.20.2",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.0.0",
    "eslint-plugin-vue": "^7.0.0",
    "lint-staged": "^9.5.0",
    "sass": "^1.26.5",
    "sass-loader": "^8.0.2"
  },
  "config": {
    "commitizen": {
      "path": "node_modules/cz-customizable"
    }
  },
  "gitHooks": {
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "*.{js,jsx,vue}": ["vue-cli-service lint", "git add"]
  }
}

commitizen 的处理方式有一个不稳妥的地方是,如果有人不知道或忘记执行 git cz,照样执行 git commit 时是无法规范化提交信息了。所以,需要一种更为强制的方式,针对 git commit 进行规范化处理,就是 Git Hooks

# Git Hooks

git 在执行某个事件之前或者之后进行的一些其他额外的操作。

详情链接Git Hooks (opens new window),部分 git hooks 如下:

Git Hook 调用时机 说明
pre-applypatch git am 执行前
applypatch-msg git am 执行前
post-applypatch git am 执行后 不影响 git am 的结果
pre-commit git commit 执行前 可以用 git commit --no-verify 绕过
commit-msg git commit 执行前 可以用 git commit --no-verify 绕过
post-commit git commit 执行后 不影响 git commit 的结果
pre-merge-commit git merge 执行前 可以用 git merge --no-verify 绕过
prepare-commit-msg git commit 执行后,编辑器打开之前
pre-rebase git rebase 执行前
post-checkout git checkoutgit switch 执行后 如果不使用--no-checkout参数,则在 git clone后也会执行
post-merge git commit 执行后 在执行git pull时也会被调用
pre-push git push 执行前
pre-receive git-receive-pack 执行前
update

TIP

本次要用的,就是 pre-commitcommit-msg

  1. pre-commit

    • git commit 执行之前
    • 不接受任何参数,并且在获取提交日志消息并进行提交之前被调用
    • git commit 如果以非零 的状态退出会导致命令在创建提交之前中止
  2. commit-msg - git commit 执行前 - 可用于将消息规范化为某种项目标准格式 - 可用于检查消息文件后拒绝提交

# husky 与 commitlint

  1. commitlint 用于检查提交信息,详情 (opens new window)
  2. husky 即为 git hooks 的工具,它可以指定在众多钩子中的哪一个回调使用 commitlint来校验提交信息

TIP

注意,以下安装后如果执行有问题,请检查 npm 版本是否大于 7.0

# 安装 commitlint

# @commitlint/config-conventional 17.0.0
# @commitlint/cli 17.0.1

# Install commitlint cli and conventional config
npm install --save-dev @commitlint/{config-conventional,cli}
# For Windows:
npm install --save-dev @commitlint/config-conventional @commitlint/cli

# commitlint.config.js 配置

commitlint.config.js 就是配置 commit 信息规范的文件,在 commitlint.config.js 中增加配置项,首先要继承 config-conventional

关于config-conventional的默认配置可以查看这里 (opens new window)

注意,保存格式必须是 UTF-8 类型

module.exports = {
  // 继承的规则
  extends: ["@commitlint/config-conventional"],
  // 定义规则类型
  rules: {
    // type 类型定义,表示 git 提交的 type 必须在以下类型范围内
    "type-enum": [
      // 当前验证的级别,2 表示错误级别
      2,
      // 在任何情况下,都进行验证
      "always",
      // type 的泛型类型
      [
        "feat", // 新功能 feature
        "fix", // 修复 bug
        "docs", // 文档注释
        "style", // 代码格式(不影响代码运行的变动)
        "refactor", // 重构(既不增加新功能,也不是修复bug)
        "perf", // 性能优化
        "test", // 增加测试
        "chore", // 构建过程或辅助工具的变动
        "revert", // 回退
        "build", // 打包
      ],
    ],
    // subject 大小写不做校验
    "subject-case": [0],
  },
};

# 安装 husky

# 当前版本 8.0.1
npm install husky --save-dev

# 配置

  1. 执行 npx husky install 指令启动 hooks 会在根目录下生成 .husky文件夹,包含 .gitignorehusky.sh文件 An image

  2. commitlint 配合 husky的使用。

通过 husky 来监听 git hooks,在 git hooks 中的 commit-msg 钩子里面执行 commitlint 对代码的提交信息进行校验。 执行命令:

npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

# 或者 yarn
yarn husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

注意,这一步要执行指令,我手动创建文件并复制粘贴的命令,最终没有生效。

此时,.husky文件夹下会多出一个 commit-msg 文件。至此,不符合标准的提交格式都无法提交了。 .husky 文件夹目录如下:

  .
  ├── _
  │   └── husky.sh
  │   └── .gitignore
  ├── commit-msg

commit-msg 的内容如下:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit "$1"

然后执行 git commit -m "提交信息",如果不符合规范就会提醒报错

An image

# package.json

package.json 中不包含上述的 commitizen 的配置模块。两者是不关联的

















 
 















 

















{
  "name": "vue3-backstage",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^3.0.0",
    "vue-router": "^4.0.0-0",
    "vuex": "^4.0.0-0"
  },
  "devDependencies": {
    "@commitlint/cli": "^17.0.1",
    "@commitlint/config-conventional": "^17.0.0",
    "@vue/cli-plugin-babel": "~4.5.15",
    "@vue/cli-plugin-eslint": "~4.5.15",
    "@vue/cli-plugin-router": "~4.5.15",
    "@vue/cli-plugin-vuex": "~4.5.15",
    "@vue/cli-service": "~4.5.15",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-standard": "^5.1.2",
    "babel-eslint": "^10.1.0",
    "cz-customizable": "^6.3.0",
    "eslint": "^6.7.2",
    "eslint-plugin-import": "^2.20.2",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.0.0",
    "eslint-plugin-vue": "^7.0.0",
    "husky": "^8.0.1",
    "lint-staged": "^9.5.0",
    "sass": "^1.26.5",
    "sass-loader": "^8.0.2"
  },
  "config": {
    "commitizen": {
      "path": "node_modules/cz-customizable"
    }
  },
  "gitHooks": {
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "*.{js,jsx,vue}": ["vue-cli-service lint", "git add"]
  }
}

# husky 配合 Eslint

之前的 ESLintPrettier 配合解决代码的问题,只能解决本地的代码。

之前的 Husky 配合 Commitlint 只能解决提交的信息的不合规范的问题。

如果有一个懒人,没有配置 ESLintPrettier,并且按合规的方式提交了格式不对的代码,就坑爹了。

所以,提交代码时,除了要对提交信息进行校验,还要对当前的代码格式进行一层校验,根据配置的规则可以自动将不符合规则的代码进行修复,至少是部分修复。

于是乎,我们通过 husky 来检测 pre-commit 钩子,在执行该钩子的时候,执行yarn husky --ext .js,.vue src 指令来进行代码检测。

  1. 执行 yarn husky add .husky/pre-commit "yarn eslint --ext .js,.vue src" 添加 commit 时的 hook。(yarn eslint --ext .js,.vue src 会在执行到该 hook 时运行)

    • 执行 eslint
    • 针对 .js, .vue 文件
    • src 文件夹下
  2. .husky 文件夹下会生成 pre-commit 文件。文件目录如下:

.
├── _
│   └── husky.sh
│   └── .gitignore
├── commit-msg
└── pre-commit

pre-commit 的内容如下:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn eslint --ext .js,.vue src

这种情况下,当关闭了 VSCode 或者别的编辑器的 Format On Save 功能时。 如果代码有了问题,执行 git commit 时就会报错。这行此时的校验时,commit-msg 校验还未执行。如下图: An image

# lint-staged 自动修复错误

经过上面 pre-commit 的校验拦截,如果代码中格式等问题触发 eslint 校验规则过多时,一一手动修复肯定很麻烦。所以,我们需要针对本次提交的内容有问题的地方,进行自动问题修复。

lint-stage 可以只检查本次修改更新的代码,并在出现错误的时候,自动的修复并且推送

在通过 vue-cli 创建项目时,lint-stage 已经被自动安装了, 当前版本是 9.5.0 并在 package.json 中进行了配置。

"lint-staged": {
  "*.{js,jsx,vue}": [
    "vue-cli-service lint",
    "git add"
  ]
}

将该配置修改成下述形式:

"lint-staged": {
  "src/**/*.{js,vue}": [
    "eslint --fix",
    "git add"
  ]
}

同时修改 pre-commit 的内容为执行 lint-staged 命令:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged

此时再次执行 git commit 提交带有错误格式的内容时,eslint 会尝试进行内容的修复,如果修复好代码则会进行提交。如果自动修复失败了,提示错误由人为修复,修复成功后才能提交代码。

# 最后的 package.json

{
  "name": "vue3-backstage",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^3.0.0",
    "vue-router": "^4.0.0-0",
    "vuex": "^4.0.0-0"
  },
  "devDependencies": {
    "@commitlint/cli": "^17.0.1",
    "@commitlint/config-conventional": "^17.0.0",
    "@vue/cli-plugin-babel": "~4.5.15",
    "@vue/cli-plugin-eslint": "~4.5.15",
    "@vue/cli-plugin-router": "~4.5.15",
    "@vue/cli-plugin-vuex": "~4.5.15",
    "@vue/cli-service": "~4.5.15",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-standard": "^5.1.2",
    "babel-eslint": "^10.1.0",
    "cz-customizable": "^6.3.0",
    "eslint": "^6.7.2",
    "eslint-plugin-import": "^2.20.2",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.0.0",
    "eslint-plugin-vue": "^7.0.0",
    "husky": "^8.0.1",
    "lint-staged": "^9.5.0",
    "sass": "^1.26.5",
    "sass-loader": "^8.0.2"
  },
  "config": {
    "commitizen": {
      "path": "node_modules/cz-customizable"
    }
  },
  "gitHooks": {
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "src/**/*.{js,vue}": [
      "eslint --fix",
      "git add"
    ]
  }
}