Husky 是一个轻量级的 Git Hooks 管理工具,专为 Node.js 项目设计。它利用 Git 的 core.hooksPath 特性,让团队可以在版本控制中共享 Git Hooks 配置。
核心特性:
| 特性 | 说明 |
|---|---|
| 轻量 | 仅 2kB(gzipped),零依赖 |
| 快速 | 执行时间约 1ms |
| 跨平台 | 支持 macOS、Linux、Windows |
| 全面支持 | 支持全部 13 种客户端 Git Hooks |
| 生态完善 | 与 lint-staged、commitlint 等工具无缝集成 |
项目目录/
├── .husky/
│ ├── pre-commit # pre-commit hook 脚本
│ └── commit-msg # commit-msg hook 脚本
├── package.json # 包含 prepare 脚本
└── ...
core.hooksPath 指向 .husky 目录.husky 目录中对应的脚本使用 husky init 一键完成安装和初始化:
# npm
npx husky init
# pnpm
pnpm exec husky init
# yarn
yarn dlx husky init
# bun
bunx husky init
该命令会自动:
.husky/ 目录package.json 中添加 prepare 脚本pre-commit hook# 1. 安装
npm install husky --save-dev
# 2. 初始化
npx husky init
package.json 中的 prepare 脚本:
{
"scripts": {
"prepare": "husky"
}
}
prepare脚本在npm install后自动执行,确保团队成员克隆项目后自动配置 hooks。
创建 hook 非常简单,只需在 .husky/ 目录下创建对应名称的文件:
# 方法 1:使用 echo
echo "npm test" > .husky/pre-commit
# 方法 2:手动创建文件
# 直接编辑 .husky/pre-commit 文件
Hook 脚本示例:
# .husky/pre-commit
npm run lint
npm test
注意:Husky v9 的 hook 脚本不需要 shebang 行(如
#!/bin/sh),Husky 会自动处理。
CI 环境通常不需要 Git hooks:
# 方法 1:环境变量(推荐)
HUSKY=0 npm ci
# 方法 2:GitHub Actions
- run: npm ci
env:
HUSKY: 0
# 方法 3:package.json 容错处理
{
"scripts": {
"prepare": "husky || true"
}
}
提交前执行,用于代码检查和格式化。
# .husky/pre-commit
npx lint-staged
验证提交信息格式。
# .husky/commit-msg
npx --no -- commitlint --edit $1
自定义验证示例:
# .husky/commit-msg
commit_msg=$(cat "$1")
pattern="^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}"
if ! echo "$commit_msg" | grep -qE "$pattern"; then
echo "错误:提交信息格式不正确"
echo "格式:<type>(<scope>): <subject>"
exit 1
fi
推送前执行,用于运行测试。
# .husky/pre-push
npm test
npm run build
合并/拉取后执行,用于自动更新依赖。
# .husky/post-merge
changed=$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)
if echo "$changed" | grep -q "package-lock.json"; then
echo "依赖变化,正在安装..."
npm ci
fi
只对暂存文件运行检查,大幅提升速度。
npm install lint-staged --save-dev
package.json 配置:
{
"lint-staged": {
"*.{js,ts,jsx,tsx}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": "prettier --write",
"*.md": "prettier --write"
}
}
Husky 配置:
# .husky/pre-commit
npx lint-staged
检查提交信息是否符合 Conventional Commits 规范。
npm install @commitlint/cli @commitlint/config-conventional --save-dev
commitlint.config.js:
module.exports = {
extends: ["@commitlint/config-conventional"],
};
Husky 配置:
# .husky/commit-msg
npx --no -- commitlint --edit $1
package.json:
{
"scripts": {
"prepare": "husky",
"lint": "eslint src",
"test": "jest"
},
"devDependencies": {
"@commitlint/cli": "^19.0.0",
"@commitlint/config-conventional": "^19.0.0",
"husky": "^9.0.0",
"lint-staged": "^15.0.0"
},
"lint-staged": {
"*.{js,ts}": ["eslint --fix", "prettier --write"]
}
}
.husky/pre-commit:
npx lint-staged
.husky/commit-msg:
npx --no -- commitlint --edit $1
# 使用 lint-staged 只检查变更文件
npx lint-staged
# ESLint 启用缓存
eslint --fix --cache
# 耗时任务放到 pre-push 而非 pre-commit
当 package.json 不在 Git 根目录时:
{
"scripts": {
"prepare": "cd .. && husky frontend/.husky"
}
}
配置 Node 版本管理器(nvm、fnm 等)的初始化脚本:
# ~/.config/husky/init.sh
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# 1. 检查 hook 文件名是否正确(不能是 precommit 或 pre-commit.sh)
ls .husky/
# 2. 检查 Git hooks 路径
git config core.hooksPath
# 3. 确保 Git 版本 >= 2.9
git --version
# 4. 重新初始化
npx husky init
GUI 应用或某些环境可能找不到 node/npm,配置启动文件:
# ~/.config/husky/init.sh
export PATH="/usr/local/bin:$PATH"
如果卸载 Husky 后 hooks 仍然失败:
git config --unset core.hooksPath
Git Bash 配合 Yarn 可能出现 “stdin is not a tty” 错误:
# .husky/common.sh
if [ -t 1 ]; then
exec < /dev/tty
fi
# .husky/pre-commit
. "$(dirname "$0")/common.sh"
yarn lint
# 单次跳过
git commit --no-verify -m "message"
git push --no-verify
# 临时禁用所有 hooks
HUSKY=0 git commit -m "message"
# 多个命令
export HUSKY=0
git add .
git commit -m "message"
unset HUSKY
# 直接运行脚本
sh .husky/pre-commit
# 添加 exit 1 测试是否能阻止提交
echo "exit 1" >> .husky/pre-commit
# 查看详细执行过程
GIT_TRACE=1 git commit -m "test"
v4 配置(旧):
{
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}
v9 配置(新):
# .husky/pre-commit
npx lint-staged
# .husky/commit-msg
npx --no -- commitlint --edit $1
迁移步骤:
# 1. 升级
npm install husky@latest --save-dev
# 2. 删除 package.json 中的 "husky" 字段
# 3. 初始化
npx husky init
# 4. 创建 hooks
echo "npx lint-staged" > .husky/pre-commit
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg
主要变化:
| 方面 | v4 | v9 |
|---|---|---|
| 配置位置 | package.json | .husky/ 目录 |
| Hook 格式 | JSON | Shell 脚本 |
| 环境变量 | HUSKY_GIT_PARAMS | $1 |
| 大小 | ~1MB | 2kB |