On Thu, Sep 01, 2011 at 11:47:59PM +0800, Tzu-Jung Lee wrote: > Correct me if I'm wrong: > > git-checkout saves the changes to index and working-tree, and > tries to apply them to the destined commit. > If the changes are applicable, then git-checkout the destined > commit and apply the changes. > Otherwise, git-checkout fails with warnings and leaves the current > status untouched. Not exactly. "git checkout <branch>" will switch your HEAD to <branch>, and then try to make your index and working tree match the contents of <branch>, with two exceptions: 1. If you have local changes in a file, but the contents of the file in <branch> do not differ from what's in the current HEAD, then the file will be left alone (i.e., your local changes will be preserved). 2. If you have local changes in a file, and the contents of the file in <branch> differ both from what's in your working tree and from what's in your current HEAD, git will print an error and refuse to overwrite your changes (though you can ask it to merge them with "git checkout -m"). So it is not about "do these changes apply", but rather that we will give up any time file-level merging is required (unless "-m" is specified). The other form, "git checkout <branch> [--] <file>", is not about switching branches at all, but about putting content from <branch> into the current index and working tree, overwriting what's there. > If the above correct. Please help me clarify if the following corner > case an intended or unexpected behavior. > [...] > $ git checkout -b br1 > $ git reset HEAD^ > Unstaged changes after reset: > M aaa.txt > M bbb.txt So you have changes in two commits... > $ git checkout HEAD aaa.txt And here you explicitly overwrite the changes in aaa.txt. > $ git status --short > M bbb.txt ...leaving only the changes in bbb.txt. > $ git add bbb.txt > $ git status > > # On branch br1 > # Changes to be committed: > # (use "git reset HEAD <file>..." to unstage) > # > # modified: bbb.txt > # OK, now it's staged. > $ git checkout master > Switched to branch 'master' > > git silently switch to master without warning against the index are > "RESTORE/RESET" to clean. Yes, because the changes in your index were identical to what was in the destination branch. So we didn't drop any changes; they're still in the index and in the working tree. It's simply that when compared to your new HEAD, they are uninteresting. > $ git checkout br1 > $ git status > # On branch br1 > nothing to commit (working directory clean) And now when we switch to br1, you have no changes against master in your working tree or index, so there is no dirty state to block switching branches. I think git is working as intended here. I agree it is a somewhat surprising corner case, but only because your changes happened to exactly match the difference between the two branches you are switching between. But it makes sense when you think about what "dirty state" means: it is differences between HEAD and your index and working tree. So we usually think of creating or removing dirty state by changing the working tree. But you could equally well do it by changing the HEAD without changing the working tree, which is what you did here. -Peff -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html