Skip to content

fix: force LF on *.txt so generated llms.txt stays clean on Windows#2289

Open
Olamiaca wants to merge 1 commit into
garrytan:mainfrom
Olamiaca:fix/gitattributes-txt-eol-lf
Open

fix: force LF on *.txt so generated llms.txt stays clean on Windows#2289
Olamiaca wants to merge 1 commit into
garrytan:mainfrom
Olamiaca:fix/gitattributes-txt-eol-lf

Conversation

@Olamiaca

@Olamiaca Olamiaca commented Jul 17, 2026

Copy link
Copy Markdown

Symptom

On Windows, git status in a gstack install permanently reports M gstack/llms.txt. Because /gstack-upgrade runs git stash before git reset --hard origin/main, every upgrade silently stashes this phantom change, accruing empty stashes and printing warning: in the working copy of 'gstack/llms.txt', LF will be replaced by CRLF the next time Git touches it.

Cause

.gitattributes already pins text eol=lf for every other generated/parsed text type — *.md, *.tmpl, *.yml, *.json, *.toml, *.ts, *.sh, setup, bin/* — and its own header comment says why:

Without this, Windows checkouts with core.autocrlf=true convert these to CRLF and break tests...

But there is no *.txt rule. gstack/llms.txt is regenerated as LF by ./setup's gen-llms-txt on every run, while the Git for Windows installer sets core.autocrlf=true at the system level (C:/Program Files/Git/etc/gitconfig). So the file falls through to the CRLF expectation and is flagged dirty forever.

Evidence

Both the committed blob and the worktree copy are pure LF (zero CR bytes), and git diff is empty — the file is phantom-modified, not content-modified:

$ git show HEAD:gstack/llms.txt | grep -c $'\r'   # 0
$ grep -c $'\r' gstack/llms.txt                   # 0
$ git diff gstack/llms.txt                        # (empty)
$ git status --porcelain                          #  M gstack/llms.txt

Only llms.txt trips it because ./setup rewrites the file each run, resetting its mtime and forcing git to re-evaluate it. Other .txt files keep a matching stat cache and are never re-examined.

Scope

*.txt matches exactly two tracked files:

  • gstack/llms.txt — the target.
  • make-pdf/test/fixtures/combined-gate.expected.txt — already pure LF and clean, so unaffected. LF is also correct here: it is compared against generated output, and a CRLF fixture vs LF output would fail.

No CI impact: on Linux runners autocrlf is off and files are already LF, so text eol=lf is a no-op there.

Verification

With the rule in place, git check-attr text eol -- gstack/llms.txt reports text: set / eol: lf, and rewriting the file with identical LF content (what ./setup does) leaves the worktree clean instead of dirty.

Deliberately omitted

No VERSION bump and no CHANGELOG entry — those belong to the maintainer's /ship release flow rather than a contributor's one-line fix.

@trunk-io

trunk-io Bot commented Jul 17, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

.gitattributes pins eol=lf for every other generated/parsed text type
(*.md, *.json, *.ts, setup, bin/*) but omits *.txt. gstack/llms.txt is
regenerated as LF by ./setup's gen-llms-txt on every run, while Git for
Windows sets core.autocrlf=true at the system level. The file is therefore
reported modified forever, and /gstack-upgrade's `git stash` silently
stashes it on every upgrade.

Blob and worktree are both pure LF and `git diff` is empty, so the file is
phantom-modified rather than content-modified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Olamiaca
Olamiaca force-pushed the fix/gitattributes-txt-eol-lf branch from 7cdc6e7 to 3004811 Compare July 17, 2026 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant