{"thread":{"id":"25595","subject":"Inconsistent behavior of the path disambiguator","startedAt":"2010-10-29T18:11:03Z","lastAt":"2010-10-31T03:57:13Z","messageCount":10,"participants":["Dun Peal","Junio C Hamano","Jonathan Nieder"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"154801","messageId":"AANLkTinM863uZfRxy_1BW1fnfEPsPo8A2m86=Wxh7XGd@mail.gmail.com","threadId":"25595","inReplyTo":null,"subject":"Inconsistent behavior of the path disambiguator","fromName":"Dun Peal","fromEmail":"dunpealer@gmail.com","sentAt":"2010-10-29T18:11:03Z","receivedAt":"2010-10-29T18:11:03Z","isPatch":false,"sender":{"key":"dunpealer@gmail.com","avatar":"https://gravatar.com/avatar/42f3e6a1166eb44e33f24c20ccbe809fa8591413f366dfe3755c8a8d4935ace9?d=mp&s=160"},"body":"Hi.\n\nWhen I clone a remote that has a branch `foo`, then `git checkout foo\n--`, the path disamgiuator makes the operation fail. `git checkout\nfoo` without the disambiguator works. Following that, when branch\n`foo` already exists, `git checkout foo --` works even with the\ndisambiguator that caused it to fail previously.\n\nHere's a log demonstrating a full reproduction of the bug with git\n1.7.2 on Linux:\n\n=== LOG START ===\n\n$ mkdir origin && cd origin && git init && echo 1 >> test.txt && git\nadd test.txt && git commit -am \"First.\" && git branch foo\nInitialized empty Git repository in /home/afine/lab/gitexp/origin/origin/.git/\n[master (root-commit) 6042525] First.\n 1 files changed, 1 insertions(+), 0 deletions(-)\n create mode 100644 test.txt\n$ cd .. && git clone origin local && cd local\nCloning into local...\ndone.\n$ git checkout foo --\nfatal: invalid reference: foo\n$ git checkout foo\nBranch foo set up to track remote branch foo from origin.\nSwitched to a new branch 'foo'\n$ git checkout master\nSwitched to branch 'master'\n$ git checkout foo --\nSwitched to branch 'foo'\n\n=== LOG END ===\n\nThis looks like a bug.\n\nThanks, D\n"},{"id":"154805","messageId":"7vbp6c7ski.fsf@alter.siamese.dyndns.org","threadId":"25595","inReplyTo":"AANLkTinM863uZfRxy_1BW1fnfEPsPo8A2m86=Wxh7XGd@mail.gmail.com","subject":"Re: Inconsistent behavior of the path disambiguator","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-10-29T18:38:21Z","receivedAt":"2010-10-29T18:38:21Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Dun Peal <dunpealer@gmail.com> writes:\n\n> When I clone a remote that has a branch `foo`, then `git checkout foo\n> --`, the path disamgiuator makes the operation fail. `git checkout\n> foo` without the disambiguator works. Following that, when branch\n> `foo` already exists, `git checkout foo --` works even with the\n> disambiguator that caused it to fail previously.\n\nI do not think there is any bug.  You were being bitten by folks who tried\nto be helpful for newbies by introducing a(n arguably confusing) special\ncase; I can see why this is confusing, though.\n\n> $ git checkout foo --\n> fatal: invalid reference: foo\n\nImmediately after a clone you would have\n\n    refs/heads/master\n    refs/HEAD -> refs/heads/master\n    refs/remotes/origin/foo\n    refs/remotes/origin/whatever-else-you-have\n    ...\n\nand there is no commit that you can name with \"foo\" when asking git to\ncheck out some paths out of, nor there is no branch that you can name with\n\"foo\" when asking git to check out to work on it.\n\nYou can say 'origin/foo', though, in general.\n\n> $ git checkout foo\n> Branch foo set up to track remote branch foo from origin.\n\nAsking to check out a branch \"foo\" in order to work on extending the\nhistory of that branch, when there is _no_ \"foo\", has a special magic\ninvented by some folks to \"help usability\", if there is only one $remote\nthat has \"foo\" in it.  In this case, you have refs/remotes/origin/foo but\nno other refs/remotes/$frotz/foo, and this special magic kicks in.\n\ngit behaves as if you meant \"git checkout -t -b foo origin/foo\" but were\ntoo lazy to type that yourself in this case.\n\n> Switched to a new branch 'foo'\n> $ git checkout master\n> Switched to branch 'master'\n> $ git checkout foo --\n> Switched to branch 'foo'\n\nThis is referring to local branch \"foo\", there is nothing magic.\n"},{"id":"154806","messageId":"AANLkTikc+pBe31j9tA88HwGz2kBouW_0S9oU6PtSQEzj@mail.gmail.com","threadId":"25595","inReplyTo":"7vbp6c7ski.fsf@alter.siamese.dyndns.org","subject":"Re: Inconsistent behavior of the path disambiguator","fromName":"Dun Peal","fromEmail":"dunpealer@gmail.com","sentAt":"2010-10-29T18:54:10Z","receivedAt":"2010-10-29T18:54:10Z","isPatch":false,"sender":{"key":"dunpealer@gmail.com","avatar":"https://gravatar.com/avatar/42f3e6a1166eb44e33f24c20ccbe809fa8591413f366dfe3755c8a8d4935ace9?d=mp&s=160"},"body":"On Fri, Oct 29, 2010 at 7:38 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> I do not think there is any bug.  You were being bitten by folks who tried\n> to be helpful for newbies by introducing a(n arguably confusing) special\n> case; I can see why this is confusing, though.\n\nThanks.\n\nWe just switched to Git, and our developers got used to being able to\njust `git checkout branch` to create a local remote-tracking one for\nthat remote branch.\n\nThen we were bitten by a branch `foo` when path `./foo` existed.\n\nI think the syntactic sugar needs to either be removed, or\n(preferably) be made consistent.\n\nThe current behavior is that if I try to checkout a branch that\ndoesn't exist, but does exist on the remote, git creates a local\nremote tracking branch for the one I tried to check out.\n\nIt makes no sense IMHO for the disambiguating syntax to break that\nbehavior, especially since in some cases, the disambiguating syntax is\nnecessary.\n\nThanks, D\n"},{"id":"154810","messageId":"20101029194639.GA1738@burratino","threadId":"25595","inReplyTo":"7vbp6c7ski.fsf@alter.siamese.dyndns.org","subject":"Re: Inconsistent behavior of the path disambiguator","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-29T19:46:39Z","receivedAt":"2010-10-29T19:46:39Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n\n>       I can see why this is confusing, though.\n>\n> Dun Peal <dunpealer@gmail.com> writes:\n>> $ git checkout foo --\n>> fatal: invalid reference: foo\n>\n> Immediately after a clone you would have\n>\n>     refs/heads/master\n>     refs/HEAD -> refs/heads/master\n>     refs/remotes/origin/foo\n>     refs/remotes/origin/whatever-else-you-have\n>     ...\n>\n> and there is no commit that you can name with \"foo\" when asking git to\n> check out some paths out of, nor there is no branch that you can name with\n> \"foo\" when asking git to check out to work on it.\n\nHow about something like this?\n-- 8< --\nSubject: checkout: apply Dscho's dwim even with \"--\" present\n\ngit reset and similar commands use -- to disambiguate between\nrevisions and paths on the command line.  The same syntax is not\nnecessary to specify a revision to git checkout (for convenience\nand historical reasons, revisions are preferred over paths), but\nfor consistency it is accepted:\n\n\tgit checkout master --; # check out master branch, not \"master\" file.\n\nThe autovivification of branches introduced by 70c9ac2f1 (DWIM \"git\ncheckout frotz\" to \"git checkout -b frotz origin/frotz\", 2009-10-18)\nis currently disabled by that syntax, for no good reason.  Paranoid\nscripts can still use\n\n\tgit checkout --no-guess master\n\nor even better,\n\n\told=$(git rev-parse --verify HEAD)\n\tnew=$(git rev-parse --verify refs/heads/master^0)\n\tgit read-tree -m -u --exclude-standard $old $new\n\tgit symbolic-ref -m \"$me: switching branches\" HEAD refs/heads/master\n\nRequested-by: Dun Peal <dunpealer@gmail.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 9240faf..1dc3640 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -771,6 +771,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t *   <ref> must be a valid tree, everything after the '--' must be\n \t *   a path.\n \t *\n+\t *   Except: with no paths, if <something> does not resolve as\n+\t *   an object, no -t nor -b was given, and there is a tracking\n+\t *   branch whose name is <something> in one and only one remote,\n+\t *   then this is a short-hand to fork local <something> from\n+\t *   that remote-tracking branch.\n+\t *\n \t * case 2: git checkout -- [<paths>]\n \t *\n \t *   everything after the '--' must be paths.\n@@ -808,13 +814,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\targ = \"@{-1}\";\n \n \t\tif (get_sha1_mb(arg, rev)) {\n-\t\t\tif (has_dash_dash)          /* case (1) */\n-\t\t\t\tdie(\"invalid reference: %s\", arg);\n \t\t\tif (!patch_mode &&\n \t\t\t    dwim_new_local_branch &&\n \t\t\t    opts.track == BRANCH_TRACK_UNSPECIFIED &&\n \t\t\t    !opts.new_branch &&\n-\t\t\t    !check_filename(NULL, arg) &&\n+\t\t\t    (has_dash_dash || !check_filename(NULL, arg)) &&\n \t\t\t    argc == 1) {\n \t\t\t\tconst char *remote = unique_tracking_name(arg);\n \t\t\t\tif (!remote || get_sha1(remote, rev))\n@@ -822,9 +826,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t\topts.new_branch = arg;\n \t\t\t\targ = remote;\n \t\t\t\t/* DWIMmed to create local branch */\n-\t\t\t}\n-\t\t\telse\n+\t\t\t} else if (has_dash_dash) {\t/* case (1) */\n+\t\t\t\tdie(\"invalid reference: %s\", arg);\n+\t\t\t} else {\n \t\t\t\tgoto no_reference;\n+\t\t\t}\n \t\t}\n \n \t\t/* we can't end up being in (2) anymore, eat the argument */\n"},{"id":"154811","messageId":"7vwrp069aq.fsf_-_@alter.siamese.dyndns.org","threadId":"25595","inReplyTo":"AANLkTikc+pBe31j9tA88HwGz2kBouW_0S9oU6PtSQEzj@mail.gmail.com","subject":"Re* Inconsistent behavior of the path disambiguator","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-10-29T20:19:57Z","receivedAt":"2010-10-29T20:19:57Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Dun Peal <dunpealer@gmail.com> writes:\n\n> It makes no sense IMHO for the disambiguating syntax to break that\n> behavior,...\n\nAhh, Ok, and sorry, I think I misread your original.\n\nI agree that there shouldn't be any difference between \"git co foo\" and\n\"git co foo --\" when you do not have local \"foo\" (i.e. immediately after\ncloning from somebody who has \"foo\").\n\nPerhaps something like this...\n\n builtin/checkout.c |   52 +++++++++++++++++++++++++++++++++-------------------\n 1 files changed, 33 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 9240faf..ceaf479 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -804,17 +804,30 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\targ = argv[0];\n \t\thas_dash_dash = (argc > 1) && !strcmp(argv[1], \"--\");\n \n+\t\tif (has_dash_dash) {\n+\t\t\targv++;\n+\t\t\targc--;\n+\t\t\t/*\n+\t\t\t * Copy arg so that argv[] ends up being all\n+\t\t\t * paths if arg turns out to be a non-ref.\n+\t\t\t */\n+\t\t\targv[0] = arg;\n+\t\t}\n+\n+\t\t/*\n+\t\t * arg may be a ref; or it may be the first of the\n+\t\t * paths, if we did not see dash-dash.\n+\t\t */\n \t\tif (!strcmp(arg, \"-\"))\n \t\t\targ = \"@{-1}\";\n \n \t\tif (get_sha1_mb(arg, rev)) {\n-\t\t\tif (has_dash_dash)          /* case (1) */\n-\t\t\t\tdie(\"invalid reference: %s\", arg);\n+\t\t\t/* Not a ref */\n \t\t\tif (!patch_mode &&\n \t\t\t    dwim_new_local_branch &&\n \t\t\t    opts.track == BRANCH_TRACK_UNSPECIFIED &&\n \t\t\t    !opts.new_branch &&\n-\t\t\t    !check_filename(NULL, arg) &&\n+\t\t\t    (has_dash_dash || !check_filename(NULL, arg)) &&\n \t\t\t    argc == 1) {\n \t\t\t\tconst char *remote = unique_tracking_name(arg);\n \t\t\t\tif (!remote || get_sha1(remote, rev))\n@@ -823,11 +836,26 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t\targ = remote;\n \t\t\t\t/* DWIMmed to create local branch */\n \t\t\t}\n-\t\t\telse\n+\t\t\telse {\n \t\t\t\tgoto no_reference;\n+\t\t\t}\n+\t\t} else if (!has_dash_dash && argc > 1) {\n+\t\t\t/*\n+\t\t\t * We saw \"checkout foo bar\" without dashdash,\n+\t\t\t * and \"foo\" can name an object.  It shouldn't\n+\t\t\t * be a filename. Note that by checking argc,\n+\t\t\t * we do not complain in the most common case\n+\t\t\t *\tgit checkout branch\n+\t\t\t * even if there happen to be a file called 'branch';\n+\t\t\t * it would be extremely annoying.\n+\t\t\t */\n+\t\t\tverify_non_filename(NULL, arg);\n \t\t}\n \n-\t\t/* we can't end up being in (2) anymore, eat the argument */\n+\t\t/*\n+\t\t * It turns out that we had a ref, so argv[1:] are the\n+\t\t * paths (we stripped dash-dash already).\n+\t\t */\n \t\targv++;\n \t\targc--;\n \n@@ -847,20 +875,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \n \t\tif (!source_tree)                   /* case (1): want a tree */\n \t\t\tdie(\"reference is not a tree: %s\", arg);\n-\t\tif (!has_dash_dash) {/* case (3 -> 1) */\n-\t\t\t/*\n-\t\t\t * Do not complain the most common case\n-\t\t\t *\tgit checkout branch\n-\t\t\t * even if there happen to be a file called 'branch';\n-\t\t\t * it would be extremely annoying.\n-\t\t\t */\n-\t\t\tif (argc)\n-\t\t\t\tverify_non_filename(NULL, arg);\n-\t\t}\n-\t\telse {\n-\t\t\targv++;\n-\t\t\targc--;\n-\t\t}\n \t}\n \n no_reference:\n"},{"id":"154812","messageId":"7vsjzo691r.fsf@alter.siamese.dyndns.org","threadId":"25595","inReplyTo":"20101029194639.GA1738@burratino","subject":"Re: Inconsistent behavior of the path disambiguator","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-10-29T20:25:20Z","receivedAt":"2010-10-29T20:25:20Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>\n>>       I can see why this is confusing, though.\n>>\n>> Dun Peal <dunpealer@gmail.com> writes:\n>>> $ git checkout foo --\n>>> fatal: invalid reference: foo\n>>\n>> Immediately after a clone you would have\n>>\n>>     refs/heads/master\n>>     refs/HEAD -> refs/heads/master\n>>     refs/remotes/origin/foo\n>>     refs/remotes/origin/whatever-else-you-have\n>>     ...\n>>\n>> and there is no commit that you can name with \"foo\" when asking git to\n>> check out some paths out of, nor there is no branch that you can name with\n>> \"foo\" when asking git to check out to work on it.\n>\n> How about something like this?\n\nThat looks simpler than what I just did.  Can we have a few tests, too?\n\n> -- 8< --\n> Subject: checkout: apply Dscho's dwim even with \"--\" present\n>\n> git reset and similar commands use -- to disambiguate between\n> revisions and paths on the command line.  The same syntax is not\n> necessary to specify a revision to git checkout (for convenience\n> and historical reasons, revisions are preferred over paths), but\n> for consistency it is accepted:\n>\n> \tgit checkout master --; # check out master branch, not \"master\" file.\n>\n> The autovivification of branches introduced by 70c9ac2f1 (DWIM \"git\n> checkout frotz\" to \"git checkout -b frotz origin/frotz\", 2009-10-18)\n> is currently disabled by that syntax, for no good reason.  Paranoid\n> scripts can still use\n>\n> \tgit checkout --no-guess master\n>\n> or even better,\n>\n> \told=$(git rev-parse --verify HEAD)\n> \tnew=$(git rev-parse --verify refs/heads/master^0)\n> \tgit read-tree -m -u --exclude-standard $old $new\n> \tgit symbolic-ref -m \"$me: switching branches\" HEAD refs/heads/master\n>\n> Requested-by: Dun Peal <dunpealer@gmail.com>\n> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>\n> ---\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 9240faf..1dc3640 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -771,6 +771,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>  \t *   <ref> must be a valid tree, everything after the '--' must be\n>  \t *   a path.\n>  \t *\n> +\t *   Except: with no paths, if <something> does not resolve as\n> +\t *   an object, no -t nor -b was given, and there is a tracking\n> +\t *   branch whose name is <something> in one and only one remote,\n> +\t *   then this is a short-hand to fork local <something> from\n> +\t *   that remote-tracking branch.\n> +\t *\n>  \t * case 2: git checkout -- [<paths>]\n>  \t *\n>  \t *   everything after the '--' must be paths.\n> @@ -808,13 +814,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>  \t\t\targ = \"@{-1}\";\n>  \n>  \t\tif (get_sha1_mb(arg, rev)) {\n> -\t\t\tif (has_dash_dash)          /* case (1) */\n> -\t\t\t\tdie(\"invalid reference: %s\", arg);\n>  \t\t\tif (!patch_mode &&\n>  \t\t\t    dwim_new_local_branch &&\n>  \t\t\t    opts.track == BRANCH_TRACK_UNSPECIFIED &&\n>  \t\t\t    !opts.new_branch &&\n> -\t\t\t    !check_filename(NULL, arg) &&\n> +\t\t\t    (has_dash_dash || !check_filename(NULL, arg)) &&\n>  \t\t\t    argc == 1) {\n>  \t\t\t\tconst char *remote = unique_tracking_name(arg);\n>  \t\t\t\tif (!remote || get_sha1(remote, rev))\n> @@ -822,9 +826,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>  \t\t\t\topts.new_branch = arg;\n>  \t\t\t\targ = remote;\n>  \t\t\t\t/* DWIMmed to create local branch */\n> -\t\t\t}\n> -\t\t\telse\n> +\t\t\t} else if (has_dash_dash) {\t/* case (1) */\n> +\t\t\t\tdie(\"invalid reference: %s\", arg);\n> +\t\t\t} else {\n>  \t\t\t\tgoto no_reference;\n> +\t\t\t}\n>  \t\t}\n>  \n>  \t\t/* we can't end up being in (2) anymore, eat the argument */\n"},{"id":"154817","messageId":"20101029235358.GA21410@burratino","threadId":"25595","inReplyTo":"7vsjzo691r.fsf@alter.siamese.dyndns.org","subject":"[PATCH v2] checkout: apply Dscho's dwim even with \"--\" present","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-29T23:53:58Z","receivedAt":"2010-10-29T23:53:58Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"git reset and similar commands use -- to disambiguate between\nrevisions and paths on the command line.  The same syntax is not\nnecessary to specify a revision to git checkout (for convenience\nand historical reasons, revisions are preferred over paths), but\nfor consistency it is accepted:\n\n\tgit checkout master --; # check out master branch, not \"master\" file.\n\nThe autovivification of branches introduced by 70c9ac2f1 (DWIM \"git\ncheckout frotz\" to \"git checkout -b frotz origin/frotz\", 2009-10-18)\nis currently disabled by that syntax, for no good reason.  Paranoid\nscripts can still use\n\n\tgit checkout --no-guess master\n\nor even better,\n\n\told=$(git rev-parse --verify HEAD)\n\tnew=$(git rev-parse --verify refs/heads/master^0)\n\tgit read-tree -m -u --exclude-standard $old $new\n\tgit symbolic-ref -m \"$me: switching branches\" HEAD refs/heads/master\n\nRequested-by: Dun Peal <dunpealer@gmail.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nJunio C Hamano wrote:\n\n> That looks simpler than what I just did.  Can we have a few tests, too?\n\nSure.  The tests are not too heavy, though (e.g., no \"ambiguous\nref\" stuff).\n\n>> -\t\t\t    !check_filename(NULL, arg) &&\n>> +\t\t\t    (has_dash_dash || !check_filename(NULL, arg)) &&\n>>  \t\t\t    argc == 1) {\n\nShould have been (argc == 2) in the has_dash_dash case.\n\n builtin/checkout.c            |   19 ++++++---\n t/t2010-checkout-ambiguous.sh |   83 +++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 96 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 9240faf..6c3de9f 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -771,6 +771,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t *   <ref> must be a valid tree, everything after the '--' must be\n \t *   a path.\n \t *\n+\t *   Except: with no paths, if <something> does not resolve as\n+\t *   an object, no -t nor -b was given, and there is a tracking\n+\t *   branch whose name is <something> in one and only one remote,\n+\t *   then this is a short-hand to fork local <something> from\n+\t *   that remote-tracking branch.\n+\t *\n \t * case 2: git checkout -- [<paths>]\n \t *\n \t *   everything after the '--' must be paths.\n@@ -808,23 +814,24 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\targ = \"@{-1}\";\n \n \t\tif (get_sha1_mb(arg, rev)) {\n-\t\t\tif (has_dash_dash)          /* case (1) */\n-\t\t\t\tdie(\"invalid reference: %s\", arg);\n+\t\t\ttrace_printf(\"trace: guess = %d\\n\", dwim_new_local_branch);\n \t\t\tif (!patch_mode &&\n \t\t\t    dwim_new_local_branch &&\n \t\t\t    opts.track == BRANCH_TRACK_UNSPECIFIED &&\n \t\t\t    !opts.new_branch &&\n-\t\t\t    !check_filename(NULL, arg) &&\n-\t\t\t    argc == 1) {\n+\t\t\t    (has_dash_dash || !check_filename(NULL, arg)) &&\n+\t\t\t    (argc == has_dash_dash ? 2 : 1)) {\n \t\t\t\tconst char *remote = unique_tracking_name(arg);\n \t\t\t\tif (!remote || get_sha1(remote, rev))\n \t\t\t\t\tgoto no_reference;\n \t\t\t\topts.new_branch = arg;\n \t\t\t\targ = remote;\n \t\t\t\t/* DWIMmed to create local branch */\n-\t\t\t}\n-\t\t\telse\n+\t\t\t} else if (has_dash_dash) {\t/* case (1) */\n+\t\t\t\tdie(\"invalid reference: %s\", arg);\n+\t\t\t} else {\n \t\t\t\tgoto no_reference;\n+\t\t\t}\n \t\t}\n \n \t\t/* we can't end up being in (2) anymore, eat the argument */\ndiff --git a/t/t2010-checkout-ambiguous.sh b/t/t2010-checkout-ambiguous.sh\nindex 7cc0a35..80ac7b5 100755\n--- a/t/t2010-checkout-ambiguous.sh\n+++ b/t/t2010-checkout-ambiguous.sh\n@@ -4,10 +4,25 @@ test_description='checkout and pathspecs/refspecs ambiguities'\n \n . ./test-lib.sh\n \n+test_branch_is () {\n+\techo \"refs/heads/$1\" >expect &&\n+\tgit symbolic-ref HEAD >actual &&\n+\ttest_cmp expect actual\n+}\n+\n test_expect_success 'setup' '\n+\tgit init upstream &&\n+\t(\n+\t\tcd upstream &&\n+\t\ttest_commit upstream-commit &&\n+\t\tgit branch -m upstream-topic\n+\t) &&\n+\tgit remote add upstream upstream &&\n+\tgit fetch upstream &&\n \techo hello >world &&\n \techo hello >all &&\n \tgit add all world &&\n+\ttest_tick &&\n \tgit commit -m initial &&\n \tgit branch world\n '\n@@ -32,6 +47,74 @@ test_expect_success 'non ambiguous call' '\n \tgit checkout all\n '\n \n+test_expect_success \"autovivification (Dscho's DWIM)\" '\n+\tgit checkout master &&\n+\ttest_might_fail git branch -D upstream-topic &&\n+\tgit checkout upstream-topic &&\n+\tgit diff --exit-code upstream-topic upstream/upstream-topic &&\n+\ttest_branch_is upstream-topic\n+'\n+\n+test_expect_success 'autovivification with --' '\n+\tgit checkout master &&\n+\ttest_might_fail git branch -D upstream-topic &&\n+\tgit checkout upstream-topic -- &&\n+\tgit diff --exit-code upstream-topic upstream/upstream-topic &&\n+\ttest_branch_is upstream-topic\n+'\n+\n+test_expect_success 'no autovivification after --' '\n+\tgit checkout master &&\n+\ttest_might_fail git branch -D upstream-topic &&\n+\ttest_must_fail git checkout -- upstream-topic &&\n+\ttest_branch_is master\n+'\n+\n+test_expect_success '--no-guess defeats autovivification' '\n+\tgit checkout master &&\n+\ttest_might_fail git branch -D upstream-topic &&\n+\ttest_must_fail git checkout --no-guess upstream-topic &&\n+\ttest_must_fail git checkout --no-guess upstream-topic -- &&\n+\ttest_branch_is master\n+'\n+\n+test_expect_success 'paths defeat autovivification' '\n+\tgit checkout master &&\n+\ttest_might_fail git branch -D upstream-topic &&\n+\ttest_must_fail git checkout upstream-topic -- . &&\n+\ttest_must_fail git checkout upstream-topic . &&\n+\ttest_branch_is master\n+'\n+\n+test_expect_success 'real branch defeats autovivification' '\n+\tgit checkout master &&\n+\tgit update-ref refs/heads/upstream-topic HEAD^0 &&\n+\tgit checkout upstream-topic &&\n+\ttest_must_fail git diff --exit-code upstream-topic upstream/upstream-topic &&\n+\ttest_branch_is upstream-topic\n+'\n+\n+test_expect_success '-t defeats autovivification' '\n+\tgit checkout master &&\n+\ttest_might_fail git branch -D upstream-topic &&\n+\ttest_must_fail git checkout -t upstream-topic &&\n+\ttest_branch_is master\n+'\n+\n+test_expect_success 'checkout of remote-tracking branch detaches HEAD' '\n+\tgit checkout master &&\n+\ttest_might_fail git branch -D upstream-topic &&\n+\tgit checkout upstream/upstream-topic &&\n+\ttest_must_fail git symbolic-ref HEAD\n+'\n+\n+test_expect_success 'checkout -t of remote-tracking branch does not detach HEAD' '\n+\tgit checkout master &&\n+\ttest_might_fail git branch -D upstream-topic &&\n+\tgit checkout -t upstream/upstream-topic &&\n+\ttest_branch_is upstream-topic\n+'\n+\n test_expect_success 'allow the most common case' '\n \tgit checkout world &&\n \ttest \"refs/heads/world\" = \"$(git symbolic-ref HEAD)\"\n"},{"id":"154818","messageId":"20101029235922.GB21410@burratino","threadId":"25595","inReplyTo":"20101029235358.GA21410@burratino","subject":"Re: [PATCH v2] checkout: apply Dscho's dwim even with \"--\" present","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-29T23:59:22Z","receivedAt":"2010-10-29T23:59:22Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jonathan Nieder wrote:\n\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> +\t\t\t    (argc == has_dash_dash ? 2 : 1)) {\n\nHmph --- this should read\n\n\t\t\t    (argc == (has_dash_dash ? 2 : 1)))\n\nfor correctness and sanity.\n"},{"id":"154820","messageId":"20101030004144.GA25927@burratino","threadId":"25595","inReplyTo":"20101029235358.GA21410@burratino","subject":"Re: [PATCH v2] checkout: apply Dscho's dwim even with \"--\" present","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-30T00:41:44Z","receivedAt":"2010-10-30T00:41:44Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jonathan Nieder wrote:\n\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -808,23 +814,24 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>  \t\t\targ = \"@{-1}\";\n>  \n>  \t\tif (get_sha1_mb(arg, rev)) {\n> +\t\t\ttrace_printf(\"trace: guess = %d\\n\", dwim_new_local_branch);\n\nGah!  This line does not belong, sorry (though presumably it wouldn't interfere\nwith testing).\n"},{"id":"154863","messageId":"7v8w1f3tgm.fsf@alter.siamese.dyndns.org","threadId":"25595","inReplyTo":"20101030004144.GA25927@burratino","subject":"Re: [PATCH v2] checkout: apply Dscho's dwim even with \"--\" present","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-10-31T03:57:13Z","receivedAt":"2010-10-31T03:57:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Jonathan Nieder wrote:\n>\n>> --- a/builtin/checkout.c\n>> +++ b/builtin/checkout.c\n>> @@ -808,23 +814,24 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>>  \t\t\targ = \"@{-1}\";\n>>  \n>>  \t\tif (get_sha1_mb(arg, rev)) {\n>> +\t\t\ttrace_printf(\"trace: guess = %d\\n\", dwim_new_local_branch);\n>\n> Gah!  This line does not belong, sorry (though presumably it wouldn't interfere\n> with testing).\n\nHeh, two Gah's in a row?  After all mine might have been simpler ;-)\n"}]}