我在 git 中跟踪一个 Virtual PC 虚拟机文件 (*.vmc),在进行更改后,git 将该文件识别为二进制文件并且不会为我区分它。我发现该文件是用 UTF-16 编码的。
可以教 git 识别这个文件是文本并适当地处理它吗?
我在 Cygwin 下使用 git,core.autocrlf 设置为 false。如有必要,我可以在 UNIX 下使用 mSysGit 或 git。
我在 git 中跟踪一个 Virtual 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
吉特摇滚。
有一个非常简单的解决方案可以在 Unices 上开箱即用。
例如,使用 Apple 的.strings
文件:
.gitattributes
在存储库的根目录中创建一个文件:
*.strings diff=localizablestrings
将以下内容添加到您的~/.gitconfig
文件中:
[diff "localizablestrings"]
textconv = "iconv -f utf-16 -t utf-8"
来源:Git 中的 Diff .strings 文件(以及2010 年的旧帖子)。
您是否尝试过将其设置.gitattributes
为将其视为文本文件?
例如:
*.vmc diff
默认情况下,它看起来git
不适用于 UTF-16;对于这样的文件,您必须确保未对其进行任何CRLF
处理,但您希望diff
并merge
作为普通文本文件工作(这忽略了您的终端/编辑器是否可以处理 UTF-16)。
但是查看.gitattributes
手册页,这是自定义属性binary
:
[attr]binary -diff -crlf
所以在我看来,您可以在顶层定义一个自定义属性(.gitattributes
请utf16
注意,我在此处添加合并以确保将其视为文本):
[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 字符的差异标记)。
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
)*.whatever
whatever
关注@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 的机器。所以我目前无法检查最新添加的内容。如果有人发现有问题,我会修改/删除。
解决办法是过滤掉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 假定反斜杠目录分隔符。
创建将转换为标准输出的单参数脚本。c:\path\to\some\script.sh:
#!/bin/bash
SED='s/\//\\\\\\\\/g'
FILE=\`echo $1 | sed -e "$SED"\`
cmd.exe /c "type $FILE"
设置 git 以便能够使用脚本文件。在你的 git config ( ~/.gitconfig
or .git/config
or see 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
脚本在同一个仓库中可用)。
请注意,此脚本要求系统上同时提供file
和iconv
命令。
最近在 Windows 上遇到了这个问题,而 git for windows 附带的dos2unix
and unix2dos
bins 解决了这个问题。默认情况下,它们位于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...
如其他答案中所述,git diff 不会将 UTF-16 文件作为文本处理,这使得它们在 Atlassian SourceTree 中不可见。如果文件名/或后缀已知,则以下修复将使这些文件在 SourceTree 下正常可见和可比较。
如果 UTF-16 文件的文件后缀是已知的(例如 *.uni),那么所有具有该后缀的文件都可以与 UTF-16 到 UTF-8 转换器相关联,并进行以下两个更改:
使用以下行在存储库的根目录中创建或修改 .gitattributes 文件:
*.uni diff=utf16
然后使用以下部分修改用户主目录 (C:\Users\yourusername\.gitconfig) 中的 .gitconfig 文件:
[diff=utf16]
textconv = "iconv -f utf-16 -t utf-8"
这两项更改应立即生效,无需将存储库重新加载到 SourceTree。它将文本转换应用于所有 *.uni 文件,使它们像其他文本文件一样可查看和可比较。如果其他文件需要这种转换,您可以在 .gitattributes 文件中添加额外的行。(如果指定的文件不是 UTF-16,您将获得该文件的不可读结果。)
请注意,此答案是对 Tony Kuneck 答案的简化重写。