builtin-push.con commit verify-tag: migrate to parse-options (4855b2a)
   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
  12static const char * const push_usage[] = {
  13        "git push [--all | --mirror] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
  14        NULL,
  15};
  16
  17static int thin;
  18static const char *receivepack;
  19
  20static const char **refspec;
  21static int refspec_nr;
  22
  23static void add_refspec(const char *ref)
  24{
  25        int nr = refspec_nr + 1;
  26        refspec = xrealloc(refspec, nr * sizeof(char *));
  27        refspec[nr-1] = ref;
  28        refspec_nr = nr;
  29}
  30
  31static void set_refspecs(const char **refs, int nr)
  32{
  33        int i;
  34        for (i = 0; i < nr; i++) {
  35                const char *ref = refs[i];
  36                if (!strcmp("tag", ref)) {
  37                        char *tag;
  38                        int len;
  39                        if (nr <= ++i)
  40                                die("tag shorthand without <tag>");
  41                        len = strlen(refs[i]) + 11;
  42                        tag = xmalloc(len);
  43                        strcpy(tag, "refs/tags/");
  44                        strcat(tag, refs[i]);
  45                        ref = tag;
  46                }
  47                add_refspec(ref);
  48        }
  49}
  50
  51static void setup_push_tracking(void)
  52{
  53        struct strbuf refspec = STRBUF_INIT;
  54        struct branch *branch = branch_get(NULL);
  55        if (!branch)
  56                die("You are not currently on a branch.");
  57        if (!branch->merge_nr)
  58                die("The current branch %s is not tracking anything.",
  59                    branch->name);
  60        if (branch->merge_nr != 1)
  61                die("The current branch %s is tracking multiple branches, "
  62                    "refusing to push.", branch->name);
  63        strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
  64        add_refspec(refspec.buf);
  65}
  66
  67static const char *warn_unconfigured_push_msg[] = {
  68        "You did not specify any refspecs to push, and the current remote",
  69        "has not configured any push refspecs. The default action in this",
  70        "case is to push all matching refspecs, that is, all branches",
  71        "that exist both locally and remotely will be updated.  This may",
  72        "not necessarily be what you want to happen.",
  73        "",
  74        "You can specify what action you want to take in this case, and",
  75        "avoid seeing this message again, by configuring 'push.default' to:",
  76        "  'nothing'  : Do not push anything",
  77        "  'matching' : Push all matching branches (default)",
  78        "  'tracking' : Push the current branch to whatever it is tracking",
  79        "  'current'  : Push the current branch"
  80};
  81
  82static void warn_unconfigured_push(void)
  83{
  84        int i;
  85        for (i = 0; i < ARRAY_SIZE(warn_unconfigured_push_msg); i++)
  86                warning("%s", warn_unconfigured_push_msg[i]);
  87}
  88
  89static void setup_default_push_refspecs(void)
  90{
  91        git_config(git_default_config, NULL);
  92        switch (push_default) {
  93        case PUSH_DEFAULT_UNSPECIFIED:
  94                warn_unconfigured_push();
  95                /* fallthrough */
  96
  97        case PUSH_DEFAULT_MATCHING:
  98                add_refspec(":");
  99                break;
 100
 101        case PUSH_DEFAULT_TRACKING:
 102                setup_push_tracking();
 103                break;
 104
 105        case PUSH_DEFAULT_CURRENT:
 106                add_refspec("HEAD");
 107                break;
 108
 109        case PUSH_DEFAULT_NOTHING:
 110                die("You didn't specify any refspecs to push, and "
 111                    "push.default is \"nothing\".");
 112                break;
 113        }
 114}
 115
 116static int do_push(const char *repo, int flags)
 117{
 118        int i, errs;
 119        struct remote *remote = remote_get(repo);
 120        const char **url;
 121        int url_nr;
 122
 123        if (!remote) {
 124                if (repo)
 125                        die("bad repository '%s'", repo);
 126                die("No destination configured to push to.");
 127        }
 128
 129        if (remote->mirror)
 130                flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
 131
 132        if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
 133                if (!strcmp(*refspec, "refs/tags/*"))
 134                        return error("--all and --tags are incompatible");
 135                return error("--all can't be combined with refspecs");
 136        }
 137
 138        if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
 139                if (!strcmp(*refspec, "refs/tags/*"))
 140                        return error("--mirror and --tags are incompatible");
 141                return error("--mirror can't be combined with refspecs");
 142        }
 143
 144        if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
 145                                (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
 146                return error("--all and --mirror are incompatible");
 147        }
 148
 149        if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
 150                if (remote->push_refspec_nr) {
 151                        refspec = remote->push_refspec;
 152                        refspec_nr = remote->push_refspec_nr;
 153                } else if (!(flags & TRANSPORT_PUSH_MIRROR))
 154                        setup_default_push_refspecs();
 155        }
 156        errs = 0;
 157        if (remote->pushurl_nr) {
 158                url = remote->pushurl;
 159                url_nr = remote->pushurl_nr;
 160        } else {
 161                url = remote->url;
 162                url_nr = remote->url_nr;
 163        }
 164        for (i = 0; i < url_nr; i++) {
 165                struct transport *transport =
 166                        transport_get(remote, url[i]);
 167                int err;
 168                if (receivepack)
 169                        transport_set_option(transport,
 170                                             TRANS_OPT_RECEIVEPACK, receivepack);
 171                if (thin)
 172                        transport_set_option(transport, TRANS_OPT_THIN, "yes");
 173
 174                if (flags & TRANSPORT_PUSH_VERBOSE)
 175                        fprintf(stderr, "Pushing to %s\n", url[i]);
 176                err = transport_push(transport, refspec_nr, refspec, flags);
 177                err |= transport_disconnect(transport);
 178
 179                if (!err)
 180                        continue;
 181
 182                error("failed to push some refs to '%s'", url[i]);
 183                errs++;
 184        }
 185        return !!errs;
 186}
 187
 188int cmd_push(int argc, const char **argv, const char *prefix)
 189{
 190        int flags = 0;
 191        int tags = 0;
 192        int rc;
 193        const char *repo = NULL;        /* default repository */
 194
 195        struct option options[] = {
 196                OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
 197                OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
 198                OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
 199                OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
 200                            (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
 201                OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
 202                OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
 203                OPT_BIT( 0,  "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
 204                OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
 205                OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 206                OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
 207                OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
 208                OPT_END()
 209        };
 210
 211        argc = parse_options(argc, argv, prefix, options, push_usage, 0);
 212
 213        if (tags)
 214                add_refspec("refs/tags/*");
 215
 216        if (argc > 0) {
 217                repo = argv[0];
 218                set_refspecs(argv + 1, argc - 1);
 219        }
 220
 221        rc = do_push(repo, flags);
 222        if (rc == -1)
 223                usage_with_options(push_usage, options);
 224        else
 225                return rc;
 226}