- Introduction: What is
pre-commit
? - Why Use
pre-commit
? - How
pre-commit
Works - Installing and Setting Up
pre-commit
- Configuring
.pre-commit-config.yaml
- Built-in and Community Hooks
- How to Run and Use
pre-commit
- Popular Use Cases
- Writing Custom Hooks
- Advanced Configuration and Features
- Integrating with CI/CD
- Best Practices
- Troubleshooting and Common Issues
- Alternatives and Related Tools
- Resources
pre-commit
is an open-source framework for managing and maintaining multi-language pre-commit hooks. In software development, Git hooks are scripts that run automatically on specific Git events (e.g., commit, push). pre-commit
makes it easy to install and run hooks for code quality, security, style, and more—before code gets committed.
It is language-agnostic and supports everything from Python, JavaScript, Go, and Shell scripts, to Rust, Ruby, and more.
- Automate Code Quality: Catch formatting errors, linting issues, and security flaws before they reach your repo.
- Consistency Across Teams: Ensures everyone runs the same checks, reducing “works on my machine” problems.
- Developer Productivity: Automates repetitive checks, freeing up dev time.
- Multi-language Support: Works across codebases with multiple languages and ecosystems.
- Easy CI/CD Integration: Hooks can be run manually or in CI to ensure consistency.
- You define a list of hooks (scripts) in a
.pre-commit-config.yaml
file. pre-commit
installs the required environments for each hook (virtualenvs, Node, etc.).- When you run
git commit
,pre-commit
runs all the enabled hooks on the files you’re committing. - If a hook fails, the commit is blocked.
-
Python users:
pip install pre-commit
-
Homebrew (macOS/Linux):
brew install pre-commit
-
Other: Install via
conda
,pipx
, or download from GitHub.
-
Add to your project:
pre-commit sample-config > .pre-commit-config.yaml
-
Install the Git hook scripts:
pre-commit install
This sets up
.git/hooks/pre-commit
to runpre-commit
on every commit. -
Run on all files (initial run):
pre-commit run --all-files
This YAML file tells pre-commit
which hooks to use and how to run them.
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0 # Use the latest stable tag
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- repo: https://github.com/psf/black
rev: 24.3.0
hooks:
- id: black
Key Fields:
repo
: URL or path to the repo with hooksrev
: Version tag or commit hashhooks
: List of hook definitions (id, args, files, etc.)
id
: The hook’s unique name.args
: Custom arguments for the hook.files
: Regex for files to include.exclude
: Regex for files to exclude.language_version
: Set the language version (e.g., python3.11).
There’s a huge list of pre-commit hooks:
- Official:
pre-commit/pre-commit-hooks
- E.g., trailing whitespace, debug statements, end-of-file fixes.
- Language Formatters:
- Linters:
- Security:
- Others: License checks, secret detection, file size checks, etc.
-
On every commit: Automatically runs via the installed hook.
-
Manually on staged files:
pre-commit run
-
On all files:
pre-commit run --all-files
-
On a specific hook:
pre-commit run black --all-files
-
Update all hooks:
pre-commit autoupdate
- Enforce code style (formatters, linters)
- Check for secrets (AWS keys, passwords)
- Fix whitespace, newlines, EOF issues
- Enforce commit message format
- Check for large files or merge conflicts
- Security vulnerability checks
You can write your own hooks in any language.
repos:
- repo: local
hooks:
- id: my-linter
name: My Custom Linter
entry: ./scripts/my_linter.sh
language: script
files: \.py$
- id: check-todo
name: Check for TODOs
entry: python scripts/check_todo.py
language: python
files: .*
Hook script must accept a list of filenames as arguments. Return 0 for pass, non-zero for fail.
- Staged-only or all files: Use
always_run
,pass_filenames
, andstages
options. - Multiple stages: Use
stages: [commit, push, manual]
. - Parallel execution: By default, hooks run in parallel.
- Failing gracefully: Hooks can be set as
required
oroptional
. - Excluding files: Use the
exclude
regex for large/irrelevant files. - Languages: Hooks support many languages (
python
,node
,golang
,docker
,system
, etc.). - Hook ordering: Hooks run in the order they’re listed.
-
Why: Ensures code quality checks run in CI, not just on developer machines.
-
How:
-
In your CI job, install
pre-commit
and run:pre-commit run --all-files --show-diff-on-failure
-
For some CIs (e.g., GitHub Actions), there are pre-built actions: pre-commit/action
-
-
Fail the build if hooks fail.
-
Pin hook versions: Always use specific
rev
values, nevermaster
/main
. -
Run
pre-commit run --all-files
after adding new hooks. -
Add
.pre-commit-config.yaml
to source control. -
Document setup in
CONTRIBUTING.md
. -
Keep hooks fast—slow hooks slow down developer flow.
-
Autoupdate hooks regularly:
pre-commit autoupdate
-
Review hook changes on update (some hooks change behavior across versions).
-
Hook not running? Did you run
pre-commit install
? -
Hook fails but works manually? Check environment—
pre-commit
uses isolated environments for each hook. -
Can’t find a hook or dependency? Sometimes you need to manually install system packages (e.g.,
libyaml-dev
). -
Files modified by hooks? By default, if a hook modifies files (e.g., a formatter), you must
git add
them and recommit. -
Want to skip
pre-commit
just once?git commit --no-verify
-
Speed up repeated runs: Use
pre-commit run --files ...
or only staged files. -
Cross-platform issues: Some hooks may have trouble on Windows—test in your team’s environments.
- Husky (JavaScript-centric, popular in frontend projects)
- lefthook (Go, cross-platform, fast)
- Overcommit (Ruby)
- git hooks (native, but more manual)
pre-commit
is the most widely used and language-agnostic solution.
- pre-commit.com documentation
- Official hook index
- Writing custom hooks
- Awesome pre-commit
- Sample
.pre-commit-config.yaml
files
- pre-commit is a framework for managing and running Git hooks.
- It is configured via
.pre-commit-config.yaml
and supports many languages. - You install it, configure hooks, and let it run checks/formatters automatically on commit.
- It boosts code quality, developer experience, and consistency.
Let me know—I'm happy to go even deeper into any area, write advanced examples, or help troubleshoot!
https://git-scm.com/book/ms/v2/Customizing-Git-Git-Hooks