fetch-pack: eliminate spurious error messages
[gitweb.git] / builtin / push.c
index b6c0fee4c6058a3aadef659a3e98bc9e83fb6398..db9ba30b08c221ac2290b1ffc939713fe378e666 100644 (file)
@@ -11,7 +11,7 @@
 #include "submodule.h"
 
 static const char * const push_usage[] = {
-       "git push [<options>] [<repository> [<refspec>...]]",
+       N_("git push [<options>] [<repository> [<refspec>...]]"),
        NULL,
 };
 
@@ -24,6 +24,7 @@ static int progress = -1;
 static const char **refspec;
 static int refspec_nr;
 static int refspec_alloc;
+static int default_matching_used;
 
 static void add_refspec(const char *ref)
 {
@@ -75,7 +76,44 @@ static int push_url_of_remote(struct remote *remote, const char ***url_p)
        return remote->url_nr;
 }
 
-static void setup_push_upstream(struct remote *remote)
+static NORETURN int die_push_simple(struct branch *branch, struct remote *remote) {
+       /*
+        * There's no point in using shorten_unambiguous_ref here,
+        * as the ambiguity would be on the remote side, not what
+        * we have locally. Plus, this is supposed to be the simple
+        * mode. If the user is doing something crazy like setting
+        * upstream to a non-branch, we should probably be showing
+        * them the big ugly fully qualified ref.
+        */
+       const char *advice_maybe = "";
+       const char *short_upstream =
+               skip_prefix(branch->merge[0]->src, "refs/heads/");
+
+       if (!short_upstream)
+               short_upstream = branch->merge[0]->src;
+       /*
+        * Don't show advice for people who explicitely set
+        * push.default.
+        */
+       if (push_default == PUSH_DEFAULT_UNSPECIFIED)
+               advice_maybe = _("\n"
+                                "To choose either option permanently, "
+                                "see push.default in 'git help config'.");
+       die(_("The upstream branch of your current branch does not match\n"
+             "the name of your current branch.  To push to the upstream branch\n"
+             "on the remote, use\n"
+             "\n"
+             "    git push %s HEAD:%s\n"
+             "\n"
+             "To push to the branch of the same name on the remote, use\n"
+             "\n"
+             "    git push %s %s\n"
+             "%s"),
+           remote->name, short_upstream,
+           remote->name, branch->name, advice_maybe);
+}
+
+static void setup_push_upstream(struct remote *remote, int simple)
 {
        struct strbuf refspec = STRBUF_INIT;
        struct branch *branch = branch_get(NULL);
@@ -102,21 +140,55 @@ static void setup_push_upstream(struct remote *remote)
                      "your current branch '%s', without telling me what to push\n"
                      "to update which remote branch."),
                    remote->name, branch->name);
+       if (simple && strcmp(branch->refname, branch->merge[0]->src))
+               die_push_simple(branch, remote);
 
        strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
        add_refspec(refspec.buf);
 }
 
+static char warn_unspecified_push_default_msg[] =
+N_("push.default is unset; its implicit value is changing in\n"
+   "Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+   "and maintain the current behavior after the default changes, use:\n"
+   "\n"
+   "  git config --global push.default matching\n"
+   "\n"
+   "To squelch this message and adopt the new behavior now, use:\n"
+   "\n"
+   "  git config --global push.default simple\n"
+   "\n"
+   "See 'git help config' and search for 'push.default' for further information.\n"
+   "(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+   "'current' instead of 'simple' if you sometimes use older versions of Git)");
+
+static void warn_unspecified_push_default_configuration(void)
+{
+       static int warn_once;
+
+       if (warn_once++)
+               return;
+       warning("%s\n", _(warn_unspecified_push_default_msg));
+}
+
 static void setup_default_push_refspecs(struct remote *remote)
 {
        switch (push_default) {
        default:
+       case PUSH_DEFAULT_UNSPECIFIED:
+               default_matching_used = 1;
+               warn_unspecified_push_default_configuration();
+               /* fallthru */
        case PUSH_DEFAULT_MATCHING:
                add_refspec(":");
                break;
 
+       case PUSH_DEFAULT_SIMPLE:
+               setup_push_upstream(remote, 1);
+               break;
+
        case PUSH_DEFAULT_UPSTREAM:
-               setup_push_upstream(remote);
+               setup_push_upstream(remote, 0);
                break;
 
        case PUSH_DEFAULT_CURRENT:
@@ -130,6 +202,45 @@ static void setup_default_push_refspecs(struct remote *remote)
        }
 }
 
