{"thread":{"id":"28664","subject":"[BUG] git checkout <branch> allowed with uncommitted changes","startedAt":"2011-10-13T08:40:40Z","lastAt":"2011-10-16T22:04:35Z","messageCount":36,"participants":["arQon","Nguyen Thai Ngoc Duy","Alexey Shumkin","Andreas Ericsson","Holger Hellmuth","Carlos Martín Nieto","Victor Engmark","Michael J Gruber","Sergei Organov","Junio C Hamano","Jakub Narebski","PJ Weisberg","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"177534","messageId":"loom.20111013T094053-111@post.gmane.org","threadId":"28664","inReplyTo":null,"subject":"[BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T08:40:40Z","receivedAt":"2011-10-13T08:40:40Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Which, as you'd expect, results in both the on-disk copies and other branches\nbecoming corrupted.\n\nTested on git versions 1.7.6 and 1.7.7 (msysgit)\n\nhttp://benno.id.au/blog/2011/10/01/git-recursive-merge-broken describes\nsomething that sounds similar, but that's supposedly fixed on 1.7.7,\nwhereas this happens on that as well.\n\nmaster is a tracking branch, \"ttfcon\" is the branch I was using to develop\na change. Got to a good point on the branch, merged it in:\n\n$ git co master\n$ git merge ttfcon\nUpdating b9f0c75..6280b7a\nFast-forward\n .gitignore                |    2 ++\n code/renderer/tr_font.cpp |   27 ++++++++-------------------\n 2 files changed, 10 insertions(+), 19 deletions(-)\n\n$ git st\n# On branch master\n# Your branch is ahead of 'origin/master' by 3 commits.\n\nback to the branch to mess around with a couple of things to be sure this\nis what i want to push\n$ git co ttfcon\ndo stuff\n\n$ git st\n# On branch ttfcon\n# Changes not staged for commit:\n#   (use \"git add <file>...\" to update what will be committed)\n#   (use \"git checkout -- <file>...\" to discard changes in working directory)\n#\n#       modified:   code/freetype-2.3.11/builds/win32/visualc/freetype.vcproj\n#       modified:   code/renderer/tr_font.cpp\n\nso far so good...\n\n$ git ci -m \"blah\" code/freetype-2.3.11/builds/win32/visualc/freetype.vcproj\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\nnote that tr_font is locally modified and still *not committed* at this point.\n\n$ git co master\nM       code/renderer/tr_font.cpp\nSwitched to branch 'master'\nYour branch is ahead of 'origin/master' by 3 commits.\n\nboom. instead of rejecting the branch change, git switches branches anyway,\nand doesn't do anything about the uncommitted changes in the file itself -\nmeaning they're now effectively \"in\" master because they're still on disk,\nso now the master is poisoned.\n\n\"git st\" does show the change:\n\n# On branch master\n# Changes not staged for commit:\n#       modified:   code/renderer/tr_font.cpp\n\nbut it's a change I never MADE on this branch (ie master), only on the\nother branch.\n\n\"git diff\" is just as confused as I am:\n\n$ git diff ttfcon\n--- a/code/renderer/tr_font.cpp\n+++ b/code/renderer/tr_font.cpp\n+\t\t// git branch bug\n\nSo it's picking up the difference between the two branches, but as far as\nthe *actual file* goes, master now has a line in it that shouldn't be there.\n\nI'm just trying out git as a possible replacement for SVN, so maybe I'm\nmistaken about what \"should\" happen, but AIUI git switching branches with\nuncommitted changes is a bug (and given that it poisoned a branch that I\nwasn't on, it certainly looks like one). A couple of days ago it DID complain\nwhen I tried to switch with uncommitted files still present, so it was working\nproperly then. I have no idea what's made it happy to ignore them now:\nnothing's changed that I know of.\n\nAt this point, reverting the master with \"checkout --\" also wipes out the\nchanges on the other branch. It's like the merge symlinked the two branches\nrather than, well, merging them.\n\nIf this is user error, and merge is supposed to break the tree like that,\nthen sorry for wasting your time, but I can't find anything in the docs that\nsays (or even suggests) that it should, so...\n\nThanks.\n"},{"id":"177536","messageId":"CACsJy8Dzy5-kOZAjwdx=ooUdnN0L2F3EiNQ7b==3AGQZYjEUXQ@mail.gmail.com","threadId":"28664","inReplyTo":"loom.20111013T094053-111@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-10-13T10:48:05Z","receivedAt":"2011-10-13T10:48:05Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Oct 13, 2011 at 7:40 PM, arQon <arqon@gmx.com> wrote:\n> $ git co master\n> M       code/renderer/tr_font.cpp\n> Switched to branch 'master'\n> Your branch is ahead of 'origin/master' by 3 commits.\n\n...\n\n> At this point, reverting the master with \"checkout --\" also wipes out the\n> changes on the other branch. It's like the merge symlinked the two branches\n> rather than, well, merging them.\n\nIt does show you that there are changes in the working tree and you\ncould have switched back with \"git co -\", done whatever you want with\nyour changes then switched to master again.\n\n> A couple of days ago it DID complain\n> when I tried to switch with uncommitted files still present, so it was working\n> properly then. I have no idea what's made it happy to ignore them now:\n> nothing's changed that I know of.\n\ngit tries to keep all changes on working tree you have. If you have\nchanges in file A and the new branch changes in file B, fine. If the\nnew branch also changes in file A too, it'll complain because\notherwise it may overwrite your changes. What it actual does is \"Two\nway merge\", there is a table in \"git read-tree\" man page that\ndescribes exactly how it is done, what cases would fail...\n\nI see it as more choices. As I said above, it does tell you there are\nchanges and you could do something. You could make alias \"co\" that\ncheck for worktree/index cleanliness before calling checkout.\nSomething like this maybe (I have not tested it)\n\ngit config alias.co '!git update-index --refresh && git diff-files\n--quiet && git diff-index --cached --quiet HEAD && git checkout \"$@\"'\n\nA config key to enforce this may be nice. I don't know, I have never\nhad problems with current behavior.\n-- \nDuy\n"},{"id":"177539","messageId":"20111013145924.2113c142@ashu.dyn.rarus.ru","threadId":"28664","inReplyTo":"CACsJy8Dzy5-kOZAjwdx=ooUdnN0L2F3EiNQ7b==3AGQZYjEUXQ@mail.gmail.com","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Alexey Shumkin","fromEmail":"alex.crezoff@gmail.com","sentAt":"2011-10-13T10:59:24Z","receivedAt":"2011-10-13T10:59:24Z","isPatch":false,"sender":{"key":"alex.crezoff@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1183752?v=4"},"body":"> On Thu, Oct 13, 2011 at 7:40 PM, arQon <arqon@gmx.com> wrote:\n> > $ git co master\n> > M       code/renderer/tr_font.cpp\n> > Switched to branch 'master'\n> > Your branch is ahead of 'origin/master' by 3 commits.\n> \n> ...\n> \n> > At this point, reverting the master with \"checkout --\" also wipes\n> > out the changes on the other branch. It's like the merge symlinked\n> > the two branches rather than, well, merging them.\n> \n> It does show you that there are changes in the working tree and you\n> could have switched back with \"git co -\", done whatever you want with\n> your changes then switched to master again.\n> \n> > A couple of days ago it DID complain\n> > when I tried to switch with uncommitted files still present, so it\n> > was working properly then. I have no idea what's made it happy to\n> > ignore them now: nothing's changed that I know of.\n> \n> git tries to keep all changes on working tree you have. If you have\n> changes in file A and the new branch changes in file B, fine. If the\n> new branch also changes in file A too, it'll complain because\n> otherwise it may overwrite your changes. What it actual does is \"Two\n> way merge\", there is a table in \"git read-tree\" man page that\n> describes exactly how it is done, what cases would fail...\n> \n> I see it as more choices. As I said above, it does tell you there are\n> changes and you could do something. You could make alias \"co\" that\n> check for worktree/index cleanliness before calling checkout.\n> Something like this maybe (I have not tested it)\n> \n> git config alias.co '!git update-index --refresh && git diff-files\n> --quiet && git diff-index --cached --quiet HEAD && git checkout \"$@\"'\n> \n> A config key to enforce this may be nice. I don't know, I have never\n> had problems with current behavior.\n\nI agree with the explanation and I like current behavior, as well.\n\n2arQon:\nYour expectations is based on SVN experience but as ex-SVN-user, too, I\ncan (and I want to) say: Git is more flexible and powerful tool then SVN\nis. Take is power and change your expectations, and your life will\nbecome better )))\n"},{"id":"177540","messageId":"loom.20111013T130924-792@post.gmane.org","threadId":"28664","inReplyTo":"20111013145924.2113c142@ashu.dyn.rarus.ru","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T11:51:12Z","receivedAt":"2011-10-13T11:51:12Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Snipping the bug and focusing on one of the after-effects of the bug is,\nunfortunately, not helpful to me unless I'm missing your point (which is\ncertainly possible).\n\ngit switched branches while there were uncommitted files. It's not supposed to\ndo this, ever, unless given -f or -m, and it broke the tree as a result. Even\n*with* -f or -m, the behavior I described is incorrect.\nThe git docs seem to agree with me, which is why there's git stash. If the docs\nare wrong, fine, though it seems pretty strange to have a change on BranchA\nappear by magic \"in\" BranchB without any merging.\n\nWhat I'm after is an understanding / explanation of how something that isn't\nsupposed to happen, does. I don't care if it's \"Because I'm an idiot\", \"Because\ngit is broken\", or even \"Make sure your config has 'git.makebranchesworkproperly\n= true' in it, the default is false\". If there is no explanation for why git\nswitches branches when there are still uncommitted files, and there doesn't seem\nto be, then it's a pretty catastrophic bug and fixing it would be a Good Thing.\n\n*AFAICT*, committing *a* file is what triggers it.\nIf you commit -a, which is what all the commits prior to this were, it works\nproperly. You change branches, and the files on the disk become what they should\nbe.\nIf you commit nothing, you correctly get the \"uncommitted files\" error.\nIf you do a partial commit though, your tree breaks.\n\nLike I say, if the man page, quote:\n\"If you have local modifications to one or more files that are different between\nthe current branch and the branch to which you are switching, the command\nrefuses to switch branches in order to preserve your modifications in context.\"\nis wrong, and this behavior is deliberate, that's fine. Bizarre, but fine in\nthe sense that git is doing what it's supposed to (regardless of how\ncounterintuitive and destructive it is).\nIf the man page is right though, this is a bug. Maybe it's only in msysgit,\nbut this is the second time it's happened, so hopefully it's fairly easy to\nreproduce.\n"},{"id":"177542","messageId":"4E96D819.20905@op5.se","threadId":"28664","inReplyTo":"loom.20111013T130924-792@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2011-10-13T12:22:49Z","receivedAt":"2011-10-13T12:22:49Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"On 10/13/2011 01:51 PM, arQon wrote:\n> Snipping the bug and focusing on one of the after-effects of the bug is,\n> unfortunately, not helpful to me unless I'm missing your point (which is\n> certainly possible).\n> \n> git switched branches while there were uncommitted files. It's not supposed to\n> do this, ever, unless given -f or -m, and it broke the tree as a result. Even\n> *with* -f or -m, the behavior I described is incorrect.\n> The git docs seem to agree with me, which is why there's git stash. If the docs\n> are wrong, fine, though it seems pretty strange to have a change on BranchA\n> appear by magic \"in\" BranchB without any merging.\n> \n> What I'm after is an understanding / explanation of how something that isn't\n> supposed to happen, does. I don't care if it's \"Because I'm an idiot\", \"Because\n> git is broken\", or even \"Make sure your config has 'git.makebranchesworkproperly\n> = true' in it, the default is false\". If there is no explanation for why git\n> switches branches when there are still uncommitted files, and there doesn't seem\n> to be, then it's a pretty catastrophic bug and fixing it would be a Good Thing.\n> \n> *AFAICT*, committing *a* file is what triggers it.\n> If you commit -a, which is what all the commits prior to this were, it works\n> properly. You change branches, and the files on the disk become what they should\n> be.\n> If you commit nothing, you correctly get the \"uncommitted files\" error.\n> If you do a partial commit though, your tree breaks.\n> \n> Like I say, if the man page, quote:\n> \"If you have local modifications to one or more files that are different between\n> the current branch and the branch to which you are switching, the command\n> refuses to switch branches in order to preserve your modifications in context.\"\n\n\nThis means that if fileX on branchA is different from fileX on branchB and you\n*also* have local modifications to fileX, git will refuse to switch branches.\nIf, on the other hand branchA:fileX == branchB:fileX and you have modifications\nto fileX in your work tree, there's no reason to refuse the branch change.\nPartly because nothing will be lost and partly because you can just switch\nbranches back if you decide you've switched branches before committing things\nto the first branch.\n\n> is wrong, and this behavior is deliberate, that's fine. Bizarre, but fine in\n> the sense that git is doing what it's supposed to (regardless of how\n> counterintuitive and destructive it is).\n> If the man page is right though, this is a bug. Maybe it's only in msysgit,\n> but this is the second time it's happened, so hopefully it's fairly easy to\n> reproduce.\n> \n\nIt's not a bug. You just read the manpage a bit wrong.\n\nConsider this scenario:\n$dev works on featureA on branchA, modifying fileX, fileZ and fileY and then\ndoes a commit of fileZ and fileY, but realizes that the changes in fileX\nwill be good for developing featureB as well, so he changes to a separate\nbranch to do the update to fileX and be able to merge those changes to\nboth branchA and branchB.\n\nI've done this myself on numerous occasions when re-working small project-\nlocal API's, and it's very, very handy indeed. If git would refuse me to\nchange branches without first committing everything I'd have to first\ncommit the change separately, switch branch, cherrypick the change, go\nback to the first branch and remove the commit I made there, merge the\nother branch where the commit really belonged and only then I could go\non about my business. If, on the other hand, I happen to switch branches\nbefore committing fileZ in the above example, I can just switch back and\namend my last commit on the first branch.\n\nSo yes, this is a feature, and it's a handy one.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n\nConsidering the successes of the wars on alcohol, poverty, drugs and\nterror, I think we should give some serious thought to declaring war\non peace.\n"},{"id":"177544","messageId":"loom.20111013T141239-151@post.gmane.org","threadId":"28664","inReplyTo":"loom.20111013T130924-792@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T12:42:42Z","receivedAt":"2011-10-13T12:42:42Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Simple testcase:\n\n>git init\nInitialized empty Git repository in C:/git-test/.git/\n>notepad file1\n>notepad file2\n>git st\n # On branch master\n # Initial commit\n # Untracked files:\n #   (use \"git add <file>...\" to include in what will be committed)\n #       file1.txt\n #       file2.txt\n nothing added to commit but untracked files present (use \"git add\" to track)\n\n>git add .\n>git st\n # On branch master\n # Initial commit\n # Changes to be committed:\n #       new file:   file1.txt\n #       new file:   file2.txt\n\n>git commit -am \"init\"\n  2 files changed, 2 insertions(+), 0 deletions(-)\n  create mode 100644 file1.txt\n  create mode 100644 file2.txt\n\n>git co -b foo\n Switched to a new branch 'foo'\n>notepad file1\n(edit stuff)\n>git st\n # On branch foo\n # Changes not staged for commit:\n #       modified:   file1.txt\n\n>git co master\n M       file1.txt\n\nfile1 now has the wrong data in it for \"master\" branch.\n\nIf I go back to \"foo\" branch and commit the file before doing anything else,\nit recovers, and changing branches works correctly again.\n\n--\n\n\"If you have local modifications to one or more files that are different\nbetween the current branch and the branch to which you are switching, the\ncommand refuses to switch branches in order to preserve your modifications\nin context.\"\n\nMaybe I'm just missing something obvious, but at the time that last \"git\nco master\" was issued:\n\nThe file is locally modified.\nThe file is different on the current branch (foo) than on the branch to which\nI am switching (master).\nThe command fails to refuse to switch branches.\n\nSo I guess the problem is that since the file wasn't re-added after the edit,\ngit is ignoring it when trying to see if it's safe to branch or not?\n"},{"id":"177549","messageId":"4E96DFDE.4060707@ira.uka.de","threadId":"28664","inReplyTo":"loom.20111013T141239-151@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Holger Hellmuth","fromEmail":"hellmuth@ira.uka.de","sentAt":"2011-10-13T12:55:58Z","receivedAt":"2011-10-13T12:55:58Z","isPatch":false,"sender":{"key":"hellmuth@ira.uka.de","avatar":null},"body":"On 13.10.2011 14:42, arQon wrote:\n>> git co -b foo\n>   Switched to a new branch 'foo'\n>> notepad file1\n> (edit stuff)\n>> git st\n>   # On branch foo\n>   # Changes not staged for commit:\n>   #       modified:   file1.txt\n>\n>> git co master\n>   M       file1.txt\n>\n> Maybe I'm just missing something obvious, but at the time that last \"git\n> co master\" was issued:\n>\n> The file is locally modified.\n> The file is different on the current branch (foo) than on the branch to which\n> I am switching (master).\n\nWrong. On branch foo as well as on master the same old file1.txt is \ncommitted. You never staged nor committed the new file1.txt anywhere.\n\n> The command fails to refuse to switch branches.\n"},{"id":"177548","messageId":"loom.20111013T144822-277@post.gmane.org","threadId":"28664","inReplyTo":"4E96D819.20905@op5.se","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T13:09:00Z","receivedAt":"2011-10-13T13:09:00Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Andreas Ericsson <ae <at> op5.se> writes:\n[snip]\n> This means that if fileX on branchA is different from fileX on branchB and you\n> *also* have local modifications to fileX, git will refuse to switch branches.\n> If, on the other hand branchA:fileX == branchB:fileX and you have modifications\n> to fileX in your work tree, there's no reason to refuse the branch change.\n\nThere's an EXCELLENT reason to refuse the branch change: once it happens, what\ngit is then telling is branchA, is not.\n\n> It's not a bug. You just read the manpage a bit wrong.\n[snip]\n> So yes, this is a feature, and it's a handy one.\n\nThanks for the explanation. Unfortunately, I still can't see it as anything but\na critical bug. Consider this:\n\nYou're working on branchA and you have a bunch of uncommitted changes.\nYou can't remember some detail of the bug you're fixing, so you switch branches\nto the master. You have to rebuild that branch, because your last build was from\nyour branch. git now builds the master with sources that were NEVER committed\nto it. How is that not a total failure to maintain branch integrity?\n\nIf that's the way git is, then that's how it is; and if there isn't a setting\nthat can make it actually preserve branches properly, then there isn't. Which\nsucks for me, because an SCCS that lies about what branch you're \"really\" on\nis worse than useless, so I'm stuck with SVN.  :(\n\nThanks again for clearing it up for me though.\n"},{"id":"177556","messageId":"loom.20111013T152144-60@post.gmane.org","threadId":"28664","inReplyTo":"4E96D819.20905@op5.se","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T13:58:06Z","receivedAt":"2011-10-13T13:58:06Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Andreas Ericsson <ae <at> op5.se> writes:\n> there's no reason to refuse the branch change.\n> Partly because nothing will be lost\n\nActually, this isn't true either, because of the second bug: doing a revert\nin branchA causes the changes in branchB to be lost. This can't possibly be\nthe intended behavior: again, it completely violates the integrity of branches\nby allowing changes on one branch to impact a different branch.\n\nYour interpretation of the manpage doubtless matches the actual behavior of git,\nbut I find it staggering if that truly is what was intended. It basically means\nthat if you have local modifications, git will Break Your Entire Tree. That\nmakes changing while you *do* have local mods more than a little undesirable,\nto put it mildly, which is something that a literal reading of the manpage would\nsuggest is exactly what the \"refuse to switch\" is for. I guess only Linus knows\nwhat he actually meant.  :)\n\nAnyway, I guess it's all moot: call it a feature or call it a bug, this cross-\nbranch destruction is a deal-breaker for me, especially given the bug above that\nactually loses data outright, rather than \"only\" putting multiple branches into\nan incorrect state.\n\nThanks for your time and help.\n"},{"id":"177557","messageId":"1318514356.4646.16.camel@centaur.lab.cmartin.tk","threadId":"28664","inReplyTo":"loom.20111013T144822-277@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Carlos Martín Nieto","fromEmail":"cmn@elego.de","sentAt":"2011-10-13T13:59:16Z","receivedAt":"2011-10-13T13:59:16Z","isPatch":false,"sender":{"key":"cmn@elego.de","avatar":"https://avatars.githubusercontent.com/u/335443?v=4"},"body":"On Thu, 2011-10-13 at 13:09 +0000, arQon wrote:\n> Andreas Ericsson <ae <at> op5.se> writes:\n> [snip]\n> > This means that if fileX on branchA is different from fileX on branchB and you\n> > *also* have local modifications to fileX, git will refuse to switch branches.\n> > If, on the other hand branchA:fileX == branchB:fileX and you have modifications\n> > to fileX in your work tree, there's no reason to refuse the branch change.\n> \n> There's an EXCELLENT reason to refuse the branch change: once it happens, what\n> git is then telling is branchA, is not.\n\nWhen you changed branches, git told you that a file had been changed in\nthe working tree. When you run 'git diff', it tells you the differences\nbetween what you have in your working tree and what's in the branch[0].\nGit is trying hard not to loose your modifications (maybe it was a\none-liner, maybe it was three hours of work) to the file.\n\n> \n> > It's not a bug. You just read the manpage a bit wrong.\n> [snip]\n> > So yes, this is a feature, and it's a handy one.\n> \n> Thanks for the explanation. Unfortunately, I still can't see it as anything but\n> a critical bug. Consider this:\n> \n> You're working on branchA and you have a bunch of uncommitted changes.\n> You can't remember some detail of the bug you're fixing, so you switch branches\n> to the master. You have to rebuild that branch, because your last build was from\n> your branch. git now builds the master with sources that were NEVER committed\n> to it. How is that not a total failure to maintain branch integrity?\n\nIt sound like you've misunderstood what a branch is for git. A branch is\nonly ever changed when you commit. What checkout does is change what the\ncurrent branch is. For a case like what you describe, the developer\nwould either do a temporary commit that they'd change later or stash the\nchanges[1]. You could also use git-new-workdir (from contrib/) so you\nhave two different directories that share the object storage. That has a\nfew rough edges, but if you restrict it to a broken branch, you\nshouldn't have any problems.\n\n> \n> If that's the way git is, then that's how it is; and if there isn't a setting\n> that can make it actually preserve branches properly, then there isn't. Which\n> sucks for me, because an SCCS that lies about what branch you're \"really\" on\n> is worse than useless, so I'm stuck with SVN.  :(\n\nDon't think of it as being \"in\" a branch. A checkout in git changes the\nactive branch. If there are any files that are different between the two\nbranches, they are changed. By switching branches with uncommitted\nchanges, you're telling git that you would rather use the other branch\nto do your changes in. But git isn't doing this silently. After the\ncheckout, it lists the files that have local modifications, so the\ndeveloper can switch branches again and commit or stash the changes.\n\n   cmn\n\n[0] Really it's between the working tree and the index, but since you\njust switched branches, the index is the same, and using it in that\nsentence would just cause confusion.\n\n[1] 'git stash' is a command that saves your uncommitted changes on a\nstack so you can recover them later.\n\n"},{"id":"177558","messageId":"20111013144450.GA2856@victor.terreactive.ch","threadId":"28664","inReplyTo":"loom.20111013T141239-151@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Victor Engmark","fromEmail":"victor.engmark@terreactive.ch","sentAt":"2011-10-13T14:44:50Z","receivedAt":"2011-10-13T14:44:50Z","isPatch":false,"sender":{"key":"victor.engmark@terreactive.ch","avatar":null},"body":"On Thu, Oct 13, 2011 at 12:42:42PM +0000, arQon wrote:\n> Simple testcase:\n> \n> >git init\n> Initialized empty Git repository in C:/git-test/.git/\n> >notepad file1\n> >notepad file2\n> >git st\n>  # On branch master\n>  # Initial commit\n>  # Untracked files:\n>  #   (use \"git add <file>...\" to include in what will be committed)\n>  #       file1.txt\n>  #       file2.txt\n>  nothing added to commit but untracked files present (use \"git add\" to track)\n> \n> >git add .\n> >git st\n>  # On branch master\n>  # Initial commit\n>  # Changes to be committed:\n>  #       new file:   file1.txt\n>  #       new file:   file2.txt\n> \n> >git commit -am \"init\"\n>   2 files changed, 2 insertions(+), 0 deletions(-)\n>   create mode 100644 file1.txt\n>   create mode 100644 file2.txt\n> \n> >git co -b foo\n>  Switched to a new branch 'foo'\n> >notepad file1\n> (edit stuff)\n> >git st\n>  # On branch foo\n>  # Changes not staged for commit:\n>  #       modified:   file1.txt\n> \n> >git co master\n>  M       file1.txt\n> \n> file1 now has the wrong data in it for \"master\" branch.\n\nThe most important thing a VCS should do is to keep history intact.\nThat happens when you check out in Git: No branches were changed, only\nthe working space. The second most important thing a VCS should do is\nnot destroy any of your uncommitted work unless you tell it to. That\nalso happens when you check out in Git. The third most important thing a\nVCS should do is facilitate the developer's workflow. One common thing\nto do is to work on some thing, for example refactoring. During this\nprocess you might realize that one of the changes actually fixed a bug\nin the software. To keep things in their right place, you could now\neither\n1. `checkout master` and commit the fix there, then shift back and\ncontinue working, or\n2. commit the refactorings, `checkout master`, and commit the fix there.\nEither of these are easy to do with Git. There really is no reason why\nthe changes in the workspace should be considered as \"part of\" the\ncurrently active branch, because they *are* not.\n\nCheers,\nV\n\n-- \nterreActive AG\nKasinostrasse 30\nCH-5001 Aarau\nTel: +41 62 834 00 55\nFax: +41 62 823 93 56\nwww.terreactive.ch\n\nWir sichern Ihren Erfolg - seit 15 Jahren\n"},{"id":"177559","messageId":"1318517194.4646.30.camel@centaur.lab.cmartin.tk","threadId":"28664","inReplyTo":"loom.20111013T152144-60@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Carlos Martín Nieto","fromEmail":"cmn@elego.de","sentAt":"2011-10-13T14:46:34Z","receivedAt":"2011-10-13T14:46:34Z","isPatch":false,"sender":{"key":"cmn@elego.de","avatar":"https://avatars.githubusercontent.com/u/335443?v=4"},"body":"On Thu, 2011-10-13 at 13:58 +0000, arQon wrote:\n> Andreas Ericsson <ae <at> op5.se> writes:\n> > there's no reason to refuse the branch change.\n> > Partly because nothing will be lost\n> \n> Actually, this isn't true either, because of the second bug: doing a revert\n> in branchA causes the changes in branchB to be lost. This can't possibly be\n> the intended behavior: again, it completely violates the integrity of branches\n> by allowing changes on one branch to impact a different branch.\n\nI have not seen a revert command in any of your messages. If a revert on\none branch changes another one, that would be a bug, but you haven't\nshown this to happen.\n\n> \n> Your interpretation of the manpage doubtless matches the actual behavior of git,\n> but I find it staggering if that truly is what was intended. It basically means\n> that if you have local modifications, git will Break Your Entire Tree. That\n> makes changing while you *do* have local mods more than a little undesirable,\n> to put it mildly, which is something that a literal reading of the manpage would\n> suggest is exactly what the \"refuse to switch\" is for. I guess only Linus knows\n> what he actually meant.  :)\n\nDo not confuse a branch with a worktree. If you haven't committed yet,\nthose changes aren't in the branch (just like they wouldn't be in svn)\n\n> \n> Anyway, I guess it's all moot: call it a feature or call it a bug, this cross-\n> branch destruction is a deal-breaker for me, especially given the bug above that\n> actually loses data outright, rather than \"only\" putting multiple branches into\n> an incorrect state.\n\nI've just asked some subversion developers to confirm this, and then\ntried it out myself: Subversion (my locally-installed version is 1.6.17,\nlatest stable) behaves the same way. Local modifications are carried\nover across branches.\n\n$ svn copy ^/trunk ^/branches/somebranch # Create a new branch\n$ $EDITOR somefile # which exists in trunk and somebranch\n$ svn switch ^/branches/somebranch\n$ svn diff # My local changes are there!\n\nThe reason this happens both in svn and git is that the most likely\ncause for someone to change a branch mid-edit is that they decide\nthey're doing the changes on the wrong branch. What I did notice is that\nsvn doesn't tell you about the modifications being carried over\n(presumably you're meant to use status and diff to figure out what's\ngoing on). Therefore, the same workflow (with the only difference being\nhow to create and switch branches) works for svn and git in this case.\n\n   cmn\n\n\n"},{"id":"177560","messageId":"4E96FF3D.90600@drmicha.warpmail.net","threadId":"28664","inReplyTo":"loom.20111013T094053-111@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-10-13T15:09:49Z","receivedAt":"2011-10-13T15:09:49Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"arQon venit, vidit, dixit 13.10.2011 10:40:\n> Which, as you'd expect, results in both the on-disk copies and other branches\n> becoming corrupted.\n> \n> Tested on git versions 1.7.6 and 1.7.7 (msysgit)\n> \n> http://benno.id.au/blog/2011/10/01/git-recursive-merge-broken describes\n> something that sounds similar, but that's supposedly fixed on 1.7.7,\n> whereas this happens on that as well.\n> \n> master is a tracking branch, \"ttfcon\" is the branch I was using to develop\n> a change. Got to a good point on the branch, merged it in:\n> \n> $ git co master\n> $ git merge ttfcon\n> Updating b9f0c75..6280b7a\n> Fast-forward\n>  .gitignore                |    2 ++\n>  code/renderer/tr_font.cpp |   27 ++++++++-------------------\n>  2 files changed, 10 insertions(+), 19 deletions(-)\n> \n> $ git st\n> # On branch master\n> # Your branch is ahead of 'origin/master' by 3 commits.\n> \n> back to the branch to mess around with a couple of things to be sure this\n> is what i want to push\n> $ git co ttfcon\n> do stuff\n> \n> $ git st\n> # On branch ttfcon\n> # Changes not staged for commit:\n> #   (use \"git add <file>...\" to update what will be committed)\n> #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n> #\n> #       modified:   code/freetype-2.3.11/builds/win32/visualc/freetype.vcproj\n> #       modified:   code/renderer/tr_font.cpp\n> \n> so far so good...\n> \n> $ git ci -m \"blah\" code/freetype-2.3.11/builds/win32/visualc/freetype.vcproj\n>  1 files changed, 4 insertions(+), 0 deletions(-)\n> \n> note that tr_font is locally modified and still *not committed* at this point.\n\nand neither staged for commit, exactly.\n\n> $ git co master\n> M       code/renderer/tr_font.cpp\n> Switched to branch 'master'\n> Your branch is ahead of 'origin/master' by 3 commits.\n> \n> boom. instead of rejecting the branch change, git switches branches anyway,\n> and doesn't do anything about the uncommitted changes in the file itself -\n\nExactly. git leaves them as they are, without changing what you have in\nyour work tree.\n\n(This is possible because the switch ttfcon to master involves no\nchanges which conflict with the chnage that you have in your work tree).\n\n> meaning they're now effectively \"in\" master because they're still on disk,\n> so now the master is poisoned.\n\nNot at all. They are on \"disk\" (work tree). Full stop. Not staged, not\ncommitted, not at all \"in master\".\n\n> \n> \"git st\" does show the change:\n> \n> # On branch master\n> # Changes not staged for commit:\n> #       modified:   code/renderer/tr_font.cpp\n> \n> but it's a change I never MADE on this branch (ie master), only on the\n> other branch.\n\nYou never made it on the other branch either. You made it in the work\ntree. And \"git status\" clearly says so: modified, not staged.\n\n> \"git diff\" is just as confused as I am:\n> \n> $ git diff ttfcon\n> --- a/code/renderer/tr_font.cpp\n> +++ b/code/renderer/tr_font.cpp\n> +\t\t// git branch bug\n\n\"git diff\" shows you the change you have in your work tree, i.e. the\ndifference between index (which coincides with master since nothing is\nstaged) and work tree. The fact that there is a difference is equivalent\nto saying \"there are unstaged changes\".\n\n> So it's picking up the difference between the two branches, but as far as\n\nNo. The difference between the branches is the change to freetype.vcproj\nbecause you committed that to ttfcon, not master.\n\n> the *actual file* goes, master now has a line in it that shouldn't be there.\n\nIt's in the work tree, not master....\n\n> I'm just trying out git as a possible replacement for SVN, so maybe I'm\n> mistaken about what \"should\" happen, but AIUI git switching branches with\n> uncommitted changes is a bug (and given that it poisoned a branch that I\n> wasn't on, it certainly looks like one). A couple of days ago it DID complain\n> when I tried to switch with uncommitted files still present, so it was working\n> properly then. I have no idea what's made it happy to ignore them now:\n> nothing's changed that I know of.\n\nWhen switching branches, git tries to preserves the changes that you\nhave in your work tree. If it is possible (because there is no overlap,\nas written above), it hapilly does just that. If not it barks.\n\nI think you have to wrap your head around the Git model after unwinding\nit from the svn model, which is normal ;)\n\nCheers,\nMichael\n"},{"id":"177561","messageId":"loom.20111013T171530-970@post.gmane.org","threadId":"28664","inReplyTo":"1318517194.4646.30.camel@centaur.lab.cmartin.tk","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T15:53:07Z","receivedAt":"2011-10-13T15:53:07Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Carlos Martín Nieto <cmn <at> elego.de> writes:\n> I have not seen a revert command in any of your messages. If a revert on\n> one branch changes another one, that would be a bug, but you haven't\n> shown this to happen.\n\nSorry, it was in prose in the original post (near the end)\n\"At this point, reverting the master with \"checkout --\" also wipes out the\nchanges on the other branch. It's like the merge symlinked the two branches\nrather than, well, merging them.\"\n\nBased on the explanations here, and the git *st* message, it wiping out the\nother branch is to be expected, because it's \"the working directory\", not\n\"the branch\".\n\n>git st\n# On branch foo\n# Changes not staged for commit:\n#   (use \"git add <file>...\" to update what will be committed)\n#   (use \"git checkout -- <file>...\" to discard changes in working directory)\n#\n#       modified:   file1.txt\n#\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n\nWhat makes this really interesting though is this: I tried to switch to\nmaster to see if that gave the same warning, and NOW, I get the correct\nerror.\n\n>git co master\nerror: Your local changes to the following files would be overwritten by\ncheckout:\n        file1.txt\nPlease, commit your changes or stash them before you can switch branches.\nAborting\n\nI'm sure if I thought about it enough (ie re-read Andreas's post a couple\nmore times) I'd be able to understand why git gets it right sometimes but\nnot other times, but I'm too tired right now. Even when I *am* awake and\ngrok it properly, I'm still going to be annoyed that it's so inconsistent,\nbut I can live with that if I have to.\n\n> The reason this happens both in svn and git is that the most likely\n> cause for someone to change a branch mid-edit is that they decide\n> they're doing the changes on the wrong branch.\n\nLucky you. :P  The most likely reason for me is, I'm working on something\nand I get interrupted and have to switch. Since the code may well not even\ncompile at this point, the last thing I want to do is commit it. git's\nability for that commit to be local is half the reason I'm trying to switch\nto it. (I'm not particularly keen on having to commit broken code to even a\nlocal repo, but that's still a hell of a lot better than having it pushed\nupstream as well).\n\n> svn doesn't tell you about the modifications being carried over\n> (presumably you're meant to use status and diff to figure out what's\n> going on). Therefore, the same workflow (with the only difference being\n> how to create and switch branches) works for svn and git in this case.\n\nI expect part of my confusion comes from using different workdirs for svn\nbranches, ie \"clone\" rather than \"branch\", because branching in svn is such\na PITA I just don't bother with it unless the branch is going to be\n\"heavyweight\" enough to warrant a \"proper\" branch.\nGood to be reminded of though, thanks.\n"},{"id":"177563","messageId":"4E970CEC.3000509@ira.uka.de","threadId":"28664","inReplyTo":"loom.20111013T152144-60@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Holger Hellmuth","fromEmail":"hellmuth@ira.uka.de","sentAt":"2011-10-13T16:08:12Z","receivedAt":"2011-10-13T16:08:12Z","isPatch":false,"sender":{"key":"hellmuth@ira.uka.de","avatar":null},"body":"On 13.10.2011 15:58, arQon wrote:\n> Andreas Ericsson<ae<at>  op5.se>  writes:\n>> there's no reason to refuse the branch change.\n>> Partly because nothing will be lost\n>\n> Actually, this isn't true either, because of the second bug: doing a revert\n> in branchA causes the changes in branchB to be lost. This can't possibly be\n> the intended behavior: again, it completely violates the integrity of branches\n> by allowing changes on one branch to impact a different branch.\n\nI assume you mean revert through 'git checkout' and not through 'git \nrevert'. Git uses a different philosphy. It works best with small \ncommits and commits done often. It assumes that when you switch \nbranches, you don't switch your brain as well and still know for what \npurpose you changed tr_font.cpp (and even if you forget you always can \ncheck with git diff).\nIt also reminds you that tr_font.cpp is changed when you switch branches \n(remember the \"M tr_font.cpp\" printed when you switched to another branch).\nIt assumes that when you use 'git checkout --' to wipe out changed files \nwithout committing them anywhere(!) that you have thought about it the \nsame way you have thought about before deleting or overwriting any file \nin the file system. The same way you have thought about before deleting \nor overwriting an uncommitted file in svn.\n\nWhat you term integrity of the branch is a model you made of the \nworkings of svn that you now try to pin onto a different model.\n"},{"id":"177564","messageId":"20111013201711.3d55c693@ashu.dyn.rarus.ru","threadId":"28664","inReplyTo":"loom.20111013T171530-970@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Alexey Shumkin","fromEmail":"alex.crezoff@gmail.com","sentAt":"2011-10-13T16:17:11Z","receivedAt":"2011-10-13T16:17:11Z","isPatch":false,"sender":{"key":"alex.crezoff@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1183752?v=4"},"body":"> Lucky you. :P  The most likely reason for me is, I'm working on\n> something and I get interrupted and have to switch. Since the code\n> may well not even compile at this point, the last thing I want to do\n> is commit it. \n\"git stash\" helps here\nWith Git you can/have_to/must change your SVN-based habits.\nDO NOT BE AFRAID OF FREQUENT COMMITS!\nThere are local until you push them.\n\n>git's ability for that commit to be local is half the\n> reason I'm trying to switch to it.\nYou always have a chance to modify/reedit you commits\nsee \"git commit --amend\" and \"git rebase [-i]\"\n\nI'm telling you it as an ex-SVN user.\n>(I'm not particularly keen on\n> having to commit broken code to even a local repo, but that's still a\n> hell of a lot better than having it pushed upstream as well).\n\nAgain, do not be afraid to commit your changes. Be afraid of losing\nyour changes. Git makes everything (as other discussion participants\nalready described) to keep your changes within workflow when you\nswitch between branches often.\n\nRead some books which are describe Git's usual (and effective) workflow,\nProGit - http://progit.org/book/\nVersion Contol by Example (there is a chapter about Git) -\nhttp://git-scm.com/course/svn.html\n\nHope, you'll feel the power of Git ))\n"},{"id":"177565","messageId":"loom.20111013T175500-495@post.gmane.org","threadId":"28664","inReplyTo":"20111013144450.GA2856@victor.terreactive.ch","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T16:17:51Z","receivedAt":"2011-10-13T16:17:51Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Victor Engmark <victor.engmark <at> terreactive.ch> writes:\n> 1. `checkout master` and commit the fix there, then shift back and\n> continue working\n\nI absolutely agree. And it's far more common than any of us would like.\nMy point is, you *can't* do this in git without first staging your current branch\nvia either commit or stash, or you risk changes bleeding between the branches\nand/or work being lost irretrievably. This is not something that you would\nexpect, and as you say:\n\n> The second most important thing a VCS should do is not destroy any of your\nuncommitted work unless you tell it to\n\n... which is exactly what git does, and why I have a problem with it.\nBut the response here is uniformly \"that's just how git is\", so obviously it's\nsomething you learn to become aware of over time, and avoid. It's not going to\nget \"fixed\", because people who are used to git don't see it as a bug, so I just\nhave to decide whether I can live with it or not.\n"},{"id":"177566","messageId":"4E97129C.3090609@ira.uka.de","threadId":"28664","inReplyTo":"loom.20111013T171530-970@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Holger Hellmuth","fromEmail":"hellmuth@ira.uka.de","sentAt":"2011-10-13T16:32:28Z","receivedAt":"2011-10-13T16:32:28Z","isPatch":false,"sender":{"key":"hellmuth@ira.uka.de","avatar":null},"body":"On 13.10.2011 17:53, arQon wrote:\n>> git st\n> # On branch foo\n> # Changes not staged for commit:\n> #   (use \"git add<file>...\" to update what will be committed)\n> #   (use \"git checkout --<file>...\" to discard changes in working directory)\n> #\n> #       modified:   file1.txt\n> #\n> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n>\n> What makes this really interesting though is this: I tried to switch to\n> master to see if that gave the same warning, and NOW, I get the correct\n> error.\n>\n>> git co master\n> error: Your local changes to the following files would be overwritten by\n> checkout:\n>          file1.txt\n> Please, commit your changes or stash them before you can switch branches.\n> Aborting\n\nAt the end of your example (in a previous email) you were on branch \nmaster, now in the beginning you are on foo. So you at least changed \nbranch again inbetween. maybe you also committed something? Check out \ngit log or gitk\n\nI tried your example and I can checkout master and foo again and again \nand I never see the error message.\n\n> Lucky you. :P  The most likely reason for me is, I'm working on something\n> and I get interrupted and have to switch. Since the code may well not even\n> compile at this point, the last thing I want to do is commit it. git's\n> ability for that commit to be local is half the reason I'm trying to switch\n> to it. (I'm not particularly keen on having to commit broken code to even a\n> local repo, but that's still a hell of a lot better than having it pushed\n> upstream as well).\n\nAs Alexey already said, just commit and later amend. Or stash. Git \nencourages you to commit small changes you can put a name to. You never \nshould delay a commit because it produces unworkable code. Instead have \na master branch (or branches) that always compiles and branches for the \nunfinished stuff. Then it won't matter if some branch is only half working.\n"},{"id":"177567","messageId":"1318525486.4646.53.camel@centaur.lab.cmartin.tk","threadId":"28664","inReplyTo":"loom.20111013T171530-970@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Carlos Martín Nieto","fromEmail":"cmn@elego.de","sentAt":"2011-10-13T17:04:46Z","receivedAt":"2011-10-13T17:04:46Z","isPatch":false,"sender":{"key":"cmn@elego.de","avatar":"https://avatars.githubusercontent.com/u/335443?v=4"},"body":"On Thu, 2011-10-13 at 15:53 +0000, arQon wrote:\n> Carlos Martín Nieto <cmn <at> elego.de> writes:\n> > I have not seen a revert command in any of your messages. If a revert on\n> > one branch changes another one, that would be a bug, but you haven't\n> > shown this to happen.\n> \n> Sorry, it was in prose in the original post (near the end)\n> \"At this point, reverting the master with \"checkout --\" also wipes out the\n> changes on the other branch. It's like the merge symlinked the two branches\n> rather than, well, merging them.\"\n> \n> Based on the explanations here, and the git *st* message, it wiping out the\n> other branch is to be expected, because it's \"the working directory\", not\n> \"the branch\".\n> \n> >git st\n> # On branch foo\n> # Changes not staged for commit:\n> #   (use \"git add <file>...\" to update what will be committed)\n> #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n> #\n> #       modified:   file1.txt\n> #\n> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n> \n> What makes this really interesting though is this: I tried to switch to\n> master to see if that gave the same warning, and NOW, I get the correct\n> error.\n> \n> >git co master\n> error: Your local changes to the following files would be overwritten by\n> checkout:\n>         file1.txt\n> Please, commit your changes or stash them before you can switch branches.\n> Aborting\n> \n> I'm sure if I thought about it enough (ie re-read Andreas's post a couple\n> more times) I'd be able to understand why git gets it right sometimes but\n> not other times, but I'm too tired right now. Even when I *am* awake and\n> grok it properly, I'm still going to be annoyed that it's so inconsistent,\n> but I can live with that if I have to.\n\nIf file1.txt in the foo branch is different from the one in the master\nbranch, git will refuse to switch branches. 'git diff foo master' should\nshow that those two files are different.\n\n> \n> > The reason this happens both in svn and git is that the most likely\n> > cause for someone to change a branch mid-edit is that they decide\n> > they're doing the changes on the wrong branch.\n> \n> Lucky you. :P  The most likely reason for me is, I'm working on something\n> and I get interrupted and have to switch. Since the code may well not even\n> compile at this point, the last thing I want to do is commit it. git's\n> ability for that commit to be local is half the reason I'm trying to switch\n> to it. (I'm not particularly keen on having to commit broken code to even a\n> local repo, but that's still a hell of a lot better than having it pushed\n> upstream as well).\n\nYes, this is a great feature of distributed systems. A local repo is\nwhere you experiment. Treat it as your own personal space to play around\nwith things. Committing non-working code is fine, as long as you don't\npush it out.\n\n> \n> > svn doesn't tell you about the modifications being carried over\n> > (presumably you're meant to use status and diff to figure out what's\n> > going on). Therefore, the same workflow (with the only difference being\n> > how to create and switch branches) works for svn and git in this case.\n> \n> I expect part of my confusion comes from using different workdirs for svn\n> branches, ie \"clone\" rather than \"branch\", because branching in svn is such\n> a PITA I just don't bother with it unless the branch is going to be\n> \"heavyweight\" enough to warrant a \"proper\" branch.\n\nThen the issue is that you've changed the workflow but haven't adjusted\nfor it. You can do this as well with the git-new-workdir. As I mentioned\nit has a few rough edges, but if you're going to use it to have a\ncheckout of a particular branch, it shouldn't present any problems. That\nwould be like your current workflow.\n\nAnother option is to clone with a reference which will create a brand\nnew clone but will use the objects that you've already downloaded (or\njust clone locally). This can be more comfortable than using the\nnew-workdir and will hardly put any strain on the filesystem.\n\nThe bigger problem seems to be your reluctance to accept that git is\ndifferent from subversion, as you keep saying \"that's just how git is\"\nto back your claim that you can't trust git on a feature where\nsubversion behaves the same way. If you'd rather use different\ndirectories for different branches, you can. That is not an aspect which\nyou can point to and say that you can't migrate to git for that reason.\nIf you're more comfortable with subversion, that's fine also, it's an\nexcellent piece of software[0], but don't go around saying that git\ncorrupts branches when that's blatantly not true.\n\n   cmn\n\n[0] Whatever one may think about the merits of CVCS vs DVCS; that\nshouldn't come into the quality of the software.\n\n"},{"id":"177569","messageId":"871uug7rel.fsf@osv.gnss.ru","threadId":"28664","inReplyTo":"loom.20111013T171530-970@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Sergei Organov","fromEmail":"osv@javad.com","sentAt":"2011-10-13T17:06:10Z","receivedAt":"2011-10-13T17:06:10Z","isPatch":false,"sender":{"key":"osv@javad.com","avatar":null},"body":"arQon <arqon@gmx.com> writes:\n\n[...]\n\n> Lucky you. :P  The most likely reason for me is, I'm working on something\n> and I get interrupted and have to switch. Since the code may well not even\n> compile at this point, the last thing I want to do is commit it.\n\n'git stash' is exactly what you need then.\n\n-- Sergei.\n"},{"id":"177568","messageId":"loom.20111013T181801-923@post.gmane.org","threadId":"28664","inReplyTo":"1318514356.4646.16.camel@centaur.lab.cmartin.tk","subject":"Re: [CLOSED] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T17:09:11Z","receivedAt":"2011-10-13T17:09:11Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Carlos Martín Nieto <cmn <at> elego.de> writes:\n> When you changed branches, git told you that a file had been changed in\n> the working tree.\n\nThat's a very good point, if it was actually documented at all that that's\nwhat it meant; and / or presented some warning that \"BTW, if you edit this\nfile again now, it'll screw up your whole tree\" instead of an innocuous \"M\";\nand didn't appear to contradict what the manpage says about \"local\nmodifications\", we could probably have avoided half of this confusion.  :P\nAs it was, when I saw that M suddenly appear after several days of bouncing\nbetween branches without it and with everything working, I just thought\n\"oh great, git's managed to break this tree\", because I remembered the same\nthing from the previous trial run.\n\nThat there IS an indication though might just be enough for me to be able to\ndeal with it. Realistically, switching branches with uncommitted changes\n(unless you're doing it because you've ALREADY screwed up and are changing\nthe wrong branch) is basically a trainwreck waiting to happen.\n\ngit stash appears to be useless for any nontrivial change on the *other*\nbranch, since there's no indication when you return to the stashed branch\nthere's a stash sitting around, which is not something you're going to\nremember the next morning if fixing the master took the rest of the day,\nand you're not going to use \"stash list\" by then either.\n\nBut as long as you get the \"warning\", an alias that does a \"commit -am 'temp\ncommit to avoid git breaking the tree'\" is something I think I can probably\nlive with.\n\nThanks for all the help guys - very much appreciated.\nAs far as I'm concerned, this topic's done.\n\n(Though if someone can come up with a script / hook / whatever that improves\nthe \"visibility\" of stash, that would be awesome. Or one that makes the\nrefusal to switch branches consistent).\n\nLooking at the manpage for checkout in the hope that there might be a \"--safe\"\nswitch, I don't understand why\n  \"-f  Proceed even if the index *or the working tree* differs from HEAD.\"\neven exists, since it proceeds under those conditions anyway.\n\"--safe\" appears to be exactly what the behavior should be if you DON'T\nspecify -f, except that -f nukes the working tree outright rather than just\nbleeding it across. Hopefully it'll be clearer after some sleep.  :)\n"},{"id":"177574","messageId":"loom.20111013T193054-868@post.gmane.org","threadId":"28664","inReplyTo":"1318525486.4646.53.camel@centaur.lab.cmartin.tk","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T18:19:26Z","receivedAt":"2011-10-13T18:19:26Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Carlos Martín Nieto <cmn <at> elego.de> writes:\n> If file1.txt in the foo branch is different from the one in the master\n> branch, git will refuse to switch branches. 'git diff foo master' should\n> show that those two files are different.\n\nRight, but only for a definition of \"branch\" that is actually \"a fully\ncommitted branch\", hence the confusion and the mention of \"uncommitted\nchanges\" in the topic.\n\nAn expectation that \"co branch\" should be analogous to \"cd ../branch/\" is by\nno means unreasonable. YOU may know better, but it's surprisingly non-obvious,\nespecially considering the -f option on checkout and the wording of -m, both\nof which strongly suggest that, in the absence of either of those flags, git\nWILL preserve the worktree by refusing to switch until that potentially-\nharmful situation is resolved by the user.\n\n> Committing non-working code is fine, as long as you don't push it out.\n\nRight, but for the problem I was describing it's actually \"committing\nnon-working code is a requirement, in this situation, if you don't want your\ntree to get eaten\". Going from \"you absolutely must not do this\" to \"you must\ndo this\" takes some mental adjustment, but you also have to be *aware* that\nyou now have to do something that was previously prohibited, which I wasn't.\n\n> The bigger problem seems to be your reluctance to accept that git is\n> different from subversion\n\nNot at all. If I didn't WANT something different, I wouldn't have been trying\nto move to git in the first place.  :)\n\n> but don't go around saying that git\n> corrupts branches when that's blatantly not true.\n\nSee my first para in this post (or indeed, the original post). It's \"not true\"\nprovided all branches are fully committed when you switch between them.\nIt blatantly IS true if you switch from a dirty branch.\nRedefining \"branch\" to mean \"fully committed branch\" makes it \"not true\" in\nthat context, but so does redefining green to be red and saying that grass is\nred in that context: it may be correct from a certain POV, but it's\nincomprehensible to anyone who isn't aware of that semantic change.\n\nAnyway, I think we're done with this thread. Thanks for your (key) observation\nearlier and several clarifications, and hopefully this will help the next guy\nwho runs into this problem and gets confused like I did.  :)\n"},{"id":"177576","messageId":"7vzkh44ug1.fsf@alter.siamese.dyndns.org","threadId":"28664","inReplyTo":"loom.20111013T193054-868@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-13T18:28:46Z","receivedAt":"2011-10-13T18:28:46Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"arQon <arqon@gmx.com> writes:\n\n> ..., in the absence of either of those flags, git\n> WILL preserve the worktree by refusing to switch until that potentially-\n> harmful situation is resolved by the user.\n\nPerhaps you can prepare a documentation patch to make it clear that git\nWILL preserve the LOCAL CHANGES to the working tree?\n\nAs it would already be clear to anybody reading this thread so far, local\nchanges made to the working tree do not belong to any particular branch.\nThey are floating on top, and it is up to the user what to do with these\nfloating changes when they conflict with the differences between the\nbranches you are switching across (i.e. you cannot switch so you need to\nclean up by either committing, stashing, or deciding not to switch and\ninstead complete the work before you switch), and when they do not\nconflict with the differences between the branches you are switching\nacross (i.e. you will carry them to the new working tree. It may be that\nyou made these changes and then realized that they do not belong to the\ngoal the current branch aims to achieve and that is why you decided to\nswitch to another branch, in which case you do not have to do anything\nspecial in order to continue to work and complete it to commit to the\nswitched branch. It may be that you made these changes but needed to tend\nto unrelated business on an unrelated branch and that is why you switched,\nin which case you would want to clear them away, which is exactly what\nstash was invented for).\n"},{"id":"177584","messageId":"20111013225611.37093103@zappedws","threadId":"28664","inReplyTo":"loom.20111013T181801-923@post.gmane.org","subject":"Re: [CLOSED] git checkout <branch> allowed with uncommitted changes","fromName":"Alexey Shumkin","fromEmail":"alex.crezoff@gmail.com","sentAt":"2011-10-13T18:56:11Z","receivedAt":"2011-10-13T18:56:11Z","isPatch":false,"sender":{"key":"alex.crezoff@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1183752?v=4"},"body":"> (Though if someone can come up with a script / hook / whatever that\n> improves the \"visibility\" of stash, that would be awesome. \n> \n\"git-completion\" for Bash/ZSH gives such an opportunity\nI use it\n\ntake a look into \n<git-sources>/contrib/completion/git-completion.bash\n-- >8 --\n#    3) Consider changing your PS1 to also show the current branch:\n#         Bash: PS1='[\\u@\\h \\W$(__git_ps1 \" (%s)\")]\\$ '\n#         ZSH:  PS1='[%n@%m %c$(__git_ps1 \" (%s)\")]\\$ '\n#\n#       The argument to __git_ps1 will be displayed only if you\n#       are currently in a git repository.  The %s token will be\n#       the name of the current branch.\n#\n#       In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty\n#       value, unstaged (*) and staged (+) changes will be shown next\n#       to the branch name.  You can configure this per-repository\n#       with the bash.showDirtyState variable, which defaults to true\n#       once GIT_PS1_SHOWDIRTYSTATE is enabled.\n#\n#       You can also see if currently something is stashed, by setting\n#       GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is\nstashed, #       then a '$' will be shown next to the branch name.\n#\n#       If you would like to see if there're untracked files, then you\ncan #       set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If\nthere're #       untracked files, then a '%' will be shown next to the\nbranch name. #\n#       If you would like to see the difference between HEAD and its\n#       upstream, set GIT_PS1_SHOWUPSTREAM=\"auto\".  A \"<\" indicates\n#       you are behind, \">\" indicates you are ahead, and \"<>\"\n#       indicates you have diverged.\n-- >8 --\nmy .bashrc contains (shortly)\nPS1='\\[\\e]0;\\w [$(__git_ps1 \"%s\")]\\a\\]\\n\\[\\e[32m\\]\\u@\\h'\nPS1=$PS1' \\[\\e[33m\\]\\w\\[\\e[0m\\]\\n[$(__git_ps1 \"%s\")]\\n\\$'\n\nexport PS1\nexport GIT_PS1_SHOWDIRTYSTATE=1\nexport GIT_PS1_SHOWSTASHSTATE=1\nexport GIT_PS1_SHOWUPSTREAM=\"auto\"\n\nand console prompt with all possible cases looks like\n\n<username>@<hostname> ~/Git-src.git/contrib/completion\n[post-receive-email *+$>]\n$ \n\n* - I have unstaged changes\n+ - I have staged changes\n$ - I have stashed changes (ta-daaa!)\n> - I have commits ahead upsteam (named branch I branched from)\n\nP.S. \nAnd JFYI, it is a good form in mailing lists to CC (Reply to all)\nparticipants\n"},{"id":"177585","messageId":"loom.20111013T203610-130@post.gmane.org","threadId":"28664","inReplyTo":"7vzkh44ug1.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-13T18:56:14Z","receivedAt":"2011-10-13T18:56:14Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Junio C Hamano <gitster <at> pobox.com> writes:\n> Perhaps you can prepare a documentation patch to make it clear that git\n> WILL preserve the LOCAL CHANGES to the working tree?\n\nOr to put that another way, git WILL NOT \"rewind\" those local changes when\nswitching branches (which I still think is the more common case for new users\nthan failing to branch before editing files). Or refuse to switch if you have\nsome. Except for when it does.\n\nI'll give a shot, though I don't know how good it'll be. Off the top of my\nhead, I don't see any good way to explain the inconsistency with LOCAL CHANGES\nsometimes preventing switches and sometimes not, based on what is to the user\nan arbitrary set of rules that has nothing to do with the *current state* of\nthe worktree, but rather the state of those files in prior commits.\n\nBut sure, I'll see if I can come up with something. If nothing else, having the\nmanpage at least explain what \"M\" means; that it can be potentially disastrous;\nand what you need to do to avoid it, would be a definite plus.\n"},{"id":"177586","messageId":"m3vcrs7m3v.fsf@localhost.localdomain","threadId":"28664","inReplyTo":"loom.20111013T181801-923@post.gmane.org","subject":"Re: [CLOSED] git checkout <branch> allowed with uncommitted changes","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-10-13T19:01:23Z","receivedAt":"2011-10-13T19:01:23Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"arQon <arqon@gmx.com> writes:\n\n> (Though if someone can come up with a script / hook / whatever that improves\n> the \"visibility\" of stash, that would be awesome. Or one that makes the\n> refusal to switch branches consistent).\n\nWell, if you use __git_ps1 from contrib/completion/git-completion.bash\n(installed with git-core package for some time), there is an option to\nadd '$' to branch name if stash is non-empty (though it doesn't actually\ncheck if stash was on said branch).\n \n> Looking at the manpage for checkout in the hope that there might be a \"--safe\"\n> switch, I don't understand why\n>\n>   \"-f  Proceed even if the index *or the working tree* differs from HEAD.\"\n>\n> even exists, since it proceeds under those conditions anyway.\n> \"--safe\" appears to be exactly what the behavior should be if you DON'T\n> specify -f, except that -f nukes the working tree outright rather than just\n> bleeding it across. Hopefully it'll be clearer after some sleep.  :)\n \nWithout '-f' git-checkout would switch branches only if uncomitted\nchanges (which do not belong to any branch) could be \"floated\" on top\nof new branch.\n\nIf branch you are switching to has differences from current branch\nthat conflict with uncomitted changes, git would refuse switching\nbranches.  Now '-f' would get rid of your uncomitted changes, and '-m'\ntry to merge it with changes brought by new branch.\n\nHTH\n-- \nJakub Narębski\n"},{"id":"177590","messageId":"CAJsNXTktP_sAOS=nXiyAQOK8LudT-wLRGM+=BoQNt4=-c9otyg@mail.gmail.com","threadId":"28664","inReplyTo":"loom.20111013T171530-970@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"PJ Weisberg","fromEmail":"pj@irregularexpressions.net","sentAt":"2011-10-13T19:44:00Z","receivedAt":"2011-10-13T19:44:00Z","isPatch":false,"sender":{"key":"pj@irregularexpressions.net","avatar":"https://gravatar.com/avatar/aa2c1edcc61b536cc5c9f37fbce084e655446e2309f9818d43f13d47304a602b?d=mp&s=160"},"body":"On Thu, Oct 13, 2011 at 8:53 AM, arQon <arqon@gmx.com> wrote:\n>>git co master\n> error: Your local changes to the following files would be overwritten by\n> checkout:\n>        file1.txt\n> Please, commit your changes or stash them before you can switch branches.\n> Aborting\n>\n> I'm sure if I thought about it enough (ie re-read Andreas's post a couple\n> more times) I'd be able to understand why git gets it right sometimes but\n> not other times, but I'm too tired right now. Even when I *am* awake and\n\nGit gets it \"right\" (by your definition) when file1.txt on one branch\nis different from file1.txt on the other branch.  That means that\nswitching branches would require changing the file, so it refuses to\noverwrite your changes by doing so.  If it CAN switch branches without\nlosing your changes, it does.\n\nThe fundamental problem is that you're thinking of the changes to the\nworking tree (which aren't commited) as being \"on\" some branch.  Until\nthey're committed, changes in the working tree are only in the working\ntree.  That's basically the difference between \"committed\" and \"not\ncommitted\".\n\n-PJ\n"},{"id":"177591","messageId":"1318536451.4646.79.camel@centaur.lab.cmartin.tk","threadId":"28664","inReplyTo":"loom.20111013T193054-868@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Carlos Martín Nieto","fromEmail":"cmn@elego.de","sentAt":"2011-10-13T20:07:31Z","receivedAt":"2011-10-13T20:07:31Z","isPatch":false,"sender":{"key":"cmn@elego.de","avatar":"https://avatars.githubusercontent.com/u/335443?v=4"},"body":"On Thu, 2011-10-13 at 18:19 +0000, arQon wrote:\n> Carlos Martín Nieto <cmn <at> elego.de> writes:\n> > If file1.txt in the foo branch is different from the one in the master\n> > branch, git will refuse to switch branches. 'git diff foo master' should\n> > show that those two files are different.\n> \n> Right, but only for a definition of \"branch\" that is actually \"a fully\n> committed branch\", hence the confusion and the mention of \"uncommitted\n> changes\" in the topic.\n\nI'm not aware of any other definition of a branch, either for git or\nsubversion.\n\n> \n> An expectation that \"co branch\" should be analogous to \"cd ../branch/\" is by\n> no means unreasonable. YOU may know better, but it's surprisingly non-obvious,\n\nI don't see how. Switching branches is not the same as changing\ndirectories. It doesn't work that way, neither with git nor subversion.\nIf you choose to have each branch in their own directory, that's fine,\nbut it has very little to do with the VCS tool.\n\n> especially considering the -f option on checkout and the wording of -m, both\n> of which strongly suggest that, in the absence of either of those flags, git\n> WILL preserve the worktree by refusing to switch until that potentially-\n> harmful situation is resolved by the user.\n\nThe general description could probably benefit from a more explicit\nmention of what happens if there are local modifications. Currently it\nlooks like it's only mentioned in the text of -f and -m, which is not\nparticularly helpful.\n\n> \n> > Committing non-working code is fine, as long as you don't push it out.\n> \n> Right, but for the problem I was describing it's actually \"committing\n> non-working code is a requirement, in this situation, if you don't want your\n> tree to get eaten\". Going from \"you absolutely must not do this\" to \"you must\n> do this\" takes some mental adjustment, but you also have to be *aware* that\n> you now have to do something that was previously prohibited, which I wasn't.\n\nYou can also have a different directory for the other branch if you\nreally don't want to commit until it works. This is the same situation\nthat you find yourself right now with subversion; I don't see how it's\nthat hard to recognise that.\n\n> \n> > The bigger problem seems to be your reluctance to accept that git is\n> > different from subversion\n> \n> Not at all. If I didn't WANT something different, I wouldn't have been trying\n> to move to git in the first place.  :)\n> \n> > but don't go around saying that git\n> > corrupts branches when that's blatantly not true.\n> \n> See my first para in this post (or indeed, the original post). It's \"not true\"\n> provided all branches are fully committed when you switch between them.\n\nRight.\n\n> It blatantly IS true if you switch from a dirty branch.\n\nNo. The branch has not been corrupted or changed at all. Your local\nmodifications to files in the working tree were kept. Again, this\nhappens both for git and svn.\n\n> Redefining \"branch\" to mean \"fully committed branch\" makes it \"not true\" in\n> that context, but so does redefining green to be red and saying that grass is\n> red in that context: it may be correct from a certain POV, but it's\n> incomprehensible to anyone who isn't aware of that semantic change.\n\nThis smells like FUD. A branch and a directory are two different things.\nIf you find it more comfortable to use different directories for\ndifferent branches that's fine, but that doesn't make it a branch.\nChanging a file doesn't automatically mean that that version of the file\nbelongs to the currently active branch (or URL in the case for svn). A\nbranch is only ever changed when you commit. This is something that\nholds true across VCSs. Play with subversion's 'switch' command, it\nbehaves the same way.\n\n   cmn\n\n"},{"id":"177602","messageId":"20111014013830.GA7258@sigill.intra.peff.net","threadId":"28664","inReplyTo":"loom.20111013T203610-130@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-10-14T01:38:30Z","receivedAt":"2011-10-14T01:38:30Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Oct 13, 2011 at 06:56:14PM +0000, arQon wrote:\n\n> I'll give a shot, though I don't know how good it'll be. Off the top of my\n> head, I don't see any good way to explain the inconsistency with LOCAL CHANGES\n> sometimes preventing switches and sometimes not, based on what is to the user\n> an arbitrary set of rules that has nothing to do with the *current state* of\n> the worktree, but rather the state of those files in prior commits.\n\nThe rules are fairly straightforward.  You are moving from branch A to\nbranch B. If path X is not changed going from A to B, git will not touch\nit, whether or not you have local changes. If path X is changed going\nfrom A to B, then git will refuse the checkout, and you have the option\nof:\n\n  1. checkout -f: overwrite your local changes with what's in B\n\n  2. checkout -m: merge your changes with what's in B (using A as a\n                  common ancestor)\n\n> But sure, I'll see if I can come up with something. If nothing else,\n> having the manpage at least explain what \"M\" means; that it can be\n> potentially disastrous; and what you need to do to avoid it, would be\n> a definite plus.\n\nYou keep saying things like \"disastrous\". Git's rules are specifically\ndesigned to be as flexible as possible without allowing the checkout\ncommand to cause data loss.\n\nDo you actually have a case that causes irrecoverable data loss?\n\nNote that I don't count \"these changes were based on A, now they are\nbased on B\" as data loss. Your file content is still completely intact,\nand if you want to make them based on \"A\" again, you just need to\n\"git checkout A\" again.\n\n-Peff\n"},{"id":"177612","messageId":"20111014105116.1e5afa5d@ashu.dyn.rarus.ru","threadId":"28664","inReplyTo":"20111013201711.3d55c693@ashu.dyn.rarus.ru","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Alexey Shumkin","fromEmail":"alex.crezoff@gmail.com","sentAt":"2011-10-14T06:51:16Z","receivedAt":"2011-10-14T06:51:16Z","isPatch":false,"sender":{"key":"alex.crezoff@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1183752?v=4"},"body":"> > Lucky you. :P  The most likely reason for me is, I'm working on\n> > something and I get interrupted and have to switch. Since the code\n> > may well not even compile at this point, the last thing I want to do\n> > is commit it. \n> \"git stash\" helps here\n> With Git you can/have_to/must change your SVN-based habits.\n> DO NOT BE AFRAID OF FREQUENT COMMITS!\n> There are local until you push them.\n> \n> >git's ability for that commit to be local is half the\n> > reason I'm trying to switch to it.\n> You always have a chance to modify/reedit you commits\n> see \"git commit --amend\" and \"git rebase [-i]\"\n> \n> I'm telling you it as an ex-SVN user.\n> >(I'm not particularly keen on\n> > having to commit broken code to even a local repo, but that's still\n> > a hell of a lot better than having it pushed upstream as well).\n> \n> Again, do not be afraid to commit your changes. Be afraid of losing\n> your changes. Git makes everything (as other discussion participants\n> already described) to keep your changes within workflow when you\n> switch between branches often.\n> \n> Read some books which are describe Git's usual (and effective)\n> workflow, ProGit - http://progit.org/book/\n> Version Contol by Example (there is a chapter about Git) -\n> http://git-scm.com/course/svn.html\noops,\nwrong url\n\nfixed link\nVersion Contol by Example (there is a chapter about Git) -\nhttp://www.ericsink.com/vcbe/\n"},{"id":"177615","messageId":"20111014071638.GB2856@victor.terreactive.ch","threadId":"28664","inReplyTo":"loom.20111013T175500-495@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Victor Engmark","fromEmail":"victor.engmark@terreactive.ch","sentAt":"2011-10-14T07:16:38Z","receivedAt":"2011-10-14T07:16:38Z","isPatch":false,"sender":{"key":"victor.engmark@terreactive.ch","avatar":null},"body":"On Thu, Oct 13, 2011 at 04:17:51PM +0000, arQon wrote:\n> Victor Engmark <victor.engmark <at> terreactive.ch> writes:\n> > 1. `checkout master` and commit the fix there, then shift back and\n> > continue working\n> \n> I absolutely agree. And it's far more common than any of us would like.\n> My point is, you *can't* do this in git without first staging your current branch\n> via either commit or stash, or you risk changes bleeding between the branches\n> and/or work being lost irretrievably.\n\nIt's been pointed out enough times already that work is *not* lost (at\nleast unless you --force it to) *nor* the branches corrupted, so I'll\njust advice to look at more Git documentation. I used CVS 2004-2006 or\nso, Subversion 2006-2009, and Git since then. It's vastly superior to\neither, and it's really difficult to lose any work unless getting into\nthe habit of forcing every change.\n\n> This is not something that you would\n> expect, and as you say:\n> \n> > The second most important thing a VCS should do is not destroy any of your\n> uncommitted work unless you tell it to\n> \n> ... which is exactly what git does, and why I have a problem with it.\n\nNo, it does not. Others have explained this better already.\n\n> But the response here is uniformly \"that's just how git is\", so obviously it's\n> something you learn to become aware of over time, and avoid. It's not going to\n> get \"fixed\", because people who are used to git don't see it as a bug, so I just\n> have to decide whether I can live with it or not.\n\nIt took a while to get my head around just how broken the Subversion\nmodel was, and why my expectations from using that model kept resulting\nin \"weird\" state (although don't get me started on `svn clean`). Don't\nworry, you'll see the light :)\n\n-- \nterreActive AG\nKasinostrasse 30\nCH-5001 Aarau\nTel: +41 62 834 00 55\nFax: +41 62 823 93 56\nwww.terreactive.ch\n\nWir sichern Ihren Erfolg - seit 15 Jahren\n"},{"id":"177629","messageId":"4E980093.6040704@ira.uka.de","threadId":"28664","inReplyTo":"20111014013830.GA7258@sigill.intra.peff.net","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Holger Hellmuth","fromEmail":"hellmuth@ira.uka.de","sentAt":"2011-10-14T09:27:47Z","receivedAt":"2011-10-14T09:27:47Z","isPatch":false,"sender":{"key":"hellmuth@ira.uka.de","avatar":null},"body":"On 14.10.2011 03:38, Jeff King wrote:\n> On Thu, Oct 13, 2011 at 06:56:14PM +0000, arQon wrote:\n>\n>> I'll give a shot, though I don't know how good it'll be. Off the top of my\n>> head, I don't see any good way to explain the inconsistency with LOCAL CHANGES\n>> sometimes preventing switches and sometimes not, based on what is to the user\n>> an arbitrary set of rules that has nothing to do with the *current state* of\n>> the worktree, but rather the state of those files in prior commits.\n>\n> The rules are fairly straightforward.\n\nThey are. But what arQon is getting at is that the normal switchability \ndepends on something that is often a game of chance: Did I change a file \nthat is different between the two branches? That is only known by the \nuser for branches not far removed.\n\nNow the obvious answer is: It doesn't matter because git tells you. At \nthe right time to act upon it. But git says \"M file\" instead of what \n'git status' would say: \"#  modified:   file\". Is there a reason for \nthat? On one hand it should be familiar to svn users, on the other hand \nit is an inconsistency. And personally I always hated those cryptic \nstatus flags of svn\n\nAnother good point arQon made is that the case that you switched with \nforgotten local changes is more common than the case that you switched \nbecause you made changes in the wrong branch. If that were the case the \nwarning that you have local changes should be more visible than that \nsmall \"M file\", at best something that looks similar to 'git status' output.\n\nNow what really is more common depends on the individual. If you are a \nbeginner or a semi-frequent user, then forgetting local changes is \nprobably far more common, wheras most people on this mailing list would \nsay its the other way round. It much depends on your commit frequency \nbecause the more often you commit, the less likely is that you would \nforget local changes.\n"},{"id":"177632","messageId":"20111014095447.GC2856@victor.terreactive.ch","threadId":"28664","inReplyTo":"4E980093.6040704@ira.uka.de","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Victor Engmark","fromEmail":"victor.engmark@terreactive.ch","sentAt":"2011-10-14T09:54:47Z","receivedAt":"2011-10-14T09:54:47Z","isPatch":false,"sender":{"key":"victor.engmark@terreactive.ch","avatar":null},"body":"On Fri, Oct 14, 2011 at 11:27:47AM +0200, Holger Hellmuth wrote:\n> On 14.10.2011 03:38, Jeff King wrote:\n> >On Thu, Oct 13, 2011 at 06:56:14PM +0000, arQon wrote:\n> >\n> >>I'll give a shot, though I don't know how good it'll be. Off the top of my\n> >>head, I don't see any good way to explain the inconsistency with LOCAL CHANGES\n> >>sometimes preventing switches and sometimes not, based on what is to the user\n> >>an arbitrary set of rules that has nothing to do with the *current state* of\n> >>the worktree, but rather the state of those files in prior commits.\n> >\n> >The rules are fairly straightforward.\n> \n> They are. But what arQon is getting at is that the normal\n> switchability depends on something that is often a game of chance:\n> Did I change a file that is different between the two branches? That\n> is only known by the user for branches not far removed.\n> \n> Now the obvious answer is: It doesn't matter because git tells you.\n> At the right time to act upon it. But git says \"M file\" instead of\n> what 'git status' would say: \"#  modified:   file\". Is there a\n> reason for that? On one hand it should be familiar to svn users, on\n> the other hand it is an inconsistency. And personally I always hated\n> those cryptic status flags of svn\n> \n> Another good point arQon made is that the case that you switched\n> with forgotten local changes is more common than the case that you\n> switched because you made changes in the wrong branch. If that were\n> the case the warning that you have local changes should be more\n> visible than that small \"M file\", at best something that looks\n> similar to 'git status' output.\n\nVery good point. How about by default just running `git status` after a\nsuccessful checkout, and only printing the result if there are any\nchanges? That way:\n1) If no changes are pending, nothing is displayed.\n2) The user sees a *familiar* style output if anything changed.\n3) If there's an alias for \"status\", it would be used.\n\nExample:\n\n$ mkdir /tmp/test\n$ cd /tmp/test\n$ git init\nInitialized empty Git repository in /tmp/test/.git/\n$ echo foo > foo\n$ echo bar > bar\n$ git add foo bar\n$ git commit -m \"Initial commit\"\n[master (root-commit) 55246c6] Initial commit\n 2 files changed, 2 insertions(+), 0 deletions(-)\n create mode 100644 bar\n create mode 100644 foo\n$ echo foobar > bar\n$ git branch --track test\nBranch test set up to track local branch master.\n$ git checkout test\nM   bar\nSwitched to branch 'test'\n\nAfter `git checkout test`, we should instead see:\n# On branch test\n# Changed but not updated:\n#   (use \"git add <file>...\" to update what will be committed)\n#   (use \"git checkout -- <file>...\" to discard changes in working directory)\n#\n#   modified:   bar\n#\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n2c,\nV\n\n-- \nterreActive AG\nKasinostrasse 30\nCH-5001 Aarau\nTel: +41 62 834 00 55\nFax: +41 62 823 93 56\nwww.terreactive.ch\n\nWir sichern Ihren Erfolg - seit 15 Jahren\n"},{"id":"177800","messageId":"loom.20111016T201930-426@post.gmane.org","threadId":"28664","inReplyTo":"20111014095447.GC2856@victor.terreactive.ch","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"arQon","fromEmail":"arqon@gmx.com","sentAt":"2011-10-16T18:25:03Z","receivedAt":"2011-10-16T18:25:03Z","isPatch":false,"sender":{"key":"arqon@gmx.com","avatar":null},"body":"Victor Engmark <victor.engmark <at> terreactive.ch> writes:\n> Very good point. How about by default just running `git status` after a\n> successful checkout, and only printing the result if there are any\n> changes? That way:\n> 1) If no changes are pending, nothing is displayed.\n> 2) The user sees a *familiar* style output if anything changed.\n> 3) If there's an alias for \"status\", it would be used.\n\nI'm sold on this. Better documentation for checkout wouldn't hurt regardless,\nand I'm still planning on that when I get a chance; but better *behavior* is a\nclear win either way. Adding half a page of text to the docs explaining what\neach status char means is a hugely-inferior \"solution\" to simply not having\nan aberrant status-ish output in the first place.\n"},{"id":"177801","messageId":"7vy5wkptan.fsf@alter.siamese.dyndns.org","threadId":"28664","inReplyTo":"loom.20111016T201930-426@post.gmane.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-16T20:37:04Z","receivedAt":"2011-10-16T20:37:04Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"arQon <arqon@gmx.com> writes:\n\n> ... better *behavior* is a\n> clear win either way.\n\nI doubt the full status output is better behaviour. For one thing, you do\nnot need full status as by definition branch switching would only have\nlocal changes as a result (i.e. you will not see \"Changes to be committed\"\nsection).\n\nBut if you really do not want to learn how to read \"diff --name-status\"\noutput, here is a patch to allow you say \"git checkout -v other_branch\".\nHopefully it will help you convince yourself why it is not a better\nbehaviour.\n\n builtin/checkout.c |   46 +++++++++++++++++++++++++++++++++-------------\n 1 files changed, 33 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 49a547a..0c21556 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -28,7 +28,7 @@ static const char * const checkout_usage[] = {\n };\n \n struct checkout_opts {\n-\tint quiet;\n+\tint verbosity;\n \tint merge;\n \tint force;\n \tint force_detach;\n@@ -291,10 +291,10 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,\n \treturn errs;\n }\n \n-static void show_local_changes(struct object *head, struct diff_options *opts)\n+static void show_local_changes_brief(struct object *head, struct diff_options *opts)\n {\n \tstruct rev_info rev;\n-\t/* I think we want full paths, even if we're in a subdirectory. */\n+\n \tinit_revisions(&rev, NULL);\n \trev.diffopt.flags = opts->flags;\n \trev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;\n@@ -304,6 +304,26 @@ static void show_local_changes(struct object *head, struct diff_options *opts)\n \trun_diff_index(&rev, 0);\n }\n \n+static void show_local_changes_status(void)\n+{\n+\tconst char *argv[] = { \"status\", NULL };\n+\n+\trun_command_v_opt(argv, RUN_GIT_CMD);\n+}\n+\n+static void show_local_changes(struct checkout_opts *opts,\n+\t\t\t       struct object *head,\n+\t\t\t       struct diff_options *diffopts)\n+{\n+\tif (opts->force || opts->verbosity < 0)\n+\t\treturn;\n+\n+\tif (0 < opts->verbosity)\n+\t\tshow_local_changes_status();\n+\telse\n+\t\tshow_local_changes_brief(head, diffopts);\n+}\n+\n static void describe_detached_head(const char *msg, struct commit *commit)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n@@ -326,7 +346,7 @@ static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)\n \topts.reset = 1;\n \topts.merge = 1;\n \topts.fn = oneway_merge;\n-\topts.verbose_update = !o->quiet;\n+\topts.verbose_update = (0 <= o->verbosity);\n \topts.src_index = &the_index;\n \topts.dst_index = &the_index;\n \tparse_tree(tree);\n@@ -403,7 +423,7 @@ static int merge_working_tree(struct checkout_opts *opts,\n \t\ttopts.update = 1;\n \t\ttopts.merge = 1;\n \t\ttopts.gently = opts->merge && old->commit;\n-\t\ttopts.verbose_update = !opts->quiet;\n+\t\ttopts.verbose_update = (0 <= opts->verbosity);\n \t\ttopts.fn = twoway_merge;\n \t\ttopts.dir = xcalloc(1, sizeof(*topts.dir));\n \t\ttopts.dir->flags |= DIR_SHOW_IGNORED;\n@@ -478,9 +498,6 @@ static int merge_working_tree(struct checkout_opts *opts,\n \t    commit_locked_index(lock_file))\n \t\tdie(_(\"unable to write new index file\"));\n \n-\tif (!opts->force && !opts->quiet)\n-\t\tshow_local_changes(&new->commit->object, &opts->diff_options);\n-\n \treturn 0;\n }\n \n@@ -552,14 +569,14 @@ static void update_refs_for_switch(struct checkout_opts *opts,\n \t} else if (opts->force_detach || !new->path) {\t/* No longer on any branch. */\n \t\tupdate_ref(msg.buf, \"HEAD\", new->commit->object.sha1, NULL,\n \t\t\t   REF_NODEREF, DIE_ON_ERR);\n-\t\tif (!opts->quiet) {\n+\t\tif (0 <= opts->verbosity) {\n \t\t\tif (old->path && advice_detached_head)\n \t\t\t\tdetach_advice(old->path, new->name);\n \t\t\tdescribe_detached_head(_(\"HEAD is now at\"), new->commit);\n \t\t}\n \t} else if (new->path) {\t/* Switch branches. */\n \t\tcreate_symref(\"HEAD\", new->path, msg.buf);\n-\t\tif (!opts->quiet) {\n+\t\tif (0 <= opts->verbosity) {\n \t\t\tif (old->path && !strcmp(new->path, old->path)) {\n \t\t\t\tfprintf(stderr, _(\"Already on '%s'\\n\"),\n \t\t\t\t\tnew->name);\n@@ -584,7 +601,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,\n \t}\n \tremove_branch_state();\n \tstrbuf_release(&msg);\n-\tif (!opts->quiet &&\n+\tif (0 <= opts->verbosity &&\n \t    (new->path || (!opts->force_detach && !strcmp(new->name, \"HEAD\"))))\n \t\treport_tracking(new);\n }\n@@ -717,13 +734,16 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)\n \tif (ret)\n \t\treturn ret;\n \n-\tif (!opts->quiet && !old.path && old.commit && new->commit != old.commit)\n+\tif (0 <= opts->verbosity && !old.path && old.commit && new->commit != old.commit)\n \t\torphaned_commit_warning(old.commit);\n \n \tupdate_refs_for_switch(opts, &old, new);\n \n \tret = post_checkout_hook(old.commit, new->commit, 1);\n \tfree((char *)old.path);\n+\n+\tshow_local_changes(opts, &new->commit->object, &opts->diff_options);\n+\n \treturn ret || opts->writeout_error;\n }\n \n@@ -906,7 +926,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \tint patch_mode = 0;\n \tint dwim_new_local_branch = 1;\n \tstruct option options[] = {\n-\t\tOPT__QUIET(&opts.quiet, \"suppress progress reporting\"),\n+\t\tOPT__VERBOSITY(&opts.verbosity),\n \t\tOPT_STRING('b', NULL, &opts.new_branch, \"branch\",\n \t\t\t   \"create and checkout a new branch\"),\n \t\tOPT_STRING('B', NULL, &opts.new_branch_force, \"branch\",\n"},{"id":"177804","messageId":"4E9B54F3.5070203@ira.uka.de","threadId":"28664","inReplyTo":"7vy5wkptan.fsf@alter.siamese.dyndns.org","subject":"Re: [BUG] git checkout <branch> allowed with uncommitted changes","fromName":"Holger Hellmuth","fromEmail":"hellmuth@ira.uka.de","sentAt":"2011-10-16T22:04:35Z","receivedAt":"2011-10-16T22:04:35Z","isPatch":false,"sender":{"key":"hellmuth@ira.uka.de","avatar":null},"body":"Am 16.10.2011 22:37, schrieb Junio C Hamano:\n> I doubt the full status output is better behaviour. For one thing, you do\n> not need full status as by definition branch switching would only have\n> local changes as a result (i.e. you will not see \"Changes to be committed\"\n> section).\n\n?? After \"git add\" on a changed file I see it under \"Changes to be \ncommitted\". And branch switching still works (with newest git from \nmaster branch):\n\n# On branch two\n# Changes to be committed:\n#   (use \"git reset HEAD <file>...\" to unstage)\n#\n#       modified:   test1.txt\n#\n# Changes not staged for commit:\n#   (use \"git add <file>...\" to update what will be committed)\n#   (use \"git checkout -- <file>...\" to discard changes in working \ndirectory)\n#\n#       modified:   test2.txt\n#\n\nSmall inconsistency: On the other branch instead of \"Changes not staged \nfor commit:\" the text \"Changed but not updated:\" is printed, everything \nelse is unchanged\n"}]}