Re: Bug? Git checkout fails with a wrong error message

2 messages, 2 authors, 2016-06-15 · open the first message on its own page

Re: Bug? Git checkout fails with a wrong error message

From: Thomas Rast <hidden>
Date: 2016-06-15 22:52:49

Yves Goergen [off-list ref] writes:
On 16.01.2012 20:17 CE(S)T, Thomas Rast wrote:
quoted
If you work together with developers who have a case-sensitive FS (such
as Linux, or with the right options OS X), it's entirely possible that
this file exists in both spellings within the repository.
Just FTR, I am working on the project alone, only on Windows with Visual
Studio 2010 and I have two copies of the repository which I am
occasionally synchronising via a USB memory stick when I work on the
other machine. I have not pulled anything since the first issue came up
on last Friday. No case-sensitive filesystem in the game.
Ok.

  $ git ls-tree -r HEAD
  100644 blob 5369994b8f905514661ee58b396dec31f8575a4d    PosterWantsItCensored.Designer.cs
  100644 blob 5369994b8f905514661ee58b396dec31f8575a4d    PosterWantsItCensored.designer.cs
  ^      ^    ^
  |      |    content hash
  |      type
  file mode

That tells us that you have identical file contents in two files whose
names differ only in case.

This is important: Different name for git.  Same name for OS.  Same
contents.

That should also settle your remark at the end:
I find it interesting to see that both files with the equal file name
(like what the only relevant file system considers equal) have the same
hash value. Does that qualify for your description of the "pretty bad bug"?
No, not a bug, just the same contents.

[And before you sue me for disclosing the SHA1 above: inferring the
contents of the file from the SHA1 is equivalent to breaking SHA1.  If
anyone could, he'd already be busy writing a paper about it (or perhaps
working for the NSA).]
quoted
* You have the byte-for-byte identical file name listed twice in the
  index.  That would be a pretty bad bug.
The index should usually be empty here, I guess. I really do not use
it.  No index interaction at all.
Please read up on the index before making such statements.  You do use
the index, because it is a very important part of how git operates
whenever the operation also involves the worktree.  And except in border
cases (new empty repo etc.) it should never be empty.

Your paste of

  $ git status -s
  [no output]

tells us that the index has *no differences* to your worktree, nor to
HEAD.


So in summary, the picture in your repository is:

* Somehow you got a different-only-in-case file pair into your
  repository.  It's already in HEAD.  See below.

* The index and worktree are healthy and unchanged (w.r.t. HEAD) from
  Git's POV.  (This is possible despite the different-only-in-case files
  because they have the same contents.)

For now I'm siding with Erik's theory

Erik Faye-Lund wrote:
} Very speculative comment: This might be a bug in TortoiseGit. Looking
} at the sources, it seems they are using libgit2 to mess around with
} the index; perhaps it's case-sensitivity code isn't as well tested as
} Git for Windows'?

It would also be interesting to know for how long this problem has
existed.  You can search for the offending commit with something like

  git log --name-status --diff-filter=A -- "PosterWantsItCensored.*"

which should normally give you just one or two commits, namely the
one(s) that introduced the two files.

As for the fix, there are two-and-two-thirds cases.  First I'd like to
point out, however, that I have no idea how core.ignoreCase interacts
with rm --cached.  I'm assuming you have to set it to 'false' for the
recipes below to work.  Erik or Peff may correct me.  You should set it
to 'true' again for real work.

Case 1: The commit that introduced the second spelling is HEAD

  In this case you're sort of lucky because it's easy to fix.  You can
  do

    git rm --cached PosterWantsItCensored.designer.cs

  to get rid of the spelling you do not want.  Then run

    git status -s

  again to verify that it did the right thing; it should say

    D  PosterWantsItCensored.designer.cs

  where it's important that a) the other spelling does *not* show up in
  the list anywhere and b) the D is in the leftmost column.  Once you
  have verified this, run

    git commit --amend

  to fix HEAD.

Case 2a: The commit that introduced it is older, but you don't care if
         you cannot sanely checkout old commits

  This is the case that I personally would never choose, since I care
  about history, but for completeness: proceed as for case 1, except at
  the end run

    git commit  # no --amend

  and write a nice message saying that you fixed the
  different-only-in-case issue.

