hook
hook,钩子:即某个时期或事件之前、之后执行和一些操作或脚本。与我们常说的中间件很相似。
git-hooks
git有很多hook,每当我们git init
初始化一个git仓库时,都会创建一个.git的隐藏文件夹,git的hook就放在.git/hooks下。hooks以.sample为后缀的是示例文件。git-hooks有客户端hooks和服务端的hooks。
这里介绍客户端会用到的hooks
- pre-commit: 钩子在键入提交信息前运行。 它用于检查即将提交的快照,例如,检查是否有所遗漏,确保测试运行,以及核查代码。
- commit-msg: 钩子在启动提交信息编辑器之前,默认信息被创建之后运行。 它允许你编辑提交者所看到的默认信息。
git仓库根目录的隐藏文件夹.git里的git-hooks是不被git管理的,只存在于本地。所以无法让仓库中所有成员使用同样的hooks。这时候就需要通过工具库来使用git-hooks,就是husky。
husky
- 安装 husky
shell
pnpm install husky --save-dev
- husky 初始化
shell
npx husky install
- 设置 package.json 的 prepare。来保证 husky 可以正常运行
shell
npm set-script prepare "husky install"
- 添加 git hooks
shell
npx husky add .husky/${hook_name} ${command}
如此一来,我们进行git操作时,触发hook_name钩子从而运行command(命令)。
接下来我们就可以借助commitlint
校验commit信息。借助lint-staged
来实现对暂存区的代码进行风格校验和格式化。
commitlint
commitlint是对commit信息校验的一款npm包。
- 安装
shell
npm i @commitlint/cli @commitlint/config-conventional -D
- 添加git-hook
shell
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
现在我们只是增加了对commit message的校验,但是在使用 Git 过程中,填写 commit message其实是比较麻烦的。如果没有良好的 commit message 规范,commit历史就会很乱。这时就需要 commitizen
来协助开发者填写 commit 信息。
commitizen
commitizen是基于 Node.js 开发的 git commit 命令行工具,用来生成标准化的commit-message。commitizen 本身只提供命令行交互框架以及一些 git 命令的执行,实际的规则则需要通过适配器来定义,commitizen 留有对应的适配器接口。市面上有很多适配器,比如: cz-conventional-changelog
、cz-git
。常见适配器生产commit-message模板
text
<type>(<scope>): <subject>
<空行>
<body>
<空行>
<footer>
- 安装 commitizen
shell
pnpm install commitizen -D
- 初始化,参数含义:使用cz-git适配器初始化commitizen,并用pnpm安装依赖。
shell
npx commitizen init cz-git --save-dev --save-exact --pnpm
go
commitizen init 做了什么
1. 安装 `cz-git` 适配器 npm 模块
2. 将其保存到 package.json 的 devDependencies 中
3. 添加配置到 package.json 中 如下:
"config": {
"commitizen": {
"path": "./node_modules/cz-git"
}
}
- 新建 commitlint.config.js 文件:(
对提交信息做格式检验的
)
js
module.exports = {
ignores: [commit => commit === "init"],
extends: ["@commitlint/config-conventional"],
rules: {
// @see: https://commitlint.js.org/#/reference-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", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert", "wip", "workflow", "types", "release" ] ]
},
prompt: {
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: "特性: 🚀 新增功能", emoji: "🚀" },
{ value: "fix: 修复", name: "修复: 🧩 修复缺陷", emoji: "🧩" },
{ value: "docs: 文档", name: "文档: 📚 文档变更", emoji: "📚" },
{ value: "style: 格式", name: "格式: 🎨 代码格式(不影响功能,例如空格、分号等格式修正)", emoji: "🎨" },
{ value: "refactor: 重构", name: "重构: ♻️ 代码重构(不包括 bug 修复、功能新增)", emoji: "♻️" }, { value: "perf: 性能", name: "性能: ⚡️ 性能优化", emoji: "⚡️" }, { value: "test: 测试", name: "测试: ✅ 添加疏漏测试或已有测试改动", emoji: "✅" }, { value: "chore: 构建", name: "构建: 📦️ 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)", emoji: "📦️" },
{ value: "ci: 集成", name: "集成: 🎡 修改 CI 配置、脚本", emoji: "🎡" },
{ value: "revert: 回退", name: "回退: ⏪️ 回滚 commit", emoji: "⏪️" },
{ value: "build: 打包", name: "打包: 🔨 项目打包发布", emoji: "🔨" }
],
useEmoji: true,
themeColorCode: "",
scopes: [],
allowCustomScopes: true,
allowEmptyScopes: true,
customScopesAlign: "bottom",
customScopesAlias: "custom",
emptyScopesAlias: "empty",
upperCaseSubject: false,
allowBreakingChanges: ["feat", "fix"],
breaklineNumber: 100, breaklineChar: "|",
skipQuestions: [],
issuePrefixs: [{ value: "closed", name: "closed: ISSUES has been processed" }],
customIssuePrefixsAlign: "top",
emptyIssuePrefixsAlias: "skip",
customIssuePrefixsAlias: "custom",
allowCustomIssuePrefixs: true,
allowEmptyIssuePrefixs: true,
confirmColorize: true,
maxHeaderLength: Infinity,
maxSubjectLength: Infinity,
minSubjectLength: 0,
scopeOverrides: undefined,
defaultBody: "",
defaultIssues: "",
defaultScope: "",
defaultSubject: "" }
};
- 配置 package.json 命令
json
"scripts": {
"commit": "git status && git add -A && git-cz"
}
运行pnpm run commit
以触发git-hook规范commit message
lint-staged
一般情况下 lint-staged
搭配着 Husky
一起使用。需要保证lint-staged
会在 pre-commit hook 中被运行。在使用lint-staged校验代码和代码风格时这里使用的是prettier
和eslint
。
- 安装
shell
pnpm install lint-staged --save-dev
- 添加 git hooks
shell
npx husky add .husky/pre-commit "npx lint-staged"
- 配置
形式一:package.json 中添加一个 lint-staged
项。
json
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.json": ["prettier --write"],
"*.vue": ["eslint --fix', 'prettier --write', 'stylelint --fix"],
"*.{scss,css,sass,less,html}": ["stylelint --fix ", "prettier --write"],
"*.md": ["prettier --write"]
}
形式二:根目录添加一个 .lintstagedrc.json
文件。
json
//.lintstagedrc.json
{
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.json": ["prettier --write"],
"*.vue": ["eslint --fix', 'prettier --write', 'stylelint --fix"],
"*.{scss,css,sass,less,html}": ["stylelint --fix ", "prettier --write"],
"*.md": ["prettier --write"]
}
之后每次的pre-commit钩子触发都会执行代码校验和代码格式化。