【问题标题】:Why does Git treat this text file as a binary file?为什么 Git 将此文本文件视为二进制文件?
【发布时间】:2011-10-14 21:42:19
【问题描述】:

我想知道为什么 git 会告诉我这个?

$ git diff MyFile.txt
diff --git a/MyFile.txt b/MyFile.txt
index d41a4f3..15dcfa2 100644
Binary files a/MyFile.txt and b/MyFile.txt differ

它们不是文本文件吗?

我检查了.gitattributes,它是空的。为什么我会收到此消息?,我不能再像以前那样获得差异了

添加:

我注意到文件权限中有一个@,这是什么?,这可能是原因吗?

$ls -all
drwxr-xr-x   5 nacho4d  staff    170 28 Jul 17:07 .
drwxr-xr-x  16 nacho4d  staff    544 28 Jul 16:39 ..
-rw-r--r--@  1 nacho4d  staff   6148 28 Jul 16:15 .DS_Store
-rw-r--r--@  1 nacho4d  staff    746 28 Jul 17:07 MyFile.txt
-rw-r--r--   1 nacho4d  staff  22538  5 Apr 16:18 OtherFile.txt

【问题讨论】:

  • 它可能是一个 UTF-8 编码的文件。
  • 应该是UTF16 little endian LF
  • 来自 Mac OS X 上的 ls 手册页:如果文件或目录具有扩展属性,则由 -l 选项打印的权限字段后跟 @ 字符。使用选项-@ 查看这些扩展属性。
  • 我认为这可能是 git 的错误。我删除了扩展属性,现在一切都很好了。
  • @nacho4d:这很奇怪,因为 git 甚至不应该知道有任何扩展属性。如果您可以复制它,那么值得在 git 邮件列表中提出。正如vger.kernel.org 列表中的良好习惯一样,您不必订阅帖子(人们会让您抄送您的答案),并且应该不会考虑到git@vger.kernel.org 列表的相当大的数量。跨度>

标签: git binary


【解决方案1】:

这只是意味着当 git 检查文件的实际内容时(它不知道任何给定的扩展名不是二进制文件 - 如果你想告诉你可以使用属性文件它明确 - 请参阅手册页)。

检查了文件的内容后,它发现了一些不是基本 ascii 字符的内容。作为 UTF16,我希望它会有“有趣”的字符,所以它认为它是二进制的。

如果您的文件具有国际化 (i18n) 或扩展字符格式,有多种方法可以告诉 git。我对设置的确切方法还不够了解-您可能需要 RT[Full]M ;-)

编辑:快速搜索 SO 找到了 can-i-make-git-recognize-a-utf-16-file-as-text,这应该会给你一些线索。

【讨论】:

  • 您几乎但并非完全没有错。 Git 确实检查了实际文件并在那里看到了“有趣”的字符。但是它并不“认为” UTF-16 是二进制的。它 二进制的,因为文本被定义为基于 ASCII 的(这是内置 diff 将给出可用结果的唯一内容)而 UTF-16 不是。是的,有一种方法可以告诉 git 对模式定义的文件使用特殊差异(使用.gitattributes)。
  • 我应该补充一点,“有趣的字符”实际上意味着零字节。
  • 我们都是对的,但观点不同。我们都说“Git 检查内容以确定其类型”。我们都说要让 git 知道它应该被视为 UTF16,用户需要通过 .gitattributes 等告诉 git。
  • @JanHudec:在您看来,所有文件都是二进制文件。
  • @stolosvik,(和 JanH)这是一个更微妙的中间地带,因为 UTF-8 包括基本的 0-127 ASCII 字符和所有其他 Unicode 字符,而不需要 null (00h)除 nul 字符(“C”字符串终止符)以外的任何内容的字节。因此,Git 的文本定义是在 utf-8 编码时内容(以及前 1k 字节)不应有空字节。尝试stackoverflow.com/questions/2241348/… 进行有趣的阅读。我原来的评论是指 UTF-16 编码数据被视为字节对的情况,因此 ascii 代码点的高字节将为 00。
【解决方案2】:

如果你的文本文件中有一个超长的行,Git 甚至会确定它是二进制的。我分解了一个长字符串,把它变成了几行源代码,突然文件从“二进制”变成了我可以看到的文本文件(在 SmartGit 中)。

所以不要在编辑器中不按“Enter”就一直往右边输入太远 - 否则稍后 Git 会认为你已经创建了一个二进制文件。

