git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [BUG] git checkout <branch> allowed with uncommitted changes
@ 2011-10-13  8:40 arQon
  2011-10-13 10:48 ` Nguyen Thai Ngoc Duy
  2011-10-13 15:09 ` Michael J Gruber
  0 siblings, 2 replies; 36+ messages in thread
From: arQon @ 2011-10-13  8:40 UTC (permalink / raw)
  To: git

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.

$ 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 -
meaning they're now effectively "in" master because they're still on disk,
so now the master is poisoned.

"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.

"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

So it's picking up the difference between the two branches, but as far as
the *actual file* goes, master now has a line in it that shouldn't be there.

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.

At this point, reverting the master with "checkout --" also wipes out the
changes on the other branch. It's like the merge symlinked the two branches
rather than, well, merging them.

If this is user error, and merge is supposed to break the tree like that,
then sorry for wasting your time, but I can't find anything in the docs that
says (or even suggests) that it should, so...

Thanks.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13  8:40 [BUG] git checkout <branch> allowed with uncommitted changes arQon
@ 2011-10-13 10:48 ` Nguyen Thai Ngoc Duy
  2011-10-13 10:59   ` Alexey Shumkin
  2011-10-13 15:09 ` Michael J Gruber
  1 sibling, 1 reply; 36+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2011-10-13 10:48 UTC (permalink / raw)
  To: arQon; +Cc: git

On Thu, Oct 13, 2011 at 7:40 PM, arQon <arqon@gmx.com> wrote:
> $ git co master
> M       code/renderer/tr_font.cpp
> Switched to branch 'master'
> Your branch is ahead of 'origin/master' by 3 commits.

...

> At this point, reverting the master with "checkout --" also wipes out the
> changes on the other branch. It's like the merge symlinked the two branches
> rather than, well, merging them.

It does show you that there are changes in the working tree and you
could have switched back with "git co -", done whatever you want with
your changes then switched to master again.

> 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.

git tries to keep all changes on working tree you have. If you have
changes in file A and the new branch changes in file B, fine. If the
new branch also changes in file A too, it'll complain because
otherwise it may overwrite your changes. What it actual does is "Two
way merge", there is a table in "git read-tree" man page that
describes exactly how it is done, what cases would fail...

I see it as more choices. As I said above, it does tell you there are
changes and you could do something. You could make alias "co" that
check for worktree/index cleanliness before calling checkout.
Something like this maybe (I have not tested it)

git config alias.co '!git update-index --refresh && git diff-files
--quiet && git diff-index --cached --quiet HEAD && git checkout "$@"'

A config key to enforce this may be nice. I don't know, I have never
had problems with current behavior.
-- 
Duy

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 10:48 ` Nguyen Thai Ngoc Duy
@ 2011-10-13 10:59   ` Alexey Shumkin
  2011-10-13 11:51     ` arQon
  0 siblings, 1 reply; 36+ messages in thread
From: Alexey Shumkin @ 2011-10-13 10:59 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: arQon, git

> On Thu, Oct 13, 2011 at 7:40 PM, arQon <arqon@gmx.com> wrote:
> > $ git co master
> > M       code/renderer/tr_font.cpp
> > Switched to branch 'master'
> > Your branch is ahead of 'origin/master' by 3 commits.
> 
> ...
> 
> > At this point, reverting the master with "checkout --" also wipes
> > out the changes on the other branch. It's like the merge symlinked
> > the two branches rather than, well, merging them.
> 
> It does show you that there are changes in the working tree and you
> could have switched back with "git co -", done whatever you want with
> your changes then switched to master again.
> 
> > 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.
> 
> git tries to keep all changes on working tree you have. If you have
> changes in file A and the new branch changes in file B, fine. If the
> new branch also changes in file A too, it'll complain because
> otherwise it may overwrite your changes. What it actual does is "Two
> way merge", there is a table in "git read-tree" man page that
> describes exactly how it is done, what cases would fail...
> 
> I see it as more choices. As I said above, it does tell you there are
> changes and you could do something. You could make alias "co" that
> check for worktree/index cleanliness before calling checkout.
> Something like this maybe (I have not tested it)
> 
> git config alias.co '!git update-index --refresh && git diff-files
> --quiet && git diff-index --cached --quiet HEAD && git checkout "$@"'
> 
> A config key to enforce this may be nice. I don't know, I have never
> had problems with current behavior.

I agree with the explanation and I like current behavior, as well.

2arQon:
Your expectations is based on SVN experience but as ex-SVN-user, too, I
can (and I want to) say: Git is more flexible and powerful tool then SVN
is. Take is power and change your expectations, and your life will
become better )))

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 10:59   ` Alexey Shumkin
@ 2011-10-13 11:51     ` arQon
  2011-10-13 12:22       ` Andreas Ericsson
  2011-10-13 12:42       ` arQon
  0 siblings, 2 replies; 36+ messages in thread
From: arQon @ 2011-10-13 11:51 UTC (permalink / raw)
  To: git

Snipping the bug and focusing on one of the after-effects of the bug is,
unfortunately, not helpful to me unless I'm missing your point (which is
certainly possible).

git switched branches while there were uncommitted files. It's not supposed to
do this, ever, unless given -f or -m, and it broke the tree as a result. Even
*with* -f or -m, the behavior I described is incorrect.
The git docs seem to agree with me, which is why there's git stash. If the docs
are wrong, fine, though it seems pretty strange to have a change on BranchA
appear by magic "in" BranchB without any merging.

What I'm after is an understanding / explanation of how something that isn't
supposed to happen, does. I don't care if it's "Because I'm an idiot", "Because
git is broken", or even "Make sure your config has 'git.makebranchesworkproperly
= true' in it, the default is false". If there is no explanation for why git
switches branches when there are still uncommitted files, and there doesn't seem
to be, then it's a pretty catastrophic bug and fixing it would be a Good Thing.

*AFAICT*, committing *a* file is what triggers it.
If you commit -a, which is what all the commits prior to this were, it works
properly. You change branches, and the files on the disk become what they should
be.
If you commit nothing, you correctly get the "uncommitted files" error.
If you do a partial commit though, your tree breaks.

Like I say, if the man page, quote:
"If you have local modifications to one or more files that are different between
the current branch and the branch to which you are switching, the command
refuses to switch branches in order to preserve your modifications in context."
is wrong, and this behavior is deliberate, that's fine. Bizarre, but fine in
the sense that git is doing what it's supposed to (regardless of how
counterintuitive and destructive it is).
If the man page is right though, this is a bug. Maybe it's only in msysgit,
but this is the second time it's happened, so hopefully it's fairly easy to
reproduce.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 11:51     ` arQon
@ 2011-10-13 12:22       ` Andreas Ericsson
  2011-10-13 13:09         ` arQon
  2011-10-13 13:58         ` [BUG] " arQon
  2011-10-13 12:42       ` arQon
  1 sibling, 2 replies; 36+ messages in thread
From: Andreas Ericsson @ 2011-10-13 12:22 UTC (permalink / raw)
  To: arQon; +Cc: git

On 10/13/2011 01:51 PM, arQon wrote:
> Snipping the bug and focusing on one of the after-effects of the bug is,
> unfortunately, not helpful to me unless I'm missing your point (which is
> certainly possible).
> 
> git switched branches while there were uncommitted files. It's not supposed to
> do this, ever, unless given -f or -m, and it broke the tree as a result. Even
> *with* -f or -m, the behavior I described is incorrect.
> The git docs seem to agree with me, which is why there's git stash. If the docs
> are wrong, fine, though it seems pretty strange to have a change on BranchA
> appear by magic "in" BranchB without any merging.
> 
> What I'm after is an understanding / explanation of how something that isn't
> supposed to happen, does. I don't care if it's "Because I'm an idiot", "Because
> git is broken", or even "Make sure your config has 'git.makebranchesworkproperly
> = true' in it, the default is false". If there is no explanation for why git
> switches branches when there are still uncommitted files, and there doesn't seem
> to be, then it's a pretty catastrophic bug and fixing it would be a Good Thing.
> 
> *AFAICT*, committing *a* file is what triggers it.
> If you commit -a, which is what all the commits prior to this were, it works
> properly. You change branches, and the files on the disk become what they should
> be.
> If you commit nothing, you correctly get the "uncommitted files" error.
> If you do a partial commit though, your tree breaks.
> 
> Like I say, if the man page, quote:
> "If you have local modifications to one or more files that are different between
> the current branch and the branch to which you are switching, the command
> refuses to switch branches in order to preserve your modifications in context."


This means that if fileX on branchA is different from fileX on branchB and you
*also* have local modifications to fileX, git will refuse to switch branches.
If, on the other hand branchA:fileX == branchB:fileX and you have modifications
to fileX in your work tree, there's no reason to refuse the branch change.
Partly because nothing will be lost and partly because you can just switch
branches back if you decide you've switched branches before committing things
to the first branch.

> is wrong, and this behavior is deliberate, that's fine. Bizarre, but fine in
> the sense that git is doing what it's supposed to (regardless of how
> counterintuitive and destructive it is).
> If the man page is right though, this is a bug. Maybe it's only in msysgit,
> but this is the second time it's happened, so hopefully it's fairly easy to
> reproduce.
> 

It's not a bug. You just read the manpage a bit wrong.

Consider this scenario:
$dev works on featureA on branchA, modifying fileX, fileZ and fileY and then
does a commit of fileZ and fileY, but realizes that the changes in fileX
will be good for developing featureB as well, so he changes to a separate
branch to do the update to fileX and be able to merge those changes to
both branchA and branchB.

I've done this myself on numerous occasions when re-working small project-
local API's, and it's very, very handy indeed. If git would refuse me to
change branches without first committing everything I'd have to first
commit the change separately, switch branch, cherrypick the change, go
back to the first branch and remove the commit I made there, merge the
other branch where the commit really belonged and only then I could go
on about my business. If, on the other hand, I happen to switch branches
before committing fileZ in the above example, I can just switch back and
amend my last commit on the first branch.

So yes, this is a feature, and it's a handy one.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

Considering the successes of the wars on alcohol, poverty, drugs and
terror, I think we should give some serious thought to declaring war
on peace.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 11:51     ` arQon
  2011-10-13 12:22       ` Andreas Ericsson
@ 2011-10-13 12:42       ` arQon
  2011-10-13 12:55         ` Holger Hellmuth
  2011-10-13 14:44         ` Victor Engmark
  1 sibling, 2 replies; 36+ messages in thread
