pre-commit/pre_commit
Sharmila Jesupaul 635912514d add pass_filenames_via_stdin for large changesets
pre-commit currently passes selected filenames to hooks via argv.
For large changesets (or --all-files), argv length limits are hit and
filenames are partitioned, causing multiple hook invocations.

This means there is currently no built-in way to pass filenames to an
underlying hook in one shot without chunking / re-running. The only practical
workaround is to set pass_filenames: false and run custom git operations in
hook code to reconstruct the file set, which is expensive and duplicates
pre-commit's own file-selection logic.

This change adds a hook option:

    pass_filenames_via_stdin: true

When enabled, pre-commit sends filenames as NUL-delimited bytes on stdin and
runs the hook in a single invocation (no argv chunking).

Why NUL-delimited stdin:
- safe for filenames containing spaces/newlines
- matches established -0 conventions in unix tooling

Usage for hook authors:
- shell:

    while IFS= read -r -d '' filename; do
        ...
    done

- python:

    data = sys.stdin.buffer.read()
    filenames = [os.fsdecode(p) for p in data.split(b'\0') if p]

Behavior notes:
- default remains argv-based passing
- pass_filenames: false still disables filename passing entirely

Implementation includes schema/runtime wiring, shared NUL encode/decode
helpers, and tests covering defaulting and runtime behavior.
2026-02-18 18:06:34 -08:00
..
commands add pass_filenames_via_stdin for large changesets 2026-02-18 18:06:34 -08:00
languages add pass_filenames_via_stdin for large changesets 2026-02-18 18:06:34 -08:00
meta_hooks python3.9+ 2023-10-28 14:20:37 -04:00
resources fix python local template when artifact dirs are present 2025-12-16 15:45:01 -05:00
__init__.py Initial commit. 2014-03-12 20:25:19 -07:00
__main__.py drop python 3.6 support 2022-01-18 18:44:20 -05:00
all_languages.py rename system and script languages to unsupported / unsupported_script 2025-11-08 15:09:16 -05:00
clientlib.py add pass_filenames_via_stdin for large changesets 2026-02-18 18:06:34 -08:00
color.py drop python 3.6 support 2022-01-18 18:44:20 -05:00
constants.py make --hook-type and stages match 2023-03-11 14:26:14 -05:00
envcontext.py [pre-commit.ci] auto fixes from pre-commit.com hooks 2024-07-29 21:59:19 +00:00
error_handler.py [pre-commit.ci] auto fixes from pre-commit.com hooks 2024-07-29 21:59:19 +00:00
errors.py drop python 3.6 support 2022-01-18 18:44:20 -05:00
file_lock.py py310+ 2025-10-09 17:44:05 -04:00
git.py fix deprecated call 2025-10-16 10:23:30 -04:00
hook.py add pass_filenames_via_stdin for large changesets 2026-02-18 18:06:34 -08:00
lang_base.py add pass_filenames_via_stdin for large changesets 2026-02-18 18:06:34 -08:00
logging_handler.py [pre-commit.ci] auto fixes from pre-commit.com hooks 2024-07-29 21:59:19 +00:00
main.py add pre-commit hazmat 2025-11-22 13:53:53 -05:00
output.py drop python 3.6 support 2022-01-18 18:44:20 -05:00
parse_shebang.py python3.9+ 2023-10-28 14:20:37 -04:00
prefix.py drop python 3.6 support 2022-01-18 18:44:20 -05:00
repository.py remove deprecated python_venv alias 2024-10-05 13:30:25 -04:00
staged_files_only.py [pre-commit.ci] auto fixes from pre-commit.com hooks 2024-07-29 21:59:19 +00:00
store.py move logic for gc back to commands.gc 2025-11-19 14:32:09 -05:00
util.py add pass_filenames_via_stdin for large changesets 2026-02-18 18:06:34 -08:00
xargs.py add pass_filenames_via_stdin for large changesets 2026-02-18 18:06:34 -08:00
yaml.py change migrate-config to use yaml parse tree instead 2024-09-16 20:16:16 -04:00
yaml_rewrite.py change migrate-config to use yaml parse tree instead 2024-09-16 20:16:16 -04:00