【问题标题】:git line endings behavior does not match documentationgit 行尾行为与文档不匹配
【发布时间】:2021-04-21 16:02:45
【问题描述】:

我看到 git 用行结尾做事,这似乎与我在本网站和官方文档上看到的一切相矛盾,甚至与它自己的警告消息相矛盾。 (或者也许我在阅读理解方面失败了。)这是一个小的复制品。

# repro.sh
git --version # 2.27.0.windows.1
mkdir empty
cd empty
echo '* text=auto !eol' > .gitattributes
echo hi > t.txt
git init
git config core.autocrlf false # I guess git attributes overrides this anyway?
git add t.txt # wait what?  warning: LF will be replaced by CRLF in t.txt???  I thought git likes LF?
git commit -m 'the plot thickens'
git cat-file -p `git rev-parse HEAD:t.txt` > temp.txt # get raw blob as its really stored, I hope
od -c t.txt # original file in working dir ends in LF
od -c temp.txt # file from git also ends in LF, despite git warning??
# end of script

这有意义吗?我认为 git 有时喜欢在“git add”上将 CRLF 转换为纯 LF,并在结帐时执行相反的操作,但我从未听说过它在 git add 上将纯 LF 转换为 CRLF,因为警告似乎有威胁。然后它不这样做。签入的文件正是我在工作目录中拥有的文件,由 cat-file 验证。那么为什么要警告呢?怎么回事?