Case 2b: The commit that introduced it is older, but history since its
         parent has been linear (use gitk or some such to establish
         this)

  First run

    git log --full-history --oneline -- "PosterWantsItCensored.*"

  to see which commits touched the file.  Let C be the SHA1 (or a unique
  prefix) of the earliest commit that contains
  PosterWantsItCensored.designer.cs (i.e., the wrong spelling) as
  established earlier.  Then run

    git rebase -i C^

  (That's right, the SHA1 of C and then a hat.)

  In the editor that pops up, change 'pick' to 'edit' on every line that
  shows a SHA1 you found in the preceding git-log command.  Save and
  exit.

  Whenever rebase stops to let you edit (you can tell by the advice
  messages it gives you), run

    git ls-tree HEAD -- PosterWantsItCensored.designer.cs PosterWantsItCensored.Designer.cs

  and check whether the SHA1s are different.  Judging by what you said
  they should always be the same (otherwise please come back for more
  advice).  You can then again do something very similar to Case 1 to
  the commit you're editing, like

    git rm --cached PosterWantsItCensored.designer.cs
    git commit --amend

  and finally

    git rebase --continue

  to edit the next commit.  Repeat until the rebase is complete.

Case 2c: History wasn't linear since C; or you're just lazy and have a
         good backup

  The all-safeties-off, please-fix-it-for-me version goes

    git filter-branch --tag-name-filter cat --index-filter '
      git rm --ignore-unmatch --cached PosterWantsItCensored.designer.cs
    ' -- --all

  I'm dead serious about the safeties off.  You have been warned.

I have not tested most of this because it would simply take even more
time than writing an essay-length email.  If something fails or got you
confused, paste everything you did and the full output again so we can
establish what happened.

All sub-items of case 2 rewrite history.  You will have to force the
push to your "hub" repository that you use to exchange history, and you
may have to reset or rebase in the other repository.  Read e.g. the
'recovering from upstream rebase' section in man git-rebase.
(What a mess it would be if I committed something different than my
working directory, however that works.)
You should really read up on this, e.g.

  http://tomayko.com/writings/the-thing-about-git

AFAIK everyone who groks the feature uses it daily.

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

Re: Bug? Git checkout fails with a wrong error message

From: Yves Goergen <hidden>
Date: 2016-06-15 22:52:49

On 17.01.2012 09:45 CE(S)T, Thomas Rast wrote:
It would also be interesting to know for how long this problem has
existed.  You can search for the offending commit with something like

  git log --name-status --diff-filter=A -- "PosterWantsItCensored.*"

which should normally give you just one or two commits, namely the
one(s) that introduced the two files.
I have found two commits adding that file. The second one has the file
with the then-already-present name modified and the new spelling added.
I could have noticed that at commit time, but that's the very commit
where I also renamed the original files and recreated them in the Forms
designer. 1) This may have led me to overlook that additional add and 2)
this may be the source of the spelling difference because the file was
newly created.
As for the fix, there are two-and-two-thirds cases. (...)
That all sounds quite complicated. The "offending" commit is quite a
while back so replacing the last commit is not a solution.

This is just my personal repository that should help me out with finding
changes when I find something broken that wasn't before. Deleting and
recreating the "hub" (bare) and the other working repository would be
okay for me in this case. I have decided that it is also okay to fix the
error by new commits. To avoid all further issues with this, I have
renamed the file, committed the deletion, renamed it back and then
committed the add. The revsion in between won't compile, but it's got a
message with it and the compiler error would be obvious.
You should really read up on this, e.g.

  http://tomayko.com/writings/the-thing-about-git

AFAIK everyone who groks the feature uses it daily.
It's on my to-read list. Looks like an interesting article from reading
the beginning of it.

I have done a test, too: I have set the core.ignorecase setting to false
(or deleted its entry) and then renamed one of the files in my working
directory only in case. TortoiseGit has offered me adding the new
spelling for a commit. After setting the core.ignorecase setting to
true, it has not offered any change to commit anymore. So it looks like
this is just the setting that every repository for Windows use should -
no - must have, and it was missing here.

Just like that stupid autocrlf that causes more issues than it solves. I
regularly see files with all lines changed and the diff says that both
files only differ in line endings. But I have no sure observation on
whether that value was set or unset in those cases. I'll have to look
after that, too.

These two config settings are not cloned with the repository, are they?

Also, TortoiseGit already sets ignorecase = true. So maybe the Visual
Studio provider does the init on its own and is missing that. Or I have
at some time cloned the repository and the setting wasn't copied over.

-- 
Yves Goergen "LonelyPixel" [off-list ref]
Visit my web laboratory at http://beta.unclassified.de
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help