feat: pin line endings so a checkout produces the same bytes on every platform - #5
Merged
Merged
Conversation
Links spec 002 to issue #4 and moves it out of the open backlog. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The repository pinned line endings nowhere, so the bytes of every text file
depended on the Git configuration of whoever checked it out. On a default
Windows install (core.autocrlf=true) all text files arrive with CRLF.
This affects the parent directly, not only its children: with packaging=pom
and no flatten-maven-plugin, pom.xml is deployed to Maven Central verbatim,
so a CRLF checkout would publish different .pom bytes.
- .gitattributes: `* text=auto eol=lf` baseline, so LF is forced in the
working tree regardless of core.autocrlf. `*.bat`/`*.cmd` are the single
exception (cmd.exe is fragile with LF-only scripts); explicit binary
markers remove the dependency on Git's content heuristic for future
additions.
- .editorconfig: the Open Elements standard, with [*.java] corrected to
Google Java Format (2 spaces, 100 columns). The shared baseline specifies
4/120, which would make the editor fight the formatter this parent
enforces. A [*.{cmd,bat}] block matches the CRLF pin.
- pom.xml: Spotless `<lineEndings>UNIX</lineEndings>`, inherited by every
child, so spotless:apply cannot write CRLF on a Windows machine.
- README: what is pinned, why the published .pom is at stake, and a
copy-paste block for child projects, which Maven inheritance cannot
deliver for them.
Verified: no tracked file carries CRLF in the index, `git add --renormalize .`
stages nothing, and checking files out with core.autocrlf=true or
core.eol=crlf forced still yields LF for text and CRLF for *.cmd.
Cross-OS reproducibility is not claimed; it stays in docs/TODO.md.
Closes #4
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Spec review found the README offered child projects only the .gitattributes block, although the design corrected .editorconfig's [*.java] precisely so that children copying it would stop fighting the formatter. The child section now points at both files and says why. Also corrects steps.md, which listed a "Related behaviors" entry that does not exist in behaviors.md, and replaces its coverage table with what implementation actually measured: 16 of 23 scenarios verified by executed commands, 2 by inspection, 5 needing a child project or a real Windows machine. Quality review: clarifies that the keystore entries in .gitattributes say how Git must treat such a file if it appears, not that one belongs in the repository. The absent CLAUDE.md is recorded in docs/TODO.md rather than generated here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Summary
The repository pinned line endings nowhere, so the bytes of every text file depended
on the Git configuration of whoever checked it out. On a default Windows install
(
core.autocrlf=true) every text file arrives with CRLF. This affects the parentdirectly and not only its children: with
packaging=pomand noflatten-maven-plugin,pom.xmlis deployed to Maven Central verbatim, so a CRLFcheckout would publish different
.pombytes.Spec
docs/specs/002-pinned-line-endings/docs/specs/002-pinned-line-endings/design.mddocs/specs/002-pinned-line-endings/behaviors.mddocs/specs/002-pinned-line-endings/steps.mdChanges
.gitattributes—* text=auto eol=lfbaseline, so LF is forced in the workingtree regardless of the developer's
core.autocrlf. A baretext=autowould not dothis: it normalizes only the index and leaves checkout to local configuration.
*.bat/*.cmdare the single exception, becausecmd.exeis fragile with LF-onlyscripts. Explicit
binarymarkers remove the dependency on Git's content heuristicfor file types added later.
.editorconfig— the Open Elements standard, with[*.java]corrected toGoogle Java Format (2 spaces, 100 columns, continuation 4). The shared baseline
specifies 4 spaces and 120 columns, which contradicts the formatter this parent
enforces via Spotless — an editor following it would fight
spotless:applyon everysave. A
[*.{cmd,bat}]block matches the CRLF pin.pom.xml—<lineEndings>UNIX</lineEndings>on Spotless. The plugin defaults toGIT_ATTRIBUTES, so in a child repository without its own.gitattributesitactively writes CRLF on Windows. This is the only part of the change Maven
inheritance can deliver to children.
README.md— what is pinned and why the published.pomis at stake, acopy-paste block for child projects, and an explicit statement of how narrow the
inherited Spotless setting is.
Verification
No test framework exists here — this is a
packaging=pomproject with no Javasources — so the scenarios were verified with Git and Maven commands:
git add --renormalize .stages nothing, so the change contributes no incidental byte churn.
core.autocrlf=true,core.autocrlf=falseandcore.eol=crlfforced all yield LF for text files and CRLF for*.cmd— theattribute beats local configuration, which is the behaviour the whole design rests on.
.java,.cmd,.mdand.tomlall land as
i/lf; a file without line endings stays untouched; an explicitly marked.p12is stored byte-identical to disk../mvnw -Pfull-build clean verifyand./mvnw spotless:checkpass.16 of 23 scenarios measured, 2 verified by inspection, 5 not verifiable here —
they need a child project or a real Windows machine. Both gaps are recorded in
docs/TODO.md.Scope boundaries
Cross-OS reproducibility is not claimed. Line endings are one variance source
among several; JDK-dependent Javadoc output, archive entry ordering and locale
defaults are untouched. There is no CI guard, by decision.
Note for the reviewer
This branch and
feat/001-reproducible-build-timestampboth add a README sectionand will conflict there on the second merge. The conflict is additive — both sections
are kept.
Closes #4
🤖 Generated with Claude Code