From: arQon @ 2011-10-13 12:42 UTC (permalink / raw)
  To: git

Simple testcase:

>git init
Initialized empty Git repository in C:/git-test/.git/
>notepad file1
>notepad file2
>git st
 # On branch master
 # Initial commit
 # Untracked files:
 #   (use "git add <file>..." to include in what will be committed)
 #       file1.txt
 #       file2.txt
 nothing added to commit but untracked files present (use "git add" to track)

>git add .
>git st
 # On branch master
 # Initial commit
 # Changes to be committed:
 #       new file:   file1.txt
 #       new file:   file2.txt

>git commit -am "init"
  2 files changed, 2 insertions(+), 0 deletions(-)
  create mode 100644 file1.txt
  create mode 100644 file2.txt

>git co -b foo
 Switched to a new branch 'foo'
>notepad file1
(edit stuff)
>git st
 # On branch foo
 # Changes not staged for commit:
 #       modified:   file1.txt

>git co master
 M       file1.txt

file1 now has the wrong data in it for "master" branch.

If I go back to "foo" branch and commit the file before doing anything else,
it recovers, and changing branches works correctly again.

--

"If you have local modifications to one or more files that are different
between the current branch and the branch to which you are switching, the
command refuses to switch branches in order to preserve your modifications
in context."

Maybe I'm just missing something obvious, but at the time that last "git
co master" was issued:

The file is locally modified.
The file is different on the current branch (foo) than on the branch to which
I am switching (master).
The command fails to refuse to switch branches.

So I guess the problem is that since the file wasn't re-added after the edit,
git is ignoring it when trying to see if it's safe to branch or not?

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 12:42       ` arQon
@ 2011-10-13 12:55         ` Holger Hellmuth
  2011-10-13 14:44         ` Victor Engmark
  1 sibling, 0 replies; 36+ messages in thread
From: Holger Hellmuth @ 2011-10-13 12:55 UTC (permalink / raw)
  To: arQon; +Cc: git

On 13.10.2011 14:42, arQon wrote:
>> git co -b foo
>   Switched to a new branch 'foo'
>> notepad file1
> (edit stuff)
>> git st
>   # On branch foo
>   # Changes not staged for commit:
>   #       modified:   file1.txt
>
>> git co master
>   M       file1.txt
>
> Maybe I'm just missing something obvious, but at the time that last "git
> co master" was issued:
>
> The file is locally modified.
> The file is different on the current branch (foo) than on the branch to which
> I am switching (master).

Wrong. On branch foo as well as on master the same old file1.txt is 
committed. You never staged nor committed the new file1.txt anywhere.

> The command fails to refuse to switch branches.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 12:22       ` Andreas Ericsson
@ 2011-10-13 13:09         ` arQon
  2011-10-13 13:59           ` Carlos Martín Nieto
  2011-10-13 13:58         ` [BUG] " arQon
  1 sibling, 1 reply; 36+ messages in thread
From: arQon @ 2011-10-13 13:09 UTC (permalink / raw)
  To: git

Andreas Ericsson <ae <at> op5.se> writes:
[snip]
> This means that if fileX on branchA is different from fileX on branchB and you
> *also* have local modifications to fileX, git will refuse to switch branches.
> If, on the other hand branchA:fileX == branchB:fileX and you have modifications
> to fileX in your work tree, there's no reason to refuse the branch change.

There's an EXCELLENT reason to refuse the branch change: once it happens, what
git is then telling is branchA, is not.

> It's not a bug. You just read the manpage a bit wrong.
[snip]
> So yes, this is a feature, and it's a handy one.

Thanks for the explanation. Unfortunately, I still can't see it as anything but
a critical bug. Consider this:

You're working on branchA and you have a bunch of uncommitted changes.
You can't remember some detail of the bug you're fixing, so you switch branches
to the master. You have to rebuild that branch, because your last build was from
your branch. git now builds the master with sources that were NEVER committed
to it. How is that not a total failure to maintain branch integrity?

If that's the way git is, then that's how it is; and if there isn't a setting
that can make it actually preserve branches properly, then there isn't. Which
sucks for me, because an SCCS that lies about what branch you're "really" on
is worse than useless, so I'm stuck with SVN.  :(

Thanks again for clearing it up for me though.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 12:22       ` Andreas Ericsson
  2011-10-13 13:09         ` arQon
@ 2011-10-13 13:58         ` arQon
  2011-10-13 14:46           ` Carlos Martín Nieto
  2011-10-13 16:08           ` Holger Hellmuth
  1 sibling, 2 replies; 36+ messages in thread
From: arQon @ 2011-10-13 13:58 UTC (permalink / raw)
  To: git

Andreas Ericsson <ae <at> op5.se> writes:
> there's no reason to refuse the branch change.
> Partly because nothing will be lost

Actually, this isn't true either, because of the second bug: doing a revert
in branchA causes the changes in branchB to be lost. This can't possibly be
the intended behavior: again, it completely violates the integrity of branches
by allowing changes on one branch to impact a different branch.

Your interpretation of the manpage doubtless matches the actual behavior of git,
but I find it staggering if that truly is what was intended. It basically means
that if you have local modifications, git will Break Your Entire Tree. That
makes changing while you *do* have local mods more than a little undesirable,
to put it mildly, which is something that a literal reading of the manpage would
suggest is exactly what the "refuse to switch" is for. I guess only Linus knows
what he actually meant.  :)

Anyway, I guess it's all moot: call it a feature or call it a bug, this cross-
branch destruction is a deal-breaker for me, especially given the bug above that
actually loses data outright, rather than "only" putting multiple branches into
an incorrect state.