+static const char message_advice_pull_before_push[] =
+       N_("Updates were rejected because the tip of your current branch is behind\n"
+          "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
+          "before pushing again.\n"
+          "See the 'Note about fast-forwards' in 'git push --help' for details.");
+
+static const char message_advice_use_upstream[] =
+       N_("Updates were rejected because a pushed branch tip is behind its remote\n"
+          "counterpart. If you did not intend to push that branch, you may want to\n"
+          "specify branches to push or set the 'push.default' configuration variable\n"
+          "to 'simple', 'current' or 'upstream' to push only the current branch.");
+
+static const char message_advice_checkout_pull_push[] =
+       N_("Updates were rejected because a pushed branch tip is behind its remote\n"
+          "counterpart. Check out this branch and merge the remote changes\n"
+          "(e.g. 'git pull') before pushing again.\n"
+          "See the 'Note about fast-forwards' in 'git push --help' for details.");
+
+static void advise_pull_before_push(void)
+{
+       if (!advice_push_non_ff_current || !advice_push_nonfastforward)
+               return;
+       advise(_(message_advice_pull_before_push));
+}
+
+static void advise_use_upstream(void)
+{
+       if (!advice_push_non_ff_default || !advice_push_nonfastforward)
+               return;
+       advise(_(message_advice_use_upstream));
+}
+
+static void advise_checkout_pull_push(void)
+{
+       if (!advice_push_non_ff_matching || !advice_push_nonfastforward)
+               return;
+       advise(_(message_advice_checkout_pull_push));
+}
+
 static int push_with_options(struct transport *transport, int flags)
 {
        int err;
@@ -151,14 +262,21 @@ static int push_with_options(struct transport *transport, int flags)
                error(_("failed to push some refs to '%s'"), transport->url);
 
        err |= transport_disconnect(transport);
-
        if (!err)
                return 0;
 
-       if (nonfastforward && advice_push_nonfastforward) {
-               fprintf(stderr, _("To prevent you from losing history, non-fast-forward updates were rejected\n"
-                               "Merge the remote changes (e.g. 'git pull') before pushing again.  See the\n"
-                               "'Note about fast-forwards' section of 'git push --help' for details.\n"));
+       switch (nonfastforward) {
+       default:
+               break;
+       case NON_FF_HEAD:
+               advise_pull_before_push();
+               break;
+       case NON_FF_OTHER:
+               if (default_matching_used)
+                       advise_use_upstream();
+               else
+                       advise_checkout_pull_push();
+               break;
        }
 
        return 1;
@@ -234,13 +352,21 @@ static int option_parse_recurse_submodules(const struct option *opt,
                                   const char *arg, int unset)
 {
        int *flags = opt->value;
+
+       if (*flags & (TRANSPORT_RECURSE_SUBMODULES_CHECK |
+                     TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND))
+               die("%s can only be used once.", opt->long_name);
+
        if (arg) {
                if (!strcmp(arg, "check"))
                        *flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
+               else if (!strcmp(arg, "on-demand"))
+                       *flags |= TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND;
                else
                        die("bad %s argument: %s", opt->long_name, arg);
        } else
-               die("option %s needs an argument (check)", opt->long_name);
+               die("option %s needs an argument (check|on-demand)",
+                               opt->long_name);
 
        return 0;
 }
@@ -253,25 +379,25 @@ int cmd_push(int argc, const char **argv, const char *prefix)
        const char *repo = NULL;        /* default repository */
        struct option options[] = {
                OPT__VERBOSITY(&verbosity),
-               OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
-               OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
-               OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
+               OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
+               OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL),
+               OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"),
                            (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
-               OPT_BOOLEAN( 0, "delete", &deleterefs, "delete refs"),
-               OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror)"),
-               OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
-               OPT_BIT( 0,  "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
-               OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
-               { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check",
-                       "controls recursive pushing of submodules",
+               OPT_BOOLEAN( 0, "delete", &deleterefs, N_("delete refs")),
+               OPT_BOOLEAN( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+               OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
+               OPT_BIT( 0,  "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
+               OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
+               { OPTION_CALLBACK, 0, "recurse-submodules", &flags, N_("check"),
+                       N_("control recursive pushing of submodules"),
                        PARSE_OPT_OPTARG, option_parse_recurse_submodules },
-               OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
-               OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
-               OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
-               OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status",
+               OPT_BOOLEAN( 0 , "thin", &thin, N_("use thin pack")),
+               OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
+               OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")),
+               OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"),
                        TRANSPORT_PUSH_SET_UPSTREAM),
-               OPT_BOOL(0, "progress", &progress, "force progress reporting"),
-               OPT_BIT(0, "prune", &flags, "prune locally removed refs",
+               OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+               OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"),
                        TRANSPORT_PUSH_PRUNE),
                OPT_END()
        };