2

我有带有变音符号的文件名(即 Exposé.pdf)。

$ svn stat
!    Exposé.pdf
?    Exposé.pdf

我正在使用 subversion 和 git 并排使用(不是 git-svn)。我正在从 subversion 迁移到 git,并希望共存一段时间。所以我在多个设备上都有大型存储库。当我用 git 克隆一个 repos 并将已经存在的 subversion .svn 文件夹添加到 repo 时,我得到了 subversion 差异(!项目丢失,?项目不在 vcs 下)但文件名似乎完全相同,但在引擎盖他们不是!我试过(见https://www.git-tower.com/help/mac/faq-and-tips/faq/unicode-filenames

git config --global core.precomposeunicode true 

但这没有任何区别。有什么线索吗?

4

1 回答 1

1

“多个设备”可能是问题所在。究竟是什么修复或解决方法可能尚不清楚。请参阅下面的技术细节。

一般来说,你不应该设置core.precomposeunicode自己,就像你不应该设置core.ignorecase自己一样。1 这些设置——连同core.symlnks——是 Git 自己设置的东西,用来记录你的计算机在你运行时的行为git initgit clone. 2 如果您使用 进行了设置--global,我建议您从您的个人 Git 配置中删除该设置:

git config --global --unset core.precomposeunicode

全局取消设置的原因是设置一个值--global 会禁用新存储库中的自动检测功能。

启用自动检测后,您始终可以将现有存储库克隆到新副本。新克隆将具有针对当前本地条件的正确(本地)设置。这个新的克隆不应该通过任何方式从一台机器传输到另一台机器git clone


1这些可以用您喜欢的任何随机大写字母拼写。Git 文档使用camelCase这样做,调用它们core.precomposeUnicodecore.ignoreCase. 您可以将它们设置为特定的测试目的,或者用于您想要处理以某种不受欢迎的方式构建的存储库的奇怪边缘情况。但这相当于对 Git 撒谎,所以要小心!在试验时在本地(而不是全局)进行。

2这里还有一个特殊情况。具有这些……损害您的文件名的“功能”的操作系统,以保护您免受丑陋现实的名义,通常实际上是在每个文件系统的基础上执行此操作。例如,MacOS 的外壳折叠功能在您构建磁盘映像时是可以更改的。Windows 上的符号链接支持取决于 Windows 的版本几个附加项。因此,可以完整地获取一个 Git 存储库,将其移动到不同的文件系统,然后需要更改设置。git clone这是从一个文件系统到另一个文件系统而不是使用tarorrarzip什至更明智的原因之一cp -r移动 Git 存储库:克隆将正确设置设置,而非克隆复制操作不会。


文件名是字节字符串,除非它们不是

这里的根本问题是,Git 想要相信文件名只不过是带有两个或三个约束的字节字符串,其中3 个是由 Linux 建立的,而没有其他任何操作系统建立的约束。这些字节字符串通常也应该是但不要求是有效的 UTF-8 序列。理想情况下,操作系统会让 Git 按原样使用这些字节串,不受干扰。

在 Windows 和 MacOS 上,这个理想立刻就变成了现实。最明显和最直接的问题是,在 Linux 上,您可以创建一个名为的文件README,然后创建另一个名为 的不同文件readme,这两个文件将共存。在 Windows 和 MacOS 上,当您创建这些文件中的任何一个时,您将无法再创建第二个文件:任何这样做的尝试都会重复使用第一个文件。

换句话说,Linux 有区分大小写的文件名,而 Windows 和 MacOS 没有。这意味着 Linux 用户可以自由地创建README.txt readme.txt文件并将两者放入单个存储库中。克隆此存储库的 Windows 或 MacOS 用户无法同时使用这两个文件。

尽管如此,Windows 或 MacOS 上的 Git 用户可以使用这些文件。这样做很痛苦。即使在 git commit -am b/c origin 有一个带有 de-capitalize filename 的文件之后,我在我对“Changes not staged for commit”的回答中也展示了一种方法。同样的方法也适用于此处,但痛苦程度相同。

同样的规则适用于某些 Unicode 文件名。 特别是,Unicode 有多种方法可以拼写一些重音字符,例如 á、ü 等。例如,如果我们有一个名为schön (pretty) 的文件,我们可以使用字母序列来拼写它:

s c h umlaut-o n

(每个都是一个 Unicode代码点),或者我们可以使用以下方式拼写它:

s c h o combining-umlaut n

这些是不同的字节码序列,因此至少根据 Git 应该是不同的文件,即使两者都将作为名称显示schön在您的屏幕上。

MacOS 说这两个名称将显示相同,因此我不会允许其中之一。如果您向操作系统提供“错误”的拼写,它会更正或直接拒绝它。请注意,这与折叠案例的情况有些不同:MacOS 将允许您创建一个 readme README,但不能同时创建两个。它只允许一种形式的schön.

因为 Git 从索引而不是文件系统构建新提交,并且索引是一个普通的数据文件,所以您可以将所需的拼写或两者都放入索引中。这意味着您可以将其中一个或两个都放入新的提交中。 任何现有的提交都具有现有的拼写并且不能更改。

加载现有提交(通过git checkout)将提交的拼写复制到索引中,并保持原样。该设置告诉 Git 当 Git 尝试将文件索引复制工作树时core.precomposeunicode,您的操作系统是否以及如何修改文件的(或文件)名称。然后,如果合适,Git 可以尝试撤消任何损坏。但并非所有情况都可以处理,尤其是文件出现在两种拼写的提交中的情况,就像 README 与自述文件中的大小写折叠一样。

(另请参阅t/t3910-mac-os-precompose.sh中的 Git 对 MacOS precompose-unicode 的内部自测。)


3限制条件是:

  • 没有字符串以斜杠开头或结尾(后者由于 Git 不会存储目录而处理得比较简单,而前者只是不使用前导斜杠(如果有的话));
  • 没有字符串连续有两个斜杠;和
  • 没有字符串具有嵌入的 NUL 字节(这条规则来自编写 Git 的 C 语言,并且受到这些操作系统的支持,所以这不是真正的问题)。

斜杠规则是因为 Linux 将斜杠视为目录/子目录或目录/文件名分隔符。MacOS 当然完全一样,Windows 的大部分界面都支持这一点,尽管内部使用了反斜杠。因此,所有三个系统都对斜线限制感到满意。但是,一些 Windows 文件系统也在内部使用 UTF-16-LE,这会在所谓的 Surrogate Escapes 周围创建一个额外的雷区。我不知道 Windows 如何处理这些。理想情况下,雷区不会从内部接口泄漏到外部接口,但话又说回来,理想情况下,Windows 将使用正斜杠和 UTF-8。:-)

于 2019-03-05T17:09:08.450 回答