builtin-push.con commit Merge branch 'maint' (317efa6)
   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
  10static const char push_usage[] = "git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
  11
  12static int all, dry_run, force, thin, verbose;
  13static const char *receivepack;
  14
  15static const char **refspec;
  16static int refspec_nr;
  17
  18static void add_refspec(const char *ref)
  19{
  20        int nr = refspec_nr + 1;
  21        refspec = xrealloc(refspec, nr * sizeof(char *));
  22        refspec[nr-1] = ref;
  23        refspec_nr = nr;
  24}
  25
  26static void set_refspecs(const char **refs, int nr)
  27{
  28        int i;
  29        for (i = 0; i < nr; i++) {
  30                const char *ref = refs[i];
  31                if (!strcmp("tag", ref)) {
  32                        char *tag;
  33                        int len;
  34                        if (nr <= ++i)
  35                                die("tag shorthand without <tag>");
  36                        len = strlen(refs[i]) + 11;
  37                        tag = xmalloc(len);
  38                        strcpy(tag, "refs/tags/");
  39                        strcat(tag, refs[i]);
  40                        ref = tag;
  41                }
  42                add_refspec(ref);
  43        }
  44}
  45
  46static int do_push(const char *repo)
  47{
  48        int i, errs;
  49        int common_argc;
  50        const char **argv;
  51        int argc;
  52        struct remote *remote = remote_get(repo);
  53
  54        if (!remote)
  55                die("bad repository '%s'", repo);
  56
  57        if (remote->receivepack) {
  58                char *rp = xmalloc(strlen(remote->receivepack) + 16);
  59                sprintf(rp, "--receive-pack=%s", remote->receivepack);
  60                receivepack = rp;
  61        }
  62        if (!refspec && !all && remote->push_refspec_nr) {
  63                refspec = remote->push_refspec;
  64                refspec_nr = remote->push_refspec_nr;
  65        }
  66
  67        argv = xmalloc((refspec_nr + 10) * sizeof(char *));
  68        argv[0] = "dummy-send-pack";
  69        argc = 1;
  70        if (all)
  71                argv[argc++] = "--all";
  72        if (dry_run)
  73                argv[argc++] = "--dry-run";
  74        if (force)
  75                argv[argc++] = "--force";
  76        if (receivepack)
  77                argv[argc++] = receivepack;
  78        common_argc = argc;
  79
  80        errs = 0;
  81        for (i = 0; i < remote->uri_nr; i++) {
  82                int err;
  83                int dest_argc = common_argc;
  84                int dest_refspec_nr = refspec_nr;
  85                const char **dest_refspec = refspec;
  86                const char *dest = remote->uri[i];
  87                const char *sender = "send-pack";
  88                if (!prefixcmp(dest, "http://") ||
  89                    !prefixcmp(dest, "https://"))
  90                        sender = "http-push";
  91                else {
  92                        char *rem = xmalloc(strlen(remote->name) + 10);
  93                        sprintf(rem, "--remote=%s", remote->name);
  94                        argv[dest_argc++] = rem;
  95                        if (thin)
  96                                argv[dest_argc++] = "--thin";
  97                }
  98                argv[0] = sender;
  99                argv[dest_argc++] = dest;
 100                while (dest_refspec_nr--)
 101                        argv[dest_argc++] = *dest_refspec++;
 102                argv[dest_argc] = NULL;
 103                if (verbose)
 104                        fprintf(stderr, "Pushing to %s\n", dest);
 105                err = run_command_v_opt(argv, RUN_GIT_CMD);
 106                if (!err)
 107                        continue;
 108
 109                error("failed to push to '%s'", remote->uri[i]);
 110                switch (err) {
 111                case -ERR_RUN_COMMAND_FORK:
 112                        error("unable to fork for %s", sender);
 113                case -ERR_RUN_COMMAND_EXEC:
 114                        error("unable to exec %s", sender);
 115                        break;
 116                case -ERR_RUN_COMMAND_WAITPID:
 117                case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
 118                case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
 119                case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
 120                        error("%s died with strange error", sender);
 121                }
 122                errs++;
 123        }
 124        return !!errs;
 125}
 126
 127int cmd_push(int argc, const char **argv, const char *prefix)
 128{
 129        int i;
 130        const char *repo = NULL;        /* default repository */
 131
 132        for (i = 1; i < argc; i++) {
 133                const char *arg = argv[i];
 134
 135                if (arg[0] != '-') {
 136                        repo = arg;
 137                        i++;
 138                        break;
 139                }
 140                if (!strcmp(arg, "-v")) {
 141                        verbose=1;
 142                        continue;
 143                }
 144                if (!prefixcmp(arg, "--repo=")) {
 145                        repo = arg+7;
 146                        continue;
 147                }
 148                if (!strcmp(arg, "--all")) {
 149                        all = 1;
 150                        continue;
 151                }
 152                if (!strcmp(arg, "--dry-run")) {
 153                        dry_run = 1;
 154                        continue;
 155                }
 156                if (!strcmp(arg, "--tags")) {
 157                        add_refspec("refs/tags/*");
 158                        continue;
 159                }
 160                if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
 161                        force = 1;
 162                        continue;
 163                }
 164                if (!strcmp(arg, "--thin")) {
 165                        thin = 1;
 166                        continue;
 167                }
 168                if (!strcmp(arg, "--no-thin")) {
 169                        thin = 0;
 170                        continue;
 171                }
 172                if (!prefixcmp(arg, "--receive-pack=")) {
 173                        receivepack = arg;
 174                        continue;
 175                }
 176                if (!prefixcmp(arg, "--exec=")) {
 177                        receivepack = arg;
 178                        continue;
 179                }
 180                usage(push_usage);
 181        }
 182        set_refspecs(argv + i, argc - i);
 183        if (all && refspec)
 184                usage(push_usage);
 185
 186        return do_push(repo);
 187}