Thanks for your time and help.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 13:09         ` arQon
@ 2011-10-13 13:59           ` Carlos Martín Nieto
  2011-10-13 17:09             ` [CLOSED] " arQon
  0 siblings, 1 reply; 36+ messages in thread
From: Carlos Martín Nieto @ 2011-10-13 13:59 UTC (permalink / raw)
  To: arQon; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 3195 bytes --]

On Thu, 2011-10-13 at 13:09 +0000, arQon wrote:
> Andreas Ericsson <ae <at> op5.se> writes:
> [snip]
> > This means that if fileX on branchA is different from fileX on branchB and you
> > *also* have local modifications to fileX, git will refuse to switch branches.
> > If, on the other hand branchA:fileX == branchB:fileX and you have modifications
> > to fileX in your work tree, there's no reason to refuse the branch change.
> 
> There's an EXCELLENT reason to refuse the branch change: once it happens, what
> git is then telling is branchA, is not.

When you changed branches, git told you that a file had been changed in
the working tree. When you run 'git diff', it tells you the differences
between what you have in your working tree and what's in the branch[0].
Git is trying hard not to loose your modifications (maybe it was a
one-liner, maybe it was three hours of work) to the file.

> 
> > It's not a bug. You just read the manpage a bit wrong.
> [snip]
> > So yes, this is a feature, and it's a handy one.
> 
> Thanks for the explanation. Unfortunately, I still can't see it as anything but
> a critical bug. Consider this:
> 
> You're working on branchA and you have a bunch of uncommitted changes.
> You can't remember some detail of the bug you're fixing, so you switch branches
> to the master. You have to rebuild that branch, because your last build was from
> your branch. git now builds the master with sources that were NEVER committed
> to it. How is that not a total failure to maintain branch integrity?

It sound like you've misunderstood what a branch is for git. A branch is
only ever changed when you commit. What checkout does is change what the
current branch is. For a case like what you describe, the developer
would either do a temporary commit that they'd change later or stash the
changes[1]. You could also use git-new-workdir (from contrib/) so you
have two different directories that share the object storage. That has a
few rough edges, but if you restrict it to a broken branch, you
shouldn't have any problems.

> 
> If that's the way git is, then that's how it is; and if there isn't a setting
> that can make it actually preserve branches properly, then there isn't. Which
> sucks for me, because an SCCS that lies about what branch you're "really" on
> is worse than useless, so I'm stuck with SVN.  :(

Don't think of it as being "in" a branch. A checkout in git changes the
active branch. If there are any files that are different between the two
branches, they are changed. By switching branches with uncommitted
changes, you're telling git that you would rather use the other branch
to do your changes in. But git isn't doing this silently. After the
checkout, it lists the files that have local modifications, so the
developer can switch branches again and commit or stash the changes.

   cmn

[0] Really it's between the working tree and the index, but since you
just switched branches, the index is the same, and using it in that
sentence would just cause confusion.

[1] 'git stash' is a command that saves your uncommitted changes on a
stack so you can recover them later.


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 12:42       ` arQon
  2011-10-13 12:55         ` Holger Hellmuth
@ 2011-10-13 14:44         ` Victor Engmark
  2011-10-13 16:17           ` arQon
  1 sibling, 1 reply; 36+ messages in thread
From: Victor Engmark @ 2011-10-13 14:44 UTC (permalink / raw)
  To: arQon; +Cc: git

On Thu, Oct 13, 2011 at 12:42:42PM +0000, arQon wrote:
> Simple testcase:
> 
> >git init
> Initialized empty Git repository in C:/git-test/.git/
> >notepad file1
> >notepad file2
> >git st
>  # On branch master
>  # Initial commit
>  # Untracked files:
>  #   (use "git add <file>..." to include in what will be committed)
>  #       file1.txt
>  #       file2.txt
>  nothing added to commit but untracked files present (use "git add" to track)
> 
> >git add .
> >git st
>  # On branch master
>  # Initial commit
>  # Changes to be committed:
>  #       new file:   file1.txt
>  #       new file:   file2.txt
> 
> >git commit -am "init"
>   2 files changed, 2 insertions(+), 0 deletions(-)
>   create mode 100644 file1.txt
>   create mode 100644 file2.txt
> 
> >git co -b foo
>  Switched to a new branch 'foo'
> >notepad file1
> (edit stuff)
> >git st
>  # On branch foo
>  # Changes not staged for commit:
>  #       modified:   file1.txt
> 
> >git co master
>  M       file1.txt
> 
> file1 now has the wrong data in it for "master" branch.

The most important thing a VCS should do is to keep history intact.
That happens when you check out in Git: No branches were changed, only
the working space. The second most important thing a VCS should do is
not destroy any of your uncommitted work unless you tell it to. That
also happens when you check out in Git. The third most important thing a
VCS should do is facilitate the developer's workflow. One common thing
to do is to work on some thing, for example refactoring. During this
process you might realize that one of the changes actually fixed a bug
in the software. To keep things in their right place, you could now
either
1. `checkout master` and commit the fix there, then shift back and
continue working, or
2. commit the refactorings, `checkout master`, and commit the fix there.
Either of these are easy to do with Git. There really is no reason why
the changes in the workspace should be considered as "part of" the
currently active branch, because they *are* not.

Cheers,
V

-- 
terreActive AG
Kasinostrasse 30
CH-5001 Aarau
Tel: +41 62 834 00 55
Fax: +41 62 823 93 56
www.terreactive.ch

Wir sichern Ihren Erfolg - seit 15 Jahren

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 13:58         ` [BUG] " arQon
@ 2011-10-13 14:46           ` Carlos Martín Nieto
  2011-10-13 15:53             ` arQon
  2011-10-13 16:08           ` Holger Hellmuth
  1 sibling, 1 reply; 36+ messages in thread
From: Carlos Martín Nieto @ 2011-10-13 14:46 UTC (permalink / raw)
  To: arQon; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 2570 bytes --]

On Thu, 2011-10-13 at 13:58 +0000, arQon wrote:
> Andreas Ericsson <ae <at> op5.se> writes:
> > there's no reason to refuse the branch change.
> > Partly because nothing will be lost
> 
> Actually, this isn't true either, because of the second bug: doing a revert
> in branchA causes the changes in branchB to be lost. This can't possibly be
> the intended behavior: again, it completely violates the integrity of branches
> by allowing changes on one branch to impact a different branch.

I have not seen a revert command in any of your messages. If a revert on
one branch changes another one, that would be a bug, but you haven't
shown this to happen.

> 
> Your interpretation of the manpage doubtless matches the actual behavior of git,
> but I find it staggering if that truly is what was intended. It basically means
> that if you have local modifications, git will Break Your Entire Tree. That
> makes changing while you *do* have local mods more than a little undesirable,
> to put it mildly, which is something that a literal reading of the manpage would
> suggest is exactly what the "refuse to switch" is for. I guess only Linus knows
> what he actually meant.  :)

Do not confuse a branch with a worktree. If you haven't committed yet,
those changes aren't in the branch (just like they wouldn't be in svn)

> 
> Anyway, I guess it's all moot: call it a feature or call it a bug, this cross-
> branch destruction is a deal-breaker for me, especially given the bug above that
> actually loses data outright, rather than "only" putting multiple branches into
> an incorrect state.

I've just asked some subversion developers to confirm this, and then
tried it out myself: Subversion (my locally-installed version is 1.6.17,
latest stable) behaves the same way. Local modifications are carried
over across branches.

$ svn copy ^/trunk ^/branches/somebranch # Create a new branch
$ $EDITOR somefile # which exists in trunk and somebranch
$ svn switch ^/branches/somebranch
$ svn diff # My local changes are there!

The reason this happens both in svn and git is that the most likely
cause for someone to change a branch mid-edit is that they decide
they're doing the changes on the wrong branch. What I did notice is that
svn doesn't tell you about the modifications being carried over
(presumably you're meant to use status and diff to figure out what's
going on). Therefore, the same workflow (with the only difference being
how to create and switch branches) works for svn and git in this case.

   cmn



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13  8:40 [BUG] git checkout <branch> allowed with uncommitted changes arQon
  2011-10-13 10:48 ` Nguyen Thai Ngoc Duy
@ 2011-10-13 15:09 ` Michael J Gruber
  1 sibling, 0 replies; 36+ messages in thread
From: Michael J Gruber @ 2011-10-13 15:09 UTC (permalink / raw)
  To: arQon; +Cc: git

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

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 14:46           ` Carlos Martín Nieto
@ 2011-10-13 15:53             ` arQon
  2011-10-13 16:17               ` Alexey Shumkin
                                 ` (4 more replies)
  0 siblings, 5 replies; 36+ messages in thread
From: arQon @ 2011-10-13 15:53 UTC (permalink / raw)
  To: git

Carlos Martín Nieto <cmn <at> elego.de> writes:
> I have not seen a revert command in any of your messages. If a revert on
> one branch changes another one, that would be a bug, but you haven't
> shown this to happen.

Sorry, it was in prose in the original post (near the end)
"At this point, reverting the master with "checkout --" also wipes out the
changes on the other branch. It's like the merge symlinked the two branches
rather than, well, merging them."

Based on the explanations here, and the git *st* message, it wiping out the
other branch is to be expected, because it's "the working directory", not
"the branch".

>git st
# On branch foo
# 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:   file1.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

What makes this really interesting though is this: I tried to switch to
master to see if that gave the same warning, and NOW, I get the correct
error.

>git co master
error: Your local changes to the following files would be overwritten by
checkout:
        file1.txt
Please, commit your changes or stash them before you can switch branches.
Aborting

I'm sure if I thought about it enough (ie re-read Andreas's post a couple
more times) I'd be able to understand why git gets it right sometimes but
not other times, but I'm too tired right now. Even when I *am* awake and
grok it properly, I'm still going to be annoyed that it's so inconsistent,
but I can live with that if I have to.

> The reason this happens both in svn and git is that the most likely
> cause for someone to change a branch mid-edit is that they decide
> they're doing the changes on the wrong branch.

Lucky you. :P  The most likely reason for me is, I'm working on something
and I get interrupted and have to switch. Since the code may well not even
compile at this point, the last thing I want to do is commit it. git's
ability for that commit to be local is half the reason I'm trying to switch
to it. (I'm not particularly keen on having to commit broken code to even a
local repo, but that's still a hell of a lot better than having it pushed
upstream as well).

> svn doesn't tell you about the modifications being carried over
> (presumably you're meant to use status and diff to figure out what's
> going on). Therefore, the same workflow (with the only difference being
> how to create and switch branches) works for svn and git in this case.

I expect part of my confusion comes from using different workdirs for svn
branches, ie "clone" rather than "branch", because branching in svn is such
a PITA I just don't bother with it unless the branch is going to be
"heavyweight" enough to warrant a "proper" branch.
Good to be reminded of though, thanks.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 13:58         ` [BUG] " arQon
  2011-10-13 14:46           ` Carlos Martín Nieto
@ 2011-10-13 16:08           ` Holger Hellmuth
  1 sibling, 0 replies; 36+ messages in thread
From: Holger Hellmuth @ 2011-10-13 16:08 UTC (permalink / raw)
  To: arQon; +Cc: git

