如何在 git 上使用 CRLF 提交文件?

How can a file be committed with CRLF on git?

我有一个包含 5 个已使用 CRLF 提交的文件的存储库。我不知道这是怎么发生的,但是如果我使用这个命令,在干净的结账时它会打印 5 个文件(数百个):

git grep -I --files-with-matches --perl-regexp '\r' HEAD

有谁知道我该如何重现这个问题?换句话说,会导致这种情况的一组 git 设置是什么?

您可能正在使用 git config --global core.autocrlf true

要获得更好的解释,请查看 docs

在内部,Git 只存储原始数据。如果你 运行 git hash-object -w 你可以将任何你喜欢的 blob 数据推送到存储库中(尽管你需要附加一个标签,或者将 blob 添加到索引以将其存储到新的提交中) .

正如我在对 的回答中指出的那样,Git 将在启用此类翻译的任何文件上应用 CRLF-to-LF-only 行尾翻译,当时您运行 git add 在该文件上。结果是索引中文件的版本(或更准确地说,索引中的 blob 散列,表示存储库中的 blob 对象)具有仅 LF 行结尾。

如果您 运行 git add 在该文件上使用:

  • 全局禁用翻译,或
  • 在该特定路径名上禁用翻译

然后 Git 不会 进行这些翻译,文件的索引版本 有任何 '\r' 它在工作树版本中的字符。

.gitattributes and/or core.autocrlf 中的设置控制是否启用翻译,如果启用,则执行哪些翻译。由于历史设置(从Git什么都没做,到早期添加Windows支持,通过Git的各种中间版本,到现在相当复杂的.gitattributes 方法)所有这些的规则都相当复杂。

In other words what is a set of git settings that can lead to this situation?

有很多不同的方法,但最简单的方法是编写一个 .gitattributes 文件,只需:

* -text

或将 core.autocrlf 设置为 false(但请注意,通常 .gitattributes 会覆盖 core.autocrlf)。现在 Git 会将所有文件视为二进制文件,在 git add 期间不执行 "cleaning",在 git checkout 期间不执行 "smudging"。工作树内容现在将逐字节匹配索引内容,除了您自己或 运行ning 程序对工作树文件所做的任何更改。然后你可以 git add 那些新文件到索引,它会逐字节复制它们;您创建的每个新 git commit 都将使用索引中的内容。

一旦您将您关心的特定文件的特定版本存储为永久且不可更改的提交,您可以修改 .gitattributes 以包含您想要测试的任何其他设置,并且 运行 git checkout <commit> -- <path> 使 Git 将文件从提交复制到索引,通过模糊过滤器,然后复制到工作树中。您可以随意修改任何工作树文件,然后 运行 git add <path> 到 运行 通过清理过滤器将文件复制到索引中。这些过滤器将由您在 运行 命令 时 .gitattributes 中的任何内容控制,因此您可以试验不同的属性而无需进行新的提交.