Hooks & Automation
Quick Summary
Git hooks are scripts that run automatically when specific Git events occur (commit, push, merge, etc.). They let you enforce code quality (lint before commit), run tests (before push), and automate repetitive tasks — all without relying on CI/CD.
Available Hooks
| Hook | Trigger | Common Use |
|---|---|---|
pre-commit | Before commit is created | Lint, format, check secrets |
commit-msg | After message is entered | Validate commit message format |
pre-push | Before push to remote | Run tests |
post-merge | After merge completes | Install dependencies |
post-checkout | After branch switch | Setup environment |
prepare-commit-msg | Before editor opens | Auto-populate message template |
Creating a Hook
Hooks live in .git/hooks/. Create a file with the hook name (no extension) and make it executable:
# Create a pre-commit hook
nano .git/hooks/pre-commit
#!/bin/sh
# pre-commit hook: run linter before allowing commit
echo "Running linter..."
npm run lint
if [ $? -ne 0 ]; then
echo "❌ Lint failed. Fix errors before committing."
exit 1 # Block the commit
fi
echo "✅ Lint passed."
exit 0 # Allow the commit
# Make it executable
chmod +x .git/hooks/pre-commit
Useful Hook Examples
Pre-commit: Check for Debug Statements
#!/bin/sh
# Block commits containing console.log or debugger
BLOCKED=$(git diff --cached --name-only | xargs grep -l "console\.log\|debugger" 2>/dev/null)
if [ -n "$BLOCKED" ]; then
echo "❌ Found debug statements in:"
echo "$BLOCKED"
echo "Remove console.log/debugger before committing."
exit 1
fi
Commit-msg: Enforce Conventional Commits
#!/bin/sh
# Require conventional commit format
MSG=$(cat "$1")
PATTERN="^(feat|fix|docs|style|refactor|test|chore|perf)(\(.+\))?: .{3,}"
if ! echo "$MSG" | grep -qE "$PATTERN"; then
echo "❌ Commit message must follow Conventional Commits format:"
echo " feat: add login page"
echo " fix(auth): resolve timeout issue"
exit 1
fi
Pre-push: Run Tests
#!/bin/sh
echo "Running tests before push..."
npm test
if [ $? -ne 0 ]; then
echo "❌ Tests failed. Fix before pushing."
exit 1
fi
Sharing Hooks with the Team
Git hooks live in .git/hooks/ which is not tracked by Git. Solutions:
Option 1: Husky (Node.js projects)
# Install Husky
npm install --save-dev husky
# Initialize
npx husky init
# Add a pre-commit hook
echo "npm run lint" > .husky/pre-commit
package.json:
{
"scripts": {
"prepare": "husky"
}
}
Option 2: Custom hooks directory
# Store hooks in a tracked directory
mkdir -p .githooks
# Configure Git to use it
git config core.hooksPath .githooks
Best Practices
- Keep hooks fast — slow pre-commit hooks frustrate developers
- Use Husky or
core.hooksPath— ensure the whole team uses the same hooks - Don't replace CI/CD — hooks are local; CI/CD is the authoritative check
- Allow bypass for emergencies —
git commit --no-verifyskips hooks - Test hooks — a broken hook can block all commits
What's Next
- Common Errors — Fix frequent Git mistakes
- Undoing Changes — Undo commits, merges, and staged changes