From: Jay Soffian <hidden> Date: 2016-06-15 22:47:29
A user who has just cloned a remote repository and wishes to then work on a
branch other than master may not realize they first need to create the local
branch. e.g.:
$ git clone git://git.kernel.org/pub/scm/git/git.git
$ cd git
$ git checkout next
error: pathspec 'next' did not match any file(s) known to git.
This commit teaches git to make a suggestion to the user:
$ git clone git://git.kernel.org/pub/scm/git/git.git
$ cd git
$ git checkout next
error: pathspec 'next' did not match any file(s) known to git.
To create a local branch from the same named remote branch, use
git checkout -b next origin/next
Motivated by http://article.gmane.org/gmane.comp.version-control.git/129528
Signed-off-by: Jay Soffian <redacted>
---
builtin-checkout.c | 43 +++++++++++++++++++++++++++++++++++++++++--
1 files changed, 41 insertions(+), 2 deletions(-)
I dunno, this seems like a lot of code just to make a suggestion to the
user. Is it worth it?
Also, I initially was going to use for_each_remote_ref and compare every
remote ref name to see if it tail matched what the user gave us, but it was
easier to use for_each_remote and build up the remote ref name and then check
for its existence. Not sure if either approach is preferable.
Thoughts/comments?
@@ -145,6 +145,38 @@ static void fill_mm(const unsigned char *sha1, mmfile_t *mm)mm->size=size;}+structsuggest_new_branch_name_data{+constchar*name,*found;+intmatches;+};++staticintsuggest_new_branch_name_compare(structremote*remote,void*priv)+{+structsuggest_new_branch_name_data*data=priv;+unsignedcharsha1[20];+structstrbufbuf=STRBUF_INIT;+strbuf_addf(&buf,"refs/remotes/%s/%s",remote->name,data->name);+if(resolve_ref(buf.buf,sha1,1,NULL)){+data->matches++;+if(data->found)+strbuf_release(&buf);+else+data->found=strbuf_detach(&buf,NULL);+}+return0;+}++staticvoidsuggest_new_branch_name(constchar*name)+{+structsuggest_new_branch_name_datadata;+data.name=name;+data.found=NULL;+data.matches=0;+for_each_remote(suggest_new_branch_name_compare,&data);+if(data.matches==1)+fprintf(stderr,"To create a local branch from the same named remote branch, use\n git checkout -b %s %s\n",name,prettify_refname(data.found));+}+staticintcheckout_merged(intpos,structcheckout*state){structcache_entry*ce=active_cache[pos];
@@ -231,8 +263,13 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,match_pathspec(pathspec,ce->name,ce_namelen(ce),0,ps_matched);}-if(report_path_error(ps_matched,pathspec,0))+if(report_path_error(ps_matched,pathspec,0)){+for(pos=0;pathspec[pos];pos++)+;+if(pos==1)+suggest_new_branch_name(pathspec[0]);return1;+}/* Any unmerged paths? */for(pos=0;pos<active_nr;pos++){
@@ -675,8 +712,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)arg="@{-1}";if(get_sha1(arg,rev)){-if(has_dash_dash)/* case (1) */+if(has_dash_dash){/* case (1) */+suggest_new_branch_name(arg);die("invalid reference: %s",arg);+}gotono_reference;/* case (3 -> 2) */}
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:47:29
Hi,
On Mon, 5 Oct 2009, Jay Soffian wrote:
A user who has just cloned a remote repository and wishes to then work on a
branch other than master may not realize they first need to create the local
branch. e.g.:
$ git clone git://git.kernel.org/pub/scm/git/git.git
$ cd git
$ git checkout next
error: pathspec 'next' did not match any file(s) known to git.
This commit teaches git to make a suggestion to the user:
$ git clone git://git.kernel.org/pub/scm/git/git.git
$ cd git
$ git checkout next
error: pathspec 'next' did not match any file(s) known to git.
To create a local branch from the same named remote branch, use
git checkout -b next origin/next
Motivated by http://article.gmane.org/gmane.comp.version-control.git/129528
Actually, we should really think long and hard why we should not
automatically check out the local branch "next" in that case. I mean,
really long and hard, and making sure to take user-friendliness into
account at least as much as simplicity of implementation.
Ciao,
Dscho
Heya,
On Mon, Oct 5, 2009 at 23:17, Johannes Schindelin
[off-list ref] wrote:
Actually, we should really think long and hard why we should not
automatically check out the local branch "next" in that case. I mean,
really long and hard, and making sure to take user-friendliness into
account at least as much as simplicity of implementation.
If git was a little more interactive I'd say prompt the user, problem solved?
$ git checkout next
No such branch 'next', do you want to check out a local branch for
'origin/next' instead? [Y/n]
@jay: you assume that if there is more than one matching remote the
user is experienced (as they have multiple remotes) enough to know
what to do?
--
Cheers,
Sverre Rabbelier
From: Jay Soffian <hidden> Date: 2016-06-15 22:47:29
On Mon, Oct 5, 2009 at 5:17 PM, Johannes Schindelin
[off-list ref] wrote:
Actually, we should really think long and hard why we should not
automatically check out the local branch "next" in that case. I mean,
really long and hard, and making sure to take user-friendliness into
account at least as much as simplicity of implementation.
Sure, why not? Are you asking for a patch, or just soliciting conversation?
j.
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:47:29
Hi,
On Mon, 5 Oct 2009, Jay Soffian wrote:
On Mon, Oct 5, 2009 at 5:17 PM, Johannes Schindelin
[off-list ref] wrote:
quoted
Actually, we should really think long and hard why we should not
automatically check out the local branch "next" in that case. I mean,
really long and hard, and making sure to take user-friendliness into
account at least as much as simplicity of implementation.
Sure, why not? Are you asking for a patch, or just soliciting
conversation?
I am asking for thoughtful arguments for and against my (shyly implied)
proposal.
Ciao,
Dscho
From: Jeff King <hidden> Date: 2016-06-15 22:47:29
On Mon, Oct 05, 2009 at 11:17:09PM +0200, Johannes Schindelin wrote:
quoted
$ git clone git://git.kernel.org/pub/scm/git/git.git
$ cd git
$ git checkout next
error: pathspec 'next' did not match any file(s) known to git.
To create a local branch from the same named remote branch, use
git checkout -b next origin/next
Motivated by http://article.gmane.org/gmane.comp.version-control.git/129528
Actually, we should really think long and hard why we should not
automatically check out the local branch "next" in that case. I mean,
really long and hard, and making sure to take user-friendliness into
account at least as much as simplicity of implementation.
Some devil's advocate questions:
1. How do we find "origin/next" given "next"? What are the exact
lookup rules? Do they cover every case? Do they avoid surprising
the user?
2. What do we do if our lookup is ambiguous (e.g., "origin/next" and
"foobar/next" both exist)?
3. If our lookup does have ambiguities or corner cases, is it better
to simply be suggesting to the user, rather than proceeding with an
action?
-Peff
This assumes that remote X always has its tracking branches in
refs/remotes/X/*. But that is really dependent on how the fetch refspec
is set up. True, it will be like that for remotes set up by "git remote"
or "git clone", but it isn't universal (and we have tried not to make
that assumption elsewhere, like when finding upstream branches to merge
from). Doing it right would mean interpreting the refspecs in
remote.*.fetch.
But this is not necessarily about actual remotes, I don't think. It is
really about the names of refs we have, and that you could reference,
but that are not actual tracking branches. It's just that refs/remotes
is the obvious hierarchy there.
But I wonder if what you should do instead is to iterate through each
ref, removing refs/heads/* and refs/tags/* (which are uninteresting, as
they are already part of the normal ref lookup), and then suffix-match.
So looking for "next" would find "refs/remotes/origin/next", or even
"refs/foobar/next" if you had some "foobar" hierarchy.
It would also match "foo" to "refs/remotes/origin/jk/foo". I'm not sure
if that is a feature or a bug, though.
Aside from that, I can't think of anything wrong with the idea.
Personally I find it more chatty than I would want, because I know what
I'm doing. So I would suggest adding an advice.suggestBranchName config
option to voluntarily suppress it.
-Peff
From: Thomas Rast <hidden> Date: 2016-06-15 22:47:29
Jeff King wrote:
On Mon, Oct 05, 2009 at 11:17:09PM +0200, Johannes Schindelin wrote:
quoted
quoted
$ git checkout next
error: pathspec 'next' did not match any file(s) known to git.
Actually, we should really think long and hard why we should not
automatically check out the local branch "next" in that case. I mean,
really long and hard, and making sure to take user-friendliness into
account at least as much as simplicity of implementation.
Some devil's advocate questions:
1. How do we find "origin/next" given "next"? What are the exact
lookup rules? Do they cover every case? Do they avoid surprising
the user?
2. What do we do if our lookup is ambiguous (e.g., "origin/next" and
"foobar/next" both exist)?
3. If our lookup does have ambiguities or corner cases, is it better
to simply be suggesting to the user, rather than proceeding with an
action?
If I may add another:
4. Are there any (scripted?) use-cases where git-checkout should fail
because it was given an invalid branch name?
The following gives a hint, though they could of course be fixed and
the ^0 case doesn't really count:
$ git grep 'git checkout .*||' -- "*.sh"
git-bisect.sh: git checkout "$start_head" -- || exit
git-rebase--interactive.sh: output git checkout $first_parent 2> /dev/null ||
git-rebase--interactive.sh: output git checkout "$1" ||
git-rebase.sh:git checkout -q "$onto^0" || die "could not detach HEAD"
t/t2007-checkout-symlink.sh:git checkout -f master || exit
--
Thomas Rast
trast@{inf,student}.ethz.ch
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:47:29
Hi,
On Mon, 5 Oct 2009, Jeff King wrote:
On Mon, Oct 05, 2009 at 11:17:09PM +0200, Johannes Schindelin wrote:
quoted
quoted
$ git clone git://git.kernel.org/pub/scm/git/git.git
$ cd git
$ git checkout next
error: pathspec 'next' did not match any file(s) known to git.
To create a local branch from the same named remote branch, use
git checkout -b next origin/next
Motivated by http://article.gmane.org/gmane.comp.version-control.git/129528
Actually, we should really think long and hard why we should not
automatically check out the local branch "next" in that case. I mean,
really long and hard, and making sure to take user-friendliness into
account at least as much as simplicity of implementation.
Some devil's advocate questions:
1. How do we find "origin/next" given "next"? What are the exact
lookup rules? Do they cover every case? Do they avoid surprising
the user?
I am sure your strategy would be the same as mine: enumerate all remote
branches, strip the remote nickname, and compare. If there are
ambiguities, tell the user and stop.
2. What do we do if our lookup is ambiguous (e.g., "origin/next" and
"foobar/next" both exist)?
See above.
3. If our lookup does have ambiguities or corner cases, is it better
to simply be suggesting to the user, rather than proceeding with an
action?
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:47:29
Hi,
On Tue, 6 Oct 2009, Thomas Rast wrote:
Jeff King wrote:
quoted
On Mon, Oct 05, 2009 at 11:17:09PM +0200, Johannes Schindelin wrote:
quoted
quoted
$ git checkout next
error: pathspec 'next' did not match any file(s) known to git.
Actually, we should really think long and hard why we should not
automatically check out the local branch "next" in that case. I mean,
really long and hard, and making sure to take user-friendliness into
account at least as much as simplicity of implementation.
Some devil's advocate questions:
1. How do we find "origin/next" given "next"? What are the exact
lookup rules? Do they cover every case? Do they avoid surprising
the user?
2. What do we do if our lookup is ambiguous (e.g., "origin/next" and
"foobar/next" both exist)?
3. If our lookup does have ambiguities or corner cases, is it better
to simply be suggesting to the user, rather than proceeding with an
action?
If I may add another:
4. Are there any (scripted?) use-cases where git-checkout should fail
because it was given an invalid branch name?
The following gives a hint, though they could of course be fixed and
the ^0 case doesn't really count:
$ git grep 'git checkout .*||' -- "*.sh"
git-bisect.sh: git checkout "$start_head" -- || exit
git-rebase--interactive.sh: output git checkout $first_parent 2> /dev/null ||
git-rebase--interactive.sh: output git checkout "$1" ||
git-rebase.sh:git checkout -q "$onto^0" || die "could not detach HEAD"
t/t2007-checkout-symlink.sh:git checkout -f master || exit
Actually, in said cases (with exception of the test case, which should be
fine, however, having no remote branches), I would expect the user to be
grateful if the DWIMery would happen.
I have to clarify something here: I am not proposing to include a patch
that does that DWIMery. We need to discuss the downsides and upsides
until we can be pretty certain that it does more good than harm.
Unfortunately, this list does not seem to be very inviting to pure users,
who I hoped would chime in on this issue.
Ciao,
Dscho
From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:29
Johannes Schindelin [off-list ref] writes:
quoted
4. Are there any (scripted?) use-cases where git-checkout should fail
because it was given an invalid branch name?
The following gives a hint, though they could of course be fixed and
the ^0 case doesn't really count:
$ git grep 'git checkout .*||' -- "*.sh"
git-bisect.sh: git checkout "$start_head" -- || exit
git-rebase--interactive.sh: output git checkout $first_parent 2> /dev/null ||
git-rebase--interactive.sh: output git checkout "$1" ||
git-rebase.sh:git checkout -q "$onto^0" || die "could not detach HEAD"
t/t2007-checkout-symlink.sh:git checkout -f master || exit
Actually, in said cases (with exception of the test case, which should be
fine, however, having no remote branches), I would expect the user to be
grateful if the DWIMery would happen.
Did you check the context before making that assertion?
- The one in git-bisect switches to (or detaches at) what was earlier
written in BISECT_START, which is either a branch name or a commit
object name, so the user definitely does not want DWIMery if it could
check out something else --- I do not think DWIMery hurts as long as
the user does not delete the original branch while bisecting, though.
- The first one in "rebase -i" is always fed a commit object name;
DWIMery is not needed (and it would not hurt).
- The second one in "rebase -i" is about switching to the branch being
rebased, and it has an explicit check to see if "$1" is a branch name;
DWIMery is not needed (and it would not hurt because of the check
before it).
- The one in "rebase" proper, as Thomas pointed out, is an explicit
request to detach, so DWIMery won't happen.
The first three cases that could trigger DWIMery fall into "DWIMery does
not hurt because it happens to be a no-op in the way it is used" category,
not "In this case, the users would actively appreciate DWIMery". IOW,
this does not look particularly a good argument to support DWIMery to me.
About the second one in "rebase -i", and also the corresponding one in
"rebase", which is:
test -z "$switch_to" || git checkout "$switch_to"
If the command did DWIM, you would fork a local branch from the remote and
immediately rebase it. Any good git tutorial teaches not to rebase work
by others, and keeping the result of such a rebase on a local branch goes
directly against it [*1*]; the script needs to be updated to protect
itself from DWIMery if we were to change "checkout" in these cases.
[Footnote]
*1* It is quite useful to temporarily rebase others work, e.g. in order to
compare what got changed in the newer version of series, so I wouldn't
object if the user did
git checkout origin/topic
git rebase $(git merge-base origin/topic@{1} origin/topic)
git show-branch origin/topic@{1} HEAD
but notice that it all happens on detached HEAD, not to be kept.
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:47:29
Hi,
On Tue, 6 Oct 2009, Junio C Hamano wrote:
Johannes Schindelin [off-list ref] writes:
quoted
quoted
4. Are there any (scripted?) use-cases where git-checkout should fail
because it was given an invalid branch name?
The following gives a hint, though they could of course be fixed and
the ^0 case doesn't really count:
$ git grep 'git checkout .*||' -- "*.sh"
git-bisect.sh: git checkout "$start_head" -- || exit
git-rebase--interactive.sh: output git checkout $first_parent 2> /dev/null ||
git-rebase--interactive.sh: output git checkout "$1" ||
git-rebase.sh:git checkout -q "$onto^0" || die "could not detach HEAD"
t/t2007-checkout-symlink.sh:git checkout -f master || exit
Actually, in said cases (with exception of the test case, which should be
fine, however, having no remote branches), I would expect the user to be
grateful if the DWIMery would happen.
Did you check the context before making that assertion?
No, but I checked the _names_ of the scripts.
In case of bisect, if I know upstream is good, I might indeed say "git
bisect good next", even if I haven't checked myself earlier.
In case of "rebase", about the same happens: if I say "git rebase next",
and there is no "next", but an "origin/next", and no other remote branch
"*/next", it is pretty clear what I mean, too.
In any case, it seems pretty clear to me that this DWIMery, while I am
pretty certain would be useful for actual users without commits in
git.git, will not make it into git.git.
So I'll stop wasting my time with this discussion.
Ciao,
Dscho
From: Junio C Hamano <hidden> Date: 2016-06-15 22:47:34
Johannes Schindelin [off-list ref] writes:
Actually, we should really think long and hard why we should not
automatically check out the local branch "next" in that case.
While people were thinking long and hard, I've spent some quality time
having fun with these patches, and realized that if we limit the scope of
the change to make sure that we only change the behaviour of a case where
we refused to do anything, this is not even something we need to think
long nor hard after all.
At least from the maintainer's point of view, that is.
I on the other hand do agree that we need to think long and hard when it
comes to the matter of explaining this to the users, though. I couldn't
come up with a good (re-)ordering of the documentation to fit this new
"short-cut" into the manpage.
A three-patch series will follow shortly.