Open camsteffen opened 8 years ago
From: Cameron Steffen Running git checkout head results in a detached HEAD and git checkout HEAD does nothing (as expected). Since Windows is case-insensitive, each command should match what happens in Unix for git checkout HEAD.
Windows 10 64-bit git version 2.7.2.windows.1
I think you have it in one. As you said "Windows is case-insensitive". It's not Unix, so I think we are stuck with the current situation.
A bigger warning (but when) might be appropriate to help 'learn' [1] new users. Alternatively doe deep code changes to the Linux version to detect wrong case scenarios (where the thing provided has a name with a different case to the thing requested) would be needed.
The issue comes up in various guises quite often, and at the moment is essentially intractable, so ends up as a "Can't Fix" (the other similar issue is the allowable characters and phrases in filenames, such as ';' and 'AUX..'; and filename lengths)
Philip [1] "I'll learn you": (locally) a historical turn of phrase for education^W teaching via corporal punishment - the 'clue bat' in modern idiom - thankfully now gone in most places.
I meant to say ‘:’ as a not allowable char, though ‘;’ isn’t desired. https://support.microsoft.com/en-us/kb/177506
From: Philip Oakley [mailto:notifications@github.com]
similar issue is the allowable characters and phrases in filenames, such as ';'
I think you have it in one. As you said "Windows is case-insensitive". It's not Unix, so I think we are stuck with the current situation.
I don't see why we are stuck. This is what I expect to happen.
git checkout head
head
to HEAD
git checkout HEAD
Please let me know if this step by step is not representative of what actually happens. The problem is not in step 2 but step 3. So the case-insensitivity is not really the core problem.
I think you have it in one. As you said "Windows is case-insensitive". It's not Unix, so I think we are stuck with the current situation. I don't see why we are stuck. This is what I expect to happen.
- User enters 'git checkout head'
- Git for Windows resolves 'head' to 'HEAD'
- Git for Windows performs git checkout HEAD
- Nothing happens
Please let me know if this step by step is not representative of what actually happens. The problem is not in step 2 but step 3. So the case-insensitivity is not really the core problem.
The problem is distinguishing G4W from Git.
So the 'problem' is Linux Git's code - see the caveat to 3c.
Unless upstream can be persuaded to include a load on redunant name checking code, with all the architectural upheaval that may entail (which is the 'problem' - there's no benefit for them), we don't have an easy way (with fast execution) to insert a shim into the code do actually do the checking.
I say 'We', in this context it's probably dscho and some of the other better coders than I, that would be needed to write a Windows fopen() shim that is explicitly case sensitive (there may even be one, I just don't know). In this case ('branch' checkout) it would need to be case insensitive on the path-to part, while sensitive on the final filename part.
Then the correct points in the upstream code (some fopen()'s are more important than others) would/should be changed to some macro expansion that would insert the Windows checks when compiled on windows.
Ensuring that this is fast, just like real git, is an awkward task, as dscho has noted elsewhere (quite vocally, 'cos it matters)
Philip (hope this formats ok..)
My rambling notes from a previous report are attached.
Git Checkout Case sensitivity
User Deigo j. (saintplay96@gmail.com) reported https://groups.google.com/forum/#!topic/git-users/EryCnwKL4_E that he could create a branch 'name' and then checkout Name sucessuflly but the HEAD and branch commands didn't think he had checked 'it' out (despite the earlier sucess)
This is a probably File system case insensitivity issue.
git init casetest cd casetest/
temp.txt git add -A & git commit -m'first' git status git branch case git branch git status git checkout Case
success!
git branch
note that no branch is marked as current, but neither are we detached head..
git status cat .git/HEAD
HEAD records the requested name, not the branch that was actually checked out!
checkout.c
Summary, the success message is printed after the create_symref for HEAD as part of update_refs_for_switch, which is itself called from switch branches after it has done merge_working_tree. The merge working tree maybe should have noticed that what it asked for, wasn't what it got.
now to delve into the merge_working_tree and the 'new' struct and msg.buf
checkout.c
**\ This merge_working_tree looks to be it (where the problem is hidden)!
in
in static void update_refs_for_switch( #L613
meanwhile
from the top of cmd_checkout #L1338 we find
defined at #L1105 parse_branchname_arg() we find
after the get_sha1_mb() we, either way, do the
but before, at #L1192 check_filename(
new->name = arg;
setup_branch_path(new);
trace eventually to (in refs.c #L1603) stat_ref: if (bad_name) {
contains at the end..
so inside (see above)
Windows methods of getting true file name http://stackoverflow.com/questions/4763117/how-can-i-obtain-the-case-sensitive-path-on-windows/4763137#4763137 http://stackoverflow.com/questions/478826/c-sharp-filepath-recasing/479198#479198 http://stackoverflow.com/questions/74451/getting-actual-file-name-with-proper-casing-on-windows
Need to look at the alternates such as the git status, git branch etc which actually look at the ref and the HEAD.
L1338 int cmd_checkout() git\builtin\checkout.c
|#L1433 * Extract branch name from command line arguments |#L1452 int n = parse_branchname_arg( (is this getting the name??)
L1105 parse_branchname_arg() git\builtin\checkout.c
| #L1181 if (get_sha1_mb(arg, rev)) _note _mb: merge base i.e. A...B syntax, the if must be saying it wasn't that.. | #L1192 check_filename( | #L1225 new->name = arg; | #L1226 setup_branch_path(new);
L460 setup_branch_path()
| #L464 strbuf_branchname
L1166 strbuf_branchname() git\sha1_name.c
| #L1169 int used = interpret_branch_name
L1126 interpret_branch_name()
| #L1130 int len = interpret_nth_prior_checkout Parse @{-N} syntax | #L1152 len = interpret_branch_mark
L1072 interpret_branch_mark()
| #L1092 branch = branch_get(name_str);
L1681 branch_get();
| #L1689 ret = make_branch(name, 0); adds "refs/heads/" prefix to new->path | trace eventually to (in refs.c #L1603) stat_ref: if (bad_name) { |at the end of cmd_checkout |#L1498 return checkout_branch(&opts, &new);
Thanks for the explanation, Philip. What I understand is that this is a very minor bug and the potential fix involves adding complexity to upstream, Unix-focused code. That's good enough for me. I'll defer closing the issue to someone else. Sorry I'm not much help.
It is interesting to note that the Windows NTFS file system is case sensitive. Through a command interpreter that operates case-sensitively (and uses case-sensitive Windows file system APIs), you could create a file named foo
and a file named FOO
, or with any combination of casing, within a single directory on an NTFS volume.
However, because traditionally the FAT file system was not case-sensitive, the Windows Explorer Shell and the Windows Command Prompt operate over files case-insensitively. (That last statement is a bit of an "over-simplification"--there are some weird quirks about how Windows treats files with names that differ only in their casing that are mentioned in the article I linked to above, but that's only a short synopsis and I'm sure there's a lot more weirdness going on with respect to file casing which could be found with additional searching). There is a way to turn off case-insensitivity with case preservation to require that file system operations respect the casing of filenames (at the file system level); however, for normal use of Windows, you probably wouldn't want to do that because some (most?) programs would most likely not work correctly.
In any event, I don't believe this is a bug. What you are experiencing is the result of legacy behavior persisting to this day in Windows for compatibility reasons (and frankly, ease of use--though, that's questionable).
Quite simply, this most likely will never be fixed. For one thing, all nices have case-sensitive shells and file systems (excluding, of course, FAT--which is not a default file system on any nix)--all that I've come into contact with, anyway. The NTFS file system is case-sensitive as well--and who's to say that sometime in the next 5 - 10 years Windows won't in fact default to a fully case-sensitive Explorer shell and command interpreter? Lest you laugh at me, no one ever thought MS would embrace Linux as much as they have over the last 2 years or so, nor open source as much software as they currently have. Things change, and case-sensitivity would be a huge change (for Windows and its ecosystem of users and software), and one that won't happen overnight, but it is possible. This may be even particularly more true now that we have things like the Windows Subsystem for Linux.
Running
git checkout head
results in a detached HEAD andgit checkout HEAD
does nothing (as expected). Since Windows is case-insensitive, each command should match what happens in Unix forgit checkout HEAD
.Windows 10 64-bit git version 2.7.2.windows.1
This issue was previously reported on the old msysgit repo https://github.com/msysgit/msysgit/issues/114