[git] git-diff to ignore ^M

In a project where some of the files contains ^M as newline separators. Diffing these files are apparently impossible, since git-diff sees it as the entire file is just a single line.

How does one diff with the previous version?

Is there an option like "treat ^M as newline when diffing" ?

prompt> git-diff "HEAD^" -- MyFile.as 
diff --git a/myproject/MyFile.as b/myproject/MyFile.as
index be78321..a393ba3 100644
--- a/myproject/MyFile.cpp
+++ b/myproject/MyFile.cpp
@@ -1 +1 @@
-<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
+<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
prompt>

UPDATE:

now I have written a Ruby script that checks out the latest 10 revisions and converts CR to LF.

require 'fileutils'

if ARGV.size != 3
  puts "a git-path must be provided"
  puts "a filename must be provided"
  puts "a result-dir must be provided"
  puts "example:"
  puts "ruby gitcrdiff.rb project/dir1/dir2/dir3/ SomeFile.cpp tmp_somefile"
  exit(1)
end

gitpath = ARGV[0]
filename = ARGV[1]
resultdir = ARGV[2]

unless FileTest.exist?(".git")
  puts "this command must be run in the same dir as where .git resides"
  exit(1)
end

if FileTest.exist?(resultdir)
  puts "the result dir must not exist"
  exit(1)
end
FileUtils.mkdir(resultdir)

10.times do |i|
  revision = "^" * i
  cmd = "git show HEAD#{revision}:#{gitpath}#{filename} | tr '\\r' '\\n' > #{resultdir}/#{filename}_rev#{i}"
  puts cmd 
  system cmd
end

This question is related to git diff newline git-diff

The answer is


Developing on Windows, I ran into this problem when using git tfs. I solved it this way:

git config --global core.whitespace cr-at-eol

This basically tells Git that an end-of-line CR is not an error. As a result, those annoying ^M characters no longer appear at the end of lines in git diff, git show, etc.

It appears to leave other settings as-is; for instance, extra spaces at the end of a line still show as errors (highlighted in red) in the diff.

(Other answers have alluded to this, but the above is exactly how to set the setting. To set the setting for only one project, omit the --global.)

EDIT:

After many line-ending travails, I've had the best luck, when working on a .NET team, with these settings:

  • NO core.eol setting
  • NO core.whitespace setting
  • NO core.autocrlf setting
  • When running the Git installer for Windows, you'll get these three options:
    • Checkout Windows-style, commit Unix-style line endings <-- choose this one
    • Checkout as-is, commit Unix-style line endings
    • Checkout as-is, commit as-is

If you need to use the whitespace setting, you should probably enable it only on a per-project basis if you need to interact with TFS. Just omit the --global:

git config core.whitespace cr-at-eol

If you need to remove some core.* settings, the easiest way is to run this command:

git config --global -e

This opens your global .gitconfig file in a text editor, and you can easily delete the lines you want to remove. (Or you can put '#' in front of them to comment them out.)


Why do you get these ^M in your git diff?

In my case I was working on a project which was developed in Windows and I used OS X. When I changed some code, I saw ^M at the end of the lines I added in git diff. I think the ^M were showing up because they were different line endings than the rest of the file. Because the rest of the file was developed in Windows it used CR line endings, and in OS X it uses LF line endings.

Apparently, the Windows developer didn't use the option "Checkout Windows-style, commit Unix-style line endings" during the installation of Git.

So what should we do about this?

You can have the Windows users reinstall git and use the "Checkout Windows-style, commit Unix-style line endings" option. This is what I would prefer, because I see Windows as an exception in its line ending characters and Windows fixes its own issue this way.

