git显示克隆后已更改的文件,没有任何其他动作 [英] `git` shows changed files after cloning, without any other actions

查看:119
本文介绍了git显示克隆后已更改的文件,没有任何其他动作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

git clone git@github.com:erocarrera/pydot( 35a8d858b )显示:

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

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

These files have CRLF line endings, for example:

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

.gitattributes文件包含:

*.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.

Changing core.autocrlf has no effect on the status of these files. Deleting the .gitattributes has no effect either. Changing these files with dos2unix does not change their status (as expected), and back with unix2dos shows no difference with diff versus an older copy. File permissions look unchanged with ls -lsa. Also, the files have uniform line endings as far as I can tell with vi -b (thus it shouldn't be the case that unix2dos or dos2unix convert from mixed to uniform line endings, which could have explained this strange behavior). I'm using git version 2.11.0.

git认为发生了什么变化?

What does git think has changed?

有些相关:

  1. Git状态将文件显示为即使内容相同也改变了
  2. 在git clone之后直接显示为已修改的文件
  3. 克隆git repo,它已经有一个肮脏的工作目录了……哇啊?
  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 .

I didn't find an answer that explains this behavior during my search over several discussions. This issue arose from 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标准化

Out of curiosity, I committed one of these files, dumped git log -1 -p > diff, and vi -b diff shows that git normalized

  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行尾).

Other weird observations: git checkout any of these files after cloning does not have any effect. After the above commit, the file b545.dot continued to have CLRF line endings in the working directory. Applying dos2unix followed by unix2dos didn't make git think that it has changed (whereas before the commit it did, probably because the committed file had CLRF line endings).

推荐答案

这种情况恰好发生,因为这些文件 带有CRLF结尾,但是.gitattributes文件说赋予它们仅含LF的结尾.

This happens precisely because those files are committed with CRLF endings, yet the .gitattributes file says to commit them with LF-only endings.

Git可以而且将在两个地方执行CRLF-vs-LF-only转换:

Git can and will do CRLF-vs-LF-only conversion in two places:

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

  • During extraction from index to work-tree. A file stored in a commit or in the index is always assumed to be in a "clean" state, but when extracting that file from the index, to the work-tree, Git should apply any conversions directed by .gitattributes in the form of "change LF-only to CRLF", for instance, and also in the form of what Git calls smudge filters.

从工作树复制文件到索引期间.存储在工作树中的文件处于已弄脏"状态,因此,在这一点上,Git应该应用任何清除"转换:例如,将CR-LF更改为仅LF,然后应用 clean过滤器.

During the copy of a file from work-tree back to index. A file stored in the work-tree is in the "smudged" state, so at this point, Git should apply any "cleaning" conversions: for instance, change CR-LF to LF-only, and applying clean filters.

请注意,可以在两个地方进行 转换.这并不意味着它们同时出现在这两个点上,而只是这是两个可能的位置.如.gitattributes文档所述,实际的转换是:

Note that there are two points at which these conversions can occur. This does not mean that they will occur at both points, just that these are the two possible places. As the .gitattributes documentation notes, the actual conversions are:

  • eol=lf:在索引->工作树上无;在工作树->索引上将CR-LF更改为仅LF
  • eol=crlf:仅LF到索引->工作树上的CR-LF;在工作树上没有->索引
  • eol=lf: none on index -> work-tree; CR-LF to LF-only on work-tree -> index
  • eol=crlf: LF-only to CR-LF on index -> work-tree; none on work-tree -> index

现在,存储在提交中的,实际上位于存储库中的文件纯粹是只读的.它不能在提交内部进行任何更改.更准确地说,提交(通过哈希ID)标识一棵树(通过哈希ID)标识具有其任何内容的Blob.这些哈希ID本身就是对象内容的冷冻校验和,因此它们自然都是只读的:如果我们尝试更改内容,我们得到的是具有新的,不同的哈希ID的新的,不同的对象.

Now, a file that's actually in the repository, stored in a commit, is purely read-only. It can never change inside that commit. More precisely, the commit identifies (by hash ID) a tree that identifies (by hash ID) a blob that has whatever contents it has. These hash IDs are themselves crytographic checksums of the object contents, so they are naturally all read-only: if we try to change the contents, what we get is instead a new, different object with a new, different hash ID.

由于git checkout实际上是通过将提交的树中的原始哈希ID对应到索引来工作的,因此索引中存储的文件版本必须与提交中存储的文件版本相同.

Because git checkout actually works by coping the raw hash IDs from the commit's tree(s) to the index, the versions of files stored in the index are necessarily identical to those stored in the commit.

因此,如果无论如何(无论方式如何),提交的文件都与.gitattributes指示Git进行操作的形式不一致,则文件将在工作中变得脏",不管对他们什么都没做的事实!如果要git add这三个文件,它将把它们从工作树复制到索引,因此从其行尾删除回车符.因此,用git status术语对它们进行了修改,但尚未进行提交.

Hence, if somehow—regardless of the how—the committed files are in a form that disagrees with what .gitattributes directs Git to do, the files will become "dirty" in the work-tree regardless of the fact that you haven't done anything to them! If you were to git add the three files in question, that would copy them from work-tree to index, and hence delete the carriage-returns from their line endings. Hence they are, in git status terms, modified but not yet staged for commit.

在工作树版本中去除回车符会使它们保持相同状态:它们已针对索引中的内容进行了修改,因为git add现在将保留其仅LF的行结尾,从而产生新的,索引中的其他文件.

Stripping out the carriage returns in the work-tree versions leaves them in the same state: they're modified with respect to what's in the index, because git add will now leave their LF-only line endings unchanged, producing new, different files that are in the index.

一个更有趣的问题是:他们是如何以错误状态进入提交的?我们无法回答这一点:只有做出那些提交的人才能给出答案.我们只能推测.实现此目的的一种方法是添加和提交文件而没有.gitattributes生效,然后将.gitattributes设置为生效而无需git add-再次打开文件.这样,即使.gitattributes文件 now 说(但没有更早说)任何 new git add应该去除回车符.

A more interesting question is: How did they get into the commit(s) in the wrong state? This is not something we can answer: only those who made those commits can produce that answer. We can only speculate. One way to achieve this is to add and commit the files without a .gitattributes in effect, then to set the .gitattributes into effect without git add-ing the files again. This way, the CR-LF endings get into someone's index and hence get into that user's commits, even though the .gitattributes file now says (but did not earlier say) that any new git add should strip away the carriage returns.

这篇关于git显示克隆后已更改的文件,没有任何其他动作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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