Re: Inconsistent behavior of the path disambiguator

3 messages, 3 authors, 2016-06-15 · open the first message on its own page

Re: Inconsistent behavior of the path disambiguator

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:49:56

Dun Peal [off-list ref] writes:
When I clone a remote that has a branch `foo`, then `git checkout foo
--`, the path disamgiuator makes the operation fail. `git checkout
foo` without the disambiguator works. Following that, when branch
`foo` already exists, `git checkout foo --` works even with the
disambiguator that caused it to fail previously.
I do not think there is any bug.  You were being bitten by folks who tried
to be helpful for newbies by introducing a(n arguably confusing) special
case; I can see why this is confusing, though.
$ git checkout foo --
fatal: invalid reference: foo
Immediately after a clone you would have

    refs/heads/master
    refs/HEAD -> refs/heads/master
    refs/remotes/origin/foo
    refs/remotes/origin/whatever-else-you-have
    ...

and there is no commit that you can name with "foo" when asking git to
check out some paths out of, nor there is no branch that you can name with
"foo" when asking git to check out to work on it.

You can say 'origin/foo', though, in general.
$ git checkout foo
Branch foo set up to track remote branch foo from origin.
Asking to check out a branch "foo" in order to work on extending the
history of that branch, when there is _no_ "foo", has a special magic
invented by some folks to "help usability", if there is only one $remote
that has "foo" in it.  In this case, you have refs/remotes/origin/foo but
no other refs/remotes/$frotz/foo, and this special magic kicks in.

git behaves as if you meant "git checkout -t -b foo origin/foo" but were
too lazy to type that yourself in this case.
Switched to a new branch 'foo'
$ git checkout master
Switched to branch 'master'
$ git checkout foo --
Switched to branch 'foo'
This is referring to local branch "foo", there is nothing magic.

Re: Inconsistent behavior of the path disambiguator

From: Dun Peal <hidden>
Date: 2016-06-15 22:49:56

On Fri, Oct 29, 2010 at 7:38 PM, Junio C Hamano [off-list ref] wrote:
I do not think there is any bug.  You were being bitten by folks who tried
to be helpful for newbies by introducing a(n arguably confusing) special
case; I can see why this is confusing, though.
Thanks.

We just switched to Git, and our developers got used to being able to
just `git checkout branch` to create a local remote-tracking one for
that remote branch.

Then we were bitten by a branch `foo` when path `./foo` existed.

I think the syntactic sugar needs to either be removed, or
(preferably) be made consistent.

The current behavior is that if I try to checkout a branch that
doesn't exist, but does exist on the remote, git creates a local
remote tracking branch for the one I tried to check out.

It makes no sense IMHO for the disambiguating syntax to break that
behavior, especially since in some cases, the disambiguating syntax is
necessary.

Thanks, D

Re: Inconsistent behavior of the path disambiguator

From: Jonathan Nieder <hidden>
Date: 2016-06-15 22:49:56

Junio C Hamano wrote:
      I can see why this is confusing, though.

Dun Peal [off-list ref] writes:
quoted
$ git checkout foo --
fatal: invalid reference: foo
Immediately after a clone you would have

    refs/heads/master
    refs/HEAD -> refs/heads/master
    refs/remotes/origin/foo
    refs/remotes/origin/whatever-else-you-have
    ...

and there is no commit that you can name with "foo" when asking git to
check out some paths out of, nor there is no branch that you can name with
"foo" when asking git to check out to work on it.
How about something like this?
-- 8< --
Subject: checkout: apply Dscho's dwim even with "--" present

git reset and similar commands use -- to disambiguate between
revisions and paths on the command line.  The same syntax is not
necessary to specify a revision to git checkout (for convenience
and historical reasons, revisions are preferred over paths), but
for consistency it is accepted:

	git checkout master --; # check out master branch, not "master" file.

The autovivification of branches introduced by 70c9ac2f1 (DWIM "git
checkout frotz" to "git checkout -b frotz origin/frotz", 2009-10-18)
is currently disabled by that syntax, for no good reason.  Paranoid
scripts can still use

	git checkout --no-guess master

or even better,

	old=$(git rev-parse --verify HEAD)
	new=$(git rev-parse --verify refs/heads/master^0)
	git read-tree -m -u --exclude-standard $old $new
	git symbolic-ref -m "$me: switching branches" HEAD refs/heads/master

Requested-by: Dun Peal [off-list ref]
Signed-off-by: Jonathan Nieder <redacted>
---
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 9240faf..1dc3640 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -771,6 +771,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	 *   <ref> must be a valid tree, everything after the '--' must be
 	 *   a path.
 	 *
+	 *   Except: with no paths, if <something> does not resolve as
+	 *   an object, no -t nor -b was given, and there is a tracking
+	 *   branch whose name is <something> in one and only one remote,
+	 *   then this is a short-hand to fork local <something> from
+	 *   that remote-tracking branch.
+	 *
 	 * case 2: git checkout -- [<paths>]
 	 *
 	 *   everything after the '--' must be paths.
@@ -808,13 +814,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 			arg = "@{-1}";
 
 		if (get_sha1_mb(arg, rev)) {
-			if (has_dash_dash)          /* case (1) */
-				die("invalid reference: %s", arg);
 			if (!patch_mode &&
 			    dwim_new_local_branch &&
 			    opts.track == BRANCH_TRACK_UNSPECIFIED &&
 			    !opts.new_branch &&
-			    !check_filename(NULL, arg) &&
+			    (has_dash_dash || !check_filename(NULL, arg)) &&
 			    argc == 1) {
 				const char *remote = unique_tracking_name(arg);
 				if (!remote || get_sha1(remote, rev))
@@ -822,9 +826,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 				opts.new_branch = arg;
 				arg = remote;
 				/* DWIMmed to create local branch */
-			}
-			else
+			} else if (has_dash_dash) {	/* case (1) */
+				die("invalid reference: %s", arg);
+			} else {
 				goto no_reference;
+			}
 		}
 
 		/* we can't end up being in (2) anymore, eat the argument */
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help