Stop pushing broken code. Here's a 15-minute setup that will save you hours of embarrassment.
We've all been there. You push code, grab coffee, return to find CI failed because of a linting error you could've caught locally. Or worse—you merged something that broke tests your teammates now have to fix.
The fix isn't discipline. It's automation.
Today I'm sharing the exact pre-commit pipeline I use across all my projects. It runs in under 10 seconds, catches 90% of issues before they leave your machine, and requires zero ongoing maintenance.
The Problem With Manual Code Quality
Most developers know they should:
- Run linters before committing
- Format their code
- Run tests
- Check for security issues
But knowing and doing are different. When you're in flow state, the last thing you want is to context-switch to "ops mode" and run five different commands.
The result? You skip it. Everyone skips it. Then CI becomes the first line of defense instead of the last.
Enter Pre-Commit Hooks
Git hooks are scripts that run automatically at specific points in your workflow. The pre-commit hook runs before every commit, making it perfect for quality gates.
But raw git hooks are painful to manage. That's where pre-commit comes in—a framework that handles hook installation, updates, and execution.
The Setup (15 Minutes)
Step 1: Install pre-commit
# With pip
pip install pre-commit
# With homebrew
brew install pre-commit
# With pipx (recommended for CLI tools)
pipx install pre-commit
Step 2: Create Your Config
Create .pre-commit-config.yaml in your repo root:
repos:
# Basic file hygiene
- 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-json
- id: check-added-large-files
args: ['--maxkb=1000']
- id: detect-private-key
- id: check-merge-conflict
# Python formatting (if applicable)
- repo: https://github.com/psf/black
rev: 24.2.0
hooks:
- id: black
# Python linting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.0
hooks:
- id: ruff
args: [--fix]
# Security scanning
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
Step 3: Install the Hooks
pre-commit install
pre-commit install --hook-type commit-msg
Step 4: Initial Run
pre-commit run --all-files
What This Pipeline Catches
| Hook | Catches |
|---|---|
trailing-whitespace |
Messy whitespace that clutters diffs |
check-yaml / check-json
|
Syntax errors in config files |
detect-private-key |
Accidentally committed secrets |
check-added-large-files |
Binary blobs that bloat your repo |
black / ruff
|
Python style and lint issues |
detect-secrets |
API keys, passwords, tokens |
Advanced: Running Tests in Pre-Commit
- repo: local
hooks:
- id: pytest-quick
name: Quick Tests
entry: pytest tests/unit -x -q --tb=no
language: system
pass_filenames: false
always_run: true
stages: [commit]
Performance Tips
- Use ruff instead of flake8+isort+pyupgrade—it's 10-100x faster
-
Skip slow hooks in
--all-files—run full suite in CI only -
Use
stagesto control when hooks run (commit vs push)
My Actual Numbers
On a 50-file Python project:
- Without pre-commit: 0 seconds (because I wasn't running anything)
- With pre-commit: 3-8 seconds per commit
- Bugs caught in last month: 47
- CI failures from lint issues: 0
Key Takeaways
- Automation beats discipline—remove the decision to run quality checks
- 15 minutes of setup saves hours of fixes—the ROI is immediate
- Start minimal, expand later—begin with basic hooks, add as needed
- Team-wide consistency—config files are shared, not individual
- Speed matters—if hooks are slow, people will skip them
The best code quality tool is the one that runs automatically.
What's in your pre-commit pipeline? Drop a comment below!
Top comments (0)