Husky Git Hooks:提交前自动检查
Husky Git Hooks:提交前自动检查,告别低质量代码
在现代软件开发中,保证代码质量不仅仅依赖个人习惯,更需要自动化的守护。当你完成一段代码,正准备提交(commit)时,如果有一个“安检员”自动帮你运行测试、检查代码风格、验证提交信息格式,甚至阻止包含明显错误的提交,那将是多么省心的事情。Husky 正是为这个目的而生——它能让你轻松管理 Git Hooks,将检查嵌入到 Git 工作流的节点中。本教程将带你从零开始,掌握 Husky 的核心用法,让每一次 git commit 都成为信任的起点。
1. 什么是 Git Hooks?为什么要用 Husky?
Git Hooks 是 Git 提供的脚本机制,允许你在特定的重要动作(如 commit、push)发生时触发自定义脚本。它们在 .git/hooks 目录下存放,默认以示例文件存在。然而,直接使用原生 Git Hooks 有几个痛点:
- 难以管理:
.git/hooks目录不在版本控制范围内,团队成员无法共享。 - 配置繁琐:需要手动编写 Shell 脚本,且不同操作系统兼容性可能出问题。
- 缺乏集成:难以与 Node.js 生态的 linting、测试工具无缝衔接。
Husky 解决了上述问题。它是一个 npm 包,帮你:
- 将 Git Hooks 的配置纳入项目版本控制(通常通过
.husky/目录)。 - 提供简洁的配置方式,你只需编写常见的 Node 命令。
- 自动处理安装和权限问题,跨平台开箱即用。
简单来说,Husky 让 Git Hooks 变得现代化、可共享、易维护。
2. 环境准备与项目初始化
在开始之前,请确保你的开发环境满足以下条件:
- Node.js:版本 >= 16(推荐使用 LTS 版本)
- npm 或 yarn:作为包管理器
- Git:项目已初始化为 Git 仓库(
git init)
创建示例项目(可选)
如果你还没有项目,可以快速创建一个用来实验:
mkdir project-guardian
cd project-guardian
npm init -y
git init
添加一个简单的 JavaScript 文件 index.js 以便后续测试:
console.log('Hello, clean code!')
3. 安装与初始化 Husky
通过 npm 安装 Husky 并执行初始化命令:
npm install husky --save-dev
npx husky init
npx husky init 会做几件重要的事:
- 在项目根目录创建
.husky/文件夹,这是存放 hook 脚本的地方。 - 在
.husky/内生成pre-commit文件(一个示例 hook)。 - 更新
package.json中的scripts,增加"prepare": "husky"脚本。这个脚本确保在npm install后,Husky 的 hook 被正确安装到.git/hooks中。
注意:如果你的项目是克隆下来的仓库,并且在 package.json 中配置了 prepare 脚本,那么 npm install 后 Husky 会自动启用,无需额外操作。
4. 创建第一个 Git Hook:代码风格检查(pre-commit)
最常用的场景是在 git commit 之前自动运行 ESLint 检查代码风格和潜在错误。我们以此为例,构建一个实用的 pre-commit hook。
4.1 配置 ESLint
如果尚未安装 ESLint,先安装并初始化:
npm install eslint --save-dev
npx eslint --init
按照提示选择适合你项目的配置(如使用 Airbnb 风格指南等)。完成后,你会得到一个 .eslintrc.* 配置文件。
为了测试,我们可以在 package.json 中添加一个 lint 脚本:
"scripts": {
"lint": "eslint ."
}
4.2 编写 pre-commit hook
打开 .husky/pre-commit 文件(由 husky init 创建),你会看到默认内容类似:
npm test
我们将其改为运行 lint 检查:
npm run lint
这样,每次执行 git commit 时,Husky 会先触发这个脚本。如果 lint 检查发现错误(退出码非0),commit 将被阻止,直到你修复所有问题。
4.3 验证效果
故意在 index.js 中制造一个 ESLint 会报错的写法,例如声明一个未使用的变量:
const unusedVar = 'I am not used';
console.log('Hello, clean code!');
然后尝试提交:
git add .
git commit -m "test: introduce lint error"
你会看到 lint 报错信息,commit 中断。修复错误后再次提交则会顺利通过。
5. 提交信息规范化:commit-msg Hook
除了代码质量,统一的提交信息格式对项目维护和自动化生成 changelog 非常重要。我们可以借助 commitlint 和 Husky 的 commit-msg hook 来强制校验。
5.1 安装 commitlint
npm install --save-dev @commitlint/config-conventional @commitlint/cli
在项目根目录创建 commitlint.config.js(或 .commitlintrc.js):
module.exports = {
extends: ['@commitlint/config-conventional']
};
这套配置遵循 Conventional Commits 规范,要求提交信息格式如:type(scope): description,例如 feat(auth): add login form。
5.2 添加 commit-msg hook
使用 Husky 添加新的 hook:
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
这条命令会在 .husky/ 下创建 commit-msg 文件,内容为调用 commitlint 并传入临时提交信息文件路径 $1。--no 参数避免某些环境下的子进程问题。
现在,如果你尝试提交一条不规范的信息,比如 git commit -m "fix stuff",commitlint 会拒绝并提示正确格式。
6. 运行测试:pre-push Hook
除了在提交前检查,有时你希望在推送(push)到远程仓库之前运行较重的任务,比如单元测试或集成测试。这时可以使用 pre-push hook。
6.1 添加测试命令
假设你的项目有测试脚本:
"scripts": {
"test": "jest"
}
创建 pre-push hook:
npx husky add .husky/pre-push "npm test"
现在每次执行 git push 时,测试都会运行。只有当所有测试通过时,推送才会继续。这为远程分支提供了一道额外的安全防线。
6.2 性能优化建议
pre-push 可能会耗时较长,影响开发体验。你可以考虑:
- 仅针对变更文件运行相关测试(如使用 Jest 的
--onlyChanged)。 - 将重任务放在 CI 中,本地只保留轻量检查。
- 为紧急情况提供绕过 hook 的能力(谨慎使用):
git push --no-verify。
7. Husky 配置详解与最佳实践
Husky 版本 9 之后,配置更简洁,所有 hook 都作为独立的可执行脚本存放在 .husky/ 目录下。和旧版在 package.json 中配置的方式不同,现在的设计更透明,便于查看和维护。
7.1 .husky/ 目录结构
典型的 .husky/ 目录包含:
.husky/
├── pre-commit
├── commit-msg
├── pre-push
└── _/ (Husky 内部使用的辅助文件)
每个文件都是一个 Shell 脚本,不需要文件扩展名,并确保有可执行权限(Husky 自动处理)。
7.2 调试 Hook
当 Hook 未按预期工作时,可以通过以下方法调试:
- 在终端直接运行
.husky/pre-commit查看输出。 - 确保脚本第一行有正确的解释器,如
#!/usr/bin/env sh(Husky 默认添加)。 - 检查 Husky 是否正确安装:
git config core.hooksPath应输出.husky/_。
7.3 跳过 Hooks 的场景
有时你确实需要跳过 hook(例如紧急修复),可以使用 --no-verify 参数:
git commit --no-verify -m "urgent fix"git push --no-verify
强烈建议:仅在特殊情况下使用,并在事后补上必要的检查和规范提交。
7.4 团队协作与版本控制
由于 .husky/ 目录已纳入版本控制,团队成员克隆项目后,首次执行 npm install 会触发 prepare 脚本,自动配置 hooks。这使得所有人都拥有相同的检查规则,避免“只有我的机器能通过”的尴尬。
8. 常见问题处理
Q: 安装后 Husky 不生效
A: 确认 package.json 中 scripts 有 "prepare": "husky",并执行一次 npm run prepare;检查 Git 版本(≥ 2.9)和 Node 版本;在 Windows 下确保终端使用 Git Bash 或 WSL。
Q: 提交时遇到 permission denied 错误
A: Hook 脚本没有可执行权限。运行 chmod +x .husky/* 赋予权限(Husky 通常自动处理,若失效可手动解决)。
Q: 如何在 Hook 中运行多个命令?
A: 直接在 hook 文件中按行书写,例如:
npm run lint
npm run test -- --onlyChanged
或者创建一个 npm script "validate": "npm run lint && npm run test",在 hook 中调用 npm run validate。
Q: 旧项目从 Husky v4 升级到 v9
A: 较新的版本架构完全不同,建议按照官方迁移指南重新初始化:删除原有配置,卸载旧版,安装最新版并运行 npx husky init,然后重新添加 hooks。
9. 扩展:与其他工具联动
Husky 的能力绝不限于 lint 和测试,你可以将任何命令行工具集成进来:
- Prettier:格式化代码,保证风格一致。
npx prettier --check . - TSC (TypeScript):编译检查类型错误。
npx tsc --noEmit - 自定义脚本:例如检查是否包含
console.log、禁止提交大文件等。
通过结合使用,你可以构建一套“提交质量门禁”,让代码库始终保持在预期状态,而无需依赖人工 review 发现基础性错误。
总结
Husky 将原本难以维护的 Git Hooks 变为项目标配,是现代前端/Node.js 工程化不可或缺的一环。你学会了:
- 安装与初始化 Husky
- 创建
pre-commit、commit-msg、pre-push等常用 hooks - 集成 ESLint、commitlint 和测试工具
- 管理 hooks 配置、调试以及团队协作要点
现在,你可以在自己的项目中引入 Husky,为每一次提交增添一道自动化的质量防线。让代码问题在提交前被消灭,把宝贵的时间留给更有价值的创意工作。