TL;DR
创建一个过滤器驱动程序加上.gitattributes:创建一个运行tr '\n' '\r'的涂抹过滤器和一个运行tr '\r' '\n'的清洁过滤器,并标记文件( s) 在使用此过滤器时有问题。使用仅 LF 行结尾将文件存储在 Git 中。 (过滤器驱动程序在.git/config 或$HOME/.gitconfig 文件中定义,文件的名称或名称模式在.gitattributes 中。)
长
如您所见,Git 强烈喜欢以换行符结尾的行。 (它可以与换行符分隔的行一起使用,其中最后一行缺少终止符,但这意味着添加一行会导致上一个最后一行发生更改,因为它现在有一个换行符终止符,而新的最后一行缺少换行符终止符。)这对单个快照无关紧要,但对产生有用的差异很重要。
现代 MacOS 和其他人一样使用换行符。只有古老的向后兼容格式才有 CR-only 行尾。参见,例如,this SuperUser Stack Exchange web site posting。
Git 没有内置 过滤器来转换或从此类行尾转换。然而,Git确实有一个通用机制用于对工作树文件进行更改。
请记住,当 Git 将任何文件存储在快照中时,该文件由 Git 所称的 blob 对象表示,该对象在内部存储在一个特殊的、压缩的(有时是高度压缩的)Git-只有形式。这种形式对任何东西但 Git 没有用处,因此当您以有用的形式获取文件时(例如,通过git checkout),Git 会将它们扩展为您计算机的常用形式。同时,任何时候你把一个像这样的普通文件转换为仅 Git 的形式,Git 都会将文件压缩成它的仅 Git 形式。每当您使用 git add 将文件复制回 Git 的 index 时,就会发生这种情况。
每个文件的索引副本在您拥有工作树时就存在,就像提交的副本一样。索引副本采用相同的仅 Git 格式。这里的关键区别在于提交的副本不能更改,但索引副本可以更改。运行git commit 会拍摄索引中的任何内容的快照当时,并将其作为新提交的新快照。因此,索引充当将进入下一次提交的内容。使用git checkout,您将一些现有的提交复制到到索引中,并让Git将其展开到工作树中;然后使用git add,您可以选择性地将特定索引副本替换为您已更改的工作树文件的压缩版本。
这种与索引和工作树之间的复制是进行 Windows 风格的 LF 到 CRLF 转换的理想点,反之亦然,所以这就是 Git 执行此操作的地方。如果你有一些 other 转换要执行,而不是直接内置到 Git 中,这就是你告诉 Git 去做的地方。
涂抹并清洁过滤器
涂抹过滤器是 Git 在将文件从压缩索引副本转换为工作树副本时应用的过滤器。在这里,如果您选择用 CRLF Windows 样式的行尾或分隔符替换换行符,Git 有一个内部转换器可以做到这一点:eol=crlf。 clean filter 是 Git 在将文件从未压缩的工作树副本转换为压缩的索引副本时应用的过滤器;再次在这里,eol=crlf 指示 Git 进行反向转换。
如果您想用 CR-only 替换换行符,您必须发明自己的转换器。假设您将整个过程称为convert-cr:
*.csv filter=convert-cr
(而不是*.csv eol=crlf)。这一行进入.gitattributes(这是一个可提交的文件,你应该提交它)。
现在您必须定义convert-cr 过滤器。这在 Git 配置文件中,在这里我们发现了一个小缺陷:配置文件不可提交。这是一个安全问题:Git 将在此处运行任意命令,如果我可以提交此文件并克隆它,您将运行 I 指定的命令,而没有机会先审查它们。因此,您必须自己将其放入您的.git/config,或放入您的全局配置中(例如git config --global --edit):
[filter "convert-cr"]
clean = tr '\r' '\n'
smudge = tr '\n' '\r'
现在,当 Git 将 from Git-only 格式转换时,它会将换行符转换为 CR,并且每当 Git 将 to Git-only 格式转换时,它将转换 CR换行。
这对现有的存储文件没有帮助
您今天拥有的任何现有快照,其中包含\r,都会以这种方式永久存储。 Git 永远不会更改任何现有的存储文件!存储的数据是宝贵且不可侵犯的。您对此无能为力。好吧,几乎什么都没有:您可以完全丢弃这些提交,而改用新的和改进的提交。但这很痛苦:每个提交都会记住它的 父 提交,因此如果您替换存储库中的早期提交,则必须替换 每个 子、孙等,所以他们都记得这个新的提交序列。 (git filter-branch 完成这项工作。)
但是,您可以指示 Git 如何diff 现有提交中的特定文件,也可以使用 .gitattributes 和 diff 驱动程序。有多种方法可以做到这一点,但最简单的是定义一个 textconv 属性,它将“二进制”文件(例如其存储版本可能包含 CR-only 字符的文件)转换为文本(面向行,即基于换行)文件。此处使用的 textconv 过滤器与 smudge 过滤器完全相同。
更多详情,请参阅the gitattributes documentation。