如何 git 在 Mac 上用 CRLF 提交一些文件而用 LF 提交其他文件?
How to git commit some files with CRLF and others with LF on Mac?
我有一个存储库,其中包含 7 个带有 CRLF
的文件以及带有 LF
的所有其他文件。我正在研究 mac,默认情况下,它使用 LF
.
当我在 git
上提交更改并将其推送到 Github 并且我的同事拉出分支时,这 7 个文件显示为 LF
.
我想做的是能够像我的 mac 一样提交所有内容(即 7 个文件 CRLF
和其他所有文件 LF
)并确保当有人在 mac 或 linux 上拉我的分支时,他们得到的结果与我承诺的完全一样?请记住,我已经使用 LF
(意外)提交了这 7 个文件,因为我不知道 git 是如何改变这些东西的。所以,我需要确保更改也到达远程分支。
我读了一些 QA,但大部分都混淆了 core.autocrlf
和 .gitattributes
。非常感谢任何有关如何实现此目标的帮助 and/or 解释。
假设 CRLF 行尾很重要且不应转换,使用 .gitattributes
文件将是最安全的,该文件将覆盖本地 git 设置。
您可以按照 Github docs 中的说明创建 .gitattributes
文件。例如,如果您的 CRLF 文件共享一个通用后缀:
# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf
这里你必须要小心,因为 Git 有一些内置的转换,他们 强烈支持 LF-only 行尾 。如果您使用内置转换,这就是您在 存储库 中实际获得的内容。但是我们必须区分 repository 中的内容和 work-tree.
中的内容
您不使用存储库中的文件,因为它们不适合工作。您使用工作树中的文件。而且,在某种意义上,Git甚至不存储文件,因为Git存储的基本单位是commit[=120] =].但是提交本身确实存储文件(快照),所以从这个意义上说,Git 存储文件。只是他们一次全部提交,或者 none 全部提交。
每个 Git 提交中的文件都以特殊的、只读的、Git-only 的压缩形式存储。您计算机上的其他程序,包括您的编辑器和文件查看器,无法使用这些文件。1 它们非常适合存档,但完全无用,至少就它们自己而言, 新 工作已完成。
因此,当您使用 git checkout
选择特定提交时,Git 提取 这些文件。它们来自提交,从特殊的、只读的、Git-only、冻干格式,到普通的普通文件。您计算机上的 每个 程序都可以使用这些未压缩和再水化的文件。这些是您将看到和使用的文件,Git 将它们复制到您的 工作树: 您工作的区域。
工作树实际上并不是存储库的一部分。而且,当 Git 根据 .gitattributes
或 core.autocrlf
或您可以选择的任何其他选项更改文件格式时,仅 Git 在将文件从索引复制到工作树时以及将文件从工作树复制到索引时执行它们。我们还没有触及索引,但现在是时候了。
1一些编辑可能可以,在这一点上:如果没有GNU-emacs模式供查看,我会感到惊讶Git 内部对象,例如。 :-) 但大多数一般情况下不能,也不需要。
索引位于提交和工作树之间
也许最好用一句话来描述索引,即构建下一次提交的地方。这个东西——Git 以不同的方式称为 index、staging area 或(现在很少)cache——其实还有很多作用。特别是在处理有冲突的合并时,它非常重要。但出于我们的目的,我们只关心它位于已提交文件和这些文件的工作树副本之间的事实。2
即:当您要求 Git 签出特定提交时,Git 所做的是 copy3 存储在那个提交到索引中的文件。但是,与提交中的冻结文件不同,索引 中的副本可以 被覆盖。然后,将提交复制到索引后,Git 现在将索引的文件复制到工作树。
最后一步——将索引文件复制到工作树——是 Git 进行行尾转换的时候。 这里Git只能进行一种转换:它可以将以换行符结尾的行转换为以 CRLF 结尾的行。
现在您的所有文件都在您的工作树中,您可以随心所欲地处理它们。您可以保持行尾相同,或根据需要更改它们。您可以批量替换文件或使用编辑器或任何您想要的方式编辑它们。它们只是 个文件,它们完全在您的控制之下。
虽然您已经更改了这些文件,但您可能希望您的下一个提交具有更新的文件。在这里,您必须 运行 git add
:git add
所做的是将工作树文件复制到索引中。这将压缩文件并以其他方式 Git 化文件,因此它现在在索引中处于冻干 格式 ,准备提交。4 并且,这里 Git 中只有一个内置转换: 它可以用仅换行符的行结尾替换 CRLF 行结尾。
Git 无法将 更改为 CRLF 结尾 在存储库中
注意 Git 中内置的两个转换。 所有的控件设置,无论是否在.gitattributes
中,都只是打开或关闭这些转换设置。 Git 要么在出路时将换行符转换为 CRLF(从索引到工作树),要么不这样做。 Git 要么在从工作树到索引的过程中将 CRLF 变成换行符,要么不这样做。 Git 无法在索引中将换行符结尾转换为 CRLF 结尾。
当然,您可以简单地不使用 Git 中内置的转换。但是,如果您想 使用 CRLF 结尾,但 存储 — 在存储库中 — 仅换行结尾,您 可以 安排它发生。这里真正的问题是:
- 你关心 存储库 中的内容、内部提交,还是只关心 工作树 中的内容?
- 如果您关心存储库中的内容,您希望 存储库 中的提交内容是什么?
- 如果 Git 偏爱的仅换行结尾在存储库中是可以接受的,只要您在工作树中获得 CRLF 结尾,您是否愿意为进行这些转换支付少量费用?
如果最后一个问题的答案是可以接受并且是的,那么忘记 存储库 中的内容并专注于在 .gitattributes
中获得正确的设置. Git 将在文件提取操作和 git add
操作期间执行要求的转换。
如果第二个问题的答案是您关心 存储库 中的内容,并且您想要 CRLF 结尾,那么您可能不应该使用 Git'内置转换。您可以编写自己的 smudge 和 clean 过滤器来执行您想要的操作:使您的 "clean" 过滤器存储行带有 CRLF 结尾。 (事实上没有内置的方法可以做到这一点,这意味着如果你认为你想要那个,你应该非常确定:Git 的人确实试图很好地涵盖 Windows 和 MacOS。)
2从某种意义上说,索引不是必需的。其他版本控制系统在没有一个的情况下也能正常工作。但在这里,我们必须了解它,因为这就是所有这些东西在 Git.
中的实际运作方式
3Git 实际上并没有复制它们。由于它们的脱水/冻干形式,Git 只能参考 提交的文件。索引中的内容实际上是 Git 内部 blob 对象 哈希 ID,加上每个文件的名称,再加上很多 make-it-go-fast cache数据,全部按照适合Git的方式排列,不适合其他任何东西。但是除非你开始查看索引的部分,例如 git ls-files --stage
或 git update-index
,否则 none 确实很重要。您可以将索引中的内容视为文件的副本,这一切都解决了。
4从技术上讲,git add
创建一个新的 blob 对象,或者重新使用一些现有的 blob 对象(如果有)内容正确的一个。然后它将 blob 散列放入索引中,如脚注 3 中所述。但是您可以再次将其视为复制操作:结果相同。
我有一个存储库,其中包含 7 个带有 CRLF
的文件以及带有 LF
的所有其他文件。我正在研究 mac,默认情况下,它使用 LF
.
当我在 git
上提交更改并将其推送到 Github 并且我的同事拉出分支时,这 7 个文件显示为 LF
.
我想做的是能够像我的 mac 一样提交所有内容(即 7 个文件 CRLF
和其他所有文件 LF
)并确保当有人在 mac 或 linux 上拉我的分支时,他们得到的结果与我承诺的完全一样?请记住,我已经使用 LF
(意外)提交了这 7 个文件,因为我不知道 git 是如何改变这些东西的。所以,我需要确保更改也到达远程分支。
我读了一些 QA,但大部分都混淆了 core.autocrlf
和 .gitattributes
。非常感谢任何有关如何实现此目标的帮助 and/or 解释。
假设 CRLF 行尾很重要且不应转换,使用 .gitattributes
文件将是最安全的,该文件将覆盖本地 git 设置。
您可以按照 Github docs 中的说明创建 .gitattributes
文件。例如,如果您的 CRLF 文件共享一个通用后缀:
# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf
这里你必须要小心,因为 Git 有一些内置的转换,他们 强烈支持 LF-only 行尾 。如果您使用内置转换,这就是您在 存储库 中实际获得的内容。但是我们必须区分 repository 中的内容和 work-tree.
中的内容您不使用存储库中的文件,因为它们不适合工作。您使用工作树中的文件。而且,在某种意义上,Git甚至不存储文件,因为Git存储的基本单位是commit[=120] =].但是提交本身确实存储文件(快照),所以从这个意义上说,Git 存储文件。只是他们一次全部提交,或者 none 全部提交。
每个 Git 提交中的文件都以特殊的、只读的、Git-only 的压缩形式存储。您计算机上的其他程序,包括您的编辑器和文件查看器,无法使用这些文件。1 它们非常适合存档,但完全无用,至少就它们自己而言, 新 工作已完成。
因此,当您使用 git checkout
选择特定提交时,Git 提取 这些文件。它们来自提交,从特殊的、只读的、Git-only、冻干格式,到普通的普通文件。您计算机上的 每个 程序都可以使用这些未压缩和再水化的文件。这些是您将看到和使用的文件,Git 将它们复制到您的 工作树: 您工作的区域。
工作树实际上并不是存储库的一部分。而且,当 Git 根据 .gitattributes
或 core.autocrlf
或您可以选择的任何其他选项更改文件格式时,仅 Git 在将文件从索引复制到工作树时以及将文件从工作树复制到索引时执行它们。我们还没有触及索引,但现在是时候了。
1一些编辑可能可以,在这一点上:如果没有GNU-emacs模式供查看,我会感到惊讶Git 内部对象,例如。 :-) 但大多数一般情况下不能,也不需要。
索引位于提交和工作树之间
也许最好用一句话来描述索引,即构建下一次提交的地方。这个东西——Git 以不同的方式称为 index、staging area 或(现在很少)cache——其实还有很多作用。特别是在处理有冲突的合并时,它非常重要。但出于我们的目的,我们只关心它位于已提交文件和这些文件的工作树副本之间的事实。2
即:当您要求 Git 签出特定提交时,Git 所做的是 copy3 存储在那个提交到索引中的文件。但是,与提交中的冻结文件不同,索引 中的副本可以 被覆盖。然后,将提交复制到索引后,Git 现在将索引的文件复制到工作树。
最后一步——将索引文件复制到工作树——是 Git 进行行尾转换的时候。 这里Git只能进行一种转换:它可以将以换行符结尾的行转换为以 CRLF 结尾的行。
现在您的所有文件都在您的工作树中,您可以随心所欲地处理它们。您可以保持行尾相同,或根据需要更改它们。您可以批量替换文件或使用编辑器或任何您想要的方式编辑它们。它们只是 个文件,它们完全在您的控制之下。
虽然您已经更改了这些文件,但您可能希望您的下一个提交具有更新的文件。在这里,您必须 运行 git add
:git add
所做的是将工作树文件复制到索引中。这将压缩文件并以其他方式 Git 化文件,因此它现在在索引中处于冻干 格式 ,准备提交。4 并且,这里 Git 中只有一个内置转换: 它可以用仅换行符的行结尾替换 CRLF 行结尾。
Git 无法将 更改为 CRLF 结尾 在存储库中
注意 Git 中内置的两个转换。 所有的控件设置,无论是否在.gitattributes
中,都只是打开或关闭这些转换设置。 Git 要么在出路时将换行符转换为 CRLF(从索引到工作树),要么不这样做。 Git 要么在从工作树到索引的过程中将 CRLF 变成换行符,要么不这样做。 Git 无法在索引中将换行符结尾转换为 CRLF 结尾。
当然,您可以简单地不使用 Git 中内置的转换。但是,如果您想 使用 CRLF 结尾,但 存储 — 在存储库中 — 仅换行结尾,您 可以 安排它发生。这里真正的问题是:
- 你关心 存储库 中的内容、内部提交,还是只关心 工作树 中的内容?
- 如果您关心存储库中的内容,您希望 存储库 中的提交内容是什么?
- 如果 Git 偏爱的仅换行结尾在存储库中是可以接受的,只要您在工作树中获得 CRLF 结尾,您是否愿意为进行这些转换支付少量费用?
如果最后一个问题的答案是可以接受并且是的,那么忘记 存储库 中的内容并专注于在 .gitattributes
中获得正确的设置. Git 将在文件提取操作和 git add
操作期间执行要求的转换。
如果第二个问题的答案是您关心 存储库 中的内容,并且您想要 CRLF 结尾,那么您可能不应该使用 Git'内置转换。您可以编写自己的 smudge 和 clean 过滤器来执行您想要的操作:使您的 "clean" 过滤器存储行带有 CRLF 结尾。 (事实上没有内置的方法可以做到这一点,这意味着如果你认为你想要那个,你应该非常确定:Git 的人确实试图很好地涵盖 Windows 和 MacOS。)
2从某种意义上说,索引不是必需的。其他版本控制系统在没有一个的情况下也能正常工作。但在这里,我们必须了解它,因为这就是所有这些东西在 Git.
中的实际运作方式3Git 实际上并没有复制它们。由于它们的脱水/冻干形式,Git 只能参考 提交的文件。索引中的内容实际上是 Git 内部 blob 对象 哈希 ID,加上每个文件的名称,再加上很多 make-it-go-fast cache数据,全部按照适合Git的方式排列,不适合其他任何东西。但是除非你开始查看索引的部分,例如 git ls-files --stage
或 git update-index
,否则 none 确实很重要。您可以将索引中的内容视为文件的副本,这一切都解决了。
4从技术上讲,git add
创建一个新的 blob 对象,或者重新使用一些现有的 blob 对象(如果有)内容正确的一个。然后它将 blob 散列放入索引中,如脚注 3 中所述。但是您可以再次将其视为复制操作:结果相同。