如何让git了解Mac(CR)行结尾

问题描述 投票:1回答:1

由于某些原因,我的一个文件包含旧式Mac行结尾(在OSX上编辑之后)。这些是“CR”(回车)字符,并在git diff中显示为^ M.

Git不明白它们是行结束代码(它真的有多难?)并将整个文件解释为单行。

我知道我可以将文件转换为LF或CRLF结尾,然后将它们提交回来,但是由于git自动将我的Windows(CRLF)行结尾转换为LF,我希望它也会处理CR行结尾。否则听起来像功能不完整。

有没有办法让git将CR解释为行尾?

git macos cross-platform compatibility line-endings
1个回答
1
投票

TL;DR

创建一个过滤器驱动程序加上.gitattributes:创建一个运行tr '\n' '\r'的涂抹过滤器和一个运行tr '\r' '\n'的干净过滤器,并使用此过滤器标记有问题的文件。使用仅LF的行结尾将文件存储在Git中。 (过滤器驱动程序在.git/config$HOME/.gitconfig文件中定义,文件的名称或名称模式在.gitattributes中。)

Long

如您所见,Git强烈倾向于使用换行终止线。 (它可以使用换行符分隔的行,其中最后一行缺少终结符,但这意味着添加一行会导致对前一行的更改,因为它现在有一个换行终止符,而新的最后一行丢失新行终止符。)这对于单个快照无关紧要,但对于生成有用的差异很重要。

与其他人一样,现代MacOS使用换行符。只有古老的向后兼容格式才有CR专线结尾。参见,例如,this SuperUser Stack Exchange web site posting

Git没有用于转换到这种行结尾的内置过滤器。但是,Git具有用于在工作树文件中进行更改的通用机制。

请记住,当Git在快照中存储任何文件时,该文件由Git称为blob对象的内容表示,该对象内部存储在一个特殊的,压缩的(有时是高度压缩的)仅Git形式中。除了Git之外,这个表单对任何东西都没有用,所以当你以有用的形式获取文件时 - 例如通过git checkout-Git将它们扩展为它们通常的计算机形式。同时,每当你采用这样的普通文件并将其转换为仅Git形式时,Git会将文件压缩为仅Git形式。每当您使用git add将文件复制回Git的索引时,就会发生这种情况。

当工作树就位时,每个文件的索引副本都存在,就像提交的副本一样。索引副本采用相同的Git格式。这里的关键区别是无法更改提交的副本,但可以更改索引副本。运行git commit会获取该点右侧索引中的所有内容的快照,并使其成为新提交的新快照。因此,索引将作为将进入下一次提交的内容。使用git checkout,将一些现有的提交复制到索引中,让Git将其扩展到工作树中;然后使用git add,您可以选择使用已更改的工作树文件的压缩版本替换特定索引副本。

这种与索引和工作树的复制,是进行Windows式LF到CRLF转换的理想点,反之亦然,因此这就是Git所做的事情。如果你有其他转换要执行,而不是直接内置到Git,那么你可以告诉Git这样做。

Smudge and clean filters

涂抹过滤器是Git在将文件从压缩索引副本转换为工作树副本时应用的过滤器。在这里,如果您选择使用CRLF Windows样式的行enders-or-separator替换换行符,Git会有一个内部转换器来执行此操作:eol=crlf。干净的过滤器是Git在将文件从未压缩的工作树副本转换为压缩索引副本时应用的过滤器;在这里,eol=crlf指示Git进行向后转换。

如果要使用仅CR替换换行符,则必须创建自己的转换器。假设您将整个过程称为convert-cr

*.csv   filter=convert-cr

(而不是*.csv eol=crlf)。这行进入.gitattributes(这是一个可提交的文件,你应该提交它)。

现在你必须定义convert-cr过滤器。这是一个Git配置文件,在这里我们发现一个小缺陷:配置文件不能提交。这是一个安全问题:Git将在这里运行任意命令,如果我可以提交此文件并将其克隆,您将运行我指定的命令,而不会有机会先审查它们。因此,您必须自己将其放入.git/config,或者放入全局配置(例如git config --global --edit):

[filter "convert-cr"]
    clean = tr '\r' '\n'
    smudge = tr '\n' '\r'

现在,只要Git转换为仅Git格式,它就会将换行转换为CR,每当Git转换为仅Git格式时,它都会将CR转换为换行符。

This does not help with existing stored files

您今天拥有\r的任何现有快照都将永久存储。 Git永远不会改变任何现有的存储文件!存储的数据非常珍贵且不受侵犯。你无能为力。好吧,几乎没有任何东西:你可以完全抛弃这些提交,改为使用新的和改进的提交。但是这非常痛苦:每次提交都会记住它的父提交,所以如果你替换你的存储库中的早期提交,你必须替换每个子,孙等,以便他们都记住这个新的提交序列。 (git filter-branch做这个工作。)

但是,您可以使用.gitattributes和diff驱动程序指示Git如何在现有提交中区分特定文件。有多种方法可以做到这一点,但最简单的方法是定义一个textconv属性,它将“二进制”文件(例如存储版本可能只有CR字符的文件)转换为文本(面向行,即基于换行的文件。此处使用的textconv过滤器与涂抹过滤器完全相同。

有关更多详细信息,请参阅the gitattributes documentation

© www.soinside.com 2019 - 2024. All rights reserved.