【问题讨论】:

    标签: git line-endings


    【解决方案1】:

    消息本身似乎总是有点……错了?奇怪的?措辞不好?——我不知道该怎么称呼它。该消息的意图是警告您某些情况似乎不一致:您将来查看文件的方式可能与您现在查看文件的方式不兼容。

    考虑到这一点,让我们来看看细节:

    echo '* text=auto !eol' > .gitattributes
    

    首先,在text=auto:这将text 属性设置为字符串值auto,它告诉Git:请猜测每个文件是文本还是二进制文件。我个人认为这是一个坏主意:您不希望 Git 猜测。你应该告诉它。 Git 的猜测通常相当不错,但我不喜欢我的软件猜测那么多。 :-)

    无论如何,让我们转到!eol:这意味着将eol 属性设置为未指定 状态。这可能不是你想要的。它开始未指定,因此如果您不想指定它,您可以不指定它。 ! 前缀的存在是为了更正一些以前的设置:例如,如果默认应该是eol=lf,你可能有:

    * eol=lf
    

    但由于不应修改 JPG 文件,因此我们可以仅为 *.jpg 覆盖它:

    *.jpg !eol
    

    (虽然*.jpg binary 可能更好:这意味着-diff -merge -text-text eol 属性变得不相关)。

    所以,到目前为止,我们得到的是:当且仅当 Git 猜测它是文本时,文件才是文本,并且 eol 属性未指定

    git config core.autocrlf false # I guess git attributes overrides this anyway?
    

    text 属性专门覆盖了这个。 The gitattributes documentation 部分表示:

    如果未指定 text 属性,Git 使用 core.autocrlf配置变量判断文件是否 应该转换。

    这并没有说明如果text 属性是指定的 会发生什么(它是,auto),但稍微回顾一下,我们发现text=auto

    如果 Git 确定内容是文本,则在签入时将其行尾转换为 LF。使用 CRLF 提交文件后,不会进行任何转换。

    这里只讨论checkin。文档没有这么说,但这确实是在 git add 期间,Git 可能会将 CRLF 变成 LF-only。

    git add t.txt # wait what?  warning: LF will be replaced by CRLF in t.txt???
    

    Git 在git add 期间发出这些警告(除非它们通过其他配置被抑制),当它发现任何可疑时。警告是或至少包括您所看到的,我有时称之为措辞不当(因为没有更好的术语)。不过,我没有更好的方式来表达它们,而不是太冗长以至于它变得有问题。

    警告:详细 = 此处有问题的描述 ?

    只有两个内置的 LF/CRLF 转换:

    • 将 CRLF 转换为仅 LF 的“正在进行中”的转换:仅在 git add 期间发生这种情况,并且仅在需要或似乎需要调用时才发生。

    • 将 LF-only 转换为 CRLF 的“即将退出”转换:这发生在 git checkoutgit reset --hardgit restore(如果使用显式或隐含的 --worktree 运行)和其他类似操作期间.但是,就像正在进行的 CRLF 到 LF 转换一样,它只有在需要或似乎需要时才会发生。

    这里发生的情况是,Git 怀疑您将在未来某个时间发生 LF 到 CRLF 的转换。我认为你的设置现在没有这样配置,因为你有!eol并且在Linux上(你在Linux上?也许不是:你在版本字符串中说windows)。所以也许你的设置现在这样配置的,因为你有!eol并且在Windows上。我不使用 Windows,所以我不确定 Windows 上的默认设置是什么

    与此同时,t.txt,在您的索引和工作树中都可以看到,具有纯 LF-only 行结尾。如果 Git 执行一个在途的 LF 到转换(从索引副本到工作树副本),你的 工作树 中的 t.txt 文件会突然有 CRLF 行结尾.

    这就是这个警告信息的意思。如果将来 Git 对文件进行文本转换,则提取 Git 索引中现在的内容的结果将与 工作树中的 actual 文件不匹配 现在。 Git可以在这里进行的一种转换是将 LF-only 转换为 CRLF,t.txt 目前是 LF-only。

    到最后几个步骤

    git commit -m 'the plot thickens'
    

    这里的情节并没有真正变厚。所有转换都发生在此之前。提交命令仅获取存储在 Git 索引中的 t.txt 文件(这是 Git 索引中的唯一文件,因为存储库是全新的)并从中进行提交。

    git cat-file -p `git rev-parse HEAD:t.txt` > temp.txt
    # get raw blob as its really stored, I hope
    

    确实如此,是的。您同样可以从索引中获取:t.txt,或使用git ls-files --stage 获取blob 哈希ID。

    注意git commit 步骤没有修改工作树副本。它仍然没有受到影响。要强制 Git 将索引副本提取回工作树,首先删除工作树副本,然后使用任何将重新创建它的 Git 命令。这将运行提取步骤,该步骤将(或不会)根据您的各种配置要求将 LF-only 转换为 CRLF:

    rm t.txt
    git checkout -- t.txt
    

    您现在可以使用od 或类似名称查看发生了什么。 \n 变成 \r\n 了吗?这告诉你 Git 如何解释你当前的设置(core.autocrlfcore.eol,以及.git/info/attributes.gitattributes 中的各种属性)。

    注意:git ls-files --eol 从 Git 2.8 开始,能够告诉你更多关于这里发生的事情。它将分别:

    • 检查索引中的内容;
    • 检查工作树中的内容;和
    • 查看适用的属性

    到当前在索引中的每个文件。

    【讨论】:

    • 首先...哇,这是一个彻底的答案!我几乎在每个段落中都学到了一些新东西。其次,在我忘记之前:是的,我的意思是“添加 t.txt”。谢谢你读心术:) 我编辑了这个问题以减少读心术。第三:我确实在窗户上。我刚刚尝试了 git checkout -- t.txt ,实际上我以 crlf 行结尾结束了。我觉得我终于开悟了。
    • 第四:我想我有一种方法可以让信息更清晰,而不会让它变得太长:“LF 将在下次检出此文件时被 CRLF 替换”。换句话说,强调转换将在以后发生,而不是暗示它现在正在发生。如果要简洁,这只是两个额外的词:“结帐时”。
    • 现在生活又变得有意义了,我想知道是否有办法重新命名这个问题以提高可搜索性。我觉得这个答案应该是任何涉及此警告的搜索的第一个结果。说真的,这是一个非常彻底的答案。
    • @MarkVY:我喜欢这个消息建议。您可以考虑将它作为 Git 的补丁提供给 Git 邮件列表。 (为 Git 发送修复程序是……一项巨大的时间投资/浪费时间,但可以帮助很多人。)
    • 也许我可以简单地提出改进的措辞而不制作实际的补丁,希望官方维护者会喜欢它并自己创建补丁?
    猜你喜欢
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 1970-01-01
    • 2020-08-14
    • 2013-06-22
    • 1970-01-01
    相关资源
    最近更新 更多