Pre-commit Framework
Learn to install and configure the pre-commit framework for managing git hooks across your development team.
The pre-commit framework is a language-agnostic tool for managing git hooks. It handles installation, updates, and execution of hooks from a simple YAML configuration file.
Installation
Install pre-commit using pip (Python's package manager):
# Install pre-commit
pip install pre-commit
# Verify installation
pre-commit --version
# pre-commit 3.6.0
Alternative installation methods:
# Using Homebrew (macOS/Linux)
brew install pre-commit
# Using pipx (isolated environment)
pipx install pre-commit
# Using conda
conda install -c conda-forge pre-commit
Basic Configuration
Create a .pre-commit-config.yaml file in your repository root:
# .pre-commit-config.yaml
repos:
# Built-in hooks from pre-commit
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
args: ['--maxkb=500']
- id: check-merge-conflict
- id: detect-private-key
Install the hooks into your git repository:
# Install hooks defined in .pre-commit-config.yaml
pre-commit install
# Output: pre-commit installed at .git/hooks/pre-commit
How Pre-commit Works
When you run git commit, pre-commit intercepts the command and runs your configured hooks:
Commit Flow with Pre-commit
---------------------------
git commit -m "message"
|
v
[pre-commit hook triggered]
|
v
[Run each configured hook]
|
+---+---+
| |
Pass Fail
| |
v v
[Commit [Commit blocked,
proceeds] show errors]
Hooks only run on staged files by default, making them fast even in large repositories.
Security-Focused Configuration
Here's a comprehensive configuration for security-focused pre-commit hooks:
# .pre-commit-config.yaml
repos:
# Standard pre-commit hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: detect-private-key
- id: check-added-large-files
- id: check-merge-conflict
- id: check-yaml
args: [--unsafe] # Allow custom tags
- id: check-json
- id: check-xml
- id: check-toml
# Secrets detection with gitleaks
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.1
hooks:
- id: gitleaks
# Alternative: detect-secrets from Yelp
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
# Security linting for Python
- repo: https://github.com/PyCQA/bandit
rev: 1.7.7
hooks:
- id: bandit
args: ['-c', 'pyproject.toml']
additional_dependencies: ['bandit[toml]']
# Dockerfile security
- repo: https://github.com/hadolint/hadolint
rev: v2.12.0
hooks:
- id: hadolint
Running Hooks Manually
You can run hooks without committing:
# Run all hooks on all files
pre-commit run --all-files
# Run a specific hook
pre-commit run gitleaks --all-files
# Run hooks on specific files
pre-commit run --files src/config.py src/auth.py
# Run hooks on staged files only (default behavior)
pre-commit run
Updating Hooks
Keep your hooks up to date to get the latest security rules:
# Update all hooks to latest versions
pre-commit autoupdate
# Update a specific repo
pre-commit autoupdate --repo https://github.com/gitleaks/gitleaks
Skipping Hooks (When Necessary)
Sometimes you need to bypass hooks (use sparingly):
# Skip all hooks for this commit
git commit --no-verify -m "Emergency fix"
# Or use the short flag
git commit -n -m "Emergency fix"
# Skip specific hooks
SKIP=gitleaks git commit -m "Commit with known false positive"
# Skip multiple hooks
SKIP=gitleaks,bandit git commit -m "Commit message"
Warning: Skipping hooks should be rare and documented. Consider using allowlists instead of skipping entirely.
Team-Wide Installation
Ensure everyone on your team uses pre-commit:
Option 1: Document in README
## Development Setup
1. Install pre-commit: `pip install pre-commit`
2. Install hooks: `pre-commit install`
Option 2: Makefile Target
# Makefile
.PHONY: setup
setup:
pip install pre-commit
pre-commit install
pre-commit install --hook-type commit-msg
Option 3: Post-clone Hook Script
#!/bin/bash
# scripts/setup-dev.sh
echo "Setting up development environment..."
# Install pre-commit if not present
if ! command -v pre-commit &> /dev/null; then
echo "Installing pre-commit..."
pip install pre-commit
fi
# Install hooks
pre-commit install
pre-commit install --hook-type commit-msg
echo "Pre-commit hooks installed successfully!"
CI Integration
Run pre-commit in your CI pipeline as a backup:
# .github/workflows/pre-commit.yml
name: Pre-commit
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: pre-commit/[email protected]
This catches any commits where developers bypassed local hooks.
Hook Stages
Pre-commit supports different git hook stages:
repos:
- repo: local
hooks:
# Runs before commit (default)
- id: unit-tests
name: Run unit tests
entry: pytest tests/unit -q
language: system
stages: [commit]
# Runs before push
- id: integration-tests
name: Run integration tests
entry: pytest tests/integration
language: system
stages: [push]
# Validates commit message format
- id: commit-msg-check
name: Check commit message
entry: scripts/check-commit-msg.sh
language: script
stages: [commit-msg]
Install hooks for different stages:
# Install pre-push hooks
pre-commit install --hook-type pre-push
# Install commit-msg hooks
pre-commit install --hook-type commit-msg
Caching and Performance
Pre-commit caches hook environments to speed up subsequent runs:
# View cache location
pre-commit --cache-dir
# Default: ~/.cache/pre-commit
# Clear cache if hooks misbehave
pre-commit clean
# Reinstall hook environments
pre-commit install-hooks
For large repositories, use files and exclude patterns:
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.1
hooks:
- id: gitleaks
# Only scan source files, not generated code
exclude: '^(vendor/|node_modules/|dist/)'
Troubleshooting
Hook Fails with No Output
Run in verbose mode:
pre-commit run --verbose
Hook Environment Issues
Reinstall the hook environment:
pre-commit clean
pre-commit install-hooks
Hook Runs Too Slowly
Check which files are being scanned:
pre-commit run --verbose --all-files 2>&1 | head -50
Add exclusions for large generated files or vendor directories.
Found an issue?