builtin / push.con commit remote-curl: retry failed requests for auth even with gzip (2e736fd)
   1/*
   2 * "git push"
   3 */
   4#include "cache.h"
   5#include "refs.h"
   6#include "run-command.h"
   7#include "builtin.h"
   8#include "remote.h"
   9#include "transport.h"
  10#include "parse-options.h"
  11#include "submodule.h"
  12
  13static const char * const push_usage[] = {
  14        "git push [<options>] [<repository> [<refspec>...]]",
  15        NULL,
  16};
  17
  18static int thin;
  19static int deleterefs;
  20static const char *receivepack;
  21static int verbosity;
  22static int progress = -1;
  23
  24static const char **refspec;
  25static int refspec_nr;
  26static int refspec_alloc;
  27static int default_matching_used;
  28
  29static void add_refspec(const char *ref)
  30{
  31        refspec_nr++;
  32        ALLOC_GROW(refspec, refspec_nr, refspec_alloc);
  33        refspec[refspec_nr-1] = ref;
  34}
  35
  36static void set_refspecs(const char **refs, int nr)
  37{
  38        int i;
  39        for (i = 0; i < nr; i++) {
  40                const char *ref = refs[i];
  41                if (!strcmp("tag", ref)) {
  42                        char *tag;
  43                        int len;
  44                        if (nr <= ++i)
  45                                die(_("tag shorthand without <tag>"));
  46                        len = strlen(refs[i]) + 11;
  47                        if (deleterefs) {
  48                                tag = xmalloc(len+1);
  49                                strcpy(tag, ":refs/tags/");
  50                        } else {
  51                                tag = xmalloc(len);
  52                                strcpy(tag, "refs/tags/");
  53                        }
  54                        strcat(tag, refs[i]);
  55                        ref = tag;
  56                } else if (deleterefs && !strchr(ref, ':')) {
  57                        char *delref;
  58                        int len = strlen(ref)+1;
  59                        delref = xmalloc(len+1);
  60                        strcpy(delref, ":");
  61                        strcat(delref, ref);
  62                        ref = delref;
  63                } else if (deleterefs)
  64                        die(_("--delete only accepts plain target ref names"));
  65                add_refspec(ref);
  66        }
  67}
  68
  69static int push_url_of_remote(struct remote *remote, const char ***url_p)
  70{
  71        if (remote->pushurl_nr) {
  72                *url_p = remote->pushurl;
  73                return remote->pushurl_nr;
  74        }
  75        *url_p = remote->url;
  76        return remote->url_nr;
  77}
  78
  79static void setup_push_upstream(struct remote *remote)
  80{
  81        struct strbuf refspec = STRBUF_INIT;
  82        struct branch *branch = branch_get(NULL);
  83        if (!branch)
  84                die(_("You are not currently on a branch.\n"
  85                    "To push the history leading to the current (detached HEAD)\n"
  86                    "state now, use\n"
  87                    "\n"
  88                    "    git push %s HEAD:<name-of-remote-branch>\n"),
  89                    remote->name);
  90        if (!branch->merge_nr || !branch->merge || !branch->remote_name)
  91                die(_("The current branch %s has no upstream branch.\n"
  92                    "To push the current branch and set the remote as upstream, use\n"
  93                    "\n"
  94                    "    git push --set-upstream %s %s\n"),
  95                    branch->name,
  96                    remote->name,
  97                    branch->name);
  98        if (branch->merge_nr != 1)
  99                die(_("The current branch %s has multiple upstream branches, "
 100                    "refusing to push."), branch->name);
 101        if (strcmp(branch->remote_name, remote->name))
 102                die(_("You are pushing to remote '%s', which is not the upstream of\n"
 103                      "your current branch '%s', without telling me what to push\n"
 104                      "to update which remote branch."),
 105                    remote->name, branch->name);
 106
 107        strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
 108        add_refspec(refspec.buf);
 109}
 110
 111static void setup_default_push_refspecs(struct remote *remote)
 112{
 113        switch (push_default) {
 114        default:
 115        case PUSH_DEFAULT_UNSPECIFIED:
 116                default_matching_used = 1;
 117                /* fallthru */
 118        case PUSH_DEFAULT_MATCHING:
 119                add_refspec(":");
 120                break;
 121
 122        case PUSH_DEFAULT_UPSTREAM:
 123                setup_push_upstream(remote);
 124                break;
 125
 126        case PUSH_DEFAULT_CURRENT:
 127                add_refspec("HEAD");
 128                break;
 129
 130        case PUSH_DEFAULT_NOTHING:
 131                die(_("You didn't specify any refspecs to push, and "
 132                    "push.default is \"nothing\"."));
 133                break;
 134        }
 135}
 136
 137static const char message_advice_pull_before_push[] =
 138        N_("Updates were rejected because the tip of your current branch is behind\n"
 139           "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n"
 140           "before pushing again.\n"
 141           "See the 'Note about fast-forwards' in 'git push --help' for details.");
 142
 143static const char message_advice_use_upstream[] =
 144        N_("Updates were rejected because a pushed branch tip is behind its remote\n"
 145           "counterpart. If you did not intend to push that branch, you may want to\n"
 146           "specify branches to push or set the 'push.default' configuration\n"
 147           "variable to 'current' or 'upstream' to push only the current branch.");
 148
 149static const char message_advice_checkout_pull_push[] =
 150        N_("Updates were rejected because a pushed branch tip is behind its remote\n"
 151           "counterpart. Check out this branch and merge the remote changes\n"
 152           "(e.g. 'git pull') before pushing again.\n"
 153           "See the 'Note about fast-forwards' in 'git push --help' for details.");
 154
 155static void advise_pull_before_push(void)
 156{
 157        if (!advice_push_non_ff_current || !advice_push_nonfastforward)
 158                return;
 159        advise(_(message_advice_pull_before_push));
 160}
 161
 162static void advise_use_upstream(void)
 163{
 164        if (!advice_push_non_ff_default || !advice_push_nonfastforward)
 165                return;
 166        advise(_(message_advice_use_upstream));
 167}
 168
 169static void advise_checkout_pull_push(void)
 170{
 171        if (!advice_push_non_ff_matching || !advice_push_nonfastforward)
 172                return;
 173        advise(_(message_advice_checkout_pull_push));
 174}
 175
 176static int push_with_options(struct transport *transport, int flags)
 177{
 178        int err;
 179        int nonfastforward;
 180
 181        transport_set_verbosity(transport, verbosity, progress);
 182
 183        if (receivepack)
 184                transport_set_option(transport,
 185                                     TRANS_OPT_RECEIVEPACK, receivepack);
 186        if (thin)
 187                transport_set_option(transport, TRANS_OPT_THIN, "yes");
 188
 189        if (verbosity > 0)
 190                fprintf(stderr, _("Pushing to %s\n"), transport->url);
 191        err = transport_push(transport, refspec_nr, refspec, flags,
 192                             &nonfastforward);
 193        if (err != 0)
 194                error(_("failed to push some refs to '%s'"), transport->url);
 195
 196        err |= transport_disconnect(transport);
 197        if (!err)
 198                return 0;
 199
 200        switch (nonfastforward) {
 201        default:
 202                break;
 203        case NON_FF_HEAD:
 204                advise_pull_before_push();
 205                break;
 206        case NON_FF_OTHER:
 207                if (default_matching_used)
 208                        advise_use_upstream();
 209                else
 210                        advise_checkout_pull_push();
 211                break;
 212        }
 213
 214        return 1;
 215}
 216
 217static int do_push(const char *repo, int flags)
 218{
 219        int i, errs;
 220        struct remote *remote = remote_get(repo);
 221        const char **url;
 222        int url_nr;
 223
 224        if (!remote) {
 225                if (repo)
 226                        die(_("bad repository '%s'"), repo);
 227                die(_("No configured push destination.\n"
 228                    "Either specify the URL from the command-line or configure a remote repository using\n"
 229                    "\n"
 230                    "    git remote add <name> <url>\n"
 231                    "\n"
 232                    "and then push using the remote name\n"
 233                    "\n"
 234                    "    git push <name>\n"));
 235        }
 236
 237        if (remote->mirror)
 238                flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
 239
 240        if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
 241                if (!strcmp(*refspec, "refs/tags/*"))
 242                        return error(_("--all and --tags are incompatible"));
 243                return error(_("--all can't be combined with refspecs"));
 244        }
 245
 246        if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
 247                if (!strcmp(*refspec, "refs/tags/*"))
 248                        return error(_("--mirror and --tags are incompatible"));
 249                return error(_("--mirror can't be combined with refspecs"));
 250        }
 251
 252        if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
 253                                (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
 254                return error(_("--all and --mirror are incompatible"));
 255        }
 256
 257        if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
 258                if (remote->push_refspec_nr) {
 259                        refspec = remote->push_refspec;
 260                        refspec_nr = remote->push_refspec_nr;
 261                } else if (!(flags & TRANSPORT_PUSH_MIRROR))
 262                        setup_default_push_refspecs(remote);
 263        }
 264        errs = 0;
 265        url_nr = push_url_of_remote(remote, &url);
 266        if (url_nr) {
 267                for (i = 0; i < url_nr; i++) {
 268                        struct transport *transport =
 269                                transport_get(remote, url[i]);
 270                        if (push_with_options(transport, flags))
 271                                errs++;
 272                }
 273        } else {
 274                struct transport *transport =
 275                        transport_get(remote, NULL);
 276
 277                if (push_with_options(transport, flags))
 278                        errs++;
 279        }
 280        return !!errs;
 281}
 282
 283static int option_parse_recurse_submodules(const struct option *opt,
 284                                   const char *arg, int unset)
 285{
 286        int *flags = opt->value;
 287        if (arg) {
 288                if (!strcmp(arg, "check"))
 289                        *flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
 290                else
 291                        die("bad %s argument: %s", opt->long_name, arg);
 292        } else
 293                die("option %s needs an argument (check)", opt->long_name);
 294
 295        return 0;
 296}
 297
 298int cmd_push(int argc, const char **argv, const char *prefix)
 299{
 300        int flags = 0;
 301        int tags = 0;
 302        int rc;
 303        const char *repo = NULL;        /* default repository */
 304        struct option options[] = {
 305                OPT__VERBOSITY(&verbosity),
 306                OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
 307                OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
 308                OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
 309                            (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
 310                OPT_BOOLEAN( 0, "delete", &deleterefs, "delete refs"),
 311                OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror)"),
 312                OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
 313                OPT_BIT( 0,  "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
 314                OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
 315                { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check",
 316                        "controls recursive pushing of submodules",
 317                        PARSE_OPT_OPTARG, option_parse_recurse_submodules },
 318                OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 319                OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
 320                OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
 321                OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status",
 322                        TRANSPORT_PUSH_SET_UPSTREAM),
 323                OPT_BOOL(0, "progress", &progress, "force progress reporting"),
 324                OPT_BIT(0, "prune", &flags, "prune locally removed refs",
 325                        TRANSPORT_PUSH_PRUNE),
 326                OPT_END()
 327        };
 328
 329        packet_trace_identity("push");
 330        git_config(git_default_config, NULL);
 331        argc = parse_options(argc, argv, prefix, options, push_usage, 0);
 332
 333        if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
 334                die(_("--delete is incompatible with --all, --mirror and --tags"));
 335        if (deleterefs && argc < 2)
 336                die(_("--delete doesn't make sense without any refs"));
 337
 338        if (tags)
 339                add_refspec("refs/tags/*");
 340
 341        if (argc > 0) {
 342                repo = argv[0];
 343                set_refspecs(argv + 1, argc - 1);
 344        }
 345
 346        rc = do_push(repo, flags);
 347        if (rc == -1)
 348                usage_with_options(push_usage, options);
 349        else
 350                return rc;
 351}