Pre-Commit Hooks¶
Overview¶
Pre-commit hooks automatically validate code before commits, catching syntax errors, formatting issues, and common mistakes. This prevents broken code from entering the repository.
Installation¶
One-Time Setup¶
# Install pre-commit (macOS)
brew install pre-commit
# Install in repository (creates .git/hooks/pre-commit)
pre-commit install
Tool Dependencies¶
Most tools are installed automatically by pre-commit. Optional tools:
# For manual linting outside pre-commit
brew install shellcheck yamllint
pip3 install --user ansible-lint black
npm install -g markdownlint-cli2 # Optional — pre-commit handles this
What Gets Checked¶
All Files¶
- Trailing whitespace removal (except markdown line breaks)
- End-of-file newline enforcement
- Large files detection (>1MB)
- Merge conflict markers
- Line endings normalized to LF
Markdown Files (*.md)¶
- markdownlint (via markdownlint-cli2) - style and consistency validation
- Heading structure and blank lines
- Code fence language identifiers (MD040)
- List formatting and indentation
- Config:
.markdownlint.yml(rules),.markdownlint-cli2.jsonc(ignores) - Manual run:
npx markdownlint-cli2 "**/*.md" - Auto-fix:
npx markdownlint-cli2 "**/*.md" --fix
Shell Scripts (*.sh)¶
- ShellCheck - catches common errors:
- Unquoted variables
- Missing error handling (
cdwithout|| exit) - Unused variables
- Incorrect conditionals (
==vs=) - And 300+ other issues
YAML Files¶
- yamllint - syntax and style validation
- Max line length: 120 characters
- Consistent indentation
- Proper quote usage
Ansible Files (cloud/ansible/*/.yml)¶
- Basic YAML checks via check-yaml
- ansible-lint disabled by default (run manually - see below)
Terraform Files (cloud/terraform/*/)¶
- terraform fmt - automatic formatting
- terraform validate - configuration validation
Python Files (*.py)¶
- black - automatic PEP8 formatting
Usage¶
Automatic (Recommended)¶
Hooks run automatically on git commit:
git add file.sh
git commit -m "Fix script"
# Pre-commit runs, auto-fixes some issues, blocks commit if errors found
If hooks fail:
- Review the errors
- Fix manually or let auto-fixers handle it
- Re-stage fixed files:
git add <files> - Commit again
Manual¶
Run on specific files:
Run on all files:
Run specific hook:
Bypassing (Emergency Only)¶
Only use for:
- True emergencies (production down)
- Committing intentionally broken code for collaboration
- Working around known false positives (fix the config instead!)
Ansible Linting (Manual)¶
ansible-lint has dependency issues in pre-commit isolation. Run manually:
# From repo root
cd cloud/ansible
ansible-lint
# Check specific playbook
ansible-lint playbooks/bootstrap-dev-host.yml
# With profile
ansible-lint --profile=production
Maintenance¶
Update Hook Versions¶
Clear Cache (if hooks misbehave)¶
Common Issues¶
"command not found: shellcheck"¶
Install system package:
"terraform: command not found"¶
Terraform validation needs terraform binary in PATH. Options:
- Install terraform:
brew install terraform - Disable terraform hooks in
.pre-commit-config.yaml
Hooks Won't Run¶
# Reinstall hooks
pre-commit uninstall
pre-commit install
# Verify installation
ls -la .git/hooks/pre-commit
False Positives¶
ShellCheck warning you disagree with? Add directive:
Or configure globally in .shellcheckrc (create if needed).
Configuration¶
Edit .pre-commit-config.yaml to:
- Add/remove hooks
- Adjust severity levels
- Exclude files/patterns
- Update versions
After config changes:
Benefits¶
Before pre-commit:
With pre-commit:
$ git commit -m "Add feature"
shellcheck...........Failed
- Syntax error detected in build-golden-image.sh
# Fix BEFORE broken code enters git history
Result:
- ✅ Catch errors in seconds, not minutes
- ✅ No broken commits in history
- ✅ Consistent code style across team
- ✅ Fewer "it works on my machine" issues