Make 'git diff' ignore M
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When git diff shows ^M at the end of every line, it means the file contains CRLF (Windows-style) line endings and Git is treating the carriage return (\r) as meaningful content. The quick fix is git diff --ignore-cr-at-eol. The permanent fix is to normalize line endings across the repository using .gitattributes, so the problem does not recur.
^M is Git's way of displaying the \r character, which is the carriage return half of a Windows \r\n line ending. On Unix-like systems where LF (\n) is the standard, Git marks every line with a trailing \r as changed, even when the visible text is identical. This creates noisy diffs that obscure real code changes.
Quick Fix: --ignore-cr-at-eol
For an immediate, one-off clean diff, pass the flag directly:
This tells Git to strip trailing carriage returns when comparing lines. Any line that differs only by a trailing \r will not appear in the output.
This works with all diff-related commands:
This is a review aid, not a fix. The underlying line ending inconsistency still exists in the repository.
Making the Flag Permanent via Git Config
If you want --ignore-cr-at-eol applied to every diff automatically, set it in your Git configuration:
The cr-at-eol whitespace setting tells Git that carriage returns at the end of a line are not errors. This affects git diff, git apply, and related commands.
Alternatively, you can use a diff-specific pager configuration to always strip ^M from display. But modifying core.whitespace is the cleaner approach.
The Real Fix: .gitattributes
The flag and config changes above hide the symptom. To fix the root cause, define a line ending policy in .gitattributes at the repository root:
The text=auto directive tells Git to detect text files automatically and normalize their line endings to LF in the repository. On checkout, Git converts to the platform's native line ending (CRLF on Windows, LF on Mac/Linux) unless overridden by a specific eol= directive.
Applying .gitattributes to Existing Files
After creating or updating .gitattributes, renormalize the repository to apply the rules to all tracked files:
The --renormalize flag re-applies the .gitattributes rules to all tracked files, converting their stored line endings to match the policy. This creates a single commit that fixes all line endings at once.
After this commit, future git diff output will be free of ^M noise because all files in the repository use consistent line endings.
Understanding core.autocrlf
The core.autocrlf Git config setting controls how line endings are converted between the repository and the working tree:
| Value | Checkout behavior | Commit behavior | Best for |
true | Converts LF to CRLF | Converts CRLF to LF | Windows developers |
input | No conversion (keeps LF) | Converts CRLF to LF | Mac/Linux developers |
false | No conversion | No conversion | Teams relying entirely on .gitattributes |
Setting core.autocrlf on each developer's machine:
The important nuance: .gitattributes is versioned and shared with the team. core.autocrlf is a local setting that varies per machine. For the strongest guarantee, use .gitattributes as the authoritative policy and treat core.autocrlf as a safety net.
Diagnosing Whether the Diff Is Only Line Endings
Before committing a normalization change, verify that the diff is purely line endings and not mixed with content changes:
You can also inspect individual files:
On Mac/Linux, file and cat -A are the fastest way to confirm what line endings a file actually contains.
Handling Mixed Line Endings in a Single File
Sometimes a file contains both CRLF and LF line endings (mixed line endings). This happens when multiple editors touched the file without consistent settings. git diff shows ^M on some lines but not others.
To normalize a single file:
On Mac, sed -i '' is the syntax for in-place editing (the empty string is required by BSD sed). On Linux, sed -i works without the empty string.
When Line Endings Are Operationally Important
In some cases, line endings are not just a formatting concern. They affect behavior:
- Shell scripts: A
#!/bin/bashscript with CRLF line endings fails to execute on Linux/Mac with a confusing/bin/bash^M: bad interpretererror. - Dockerfiles: CRLF in a Dockerfile can cause
RUNcommands to fail withnot founderrors because the command includes a trailing\r. - Makefiles: GNU Make is sensitive to line endings. CRLF can cause cryptic parse errors.
.gitattributesitself: If this file has CRLF line endings, Git may not parse it correctly on all platforms.
For these files, use explicit eol=lf directives in .gitattributes to enforce LF regardless of platform.
Other Whitespace Diff Flags
Git provides several whitespace-related diff flags. Use the narrowest one that matches your problem:
| Flag | What it ignores |
--ignore-cr-at-eol | Carriage returns at end of line only |
-w / --ignore-all-space | All whitespace differences |
-b / --ignore-space-change | Changes in the amount of whitespace |
--ignore-blank-lines | Additions/deletions of blank lines |
Using -w when you only need --ignore-cr-at-eol hides real whitespace changes (indentation fixes, trailing spaces) alongside the ^M noise. Be precise.
Common Pitfalls
- Using
--ignore-cr-at-eolpermanently without fixing the underlying line ending policy. This hides the symptom in your diffs but leaves the inconsistency in the repository for every other tool (editors, CI scripts, deployment) to deal with. - Relying on
core.autocrlfwithout a.gitattributesfile.core.autocrlfis a local setting. Every new developer or CI runner that does not set it correctly reintroduces the problem. - Renormalizing the repository without warning the team. A normalization commit touches many files and can cause merge conflicts for everyone with outstanding branches. Coordinate the timing.
- Ignoring all whitespace (
-w) when the goal is only to hide\r. This suppresses real indentation and spacing changes, which can hide bugs or style violations. - Forgetting to set
eol=lffor shell scripts, Dockerfiles, and Makefiles. These files break with CRLF endings on Unix systems, andtext=autoalone does not always enforce LF on Windows checkouts.
Summary
^Mingit diffmeans the file has CRLF line endings where Git expects LF.- For a quick readable diff, use
git diff --ignore-cr-at-eol. - For a permanent fix, create a
.gitattributesfile with* text=autoand expliciteol=rules for platform-sensitive files, then rungit add --renormalize .to apply. - Set
core.autocrlfconsistently across the team (trueon Windows,inputon Mac/Linux) as a safety net alongside.gitattributes. - Use the narrowest whitespace flag that matches the problem.
--ignore-cr-at-eolis almost always what you want, not-w.

