我在git中跟踪虚拟PC虚拟机文件(* .vmc),在进行更改后,git将该文件识别为二进制文件并且不会为我进行区分。我发现该文件是用UTF-16编码的。
可以教git识别这个文件是文本并适当处理它吗?
我在Cygwin下使用git,core.autocrlf设置为false。如果需要,我可以在UNIX下使用mSysGit或git。
我一直在努力解决这个问题,并且刚刚发现(对我来说)一个完美的解决方案:
$ 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
Git岩石。
有一个非常简单的解决方案,在Unices上开箱即用。
例如,使用Apple的.strings
文件:
.gitattributes
文件:
*.strings diff=localizablestrings
~/.gitconfig
文件中:
[diff "localizablestrings"]
textconv = "iconv -f utf-16 -t utf-8"
资料来源:Diff .strings files in Git(以及2010年的older post)。
默认情况下,git
看起来不适用于UTF-16;对于这样的文件,你必须确保没有对它进行CRLF
处理,但你希望diff
和merge
作为普通文本文件工作(这忽略了你的终端/编辑器是否可以处理UTF-16)。
但是看看.gitattributes
manpage,这里是binary
的自定义属性:
[attr]binary -diff -crlf
因此,在我看来,您可以在.gitattributes
的顶级utf16
中定义自定义属性(请注意,我在此处添加合并以确保它被视为文本):
[attr]utf16 diff merge -crlf
从那里你可以在任何.gitattributes
文件中指定类似于:
*.vmc utf16
另请注意,即使diff
认为它是二进制文件,您仍然可以使用git
文件:
git diff --text
编辑
This answer基本上说GNU diff与UTF-16甚至UTF-8都不能很好地工作。如果你想让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字符的diff标记结合)。
解决方案是通过cmd.exe /c "type %1"
过滤。 cmd的type
builtin将进行转换,因此你可以使用git diff的textconv能力来启用UTF-16文件的文本差异(也应该使用UTF-8,尽管未经测试)。
从gitattributes手册页引用:
有时需要查看某些二进制文件的文本转换版本的差异。例如,可以将文字处理器文档转换为ASCII文本表示,并显示文本的差异。即使这种转换失去了一些信息,生成的差异对人类观看也很有用(但不能直接应用)。
textconv配置选项用于定义执行此类转换的程序。程序应该采用单个参数,要转换的文件的名称,并在stdout上生成结果文本。
例如,要显示文件的exif信息的差异而不是二进制信息(假设您已安装exif工具),请将以下部分添加到$GIT_DIR/config
文件(或$HOME/.gitconfig
文件):
[diff "jpg"]
textconv = exif
对于mingw32的解决方案,cygwin粉丝可能不得不改变这种方法。问题是传递文件名转换为cmd.exe - 它将使用正斜杠,cmd假定反斜杠目录分隔符。
创建将转换为stdout的单个参数脚本。 C:\路径\为\一些\ 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
通过使用.gitattributes文件指出要应用此工作区的文件(请参阅man gitattributes(5)):
*vmc diff=cmdtype
然后在你的文件上使用git diff
。
我编写了一个小的git-diff驱动程序to-utf8
,它可以很容易地对任何非ASCII / UTF-8编码的文件进行区分。您可以使用以下说明安装它:https://github.com/chaitanyagupta/gitutils#to-utf8(to-utf8
脚本在同一个repo中可用)。
请注意,此脚本需要在系统上使用file
和iconv
命令。
git最近开始理解utf16这样的编码。请参阅gitattributes docs,搜索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 eol=LF
(将*.vmc
替换为需要处理的*.whatever
类型文件的whatever
)
最近在Windows上出现了这个问题,并且使用git for windows附带的dos2unix
and unix2dos
垃圾箱就可以了。默认情况下,它们位于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...