Software Engineering · lesson 15 of 18
Git Hooks & Automation
Automate Quality
Why it matters
Automation catches mistakes before they become problems. Git hooks enforce quality standards at commit time. CI/CD extends this to the entire pipeline.
Key concepts
- Git Hooks — Scripts triggered by Git events
- Pre-commit — Hook that runs before commit is created
- CI/CD — Continuous Integration/Deployment automation
- GitHub Actions — GitHub’s built-in CI/CD platform
The idea
The Quality Gate
Hooks are scripts that run automatically at key points:
Pre-commit: Before commit is created
- Lint code
- Run formatter
- Check for secrets
- Validate commit message
Pre-push: Before push to remote
- Run tests
- Check branch naming
CI/CD: After push to remote
- Build project
- Run full test suite
- Deploy to staging/production
Walkthrough
Git Hook Locations
.git/hooks/
├── pre-commit # Before commit
├── prepare-commit-msg # Edit default message
├── commit-msg # Validate commit message
├── pre-push # Before push
├── pre-rebase # Before rebase
└── post-merge # After merge
Simple Pre-Commit Hook
#!/bin/bash
# .git/hooks/pre-commit
# Run linter
npm run lint
if [ $? -ne 0 ]; then
echo "Linting failed. Fix errors before committing."
exit 1
fi
# Check for console.log
if git diff --cached | grep -q "console.log"; then
echo "Warning: console.log found in staged changes"
read -p "Continue anyway? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
exit 0
Using Husky (Node.js)
# Install
npm install husky --save-dev
npx husky init
# Add pre-commit hook
echo "npm run lint" > .husky/pre-commit
# Add commit-msg hook (with commitlint)
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg
Using pre-commit (Python)
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.1
hooks:
- id: gitleaks
# Install
pip install pre-commit
pre-commit install
pre-commit run --all-files
GitHub Actions CI
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Test
run: npm test
- name: Build
run: npm run build
Key takeaways
- Hooks catch issues before they’re committed
- Use tools like Husky or pre-commit for easy setup
- CI/CD runs on every push—comprehensive testing
- Automate everything that can be automated
Dos & don’ts
✅ DO
- Keep hooks fast: Slow hooks frustrate developers
- Share hooks via config: Husky, pre-commit, lefthook
- Scan for secrets: Use gitleaks or git-secrets
- Run tests in CI: Full suite, every push
❌ DON’T
- Don’t skip hooks habitually: —no-verify should be rare
- Don’t put slow tests in pre-commit: Save those for CI
- Don’t ignore CI failures: Fix them immediately
Going deeper
Branch Protection Rules: GitHub can require:
- PRs before merging
- Passing CI checks
- Code review approvals
- Signed commits Configure in Settings > Branches.
Secret Scanning:
GitHub automatically scans for leaked secrets.
Add gitleaks to pre-commit for local protection.
Common mistakes
Hooks not shared: .git/hooks/ isn’t tracked. Use Husky, pre-commit, or commit scripts to share.
Skipping hooks too often:
If everyone uses --no-verify, hooks are useless.
If hooks are too slow/annoying, fix them rather than bypassing.