理解 Git Hooks 的工作原理,掌握常用钩子的使用场景,学会用 Husky 实现团队代码规范化。

Hooks — 在 Git 操作的前后自动执行脚本

每次 git commit 之前自动检查代码风格、跑单元测试、验证提交信息格式……这些自动化流程都可以通过 Git Hooks 实现。


一、什么是 Git Hooks?

Git Hooks 是在 Git 事件(如 commit、push、merge)前后自动执行的脚本。它们存放在 .git/hooks/ 目录中。

1
2
3
4
5
6
7
ls .git/hooks/
# applypatch-msg.sample
# pre-commit.sample
# commit-msg.sample
# pre-push.sample
# pre-rebase.sample
# ...

工作原理

  1. Git 执行某个操作(如 git commit
  2. 检查 .git/hooks/ 目录下是否有对应的钩子脚本
  3. 如果有,自动执行该脚本
  4. 如果脚本返回非零退出码,操作会被中止

二、常用钩子一览

客户端钩子(本地操作触发)

钩子触发时机典型用途
pre-commitcommit 之前代码检查、格式化、跑测试
prepare-commit-msg打开提交信息编辑器之前自动填充提交模板
commit-msg提交信息写好之后验证提交信息格式
post-commitcommit 之后发送通知、记录日志
pre-pushpush 之前跑完整测试套件
pre-rebaserebase 之前禁止对公共分支 rebase

服务端钩子(远程仓库触发)

钩子触发时机典型用途
pre-receive接收 push 之前拒绝不符合规范的推送
update接收 push 时(每个分支)分支级别的控制
post-receive接收 push 之后自动部署、发送通知

三、手动创建钩子

创建一个 pre-commit 钩子

1
2
# 1. 创建钩子文件(去掉 .sample 后缀)
vim .git/hooks/pre-commit

写入脚本内容:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
# 检查是否有 TODO 注释
if git diff --cached | grep -q "TODO"; then
echo "⚠️ 检测到 TODO 注释,请先处理后再提交"
exit 1
fi

# 检查是否有调试代码
if git diff --cached | grep -q "console.log"; then
echo "⚠️ 检测到 console.log,请移除后再提交"
exit 1
fi
1
2
# 2. 添加执行权限
chmod +x .git/hooks/pre-commit

创建一个 commit-msg 钩子

1
2
3
4
5
6
7
8
9
#!/bin/bash
# 验证提交信息格式:必须以 type: 开头
commit_msg=$(cat "$1")
if ! echo "$commit_msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore):"; then
echo "❌ 提交信息格式错误"
echo " 必须以 feat: fix: docs: style: refactor: test: chore: 开头"
echo " 你的提交信息:$commit_msg"
exit 1
fi

手动创建钩子的两个问题

  1. .git/hooks/ 不会被 Git 跟踪,团队成员 clone 后没有你的钩子
  2. 每次 git initgit clone 后需要重新配置

解决方案:用 Husky(见下文)。


四、Husky — 团队共享的 Git Hooks

Husky 是目前最流行的 Git Hooks 管理工具,它把钩子配置放在项目代码中,团队成员 clone 后自动生效。

安装与初始化

1
2
3
4
5
# 安装
npm install -D husky

# 初始化(生成 .husky/ 目录 + 在 package.json 中加 prepare 脚本)
npx husky init

生成的结构:

1
2
3
4
5
my-project/
├── .husky/
│ └── pre-commit ← 钩子脚本(会被 Git 跟踪)
├── package.json ← 包含 prepare 脚本
└── ...

配置 pre-commit 钩子

编辑 .husky/pre-commit

1
2
3
4
5
# 跑 lint 检查
npx eslint src/ --fix

# 跑单元测试
npm test

配置 commit-msg 钩子

1
2
# 创建 commit-msg 钩子
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'

五、lint-staged — 只检查暂存的文件

Husky 配合 lint-staged 使用效果更好:只检查本次提交暂存的文件,而不是全量检查。

安装

1
npm install -D lint-staged

配置

package.json 中添加:

1
2
3
4
5
6
7
8
9
10
{
"lint-staged": {
"*.{js,ts,vue}": [
"eslint --fix"
],
"*.{css,scss,less}": [
"stylelint --fix"
]
}
}

配合 Husky

编辑 .husky/pre-commit

1
npx lint-staged

完整效果

  1. 开发者执行 git commit
  2. Husky 触发 pre-commit 钩子
  3. lint-staged 只检查暂存区的 .js.css 文件
  4. 自动修复能修复的问题(--fix
  5. 如果有无法自动修复的错误 → 提交被阻止
  6. 全部通过 → 提交成功

六、commitlint — 规范提交信息

commitlint 用于强制提交信息遵循 Conventional Commits 规范。

安装

1
npm install -D @commitlint/cli @commitlint/config-conventional

配置

创建 commitlint.config.js

1
2
3
module.exports = {
extends: ['@commitlint/config-conventional']
};

允许的格式:

1
2
3
4
5
feat: 添加用户登录功能       ✅
fix: 修复密码验证错误 ✅
docs: 更新 API 文档 ✅
update ❌ 缺少类型前缀
修复了一个bug ❌ 格式不对

配合 Husky

1
2
3
# 添加 commit-msg 钩子
echo "npx --no -- commitlint --edit \${1}" > .husky/commit-msg
chmod +x .husky/commit-msg

七、跳过钩子

某些紧急情况下需要跳过钩子:

1
2
# --no-verify 跳过 pre-commit 和 commit-msg 钩子
git commit --no-verify -m "hotfix: 紧急修复线上问题"

慎用 --no-verify:这等于绕过了所有质量检查。只在紧急修复时使用,事后要记得补上规范化的提交。


八、实战:完整的团队规范配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1. 安装依赖
npm install -D husky lint-staged @commitlint/cli @commitlint/config-conventional

# 2. 初始化 Husky
npx husky init

# 3. 配置 pre-commit(.husky/pre-commit)
echo "npx lint-staged" > .husky/pre-commit

# 4. 配置 commit-msg
echo 'npx --no -- commitlint --edit ${1}' > .husky/commit-msg

# 5. 在 package.json 中添加
# "lint-staged": { "*.{js,ts}": ["eslint --fix"] }
# "scripts": { "prepare": "husky" }

# 6. 创建 commitlint.config.js
echo "module.exports = { extends: ['@commitlint/config-conventional'] }" > commitlint.config.js

# 7. 提交
git add .
git commit -m "chore: 配置 husky + lint-staged + commitlint"

总结:Git Hooks 速查卡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──────────────────────────────────────────────────────────┐
│ Git Hooks 速查 │
├────────────────┬─────────────────────────────────────────┤
│ pre-commit │ commit 前:代码检查、格式化、跑测试 │
│ commit-msg │ 提交信息写好后:验证格式 │
│ pre-push │ push 前:跑完整测试套件 │
│ pre-rebase │ rebase 前:禁止对公共分支操作 │
├────────────────┼─────────────────────────────────────────┤
│ 手动创建钩子 │ .git/hooks/pre-commit + chmod +x │
│ 团队共享钩子 │ Husky:.husky/ 目录被 Git 跟踪 │
│ 只检查暂存文件 │ lint-staged │
│ 规范提交信息 │ commitlint │
├────────────────┼─────────────────────────────────────────┤
│ 跳过钩子 │ git commit --no-verify │
└────────────────┴─────────────────────────────────────────┘