pre-commit files and exclude: Path Filtering
files and exclude are regular expressions that include or exclude paths from a hook.
pre-commit matches files against these patterns to decide what each hook sees. They are Python regexes, not globs, and that trips people up.
What it does
A top-level files/exclude filters every hook; a per-hook files/exclude filters that one hook. A path runs through a hook only if it matches files (default: everything) and does not match exclude. The patterns are anchored-search Python regular expressions.
Common usage
exclude: '^(vendor/|third_party/|.*\.min\.js$)'
repos:
- repo: https://github.com/psf/black
rev: 24.4.2
hooks:
- id: black
files: '^src/'
exclude: '^src/generated/'Keys
| Key | What it does |
|---|---|
| files | Regex of paths to include (default: all) |
| exclude | Regex of paths to skip |
| exclude_types | Skip files of a detected type |
| types / types_or | Restrict to detected file types |
| ^ and $ | Anchor the pattern; multiline excludes use ( | ) groups |
In CI
Because patterns are regexes, escape dots and remember these are not globs: ^.*\.lock$ not *.lock. To exclude many directories, use an alternation with ^( ... ) and the YAML block-scalar syntax for long lists. The meta hook check-useless-excludes flags exclude patterns that match nothing.
Common errors in CI
A hook that "still runs on a file you excluded" almost always has a glob where a regex was expected; convert *.min.js to .*\.min\.js$. "check-useless-excludes" failing means an exclude pattern no longer matches any file. An unescaped regex metacharacter can raise a config error or silently match too much.