One-click configure Git Hooks to standardize the team development workflow.
Overview
Automatically generate pre-commit / commit-msg / pre-push hook configurations, including code formatting, commit message validation, and sensitive information checks. Supports both husky and native git hooks approaches.
When to Use
- User wants to set up git hooks
- User mentions pre-commit or commit message conventions
- User wants to automate lint/format checks
- User inputs
/git-hooks-setup - User wants to enforce pre-push checks (tests, lint)
- User wants to prevent pushing broken code
- User wants to standardize team commit message format
- User wants to add secret scanning before commit
- User wants to auto-format code on every commit
When NOT to Use:
- User only wants to view current git hooks configuration
- User wants CI-based checks (no local hooks needed)
- User's project already has a complete hooks setup
- User wants to run hooks on specific files only (use lint-staged directly)
- User wants to hook into Git events other than pre-commit/commit-msg/push
Core Pattern
Step 1: Detect the project environment
# 检测包管理器(按 lock 文件判断)
if [ -f "package-lock.json" ]; then PACKAGE_MANAGER="npm"
elif [ -f "yarn.lock" ]; then PACKAGE_MANAGER="yarn"
elif [ -f "pnpm-lock.yaml" ]; then PACKAGE_MANAGER="pnpm"
# 检测已有 hooks 配置
test -d ".husky" && echo "husky 已配置"
test -f ".git/hooks/pre-commit" && echo "原生 hooks 已配置"
# 从 package.json 检测已安装的 lint 工具(eslint/prettier/lint 相关)
Step 2: Choose an approach
| Approach | Use case | Advantages |
|---|---|---|
| husky | Node.js projects | Team collaboration friendly, configuration as code |
| Native git hooks | Non-Node.js projects | No dependencies |
Step 3: Generate configuration
Approach A: Husky
# 根据 $PACKAGE_MANAGER 选择: pnpm dlx / yarn dlx / npx
husky init # 初始化 husky
Generate .husky/pre-commit(executes lint-staged) and .husky/commit-msg(executes commitlint), note that commitlint requires adding the --no prefix to avoid interactive installation.
Generate lint-staged configuration (written to package.json):
{
"lint-staged": {
"*.{ts,tsx,js,jsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yml}": ["prettier --write"]
}
}
Generate .husky/pre-push(optional, run tests before push):
# 根据包管理器选择命令
if [ "$PACKAGE_MANAGER" = "pnpm" ]; then
pnpm test
elif [ "$PACKAGE_MANAGER" = "yarn" ]; then
yarn test
else
npm test
fi
Approach B: Native git hooks
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
# 自动 lint + format(按项目实际替换命令;示例为 Node 项目)
if [ -f "package.json" ] && [ -x "$(command -v npm)" ]; then
npm run lint -- --fix 2>/dev/null || true
npm run format 2>/dev/null || true
fi
# 注意:不要执行 git add -u —— 那会把用户未暂存的改动也一并提交。
# 若需把 lint 修复的结果纳入提交,请使用 lint-staged(只处理暂存文件)。
EOF
chmod +x .git/hooks/pre-commit
# pre-push hook(可选,push 前跑测试;按项目实际替换)
cat > .git/hooks/pre-push << 'EOF'
#!/bin/sh
if [ -f "package.json" ] && [ -x "$(command -v npm)" ]; then
npm test || exit 1
fi
EOF
chmod +x .git/hooks/pre-push
Step 4: Configure the Commit Message convention
Copy templates/commitlint.config.js to the project root directory (commitlint.config.js). This configuration is based on @commitlint/config-conventional, and validates the commit message format:
type(scope): subject
# type: feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert
# scope: 可选,影响范围
# subject: 简短描述(header-max-length 限制 100 字符)
Install the commitlint dependency at the same time:
npm install -D @commitlint/cli @commitlint/config-conventional
Step 5: Add sensitive information checks
⚠️ Do not use keyword scanning like
grep "password|secret|token"— it is normal for the words "token"/"secret" to appear in business code, and this will cause widespread false positives that frequently block commits.
It is recommended to use gitleaks(specifically for secret scanning, with built-in entropy detection + allowlist, and a low false positive rate):
# 生成 gitleaks pre-commit hook
npx gitleaks git-config 2>/dev/null || brew install gitleaks && gitleaks git-config
# 或手动在 .git/hooks/pre-commit 中加入:
# gitleaks protect --staged --verbose 2>&1
# 若 gitleaks 不可用,宁可跳过也不要退化成关键字 grep
If gitleaks really cannot be installed, as a fallback you should still avoid whole-word false positives — only matchhigh-confidence patterns(such as private key blocks and AWS key formats), and do not match commonly used business words like token/secret/password :
# 低误报替代方案:只扫私钥和云厂商密钥格式(示例)
if git diff --cached --diff-filter=ACM --name-only -z | xargs -0 grep -IlE "BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}" 2>/dev/null | grep -q .; then
echo "警告: 检测到可能的密钥泄露,请检查后重新提交"
exit 1
fi
Quick Reference
/git-hooks-setup # 交互式选择方案和 hooks
/git-hooks-setup --husky # 直接用 husky
/git-hooks-setup --native # 直接用原生 git hooks
| Parameter | Description | Default value |
|---|---|---|
--husky |
Use husky | Auto-detect |
--native |
Use native git hooks | false |
--commitlint |
Add commit message validation | true |
Common Mistakes
| Mistake | Correct practice | Reason |
|---|---|---|
| The hook script does not have execute permission | chmod +x .git/hooks/* |
The hook will not run |
| lint-staged is configured with too many rules | Only check staged files | Reduce commit waiting time |
| Commit message validation is too strict | Start lenient, then tighten | Avoid team resistance |
| Do not check for sensitive information | Add secret scanning | Prevent leaks |
| .git/hooks is not committed | Manage with husky/lefthook | The team needs to share configuration |
| The pre-push hook runs too long | Run only quick checks, put full tests in CI | Push being blocked affects efficiency |
| Use relative paths in hooks | Use absolute paths or the project root directory | Path resolution fails when executed from different directories |
| Skip the prepare script | Ensure that package.json's prepare runs husky(v9+) |
CI environment hook does not take effect |
| commitlint rules are inconsistent with the team | Use commitlint.config.js unified configuration |
Verbal agreements are easily violated |
| Do not configure a --no-verify whitelist | Allow --no-verify but log it |
Emergency fixes must not be completely blocked |