I'm on Windows and I have core.autocrlf
disabled:
$ git config core.autocrlf; git config --global core.autocrlf
false
false
Now, I would assume, that git does not mess with any line endings, but some files in my repo keep causing issues.
I just cloned a fresh copy of the repo, and git is already telling me that there are unstaged changes. When I git diff -R
, I can see that CRLF line endings have been added to a 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 line endings come from, but I'm also unable to "revert" this change. When I checkout the file again, it will still be modified afterwards:
$ 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 run dos2unix
on 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 surely shouldn't be any changes, right? But the file is still being shown as modified in git status
and git diff
will still report CRLF line endings in the working copy.
When I now stage and commit the file, the resulting file will have LF line endings, even though the diff showed CRLF line endings.
I don't have a global .gitattributes
(git config --global core.attributesfile
does not output anything). And the .gitattributes
in the project has * text eol=lf
set (full .gitattributes
).
What is going on here and how can I resolve this?
I can repro this issue with an open source project I'm maintaining:
$ git clone [email protected]: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")
Interesting: with the newly added-to-question repo I tried cloning it and, on BSD, see the same thing:
$ git clone [email protected]: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's going on:
$ git diff
warning: CRLF will be replaced by LF in .idea/dictionaries/OliverSalzburg.xml.
[snip]
It seems that HEAD:.idea/
files actually have carriage-returns in them (and the last line has no newline, hence the prompt right after the close angle bracket):
$ 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 work-tree version likewise has carriage returns (no cut and paste but vis
shows the same \^M
line endings).
So what has happened in this case, at least, is that due to the .gitattributes
setting of:
$ head -2 .gitattributes
# In general, use LF for text
* text eol=lf
Git will convert these files to LF-only during commit, vs the HEAD
version that contains CR-LF endings. This is what git status
is saying here.
Commenting out the * text eol=lf
in .gitattributes
makes the status go away (since the files won't be converted), though of course .gitattributes
is now marked as modified. Interestingly, putting the attribute line back again, the status goes completely silent: it's necessary to force git checkout
to replace the work-tree version to get the status back (e.g., manually rm -rf .idea
and check out again, or git reset --hard
).
(Presumably—I'm guessing a bit here—the index entry gets marked specially during git checkout
when Git notices that the work-tree and HEAD version differ. This makes Git inspect the file closely. Modifying .gitattributes
and running an internal diff via git status
probably un-marks the index entries. This part is pure speculation meant to explain the weird behavior of git status
...)
If the local setting git config core.autocrlf
is indeed to false
, then those eol changes must come from a .gitattributes
file (see man page).
Look for one in your local repo, which would include eol rules (like * text=auto eol=crlf
I mentioned here).
Or check if you have a global gitattributes file.
git config --global core.attributesfile
Regarding fairmanager/fm-log
, you can see one of the "modified" files .idea/dictionaries/OliverSalzburg.xml
added in commit e6f823b with crlf at the end.
Since the .gitattributes
has * text eol=lf
rule, the working directory checkout blobs with lf eol, hence the git diff
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With