【讨论】:

  • 这是一个正确的信息。我试图控制一个非常大的 MySQL 转储(.sql 文件)的差异,但 git 将其视为二进制文件,即使它只有 ASCII/UTF8 数据。原因是行超长(插入值(一),(二),(三),(...),(300万...);奇怪的是,对于每次提交,git存储库都会没有增加 1.7gb,但只有 ~350mb。也许,git 在保存之前压缩了“二进制”文件。
  • @AlexandreT。 Git 确实会压缩文件 blob(使用 GZip、IIRC)。
【解决方案3】:

在新编辑器中编辑我的一个文件后,我遇到了同样的问题。原来新编辑器使用的编码(Unicode)与我的旧编辑器(UTF-8)不同。所以我只是告诉我的新编辑器用 UTF-8 保存我的文件,然后 git 再次正确地显示我的更改并且没有将其视为二进制文件。

我认为问题只是 git 不知道如何比较不同编码类型的文件。因此,您使用的编码类型实际上并不重要,只要它保持一致即可。

我没有对其进行测试,但我确定如果我刚刚使用新的 Unicode 编码提交了我的文件,那么下次我对该文件进行更改时,它会正确显示更改并且不会将其检测为二进制,从那时起,它将一直在比较两个 Unicode 编码文件,而不是 UTF-8 文件与 Unicode 文件。

您可以使用Notepad++ 之类的应用程序轻松查看和更改文本文件的编码类型;在 Notepad++ 中打开文件并使用工具栏中的编码菜单。

【讨论】:

  • Unicode 不是编码。它是一个字符集,UTF-8 是它的一种编码方式,即编码 Unicode 代码点的方式
  • 这并不能解决问题,只能避免它。问题是 git 或其 diff 工具无法正确识别文本文件或不允许用户轻松覆盖其行为。
【解决方案4】:

如果您没有设置文件的类型,Git 会尝试自动确定它,并且行很长的文件,可能还有一些 wide characters(例如 Unicode)被视为二进制文件。使用 .gitattributes 文件,您可以定义 Git 如何解释文件。手动设置 diff 属性可以让 Git 将文件内容解释为文本,并会进行通常的 diff。

只需将 .gitattributes 添加到您的存储库根文件夹并将 diff 属性设置为路径或文件。这是一个例子:

src/Acme/DemoBundle/Resources/public/js/i18n/* diff
doc/Help/NothingToSay.yml                      diff
*.css                                          diff

如果你想检查文件是否设置了属性,你可以在git check-attr的帮助下做到这一点

git check-attr --all -- src/my_file.txt

关于 Git 属性的另一个很好的参考可以在 here 找到。

【讨论】:

  • 这很有帮助,但实际上是不正确的——正确的属性是diff,而不是texttext 属性不会告诉 git 使用文本来区分,而是控制如何处理行尾(标准化为 LF)。有关更多详细信息,请参阅指向 .gitattributes 的链接。
  • 感谢@ErikE。我已根据您的评论和 Git 文档更新了我的帖子。
  • 此外,您可以设置应该执行哪种差异。例如,如果它是一个 xml 文件,您可以使用 diff=xml 而不仅仅是 diff
  • check-attr 的反义词是什么 - 有 set-attr 吗?我最初不小心将一个文件保存为 UTF-16,然后提交并推送它,现在 BitBucket 将其视为 UTF-16,即使在将其重新保存为 UTF-8 后,再次提交并推送它。这基本上使我的拉取请求无法阅读,因为审阅者需要单击每个单独的评论才能添加审阅 cmets。
【解决方案5】:

我只是花了几个小时浏览此列表中的所有内容,试图弄清楚为什么我的解决方案中的一个测试项目没有向资源管理器添加任何测试。

在我的情况下,VS 以某种方式(可能是由于某处糟糕的 git 合并)完全失去了对该项目的引用。它仍在构建中,但我注意到它只构建了依赖项。

然后我注意到它本身并没有显示在依赖项列表中,所以我删除并重新添加了测试项目,我的所有测试最终都显示了。

【讨论】:

  • Visual Studio 在这里真的不相关。
【解决方案6】:

我也遇到了同样的问题。我在谷歌上搜索解决方案时找到了该线程,但我仍然没有找到任何线索。但我想我在研究后找到了原因,下面的例子将清楚地解释我的线索。

    echo "new text" > new.txt
    git add new.txt
    git commit -m "dummy"

目前,文件 new.txt 被视为文本文件。

    echo -e "newer text\000" > new.txt
    git diff

你会得到这个结果

diff --git a/new.txt b/new.txt
index fa49b07..410428c 100644
Binary files a/new.txt and b/new.txt differ

试试这个

git diff -a

你会得到下面

    diff --git a/new.txt b/new.txt
    index fa49b07..9664e3f 100644
    --- a/new.txt
    +++ b/new.txt
    @@ -1 +1 @@
    -new file
    +newer text^@

【讨论】:

    【解决方案7】:

    我遇到了这个问题,Git GUI 和 SourceTree 将 Java/JS 文件视为二进制文件,因此不会显示差异。

    .git/info 中创建一个名为attributes 的文件,内容如下:

    *.java diff
    *.js diff
    *.pl diff
    *.txt diff
    *.ts diff
    *.html diff
    *.sh diff
    *.xml diff
    

    如果您希望将其应用于所有存储库,则可以将文件 attributes 添加到 $HOME/.config/git/attributes

    【讨论】:

    • 另请注意<project-root>/.gitattributes 文件,它使更改对所有贡献者有效,并且仅适用于相关项目。
    • 添加 * diff 对我很有帮助:它显示了所有类型文件的差异。但是您的解决方案更好,因为避免在大型二进制文件中显示不必要的差异。
    • 是的!这有帮助!
    【解决方案8】:

    我们遇到过这种情况,每当我们尝试对其进行更改时,.html 文件都会被视为二进制文件。看不到差异非常不酷。老实说,我没有检查这里的所有解决方案,但对我们有用的是:

    1. 删除文件(实际上是移动到我的桌面)并提交 git deletion。 Git 说Deleted file with mode 100644 (Regular) Binary file differs
    2. 重新添加文件(实际移动 它从我的桌面回到项目中)。 Git 说New file with mode 100644 (Regular) 1 chunk, 135 insertions, 0 deletions 文件 现在添加为常规文本文件

    从现在开始,我在文件中所做的任何更改都将被视为常规文本差异。您也可以压缩这些提交(1、2 和 3 是您所做的实际更改),但我更希望能够在未来看到我所做的事情。挤压 1 和 2 将显示二进制变化。

    【讨论】:

    • 与从 VS 推送的一两个(成功编译的)cpp 文件类似。使 Compare 的 Github gui 变得可笑。在这样的叮咚交流中,一个人不希望成为铃铛上的苍蝇,- VS 一边说它是 Github,而另一边 Github 说它是 VS。 :(
    【解决方案9】:

    尝试使用文件查看编码详情(reference):

    cd directory/of/interest
    file *
    

    它会产生如下有用的输出:

    $ file *
    CR6Series_stats resaved.dat: ASCII text, with very long lines, with CRLF line terminators
    CR6Series_stats utf8.dat:    UTF-8 Unicode (with BOM) text, with very long lines, with CRLF line terminators
    CR6Series_stats.dat:         ASCII text, with very long lines, with CRLF line terminators
    readme.md:                   ASCII text, with CRLF line terminators
    

    【讨论】:

    • file 不是 git 命令。它是一个完全独立的工具,在 Windows 上与 git 一起打包。是否有文档表明这是 git 用于二进制文件检测的内容?
    • 是的 file 是一个 Linux 工具,但它在 C:\Program Files\git\usr\bin 中与 Git 打包在一起
    【解决方案10】:

    我有一个实例,其中 .gitignore 按目的包含一个双 \r(回车)序列。

    该文件被 git 识别为二进制文件。添加.gitattributes 文件有帮助。

    # .gitattributes file
    .gitignore diff
    

    【讨论】:

    • 工作。我还有一个双 \r 来忽略一些操作系统“Icon\r\r”文件。很高兴知道原因和解决方法。
    【解决方案11】:

    如果git check-attr --all -- src/my_file.txt 表明您的文件被标记为二进制文件,而您尚未在.gitattributes 中将其设置为二进制文件,请在/.git/info/attributes 中进行检查。

    【讨论】:

      【解决方案12】:

      将 Aux.js 更改为另一个名称,例如 Sig.js。

      源代码树仍将其显示为二进制文件,但您可以暂存(添加)它并提交。

      【讨论】:

        【解决方案13】:

        这也是由具有 UTF-8 和 BOM 编码的文本文件引起的(至少在 Windows 上)。将编码更改为常规 UTF-8 立即使 Git 将文件视为 type=text

        【讨论】:

        • 我有两个文件被 Notepad++ 识别为 UTF-8 和 BOM 编码。 SourceTree/git 将一个标识为二进制,另一个标识为文本。除了这似乎不是一个完全准确的陈述之外,我没有任何明确的说法。
        【解决方案14】:

        我在粘贴二进制 Kafka 消息中的一些文本时遇到了类似的问题,该消息插入了不可见字符并导致 git 认为该文件是二进制文件。

        我通过使用正则表达式 [^ -~\n\r\t]+ 搜索文件找到了违规字符。

        • [ 匹配此集中的字符
        • ^ 匹配不在此集中的字符
        • -~ 匹配从 ' '(空格)到 '~' 的所有字符
        • \n换行
        • \r回车
        • \t标签
        • ]关闭集
        • + 匹配这些字符中的一个或多个

        【讨论】:

          【解决方案15】:

          我的文件显示为二进制文件的原因(使用git diff 或 SourceTree 的 dI 没有获得差异)是因为相关文件被添加为 Git LFS 文件

          Git(和 SourceTree)似乎无法区分添加到 LFS 的文本文件。然而,经过一番狩猎,我能够通过运行来解决这个问题...... git config --global diff.lfs.textconv cat

          在此处建议的帮助下... https://github.com/git-lfs/git-lfs/issues/440#issuecomment-501007460

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-03-24
            • 1970-01-01
            • 1970-01-01
            • 2016-07-12
            • 1970-01-01
            • 2012-01-25
            • 1970-01-01
            相关资源
            最近更新 更多