Git Hooks
This template uses Husky and lint-staged to run automated checks before commits and pushes.
Overview
| Hook | Tool | What Runs |
|---|---|---|
pre-commit | lint-staged | ESLint + Prettier on staged files |
pre-push | Scripts | Full lint, typecheck, test, publint |
How It Works
Husky
Husky manages Git hooks. Hooks are shell scripts in .husky/ that Git executes at specific points.
lint-staged
lint-staged runs commands only on files that are staged for commit, making pre-commit checks fast.
Hook Configuration
Pre-commit Hook
File: .husky/pre-commit
pnpm lint-stagedThis runs lint-staged, which is configured in package.json:
{
"lint-staged": {
"*.{ts,tsx,js,mjs,cjs}": ["eslint --fix", "prettier --write"],
"*.{md,json,yml,yaml}": ["prettier --write"]
}
}What happens:
- You stage files:
git add src/index.ts - You commit:
git commit -m "feat: add feature" - Husky triggers pre-commit hook
- lint-staged runs ESLint and Prettier on staged
.tsfiles - If fixes are applied, they're automatically staged
- If errors remain, commit is aborted
Pre-push Hook
File: .husky/pre-push
pnpm run lint
pnpm run typecheck
pnpm run test
pnpm run lint:packageWhat happens:
- You push:
git push origin main - Husky triggers pre-push hook
- Full project lint, typecheck, tests, and publint run
- If any check fails, push is aborted
This prevents pushing broken code to the repository.
Installing Hooks
Hooks are installed automatically when you run pnpm install via the prepare script:
{
"scripts": {
"prepare": "husky"
}
}To manually reinstall hooks:
pnpm run prepareBypassing Hooks
In emergencies, you can skip hooks:
# Skip pre-commit
git commit --no-verify -m "emergency fix"
# Skip pre-push
git push --no-verifyWARNING
Use --no-verify sparingly. CI will still run all checks, so broken code may fail in the pipeline.
Troubleshooting
Hooks Not Running
Symptoms: Commits succeed without linting, or pnpm lint-staged is not found.
Causes:
- Hooks not installed
- Husky not initialized
- Git not detecting
.husky/directory
Fix:
# Ensure Git is initialized
git status
# Reinstall hooks
pnpm run prepare
# Verify hooks exist
ls -la .husky/Hooks Not Running on Windows
Symptoms: Hooks work in Git Bash but not in PowerShell or CMD.
Causes:
- Windows line endings (CRLF) in hook files
- Shell not properly configured
Fix:
- Ensure
.husky/files use LF line endings (not CRLF) - Use Git Bash instead of PowerShell/CMD
- Or configure Git to use bash:
git config core.hooksPath .huskylint-staged Errors
Symptom: lint-staged fails with ESLint errors.
Fix options:
- Fix the errors manually
- Let ESLint auto-fix: errors that can't be auto-fixed need manual attention
- As last resort:
git commit --no-verify
Pre-push Hook Fails
Symptom: Push blocked due to test or lint failures.
Fix:
Run the failing command locally to see the error:
bashpnpm run lint pnpm run typecheck pnpm run test pnpm run lint:packageFix the issues
Commit the fixes
Push again
publint Fails in Pre-push
Symptom: lint:package fails with "dist/index.js does not exist"
Cause: Pre-push runs publint, which requires built files.
Fix:
# Build first
pnpm run build
# Then push
git pushOr ensure you always build before pushing.
Customizing Hooks
Adding Commands to Pre-commit
Edit .husky/pre-commit:
pnpm lint-staged
pnpm run my-custom-checkAdding Commands to Pre-push
Edit .husky/pre-push:
pnpm run lint
pnpm run typecheck
pnpm run test
pnpm run lint:package
pnpm run my-custom-checkChanging lint-staged Configuration
Edit package.json:
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.css": ["stylelint --fix"],
"*.md": ["markdownlint --fix", "prettier --write"]
}
}Why Both Hooks?
Pre-commit (Fast)
- Runs only on staged files
- Quick feedback loop
- Catches formatting and obvious lint errors
- Doesn't block development flow
Pre-push (Comprehensive)
- Runs full project checks
- Catches issues that affect the whole codebase
- Ensures CI won't fail
- Last line of defense before code reaches remote
This two-tier approach balances development speed with code quality.