On 13.10.2011 15:58, arQon wrote:
> Andreas Ericsson<ae<at>  op5.se>  writes:
>> there's no reason to refuse the branch change.
>> Partly because nothing will be lost
>
> Actually, this isn't true either, because of the second bug: doing a revert
> in branchA causes the changes in branchB to be lost. This can't possibly be
> the intended behavior: again, it completely violates the integrity of branches
> by allowing changes on one branch to impact a different branch.

I assume you mean revert through 'git checkout' and not through 'git 
revert'. Git uses a different philosphy. It works best with small 
commits and commits done often. It assumes that when you switch 
branches, you don't switch your brain as well and still know for what 
purpose you changed tr_font.cpp (and even if you forget you always can 
check with git diff).
It also reminds you that tr_font.cpp is changed when you switch branches 
(remember the "M tr_font.cpp" printed when you switched to another branch).
It assumes that when you use 'git checkout --' to wipe out changed files 
without committing them anywhere(!) that you have thought about it the 
same way you have thought about before deleting or overwriting any file 
in the file system. The same way you have thought about before deleting 
or overwriting an uncommitted file in svn.

What you term integrity of the branch is a model you made of the 
workings of svn that you now try to pin onto a different model.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 15:53             ` arQon
@ 2011-10-13 16:17               ` Alexey Shumkin
  2011-10-14  6:51                 ` Alexey Shumkin
  2011-10-13 16:32               ` Holger Hellmuth
                                 ` (3 subsequent siblings)
  4 siblings, 1 reply; 36+ messages in thread
From: Alexey Shumkin @ 2011-10-13 16:17 UTC (permalink / raw)
  To: arQon; +Cc: git

> Lucky you. :P  The most likely reason for me is, I'm working on
> something and I get interrupted and have to switch. Since the code
> may well not even compile at this point, the last thing I want to do
> is commit it. 
"git stash" helps here
With Git you can/have_to/must change your SVN-based habits.
DO NOT BE AFRAID OF FREQUENT COMMITS!
There are local until you push them.

>git's ability for that commit to be local is half the
> reason I'm trying to switch to it.
You always have a chance to modify/reedit you commits
see "git commit --amend" and "git rebase [-i]"

I'm telling you it as an ex-SVN user.
>(I'm not particularly keen on
> having to commit broken code to even a local repo, but that's still a
> hell of a lot better than having it pushed upstream as well).

Again, do not be afraid to commit your changes. Be afraid of losing
your changes. Git makes everything (as other discussion participants
already described) to keep your changes within workflow when you
switch between branches often.

Read some books which are describe Git's usual (and effective) workflow,
ProGit - http://progit.org/book/
Version Contol by Example (there is a chapter about Git) -
http://git-scm.com/course/svn.html

Hope, you'll feel the power of Git ))

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 14:44         ` Victor Engmark
@ 2011-10-13 16:17           ` arQon
  2011-10-14  7:16             ` Victor Engmark
  0 siblings, 1 reply; 36+ messages in thread
From: arQon @ 2011-10-13 16:17 UTC (permalink / raw)
  To: git

Victor Engmark <victor.engmark <at> terreactive.ch> writes:
> 1. `checkout master` and commit the fix there, then shift back and
> continue working

I absolutely agree. And it's far more common than any of us would like.
My point is, you *can't* do this in git without first staging your current branch
via either commit or stash, or you risk changes bleeding between the branches
and/or work being lost irretrievably. This is not something that you would
expect, and as you say:

> The second most important thing a VCS should do is not destroy any of your
uncommitted work unless you tell it to

... which is exactly what git does, and why I have a problem with it.
But the response here is uniformly "that's just how git is", so obviously it's
something you learn to become aware of over time, and avoid. It's not going to
get "fixed", because people who are used to git don't see it as a bug, so I just
have to decide whether I can live with it or not.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 15:53             ` arQon
  2011-10-13 16:17               ` Alexey Shumkin
@ 2011-10-13 16:32               ` Holger Hellmuth
  2011-10-13 17:04               ` Carlos Martín Nieto
                                 ` (2 subsequent siblings)
  4 siblings, 0 replies; 36+ messages in thread
From: Holger Hellmuth @ 2011-10-13 16:32 UTC (permalink / raw)
  To: arQon; +Cc: git

On 13.10.2011 17:53, arQon wrote:
>> git st
> # On branch foo
> # 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:   file1.txt
> #
> no changes added to commit (use "git add" and/or "git commit -a")
>
> What makes this really interesting though is this: I tried to switch to
> master to see if that gave the same warning, and NOW, I get the correct
> error.
>
>> git co master
> error: Your local changes to the following files would be overwritten by
> checkout:
>          file1.txt
> Please, commit your changes or stash them before you can switch branches.
> Aborting

At the end of your example (in a previous email) you were on branch 
master, now in the beginning you are on foo. So you at least changed 
branch again inbetween. maybe you also committed something? Check out 
git log or gitk

I tried your example and I can checkout master and foo again and again 
and I never see the error message.

> Lucky you. :P  The most likely reason for me is, I'm working on something
> and I get interrupted and have to switch. Since the code may well not even
> compile at this point, the last thing I want to do is commit it. git's
> ability for that commit to be local is half the reason I'm trying to switch
> to it. (I'm not particularly keen on having to commit broken code to even a
> local repo, but that's still a hell of a lot better than having it pushed
> upstream as well).

As Alexey already said, just commit and later amend. Or stash. Git 
encourages you to commit small changes you can put a name to. You never 
should delay a commit because it produces unworkable code. Instead have 
a master branch (or branches) that always compiles and branches for the 
unfinished stuff. Then it won't matter if some branch is only half working.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 15:53             ` arQon
  2011-10-13 16:17               ` Alexey Shumkin
  2011-10-13 16:32               ` Holger Hellmuth
@ 2011-10-13 17:04               ` Carlos Martín Nieto
  2011-10-13 18:19                 ` arQon
  2011-10-13 17:06               ` Sergei Organov
  2011-10-13 19:44               ` PJ Weisberg
  4 siblings, 1 reply; 36+ messages in thread
From: Carlos Martín Nieto @ 2011-10-13 17:04 UTC (permalink / raw)
  To: arQon; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 4828 bytes --]

On Thu, 2011-10-13 at 15:53 +0000, arQon wrote:
> Carlos Martín Nieto <cmn <at> elego.de> writes:
> > I have not seen a revert command in any of your messages. If a revert on
> > one branch changes another one, that would be a bug, but you haven't
> > shown this to happen.
> 
> Sorry, it was in prose in the original post (near the end)
> "At this point, reverting the master with "checkout --" also wipes out the
> changes on the other branch. It's like the merge symlinked the two branches
> rather than, well, merging them."
> 
> Based on the explanations here, and the git *st* message, it wiping out the
> other branch is to be expected, because it's "the working directory", not
> "the branch".
> 
> >git st
> # On branch foo
> # 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:   file1.txt
> #
> no changes added to commit (use "git add" and/or "git commit -a")
> 
> What makes this really interesting though is this: I tried to switch to
> master to see if that gave the same warning, and NOW, I get the correct
> error.
> 
> >git co master
> error: Your local changes to the following files would be overwritten by
> checkout:
>         file1.txt
> Please, commit your changes or stash them before you can switch branches.
> Aborting
> 
> I'm sure if I thought about it enough (ie re-read Andreas's post a couple
> more times) I'd be able to understand why git gets it right sometimes but
> not other times, but I'm too tired right now. Even when I *am* awake and
> grok it properly, I'm still going to be annoyed that it's so inconsistent,
> but I can live with that if I have to.

If file1.txt in the foo branch is different from the one in the master
branch, git will refuse to switch branches. 'git diff foo master' should
show that those two files are different.

> 
> > The reason this happens both in svn and git is that the most likely
> > cause for someone to change a branch mid-edit is that they decide
> > they're doing the changes on the wrong branch.
> 
> Lucky you. :P  The most likely reason for me is, I'm working on something
> and I get interrupted and have to switch. Since the code may well not even
> compile at this point, the last thing I want to do is commit it. git's
> ability for that commit to be local is half the reason I'm trying to switch
> to it. (I'm not particularly keen on having to commit broken code to even a
> local repo, but that's still a hell of a lot better than having it pushed
> upstream as well).

Yes, this is a great feature of distributed systems. A local repo is
where you experiment. Treat it as your own personal space to play around
with things. Committing non-working code is fine, as long as you don't
push it out.

> 
> > svn doesn't tell you about the modifications being carried over
> > (presumably you're meant to use status and diff to figure out what's
> > going on). Therefore, the same workflow (with the only difference being
> > how to create and switch branches) works for svn and git in this case.
> 
> I expect part of my confusion comes from using different workdirs for svn
> branches, ie "clone" rather than "branch", because branching in svn is such
> a PITA I just don't bother with it unless the branch is going to be
> "heavyweight" enough to warrant a "proper" branch.

Then the issue is that you've changed the workflow but haven't adjusted
for it. You can do this as well with the git-new-workdir. As I mentioned
it has a few rough edges, but if you're going to use it to have a
checkout of a particular branch, it shouldn't present any problems. That
would be like your current workflow.

Another option is to clone with a reference which will create a brand
new clone but will use the objects that you've already downloaded (or
just clone locally). This can be more comfortable than using the
new-workdir and will hardly put any strain on the filesystem.

