157

我在 git 中跟踪一个 Virtual PC 虚拟机文件 (*.vmc),在进行更改后,git 将该文件识别为二进制文件并且不会为我区分它。我发现该文件是用 UTF-16 编码的。

可以教 git 识别这个文件是文本并适当地处理它吗?

我在 Cygwin 下使用 git,core.autocrlf 设置为 false。如有必要,我可以在 UNIX 下使用 mSysGit 或 git。

4

9 回答 9

92

我已经为这个问题苦苦挣扎了一段时间,刚刚发现(对我来说)一个完美的解决方案:

$ git config --global diff.tool vimdiff      # or merge.tool to get merging too!
$ git difftool commit1 commit2

git difftool采用相同的参数git diff,但运行您选择的差异程序而不是内置的 GNU diff。所以选择一个多字节感知差异(在我的例子中,vim在差异模式下)并使用git difftool而不是git diff.

发现“difftool”太长而无法输入?没问题:

$ git config --global alias.dt difftool
$ git dt commit1 commit2

吉特摇滚。

于 2009-08-19T15:55:47.223 回答
73

有一个非常简单的解决方案可以在 Unices 上开箱即用。

例如,使用 Apple 的.strings文件:

  1. .gitattributes在存储库的根目录中创建一个文件:

     *.strings diff=localizablestrings
    
  2. 将以下内容添加到您的~/.gitconfig文件中:

     [diff "localizablestrings"]
     textconv = "iconv -f utf-16 -t utf-8"
    

来源Git 中的 Diff .strings 文件(以及2010 年的旧帖子)。

于 2014-01-09T12:42:45.740 回答
43

您是否尝试过将其设置.gitattributes为将其视为文本文件?

例如:

*.vmc diff

更多详细信息,请访问 http://www.git-scm.com/docs/gitattributes.html

于 2009-04-22T16:42:22.537 回答
32

默认情况下,它看起来git不适用于 UTF-16;对于这样的文件,您必须确保未对其进行任何CRLF处理,但您希望diffmerge作为普通文本文件工作(这忽略了您的终端/编辑器是否可以处理 UTF-16)。

但是查看.gitattributes手册页,这是自定义属性binary

[attr]binary -diff -crlf

所以在我看来,您可以在顶层定义一个自定义属性(.gitattributesutf16注意,我在此处添加合并以确保将其视为文本):

[attr]utf16 diff merge -crlf

从那里您可以在任何.gitattributes文件中指定如下内容:

*.vmc utf16

另请注意,您仍然应该能够访问diff文件,即使git认为它是二进制文件:

git diff --text

编辑

这个答案基本上说带有 UTF-16 甚至 UTF-8 的 GNU diff 不能很好地工作。如果您想git使用不同的工具来查看差异(通过--ext-diff),该答案建议使用 Guiffy

但是您可能需要的只是diff一个仅包含 ASCII 字符的 UTF-16 文件。使其工作的一种方法是使用--ext-diff以下 shell 脚本:

#!/bin/bash
diff <(iconv -f utf-16 -t utf-8 "$1") <(iconv -f utf-16 -t utf-8 "$2")

请注意,转换为 UTF-8 也可能适用于合并,您只需确保它在两个方向上都完成。

至于查看 UTF-16 文件的差异时到终端的输出:

尝试像这样区分会导致二进制垃圾喷到屏幕上。如果 git 使用的是 GNU diff,那么 GNU diff 似乎不支持 unicode。

GNU diff 并不真正关心 unicode,因此当您使用 diff --text 时,它只是区分并输出文本。问题是您使用的终端无法处理发出的 UTF-16(结合 ASCII 字符的差异标记)。

于 2009-04-22T16:40:54.583 回答
11

git 最近开始理解 utf16 等编码。查看gitattributes文档,搜索working-tree-encoding

[确保您的手册页匹配,因为这是相当新的!]

如果(比如说)文件是 UTF-16,在 Windows 机器上没有 BOM,那么添加到您的.gitattributes文件中

*.vmc text working-tree-encoding=UTF-16LE eol=CRLF

如果 *nix 上的 UTF-16(带 bom)使它:

*.vmc text working-tree-encoding=UTF-16-BOM eol=LF

