Re: git-checkout silently throws away the dirty status of index without a warning?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Sep 2, 2011 at 12:56 AM, Jeff King <peff@xxxxxxxx> wrote:
> 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).
>

Ah!!! I think it was the "file-level merging" that surprised me so much.
I used to think it's an atomic "commit-level merging" -- cleanly apply
all the changes or touch nothing at all.
Having using git for years, I never notice this difference and neither
did it cause any trouble to me.
Until the corner case came to me today...

Thanks for the quick and precise explanation.

> 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


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]