Search code examples
windowsgitline-endings

Why is git showing line endings change although there should be none?


I have a file checked in as CRLF which should be CRLF as can be seen by: git ls-files --eol:

i/crlf  w/crlf  attr/text eol=crlf      src/Project.Tests/ReadTestsV4.cs

But it is still showing a diff with file changes supposedly like this (the real file is CRLF):

diff --git a/src/Project.Tests/ReadTestsV4.cs b/src/Project.Tests/ReadTestsV4.cs
index 9f139a6..23d11a5 100644
--- a/src/Project.Tests/ReadTestsV4.cs
+++ b/src/Project.Tests/ReadTestsV4.cs
@@ -1,605 +1,605 @@
-^M
-using Renci.SshNet;^M
-using Xunit;^M
-using Project;^M
-using System.Linq;^M
-using System.Diagnostics.CodeAnalysis;^M
-using Microsoft.Extensions.Logging;^M
...
+
+using Renci.SshNet;
+using Xunit;
+using Project;
+using System.Linq;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.Extensions.Logging;

The gitattributes for this project are:

*.json eol=lf
*.cs eol=lf
*.csproj eol=lf
*.scss eol=lf
*.ts eol=lf
*.js eol=lf
*.yml eol=lf
*.md eol=lf
*.xml eol=lf
*.html eol=lf
*.config eol=lf
*.txt eol=lf

*.png binary
*.zip binary

# Except for Testing the SSH Libaray CRLF line endings are required for the tests to succeed
src/Project.Tests/**/*.cs eol=crlf
*.bat eol=crlf

My personal git settings are:

[alias]
    c = commit -m
    aa = add --all
    s = status 
    slog = log -n 10 --date-order --abbrev-commit --graph --pretty=format:"%h|%an|%ar|%s"
    glog = log --graph --pretty=oneline --abbrev-commit --decorate --branches --all
[user]
    name = Daniel Habenicht
[core]
    autocrlf = false
    editor = \"C:\\MyPath\\bin\\code.cmd\" --wait
[commit]
    gpgsign = true
[gpg]
    program = C:\\Program Files (x86)\\GnuPG\\bin\\gpg.exe

I already tried:

git rm --cached -r .
git reset --hard

but its always showing theses changes.

Remarks:

  • Project is a replacement for the real project name which I abbreviated.

Solution

  • What's going on here is this:

    • The committed file (which cannot be changed) actually has CRLF endings.
    • The index copy, once you run git add, will not have CRLF endings: it will have LF-only endings. (It currently has CRLF endings, based on the git ls-files --eol output, which makes sense as the initial index copy is made by reading the committed copy into the index. This keeps the committed copy's CRLF endings intact. But eol=crlf in .gitattributes says that when you run git add, Git should strip the carriage returns, so it will do that.)
    • A future commit will be made from what is (in the future) in the index: that is, what would be in the index if you run git add.
    • Therefore the diff between what's committed now, and what would be committed next if you ran git add and git commit, involves removing all the carriage returns from the file that would be git added once you run git add.

    Basically, any time you change the "normalization" process for some file(s)—the way that Git will convert that file or those files from the committed copies to the working tree copies, or vice versa—you may need to make one new "convert the file(s)" commit first. That way you'll have the new normalization in effect. You can then make changes the usual way, and these changes will be normalized in accordance with the new normal.

    To make those newly normalized copies, consider using git add --renormalize, if your Git is not too ancient (very old Git versions lack the --renormalize option and you must trick such a Git into re-adding the file). Do this before making any other changes, and make a new commit that has, as its commit message, something that will remind you why you made this commit. For instance:

    renormalize files
    
    We changed the `.gitattributes` setting, so we now need to
    renormalize files.  Git will show every line changed in
    this commit, and `git blame` will point to this commit; use
    Git's facilities for skipping over this commit when using
    `git blame` because although every line *is* changed, these
    changes are purely white-space housekeeping changes that are
    not otherwise noteworthy.
    

    Now that you have made this new commit so that the committed files match the new normal, you can go back to working as usual. If you later are looking for something of interest and run git blame and discover this commit and its error message, it will remind you to look up the git blame documentation and see how to tell git blame don't count the renormalization commit. (See the --ginore-rev and --ignore-revs-file options.)