The bigger problem seems to be your reluctance to accept that git is
different from subversion, as you keep saying "that's just how git is"
to back your claim that you can't trust git on a feature where
subversion behaves the same way. If you'd rather use different
directories for different branches, you can. That is not an aspect which
you can point to and say that you can't migrate to git for that reason.
If you're more comfortable with subversion, that's fine also, it's an
excellent piece of software[0], but don't go around saying that git
corrupts branches when that's blatantly not true.

   cmn

[0] Whatever one may think about the merits of CVCS vs DVCS; that
shouldn't come into the quality of the software.


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 15:53             ` arQon
                                 ` (2 preceding siblings ...)
  2011-10-13 17:04               ` Carlos Martín Nieto
@ 2011-10-13 17:06               ` Sergei Organov
  2011-10-13 19:44               ` PJ Weisberg
  4 siblings, 0 replies; 36+ messages in thread
From: Sergei Organov @ 2011-10-13 17:06 UTC (permalink / raw)
  To: arQon; +Cc: git

arQon <arqon@gmx.com> writes:

[...]

> Lucky you. :P  The most likely reason for me is, I'm working on something
> and I get interrupted and have to switch. Since the code may well not even
> compile at this point, the last thing I want to do is commit it.

'git stash' is exactly what you need then.

-- Sergei.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [CLOSED] git checkout <branch> allowed with uncommitted changes
  2011-10-13 13:59           ` Carlos Martín Nieto
@ 2011-10-13 17:09             ` arQon
  2011-10-13 18:56               ` Alexey Shumkin
  2011-10-13 19:01               ` Jakub Narebski
  0 siblings, 2 replies; 36+ messages in thread
From: arQon @ 2011-10-13 17:09 UTC (permalink / raw)
  To: git

Carlos Martín Nieto <cmn <at> elego.de> writes:
> When you changed branches, git told you that a file had been changed in
> the working tree.

That's a very good point, if it was actually documented at all that that's
what it meant; and / or presented some warning that "BTW, if you edit this
file again now, it'll screw up your whole tree" instead of an innocuous "M";
and didn't appear to contradict what the manpage says about "local
modifications", we could probably have avoided half of this confusion.  :P
As it was, when I saw that M suddenly appear after several days of bouncing
between branches without it and with everything working, I just thought
"oh great, git's managed to break this tree", because I remembered the same
thing from the previous trial run.

That there IS an indication though might just be enough for me to be able to
deal with it. Realistically, switching branches with uncommitted changes
(unless you're doing it because you've ALREADY screwed up and are changing
the wrong branch) is basically a trainwreck waiting to happen.

git stash appears to be useless for any nontrivial change on the *other*
branch, since there's no indication when you return to the stashed branch
there's a stash sitting around, which is not something you're going to
remember the next morning if fixing the master took the rest of the day,
and you're not going to use "stash list" by then either.

But as long as you get the "warning", an alias that does a "commit -am 'temp
commit to avoid git breaking the tree'" is something I think I can probably
live with.

Thanks for all the help guys - very much appreciated.
As far as I'm concerned, this topic's done.

(Though if someone can come up with a script / hook / whatever that improves
the "visibility" of stash, that would be awesome. Or one that makes the
refusal to switch branches consistent).

Looking at the manpage for checkout in the hope that there might be a "--safe"
switch, I don't understand why
  "-f  Proceed even if the index *or the working tree* differs from HEAD."
even exists, since it proceeds under those conditions anyway.
"--safe" appears to be exactly what the behavior should be if you DON'T
specify -f, except that -f nukes the working tree outright rather than just
bleeding it across. Hopefully it'll be clearer after some sleep.  :)

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 17:04               ` Carlos Martín Nieto
@ 2011-10-13 18:19                 ` arQon
  2011-10-13 18:28                   ` Junio C Hamano
  2011-10-13 20:07                   ` Carlos Martín Nieto
  0 siblings, 2 replies; 36+ messages in thread
From: arQon @ 2011-10-13 18:19 UTC (permalink / raw)
  To: git

Carlos Martín Nieto <cmn <at> elego.de> writes:
> If file1.txt in the foo branch is different from the one in the master
> branch, git will refuse to switch branches. 'git diff foo master' should
> show that those two files are different.

Right, but only for a definition of "branch" that is actually "a fully
committed branch", hence the confusion and the mention of "uncommitted
changes" in the topic.

An expectation that "co branch" should be analogous to "cd ../branch/" is by
no means unreasonable. YOU may know better, but it's surprisingly non-obvious,
especially considering the -f option on checkout and the wording of -m, both
of which strongly suggest that, in the absence of either of those flags, git
WILL preserve the worktree by refusing to switch until that potentially-
harmful situation is resolved by the user.

> Committing non-working code is fine, as long as you don't push it out.

Right, but for the problem I was describing it's actually "committing
non-working code is a requirement, in this situation, if you don't want your
tree to get eaten". Going from "you absolutely must not do this" to "you must
do this" takes some mental adjustment, but you also have to be *aware* that
you now have to do something that was previously prohibited, which I wasn't.

> The bigger problem seems to be your reluctance to accept that git is
> different from subversion

Not at all. If I didn't WANT something different, I wouldn't have been trying
to move to git in the first place.  :)

> but don't go around saying that git
> corrupts branches when that's blatantly not true.

See my first para in this post (or indeed, the original post). It's "not true"
provided all branches are fully committed when you switch between them.
It blatantly IS true if you switch from a dirty branch.
Redefining "branch" to mean "fully committed branch" makes it "not true" in
that context, but so does redefining green to be red and saying that grass is
red in that context: it may be correct from a certain POV, but it's
incomprehensible to anyone who isn't aware of that semantic change.

Anyway, I think we're done with this thread. Thanks for your (key) observation
earlier and several clarifications, and hopefully this will help the next guy
who runs into this problem and gets confused like I did.  :)

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 18:19                 ` arQon
@ 2011-10-13 18:28                   ` Junio C Hamano
  2011-10-13 18:56                     ` arQon
  2011-10-13 20:07                   ` Carlos Martín Nieto
  1 sibling, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2011-10-13 18:28 UTC (permalink / raw)
  To: arQon; +Cc: git

arQon <arqon@gmx.com> writes:

> ..., in the absence of either of those flags, git
> WILL preserve the worktree by refusing to switch until that potentially-
> harmful situation is resolved by the user.

Perhaps you can prepare a documentation patch to make it clear that git
WILL preserve the LOCAL CHANGES to the working tree?

As it would already be clear to anybody reading this thread so far, local
changes made to the working tree do not belong to any particular branch.
They are floating on top, and it is up to the user what to do with these
floating changes when they conflict with the differences between the
branches you are switching across (i.e. you cannot switch so you need to
clean up by either committing, stashing, or deciding not to switch and
instead complete the work before you switch), and when they do not
conflict with the differences between the branches you are switching
across (i.e. you will carry them to the new working tree. It may be that
you made these changes and then realized that they do not belong to the
goal the current branch aims to achieve and that is why you decided to
switch to another branch, in which case you do not have to do anything
special in order to continue to work and complete it to commit to the
switched branch. It may be that you made these changes but needed to tend
to unrelated business on an unrelated branch and that is why you switched,
in which case you would want to clear them away, which is exactly what
stash was invented for).

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [CLOSED] git checkout <branch> allowed with uncommitted changes
  2011-10-13 17:09             ` [CLOSED] " arQon
@ 2011-10-13 18:56               ` Alexey Shumkin
  2011-10-13 19:01               ` Jakub Narebski
  1 sibling, 0 replies; 36+ messages in thread
From: Alexey Shumkin @ 2011-10-13 18:56 UTC (permalink / raw)
  To: arQon; +Cc: git

