File paths in Windows environment not case sensitive?
Is it safe to assume that Windows local and network file paths are NOT case sensitive?
回答1
Yes. Windows (local) file systems, including NTFS, as well as FAT and variants, are case insensitive (normally). The underlying implementation of a network file system may be case sensitive, however, most software that allows Windows to access it (such as SMB) will automatically make case sensitive file systems appear as case insensitive to Windows.
For details, I'd read the section in the Wikipedia article on filenames.
回答2
Case sensitivity on Windows is actually implemented in how the application opens the files. NTFS can be a case-sensitive file system and can happily store files, with identical names differing only by case in the same directory.
On Windows all files are ultimately opened via the CreateFile API - If the FILE_FLAG_POSIX_SEMANTICS
flag is passed to the call (and the file system being accessed is natively case-sensitive) then the file will be opened based on an exact name match. If FILE_FLAG_POSIX_SEMANTICS
is not passed then the filesystem does a case-insensitive file open and will open one of the files with a matching name. If there is more than one it's undefined as to which one is actually opened.
Most C and C++ runtime implementations on Windows do not provide any access to this mechanism and never use this flag so the only way to get access to case-sensitive behaviors is to use the Windows API directly.
tl;dr - Your language runtime probably exposes your filesystem as case insensitive or case preserving. You can, if you use the windows API directly, access supported filesystems fully case senstive.
Git case sensitivity
The Windows and macOS file systems are case-insensitive (but case-preserving) by default. Most Linux filesystems are case-sensitive. Git was built originally to be the Linux kernel's version control system, so unsurprisingly, it's case-sensitive.
While many of the issues with a case-insensitive OS have been addressed in Git for Windows, a few quirks remain.
File and folder names
On Linux, checking out a Git repo which contains both "File.txt" and "file.txt" is no problem. Those are distinct filenames.
On Windows and macOS, checking out both files will result in the second one overwriting the first one. If two folders differ only by case, their contents will end up mixed together on case-insensitive filesystems.
Fixing case conflicts
One way to fix a repository with this problem is to check it out in a case-sensitive environment. Rename files and folders so they no longer conflict, then push those changes to the repository.
Windows Subsystem for Linux is one such environment. Another approach is to use the command git mv -f <conflicting name> <non-conflicting name>
for each conflict, being careful to use exact capitalization on both file names.
Avoiding case conflicts
It's good to avoid creating this situation in the first place. Azure Repos offers a case-enforcement setting to prevent pushes which would lead to this situation. For developers, adopting the habit of using tab-completion to commit files will also help. Since both Windows and macOS are case-preserving, this will ensure that Git's internals see the exact same casing that the filesystem uses.
Branch and tag names
You can create two branches or tags (known as 'refs') that differ only in casing. Git's internals, as well as Azure DevOps Services/TFS, will treat them as two separate refs. On a user's machine, Git uses the filesystem to store refs. Fetches and other operations begin to fail because of the ambiguity. Each ref is represented by a small file, and if a ref name contains /
characters, the parts before the final /
are represented by folders.
One simple way to avoid issues is to always use all-lowercase branch and tag names. If you have already created two branches or tags with this problem, you can fix it in the Azure Repos web UI.
Fixing branch names
From the branches page, navigate to the related commit. In the context menu, choose "New branch". Give the branch a new name that doesn't have a case conflict. Return to the branches page and delete the conflicting branch.
Fixing tag names
The steps for fixing a tag name are similar to branches. From the tags page, navigate to the tagged commit. In the context menu, choose "Create tag". Give the tag a new name that doesn't have a case conflict. Return to the tags page and delete the conflicting tag.