If you go for this option, you should however fix the current files (because they're still using the CR line endings). I did this by following these steps:

  1. Remove all files from the repository, but not from your filesystem.

    git rm --cached -r .
    
  2. Add a .gitattributes file that enforces certain files to use a LF as line endings. Put this in the file:

    *.ext text eol=crlf
    

    Replace .ext with the file extensions you want to match.

  3. Add all the files again.

    git add .
    

    This will show messages like this:

    warning: CRLF will be replaced by LF in <filename>.
    The file will have its original line endings in your working directory.
    
  4. You could remove the .gitattributes file unless you have stubborn Windows users that don't want to use the "Checkout Windows-style, commit Unix-style line endings" option.

  5. Commit and push it all.

  6. Remove and checkout the applicable files on all the systems where they're used. On the Windows systems, make sure they now use the "Checkout Windows-style, commit Unix-style line endings" option. You should also do this on the system where you executed these tasks because when you added the files git said:

    The file will have its original line endings in your working directory.
    

    You can do something like this to remove the files:

    git ls | grep ".ext$" | xargs rm -f
    

    And then this to get them back with the correct line endings:

    git ls | grep ".ext$" | xargs git checkout
    

    Of course replacing .ext with the extension you want.

Now your project only uses LF characters for the line endings, and the nasty CR characters won't ever come back :).

The other option is to enforce windows style line endings. You can also use the .gitattributes file for this.

More info: https://help.github.com/articles/dealing-with-line-endings/#platform-all


Also see:

core.whitespace = cr-at-eol

or equivalently,

[core]
    whitespace = cr-at-eol

where whitespace is preceded by a tab character.


TL;DR

Change the core.pager to "tr -d '\r' | less -REX", not the source code

This is why

Those pesky ^M shown are an artifact of the colorization and the pager. enter image description here It is caused by less -R, a default git pager option. (git's default pager is less -REX)

The first thing to note is that git diff -b will not show changes in white space (e.g. the \r\n vs \n)

setup:

git clone https://github.com/CipherShed/CipherShed
cd CipherShed

A quick test to create a unix file and change the line endings will show no changes with git diff -b:

echo -e 'The quick brown fox\njumped over the lazy\ndogs.' > test.txt
git add test.txt
unix2dos.exe test.txt
git diff -b test.txt

We note that forcing a pipe to less does not show the ^M, but enabling color and less -R does:

git diff origin/v0.7.4.0 origin/v0.7.4.1 | less
git -c color.ui=always diff origin/v0.7.4.0 origin/v0.7.4.1 | less -R

The fix is shown by using a pipe to strip the \r (^M) from the output:

git diff origin/v0.7.4.0 origin/v0.7.4.1
git -c core.pager="tr -d '\r' | less -REX"  diff origin/v0.7.4.0 origin/v0.7.4.1

An unwise alternative is to use less -r, because it will pass through all control codes, not just the color codes.

If you want to just edit your git config file directly, this is the entry to update/add:

[core]
        pager = tr -d '\\r' | less -REX

As noted by VonC, this has already been included in git 2.16+. Unfortunately, the name of the option (--ignore-cr-at-eol) differs from the one used by GNU diff that I'm used to (--strip-trailing-cr).

When I was confronted with this problem, my solution was to invoke GNU diff instead of git's built-in diff, because my git is older than 2.16. I did that using this command line:

GIT_EXTERNAL_DIFF='diff -u --strip-trailing-cr "$2" "$5";true;#' git diff --ext-diff

That allows using --strip-trailing-cr and any other GNU diff options.

There's also this other way:

git difftool -y -x 'diff -u --strip-trailing-cr'

but it doesn't use the configured pager settings, which is why I prefer the former.


In my case, what did it was this command:

git config  core.whitespace cr-at-eol

Source: https://public-inbox.org/git/[email protected]/T/


Try git diff --ignore-space-at-eol, or git diff --ignore-space-change, or git diff --ignore-all-space.


Is there an option like "treat ^M as newline when diffing" ?

There will be one with Git 2.16 (Q1 2018), as the "diff" family of commands learned to ignore differences in carriage return at the end of line.

See commit e9282f0 (26 Oct 2017) by Junio C Hamano (gitster).
Helped-by: Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit 10f65c2, 27 Nov 2017)

diff: --ignore-cr-at-eol

A new option --ignore-cr-at-eol tells the diff machinery to treat a carriage-return at the end of a (complete) line as if it does not exist.

Just like other "--ignore-*" options to ignore various kinds of whitespace differences, this will help reviewing the real changes you made without getting distracted by spurious CRLF<->LF conversion made by your editor program.


I struggled with this problem for a long time. By far the easiest solution is to not worry about the ^M characters and just use a visual diff tool that can handle them.

Instead of typing:

git diff <commitHash> <filename>

try:

git difftool <commitHash> <filename>

Examples related to git

Does the target directory for a git clone have to match the repo name? Git fatal: protocol 'https' is not supported Git is not working after macOS Update (xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools) git clone: Authentication failed for <URL> destination path already exists and is not an empty directory SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443 GitLab remote: HTTP Basic: Access denied and fatal Authentication How can I switch to another branch in git? VS 2017 Git Local Commit DB.lock error on every commit How to remove an unpushed outgoing commit in Visual Studio?

Examples related to diff

Create patch or diff file from git repository and apply it to another different git repository Comparing the contents of two files in Sublime Text Git diff between current branch and master but not including unmerged master commits Fast way of finding lines in one file that are not in another? Python - difference between two strings How to see the changes in a Git commit? unix diff side-to-side results? Find the files existing in one directory but not in the other git diff between two different files How to get the difference (only additions) between two files in linux

Examples related to newline

How can I insert a line break into a <Text> component in React Native? Print "\n" or newline characters as part of the output on terminal Using tr to replace newline with space How to write one new line in Bitbucket markdown? Line break in SSRS expression How to insert a new line in Linux shell script? Replace CRLF using powershell How to write new line character to a file in Java What is the newline character in the C language: \r or \n? How to print values separated by spaces instead of new lines in Python 2.7

Examples related to git-diff

How to show uncommitted changes in Git and some Git diffs in detail Git list of staged files Create patch or diff file from git repository and apply it to another different git repository There isn't anything to compare. Nothing to compare, branches are entirely different commit histories git: diff between file in local repo and origin Git diff between current branch and master but not including unmerged master commits How to Diff between local uncommitted changes and origin How to see the changes in a Git commit? How do you take a git diff file, and apply it to a local branch that is a copy of the same repository? git diff file against its last change