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 <jaysoffian@xxxxxxxxx> --- 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? diff --git a/builtin-checkout.c b/builtin-checkout.c index d050c37..7f2e215 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -145,6 +145,38 @@ static void fill_mm(const unsigned char *sha1, mmfile_t *mm) mm->size = size; } +struct suggest_new_branch_name_data { + const char *name, *found; + int matches; +}; + +static int suggest_new_branch_name_compare(struct remote *remote, void *priv) +{ + struct suggest_new_branch_name_data *data = priv; + unsigned char sha1[20]; + struct strbuf buf = 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); + } + return 0; +} + +static void suggest_new_branch_name(const char *name) +{ + struct suggest_new_branch_name_data data; + 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)); +} + static int checkout_merged(int pos, struct checkout *state) { struct cache_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]); return 1; + } /* 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); + } goto no_reference; /* case (3 -> 2) */ } -- 1.6.4.2 -- 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