Why does my diff show every line changed
Tools Nimbus is a free, no-signup developer toolkit that runs entirely in your browser, so your data is never uploaded to a server. A diff that marks every line as changed almost always means invisible bytes changed, not content: CRLF versus LF line endings, a re-indent from tabs to spaces, trailing whitespace stripped on save, or a new file encoding. Paste both versions into the Tools Nimbus Diff Checker to see which.
Last updated October 2026
A line diff compares bytes, not what you see
Git, GitHub, and every line-based diff tool split both files into lines and look for the longest run of lines that are byte-for-byte identical. A line counts as unchanged only if every byte matches, including the ones your editor does not draw: the carriage return before a line break, a trailing space, a tab that renders as four spaces. Change one of those on every line and the diff has no common lines left to anchor on, so it reports the whole file as removed and re-added, even when the text reads exactly the same.
That makes the problem mechanical to debug. You are not looking for a bug in the diff tool; you are looking for the one invisible thing that changed on every line at once. In practice there are only a handful of candidates, and each leaves a recognizable fingerprint.
Symptom, cause, and fix at a glance
| What you see | Most likely cause | Confirm with | Fix |
|---|---|---|---|
Every line changed, ^M at line ends | CRLF vs LF line endings | git diff --ignore-cr-at-eol collapses the diff | Add .gitattributes, then git add --renormalize . |
| Every indented line changed, others untouched | Tabs converted to spaces, or indent width changed | git diff -w collapses the diff | Commit the re-indent on its own; set an editorconfig |
| Scattered lines changed with no visible edit | Trailing whitespace stripped on save | git diff --ignore-space-at-eol | Separate the cleanup commit, or turn off the editor setting |
| Only line 1 changed, or Git says "Binary files differ" | Byte-order mark added, or UTF-16 vs UTF-8 encoding | file name.txt reports the encoding | Re-save as UTF-8 without BOM |
old mode 100644 / new mode 100755, no line changes | Executable bit flipped, not content | The diff header itself | git update-index --chmod=-x or restore the mode |
| The whole file is one changed line | Minified JSON or a single-line file | Line count is 1 on both sides | Pretty-print both versions, then diff |
| Every line of a paragraph changed | Prose was re-wrapped to a new line width | git diff --word-diff | Diff by word, or write one sentence per line |
Cause 1: CRLF versus LF line endings (the usual culprit)
Windows editors traditionally end each line with two bytes, a carriage return and a line feed (\r\n, CRLF). macOS and Linux use a bare line feed (\n, LF). If a file was committed with LF and someone saves it on Windows with CRLF, every single line gains one byte, and the diff marks all of them. Git usually prints the stray carriage return as ^M at the end of each added line, which is the giveaway.
To confirm, run git diff --ignore-cr-at-eol (Git 2.16 and later). If the diff shrinks to the edit you actually made, you have your answer. git ls-files --eol goes further and shows, per file, the line endings stored in the index (i/lf) next to the ones in your working copy (w/crlf).
The durable fix is a .gitattributesfile at the repository root, so the rule travels with the repo instead of depending on each person's core.autocrlf setting:
* text=auto
*.sh text eol=lf
*.bat text eol=crlfThen run git add --renormalize .and commit the result as a standalone "normalize line endings" commit. From then on Git stores LF in the repository and converts on checkout where a file type needs it. Line endings also quietly change hashes, which is why the same file can produce two checksums on two machines; see why a SHA-256 hash is different for that side of the problem.
Cause 2: tabs, spaces, and re-indentation
If every indented line changed but blank lines and top-level lines did not, the indentation changed. An editor converted tabs to spaces, a formatter such as Prettier or Black ran for the first time, or the indent width went from four spaces to two. The text is identical once you strip leading whitespace, which is exactly what git diff -w (ignore all whitespace) does. Use -b instead if you only want to ignore changes in the amount of whitespace while still seeing whitespace that was added where there was none.
Formatting changes are legitimate, but they bury real edits. Put them in their own commit, and add the commit hash to a .git-blame-ignore-revs file so git blame skips it. An .editorconfigfile stops the next contributor's editor from re-indenting the file again.
Cause 3: trailing whitespace stripped on save
Many editors remove spaces at the end of lines when you save. In a file that had a lot of trailing whitespace, that shows up as dozens of scattered changed lines that look untouched. Run git diff --ignore-space-at-eolto hide them. The same setting is the reason a file that ends without a final newline suddenly gains one: the last line shows as changed, often with Git's "\ No newline at end of file" marker on the old side.
Cause 4: encoding and byte-order marks
A UTF-8 byte-order mark is three invisible bytes (EF BB BF) at the very start of a file. Adding or removing one changes only the first line, which is a useful tell when a diff flags line 1 and nothing else. A full encoding change is louder: a file re-saved from UTF-16 to UTF-8 has different bytes for every character, and Git often treats UTF-16 as binary and prints only "Binary files differ". Run file name.txt on macOS or Linux to see the encoding and whether it has CRLF terminators. Standardize on UTF-8 without a BOM, or tell Git about a file that must stay UTF-16 with the working-tree-encoding attribute.
Cause 5: the file is one long line
A line diff cannot show you a small change inside one huge line. Minified JSON, a compressed CSS bundle, or a lockfile written on one line will always show as "the whole file changed" because the whole file is one line. Pretty-print both versions first with the JSON Formatter (sort or keep keys the same on both sides), then compare the formatted output. The same logic applies to prose: if a paragraph was re-wrapped to a new width, every line shifts. git diff --word-diff compares by word instead of by line and shows only the words that actually changed.
Find the cause in one paste
Open the Diff Checker and paste the old version on the left and the new one on the right. Then read the result as a decision tree:
- Zero changes, while Git insists every line changed: the difference is line endings. Browsers normalize CRLF to LF in any text box you paste into, so a pure line-ending change vanishes here, which is itself the diagnosis.
- Many changes that disappear when you tick Ignore whitespace: the difference is indentation or trailing whitespace (causes 2 and 3).
- Only the first line changed: suspect a byte-order mark (cause 4).
- Changes remain with whitespace ignored: the content really did change, or a long line or re-wrap is hiding a small edit (cause 5).
The comparison runs entirely in your browser, so source code and config files never leave your device. It compares up to 1,500 lines per side, which covers most single files you would review by hand. If you are choosing a diff tool more generally, the honest comparison with Diffchecker covers what each one does better.
How to keep it from happening again
- Commit a
.gitattributeswith* text=autoso line endings no longer depend on each machine's settings. - Commit an
.editorconfigthat pins indent style, indent size, final newline, and trailing-whitespace behaviour. - Run formatters in a dedicated commit, and list that commit in
.git-blame-ignore-revs. - Review with whitespace hidden (
git diff -w, or Hide whitespace on GitHub), but fix the cause rather than relying on the flag, because the bytes in the commit are still different.
More troubleshooting guides live in the guides index.