> (Though if someone can come up with a script / hook / whatever that
> improves the "visibility" of stash, that would be awesome. 
> 
"git-completion" for Bash/ZSH gives such an opportunity
I use it

take a look into 
<git-sources>/contrib/completion/git-completion.bash
-- >8 --
#    3) Consider changing your PS1 to also show the current branch:
#         Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
#         ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
#
#       The argument to __git_ps1 will be displayed only if you
#       are currently in a git repository.  The %s token will be
#       the name of the current branch.
#
#       In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
#       value, unstaged (*) and staged (+) changes will be shown next
#       to the branch name.  You can configure this per-repository
#       with the bash.showDirtyState variable, which defaults to true
#       once GIT_PS1_SHOWDIRTYSTATE is enabled.
#
#       You can also see if currently something is stashed, by setting
#       GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is
stashed, #       then a '$' will be shown next to the branch name.
#
#       If you would like to see if there're untracked files, then you
can #       set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If
there're #       untracked files, then a '%' will be shown next to the
branch name. #
#       If you would like to see the difference between HEAD and its
#       upstream, set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates
#       you are behind, ">" indicates you are ahead, and "<>"
#       indicates you have diverged.
-- >8 --
my .bashrc contains (shortly)
PS1='\[\e]0;\w [$(__git_ps1 "%s")]\a\]\n\[\e[32m\]\u@\h'
PS1=$PS1' \[\e[33m\]\w\[\e[0m\]\n[$(__git_ps1 "%s")]\n\$'

export PS1
export GIT_PS1_SHOWDIRTYSTATE=1
export GIT_PS1_SHOWSTASHSTATE=1
export GIT_PS1_SHOWUPSTREAM="auto"

and console prompt with all possible cases looks like

<username>@<hostname> ~/Git-src.git/contrib/completion
[post-receive-email *+$>]
$ 

* - I have unstaged changes
+ - I have staged changes
$ - I have stashed changes (ta-daaa!)
> - I have commits ahead upsteam (named branch I branched from)

P.S. 
And JFYI, it is a good form in mailing lists to CC (Reply to all)
participants

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 18:28                   ` Junio C Hamano
@ 2011-10-13 18:56                     ` arQon
  2011-10-14  1:38                       ` Jeff King
  0 siblings, 1 reply; 36+ messages in thread
From: arQon @ 2011-10-13 18:56 UTC (permalink / raw)
  To: git

Junio C Hamano <gitster <at> pobox.com> writes:
> Perhaps you can prepare a documentation patch to make it clear that git
> WILL preserve the LOCAL CHANGES to the working tree?

Or to put that another way, git WILL NOT "rewind" those local changes when
switching branches (which I still think is the more common case for new users
than failing to branch before editing files). Or refuse to switch if you have
some. Except for when it does.

I'll give a shot, though I don't know how good it'll be. Off the top of my
head, I don't see any good way to explain the inconsistency with LOCAL CHANGES
sometimes preventing switches and sometimes not, based on what is to the user
an arbitrary set of rules that has nothing to do with the *current state* of
the worktree, but rather the state of those files in prior commits.

But sure, I'll see if I can come up with something. If nothing else, having the
manpage at least explain what "M" means; that it can be potentially disastrous;
and what you need to do to avoid it, would be a definite plus.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [CLOSED] git checkout <branch> allowed with uncommitted changes
  2011-10-13 17:09             ` [CLOSED] " arQon
  2011-10-13 18:56               ` Alexey Shumkin
@ 2011-10-13 19:01               ` Jakub Narebski
  1 sibling, 0 replies; 36+ messages in thread
From: Jakub Narebski @ 2011-10-13 19:01 UTC (permalink / raw)
  To: arQon; +Cc: git

arQon <arqon@gmx.com> writes:

> (Though if someone can come up with a script / hook / whatever that improves
> the "visibility" of stash, that would be awesome. Or one that makes the
> refusal to switch branches consistent).

Well, if you use __git_ps1 from contrib/completion/git-completion.bash
(installed with git-core package for some time), there is an option to
add '$' to branch name if stash is non-empty (though it doesn't actually
check if stash was on said branch).
 
> Looking at the manpage for checkout in the hope that there might be a "--safe"
> switch, I don't understand why
>
>   "-f  Proceed even if the index *or the working tree* differs from HEAD."
>
> even exists, since it proceeds under those conditions anyway.
> "--safe" appears to be exactly what the behavior should be if you DON'T
> specify -f, except that -f nukes the working tree outright rather than just
> bleeding it across. Hopefully it'll be clearer after some sleep.  :)
 
Without '-f' git-checkout would switch branches only if uncomitted
changes (which do not belong to any branch) could be "floated" on top
of new branch.

If branch you are switching to has differences from current branch
that conflict with uncomitted changes, git would refuse switching
branches.  Now '-f' would get rid of your uncomitted changes, and '-m'
try to merge it with changes brought by new branch.

HTH
-- 
Jakub Narębski

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 15:53             ` arQon
                                 ` (3 preceding siblings ...)
  2011-10-13 17:06               ` Sergei Organov
@ 2011-10-13 19:44               ` PJ Weisberg
  4 siblings, 0 replies; 36+ messages in thread
From: PJ Weisberg @ 2011-10-13 19:44 UTC (permalink / raw)
  To: git

On Thu, Oct 13, 2011 at 8:53 AM, arQon <arqon@gmx.com> wrote:
>>git co master
> error: Your local changes to the following files would be overwritten by
> checkout:
>        file1.txt
> Please, commit your changes or stash them before you can switch branches.
> Aborting
>
> I'm sure if I thought about it enough (ie re-read Andreas's post a couple
> more times) I'd be able to understand why git gets it right sometimes but
> not other times, but I'm too tired right now. Even when I *am* awake and

Git gets it "right" (by your definition) when file1.txt on one branch
is different from file1.txt on the other branch.  That means that
switching branches would require changing the file, so it refuses to
overwrite your changes by doing so.  If it CAN switch branches without
losing your changes, it does.

The fundamental problem is that you're thinking of the changes to the
working tree (which aren't commited) as being "on" some branch.  Until
they're committed, changes in the working tree are only in the working
tree.  That's basically the difference between "committed" and "not
committed".

-PJ

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 18:19                 ` arQon
  2011-10-13 18:28                   ` Junio C Hamano
@ 2011-10-13 20:07                   ` Carlos Martín Nieto
  1 sibling, 0 replies; 36+ messages in thread
From: Carlos Martín Nieto @ 2011-10-13 20:07 UTC (permalink / raw)
  To: arQon; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 3810 bytes --]

On Thu, 2011-10-13 at 18:19 +0000, arQon wrote:
> Carlos Martín Nieto <cmn <at> elego.de> writes:
> > If file1.txt in the foo branch is different from the one in the master
> > branch, git will refuse to switch branches. 'git diff foo master' should
> > show that those two files are different.
> 
> Right, but only for a definition of "branch" that is actually "a fully
> committed branch", hence the confusion and the mention of "uncommitted
> changes" in the topic.

I'm not aware of any other definition of a branch, either for git or
subversion.

> 
> An expectation that "co branch" should be analogous to "cd ../branch/" is by
> no means unreasonable. YOU may know better, but it's surprisingly non-obvious,

I don't see how. Switching branches is not the same as changing
directories. It doesn't work that way, neither with git nor subversion.
If you choose to have each branch in their own directory, that's fine,
but it has very little to do with the VCS tool.

> especially considering the -f option on checkout and the wording of -m, both
> of which strongly suggest that, in the absence of either of those flags, git
> WILL preserve the worktree by refusing to switch until that potentially-
> harmful situation is resolved by the user.

The general description could probably benefit from a more explicit
mention of what happens if there are local modifications. Currently it
looks like it's only mentioned in the text of -f and -m, which is not
particularly helpful.

> 
> > Committing non-working code is fine, as long as you don't push it out.
> 
> Right, but for the problem I was describing it's actually "committing
> non-working code is a requirement, in this situation, if you don't want your
> tree to get eaten". Going from "you absolutely must not do this" to "you must
> do this" takes some mental adjustment, but you also have to be *aware* that
> you now have to do something that was previously prohibited, which I wasn't.

You can also have a different directory for the other branch if you
really don't want to commit until it works. This is the same situation
that you find yourself right now with subversion; I don't see how it's
that hard to recognise that.

> 
> > The bigger problem seems to be your reluctance to accept that git is
> > different from subversion
> 
> Not at all. If I didn't WANT something different, I wouldn't have been trying
> to move to git in the first place.  :)
> 
> > but don't go around saying that git
> > corrupts branches when that's blatantly not true.
> 
> See my first para in this post (or indeed, the original post). It's "not true"
> provided all branches are fully committed when you switch between them.

Right.

> It blatantly IS true if you switch from a dirty branch.

No. The branch has not been corrupted or changed at all. Your local
modifications to files in the working tree were kept. Again, this
happens both for git and svn.

> Redefining "branch" to mean "fully committed branch" makes it "not true" in
> that context, but so does redefining green to be red and saying that grass is
> red in that context: it may be correct from a certain POV, but it's
> incomprehensible to anyone who isn't aware of that semantic change.

This smells like FUD. A branch and a directory are two different things.
If you find it more comfortable to use different directories for
different branches that's fine, but that doesn't make it a branch.
Changing a file doesn't automatically mean that that version of the file
belongs to the currently active branch (or URL in the case for svn). A
branch is only ever changed when you commit. This is something that
holds true across VCSs. Play with subversion's 'switch' command, it
behaves the same way.

   cmn


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 18:56                     ` arQon
@ 2011-10-14  1:38                       ` Jeff King
  2011-10-14  9:27                         ` Holger Hellmuth
  0 siblings, 1 reply; 36+ messages in thread
From: Jeff King @ 2011-10-14  1:38 UTC (permalink / raw)
  To: arQon; +Cc: git

On Thu, Oct 13, 2011 at 06:56:14PM +0000, arQon wrote:

> I'll give a shot, though I don't know how good it'll be. Off the top of my
> head, I don't see any good way to explain the inconsistency with LOCAL CHANGES
> sometimes preventing switches and sometimes not, based on what is to the user
> an arbitrary set of rules that has nothing to do with the *current state* of
> the worktree, but rather the state of those files in prior commits.

The rules are fairly straightforward.  You are moving from branch A to
branch B. If path X is not changed going from A to B, git will not touch
it, whether or not you have local changes. If path X is changed going
from A to B, then git will refuse the checkout, and you have the option
of:

  1. checkout -f: overwrite your local changes with what's in B

  2. checkout -m: merge your changes with what's in B (using A as a
                  common ancestor)

> But sure, I'll see if I can come up with something. If nothing else,
> having the manpage at least explain what "M" means; that it can be
> potentially disastrous; and what you need to do to avoid it, would be
> a definite plus.

You keep saying things like "disastrous". Git's rules are specifically
designed to be as flexible as possible without allowing the checkout
command to cause data loss.

Do you actually have a case that causes irrecoverable data loss?

Note that I don't count "these changes were based on A, now they are
based on B" as data loss. Your file content is still completely intact,
and if you want to make them based on "A" again, you just need to
"git checkout A" again.

-Peff

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 16:17               ` Alexey Shumkin
@ 2011-10-14  6:51                 ` Alexey Shumkin
  0 siblings, 0 replies; 36+ messages in thread
From: Alexey Shumkin @ 2011-10-14  6:51 UTC (permalink / raw)
  To: arQon; +Cc: git

> > Lucky you. :P  The most likely reason for me is, I'm working on
> > something and I get interrupted and have to switch. Since the code
> > may well not even compile at this point, the last thing I want to do
> > is commit it. 
> "git stash" helps here
> With Git you can/have_to/must change your SVN-based habits.
> DO NOT BE AFRAID OF FREQUENT COMMITS!
> There are local until you push them.
> 
> >git's ability for that commit to be local is half the
> > reason I'm trying to switch to it.
> You always have a chance to modify/reedit you commits
> see "git commit --amend" and "git rebase [-i]"
> 
> I'm telling you it as an ex-SVN user.
> >(I'm not particularly keen on
> > having to commit broken code to even a local repo, but that's still
> > a hell of a lot better than having it pushed upstream as well).
> 
> Again, do not be afraid to commit your changes. Be afraid of losing
> your changes. Git makes everything (as other discussion participants
> already described) to keep your changes within workflow when you
> switch between branches often.
> 
> Read some books which are describe Git's usual (and effective)
> workflow, ProGit - http://progit.org/book/
> Version Contol by Example (there is a chapter about Git) -
> http://git-scm.com/course/svn.html
oops,
wrong url

fixed link
Version Contol by Example (there is a chapter about Git) -
http://www.ericsink.com/vcbe/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-13 16:17           ` arQon
@ 2011-10-14  7:16             ` Victor Engmark
  0 siblings, 0 replies; 36+ messages in thread
From: Victor Engmark @ 2011-10-14  7:16 UTC (permalink / raw)
  To: arQon; +Cc: git

On Thu, Oct 13, 2011 at 04:17:51PM +0000, arQon wrote:
> Victor Engmark <victor.engmark <at> terreactive.ch> writes:
> > 1. `checkout master` and commit the fix there, then shift back and
> > continue working
> 
> I absolutely agree. And it's far more common than any of us would like.
> My point is, you *can't* do this in git without first staging your current branch
> via either commit or stash, or you risk changes bleeding between the branches
> and/or work being lost irretrievably.

It's been pointed out enough times already that work is *not* lost (at
least unless you --force it to) *nor* the branches corrupted, so I'll
just advice to look at more Git documentation. I used CVS 2004-2006 or
so, Subversion 2006-2009, and Git since then. It's vastly superior to
either, and it's really difficult to lose any work unless getting into
the habit of forcing every change.

> This is not something that you would
> expect, and as you say:
> 
> > The second most important thing a VCS should do is not destroy any of your
> uncommitted work unless you tell it to
> 
> ... which is exactly what git does, and why I have a problem with it.

No, it does not. Others have explained this better already.

> But the response here is uniformly "that's just how git is", so obviously it's
> something you learn to become aware of over time, and avoid. It's not going to
> get "fixed", because people who are used to git don't see it as a bug, so I just
> have to decide whether I can live with it or not.

It took a while to get my head around just how broken the Subversion
model was, and why my expectations from using that model kept resulting
in "weird" state (although don't get me started on `svn clean`). Don't
worry, you'll see the light :)

-- 
terreActive AG
Kasinostrasse 30
CH-5001 Aarau
Tel: +41 62 834 00 55
Fax: +41 62 823 93 56
www.terreactive.ch

Wir sichern Ihren Erfolg - seit 15 Jahren

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-14  1:38                       ` Jeff King
@ 2011-10-14  9:27                         ` Holger Hellmuth
  2011-10-14  9:54                           ` Victor Engmark
  0 siblings, 1 reply; 36+ messages in thread
From: Holger Hellmuth @ 2011-10-14  9:27 UTC (permalink / raw)
  To: Jeff King; +Cc: arQon, git

On 14.10.2011 03:38, Jeff King wrote:
> On Thu, Oct 13, 2011 at 06:56:14PM +0000, arQon wrote:
>
>> I'll give a shot, though I don't know how good it'll be. Off the top of my
>> head, I don't see any good way to explain the inconsistency with LOCAL CHANGES
>> sometimes preventing switches and sometimes not, based on what is to the user
>> an arbitrary set of rules that has nothing to do with the *current state* of
>> the worktree, but rather the state of those files in prior commits.
>
> The rules are fairly straightforward.

They are. But what arQon is getting at is that the normal switchability 
depends on something that is often a game of chance: Did I change a file 
that is different between the two branches? That is only known by the 
user for branches not far removed.

Now the obvious answer is: It doesn't matter because git tells you. At 
the right time to act upon it. But git says "M file" instead of what 
'git status' would say: "#  modified:   file". Is there a reason for 
that? On one hand it should be familiar to svn users, on the other hand 
it is an inconsistency. And personally I always hated those cryptic 
status flags of svn

Another good point arQon made is that the case that you switched with 
forgotten local changes is more common than the case that you switched 
because you made changes in the wrong branch. If that were the case the 
warning that you have local changes should be more visible than that 
small "M file", at best something that looks similar to 'git status' output.

Now what really is more common depends on the individual. If you are a 
beginner or a semi-frequent user, then forgetting local changes is 
probably far more common, wheras most people on this mailing list would 
say its the other way round. It much depends on your commit frequency 
because the more often you commit, the less likely is that you would 
forget local changes.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-14  9:27                         ` Holger Hellmuth
@ 2011-10-14  9:54                           ` Victor Engmark
  2011-10-16 18:25                             ` arQon
  0 siblings, 1 reply; 36+ messages in thread
From: Victor Engmark @ 2011-10-14  9:54 UTC (permalink / raw)
  To: Holger Hellmuth; +Cc: Jeff King, arQon, git

On Fri, Oct 14, 2011 at 11:27:47AM +0200, Holger Hellmuth wrote:
> On 14.10.2011 03:38, Jeff King wrote:
> >On Thu, Oct 13, 2011 at 06:56:14PM +0000, arQon wrote:
> >
> >>I'll give a shot, though I don't know how good it'll be. Off the top of my
> >>head, I don't see any good way to explain the inconsistency with LOCAL CHANGES
> >>sometimes preventing switches and sometimes not, based on what is to the user
> >>an arbitrary set of rules that has nothing to do with the *current state* of
> >>the worktree, but rather the state of those files in prior commits.
> >
> >The rules are fairly straightforward.
> 
> They are. But what arQon is getting at is that the normal
> switchability depends on something that is often a game of chance:
> Did I change a file that is different between the two branches? That
> is only known by the user for branches not far removed.
> 
> Now the obvious answer is: It doesn't matter because git tells you.
> At the right time to act upon it. But git says "M file" instead of
> what 'git status' would say: "#  modified:   file". Is there a
> reason for that? On one hand it should be familiar to svn users, on
> the other hand it is an inconsistency. And personally I always hated
> those cryptic status flags of svn
> 
> Another good point arQon made is that the case that you switched
> with forgotten local changes is more common than the case that you
> switched because you made changes in the wrong branch. If that were
> the case the warning that you have local changes should be more
> visible than that small "M file", at best something that looks
> similar to 'git status' output.

Very good point. How about by default just running `git status` after a
successful checkout, and only printing the result if there are any
changes? That way:
1) If no changes are pending, nothing is displayed.
2) The user sees a *familiar* style output if anything changed.
3) If there's an alias for "status", it would be used.

Example:

$ mkdir /tmp/test
$ cd /tmp/test
$ git init
Initialized empty Git repository in /tmp/test/.git/
$ echo foo > foo
$ echo bar > bar
$ git add foo bar
$ git commit -m "Initial commit"
[master (root-commit) 55246c6] Initial commit
 2 files changed, 2 insertions(+), 0 deletions(-)
 create mode 100644 bar
 create mode 100644 foo
$ echo foobar > bar
$ git branch --track test
Branch test set up to track local branch master.
$ git checkout test
M   bar
Switched to branch 'test'

After `git checkout test`, we should instead see:
# On branch test
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   bar
#
no changes added to commit (use "git add" and/or "git commit -a")

2c,
V

-- 
terreActive AG
Kasinostrasse 30
CH-5001 Aarau
Tel: +41 62 834 00 55
Fax: +41 62 823 93 56
www.terreactive.ch

Wir sichern Ihren Erfolg - seit 15 Jahren

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-14  9:54                           ` Victor Engmark
@ 2011-10-16 18:25                             ` arQon
  2011-10-16 20:37                               ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: arQon @ 2011-10-16 18:25 UTC (permalink / raw)
  To: git

Victor Engmark <victor.engmark <at> terreactive.ch> writes:
> Very good point. How about by default just running `git status` after a
> successful checkout, and only printing the result if there are any
> changes? That way:
> 1) If no changes are pending, nothing is displayed.
> 2) The user sees a *familiar* style output if anything changed.
> 3) If there's an alias for "status", it would be used.

I'm sold on this. Better documentation for checkout wouldn't hurt regardless,
and I'm still planning on that when I get a chance; but better *behavior* is a
clear win either way. Adding half a page of text to the docs explaining what
each status char means is a hugely-inferior "solution" to simply not having
an aberrant status-ish output in the first place.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-16 18:25                             ` arQon
@ 2011-10-16 20:37                               ` Junio C Hamano
  2011-10-16 22:04                                 ` Holger Hellmuth
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2011-10-16 20:37 UTC (permalink / raw)
  To: arQon; +Cc: git

arQon <arqon@gmx.com> writes:

> ... better *behavior* is a
> clear win either way.

I doubt the full status output is better behaviour. For one thing, you do
not need full status as by definition branch switching would only have
local changes as a result (i.e. you will not see "Changes to be committed"
section).

But if you really do not want to learn how to read "diff --name-status"
output, here is a patch to allow you say "git checkout -v other_branch".
Hopefully it will help you convince yourself why it is not a better
behaviour.

 builtin/checkout.c |   46 +++++++++++++++++++++++++++++++++-------------
 1 files changed, 33 insertions(+), 13 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index 49a547a..0c21556 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -28,7 +28,7 @@ static const char * const checkout_usage[] = {
 };
 
 struct checkout_opts {
-	int quiet;
+	int verbosity;
 	int merge;
 	int force;
 	int force_detach;
@@ -291,10 +291,10 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
 	return errs;
 }
 
-static void show_local_changes(struct object *head, struct diff_options *opts)
+static void show_local_changes_brief(struct object *head, struct diff_options *opts)
 {
 	struct rev_info rev;
-	/* I think we want full paths, even if we're in a subdirectory. */
+
 	init_revisions(&rev, NULL);
 	rev.diffopt.flags = opts->flags;
 	rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
@@ -304,6 +304,26 @@ static void show_local_changes(struct object *head, struct diff_options *opts)
 	run_diff_index(&rev, 0);
 }
 
+static void show_local_changes_status(void)
+{
+	const char *argv[] = { "status", NULL };
+
+	run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
+static void show_local_changes(struct checkout_opts *opts,
+			       struct object *head,
+			       struct diff_options *diffopts)
+{
+	if (opts->force || opts->verbosity < 0)
+		return;
+
+	if (0 < opts->verbosity)
+		show_local_changes_status();
+	else
+		show_local_changes_brief(head, diffopts);
+}
+
 static void describe_detached_head(const char *msg, struct commit *commit)
 {
 	struct strbuf sb = STRBUF_INIT;
@@ -326,7 +346,7 @@ static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
 	opts.reset = 1;
 	opts.merge = 1;
 	opts.fn = oneway_merge;
-	opts.verbose_update = !o->quiet;
+	opts.verbose_update = (0 <= o->verbosity);
 	opts.src_index = &the_index;
 	opts.dst_index = &the_index;
 	parse_tree(tree);
@@ -403,7 +423,7 @@ static int merge_working_tree(struct checkout_opts *opts,
 		topts.update = 1;
 		topts.merge = 1;
 		topts.gently = opts->merge && old->commit;
-		topts.verbose_update = !opts->quiet;
+		topts.verbose_update = (0 <= opts->verbosity);
 		topts.fn = twoway_merge;
 		topts.dir = xcalloc(1, sizeof(*topts.dir));
 		topts.dir->flags |= DIR_SHOW_IGNORED;
@@ -478,9 +498,6 @@ static int merge_working_tree(struct checkout_opts *opts,
 	    commit_locked_index(lock_file))
 		die(_("unable to write new index file"));
 
-	if (!opts->force && !opts->quiet)
-		show_local_changes(&new->commit->object, &opts->diff_options);
-
 	return 0;
 }
 
@@ -552,14 +569,14 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 	} else if (opts->force_detach || !new->path) {	/* No longer on any branch. */
 		update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 			   REF_NODEREF, DIE_ON_ERR);
-		if (!opts->quiet) {
+		if (0 <= opts->verbosity) {
 			if (old->path && advice_detached_head)
 				detach_advice(old->path, new->name);
 			describe_detached_head(_("HEAD is now at"), new->commit);
 		}
 	} else if (new->path) {	/* Switch branches. */
 		create_symref("HEAD", new->path, msg.buf);
-		if (!opts->quiet) {
+		if (0 <= opts->verbosity) {
 			if (old->path && !strcmp(new->path, old->path)) {
 				fprintf(stderr, _("Already on '%s'\n"),
 					new->name);
@@ -584,7 +601,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 	}
 	remove_branch_state();
 	strbuf_release(&msg);
-	if (!opts->quiet &&
+	if (0 <= opts->verbosity &&
 	    (new->path || (!opts->force_detach && !strcmp(new->name, "HEAD"))))
 		report_tracking(new);
 }
@@ -717,13 +734,16 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 	if (ret)
 		return ret;
 
-	if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
+	if (0 <= opts->verbosity && !old.path && old.commit && new->commit != old.commit)
 		orphaned_commit_warning(old.commit);
 
 	update_refs_for_switch(opts, &old, new);
 
 	ret = post_checkout_hook(old.commit, new->commit, 1);
 	free((char *)old.path);
+
+	show_local_changes(opts, &new->commit->object, &opts->diff_options);
+
 	return ret || opts->writeout_error;
 }
 
@@ -906,7 +926,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	int patch_mode = 0;
 	int dwim_new_local_branch = 1;
 	struct option options[] = {
-		OPT__QUIET(&opts.quiet, "suppress progress reporting"),
+		OPT__VERBOSITY(&opts.verbosity),
 		OPT_STRING('b', NULL, &opts.new_branch, "branch",
 			   "create and checkout a new branch"),
 		OPT_STRING('B', NULL, &opts.new_branch_force, "branch",

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [BUG] git checkout <branch> allowed with uncommitted changes
  2011-10-16 20:37                               ` Junio C Hamano
@ 2011-10-16 22:04                                 ` Holger Hellmuth
  0 siblings, 0 replies; 36+ messages in thread
From: Holger Hellmuth @ 2011-10-16 22:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: arQon, git

Am 16.10.2011 22:37, schrieb Junio C Hamano:
> I doubt the full status output is better behaviour. For one thing, you do
> not need full status as by definition branch switching would only have
> local changes as a result (i.e. you will not see "Changes to be committed"
> section).

?? After "git add" on a changed file I see it under "Changes to be 
committed". And branch switching still works (with newest git from 
master branch):

# On branch two
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   test1.txt
#
# 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:   test2.txt
#

Small inconsistency: On the other branch instead of "Changes not staged 
for commit:" the text "Changed but not updated:" is printed, everything 
else is unchanged

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2011-10-16 22:05 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-13  8:40 [BUG] git checkout <branch> allowed with uncommitted changes arQon
2011-10-13 10:48 ` Nguyen Thai Ngoc Duy
2011-10-13 10:59   ` Alexey Shumkin
2011-10-13 11:51     ` arQon
2011-10-13 12:22       ` Andreas Ericsson
2011-10-13 13:09         ` arQon
2011-10-13 13:59           ` Carlos Martín Nieto
2011-10-13 17:09             ` [CLOSED] " arQon
2011-10-13 18:56               ` Alexey Shumkin
2011-10-13 19:01               ` Jakub Narebski
2011-10-13 13:58         ` [BUG] " arQon
2011-10-13 14:46           ` Carlos Martín Nieto
2011-10-13 15:53             ` arQon
2011-10-13 16:17               ` Alexey Shumkin
2011-10-14  6:51                 ` Alexey Shumkin
2011-10-13 16:32               ` Holger Hellmuth
2011-10-13 17:04               ` Carlos Martín Nieto
2011-10-13 18:19                 ` arQon
2011-10-13 18:28                   ` Junio C Hamano
2011-10-13 18:56                     ` arQon
2011-10-14  1:38                       ` Jeff King
2011-10-14  9:27                         ` Holger Hellmuth
2011-10-14  9:54                           ` Victor Engmark
2011-10-16 18:25                             ` arQon
2011-10-16 20:37                               ` Junio C Hamano
2011-10-16 22:04                                 ` Holger Hellmuth
2011-10-13 20:07                   ` Carlos Martín Nieto
2011-10-13 17:06               ` Sergei Organov
2011-10-13 19:44               ` PJ Weisberg
2011-10-13 16:08           ` Holger Hellmuth
2011-10-13 12:42       ` arQon
2011-10-13 12:55         ` Holger Hellmuth
2011-10-13 14:44         ` Victor Engmark
2011-10-13 16:17           ` arQon
2011-10-14  7:16             ` Victor Engmark
2011-10-13 15:09 ` Michael J Gruber

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).