我能让 git 将 UTF-16文件识别为文本吗?

我正在跟踪一个 Virtual PC 虚拟机文件(* 。在 git 中,在做了一个更改之后,git 将该文件标识为二进制文件,并且不会对其进行区分。我发现这个文件是用 UTF-16编码的。

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

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

77131 次浏览

默认情况下,看起来 git与 UTF-16不能很好地工作; 对于这样的文件,你必须确保没有对它进行 CRLF处理,但是你希望 diffmerge作为一个正常的文本文件工作(这忽略了你的终端/编辑器是否可以处理 UTF-16)。

但是看看 .gitattributes手册,下面是自定义属性 binary:

[attr]binary -diff -crlf

因此,在我看来,您可以在顶级 .gitattributes中为 utf16定义一个自定义属性(注意,我在这里添加 merge 是为了确保它被当作文本处理) :

[attr]utf16 diff merge -crlf

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

*.vmc utf16

还要注意的是,即使 git认为它是二进制文件,您仍然应该能够使用以下命令执行 diff文件:

git diff --text

剪辑

这个答案 基本上说明了使用 UTF-16或甚至 UTF-8的 GNU diff 并不能很好地工作。如果你想让 git使用不同的工具来看到差异(通过 --ext-diff) ,这个答案建议使用 吉菲

但是您可能需要的仅仅是 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 感知能力。

GNUdiff 实际上并不关心 unicode,所以当您使用 diff-text 时,它只是差异和输出文本。问题是您正在使用的终端无法处理发出的 UTF-16(与 ASCII 字符的 diff 标记结合在一起)。

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

例如:

*.vmc diff

详情请浏览 http://www.git-scm.com/docs/gitattributes.html

解决方案是通过 cmd.exe /c "type %1"过滤。Cmd 的 type内置函数将执行转换,因此您可以使用 git diff 的 textconv 功能来支持 UTF-16文件的文本差异(应该也可以使用 UTF-8,尽管未经测试)。

引自 gitAttribute 手册页:


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

有时候,我们希望看到一些二进制文件的文本转换版本的差异。例如,文字处理器文档可以转换为 ASCII 文本表示形式,以及所示文本的差异。尽管这种转换会丢失一些信息,但是产生的 diff 对于人类查看是有用的(但是不能直接应用)。

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

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

[diff "jpg"]
textconv = exif

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

第一步:

创建单个参数脚本,该脚本将执行到 stdout.c: path 到一些 script.sh 的转换:

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

第二步:

设置 git 以便能够使用脚本文件。在你的 git 配置(~/.gitconfig或者 .git/config或者参见 man git-config)中,放入以下内容:

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

第三步:

通过使用. gitproperties 文件指出应用此解决方案的文件(参见 man gitproperties (5)) :

*vmc diff=cmdtype

然后对你的文件使用 git diff

我为这个问题苦苦挣扎了一段时间,终于(对我而言)找到了一个完美的解决方案:

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

git difftool采用与 git diff相同的参数,但是运行自己选择的 diff 程序,而不是内置的 GNUdiff。因此,选择一个多字节感知的 diff (在我的例子中,是 diff 模式下的 vim) ,只使用 git difftool而不是 git diff

发现“ deftool”太长而无法打字? 没问题:

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

饭桶石头。

我已经编写了一个小的 git-diff 驱动程序 to-utf8,它可以很容易地区分任何非 ASCII/UTF-8编码的文件。您可以使用这里的说明安装它: https://github.com/chaitanyagupta/gitutils#to-utf8(to-utf8脚本可以在同一个回购中获得)。

注意,这个脚本需要 fileiconv命令在系统上都可用。

有一个非常简单的解决方案,工程的方框在 Unice。

例如,苹果的 .strings文件只有:

  1. 用以下方法在存储库的根目录中创建一个 .gitattributes文件:

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

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

资料来源 : Git 中的 Diff. string 文件(和2010年的 老职位)。

最近在 Windows 上出现了这个问题,装有用于 Windows 的 git 的 dos2unixunix2dos垃圾箱解决了这个问题。默认情况下,它们位于 C:\Program Files\Git\usr\bin\中。例如,有人在不需要的时候(在我的例子中)意外地将 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...

Git 最近已经开始理解像 utf16这样的编码。 查看 GitAttrips文档,搜索 working-tree-encoding

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

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

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

如果 UTF-16(with bom) on * nix,那么应该是:

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

(对于需要处理的 whatever类型文件,将 *.vmc替换为 *.whatever)

见: 支持工作树编码“ 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

为什么不用 diff 呢?

实用: 在大多数情况下,我们需要本地的 eol。也就是说没有 eol=...。因此,text不会被暗示,而是需要被明确地表达出来。

概念: 文本和二进制文件是最基本的区别。 eol,编码,diff 等等只是它的一些方面。

免责声明

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

如其他答案所述,git diff 不将 UTF-16文件作为文本处理,这使得它们在 Atlassian SourceTree 中不可见,例如。如果文件名/或后缀已知,下面的修复程序将使这些文件在 SourceTree 下可见,并且通常具有可比性。

如果已知 UTF-16文件的文件后缀(* 。那么所有带有该后缀的文件都可以与 UTF-16到 UTF-8转换器相关联,只需要进行以下两项更改:

  1. 在存储库的根目录中创建或修改. gitproperties 文件,代码如下:

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

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

这两个更改应该立即生效,而不需要将存储库重新加载到 SourceTree 中。它将文本转换应用于所有 * 。Uni 文件,使他们像其他文本文件一样可视和可比较。如果其他文件需要此转换,可以向。属性文件。(如果指定的文件不是 UTF-16,则该文件的结果将无法读取。)

请注意,这个答案是对托尼 · 库内克的答案的简化重写。

关于 GitAttrips的 git 文档给出了关于编码主题的简短而漂亮的解释-

Git 识别 ASCII 或其超集中编码的文件(例如。 UTF-8,ISO-8859-1,...)作为文本文件 编码(例如 UTF-16)被解释为二进制,因此 内置的 Git 文本处理工具(例如 Git diff)和大多数 Git 一样 网页前端不可视化这些文件的内容 违约。

但是,working-tree-encoding属性允许您告诉 Git 哪些文件在存储到存储库之前应该被重新编码(UTF-8)。它们稍后在“复制”到 工作目录时被“返回”到它们的原始编码。

免责声明 -(也许)这里的一切都已经在其他的回答中说过了,有些甚至给出了更多关于如何解决你的问题的细节。然而,我引用的这句话让我意识到“ Git 能够处理 UTF-8以外的编码吗?”在浏览了几个小时之后。