pre-commit stages: When Hooks Run
stages tells pre-commit which git phases a hook runs at, such as pre-commit, pre-push, or manual.
Not every hook should run on every commit. Slow or release-only checks can be scoped to pre-push or a manual stage you invoke explicitly in CI.
What it does
A hook stages list (or default_stages at the top level) restricts when the hook fires. The manual stage never runs automatically; it only runs when you call pre-commit run --hook-stage manual, which is handy for CI-only checks.
Common usage
- repo: local
hooks:
- id: heavy-tests
name: heavy tests
entry: pytest -m slow
language: system
stages: [manual]
# in CI:
# pre-commit run --hook-stage manual --all-filesStages
| Stage | When it fires |
|---|---|
| pre-commit (commit) | On git commit, against staged files |
| pre-push | On git push |
| commit-msg | After the commit message is written |
| manual | Only when invoked with --hook-stage manual |
| default_stages | Top-level default applied to hooks without stages |
In CI
Use the manual stage for expensive checks you want only in the pipeline, then run pre-commit run --hook-stage manual --all-files as a dedicated step. Newer pre-commit renamed the commit stage to pre-commit; old configs using stages: [commit] still work but emit a deprecation note.
Common errors in CI
A hook that "does nothing" in CI is often scoped to stages: [manual] but invoked without --hook-stage manual. The deprecation message "[WARNING] hook id ... uses deprecated stage names (commit, push)" means you should rename them to pre-commit and pre-push. An unknown stage name raises InvalidConfigError.