Husky 详解
Husky 是一个流行的 Git 钩子(Git Hooks) 管理工具,它允许你在 Git 工作流中的特定事件(例如
pre-commit提交前、pre-push推送前等)自动执行脚本。通过 Husky,团队可以轻松地在代码提交或推送前强制执行代码规范、运行测试、检查代码质量等操作,从而标准化开发流程,有效防止不符合要求的代码进入版本库。
核心思想:
- 自动化 Git 钩子:将 Git 钩子集成到
package.json中,方便管理和版本控制。 - 规范代码提交:在提交或推送前执行脚本,确保代码质量和提交信息符合团队标准。
- 团队协作效率:统一开发环境中的代码质量检查和预提交操作,减少人工审查成本。
一、为什么需要 Husky?
在团队协作开发中,代码质量和规范一致性是至关重要的。然而,仅仅依靠人工审查或后期修复往往效率低下,且容易遗漏。常见的问题包括:
- 不规范的代码进入仓库:忘记运行代码格式化工具、提交了未经 ESLint 检查的代码。
- 提交了失败的测试:在本地没跑完测试就提交,导致 CI/CD 流程失败。
- 提交信息不一致:团队成员使用不同的提交信息格式,导致难以追溯和管理。
- 环境差异导致问题:不同开发者的本地环境配置差异,导致代码在某些机器上可以运行但提交后出问题。
Husky 通过利用 Git 钩子机制,将这些检查和自动化任务前置到提交或推送的本地阶段,从而有效地解决了上述问题:
- 强制执行标准:在代码进入版本库之前进行校验,确保所有提交都符合预设标准。
- 提前发现问题:在开发者本地工作流中发现并修复问题,避免将问题带入共享仓库。
- 提升团队效率:减少代码审查中的格式和风格问题,让团队更专注于业务逻辑。
- 简化配置:将 Git 钩子配置集中在
package.json中,便于项目共享和版本控制。
二、Git 钩子 (Git Hooks) 机制
在深入 Husky 之前,理解 Git 钩子是关键。
2.1 Git 钩子定义
Git 钩子 是用户或系统在 Git 仓库中特定事件发生时自动触发脚本的机制。这些脚本是可执行程序(通常是 Shell 脚本),它们存储在 .git/hooks 目录下,并以相应的事件名称命名。
2.2 常见的 Git 钩子类型
Git 钩子大致分为三类:客户端钩子 和 服务端钩子。Husky 主要管理客户端钩子。
客户端钩子 (Client-side Hooks)
在开发者的本地仓库中执行,常见的有:
pre-commit(提交前):在git commit命令运行,但提交信息还没有编辑时触发。常用于 Lint 代码、运行单元测试、格式化代码。如果脚本以非零状态退出,Git 会停止提交。prepare-commit-msg(准备提交信息):在提交信息编辑器启动之前,默认信息创建之后运行。可用于生成自动化提交信息。commit-msg(提交信息):在提交信息编辑器关闭后,提交信息被读取时触发。常用于验证提交信息是否符合特定的规范(如 Conventional Commits)。pre-push(推送前):在git push命令运行前触发。常用于运行更全面的测试、检查大型文件等。如果脚本以非零状态退出,推送会被取消。post-merge(合并后):在git merge成功运行后触发。常用于恢复权限、生成文档等。
服务端钩子 (Server-side Hooks)
在 Git 服务器上执行,例如 pre-receive, update, post-receive,常用于强制执行仓库政策,如拒绝不符合规范的提交,或者在收到推送后集成 CI/CD 系统。
2.3 Git 钩子的局限性
默认的 Git 钩子存在以下问题:
- 难以版本控制:
.git/hooks目录不在 Git 仓库本身的管理范围内,无法直接通过 Git 版本控制共享给团队成员。 - 管理复杂:对于大型项目和多个钩子,手动编写和维护 Shell 脚本效率较低。
- 跨平台兼容性:Shell 脚本在不同操作系统(Windows/macOS/Linux)上的行为可能存在差异。
Husky 正是为了解决这些问题而生。 它将 Git 钩子的管理抽象到 package.json 中,并通过 Node.js 环境提供跨平台兼容性。
三、Husky 的工作原理
Husky 通过以下方式集成和管理 Git 钩子:
- 安装钩子脚本:当你运行
husky install命令时,Husky 会在你的.git/hooks/目录中创建一个特殊的脚本。这个脚本是 Husky 的入口点。 - 代理执行:当 Git 触发任何一个钩子(例如
pre-commit)时,它会执行.git/hooks/pre-commit脚本。这个脚本实际上会调用 Husky 的内部逻辑。 - 读取配置:Husky 的内部逻辑会读取你的
package.json文件或.husky/目录中的配置,找到与当前 Git 钩子相对应配置。 - 执行用户定义命令:Husky 随后会执行你为该钩子定义的命令(例如
npm test或lint-staged)。
这个流程有效地将 Git 钩子的执行从本地 .git 目录转移到了项目根目录下的配置文件,从而实现了版本控制和团队共享。
graph TD
subgraph GitCore [Git 核心层]
Start([开发者执行 Git 命令]) --> Trigger{Git 触发 Hook 事件}
Trigger --> Proxy[[.git/hooks/ 代理脚本]]
end
subgraph HuskyLayer [Husky 拦截层]
Proxy --> CLI[Husky CLI 读取配置]
CLI --> Config[加载 .husky/ 目录下的自定义钩子]
Config --> Execute[运行用户定义脚本]
end
subgraph Result [最终结果]
Execute -- "退出码: 0" --> Success([Git 命令继续完成])
Execute -- "退出码: 非0" --> FailX([Git 命令中断/报错])
end
%% 样式定义 (深色 UI 增强)
classDef gitBase fill:#44475a,stroke:#bd93f9,color:#f8f8f2;
classDef huskyLogic fill:#6272a4,stroke:#8be9fd,color:#f8f8f2;
classDef pass fill:#50fa7b,stroke:#50fa7b,color:#282a36,font-weight:bold;
classDef fail fill:#ff5555,stroke:#ff5555,color:#ffffff,font-weight:bold;
classDef event fill:#f1fa8c,stroke:#f1fa8c,color:#282a36;
%% 应用样式
class Start,Proxy gitBase;
class CLI,Config,Execute huskyLogic;
class Success pass;
class FailX fail;
class Trigger event;
四、安装与基本使用
4.1 基本安装
我们以一个 Node.js 项目为例,使用 npm 或 yarn 进行安装。
安装 Husky 为开发依赖:
1
2
3
4
5npm install husky --save-dev
# 或者
yarn add husky --dev
# 或者对于 pnpm
pnpm add husky --save-dev安装完成后,
package.json的devDependencies中会新增husky。激活 Husky (创建
.husky目录并配置prepare脚本):Husky 官方推荐使用
prepare脚本来自动化husky install的过程。这确保了在项目初次安装依赖 (npm install) 后,Husky 能自动在.git/hooks中设置好钩子。1
npx husky install
这会在项目根目录下创建一个
.husky文件夹,其中包含一些用于管理钩子的脚本。接着,将
prepare脚本添加到package.json:1
2
3
4
5
6
7
8
9
10
11
12
13// package.json
{
"name": "my-project",
"version": "1.0.0",
"description": "A sample project",
"main": "index.js",
"scripts": {
"prepare": "husky install" // 添加此行
},
"devDependencies": {
"husky": "^9.0.0"
}
}现在,当其他人克隆你的仓库并运行
npm install(或yarn/pnpm install) 时,husky install命令将自动执行,激活 Git 钩子。添加你的第一个 Git 钩子:
以
pre-commit钩子为例,我们希望在每次提交前运行测试。1
npx husky add .husky/pre-commit "npm test"
执行此命令后,会在
.husky/目录下创建一个pre-commit文件,内容类似于:1
2
3
4
. "$(dirname -- "$0")/_/husky.sh"
npm test现在,当你尝试
git commit时,npm test命令会在提交前自动运行。如果npm test失败(即以非零状态退出),则 Git 提交会被阻止。
4.2 示例:配合 lint-staged 使用 pre-commit
在实际开发中,我们通常不希望在 pre-commit 钩子中对整个项目运行 Lint 和格式化,这样效率低下。我们更希望只对已暂存 (staged) 的文件进行检查。这时,lint-staged 就派上用场了。
lint-staged 是一个工具,它允许你对 Git 暂存区中的文件运行命令,并将这些命令的输出重新添加到暂存区。
安装
lint-staged和eslint(示例):1
npm install lint-staged eslint prettier --save-dev
配置
package.json或lint-staged配置文件:在
package.json中配置lint-staged: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// package.json
{
"name": "my-project",
"version": "1.0.0",
"description": "A sample project",
"main": "index.js",
"scripts": {
"prepare": "husky install"
},
"devDependencies": {
"husky": "^9.0.0",
"eslint": "^8.0.0",
"prettier": "^3.0.0",
"lint-staged": "^15.0.0"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix", // 自动修复 ESLint 错误
"prettier --write", // 自动格式化代码
"git add" // 重新添加修改后的文件到暂存区
],
"*.{json,css,scss,less,html,md}": [
"prettier --write",
"git add"
]
}
}或者,你可以在项目根目录创建
lint-staged.config.js(.mjs/.cjs/.json/.yaml/.yml) 文件来配置lint-staged。修改
.husky/pre-commit钩子:将之前添加的
npm test命令替换为npx lint-staged:1
npx husky add .husky/pre-commit "npx lint-staged"
现在,每当
git commit时,Husky 会执行npx lint-staged,后者只会对你修改并暂存的.js,.ts等文件运行 ESLint 和 Prettier,并自动将修复后的文件重新添加到暂存区。
五、更多常用钩子和高级用法
5.1 其他常用 Git 钩子
commit-msg钩子:
用于验证提交信息是否符合规范,常配合commitlint使用。1
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
你需要安装
commitlint和相应的配置。例如:
1
2npm install --save-dev @commitlint/config-conventional @commitlint/cli
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.jspre-push钩子:
在git push前运行更全面的测试或检查,防止不稳定的代码被推送到远程仓库。1
npx husky add .husky/pre-push "npm run test:ci"
5.2 跳过钩子
有时你可能需要绕过 Git 钩子的检查(例如,在紧急修复或提交 WIP 代码时)。
跳过所有
pre-commit钩子:1
2
3git commit -n --no-verify
# 或简写
git commit --no-verify跳过所有客户端钩子:
1
git push --no-verify
5.3 Yarn Berry (Yarn 2/3+) 和 PNPM 支持
Husky 完全支持 Yarn Berry 和 PNPM。由于 Yarn Berry 引入了 Plug’n’Play (PnP) 机制,全局安装的 CLI 可能无法找到。Husky 建议使用 npx 或者 yarn dlx 来运行。上面的示例中已基本使用 npx,这在所有包管理器下都兼容良好。
5.4 多个命令
在一个钩子文件中,你可以像正常的 Shell 脚本一样添加多个命令:
1 |
|
如果其中任何一个命令以非零状态退出,整个钩子就会失败,Git 命令就会被中断。
六、总结
Husky 是现代前端和 Node.js 项目不可或缺的工具,它通过优雅地管理 Git 钩子,将代码质量和规范前置到开发者的本地环节。
通过使用 Husky:
- 代码质量得到了保障:强制执行代码风格、运行测试,减少不规范代码提交。
- 开发流程标准化:每个开发者在提交和推送时遵循相同的规则。
- 团队协作更高效:减少了代码审查的琐碎工作,提升了团队整体开发效率。
- 项目可维护性提高:稳定且规范的代码库更易于长期维护和迭代。
将 Husky 与 lint-staged、eslint、prettier、commitlint 等工具结合使用,可以构建一个强大的自动化代码质量保障体系,极大地提升项目的健康度和团队的工作效率。
