【发布时间】:2018-03-23 13:26:05
【问题描述】:
我有一个包含 5 个已使用 CRLF 提交的文件的存储库。我不知道这是怎么发生的,但是如果我使用这个命令,它会打印 5 个文件(数百个):
git grep -I --files-with-matches --perl-regexp '\r' HEAD
有谁知道如何重现此问题?换句话说,什么是一组 git 设置会导致这种情况?
【问题讨论】:
标签: git gitattributes core.autocrlf
我有一个包含 5 个已使用 CRLF 提交的文件的存储库。我不知道这是怎么发生的,但是如果我使用这个命令,它会打印 5 个文件(数百个):
git grep -I --files-with-matches --perl-regexp '\r' HEAD
有谁知道如何重现此问题?换句话说,什么是一组 git 设置会导致这种情况?
【问题讨论】:
标签: git gitattributes core.autocrlf
在内部,Git 只存储原始数据。如果您运行 git hash-object -w,您可以将任何您喜欢的 blob 数据推送到存储库中(尽管您随后需要附加标签,或者将 blob 添加到索引中以将其存储到新的提交中)。
正如我在对What does "check out code" mean in git documentation for line endings? 的回答中指出的那样,当您在该文件上运行git add 时,Git 将在启用了此类翻译的任何文件上应用 CRLF-to-LF-only line-endings 翻译。结果是索引中文件的版本(或者更准确地说,索引中的 blob 哈希,表示 in-repo blob 对象)仅具有 LF 行结尾。
如果您在该文件上运行git add:
然后 Git 不会进行这些翻译,文件的索引版本将在工作树版本中包含任何 '\r' 字符。
.gitattributes 和/或core.autocrlf 中的设置控制是否启用翻译,如果启用,则执行哪些翻译。由于历史设置(从 Git 什么都不做,到添加 Windows 支持的早期阶段,通过 Git 的各种中间版本,到当前相当复杂的 .gitattributes 方法),所有这些的规则都非常复杂。
换句话说,什么是一组 git 设置会导致这种情况?
有许多不同的方法可以做到这一点,但迄今为止最简单的一种方法是编写一个.gitattributes 文件,只需:
* -text
或将core.autocrlf 设置为false(但请注意,.gitattributes 通常会覆盖core.autocrlf)。现在 Git 会将所有文件视为二进制文件,在 git add 期间不进行“清理”,在 git checkout 期间不进行“涂抹”。工作树内容现在将逐字节匹配索引内容,除了您自己或通过运行程序对工作树文件所做的任何更改。然后您可以git add 将这些新文件添加到索引中,它会逐字节复制它们;并且您创建的每个新 git commit 都将使用索引中的内容。
一旦您将您关心的特定文件的特定版本存储为永久且不可更改的提交,您可以修改 .gitattributes 以包含您想要测试的任何其他设置,并运行 git checkout <commit> -- <path> 以制作 Git 副本文件从提交到索引,通过污迹过滤器,然后进入工作树。您可以以任何您喜欢的方式修改任何工作树文件,然后运行git add <path> 以通过清理过滤器运行文件以将其复制到索引中。这些过滤器将由您在.gitattributes 中的所有内容控制在您运行命令时,因此您可以尝试不同的属性而无需进行新的提交。
【讨论】:
core.autocrlf=true (windows) / core.autocrlf=input (linux) 以上是否可以得出以下结论:没有办法(使用标准 git 客户端)执行包含 CRLF 的提交, 并且没有 .gitattributes 存在?
git add 重新放入索引,则索引版本继续以 CRLF 结尾,并且下一次提交使用索引版本。此时没有设置问题:下一次提交的内容与上一次提交中的内容相同。
您可能正在使用git config --global core.autocrlf true
如需更好的解释,请查看docs。
【讨论】: