Subject: Re: [BUG] git checkout <branch> allowed with uncommitted changes

From: Michael J Gruber <[email-masked]>
Date: Thu, 13 Oct 2011 17:09:49 +0200

arQon venit, vidit, dixit 13.10.2011 10:40:
> Which, as you'd expect, results in both the on-disk copies and other branches
> becoming corrupted.
> 
> Tested on git versions 1.7.6 and 1.7.7 (msysgit)
> 
> http://benno.id.au/blog/2011/10/01/git-recursive-merge-broken describes
> something that sounds similar, but that's supposedly fixed on 1.7.7,
> whereas this happens on that as well.
> 
> master is a tracking branch, "ttfcon" is the branch I was using to develop
> a change. Got to a good point on the branch, merged it in:
> 
> $ git co master
> $ git merge ttfcon
> Updating b9f0c75..6280b7a
> Fast-forward
>  .gitignore                |    2 ++
>  code/renderer/tr_font.cpp |   27 ++++++++-------------------
>  2 files changed, 10 insertions(+), 19 deletions(-)
> 
> $ git st
> # On branch master
> # Your branch is ahead of 'origin/master' by 3 commits.
> 
> back to the branch to mess around with a couple of things to be sure this
> is what i want to push
> $ git co ttfcon
> do stuff
> 
> $ git st
> # On branch ttfcon
> # Changes not staged for commit:
> #   (use "git add <file>..." to update what will be committed)
> #   (use "git checkout -- <file>..." to discard changes in working directory)
> #
> #       modified:   code/freetype-2.3.11/builds/win32/visualc/freetype.vcproj
> #       modified:   code/renderer/tr_font.cpp
> 
> so far so good...
> 
> $ git ci -m "blah" code/freetype-2.3.11/builds/win32/visualc/freetype.vcproj
>  1 files changed, 4 insertions(+), 0 deletions(-)
> 
> note that tr_font is locally modified and still *not committed* at this point.

and neither staged for commit, exactly.

> $ git co master
> M       code/renderer/tr_font.cpp
> Switched to branch 'master'
> Your branch is ahead of 'origin/master' by 3 commits.
> 
> boom. instead of rejecting the branch change, git switches branches anyway,
> and doesn't do anything about the uncommitted changes in the file itself -

Exactly. git leaves them as they are, without changing what you have in
your work tree.

(This is possible because the switch ttfcon to master involves no
changes which conflict with the chnage that you have in your work tree).

> meaning they're now effectively "in" master because they're still on disk,
> so now the master is poisoned.

Not at all. They are on "disk" (work tree). Full stop. Not staged, not
committed, not at all "in master".

> 
> "git st" does show the change:
> 
> # On branch master
> # Changes not staged for commit:
> #       modified:   code/renderer/tr_font.cpp
> 
> but it's a change I never MADE on this branch (ie master), only on the
> other branch.

You never made it on the other branch either. You made it in the work
tree. And "git status" clearly says so: modified, not staged.

> "git diff" is just as confused as I am:
> 
> $ git diff ttfcon
> --- a/code/renderer/tr_font.cpp
> +++ b/code/renderer/tr_font.cpp
> +		// git branch bug

"git diff" shows you the change you have in your work tree, i.e. the
difference between index (which coincides with master since nothing is
staged) and work tree. The fact that there is a difference is equivalent
to saying "there are unstaged changes".

> So it's picking up the difference between the two branches, but as far as

No. The difference between the branches is the change to freetype.vcproj
because you committed that to ttfcon, not master.

> the *actual file* goes, master now has a line in it that shouldn't be there.

It's in the work tree, not master....

> I'm just trying out git as a possible replacement for SVN, so maybe I'm
> mistaken about what "should" happen, but AIUI git switching branches with
> uncommitted changes is a bug (and given that it poisoned a branch that I
> wasn't on, it certainly looks like one). A couple of days ago it DID complain
> when I tried to switch with uncommitted files still present, so it was working
> properly then. I have no idea what's made it happy to ignore them now:
> nothing's changed that I know of.

When switching branches, git tries to preserves the changes that you
have in your work tree. If it is possible (because there is no overlap,
as written above), it hapilly does just that. If not it barks.

I think you have to wrap your head around the Git model after unwinding
it from the svn model, which is normal ;)

Cheers,
Michael