Files
holocron/plugins/git/docs/research/docs/pre-commit/configuration.md

207 lines
6.9 KiB
Markdown

---
topic: configuration
source_keys:
- context7-pre-commit-com
- pre-commit-com
---
## `.pre-commit-config.yaml` structure
### Top-level keys
| Key | Type | Default | Purpose |
|-----|------|---------|---------|
| `repos` | List | required | List of repo blocks |
| `default_install_hook_types` | List | `[pre-commit]` | Hook types installed when `pre-commit install` is run without `-t` |
| `default_language_version` | Dict | `{}` | Maps language name → version string; overrides per-hook defaults |
| `default_stages` | List | all stages | Applied to every hook unless the hook specifies `stages` |
| `files` | Regex string | `''` | Global include pattern applied before hook-level filters |
| `exclude` | Regex string | `^$` | Global exclude pattern |
| `fail_fast` | Boolean | `false` | Stop after the first failing hook |
| `minimum_pre_commit_version` | String | `'0'` | Minimum pre-commit version required to use this config |
### Repo block keys
| Key | Required | Description |
|-----|----------|-------------|
| `repo` | Yes | Git URL, or the special values `local` or `meta` |
| `rev` | Yes (not for `local`/`meta`) | Tag or SHA — must be immutable |
| `hooks` | Yes | List of hook override blocks |
### Hook override block keys
These keys appear under `hooks:` inside a repo block. All are optional overrides of the hook's upstream manifest values.
| Key | Type | Description |
|-----|------|-------------|
| `id` | String (required) | Hook identifier — must match an `id` in the repo's `.pre-commit-hooks.yaml` |
| `alias` | String | Extra name for targeting with `pre-commit run <alias>` |
| `name` | String | Override the display name |
| `language_version` | String | Override language version |
| `files` | Regex string | Override file include pattern (appended to upstream with AND logic) |
| `exclude` | Regex string | Override file exclude pattern |
| `types` | List | AND-logic type filter (all tags must match) |
| `types_or` | List | OR-logic type filter (any tag must match) |
| `exclude_types` | List | Exclude files matching these types |
| `args` | List | Additional CLI arguments prepended before filenames |
| `stages` | List | Which git stages trigger this hook |
| `additional_dependencies` | List | Extra packages to install into hook environment |
| `always_run` | Boolean | Run even if no files match the filter |
| `verbose` | Boolean | Always print output (not only on failure) |
| `log_file` | String | Write output to this file path on failure |
### Complete annotated example
```yaml
minimum_pre_commit_version: '3.0.0'
fail_fast: false
default_language_version:
python: python3.11
default_stages: [pre-commit, pre-push]
exclude: ^vendor/
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: pretty-format-json
args: [--autofix]
- id: trailing-whitespace
exclude: ^tests/fixtures/
- repo: local
hooks:
- id: validate-manifest
name: Validate marketplace manifest
entry: python scripts/validate_manifest.py
language: python
files: ^\.claude-plugin/marketplace\.json$
always_run: false
- repo: meta
hooks:
- id: check-hooks-apply
- id: check-useless-excludes
```
### Multi-line exclude pattern (readable for long lists)
```yaml
- id: my-hook
exclude: |
(?x)^(
path/to/file1.py|
path/to/file2.py|
path/to/generated/.*
)$
```
## Stages
Valid `stages` values: `pre-commit`, `pre-push`, `commit-msg`, `prepare-commit-msg`, `post-checkout`, `post-commit`, `post-merge`, `post-rewrite`, `pre-merge-commit`, `pre-rebase`, `manual`.
The `manual` stage only runs when explicitly invoked: `pre-commit run --hook-stage manual <hookid>`.
To install hooks for non-default stages, pass them to install:
```bash
pre-commit install -t pre-commit -t pre-push -t commit-msg
```
Or declare them in config so they install automatically:
```yaml
default_install_hook_types: [pre-commit, pre-push, commit-msg]
```
## `types` vs `types_or` vs `files`
- `types: [json, text]` — file must carry ALL listed tags (AND)
- `types_or: [javascript, typescript]` — file must carry ANY listed tag (OR)
- `files: \.py$` — regex applied via `re.search()` (not full match) on the file path
- `exclude: \.generated\.py$` — regex excludes matching paths after `files` matches
Both `types` and `files` filters must pass for a file to be processed. Use `identify-cli <file>` to see what tags a file has.
## Local hooks (`repo: local`)
No external repository required. Required fields: `id`, `name`, `language`, `entry`.
```yaml
- repo: local
hooks:
# System tool already installed (don't let pre-commit manage env)
- id: shellcheck
name: shellcheck
entry: shellcheck
language: unsupported # formerly "system"
types: [shell]
# Script in the repo
- id: run-tests
name: Run test suite
entry: bash tests/run-tests.sh
language: unsupported_script # formerly "script"
pass_filenames: false
always_run: true
stages: [pre-push]
# Always-fail guard (lightweight, no env needed)
- id: no-dotenv
name: No .env files
entry: .env files must not be committed
language: fail
files: \.env$
# Python with managed dependencies
- id: my-checker
name: My Python Checker
entry: python -m mymodule.checker
language: python
additional_dependencies: [requests==2.28.0]
types: [python]
```
### Language choices for local hooks
| Language | Description |
|----------|-------------|
| `unsupported` / `system` | Runs executable from system PATH — pre-commit does not manage environment |
| `unsupported_script` / `script` | Runs a script path relative to repo root |
| `fail` | Always fails; `entry` text becomes the error message — good for forbidden file patterns |
| `python` | Creates isolated venv; `additional_dependencies` are pip-installed |
| `node` | Creates isolated node env |
| `ruby`, `golang`, `rust`, `docker`, `docker_image` | Language-specific isolated envs |
### `pass_filenames` behavior
`true` (default): `entry arg1 arg2 file1 file2 file3`
`false`: `entry arg1 arg2` — hook gets no filenames; use for repo-wide or stateful checks.
## Meta hooks (`repo: meta`)
```yaml
- repo: meta
hooks:
- id: check-hooks-apply # each hook must match ≥1 file — catches dead hooks
- id: check-useless-excludes # each exclude must exclude ≥1 file — catches dead excludes
- id: identity # debug: prints every filename passed to pre-commit
```
## Hazmat helpers (v4.5.0+)
Entry-point prefixes for edge cases:
```yaml
# Change directory before running (monorepo)
entry: pre-commit hazmat cd subdir my-bin --
# Treat non-zero exit as warning instead of failure
entry: pre-commit hazmat ignore-exit-code my-bin --
verbose: true
# Run hook once per file (not batched)
entry: pre-commit hazmat n1 my-bin --
```