git diff
ignore carriage return
^M characters
git configuration
version control tips

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:

bash
git diff --ignore-cr-at-eol

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:

bash
1# Compare branches
2git diff --ignore-cr-at-eol main..feature-branch
3
4# Compare specific file
5git diff --ignore-cr-at-eol -- path/to/file.txt
6
7# Compare staged changes
8git diff --cached --ignore-cr-at-eol
9
10# Show a specific commit's changes
11git show --ignore-cr-at-eol abc1234

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:

bash
1# Apply to the current repository only
2git config core.whitespace cr-at-eol
3
4# Apply to all repositories on this machine
5git config --global core.whitespace cr-at-eol

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:

gitattributes
1# Normalize all text files to LF in the repository
2* text=auto
3
4# Force LF for shell scripts (critical for Unix execution)
5*.sh text eol=lf
6*.bash text eol=lf
7
8# Force LF for source code
9*.py text eol=lf
10*.js text eol=lf
11*.ts text eol=lf
12*.java text eol=lf
13*.go text eol=lf
14*.rb text eol=lf
15*.rs text eol=lf
16
17# Force CRLF for Windows-specific files
18*.bat text eol=crlf
19*.cmd text eol=crlf
20*.ps1 text eol=crlf
21
22# Binary files -- no line ending conversion
23*.png binary
24*.jpg binary
25*.ico binary
26*.woff2 binary
27*.zip binary

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:

bash
1# Re-normalize all tracked files
2git add --renormalize .
3
4# Check what changed
5git status
6
7# Commit the normalization
8git commit -m "Normalize line endings via .gitattributes"

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:

ValueCheckout behaviorCommit behaviorBest for
trueConverts LF to CRLFConverts CRLF to LFWindows developers
inputNo conversion (keeps LF)Converts CRLF to LFMac/Linux developers
falseNo conversionNo conversionTeams relying entirely on .gitattributes

Setting core.autocrlf on each developer's machine:

bash
1# Windows developers
2git config --global core.autocrlf true
3
4# Mac/Linux developers
5git config --global core.autocrlf input

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:

bash
1# Step 1: diff with CR ignored
2git diff --ignore-cr-at-eol
3
4# Step 2: if this shows nothing, the diff is purely line endings
5# Step 3: if this shows changes, there are real content changes mixed in

You can also inspect individual files:

bash
1# Show the exact bytes in a file
2file path/to/file.txt
3# Output: "ASCII text, with CRLF line terminators"
4
5# Count CRLFs vs LFs
6cat -A path/to/file.txt | head -5
7# Lines ending with ^M$ have CRLF; lines ending with just $ have LF

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:

bash
1# Convert CRLF to LF using sed
2sed -i '' 's/\r$//' path/to/file.txt
3
4# Or use dos2unix if installed
5dos2unix path/to/file.txt

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/bash script with CRLF line endings fails to execute on Linux/Mac with a confusing /bin/bash^M: bad interpreter error.
  • Dockerfiles: CRLF in a Dockerfile can cause RUN commands to fail with not found errors because the command includes a trailing \r.
  • Makefiles: GNU Make is sensitive to line endings. CRLF can cause cryptic parse errors.
  • .gitattributes itself: 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:

FlagWhat it ignores
--ignore-cr-at-eolCarriage returns at end of line only
-w / --ignore-all-spaceAll whitespace differences
-b / --ignore-space-changeChanges in the amount of whitespace
--ignore-blank-linesAdditions/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-eol permanently 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.autocrlf without a .gitattributes file. core.autocrlf is 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=lf for shell scripts, Dockerfiles, and Makefiles. These files break with CRLF endings on Unix systems, and text=auto alone does not always enforce LF on Windows checkouts.

Summary

  • ^M in git diff means 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 .gitattributes file with * text=auto and explicit eol= rules for platform-sensitive files, then run git add --renormalize . to apply.
  • Set core.autocrlf consistently across the team (true on Windows, input on Mac/Linux) as a safety net alongside .gitattributes.
  • Use the narrowest whitespace flag that matches the problem. --ignore-cr-at-eol is almost always what you want, not -w.

Course illustration
Course illustration

All Rights Reserved.