Git 与 MacOSX 上的 Umlaut 问题

今天我在 Mac OS X 上发现了 Git 的一个 bug。

例如,我将提交一个名为 überschrift.txt 的文件,文件开头使用德语特殊字符。从命令 git status我得到以下输出。

Users-iMac: user$ git status


On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   "U\314\210berschrift.txt"
nothing added to commit but untracked files present (use "git add" to track)

看起来 Git 1.7.2在 Mac OS X 上的德语特殊字符有问题。 是否有解决方案让 Git 正确地读取文件名?

17945 次浏览

没错。

你的文件名是在 UTF-8中,用拉丁大写字母 u + 组合 DIAERESIS (Unicode 0x0308,utf80xcc 0x88)代替拉丁大写字母 Ӱ (Unicode 0x00dc,utf80xc30x9c)。Mac OS X HFS 文件系统以这种方式分解 Unicode.饭桶依次显示非 ASCII 文件名字节的八进制转义形式。

注意,Unicode 文件名可能使存储库不可移植。

原因是文件系统存储文件名的不同实现。

在 Unicode 中,Ü 可以用两种方式表示,一种是用 Ü 单独表示,另一种是用 U + “组合元音字符”表示。Unicode 字符串可以包含两种形式,但是由于两种形式都包含会让人感到困惑,所以文件系统通过将每个元变量 U 设置为 Ü 或 U + “组合元变量字符”来规范 Unicode 字符串。

Linux 使用前一种方法,称为 Normal-Form-Composed (或 NFC) ,而 Mac OS X 使用后一种方法,称为 Normal-Form-Decposed (NFD)。

显然,饭桶并不关心这一点,而只是简单地使用文件名的字节序列,这就导致了您所遇到的问题。

邮件列表线程 Git,Mac OS X 和德语特殊字符中有一个补丁,以便 Git 在标准化后比较文件名。

要使 git add file在 Mac OS X 上使用文件名中的变音符号,您可以使用 iconv将文件路径字符串从组合转换为经过规范分解的 UTF-8。

# test case


mkdir testproject
cd testproject


git --version    # git version 1.7.6.1
locale charmap   # UTF-8


git init
file=$'\303\234berschrift.txt'    # composed UTF-8 (Linux-compatible)
touch "$file"
echo 'Hello, world!' > "$file"


# convert composed into canonically decomposed UTF-8
# cf. http://codesnippets.joyent.com/posts/show/12251
# printf '%s' "$file" | iconv -f utf-8 -t utf-8-mac | LC_ALL=C vis -fotc
#git add "$file"
git add "$(printf '%s' "$file" | iconv -f utf-8 -t utf-8-mac)"


git commit -a -m 'This is my commit message!'
git show
git status
git ls-files '*'
git ls-files -z '*' | tr '\0' '\n'


touch $'caf\303\251 1' $'caf\303\251 2' $'caf\303\251 3'
git ls-files --other '*'
git ls-files -z --other '*' | tr '\0' '\n'

在 Mac 上启用 core.precomposunicode

git config --global core.precomposeunicode true

为了实现这个目标,您至少需要有 Git1.8.2。

Mountain Lion 提供1.7.5版本。要获得一个更新的 git,可以使用 Git-osx 安装程序自酿的(需要 Xcode)。

就是这样。

将存储库特定于 OSX 的 core.precomposeunicode标志更改为 true:

git config core.precomposeunicode.true

为了确保新的存储库获得这个标志,还可以运行:

git config --global core.precomposeunicode true

以下是手册中的相关片段:

此选项仅由 Git 的 Mac OS 实现使用 Precomposunicode = true,Git 还原 这在共享资源库时非常有用 (适用于 Windows1.7.10或更高版本的 Git) 或 Cygwin 1.7下的 Git)。如果为 false,则文件名为 处理完全透明的 Git,它向后兼容 Git 的旧版本。

我的个人存储库也有类似的问题,所以我用 Python3编写了一个 helper 脚本。你可以在这里抓住它: https://github.com/sjtoik/umlaut-cleaner

这个脚本需要一点体力劳动,但不是很多。

在10.12.1 Sierra 中,~/. gitconfig 对 UTF-8名称起作用:

precomposeunicode = true
quotepath = false

第一个选项是必需的,这样 git 可以“理解”UTF-8,第二个选项则不会转义字符。