git - `git` 显示克隆后更改的文件,没有任何其他操作

标签 git newline eol gitattributes core.autocrlf

git clone git@github.com:erocarrera/pydot ( 35a8d858b ) 在带有 git config core.autocrlf input 的 Debian 中显示:

modified:   test/graphs/b545.dot
modified:   test/graphs/b993.dot
modified:   test/graphs/cairo.dot

这些文件有 CRLF 行结尾,例如:

$ file test/graphs/cairo.dot
test/graphs/cairo.dot: UTF-8 Unicode text, with CRLF line terminators

.gitattributes文件 contains :

*.py eol=lf
*.dot eol=lf
*.txt eol=lf
*.md eol=lf
*.yml eol=lf

*.png binary
*.ps binary

改变 core.autocrlf对这些文件的状态没有影响。删除 .gitattributes也没有效果。使用 dos2unix 更改这些文件不会改变他们的状态(如预期的那样),并返回 unix2dos显示与 diff 没有区别与旧副本相比。 ls -lsa 的文件权限看起来没有变化| .此外,据我所知,这些文件具有统一的行结尾 vi -b (因此不应该是 unix2dosdos2unix 从混合行尾转换为统一行尾,这可以解释这种奇怪的行为)。我正在使用 git版本 2.11.0。

什么是git想法变了?

有些相关:

  1. Git status shows files as changed even though contents are the same
  2. Files showing as modified directly after git clone
  3. Cloning a git repo, and it already has a dirty working directory... Whaaaaa?

在搜索多个讨论时,我没有找到解释此行为的答案。此问题源于 pydot # 163 .

更详细:

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:   test/graphs/b545.dot
    modified:   test/graphs/b993.dot
    modified:   test/graphs/cairo.dot

no changes added to commit (use "git add" and/or "git commit -a")

git diff test/graphs/b993.dot

warning: CRLF will be replaced by LF in test/graphs/b993.dot.
The file will have its original line endings in your working directory.
diff --git a/test/graphs/b993.dot b/test/graphs/b993.dot
index e87e112..8aa0872 100644
--- a/test/graphs/b993.dot
+++ b/test/graphs/b993.dot
@@ -1,10 +1,10 @@
-diGraph G{
-graph [charset="utf8"]
-1[label="Umlaut"];
-2[label="ü"];
-3[label="ä"];
-4[label="ö"];
-1->2;
-1->3;
-1->4;
-}
+diGraph G{
+graph [charset="utf8"]
+1[label="Umlaut"];
+2[label="ü"];
+3[label="ä"];
+4[label="ö"];
+1->2;
+1->3;
+1->4;
+}

更新:

出于好奇,我提交了其中一个文件,转储 git log -1 -p > diff , 和 vi -b diff表明 git归一化

  1 commit 2021d6adc1bc8978fa08d729b3f4d565f9b89651
  2 Author:
  3 Date:
  4 
  5     DRAFT: experiment to see what changed
  6 
  7 diff --git a/test/graphs/b545.dot b/test/graphs/b545.dot
  8 index ebd3e8f..2c33f91 100644
  9 --- a/test/graphs/b545.dot
 10 +++ b/test/graphs/b545.dot
 11 @@ -1,9 +1,9 @@
 12 -digraph g {^M
 13 -^M
 14 -"N11" ^M
 15 -  [^M
 16 -  shape = record^M
 17 -  label = "<p0>WFSt|1571       as Ref: 1338    D"^M
 18 -]^M
 19 -N11ne -> N11:p0^M
 20 -}^M
 21 +digraph g {
 22 +
 23 +"N11" 
 24 +  [
 25 +  shape = record
 26 +  label = "<p0>WFSt|1571       as Ref: 1338    D"
 27 +]
 28 +N11ne -> N11:p0
 29 +}

