Skip to content

chore: check out all text files with LF via .gitattributes - #4

Merged
cataggar merged 1 commit into
kfrom
chore/normalize-line-endings-to-lf
Aug 16, 2026
Merged

cataggar merged 1 commit into
kfrom
chore/normalize-line-endings-to-lf

Conversation

@cataggar

Copy link
Copy Markdown
Owner

Why

brush is a shell, and its test corpus is shell scripts. Shell is newline-sensitive in ways most languages are not — a stray CR becomes part of a here-document delimiter, a command name, or a #! interpreter path. So on this repo the line ending is a correctness concern, not a formatting preference.

The repository had no .gitattributes at all, leaving the checkout representation entirely to each contributor's local git config. On a Windows checkout with core.autocrlf=true, every text file lands as CRLF and tests fail for reasons that have nothing to do with brush:

/usr/bin/env: 'bash\r': Permission denied
process-helpers.sh: line 1: syntax error near unexpected token `$'{\r''

What

Pin every text file to LF on all platforms.

text rather than text=auto is deliberate: it states the intent outright instead of deferring to git's binary heuristic, so a newly added file cannot be silently classified as binary and escape normalization. The sole real binary in the tree (docs/extras/brush-screenshot.png) is exempted with binary, shorthand for -text -diff.

No content is rewritten

This is the part worth checking before merging — the change is a single new file, not a mass rewrite:

  • git ls-files --eol reported all 674 tracked text files as already i/lf
  • git add --renormalize . staged nothing beyond .gitattributes itself
  • after re-checkout: 675 i/lf w/lf, plus the one -text PNG untouched

CRLF only ever existed in the working tree, injected at checkout. This commit makes the LF guarantee explicit and permanent rather than a property of how any one contributor is configured.

Effect on the suite

On a Windows checkout under WSL, the compat suite had 5 failures. This fixes the Basic process failure outright (its process-helpers.sh fixture was being mangled).

The remaining 4 — the Error: newline before ... in [[ ]] cases — are unrelated and pre-existing, and are not addressed here. They're a genuine semantic difference: given [[ a followed by a newline, bash reports the error at execution time and the script still exits 0, while brush rejects it at parse time and exits 2. Both correctly refuse to run it; only the exit status differs.

brush is a shell, and its test corpus is shell scripts. Shell is
newline-sensitive in ways most languages are not: a stray CR becomes part of
a here-document delimiter, a command name, or a `#!` interpreter path. On a
Windows checkout with core.autocrlf=true every text file lands as CRLF, and
several compat tests fail as a result -- not because brush is wrong, but
because the fixtures were mangled on their way to disk. Two examples of the
resulting noise:

    /usr/bin/env: 'bash\r': Permission denied
    process-helpers.sh: line 1: syntax error near unexpected token `$'{\r''

The repository had no .gitattributes at all, so the checkout representation
was left entirely to each contributor's local git configuration.

Add one that pins every text file to LF on all platforms. `text` rather than
`text=auto` states the intent outright instead of deferring to git's binary
heuristic, so a newly added file cannot be silently classified as binary and
escape normalization. The sole real binary in the tree, the docs screenshot,
is exempted with `binary` (shorthand for `-text -diff`).

No content is rewritten by this change: `git ls-files --eol` reports every one
of the 674 tracked text files as already `i/lf`, and `git add --renormalize .`
stages nothing beyond this file. CRLF only ever existed in the working tree,
injected at checkout. This commit makes that guarantee explicit and permanent
rather than a property of how any one contributor happens to be configured.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@cataggar
cataggar merged commit 16ba91d into k Aug 16, 2026
30 checks passed
@cataggar
cataggar deleted the chore/normalize-line-endings-to-lf branch August 16, 2026 20:53
cataggar added a commit that referenced this pull request Aug 22, 2026
brush is a shell, and its test corpus is shell scripts. Shell is
newline-sensitive in ways most languages are not: a stray CR becomes part of
a here-document delimiter, a command name, or a `#!` interpreter path. On a
Windows checkout with core.autocrlf=true every text file lands as CRLF, and
several compat tests fail as a result -- not because brush is wrong, but
because the fixtures were mangled on their way to disk. Two examples of the
resulting noise:

    /usr/bin/env: 'bash\r': Permission denied
    process-helpers.sh: line 1: syntax error near unexpected token `$'{\r''

The repository had no .gitattributes at all, so the checkout representation
was left entirely to each contributor's local git configuration.

Add one that pins every text file to LF on all platforms. `text` rather than
`text=auto` states the intent outright instead of deferring to git's binary
heuristic, so a newly added file cannot be silently classified as binary and
escape normalization. The sole real binary in the tree, the docs screenshot,
is exempted with `binary` (shorthand for `-text -diff`).

No content is rewritten by this change: `git ls-files --eol` reports every one
of the 674 tracked text files as already `i/lf`, and `git add --renormalize .`
stages nothing beyond this file. CRLF only ever existed in the working tree,
injected at checkout. This commit makes that guarantee explicit and permanent
rather than a property of how any one contributor happens to be configured.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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