fix(update): repair managed checkouts still running core.autocrlf=true - #74487
Merged
Conversation
Git for Windows ships core.autocrlf=true in its system config, which renormalizes this repo's LF text files to CRLF in the working tree. install.ps1 pins core.autocrlf=false on the managed clone for that reason (#67730), but a checkout created before that landed never got the pin -- and cannot get it, because hermes-setup.exe resolves install.ps1 by an immutable build-time commit pin and reuses the cached script forever. A Windows install from May 2026 still runs the May install.ps1 no matter how many times it updates. `hermes update` ships with the checkout itself, so it is the only path left that reaches those installs. The pin and the cleanup have to be one operation. Under autocrlf=true git compares normalized content, so a CRLF working tree reads clean; pinning alone would expose every tracked text file as modified and hand the very next update an autostash and pop of the whole tree -- strictly worse than the state it set out to fix. So the tree is evaluated as it would look pinned (git -c, nothing persisted), the files whose only difference is the line ending are restored, and the pin is written only once that is verified clean. A checkout we cannot fully normalize is left exactly as it was found. Files still dirty under --ignore-cr-at-eol are never touched, so a real edit survives even when it also got renormalized. The restore takes its pathspec over stdin because a fully renormalized checkout is thousands of paths, well past the Windows command-line limit.
Contributor
૮ >ﻌ< ა ci reviewran on e65ff96 ℹ️ InfoDesktop E2E visual evidence · View test artifacts · View job1 visual diff. inline evidence upload failed. Failed to upload diff-665a0833239e-onboarding-overlay-diff.png with gh image (exit code 1): Error uploading /home/runner/work/_temp/e2e-evidence/diff-665a0833239e-onboarding-overlay-diff.png: step 0 (get upload token): uploadToken not found on repo page — do you have write access to NousResearch/hermes-agent? (or, if NousResearch enforces SAML SSO, authorize at https://github.com/orgs/NousResearch/sso) |
This was referenced Jul 31, 2026
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…-churn fix(update): repair managed checkouts still running core.autocrlf=true
33hodl
pushed a commit
to 33hodl/hermes-agent
that referenced
this pull request
Aug 12, 2026
…-churn fix(update): repair managed checkouts still running core.autocrlf=true
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A Windows install from May 2026 still runs the May
install.ps1no matter how many times it updates. That means thecore.autocrlf=falsepin added in #67730 never reaches the installs that need it most, and those checkouts keep every tracked text file rewritten to CRLF in the working tree.hermes updateships with the checkout itself, so it is the only path left that can repair them.Why the existing fix can't get there
install.ps1pinscore.autocrlf=falseon the managed clone in all three paths — in-place update, ZIP-init, and the shared post-clone block. That landed 19 Jul 2026. It is correct, and it is unreachable for anyone who installed earlier:hermes-setup.exebakesBUILD_PIN_COMMITinto the binary and resolvesinstall.ps1from it. A commit pin is treated as immutable, socache_planreturnsReuseand the installer executes its cached script forever:From a real user's
bootstrap-installer.log, three separate runs today:That script is dated 31 May and contains no
autocrlfhandling at all. Their.git/confighas no pin, so the portable Git's system config wins:Result: 6,382 tracked files reading as modified against
origin/mainwith insertions matching deletions almost exactly, and a real diff of two regenerable artifacts once--ignore-cr-at-eolis applied.Why the pin and the cleanup are one operation
This is the part that makes a naive version of this fix a regression rather than a fix.
Under
autocrlf=truegit compares normalized content, so a CRLF working tree reads clean. Pinningautocrlf=falseon its own does not repair anything — it reveals thousands of files as modified, and the very nexthermes updateautostashes and pops the entire tree. Strictly worse than the state it set out to fix.So
_normalize_managed_eoldoes both, in an order that cannot half-apply:git -c core.autocrlf=false— nothing persisted yet.--ignore-cr-at-eol.A checkout that cannot be fully normalized — a git too old for
--pathspec-from-file, an unwritable tree, a file locked by a running process — is left exactly as it was found. There is no rollback path because nothing is committed until it is known to be safe.Two details worth calling out: files still dirty under
--ignore-cr-at-eolare never touched, so a real edit survives even when it also got renormalized; and the restore takes its pathspec over stdin, because a fully renormalized checkout is thousands of paths, well past the Windows command-line limit.It sits next to
_discard_lockfile_churnat the same point in_cmd_update_impl, before any stash or branch logic, on the same reasoning: machine-generated dirt on a managed checkout should be cleared, not autostashed.Verification
9 tests in
tests/hermes_cli/test_update_eol_churn.py, driving real git repos in the broken state — LF index, CRLF worktree written by git's own checkout so the stat cache reproduces the churn-reads-clean condition,autocrlf=truestill set.Covered: churn invisible under
autocrlf=trueis still found and cleared; the pin is persisted; a real edit that also got renormalized survives; the pin is withheld when the restore cannot finish;autocrlf=inputand already-pinned checkouts are left alone; 1,200 files normalize in one pass.Mutation-checked, each caught by the intended test:
test_pin_is_withheld_when_the_churn_cannot_be_clearedcheckout -- .test_real_edits_survive_even_when_line_endings_also_flippedtest_churn_invisible_under_autocrlf_true_is_still_found+ 4 others288 tests pass across
tests/hermes_cli/ -k 'update or install'.The failure the restore-shim stands in for is exercised through a git wrapper that fails only on
checkout, rather than a brokengit_cmd. A brokengit_cmdwould fail the firstconfig --getand return early, passing the test without ever reaching the guard.