我可以让git识别UTF-16文件为文本吗?


140

我正在git中跟踪Virtual PC虚拟机文件(* .vmc),进行更改后git将该文件标识为二进制文件,因此不会对我造成影响。我发现该文件使用UTF-16编码。

可以教git识别该文件是文本并适当处理吗?

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

Answers:


83

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

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

git difftool接受相同的参数git diff,但是运行您选择的diff程序而不是内置的GNU diff。因此,选择一个可识别多字节的diff(在我的情况下vim为diff模式),然后使用git difftool代替git diff

查找“ difftool”太长而无法键入?没问题:

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

吉特岩石。


1
但是,这不是一个完美的解决方案(宁愿有一个滚动的统一差异),但鉴于选择和我不愿意找到新安装的东西,这是比较小的邪恶。“ vimdiff”,是!(yea,vim ... and git)
Roboprog 2011年

1
这是否也可以用于暂存和提交仅一部分UTF16文件?
Ortwin Gentz '11年

我使用Beyond Compare作为差异和合并工具。来自.gitconfig <pre> <code> [difftool“ bc3”]路径= c:/程序文件(x86)/超越比较3 / bcomp.exe [mergetool“ bc3”]路径= c:/程序文件(x86)/ Beyond Compare 3 / bcomp.exe </ code> </ pre>
Tom Wilson

@Tom Wilson对不起,无法通过缩进4个空格来格式化代码块!
汤姆·威尔逊

我有git的基本知识,不确定它如何处理文件更改。是否总是以二进制文件或文本(ASCII)格式进行特殊处理/检测更改?
i486

63

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

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

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

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

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

资料来源:Git中的Diff .strings文件(以及2010年以来的旧文章)。


我这样做了,但是git拒绝在此之后运行。我得到的错误是“ /Users/myusername/.gitconfig中错误的配置文件第4行”。我使用“ git config --global --edit”打开我的gitconfig文件。有趣的是,如果我删除添加的行,则一切正常。有什么线索吗?
shshnk 2014年

如果您复制/粘贴,我将猜测智能报价。我编辑了答案以解决此问题。
Lou Franco

这就像一种魅力,为了简单和更好地集成,应该接受它。我看不到“使用其他工具”如何回答“我可以让git识别UTF-16文件为文本吗?”的答案。
itMaxence

@itMaxence严格来说,iconv是“另一个工具”,与Vim或Beyond Compare是相同的方式(不是git套件的一部分)。
Agi Hammerthief

@AgiHammerthief确定再次阅读后我同意,不知道我在想什么。FWIW vimdifficonv都已经出现在MacOS,所以你不必费心琢磨让他们在哪里,他们做的工作
itMaxence

39

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

例如:

*.vmc diff

有关更多详细信息,请参见http://www.git-scm.com/docs/gitattributes.html


2
此方法有效,但为正确起见,请注意,它设置了两个属性:setdiff...
确定。

2
此解决方案是我唯一可以接受的解决方案。按@ OK评论,“设置”在这里无关紧要,只是*.vmc diff*.sql diff等被设置为指定路径的“差异”属性需要。(我无法编辑答案)。但是有2个警告:差异显示为每个字符之间有一个空格,对于那些有问题的文件,不可能“大块头”或“舍弃大块头”。
Pac0

30

默认情况下,它似乎git不适用于UTF-16。对于这样的文件,您必须确保没有对其进行任何CRLF处理,但是您想要diff并且merge要像普通的文本文件一样工作(这将忽略您的终端/编辑器是否可以处理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效果不是很好。如果您想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时,它只是进行diff并输出文本。问题是您使用的终端无法处理发出的UTF-16(与ASCII字符的差异标记结合使用)。


尝试像这样进行比较会导致二进制垃圾涌入屏幕。如果git使用的是GNU diff,那么看来GNU diff不支持unicode。
skiphoppy

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

@ jared-oberhaus-是否有一种仅对某些类型的文件(即给定的扩展名)触发此脚本的方法?
特里

8

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

引用gitattributes手册页:


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

有时希望看到一些二进制文件的文本转换版本的差异。例如,可以将文字处理器文档转换为ASCII文本表示形式,并显示文本的差异。即使此转换丢失了一些信息,所得的差异对于人类查看也是有用的(但不能直接应用)。

textconv config选项用于定义执行此转换的程序。该程序应采用一个参数,即要转换的文件名,并在stdout上生成结果文本。

例如,要显示文件的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中(~/.gitconfig.git/config参见man git-config),将其放入:

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

第三步:

通过使用.gitattributes文件指出要将此工作对象应用到的文件(请参见man gitattributes(5)):

*vmc diff=cmdtype

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


几乎托尼Kuneck的,但没有“C:/path/to/some/script.sh” entropy.ch/blog/Developer/2010/04/15/...
阿列克谢Shumkin

我在Windows上的Git上面显示的脚本有一些问题,但是我发现以下内容很好,并且可以处理路径中的空格:cmd //c type "${1//\//\\}"
patthoyts

这将无需创建脚本文件即可工作:textconv = powershell -NoProfile -Command \"& {Get-Content \\$args[0]}\"
Jakub Berezanski 2015年

5

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

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

如果(说)该文件是Windows计算机上没有BOM的UTF-16,则添加到您的.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 = ...表示文本)和冗长的(大型项目可能很容易拥有数十种不同的文本文件类型!)

我建议的解决方案是在gitattributes文件的早期使用:

 [attr]textfile text diff

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

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

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

免责声明:由于我们生活在离奇的时代,我没有工作的git。因此,我目前无法检查。如果有人发现问题,我会修改/删除。

注意:为什么不只使用diff?

实用:在大多数情况下,我们希望使用天然eol。这意味着没有“ eol = ...”。因此,文本不会被隐含,需要明确地放置。

概念上:文本与二进制是基本区别。eol,encoding,diff等只是其中的一些方面。


要使用我的UTF-16LE-BOM文件,我必须使用*.vmc diff working-tree-encoding=UTF-16LE-BOM eol=CRLF
HackSlash

@HackSlash:感谢您的单挑。我想你是说text一个人没得到很好的文字差异吗?能否请您检查有两个 textdiff一切工作正常?在这种情况下,我会提出不同的建议
Rusi

正确,text单独会导致二进制比较。我可以做diff或者text diff和它的作品。我只需要添加-BOM文件是因为我的文件具有BOM表,即YMMV。
HackSlash

@HackSlash我已经纳入您的发现。如果您可以检查一下,那就太好了!
Rusi

4

我已经编写了一个小的git-diff驱动程序,to-utf8该驱动程序应该可以轻松区分所有非ASCII / UTF-8编码的文件。您可以按照以下说明进行安装:https : //github.com/chaitanyagupta/gitutils#to-utf8(该to-utf8脚本在同一仓库中可用)。

请注意,此脚本需要fileiconv命令都可以在系统上使用。


2

最近在Windows上出现了这个问题,而git附带的Windows的bins dos2unixunix2dosbins 解决了这个问题。默认情况下,它们位于中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...
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.