{"thread":{"id":"15609","subject":"[funny] \"git checkout -t origin/xyzzy\" seems to misbehave","startedAt":"2008-09-21T08:23:00Z","lastAt":"2008-09-21T18:36:06Z","messageCount":3,"participants":["Junio C Hamano","Daniel Barkalow","Alex Riesen"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"91215","messageId":"7v1vzd29i3.fsf@gitster.siamese.dyndns.org","threadId":"15609","inReplyTo":null,"subject":"[funny] \"git checkout -t origin/xyzzy\" seems to misbehave","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-21T08:23:00Z","receivedAt":"2008-09-21T08:23:00Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When you\n\n * are on a branch \"foo\" that is not \"bar\",\n * have \"origin/bar\",\n * and already have a local branch \"bar\",\n\n\"git checkout -t origin/bar\" seems to misbehave.\n\n    $ git clone -s git.junio victim-002\n    $ cd victim-002\n    $ git branch\n    * master\n    $ git checkout -t origin/next\n    Branch next set up to track remote branch refs/remotes/origin/next.\n    Switched to a new branch \"next\"\n    $ git checkout -t origin/master\n    fatal: A branch named 'master' already exists.\n    $ git branch\n      master\n    * next\n    $ git diff --cached --shortstat\n     60 files changed, 2378 insertions(+), 3412 deletions(-)\n    $ git diff --cached master\n    $ exit\n\nThe first \"checkout -t\" is fine.  The failed one seems to have already\nupdated the index and the work tree when it notices that it cannot create\na new branch.\n\nI suspect \"-t\" does not have to be in effect to trigger this; in other\nwords, \"git checkout -b master origin/master\" would have the same issue.\n\nI'm reporting this before digging it further myself, because I may not be\nable to diagnose this before I leave for a vacation.\n"},{"id":"91332","messageId":"20080921174438.GB3877@blimp.localhost","threadId":"15609","inReplyTo":"7v1vzd29i3.fsf@gitster.siamese.dyndns.org","subject":"Re: [funny] \"git checkout -t origin/xyzzy\" seems to misbehave","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2008-09-21T17:44:38Z","receivedAt":"2008-09-21T17:44:38Z","isPatch":false,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Junio C Hamano, Sun, Sep 21, 2008 10:23:00 +0200:\n> When you\n> \n>  * are on a branch \"foo\" that is not \"bar\",\n>  * have \"origin/bar\",\n>  * and already have a local branch \"bar\",\n> \n> \"git checkout -t origin/bar\" seems to misbehave.\n> \n>     $ git clone -s git.junio victim-002\n>     $ cd victim-002\n>     $ git branch\n>     * master\n>     $ git checkout -t origin/next\n>     Branch next set up to track remote branch refs/remotes/origin/next.\n>     Switched to a new branch \"next\"\n>     $ git checkout -t origin/master\n>     fatal: A branch named 'master' already exists.\n>     $ git branch\n>       master\n>     * next\n>     $ git diff --cached --shortstat\n>      60 files changed, 2378 insertions(+), 3412 deletions(-)\n>     $ git diff --cached master\n>     $ exit\n> \n> The first \"checkout -t\" is fine.  The failed one seems to have already\n> updated the index and the work tree when it notices that it cannot create\n> a new branch.\n\nPrecisely this (branch already exists) case is easy to handle with a\nresolve_ref in builtin-checkout.c:switch_branches.\n\nThe other errors will still leave index and working tree in this\nstate: branch.c:create_branch does not cleanup in case of errors,\nit just dies.\n"},{"id":"91249","messageId":"alpine.LNX.1.00.0809211406150.19665@iabervon.org","threadId":"15609","inReplyTo":"7v1vzd29i3.fsf@gitster.siamese.dyndns.org","subject":"Re: [funny] \"git checkout -t origin/xyzzy\" seems to misbehave","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-09-21T18:36:06Z","receivedAt":"2008-09-21T18:36:06Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sun, 21 Sep 2008, Junio C Hamano wrote:\n\n> When you\n> \n>  * are on a branch \"foo\" that is not \"bar\",\n>  * have \"origin/bar\",\n>  * and already have a local branch \"bar\",\n> \n> \"git checkout -t origin/bar\" seems to misbehave.\n\nIt's always been the case if the thing that fails is changing the ref for \nHEAD, you're left with the index and working tree changed but the ref \nunchanged. OTOH, the C conversion lost the early checks that a new branch \nname is plausible in advance of trying anything.\n\ncommit c36a025b20ac752f8960bc36dcbab98ca1824657\nAuthor: Daniel Barkalow <barkalow@iabervon.org>\nDate:   Sun Sep 21 14:25:31 2008 -0400\n\n    Check early that a new branch is new and valid\n    \n    If you fail to update refs to change branches in checkout, your index\n    and working tree are left already updated. We don't have an easy way\n    to undo this, but at least we can check things that would make the\n    creation of a new branch fail. These checks were in the shell version,\n    and were lost in the C conversion.\n    \n    The messages are from the shell version, and should probably be made nicer.\n    \n    Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>\n\ndiff --git a/builtin-checkout.c b/builtin-checkout.c\nindex 9377a1c..4497b70 100644\n--- a/builtin-checkout.c\n+++ b/builtin-checkout.c\n@@ -580,6 +580,18 @@ no_reference:\n \t\treturn checkout_paths(source_tree, pathspec);\n \t}\n \n+\tif (opts.new_branch) {\n+\t\tstruct strbuf buf;\n+\t\tstrbuf_init(&buf, 0);\n+\t\tstrbuf_addstr(&buf, \"refs/heads/\");\n+\t\tstrbuf_addstr(&buf, opts.new_branch);\n+\t\tif (!get_sha1(buf.buf, rev))\n+\t\t\tdie(\"git checkout: branch %s already exists\", opts.new_branch);\n+\t\tif (check_ref_format(buf.buf))\n+\t\t\tdie(\"git checkout: we do not like '%s' as a branch name.\", opts.new_branch);\n+\t\tstrbuf_release(&buf);\n+\t}\n+\n \tif (new.name && !new.commit) {\n \t\tdie(\"Cannot switch branch to a non-commit.\");\n \t}\n"}]}