文件名中的变音符号导致 subversion 和 git (MacOS) 之间存在差异

2024-03-03

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

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

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

git config --global core.precomposeunicode true 

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


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

In general, you should not set core.precomposeunicode yourself, in the same way that you should not set core.ignorecase yourself.1 These settings—along with core.symlnks—are something that Git sets by itself to record how your computer behaves, at the time you run git init or git clone.2 If you have set this with --global, I would recommend that you remove the setting from your personal Git configuration:

git config --global --unset core.precomposeunicode

全局取消设置的原因是设置一个值--global disables新存储库中的自动感应功能。

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


1These can be spelled with any random capitalization you like. The Git documentation does so using camelCase https://en.wikipedia.org/wiki/Camel_case, calling them core.precomposeUnicode and core.ignoreCase. You can set them for specific testing purposes or for weird edge cases where you want to deal with a repository that was built in some sort of undesirable way. But this amounts to lying to Git, so be careful with it! Do it locally (not globally) while experimenting.

2There's another special case here. The OSes that have these ... "features" of doing harm to your file names, in the name of shielding you from ugly reality, often actually do this on a per-file-system basis. The case folding feature of MacOS, for instance, is changeable at the time you build a disk image. Symlink support on Windows depends on the version of Windows and several additional items. So it's possible to pick up a Git repository intact, move it to a different file system, and then need to change the settings. This is one reason it's often wiser to git clone from one file system to another, rather than using tar or rar or zip or even cp -r to move a Git repository: the clone will set the settings correctly, while the non-clone copy operation won't.


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

The fundamental problem here is that Git wants to believe that file names are nothing but byte strings with two or three constraints,3 established by Linux, and no other constraints established by any other OS. These byte strings generally should be, but are not required to be, valid UTF-8 sequences as well. Ideally, the OS will let Git use these byte-strings as-is, unmolested.

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

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

尽管如此,Windows 或 MacOS 上的 Git 用户can处理这些文件。这样做只是痛苦的。我在回答中展示了一种方法即使在 git commit -am b/c origin 具有文件名大写的文件之后,“更改也未暂存提交” https://stackoverflow.com/q/54490905/1256452。同样的方法也适用于此,但疼痛程度相同。

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

s c h umlaut-o n

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

s c h o combining-umlaut n

这些都是不同的字节码序列因此至少根据 Git 应该是不同的文件,尽管两者都会display正如名字schön在你的屏幕上。

macOS 说这两个名称将显示相同,因此我不会允许其中之一。如果您向操作系统提供“错误”的拼写,它要么会纠正它,要么干脆拒绝它。请注意,这与折叠情况有些不同:MacOS 将允许您创建either readme or README,但不能两者兼而有之。它将只允许一种形式schön.

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

加载现有提交(通过git checkout) 将提交的拼写复制到索引中,并保持原样。这core.precomposeunicode设置告诉 Git 您的操作系统是否以及如何modifyGit 尝试复制文件时的文件名from索引to工作树。然后,如果合适的话,Git 可以尝试消除任何损坏。但并非所有情况都可以处理,特别是文件出现在提交中的情况both拼写,很像 README 与自述文件中的大小写折叠。

(另请参阅 Git 对 MacOS precompose-unicode 的内部自测试,位于t/t3910-mac-os-precompose.sh https://github.com/git/git/blob/master/t/t3910-mac-os-precompose.sh.)


3The constraints are:

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

文件名中的变音符号导致 subversion 和 git (MacOS) 之间存在差异 的相关文章

随机推荐