其他奇怪的观察:git checkout克隆后的任何这些文件都没有任何效果。 以上提交之后,文件b545.dot继续在工作目录中使用 CLRF 行结尾。正在申请 dos2unix其次是 unix2dos没做git认为它已经改变(而在提交之前它确实发生了变化,可能是因为 committed 文件有 CLRF 行结尾)。

最佳答案

这恰恰发生了因为那些文件以CRLF结尾提交的,但是.gitattributes文件说要以仅LF结尾提交它们.

Git 可以并且将会在两个地方进行 CRLF-vs-LF-only 转换:

  • 在从索引提取到工作树期间。存储在提交或索引中的文件始终假定处于“干净”状态,但是当从索引中提取该文件到工作树时,Git 应该应用 .gitattributes< 指示的任何转换 以“将 LF-only 更改为 CRLF”的形式,例如,也以 Git 所谓的涂抹过滤器的形式。

  • 在将文件从工作树复制回索引期间。存储在工作树中的文件处于“污迹”状态,因此此时,Git 应该应用任何“清理”转换:例如,将 CR-LF 更改为 LF-only,并应用清理过滤器.

请注意,这些转换可以发生在两个点上。这并不意味着它们出现在这两个点上,只是说这是两个可能的地方。正如 .gitattributes 文档所述,实际的转换是:

  • eol=lf:索引上没有 -> 工作树; CR-LF 到 LF-only on work-tree -> index
  • eol=crlf:索引 -> 工作树上的 LF-only 到 CR-LF;工作树上没有 -> 索引

现在,存储在提交中的实际存储库中的文件是纯只读的。它可以永远在该提交内更改。更准确地说,提交标识(通过哈希 ID)一棵树,该树标识(通过哈希 ID)具有任何内容的 blob。这些哈希 ID 本身是对象内容的加密校验和,因此它们自然都是只读的:如果我们尝试更改内容,我们得到的是一个新的、不同的对象,它具有一个新的、不同的哈希 ID。

因为 git checkout 实际上是通过将原始哈希 ID 从提交的树复制到索引来工作的,所以存储在索引中的文件版本必须与存储在提交中的文件版本相同。

因此,如果以某种方式——不管如何——提交的文件的形式与 .gitattributes 指示 Git 执行的操作不一致,文件将变为“dirty"在工作树中,而不管 没有对它们做任何事情!如果您要 git add 有问题的三个文件,这会将它们从工作树复制到索引,从而从它们的行尾删除回车符。因此,在 git status 术语中,它们已修改但尚未准备提交。

去除工作树版本中的回车符会使它们处于相同的状态:它们根据索引中的内容进行了修改,因为 git add 现在将保留它们的 LF-only行尾不变,生成索引中的新的不同文件。

一个更有趣的问题是:他们是如何以错误的状态进入提交的?这不是我们可以回答的问题:只有做出这些提交的人才能给出答案。我们只能推测。实现此目的的一种方法是在没有 .gitattributes 的情况下添加和提交文件,然后在没有 git add 的情况下将 .gitattributes 设置为有效>-再次编辑文件。这样,CR-LF 结尾进入某人的索引并因此进入该用户的提交,即使 .gitattributes 文件 now 说(但之前没有说)任何 new git add 都应该去除回车符。

关于git - `git` 显示克隆后更改的文件,没有任何其他操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47491415/

相关文章:

Git LFS 图像和/或文件,如何查看它们?我如何下载它们?

Git:git push -u origin 来源:master

git - 我 merge 而不是 pull ,如何修复

c# - 如何防止 Visual Studio 缩进换行符 (C#)?

python - 当我重新启动 Tornado 服务器时,html 文件中的更改不会生效

notepad++ - 一次性更改多个文件的 EOL

Git "Fetch URL"和 "Push URL",有什么区别?

C 程序 - 输出显示在下一行而不使用换行符

java - 如何匹配java正则表达式中的字符串结尾或空格

linux - 如何在 unix 中只删除 > [大于] 和 < [小于] 之间的一个换行符