如何在Mac上用CRLF提交一些文件,用LF提交其他文件



我有一个repo,它包含7个带有CRLF的文件和其他带有LF的文件。我在一个默认使用LF的mac上工作。

当我在git上提交我的更改并将其推送到Github,并且我的同事提取分支时,这7个文件显示为LF

我想做的是能够在我的mac上原样提交所有内容(即使用CRLF的7个文件和使用LF的其他所有文件),并确保当有人在mac或linux上拉我的分支时,他们得到的内容与我提交的内容完全相同?请记住,我已经用LF提交了这7个文件(意外),因为我不知道git是如何改变这些东西的。因此,我需要确保更改也能到达远程分支。

我读了一些QA,但大多混淆了core.autocrlf.gitattributes。我们非常感谢任何关于如何实现这一目标的帮助和/或解释。

这里你必须小心,因为Git有一些内置转换,他们强烈支持仅LF行结尾。如果您使用内置的转换,这就是您在存储库中实际得到的。但我们必须区分存储库工作树中的内容。

您不能处理存储库中的文件,因为它们不适合进行工作。您使用工作树中的文件。而且,从某种意义上说,Git甚至不存储文件,因为Git存储的基本单元是提交。但是提交本身确实存储(文件的快照),所以从这个意义上说,Git存储文件。只是它们一次都是承诺,或者没有承诺。

每个Git提交中的文件都以一种特殊的、只读的、仅限Git的压缩形式存储。计算机上的其他程序,包括编辑器和文件查看器,无法使用这些文件1它们非常适合存档,但对于完成任何新的工作来说,它们完全无用,至少就它们自己而言。

因此,当您使用git checkout来选择特定的提交时,Git会提取这些文件。它们来自提交,从特殊的、只读的、仅Git的、冻干的格式,到普通的文件。这些未压缩和重新水合的文件可以被计算机上的每个程序使用。这些是你将看到并使用的文件,Git将它们复制到你的工作树中:你工作的区域。

工作树实际上并不是存储库的一部分。而且,当Git根据.gitattributescore.autocrlf或您可以选择的任何其他选项更改文件格式时,Git仅在将文件从索引复制到工作树以及将文件从工作树复制到索引时执行这些操作。我们还没有谈到这个指数,但现在是时候这么做了。


1一些编辑器可能可以,在这一点上:例如,如果没有GNUemacs模式来查看Git内部对象,我会感到惊讶。:-)但一般来说,大多数人不能,也不需要。


索引位于提交和工作树之间

用一句话来说,索引最好被描述为构建下一个提交的地方。这个东西——Git以各种方式调用索引暂存区或(现在很少)缓存——实际上有多个功能。尤其是在处理冲突合并时,这一点非常关键。但出于我们的目的,我们只关心它位于提交的文件和这些文件的工作树副本之间的事实2

也就是说:当你要求Git检查一个特定的提交时,Git所做的就是3中存储的文件复制到索引中。不过,与提交中的冻结文件不同,索引中的副本可以被覆盖。然后,在将提交复制到索引之后,Git现在将索引的文件复制到工作树中。

最后一步——将索引文件复制到工作树——是Git进行行尾转换的时候Git在这里只能自己做一个转换:它可以将换行的行转换为CRLF终止的行。

现在所有文件都在工作树中,您可以随心所欲地处理它们。您可以保持行尾不变,也可以根据自己的喜好进行更改。您可以批量替换文件,也可以使用编辑器或任何您想要的工具进行编辑。它们只是文件,完全在您的控制之下。

不过,现在您已经更改了这些文件,您可能希望您的下一次提交具有更新的文件。在这里,您必须运行git addgit add所做的是将工作树文件复制到索引中。这会压缩文件,否则会对文件进行Git-ifie,因此它现在在索引中处于冷冻干燥的格式,准备提交4而且,这里只有一个内置在Git中的转换:它可以用换行符替换CRLF的行尾。

Git无法在存储库中将更改为CRLF结尾

请注意Git中内置的两个转换所有控件设置,无论是否在.gitattributes中,都只是打开或关闭这些转换设置。要么Git在从索引到工作树的过程中将换行符转换为CRLF,要么它不这样做。要么Git在从工作树到索引的过程中将CRLF变成换行符,要么它没有。Git在索引中没有将换行符结尾转换为CRLF结尾的过程。

当然,您可以简单地不使用Git中内置的转换。但是,如果您想使用CRLF结尾,而存储——在存储库中——仅换行结尾,则可以安排这种情况发生。这里真正的问题是:

  • 您关心存储库中的内容、提交内部的内容,还是只关心work-tree中的内容
  • 如果您关心存储库中的内容,那么您希望存储库中的提交内容是什么
  • 如果Git喜欢的仅换行符结尾在存储库中是可以接受的,那么只要你在工作树中得到CRLF结尾,你愿意为进行这些转换支付少量成本吗

如果最后一个问题的答案是可以接受并且是的,那么忘记存储库中的内容,集中精力在.gitattributes中获得正确的设置。Git将在文件提取操作和git add操作期间执行调用的转换。

如果第二个问题的答案是你关心存储库中的内容,并且你想要CRLF结尾,那么你可能不应该使用Git的内置转换。您可以编写自己的smootclean过滤器来执行您想要的操作:使您的"干净"过滤器存储行具有CRLF结尾。(事实上,没有内置的方法可以做到这一点,这意味着如果你认为你想要这样做,你应该非常确定:Git的人确实试图很好地覆盖Windows和MacOS。)


2从某种意义上说,索引不是必需的。其他版本控制系统在没有版本控制的情况下也可以正常工作。但在这里,我们必须了解它,因为这就是所有这些东西在Git中的实际工作方式。

3Git实际上并没有复制它们。由于它们的脱水/冻干形式,Git只能引用提交的文件。索引中真正的是Git内部blob对象哈希ID,加上每个文件的名称,再加上许多快速缓存数据,所有这些都以适合Git的方式排列,不适合其他任何东西。但是,除非您开始查看索引的各个部分,例如git ls-files --stagegit update-index,否则这些都不重要。你可以把索引中的内容想象成文件的副本,一切都会好起来。

4从技术上讲,git add生成一个新的blob对象,或者如果有一个具有正确内容的对象,则重新使用一些现有的blob对象。然后,它将blob散列放入索引中,如脚注3所示。但你也可以把它看作一个复制操作:它的效果是一样的。

假设CRLF行尾很重要,不应该转换,那么使用.gitattributes文件将最安全,因为它将覆盖本地git设置。

您可以创建.gitattributes文件,如Github文档中所述。例如,如果您的CRLF文件共享一个通用后缀:

# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf

最新更新