agent's codemod didnt handle CRLF line endings - every file shows as changed in the diff
How to fix a codemod that did not handle CRLF line endings, leaving every file showing as changed: reverting the line-ending churn, normalizing endings in the transform, and re-running cleanly. Use when a codemod diff is all line endings and no substance. Not for real content changes mixed with line-ending noise.
TL;DR
The codemod wrote LF endings into CRLF files (or vice versa), so every line diffs even though nothing changed semantically. Revert the churn, make the transform preserve or normalize line endings deliberately (and set .gitattributes so the repo is explicit), then re-run: the new diff should show only real changes.
The query
agent's codemod didnt handle CRLF line endings - every file shows as changed in the diffUse this when
- Codemod diff shows every file changed but nothing real changed
- CRLF vs LF churn from a codemod
- Need the transform to preserve line endings
- An agent's codemod rewrote line endings repo-wide
Not for
- Real content changes mixed with line-ending noise (normalize first, then review the real diff)
- Line-ending churn from editors or git settings (a repo config problem, not the codemod)
- A codemod that intentionally normalizes endings (review it as a deliberate change)
Steps
1. Confirm the diff is only line endings
git diff --stat | tail -3
git diff --ignore-cr-at-eol --stat | tail -3Expected output: the first stat shows massive churn, the second (ignoring carriage returns) shows little or nothing. That gap is the line-ending damage, quantified.
2. Revert the churn
git checkout -- [affected paths]Expected output: the working tree is clean again. Do not try to "fix" the churned files in place: revert and re-run correctly.
3. Make the repo explicit about line endings
Add or fix .gitattributes so text files declare their endings (e.g. * text=auto, or explicit eol=crlf for the files that need it). Normalize the repo once with git add --renormalize.
Expected output: git's own handling is deterministic, so the codemod's output and the repo agree on what an ending is.
4. Fix the transform to preserve endings
Read files in binary or universal-newline mode and write back the original ending style per file (or normalize deliberately to the repo standard in the same run, as a separate reviewed change). Test on a mixed sample: CRLF files must come back CRLF, LF files LF.
Expected output: a test run over mixed endings produces zero ending-only diffs.
5. Re-run and verify the diff is substantive
Run the fixed codemod and check git diff --ignore-cr-at-eol --stat versus plain --stat: they should now agree.
Expected output: the diff contains only the transform's real changes.
Tool compatibility
Tool-agnostic: any codemod (jscodeshift, ast-grep, libcst, scripts) that reads and writes files byte-wise can do this.
Variant phrasings
codemod changed line endings every file shows as changed
Steps 1 and 2: confirm with --ignore-cr-at-eol, revert.
codemod CRLF handling
Step 4: preserve per-file endings in the transform; test on a mixed sample.
gitattributes line endings codemod
Step 3: declare endings in .gitattributes so the repo and the tool agree.
Why it happens
Most codemod tools read text with universal newlines (normalizing to LF internally) and write back LF, silently converting CRLF files. Git then sees every line as changed because the bytes differ. The tool did not change your code; it changed your line endings, and the diff cannot tell the difference without --ignore-cr-at-eol.
Edge cases
- Mixed-ending files (some lines CRLF, some LF) are the worst case: decide on one ending per file during normalization, or the churn recurs.
- A codemod that intentionally normalizes endings should do it as its own commit, separate from the transform: mixed diffs are unreviewable.
- EditorConfig and .gitattributes can fight: pick one source of truth for endings and remove the other's eol settings.
Provenance
Resolved from the public thread: https://vectle.com/posts/pstK4gghGzoA9Kv88VG6AJhw