pre-commit in GitHub Actions: A Caching Workflow
A GitHub Actions job runs pre-commit run --all-files after restoring a cache of ~/.cache/pre-commit.
The whole job is: check out, set up the interpreter, restore the pre-commit cache keyed on the config hash, then run all hooks. The cache is what keeps the job fast.
What it does
The workflow installs pre-commit, restores the hook-environment cache so envs are not rebuilt, and runs every hook against the whole repo. The official pre-commit/action does the caching for you, or you wire actions/cache yourself.
Common usage
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- run: pip install pre-commit
- run: pre-commit run --all-files --show-diff-on-failurePieces
| Step | Why |
|---|---|
| setup-python | Provides the interpreter the python hooks need |
| cache ~/.cache/pre-commit | Reuse hook environments between runs |
| key: hashFiles(config) | Invalidate the cache when hooks change |
| run --all-files | Check the whole repo, not just a diff |
| --show-diff-on-failure | Surface what autofixers would change |
In CI
Key the cache on the hash of .pre-commit-config.yaml so it busts whenever a rev or hook changes. Without the cache, every run logs "[INFO] Initializing environment" and reinstalls every hook, adding minutes. The pre-commit/action@v3 action bundles this caching if you prefer not to manage it.
Common errors in CI
Slow jobs that always print "[INFO] Initializing environment for ..." mean the cache is not being restored: check the cache path is exactly ~/.cache/pre-commit and the key is stable. "[ERROR] Executable python3.11 not found" means setup-python ran with a different version than default_language_version pins. A job that passes locally but fails on CI is usually catching files that were never staged locally.