checkout: add advice for ambiguous "checkout <branch>"
[gitweb.git] / builtin / checkout.c
index 2e1d2376d24043a75adb9bbc69724591bcc2d5c3..baa027455ad74df72700b90893291ae4dc545254 100644 (file)
@@ -22,6 +22,7 @@
 #include "resolve-undo.h"
 #include "submodule-config.h"
 #include "submodule.h"
+#include "advice.h"
 
 static const char * const checkout_usage[] = {
        N_("git checkout [<options>] <branch>"),
@@ -878,7 +879,8 @@ static int parse_branchname_arg(int argc, const char **argv,
                                int dwim_new_local_branch_ok,
                                struct branch_info *new_branch_info,
                                struct checkout_opts *opts,
-                               struct object_id *rev)
+                               struct object_id *rev,
+                               int *dwim_remotes_matched)
 {
        struct tree **source_tree = &opts->source_tree;
        const char **new_branch = &opts->new_branch;
@@ -972,7 +974,8 @@ static int parse_branchname_arg(int argc, const char **argv,
                        recover_with_dwim = 0;
 
                if (recover_with_dwim) {
-                       const char *remote = unique_tracking_name(arg, rev);
+                       const char *remote = unique_tracking_name(arg, rev,
+                                                                 dwim_remotes_matched);
                        if (remote) {
                                *new_branch = arg;
                                arg = remote;
@@ -1109,6 +1112,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        struct branch_info new_branch_info;
        char *conflict_style = NULL;
        int dwim_new_local_branch = 1;
+       int dwim_remotes_matched = 0;
        struct option options[] = {
                OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
                OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -1219,7 +1223,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                        opts.track == BRANCH_TRACK_UNSPECIFIED &&
                        !opts.new_branch;
                int n = parse_branchname_arg(argc, argv, dwim_ok,
-                                            &new_branch_info, &opts, &rev);
+                                            &new_branch_info, &opts, &rev,
+                                            &dwim_remotes_matched);
                argv += n;
                argc -= n;
        }
@@ -1261,8 +1266,22 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        }
 
        UNLEAK(opts);
-       if (opts.patch_mode || opts.pathspec.nr)
-               return checkout_paths(&opts, new_branch_info.name);
-       else
+       if (opts.patch_mode || opts.pathspec.nr) {
+               int ret = checkout_paths(&opts, new_branch_info.name);
+               if (ret && dwim_remotes_matched > 1 &&
+                   advice_checkout_ambiguous_remote_branch_name)
+                       advise(_("'%s' matched more than one remote tracking branch.\n"
+                                "We found %d remotes with a reference that matched. So we fell back\n"
+                                "on trying to resolve the argument as a path, but failed there too!\n"
+                                "\n"
+                                "If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
+                                "you can do so by fully qualifying the name with the --track option:\n"
+                                "\n"
+                                "    git checkout --track origin/<name>"),
+                              argv[0],
+                              dwim_remotes_matched);
+               return ret;
+       } else {
                return checkout_branch(&opts, &new_branch_info);
+       }
 }