(替换为您需要处理的类型文件*.vmc*.whateverwhatever

请参阅:支持工作树编码“UTF-16LE-BOM”


稍后添加

关注@Hackslash,可能会发现这还不够

 *.vmc text working-tree... 

要获得漂亮的文本差异,您需要

 *.vmc diff working-tree...

把这两个作品以及

 *.vmc text diff working-tree... 

但可以说是

  • 冗余——eol=...意味着text
  • 冗长——一个大型项目很容易有几十种不同的文本文件类型

问题

Git 有一个宏属性 binary,意思是-text -diff. 相反+text +diff的内置不可用,但 git 提供了用于合成它的工具(我认为!)

解决方案

Git 允许定义新的宏属性。

我建议.gitattributes你拥有的文件的顶部

 [attr]textfile text diff

然后对于需要是文本和差异的所有路径

 path textfile working-tree-encoding= eol=...

请注意,在大多数情况下,我们需要默认编码(utf-8)和默认 eol(本机),因此可能会被删除。

大多数线条应该看起来像

*.c textfile
*.py textfile
Etc

为什么不只使用差异?

实用:在大多数情况下,我们需要原生 eol。这意味着没有eol=...。所以text不会被暗示,需要明确说明。

概念:文本与二进制是根本区别。eol,编码,差异等只是它的一些方面。

免责声明

由于我们生活在一个奇怪的时代,我没有一台带有当前工作 git 的机器。所以我目前无法检查最新添加的内容。如果有人发现有问题,我会修改/删除。

于 2019-02-14T05:02:18.513 回答
8

解决办法是过滤掉cmd.exe /c "type %1"。cmd 的type内置函数将进行转换,因此您可以将其与 git diff 的 textconv 功能一起使用,以启用 UTF-16 文件的文本差异(也应与 UTF-8 一起使用,尽管未经测试)。

引用 gitattributes 手册页:


执行二进制文件的文本差异

有时希望查看某些二进制文件的文本转换版本的差异。例如,可以将文字处理器文档转换为 ASCII 文本表示,并显示文本的差异。尽管这种转换会丢失一些信息,但生成的差异对于人类查看很有用(但不能直接应用)。

textconv 配置选项用于定义执行此类转换的程序。该程序应采用单个参数,即要转换的文件的名称,并在标准输出上生成结果文本。

例如,要显示文件的 exif 信息而不是二进制信息的差异(假设您安装了 exif 工具),请将以下部分添加到您的$GIT_DIR/config文件(或$HOME/.gitconfig文件)中:

[diff "jpg"]
        textconv = exif

mingw32 的解决方案,cygwin 粉丝可能不得不改变方法。问题在于传递文件名以转换为 cmd.exe - 它将使用正斜杠,并且 cmd 假定反斜杠目录分隔符。

步骤1:

创建将转换为标准输出的单参数脚本。c:\path\to\some\script.sh:

#!/bin/bash
SED='s/\//\\\\\\\\/g'
FILE=\`echo $1 | sed -e "$SED"\`
cmd.exe /c "type $FILE"

第2步:

设置 git 以便能够使用脚本文件。在你的 git config ( ~/.gitconfigor .git/configor see man git-config) 中,输入:

[diff "cmdtype"]
textconv = c:/path/to/some/script.sh

第 3 步:

通过使用 .gitattributes 文件指出要应用此工作的文件(请参阅 man gitattributes(5)):

*vmc diff=cmdtype

然后git diff在您的文件上使用。

于 2009-07-09T03:48:46.320 回答
4

我编写了一个小的 git-diff 驱动程序,to-utf8它应该可以轻松区分任何非 ASCII/UTF-8 编码的文件。您可以使用此处的说明安装它:https ://github.com/chaitanyagupta/gitutils#to-utf8 (该to-utf8脚本在同一个仓库中可用)。

请注意,此脚本要求系统上同时提供fileiconv命令。

于 2013-04-02T08:37:01.467 回答
3

最近在 Windows 上遇到了这个问题,而 git for windows 附带的dos2unixand unix2dosbins 解决了这个问题。默认情况下,它们位于C:\Program Files\Git\usr\bin\. 请注意,这仅在您的文件不需要是 UTF-16 时才有效。例如,有人在不需要时(在我的情况下)意外地将 python 文件编码为 UTF-16。

PS C:\Users\xxx> dos2unix my_file.py
dos2unix: converting UTF-16LE file my_file.py to ANSI_X3.4-1968 Unix format...

PS C:\Users\xxx> unix2dos my_file.py
unix2dos: converting UTF-16LE file my_file.py to ANSI_X3.4-1968 DOS format...
于 2018-07-24T15:46:20.727 回答
1

如其他答案中所述,git diff 不会将 UTF-16 文件作为文本处理,这使得它们在 Atlassian SourceTree 中不可见。如果文件名/或后缀已知,则以下修复将使这些文件在 SourceTree 下正常可见和可比较。

如果 UTF-16 文件的文件后缀是已知的(例如 *.uni),那么所有具有该后缀的文件都可以与 UTF-16 到 UTF-8 转换器相关联,并进行以下两个更改:

  1. 使用以下行在存储库的根目录中创建或修改 .gitattributes 文件:

     *.uni diff=utf16
    
  2. 然后使用以下部分修改用户主目录 (C:\Users\yourusername\.gitconfig) 中的 .gitconfig 文件:

    [diff=utf16]
        textconv = "iconv -f utf-16 -t utf-8"
    

这两项更改应立即生效,无需将存储库重新加载到 SourceTree。它将文本转换应用于所有 *.uni 文件,使它们像其他文本文件一样可查看和可比较。如果其他文件需要这种转换,您可以在 .gitattributes 文件中添加额外的行。(如果指定的文件不是 UTF-16,您将获得该文件的不可读结果。)

请注意,此答案是对 Tony Kuneck 答案的简化重写。

于 2021-03-29T14:51:59.527 回答