Fix line-ending problems that show every file as modified
git status says every file changed but I didn't touch them — how do I fix line endings?
If you’re seeing this error
warning: LF will be replaced by CRLF in <file>.warning: CRLF will be replaced by LF in <file>.You’re in the right place — the fix is below.
Short answer
Windows writes CRLF and Unix writes LF, and without a policy Git records whichever your editor produced. Commit a .gitattributes with `* text=auto`, then renormalise the repository once — this fixes it for everyone, unlike the per-machine core.autocrlf setting.
printf "* text=auto\n" > .gitattributes
git add --renormalize .
git commit -m "Normalise line endings"
Set a repo-wide policy and renormalise every tracked file
Does this match your situation?
- git status shows files as modified with no visible change.
- git diff shows every single line as changed.
- 'warning: LF will be replaced by CRLF' on every add.
- Shell scripts fail with 'bad interpreter' or '\r: command not found'.
Step-by-step fix
Confirm line endings are the cause
If the diff disappears when whitespace is ignored, the change is invisible characters rather than real edits.
step 1git diff | cat -A | head -20 # ^M at line ends means CRLF git diff --ignore-all-space # empty? then it is purely line endingsShow the PowerShell (Windows) version
PowerShell (Windows)git diff --ignore-all-space git config core.autocrlfAdd a .gitattributes policy
Because .gitattributes is committed, it applies identically for everyone who clones — which is exactly why it beats core.autocrlf, a per-machine setting that different teammates inevitably have set differently.
step 2# .gitattributes * text=auto *.sh text eol=lf *.bash text eol=lf *.bat text eol=crlf *.cmd text eol=crlf *.ps1 text eol=crlf *.png binary *.jpg binary *.fbx binary *.wav binarytext=auto stores LF in the repository and checks out whatever is native to each machine. eol= pins files that must have a specific ending regardless of platform.
Renormalise everything already committed
The new rules only affect future writes until you rewrite the existing entries. This produces one large commit that touches many files and is best done when nobody has work in flight.
step 3git add .gitattributes git commit -m "Add line-ending policy" git add --renormalize . git status git commit -m "Renormalise line endings across the repository"Set a sensible local default too
A belt-and-braces default for repositories that have no .gitattributes of their own.
step 4# Windows git config --global core.autocrlf true # macOS / Linux git config --global core.autocrlf inputNever use core.autocrlf true on macOS or Linux - it writes CRLF into files that should have LF.
Refresh your working copy
After renormalising, re-check out the tree so every file on disk matches the new policy.
step 5git rm --cached -r . git reset --hard
Why this works
Git stores file contents byte for byte, so a carriage return is as much a change as a letter. Windows tools write CRLF and Unix tools write LF, which means the same logical edit produces different bytes on different machines and Git honestly reports every line as changed. `text=auto` resolves this by normalising to LF inside the repository and converting on checkout, so the stored form is consistent no matter who committed it. Putting the rule in .gitattributes rather than local config is what makes it a team-wide guarantee instead of a per-machine hope.
How to stop it happening again
- Add .gitattributes with `* text=auto` to every new repository on day one.
- Pin shell scripts to eol=lf and Windows batch files to eol=crlf.
- Configure your editor to respect .editorconfig alongside it.
Commands used in this guide
.gitattributesPer-path rules for line endings, diffing, merging and export.
git configRead and write Git settings for one repo, your user, or the whole machine.
git addStage changes so they go into your next commit.
git diffShow exactly what changed - between your files, the index, commits or branches.
git check-attrShow which .gitattributes rules apply to a file — text, eol, diff, filter and merge.
Still stuck?
Search the full command reference and every other rescue guide — there are 76 of them, covering everything from detached HEAD to force-push disasters.
Browse all guides →Frequently asked questions
Why does Git show every file as modified after I clone on Windows?
Your files were committed with LF endings and your setup is writing CRLF (or vice versa), so every line differs at the byte level. A .gitattributes with `* text=auto` plus a one-off git add --renormalize . fixes it permanently for the whole team.
Should I use core.autocrlf or .gitattributes?
.gitattributes. It's committed, so every contributor gets identical behaviour automatically. core.autocrlf is a per-machine setting, which means one teammate with a different value reintroduces the churn.
What does 'warning: LF will be replaced by CRLF' mean?
Git is telling you it will convert line endings when writing the file to your working directory, because core.autocrlf is true. It's informational, not an error - and it disappears once a .gitattributes policy makes the behaviour explicit.
Related rescue guides
I renamed a file's case and Git won't notice — how do I fix it?
Windows and macOS filesystems treat Player.cs and player.cs as the same file, so a case-only rename is invisible to Git. Use git mv -f to force it, or rename via a temporary name, then commit — otherwise the wrong case ships to your Linux CI and the build breaks.
Read the fix →Always fixableGit says files changed but only the mode differs — how do I ignore that?
Git tracks the executable bit, so a file going from 100644 to 100755 counts as a change. Set core.fileMode false to ignore mode differences, or fix the bit properly with git update-index --chmod when it genuinely matters.
Read the fix →Always fixablegit clone fails on Windows with 'Filename too long' — how do I fix it?
Windows caps paths at 260 characters unless both Git and Windows are told otherwise. Run git config --system core.longpaths true in an administrator terminal, and enable LongPathsEnabled in the registry. Then re-run git checkout in the half-cloned folder — the objects are already downloaded, only the file writing failed.
Read the fix →Always fixableMy pre-commit hook (or Husky) isn't running — why does Git ignore it?
Nine times out of ten the hook file is not executable, is misnamed, or sits in a folder Git isn't reading. Run git config core.hooksPath to see where Git actually looks, check the file is named exactly pre-commit with no extension, then chmod +x it. A stray global core.hooksPath silently overrides every repository on the machine — including Husky's.
Read the fix →