为什么git不停地搞乱我的行结尾? [英] Why does git keep messing with my line endings?

查看:142
本文介绍了为什么git不停地搞乱我的行结尾?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Windows上,我有 core.autocrlf 禁用:

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

现在,我假设,git不会混淆任何行结尾,但是我的回购库中的一些文件不断引发问题。



我刚刚克隆了repo的新副本,并且git已经告诉我,有未分离的变化。当我 git diff -R 时,我可以看到CRLF行尾已添加到文件中:

  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

我不明白这些行结尾是从哪里来的,但我也无法回复这一改变。当我再次检出文件时,它仍然会被修改:

  $ git checkout -f nginx-1.11.1 / contrib /geo2nginx.pl 
$ git status
在分支开发
您的分支与'origin / dev'保持同步。
更改没有为commit提交:
(使用git add< file> ...更新将提交的内容)
(使用git checkout - < file> ;. ..放弃工作目录中的更改)

修改:nginx-1.11.1 / contrib / geo2nginx.pl

没有更改添加到提交(使用git add和/或git commit -a)

这对我没有意义,所以我只是运行 dos2unix 对该文件:

  $ dos2unix nginx-1.11.1 / contrib / geo2nginx.pl 
dos2unix:将文件nginx-1.11.1 / contrib / geo2nginx.pl转换为Unix格式...

现在肯定不应该有任何改变,对吧?但该文件仍然显示为在 git status git diff 中修改后仍会在工作中报告CRLF行结尾复制。

当我现在执行并提交文件时,即使diff显示CRLF行尾,结果文件也会有LF行尾。



我没有全局 .gitattributes git config --global core.attributesfile 不输出任何内容)。项目中的 .gitattributes 具有 * text eol = lf set(完整 .gitattributes )。

这里发生了什么,我该如何解决这个问题?

重现问题



我可以使用开源我正在维护的项目重现此问题:

  $ git clone git@github.com:fairmanager / fm-log.git 
克隆到'fm-log'中...
remote:计数对象:790,完成。
remote:总计790(delta 0),重用0(delta 0),重复使用包790
接收对象:100%(790/790),201.71 KiB | 138.00 KiB / s,完成。
解决三角洲问题:完成100%(418/418)。
检查连通性...完成。

$ cd fm-log /
$ git status
在分支主设备
上你的分支是'origin / master'的最新版本。
更改没有为commit提交:
(使用git add< file> ...更新将提交的内容)
(使用git checkout - < file> ;. ..放弃工作目录中的更改)

修改:.idea / dictionaries / OliverSalzburg.xml
修改:.idea / inspectionProfiles / Project_Default.xml
修改:.idea /inspectionProfiles/profiles_settings.xml

没有更改添加到提交中(使用git add和/或git commit -a)


解决方案

有趣的是:在新添加的问题回购中,我尝试了克隆它,并且在BSD上看到同样的事情:

  $ git clone git@github.com:fairmanager / fm-log.git 
克隆到'fm-log' ...
remote:计数对象:790,完成。
remote:总计790(delta 0),重用0(delta 0),重复使用包790
接收对象:100%(790/790),201.71 KiB | 0字节/秒,完成。
解决三角洲问题:完成100%(418/418)。
检查连通性...完成。
$ cd fm-log /
$ git status
在分支大师
您的分支是最新的'origin / master'。
更改没有为commit提交:
(使用git add< file> ...更新将提交的内容)
(使用git checkout - < file> ;. ..放弃工作目录中的更改)

修改:.idea / dictionaries / OliverSalzburg.xml
修改:.idea / inspectionProfiles / Project_Default.xml
修改:.idea /inspectionProfiles/profiles_settings.xml

没有更改添加到提交中(使用git add和/或git commit -a)

试图看看发生了什么:

  $ git diff 
警告:CRLF将被替换为.idea / dictionaries / OliverSalzburg.xml中的LF。
[snip]

看来 HEAD:.idea / 文件实际上具有回车符(并且最后一行没有换行符,因此紧接在括号后面的提示符):

  $ git show HEAD:.idea / dictionaries / OliverSalzburg.xml | vis 
< component name =ProjectDictionaryState> \ ^ M
< dictionary name =OliverSalzburg> \ ^ M
< words> \ ^ M
< w>着色器< / w> \ ^ M
< w>多行< / w> \ ^ M
< / words> \ ^ M
< / dictionary> \ ^ M
< / component> $

- 树版本同样有回车符(没有剪切和粘贴,但 vis 显示相同的 \ ^ M 行结尾) 。

因此,至少在这种情况下发生的是由于 .gitattributes 设置为:

  $ head -2 .gitattributes 
#通常,使用LF作为文本
* text eol = lf

Git会在提交过程中将这些文件转换为仅LF,与 HEAD 版本包含CR-LF结尾。这就是 git status 在这里说的内容。



注释 * text eol =如果 .gitattributes 中的使得状态消失(因为文件不会被转换),当然。 gitattributes 现在被标记为已修改。有趣的是,将属性行再次放回,状态变为完全无声:必须强制 git checkout 替换工作树版本以获取状态(例如,手动 rm -rf .idea 并重新检出,或 git reset --hard )。



(大概 - 我在这里猜测 - 当Git注意到工作树时,索引条目在 git checkout 和HEAD版本有所不同,这让Git仔细检查文件,修改 .gitattributes 并通过 git status 这部分纯粹是为了解释 git status ...)的怪异行为。

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?

Reproduce the issue

I can repro this issue with an open source project I'm maintaining:

$ 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")

解决方案

Interesting: with the newly added-to-question repo I tried cloning it and, on 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'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...)

这篇关于为什么git不停地搞乱我的行结尾?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