“多个设备”可能是问题所在。确切的修复或解决方法可能是什么尚不清楚。请参阅下面的技术细节。
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。 :-)