Why does git keep messing with my line endings?

I am on Windows and disabled core.autocrlf :

 $ git config core.autocrlf; git config --global core.autocrlf false false 

Now, I would suggest that git does not interfere with any line endings, but some files in my repository continue to cause problems.

I just cloned a new copy of the repo, and git already tells me that there are unspecified changes. When I git diff -R , I see that the CRLF line ending has been added to the file:

 diff --git b/nginx-1.11.1/contrib/geo2nginx.pl a/nginx-1.11.1/contrib/geo2nginx.pl index bc8af46..29243ec 100644 --- b/nginx-1.11.1/contrib/geo2nginx.pl +++ a/nginx-1.11.1/contrib/geo2nginx.pl @@ -1,58 +1,58 @@ -#!/usr/bin/perl -w - -# (c) Andrei Nigmatulin, 2005 +#!/usr/bin/perl -w^M +^M +# (c) Andrei Nigmatulin, 2005^M 

I donโ€™t understand where these lines come from, but I also cannot โ€œreturnโ€ this change. When I exit the file again, it will still change after:

 $ git checkout -f nginx-1.11.1/contrib/geo2nginx.pl $ git status On branch dev Your branch is up-to-date with 'origin/dev'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: nginx-1.11.1/contrib/geo2nginx.pl no changes added to commit (use "git add" and/or "git commit -a") 

This makes no sense to me, so I just ran dos2unix in the file:

 $ dos2unix nginx-1.11.1/contrib/geo2nginx.pl dos2unix: converting file nginx-1.11.1/contrib/geo2nginx.pl to Unix format... 

Now there should be no change, right? But the file is still showing as changed in git status , and git diff will still report the completion of the CRLF line in the working copy.

When I execute and commit the file now, the resulting file will have an LF line ending, although diff showed CRLF line endings.

I don't have a global .gitattributes ( git config --global core.attributesfile doesn't output anything). And .gitattributes in the project has * text eol=lf set ( full .gitattributes ).

What is going on here and how can I solve it?

Reproduce the problem

I can reproduce this problem with an open source project that I support :

 $ git clone git@github.com :fairmanager/fm-log.git Cloning into 'fm-log'... remote: Counting objects: 790, done. remote: Total 790 (delta 0), reused 0 (delta 0), pack-reused 790 Receiving objects: 100% (790/790), 201.71 KiB | 138.00 KiB/s, done. Resolving deltas: 100% (418/418), done. Checking connectivity... done. $ cd fm-log/ $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: .idea/dictionaries/OliverSalzburg.xml modified: .idea/inspectionProfiles/Project_Default.xml modified: .idea/inspectionProfiles/profiles_settings.xml no changes added to commit (use "git add" and/or "git commit -a") 
+7
git windows
source share
2 answers

Interesting: with a recently added repo question, I tried to clone it and, in BSD, see the same thing:

 $ git clone git@github.com :fairmanager/fm-log.git Cloning into 'fm-log'... remote: Counting objects: 790, done. remote: Total 790 (delta 0), reused 0 (delta 0), pack-reused 790 Receiving objects: 100% (790/790), 201.71 KiB | 0 bytes/s, done. Resolving deltas: 100% (418/418), done. Checking connectivity... done. $ cd fm-log/ $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: .idea/dictionaries/OliverSalzburg.xml modified: .idea/inspectionProfiles/Project_Default.xml modified: .idea/inspectionProfiles/profiles_settings.xml no changes added to commit (use "git add" and/or "git commit -a") 

Trying to see what happens:

 $ git diff warning: CRLF will be replaced by LF in .idea/dictionaries/OliverSalzburg.xml. [snip] 

It seems that the HEAD:.idea/ files actually have carriage returns in them (and the last line has no new line, so the prompt immediately after the bracket of the closed corner):

 $ git show HEAD:.idea/dictionaries/OliverSalzburg.xml | vis <component name="ProjectDictionaryState">\^M <dictionary name="OliverSalzburg">\^M <words>\^M <w>colorizer</w>\^M <w>multiline</w>\^M </words>\^M </dictionary>\^M </component>$ 

The working tree version also has a carriage return (without cutting and pasting, but vis shows the same line endings \^M ).

So what happened in this case, at least due to the installation of .gitattributes :

 $ head -2 .gitattributes # In general, use LF for text * text eol=lf 

Git converts these files to LF-only during commit, as well as the HEAD version containing CR-LF endings. This is what git status says.

Note * text eol=lf in .gitattributes makes the status go away (since the files will not be converted), although, of course, .gitattributes now marked as modified. It is interesting to note that once the attribute string is returned, the status is completely disabled: you must force git checkout to be replaced by a working tree to return the status (for example, manually rm -rf .idea and check again, or git reset --hard ).

(Presumably, Iโ€™m a little guessing about this - the index entry is specially marked during git checkout , when Git notices that the version of the working tree and HEAD are different. This makes Git carefully check the .gitattributes file and running internal diff via git status probably tags index entries. This part is pure speculation, intended to explain the strange behavior of git status ...)

+5
source share

If the local configuration of git config core.autocrlf indeed false , then these eol changes should come from the .gitattributes file (see the man page ).

Look for one in your local repo that will include eol rules (e.g. * text=auto eol=crlf I mentioned here ).

Or check if you have a global gitattributes file .

 git config --global core.attributesfile 

As for fairmanager/fm-log , you can see one of the โ€œmodifiedโ€ .idea/dictionaries/OliverSalzburg.xml added to commit e6f823b with crlf at the end.

Since .gitattributes has the * text eol=lf rule, the working directory is checked using lf eol, therefore << 29>.

+2
source share

All Articles