git 中的自定义行结尾(LF 和 CR+LF 除外)

Custom line-endings in git (other than LF and CR+LF)

我被聘为顾问,与一家大公司使用的糟糕内部 DSL 一起工作。

我说很糟糕,因为代码行不是用回车 returns 或换行符来结束每行代码,而是用五个字符的 ASCII 字符串 <EOL> 分隔。这些文件有数千 "lines" 长。任何嵌入的回车 returns 或换行符都会导致解释器崩溃。

我无法更改他们的解释器或语言,但我需要使用用这种语言编写的大量 (>100 MB) 代码库。

在对此代码进行任何更改之前,我想将其放入 git 存储库中以进行跟踪。有没有办法告诉 git 字符串 <EOL> 代表行尾,就像您可以用 core.eol=lf 指定 LFCR+LF 一样?例如,core.eol="<EOL>"。如果是这样,这将使我的生活在两个方面变得更轻松:

  1. 它将使合并和差异智能地工作; git 会知道 "lines" 在哪里。
  2. 我可以(例如)签入以 <EOL> 作为行尾的原始代码,然后在另一台设置了 core.eol=lf 的机器上签出,然后 git 将转换自动来回。 (我可以使用常规文本编辑器和常规工具!)

我确实认识到这是一个小众的边缘案例。我也明白我可以添加一个中间处理步骤来在与 git 交互之前来回转换,但我想避免这种情况,除非绝对必要,因为我更愿意将他们现有的代码库直接导入 git ] 无需先对其进行预处理。

如果此功能不可用,我什至更愿意创建 git 的自定义版本而不是添加额外的处理步骤,所以如果有人知道其中可能涉及哪些复杂性,我会很感兴趣在了解这些。

此自定义过滤器设置将导致 *.dsl 个文件在 Git 存储中包含 <EOL>,但在您的工作目录中检出时 \ngit diff 等工具将在签出版本(例如 \n)上运行。那是你想要的吗?

~/.gitconfig.git/config

[filter "crazy-eol"]
    clean = awk 'BEGIN{ORS="<EOL>"}1'
    smudge = awk 'BEGIN{RS="<EOL>"}1'
[diff "crazy-eol"]
    textconv = awk 'BEGIN{RS="<EOL>"}1'

.gitattributes.git/info/attributes

*.dsl filter=crazy-eol diff=crazy-eol

有一种方法可以做到这一点。这一点都不方便,如果文字字符串 <EOL> 确实 出现在一行中,则 运行 存在进行不可逆更改的风险(尽管根据您对 DSL 的描述,这似乎不可能发生。

不过,您不能使用 core.eol 设置。您将需要使用 smudgeclean 过滤器。查看the gitattributes documentation中的描述。您的两个过滤器会将 <EOL> 转换为换行,反之亦然。事实上,这正是 core.eolcore.autocrlf 以及 text 转换过滤器所做的:它们在一个或另一个方向上用 \n 替换 \r\n,只是正如您在一个方向或另一个方向将 <EOL> 替换为 \n 一样。事实上,如果你进一步查看文档,在 "Interaction between checkin/checkout attributes" 部分,你会看到 Git 只是有一个 text 过滤器,它的作用就像一个干净的 and/or 涂抹过滤器,作为管道的一部分。

在你做任何这些之前,考虑...

在你为此烦恼之前,考虑一下你自己的一次性传球。一旦你有了 "normal" 形式的文件,你就可以 Git-ize 那些。在处理这些文件之前,您总是可以 运行 您自己的消毒剂。然后,一旦你准备好文件,你 运行 他们通过 "insanitizer" 回到疯狂的 <EOL> 格式,完全在 Git 之外。

我认为这个(外部 sanitizer/insanitizer)会更容易使用,真的。