我正在跟踪一个 Virtual PC 虚拟机文件(* 。在 git 中,在做了一个更改之后,git 将该文件标识为二进制文件,并且不会对其进行区分。我发现这个文件是用 UTF-16编码的。
是否可以教 git 识别这个文件是文本并适当地处理它?
我在 Cygwin 下面使用 git,core.autocrlf 设置为 false。如果需要,我可以在 UNIX 下使用 mSysGit 或 git。
默认情况下,看起来 git与 UTF-16不能很好地工作; 对于这样的文件,你必须确保没有对它进行 CRLF处理,但是你希望 diff和 merge作为一个正常的文本文件工作(这忽略了你的终端/编辑器是否可以处理 UTF-16)。
git
CRLF
diff
merge
但是看看 .gitattributes手册,下面是自定义属性 binary:
.gitattributes
binary
[attr]binary -diff -crlf
因此,在我看来,您可以在顶级 .gitattributes中为 utf16定义一个自定义属性(注意,我在这里添加 merge 是为了确保它被当作文本处理) :
utf16
[attr]utf16 diff merge -crlf
从那里,您可以在任何 .gitattributes文件中指定如下内容:
*.vmc utf16
还要注意的是,即使 git认为它是二进制文件,您仍然应该能够使用以下命令执行 diff文件:
git diff --text
剪辑
这个答案 基本上说明了使用 UTF-16或甚至 UTF-8的 GNU diff 并不能很好地工作。如果你想让 git使用不同的工具来看到差异(通过 --ext-diff) ,这个答案建议使用 吉菲。
--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,尽管未经测试)。
cmd.exe /c "type %1"
type
引自 gitAttribute 手册页:
有时候,我们希望看到一些二进制文件的文本转换版本的差异。例如,文字处理器文档可以转换为 ASCII 文本表示形式,以及所示文本的差异。尽管这种转换会丢失一些信息,但是产生的 diff 对于人类查看是有用的(但是不能直接应用)。
Textconv 配置选项用于定义执行此类转换的程序。程序应该接受一个参数,即要转换的文件的名称,并在标准输出上生成结果文本。
例如,为了显示文件的 exif 信息而不是二进制信息的差异(假设您已经安装了 exif 工具) ,将以下部分添加到您的 $GIT_DIR/config文件(或 $HOME/.gitconfig文件) :
$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)中,放入以下内容:
~/.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 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。
git difftool
vim
发现“ 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脚本可以在同一个回购中获得)。
to-utf8
注意,这个脚本需要 file和 iconv命令在系统上都可用。
file
iconv
有一个非常简单的解决方案,工程的方框在 Unice。
例如,苹果的 .strings文件只有:
.strings
用以下方法在存储库的根目录中创建一个 .gitattributes文件:
*.strings diff=localizablestrings
在 ~/.gitconfig文件中添加以下内容:
[diff "localizablestrings"] textconv = "iconv -f utf-16 -t utf-8"
资料来源 : Git 中的 Diff. string 文件(和2010年的 老职位)。
最近在 Windows 上出现了这个问题,装有用于 Windows 的 git 的 dos2unix和 unix2dos垃圾箱解决了这个问题。默认情况下,它们位于 C:\Program Files\Git\usr\bin\中。例如,有人在不需要的时候(在我的例子中)意外地将 python 文件编码为 UTF-16。
dos2unix
unix2dos
C:\Program Files\Git\usr\bin\
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
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)
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 提供了工具(我认为!)合成它
-text -diff
+text +diff
Git 允许定义新的宏属性。
我建议你把 .gitattributes文件的顶部
[attr]textfile text diff
然后,对于所有需要文本和差异的路径
path textfile working-tree-encoding= eol=...
注意,在大多数情况下,我们需要缺省编码(utf-8)和缺省 eol (本机) ,因此需要 可能会被撤销。
大多数线条应该看起来像
*.c textfile *.py textfile Etc
实用: 在大多数情况下,我们需要本地的 eol。也就是说没有 eol=...。因此,text不会被暗示,而是需要被明确地表达出来。
概念: 文本和二进制文件是最基本的区别。 eol,编码,diff 等等只是它的一些方面。
由于我们生活在一个怪异的时代,我没有一台机器可以工作。所以我现在无法查看最新添加的内容。如果有人发现问题,我会修改/删除。
如其他答案所述,git diff 不将 UTF-16文件作为文本处理,这使得它们在 Atlassian SourceTree 中不可见,例如。如果文件名/或后缀已知,下面的修复程序将使这些文件在 SourceTree 下可见,并且通常具有可比性。
如果已知 UTF-16文件的文件后缀(* 。那么所有带有该后缀的文件都可以与 UTF-16到 UTF-8转换器相关联,只需要进行以下两项更改:
在存储库的根目录中创建或修改. gitproperties 文件,代码如下:
*.uni diff=utf16
然后使用以下部分修改 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以外的编码吗?”在浏览了几个小时之后。