首页 > 解决方案 > 无法从 Windows 签入 linux 格式文件

问题描述

第 1 步:运行dos2unix file*

      Result : files converted to linux format on two files.

第 2 步:运行git status

       Result : Two files with changes in shown.

第 3 步:运行git add .

注意:在此之后,git 开始忽略 lf 和 crlf 更改。

 Result : warning: LF will be replaced by CRLF in file1.sh.The file will have its original line endings in your working directory warning: LF will be replaced by CRLF in file2.sh.The file will have its original line endings in your working directory

第 4 步:运行git status

  Result : Your branch is up to date. Noting to commit

第 5 步:重复第 1 步和第 2 步。

  Result : same as step 4

第6步:运行后尝试git config core.autocrlf false

 Result: Problem is not resolved.

下面是步骤的截图。

在此处输入图像描述

标签: git

解决方案


你不需要做任何事情。

虽然解释有点棘手。您需要注意,当您使用 Git 时,每个活动文件总是有三个版本。

稍微思考一下,其中两个版本存在的原因就很明显了。第三个有点奇怪;我们稍后会谈到。

首先是每个提交(由其唯一的哈希 ID 标识)存储所有文件的完整快照。这个 inside-a-commit 快照以一种特殊的、只读的、仅限 Git 的格式存储文件。只有 Git 可以实际使用这些文件。特殊的 Git 格式会导致重复数据删除,因此如果您在多次提交中具有相同版本的某些文件,则该文件实际上只有一个副本。这就是为什么每个提交都有每个文件的完整副本并不是什么大问题:只要有可能,它们都会被共享。由于每个文件都被永久冻结,因此很容易共享它。

但是因为这些文件副本实际上是无法更改的,并且不能被您计算机上的任何其他非 Git 程序使用,所以它们不适合工作。它们仅作为归档提交有用。因此,当您使用git checkout(或git switch在 Git 2.23 或更高版本中)时,您选择一个您希望“签出”的提交。Git复制该提交中的所有文件,将它们从特殊的、只读的、仅限 Git 的冻结文件转换为常规的日常读/写文件,采用计算机的正常文件格式。

Git 将您可以查看和使用的正常日常格式的副本位于工作空间区域中。Git 将此称为您的工作树工作树。由于这些普通文件,您可以使用它们,甚至可以随时更改它们。

这就是为什么每个文件都有两个副本在使用中的原因:在当前提交中有一个冻结的副本,在你的工作树中有一个正常格式的副本。但是第三个副本呢?该副本位于 Git 所谓的index暂存区域(同一事物的两个术语)中。这一种位于冻结的HEAD提交副本和工作树副本之间。

假设您只有两个名为README.mdand的文件,让我们对这三个副本进行简单说明main.py

   HEAD         index       work-tree
---------     ---------     ---------
README.md     README.md     README.md
main.py       main.py       main.py

比如说,所有三个副本都main.py匹配——嗯,有点——在开头,就在你最初的. 之后git checkout。那个HEAD,当前提交中的那个,被冻结了:它实际上是不能改变的。工作树副本由您随意处理。

介于两者之间的是 Git 将在您进行的下一次提交中放入的那个。现在,它与其他两个匹配。但是如果你改变 main.py了呢?让我们为每个文件添加一个版本号:

   HEAD         index       work-tree
---------     ---------     ---------
README.md(1)  README.md(1)  README.md(1)
main.py(1)    main.py(1)    main.py(2)

更改了工作树副本,因此我们增加了版本号。(它实际上不在文件中,我们只是绘制它以跟踪每个副本的外观。)

如果您希望您的更改main.py进入您的下一次提交,您现在必须运行git add main.py. 这会将main.py文件复制到 Git 的索引中,替换现有的索引。新副本采用 Git 的冻结格式,但实际上还没有冻结:

   HEAD         index       work-tree
---------     ---------     ---------
README.md(1)  README.md(1)  README.md(1)
main.py(1)    main.py(2)    main.py(2)

...但是现在,在 之后git add,索引中的HEAD副本与副本不同(并且与工作树副本相同)。如果您git commit现在运行,Git 将从每个文件的索引副本中进行新的冻结提交。

请注意,副本是 index → work-tree 和 work-tree → index

当 Git 最初提取提交时,它需要其索引中的冻结格式文件。这很简单,而且是直接复制。1 不过,Git 需要将该冻结格式的文件复制到您的工作树中,这涉及对其进行解压缩和反 Git 化。Git 通过将索引版本(冻结格式)提取到您的工作树(常规日常文件)来制作此副本:

  • 索引 → 工作树:解压缩

同时,您稍后git add必须将您的工作树文件复制到索引中:

  • 工作树→索引:压缩成冻结格式

如果在 Git 复制这些副本时,我们让 Git 能够将 Unix/Linux 风格的 LF-only 行尾转换为 Windows 风格的 CRLF 行尾?然后我们只需要这个:

  • 索引 → 工作树:解压缩和 Windows 化
  • 工作树 → 索引:de-Windows-ify 并重新压缩

当你告诉它操作行尾时,这就是 Git 所做的。


1实际上,它更容易,因为索引不包含文件的真实副本,而是对内部 Git blob 对象的引用。但是您不必担心这一点——除非您深入了解使用git ls-files --stageand的细节,否则不必担心git update-index


你做了什么

你开始了,到目前为止运行了一些提交,core.autocrlf设置为true. 这告诉 Git:不要弄乱我的行尾。默认情况下,Git 修改的文件是它猜测的正确文件。(通常更明智的做法是.gitattributes告诉 Git 应该像这样操作哪些文件,而不是让 Git 猜测,但大多数时候 Git 的猜测非常好。)

由于 Git 已经完成了相同的 de-Windows-line-ending 工作,因此在 Windows 上提交的早期文件已经具有 Linux 风格的 LF-only 行尾。最初总是与提交的副本完全匹配的索引副本也有 Linux 风格的 LF-only 行结尾。

只有你的工作树副本有其他类型的行尾,即使那样,如果你告诉 Git 操作行尾(你做了),它们也只有那些行尾。

当您告诉 Git根本不要弄乱我的行尾时那么您的工作树文件是否具有 CRLF 行尾或仅 LF 行尾很重要,因为那样 git add会将您在工作树中的所有内容复制到Git 的索引,不会弄乱任何行尾。设置core.autocrlf为 false,并且在 中没有任何更明确的设置.gitattributes,这样做,所以现在确保您的工作树文件具有您希望在新副本中具有的结尾变得很重要git add,然后git commit.

dos2unix在两个工作树文件上运行。这将采用他们的 CR-LF Windows 样式的行尾,如果他们首先有这些行尾(他们可能有),并将它们变成 LF-ony 行尾。然后你跑了git add。这次的git add步骤并没有对行尾进行 de-Windows 化,而是重新压缩了文件。结果是......对于每个文件,索引中已经存在相同的文件,因为索引副本一直是 Unix / Linux 样式。

请注意,现在在每个文件中放置什么行尾非常重要core.autocrlf,因为在关闭且没有.gitattributes条目的情况下,您已经告诉 Git:交出所有文件内容:不要弄乱行尾。

如果您希望 Git 以真正可预测的方式处理行尾,而不是猜测,您应该创建一个.gitattributes文件并列出每个文件名或文件名模式以及该文件的正确处理方式。最初设置这有点痛苦,但在此之后,往往会运行良好——这就是 Git 人员对 Git 项目所做的事情。


推荐阅读