代码之家  ›  专栏  ›  技术社区  ›  Rolf

如何让git理解mac(cr)行结尾

  •  1
  • Rolf  · 技术社区  · 6 年前

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

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

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

    有没有办法让git把cr解释为行尾?

    1 回复  |  直到 6 年前
        1
  •  1
  •   torek    6 年前

    DR

    创建筛选器驱动程序升级版 .gitattributes :创建 污迹过滤器 那是跑步 tr '\n' '\r' 和一个 清洁过滤器 那是跑步 tr '\r' '\n' ,并将有问题的文件标记为使用此筛选器。使用仅限lf的行尾将文件存储在git中。(筛选器驱动程序在 .git/config $HOME/.gitconfig 文件和文件的名称或名称模式进入 .gitattributes属性 )

    正如您所看到的,Git非常喜欢以换行结尾的行。(它可以处理换行分隔的行,其中最后一行缺少终止符,但这意味着添加一行会导致对上一个最后一行的更改,因为它现在有一个换行终止符,而新的最后一行缺少换行终止符。)这对e单个快照,但对于产生有用的差异很重要。

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

    Git没有 内置 用于转换此类行尾或从行尾转换的筛选器。吉特 但是,有一个 通用机制 用于更改工作树文件。

    记住,当Git在快照中存储任何文件时,该文件由Git调用的 BLOB对象 它以一种特殊的、压缩的(有时是高度压缩的)仅Git形式存储在内部。此表单对任何内容都无效 但是 Git,所以当您通过 git checkout 例如,Git将它们扩展为计算机的常规形式。同时,任何时候,当您使用这样的普通文件并将其转换为仅Git格式时,Git都会将该文件压缩为仅Git格式。当你把文件复制回Git的时候就会发生这种情况。 指数 使用 git add .

    每个文件的索引副本在工作树就位时就存在,就像提交的副本一样。索引副本采用相同的仅Git格式。这里的关键区别在于提交的副本 不能 被更改,但索引副本 可以 被改变。正在运行 git commit 对索引中的内容进行快照 就在那时 并使其成为新提交的新快照。因此,索引起到了 下一次提交将进行什么 . 使用 Git结账 ,您复制一些现有的提交 进入之内 索引,并让git将其扩展到工作树中;然后使用 Git添加 ,您可以有选择地用已更改的工作树文件的压缩版本替换特定的索引副本。

    这种向索引树和工作树或从索引树和工作树复制是进行Windows样式的LF到CRLF转换的理想点,反之亦然,所以这就是Git所做的。如果你有 其他 要执行的转换,而不是直接内置到Git,这是您告诉Git执行的地方。

    污迹和清洁过滤器

    污迹过滤器 是Git在将文件从压缩索引副本转换为工作树副本时应用的。在这里,如果您选择用CRLF Windows样式的换行符或分隔符替换换行符,那么Git有一个内部转换器可以做到这一点: eol=crlf . 一 清洁过滤器 是Git在将文件从未压缩的工作树副本转换为压缩的索引副本时应用的;这里再次说明, EOL=CRLF 指示Git进行向后转换。

    如果只想用CR替换换行符,就必须发明自己的转换器。假设你称整个过程为 convert-cr :

    *.csv   filter=convert-cr
    

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

    现在您必须定义 转换CR 过滤。这是一个git配置文件,这里我们发现了一个小缺陷:配置文件不可提交。这是一个安全问题:Git将在这里运行任意命令,如果我可以提交这个文件并克隆它,您将运行这些命令 指定,但没有机会先审查它们。所以你必须把这个放进你的 .git/配置 您自己,或进入您的全局配置( git config --global --edit 例如):

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

    现在只要Git转换 仅Git格式,它会将换行符转换为CRS,并且每当Git转换时 仅Git格式,它将CRS转换为换行。

    这对现有存储文件没有帮助

    您今天拥有的任何现有快照 \r 在它们里面,永远以这种方式储存。Git永远不会更改任何现有的存储文件!存储的数据是宝贵的和不可侵犯的。你对此无能为力。嗯,有 几乎 什么都不做:您可以完全放弃这些提交,转而生成新的和改进的提交。但那是非常痛苦的:每一个承诺都会记住 起源 提交,因此如果替换存储库中的早期提交,则必须替换 每一个 孩子、孙子等等,这样他们都能记住这一新的承诺序列。( git filter-branch 做这个工作。)

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

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