fix(update): honor --ignore-cr-at-eol on git < 2.48 via --numstat - #75220
fix(update): honor --ignore-cr-at-eol on git < 2.48 via --numstat#75220Zeraphim wants to merge 1 commit into
Conversation
`_normalize_managed_eol` derived the line-ending-only churn set from `git diff --name-only --ignore-cr-at-eol`. On git < 2.48 `--name-only` silently drops `--ignore-cr-at-eol`, so the "real dirty" set equaled the full set, `_eol_only()` was always empty, and the `core.autocrlf=false` pin was written over uncleared CRLF churn (5 regression tests from NousResearch#74487 failed). Switch the ignore-eol probe to `--numstat`, which honors the option on every supported git version, and parse its path records. The non-ignore path is unchanged. Closes NousResearch#75175
Duplicate of #75213: both open PRs repair the same |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for identifying the --name-only --ignore-cr-at-eol failure; the premise is confirmed on current main at hermes_cli/update_cmd.py:3075-3090.
Problems
hermes_cli/update_cmd.py:3101usesrecord.split("\t"). With-z, Git outputs literal pathname characters verbatim, including tabs, so this can split one pathname into fragments. The resulting incompletereal_dirtyset feeds_eol_only()and can classify a real edit as checkout-safe, contrary to the preservation contract intests/hermes_cli/test_update_eol_churn.py:118-127.- The comment at
hermes_cli/update_cmd.py:3098-3100describes renamed records as tab-delimited. Git's documented--numstat -zrename/copy form instead has an empty path field followed by NUL-delimited preimage and postimage paths; the loop ignores those records.
Suggested changes
- Parse ordinary entries with only the first two tab splits, and parse the empty-path rename/copy form by consuming its following NUL path pair. Add tab-path and rename/copy preservation tests.
This is an automated hermes-sweeper review.
| # numstat -z records are "added\tdeleted\tpath" (renames add a | ||
| # fourth field); the path fields are everything after the two | ||
| # counts. Binary/unknown counts appear as "-". | ||
| fields = record.split("\t") |
There was a problem hiding this comment.
With -z, literal tabs in a pathname are verbatim, so splitting on every tab turns one path into fragments. Rename/copy output is also NUL-delimited after the counts, not a fourth tab field. Parse only the first two tabs for ordinary entries and consume the following NUL path pair for rename/copy entries; otherwise a real edit can enter eol_only and be checked out.
What does this PR do?
Fixes
_normalize_managed_eol(hermes_cli/update_cmd.py) so it actuallyclears CRLF churn on managed checkouts when running on git < 2.48.
git diff --name-only --ignore-cr-at-eolsilently ignores--ignore-cr-at-eolon git < 2.48 (the flag is only honored on the--numstat/--patch/--quietoutput paths). As a result the"real dirty" set equaled the full dirty set,
_eol_only()was alwaysempty, and the
core.autocrlf=falsepin was written over a still-dirtytree — the 5 regression tests from #74487 failed deterministically
(reproduced on git 2.43.0 / 2.45.2; CI passed only because it ran git 2.54).
This swaps the ignore-eol probe to
--numstat, which honors the option onevery supported git version, and parses its path records. The non-ignore
path is unchanged.
Related Issue
Fixes #75175
Type of Change
Changes Made
hermes_cli/update_cmd.py: in_normalize_managed_eol._dirty, use--numstatinstead of--name-onlywhen--ignore-cr-at-eolisrequested, and parse the path fields from each numstat record.
How to Test
Expected: 9 passed. On git < 2.48 (e.g. git 2.43/2.45) this was
5 failed / 4 passed before the fix.
Checklist
Code
fix(update): …)scripts/run_tests.sh tests/hermes_cli/test_update_eol_churn.py -qand all tests passDocumentation & Housekeeping
cli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs
Not needed — deterministic pytest fix.