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
git diff -b
- I showed this in stackoverflow.com/a/46265081/58794
git diff --ignore-cr-at-eol
. See my answer below.
git diff -b
is identical to git diff --ignore-space-change
.
dos2unix
(and unix2dos
) to convert between line-endings.
GitHub suggests that you should make sure to only use \n as a newline character in git-handled repos. There's an option to auto-convert:
$ git config --global core.autocrlf true
Of course, this is said to convert crlf to lf, while you want to convert cr to lf. I hope this still works …
And then convert your files:
# Remove everything from the index
$ git rm --cached -r .
# Re-add all the deleted files to the index
# You should get lots of messages like: "warning: CRLF will be replaced by LF in <file>."
$ git diff --cached --name-only -z | xargs -0 git add
# Commit
$ git commit -m "Fix CRLF"
core.autocrlf is described on the man page.
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
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.)
core.autocrlf
to true
git config --global core.whitespace cr-at-eol
would turn off other settings that are default. There are three defaults: blank-at-eol, blank-at-eof and space-before-tab. So to enable cr-at-eol while keeping the others you would need to use git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol
.
cr-at-eol
got rid of ^M
at the end of lines in git diff
all right, but GIT still showed those lines as different, although the line ending was the only difference.
git help config
.
Try git diff --ignore-space-at-eol
, or git diff --ignore-space-change
, or git diff --ignore-all-space
.
autocrlf
settings. Thanks!
Also see:
core.whitespace = cr-at-eol
or equivalently,
[core]
whitespace = cr-at-eol
where whitespace
is preceded by a tab character.
git show
) stop bugging me about the ^M
s on the changed lines! :)
git diff
still shows ^M characters.
git config --global core.whitespace cr-at-eol
(where --global is optional if you just want it on the repo you're on)
[core]
so I can replace the core.
prefix with a TAB character.
^M
in git diff
, not about how to not put in ^M in the first place. That means the accepted answer of changing core.autocrlf
is not the best because it silently alters the files without user's confirmation.
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 Linux. 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 CRLF
line endings, and in Linux 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 CRLF
line endings). I did this by following these steps:
Remove all files from the repository, but not from your filesystem. git rm --cached -r .
Add a .gitattributes file that enforces certain files to use a LF as line endings. Put this in the file: * text=auto eol=lf
Add all the files again. git add .
This will show messages like this: warning: CRLF will be replaced by LF in
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
View
-> Line Endings
and click on Unix
.
^M
means? Is it a windows or linux newline? Or is it just a "different" newline compared to the other newlines in the file?
git config --global core.autocrlf true
is overkill, and the anti-Windows/anti-CR
campaign seems tangential to the question.
*.ext text eol=lf
inplace of of crlf
? I think that was a typo, that noone noticed !
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.
git config --global core.autocrlf true
as in the accepted answer, this answers the OP's question more directly: 'Is there an option like "treat ^M as newline when diffing" ?'
git version 2.20.1 (Apple Git-117)
but adding Jason Pyeron's core.pager answer fixed it. YMMV obviously.
TL;DR
Change the core.pager
to "tr -d '\r' | less -REX"
, not the source code
This is why
https://i.stack.imgur.com/ysOdN.png
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
\r\n
line endings and some had \n
line endings (I don't know if that's relevant); diffs of the former showed the ^M
in the modified lines (that is, the +
lines). core.autocrlf
was set to true
. Running git config core.pager "tr -d '\r' | less -REX"
got rid of the pesky ^M
s. Thanks!
git diff -b
is what I was looking for, but I do appreciate the thorough explanation.
[core]
section by adding pager = tr -d '\\r' | less -REX
was the only answer that worked for me. Thank you!
git diff -b
did not work, but the config modification did.
In my case, what did it was this command:
git config core.whitespace cr-at-eol
Source: https://public-inbox.org/git/8d7e4807-9a79-e357-8265-95f22ab716e0@web.de/T/
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>
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.
If you just want a quick line that makes the git diff
but does not show the different endings (thus the ^M
) use the one in the first comments to the original question, it worked for me:
git diff -b
Take into account that, in the long run, you should get your line endings configuration right, as all other answers suggest.
If the git patch is already generated in a windows machine and you are using it you can format the patch with dos2unix utility in Linux.
find -name "*.patch"| xargs dos2unix
This will solve the ^M at EOL and you will be able to git apply patch in your linux machine.
Success story sharing
git config core.whitespace cr-at-eol
.warning: LF will be replaced by CRLF
instead ofwarning: CRLF will be replaced by LF
, and I'm in Linux. Any idea why? I want all to end with LF, not CRLF!git config --global core.autocrlf input
, do the steps in this answer(rm, add, commit), and you will getwarning: CRLF will be replaced by LF. The file will have its original line endings in your working directory.
. Remove the files (because they have the original, wrong CRLF) and checkout them again from the last "Fix CRLF" commit.