builtin-push.con commit Display warning for default git push with no push.default config (665d3e8)
   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] [--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 anythig",
  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
 121        if (!remote)
 122                die("bad repository '%s'", repo);
 123
 124        if (remote->mirror)
 125                flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
 126
 127        if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
 128                if (!strcmp(*refspec, "refs/tags/*"))
 129                        return error("--all and --tags are incompatible");
 130                return error("--all can't be combined with refspecs");
 131        }
 132
 133        if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
 134                if (!strcmp(*refspec, "refs/tags/*"))
 135                        return error("--mirror and --tags are incompatible");
 136                return error("--mirror can't be combined with refspecs");
 137        }
 138
 139        if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
 140                                (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
 141                return error("--all and --mirror are incompatible");
 142        }
 143
 144        if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
 145                if (remote->push_refspec_nr) {
 146                        refspec = remote->push_refspec;
 147                        refspec_nr = remote->push_refspec_nr;
 148                } else if (!(flags & TRANSPORT_PUSH_MIRROR))
 149                        setup_default_push_refspecs();
 150        }
 151        errs = 0;
 152        for (i = 0; i < remote->url_nr; i++) {
 153                struct transport *transport =
 154                        transport_get(remote, remote->url[i]);
 155                int err;
 156                if (receivepack)
 157                        transport_set_option(transport,
 158                                             TRANS_OPT_RECEIVEPACK, receivepack);
 159                if (thin)
 160                        transport_set_option(transport, TRANS_OPT_THIN, "yes");
 161
 162                if (flags & TRANSPORT_PUSH_VERBOSE)
 163                        fprintf(stderr, "Pushing to %s\n", remote->url[i]);
 164                err = transport_push(transport, refspec_nr, refspec, flags);
 165                err |= transport_disconnect(transport);
 166
 167                if (!err)
 168                        continue;
 169
 170                error("failed to push some refs to '%s'", remote->url[i]);
 171                errs++;
 172        }
 173        return !!errs;
 174}
 175
 176int cmd_push(int argc, const char **argv, const char *prefix)
 177{
 178        int flags = 0;
 179        int tags = 0;
 180        int rc;
 181        const char *repo = NULL;        /* default repository */
 182
 183        struct option options[] = {
 184                OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
 185                OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
 186                OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
 187                OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
 188                            (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
 189                OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
 190                OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
 191                OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
 192                OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 193                OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
 194                OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
 195                OPT_END()
 196        };
 197
 198        argc = parse_options(argc, argv, options, push_usage, 0);
 199
 200        if (tags)
 201                add_refspec("refs/tags/*");
 202
 203        if (argc > 0) {
 204                repo = argv[0];
 205                set_refspecs(argv + 1, argc - 1);
 206        }
 207
 208        rc = do_push(repo, flags);
 209        if (rc == -1)
 210                usage_with_options(push_usage, options);
 211        else
 212                return rc;
 213}