6027ead5a9f60cf1986d0ad6aeb7dca9f776c9b5
   1#include "builtin.h"
   2#include "commit.h"
   3#include "refs.h"
   4#include "pkt-line.h"
   5#include "sideband.h"
   6#include "run-command.h"
   7#include "remote.h"
   8#include "connect.h"
   9#include "send-pack.h"
  10#include "quote.h"
  11#include "transport.h"
  12#include "version.h"
  13
  14static const char send_pack_usage[] =
  15"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
  16"  --all and explicit <ref> specification are mutually exclusive.";
  17
  18static struct send_pack_args args;
  19
  20static void print_helper_status(struct ref *ref)
  21{
  22        struct strbuf buf = STRBUF_INIT;
  23
  24        for (; ref; ref = ref->next) {
  25                const char *msg = NULL;
  26                const char *res;
  27
  28                switch(ref->status) {
  29                case REF_STATUS_NONE:
  30                        res = "error";
  31                        msg = "no match";
  32                        break;
  33
  34                case REF_STATUS_OK:
  35                        res = "ok";
  36                        break;
  37
  38                case REF_STATUS_UPTODATE:
  39                        res = "ok";
  40                        msg = "up to date";
  41                        break;
  42
  43                case REF_STATUS_REJECT_NONFASTFORWARD:
  44                        res = "error";
  45                        msg = "non-fast forward";
  46                        break;
  47
  48                case REF_STATUS_REJECT_FETCH_FIRST:
  49                        res = "error";
  50                        msg = "fetch first";
  51                        break;
  52
  53                case REF_STATUS_REJECT_NEEDS_FORCE:
  54                        res = "error";
  55                        msg = "needs force";
  56                        break;
  57
  58                case REF_STATUS_REJECT_ALREADY_EXISTS:
  59                        res = "error";
  60                        msg = "already exists";
  61                        break;
  62
  63                case REF_STATUS_REJECT_NODELETE:
  64                case REF_STATUS_REMOTE_REJECT:
  65                        res = "error";
  66                        break;
  67
  68                case REF_STATUS_EXPECTING_REPORT:
  69                default:
  70                        continue;
  71                }
  72
  73                strbuf_reset(&buf);
  74                strbuf_addf(&buf, "%s %s", res, ref->name);
  75                if (ref->remote_status)
  76                        msg = ref->remote_status;
  77                if (msg) {
  78                        strbuf_addch(&buf, ' ');
  79                        quote_two_c_style(&buf, "", msg, 0);
  80                }
  81                strbuf_addch(&buf, '\n');
  82
  83                write_or_die(1, buf.buf, buf.len);
  84        }
  85        strbuf_release(&buf);
  86}
  87
  88int cmd_send_pack(int argc, const char **argv, const char *prefix)
  89{
  90        int i, nr_refspecs = 0;
  91        const char **refspecs = NULL;
  92        const char *remote_name = NULL;
  93        struct remote *remote = NULL;
  94        const char *dest = NULL;
  95        int fd[2];
  96        struct child_process *conn;
  97        struct extra_have_objects extra_have;
  98        struct ref *remote_refs, *local_refs;
  99        int ret;
 100        int helper_status = 0;
 101        int send_all = 0;
 102        const char *receivepack = "git-receive-pack";
 103        int flags;
 104        unsigned int reject_reasons;
 105        int progress = -1;
 106        struct push_cas_option cas = {0};
 107
 108        argv++;
 109        for (i = 1; i < argc; i++, argv++) {
 110                const char *arg = *argv;
 111
 112                if (*arg == '-') {
 113                        if (!prefixcmp(arg, "--receive-pack=")) {
 114                                receivepack = arg + 15;
 115                                continue;
 116                        }
 117                        if (!prefixcmp(arg, "--exec=")) {
 118                                receivepack = arg + 7;
 119                                continue;
 120                        }
 121                        if (!prefixcmp(arg, "--remote=")) {
 122                                remote_name = arg + 9;
 123                                continue;
 124                        }
 125                        if (!strcmp(arg, "--all")) {
 126                                send_all = 1;
 127                                continue;
 128                        }
 129                        if (!strcmp(arg, "--dry-run")) {
 130                                args.dry_run = 1;
 131                                continue;
 132                        }
 133                        if (!strcmp(arg, "--mirror")) {
 134                                args.send_mirror = 1;
 135                                continue;
 136                        }
 137                        if (!strcmp(arg, "--force")) {
 138                                args.force_update = 1;
 139                                continue;
 140                        }
 141                        if (!strcmp(arg, "--quiet")) {
 142                                args.quiet = 1;
 143                                continue;
 144                        }
 145                        if (!strcmp(arg, "--verbose")) {
 146                                args.verbose = 1;
 147                                continue;
 148                        }
 149                        if (!strcmp(arg, "--progress")) {
 150                                progress = 1;
 151                                continue;
 152                        }
 153                        if (!strcmp(arg, "--no-progress")) {
 154                                progress = 0;
 155                                continue;
 156                        }
 157                        if (!strcmp(arg, "--thin")) {
 158                                args.use_thin_pack = 1;
 159                                continue;
 160                        }
 161                        if (!strcmp(arg, "--stateless-rpc")) {
 162                                args.stateless_rpc = 1;
 163                                continue;
 164                        }
 165                        if (!strcmp(arg, "--helper-status")) {
 166                                helper_status = 1;
 167                                continue;
 168                        }
 169                        if (!strcmp(arg, "--" CAS_OPT_NAME)) {
 170                                if (parse_push_cas_option(&cas, NULL, 0) < 0)
 171                                        exit(1);
 172                                continue;
 173                        }
 174                        if (!strcmp(arg, "--no-" CAS_OPT_NAME)) {
 175                                if (parse_push_cas_option(&cas, NULL, 1) < 0)
 176                                        exit(1);
 177                                continue;
 178                        }
 179                        if (!prefixcmp(arg, "--" CAS_OPT_NAME "=")) {
 180                                if (parse_push_cas_option(&cas,
 181                                                          strchr(arg, '=') + 1, 1) < 0)
 182                                        exit(1);
 183                                continue;
 184                        }
 185                        usage(send_pack_usage);
 186                }
 187                if (!dest) {
 188                        dest = arg;
 189                        continue;
 190                }
 191                refspecs = (const char **) argv;
 192                nr_refspecs = argc - i;
 193                break;
 194        }
 195        if (!dest)
 196                usage(send_pack_usage);
 197        /*
 198         * --all and --mirror are incompatible; neither makes sense
 199         * with any refspecs.
 200         */
 201        if ((refspecs && (send_all || args.send_mirror)) ||
 202            (send_all && args.send_mirror))
 203                usage(send_pack_usage);
 204
 205        if (remote_name) {
 206                remote = remote_get(remote_name);
 207                if (!remote_has_url(remote, dest)) {
 208                        die("Destination %s is not a uri for %s",
 209                            dest, remote_name);
 210                }
 211        }
 212
 213        if (progress == -1)
 214                progress = !args.quiet && isatty(2);
 215        args.progress = progress;
 216
 217        if (args.stateless_rpc) {
 218                conn = NULL;
 219                fd[0] = 0;
 220                fd[1] = 1;
 221        } else {
 222                conn = git_connect(fd, dest, receivepack,
 223                        args.verbose ? CONNECT_VERBOSE : 0);
 224        }
 225
 226        memset(&extra_have, 0, sizeof(extra_have));
 227
 228        get_remote_heads(fd[0], NULL, 0, &remote_refs, REF_NORMAL, &extra_have);
 229
 230        transport_verify_remote_names(nr_refspecs, refspecs);
 231
 232        local_refs = get_local_heads();
 233
 234        flags = MATCH_REFS_NONE;
 235
 236        if (send_all)
 237                flags |= MATCH_REFS_ALL;
 238        if (args.send_mirror)
 239                flags |= MATCH_REFS_MIRROR;
 240
 241        /* match them up */
 242        if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
 243                return -1;
 244
 245        if (!is_empty_cas(&cas))
 246                apply_push_cas(&cas, remote, remote_refs);
 247
 248        set_ref_status_for_push(remote_refs, args.send_mirror,
 249                args.force_update);
 250
 251        ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
 252
 253        if (helper_status)
 254                print_helper_status(remote_refs);
 255
 256        close(fd[1]);
 257        close(fd[0]);
 258
 259        ret |= finish_connect(conn);
 260
 261        if (!helper_status)
 262                transport_print_push_status(dest, remote_refs, args.verbose, 0, &reject_reasons);
 263
 264        if (!args.dry_run && remote) {
 265                struct ref *ref;
 266                for (ref = remote_refs; ref; ref = ref->next)
 267                        transport_update_tracking_ref(remote, ref, args.verbose);
 268        }
 269
 270        if (!ret && !transport_refs_pushed(remote_refs))
 271                fprintf(stderr, "Everything up-to-date\n");
 272
 273        return ret;
 274}