【问题标题】:Confused about how to handle line endings in git repo对如何处理 git repo 中的行尾感到困惑
【发布时间】:2021-10-11 06:48:31
【问题描述】:

我对@9​​87654323@ 中的core.autocrlftext 有一些基本知识,但我仍然坚持我的方案。

场景

在我所有的编辑器中,我都使用 CR LF,所以当我修改文件时,它将以 CR LF 结尾保存。但是,我必须定期从 external 源(我的意思是复制)更新我的 repo 中的文件,并且这些文件使用 LF 行结尾。

我的尝试

我认为core.autocrlf=true 对我有用,但不幸的是,这是陷阱:

我的问题是所有复制的文件显示总是变化,无论是否有真正的内容变化,因为行尾变化从 CR LF -> LF

如果我设置了core.autocrlf=input,那么在过度复制之后不会发生错误的更改,但是如果我编辑(甚至添加空格)并保存文件然后撤消编辑并再次保存,它会自动更改为 CR LF(由我的编辑)所以也似乎是 git 的变化,没有真正的内容变化......

问题

维护此 repo 并始终保持提交更改干净的工作流程是什么,这意味着只有文件中的真实内容更改具有清晰的差异信息?

【问题讨论】:

    标签: git line-endings


    【解决方案1】:

    git config core.autocrlf false 仍然是明智的选择。

    我通常会添加一个 .gitattributes,例如:

    *.bat   text eol=crlf
    

    这样,文件就会在git commit上正确转换。

    由于.gitattributes 文件是代码库的一部分,任何克隆存储库的用户都将使用它。

    【讨论】:

      【解决方案2】:

      如果您曾经启用 CRLF 修改,Git 最终会以“首选”内部编码结束,其中保存的文件随着时间的推移具有仅换行(仅 LF)行结尾。

      如果您不希望这种情况发生,并且希望保留所有带有 CRLF 行结尾的文件,在提交中从提交中提取时,永远不要打开任何 CRLF 修改。每当您从其他地方获取文件时,请将其修改为 CRLF 行结尾您曾经让 Git 看到它之前。

      否则,您需要确保 Git 本身存储所有带有仅 LF 行结尾的文件,并安排文本文件(而不是任何其他文件)在 从中提取时具有 CRLF 行结尾 em> 存储库。要从高层次上理解这一点,请记住以下几点:

      • 每次提交都会存储每个文件的完整快照。但是,这些文件与您的计算机使用的格式不同。相反,它们被压缩、Git 化和重复数据删除。重复数据删除尤其有用,因为许多提交与之前的提交具有大部分相同的文件,这意味着 Git 仅在内部存储文件的一个副本

      • 这意味着每个提交就像一个存档(例如 tar 或 zip 文件)。任何现有提交中的内容永远无法更改:即使是 Git 本身也无法更改它。1 但这也意味着您的其他计算机程序甚至都无法读取文件。从字面上看,没有任何东西可以它,只有 Git 可以它。所以档案只是as好的档案:你不能用它们来完成任何新的工作。

      • 因此,为了完成工作,Git 必须提取存档文件。

      提取过程会将存储在提交中的仅 LF 行结尾更改为 CRLF 行结尾。从现在开始,Git 的文件将以这种压缩和去重的形式在内部存储,作为 LF-only 行结尾。 (任何具有 CRLF 行结尾的现有副本都不能更改,因此仍然是 CRLF 结尾,但 new 副本——不是重复使用的旧副本,而是新添加的副本——将是 LF-only。)

      这就是为什么打开 CRLF 修改会造成破坏:所有 现有 提交大概都是 CRLF-only,并且所有 提交都倾向于将文件保存为 LF -只要。如果您根本没有接触过工作树文件,新提交将重新使用旧文件,但如果您已经接触过工作树文件,则会更改文件(因为他们会从 CRLF 对中剥离 CR-s)。您可以选择“一次性撕掉创可贴”(重新添加每个文件,使用git add --renormalize 或类似名称)或让它随着时间的推移发生,但一种或另一种方式 Git 会一直认为你改变了 每个文件的每一行,因为您这样做。

      让我暂停一下脚注,然后进入细节。


      1原因与 Git 在内部存储文件数据的方式有关,将其表示为哈希 ID。如果有任何变化,哈希 ID 也会发生变化,因此这是一个新的附加文件:旧文件仍然存在,具有旧的哈希 ID。


      细节

      我认为core.autocrlf=true 会为我工作......

      可以。我个人认为这是一个坏主意,因为其中的“自动”部分意味着请猜测哪些文件是文本,哪些不是。我不喜欢我的软件猜测。多年来,Git 的猜测能力已经相当不错了,但它仍然会时不时地猜测错误。

      ...如果我设置core.autocrlf=input ...

      再次从高层次的角度来看,我们需要记住提交是 Git 化的,并且每当 Git 执行 CRLF 行敲击时,Git 倾向于将文件存储为 LF -只要。但现在是谈低层次而不是高层次的时候了。

      这里有两个关键步骤:

      • 提取提交:在这里,Git 必须读取 提交 文件(以 Git-only、只读、压缩和去重形式)。这些文件根本不是普通文件。在进行这种扩展时,Git 很容易将 LF-only 替换为 CRLF。

        扩展的结果是您的工作树副本:一个普通文件,您的计算机可以实际使用。这些是您的程序将看到的文件。请注意,此步骤发生在例如git checkoutgit reset --hard 将文件恢复到提交中找到的方式时。

      • 压缩文件以准备将其存储到新的提交中。在这里,Git 必须读取文件的工作树副本。 Git 必须压缩它并检查它是否是重复的。压缩阶段已经在逐字节检查文件,所以 Git 在这一步很容易将 CRLF 替换为 LF-only。

        压缩的结果要么是重复的(完整的带有 CRLF 行尾,如果 Git 没有使用它们工作树副本 CRLF行尾, 或者如果 Git 是 LF-only 行结尾),或者它是一个全新的文件。如果它是重复的,Git 会链接到现有的副本。如果它是全新的,Git 会将其存储起来,随时可以提交。

        请注意,此步骤发生在git add 期间。除了git add 之外,几乎没有什么东西可以重新压缩文件。2 但是,如果您在一个文件上运行git add,而您在您签出后没有接触过 , Git 会注意到你没有碰过它,并且经常会跳过重新压缩的步骤。所以你必须用--renormalize 打败这个优化,或者触摸文件,让Git 真正重新压缩。

      Git 真正确实弄乱行尾的唯一一次是在这两个步骤中。使用 input 作为设置告诉 Git:不要在提取期间执行 LF-to-CRLF,但在提取期间执行 CRLF-to-LF压缩。 仅当您希望所有 存储的 Git 文件永远只使用 LF,并且所有 签出 文件都保持 LF-only 时,这才有用:换句话说,它让您查看是否有已提交的文件具有 CRLF 结尾,因为它们会在您的工作树中以 CRLF 结尾结束。

      除了任何auto 设置之外,您还可以使用.gitattributes 控件来告诉Git 哪些文件要使用 以及当它这样做时要做什么。这里的设置更细一些:

      *.sh text eol=lf
      *.bat text eol=crlf
      *.jpg -text    # or binary
      

      例如告诉 Git 以 .sh 结尾命名的文件将被弄乱(是文本),并且应该只有 LF 行结尾:Git 会在 git add 期间搞乱,但在此期间什么也不做git checkout。同时,带有.bat 结尾的文件将被弄乱,并且应该将提取和添加步骤都弄乱,以便工作树副本具有 CRLF 行结尾,但提交的副本具有仅 LF 行结尾,并且*.jpg文件不应该被弄乱。

      auto 的各种设置意味着:Git,请猜测哪些文件是文本,哪些是二进制文件,并使用操作系统来决定如何处理文本文件。省略 .gitattributesnot 设置 auto 设置(或将它们设置为 false)意味着 Git,不要弄乱我的文件!


      2有一些低级管道命令,例如git hash-file,也可以做到这一点。

      【讨论】:

        猜你喜欢
        • 2021-10-22
        • 2015-10-28
        • 2021-02-04
        • 1970-01-01
        • 1970-01-01
        • 2015-08-23
        • 2017-12-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多