3b66185401adf2d7b5a1b40cb1b7ada0ee73396e
   1#include "cache.h"
   2#include "commit.h"
   3#include "refs.h"
   4#include "pkt-line.h"
   5
   6static const char send_pack_usage[] =
   7"git-send-pack [--all] [--exec=git-receive-pack] <remote> [<head>...]\n"
   8"  --all and explicit <head> specification are mutually exclusive.";
   9static const char *exec = "git-receive-pack";
  10static int send_all = 0;
  11static int force_update = 0;
  12
  13static int is_zero_sha1(const unsigned char *sha1)
  14{
  15        int i;
  16
  17        for (i = 0; i < 20; i++) {
  18                if (*sha1++)
  19                        return 0;
  20        }
  21        return 1;
  22}
  23
  24static void exec_pack_objects(void)
  25{
  26        static char *args[] = {
  27                "git-pack-objects",
  28                "--stdout",
  29                NULL
  30        };
  31        execvp("git-pack-objects", args);
  32        die("git-pack-objects exec failed (%s)", strerror(errno));
  33}
  34
  35static void exec_rev_list(struct ref *refs)
  36{
  37        static char *args[1000];
  38        int i = 0;
  39
  40        args[i++] = "git-rev-list";     /* 0 */
  41        args[i++] = "--objects";        /* 1 */
  42        while (refs) {
  43                char *buf = malloc(100);
  44                if (i > 900)
  45                        die("git-rev-list environment overflow");
  46                if (!is_zero_sha1(refs->old_sha1) &&
  47                    has_sha1_file(refs->old_sha1)) {
  48                        args[i++] = buf;
  49                        snprintf(buf, 50, "^%s", sha1_to_hex(refs->old_sha1));
  50                        buf += 50;
  51                }
  52                if (!is_zero_sha1(refs->new_sha1)) {
  53                        args[i++] = buf;
  54                        snprintf(buf, 50, "%s", sha1_to_hex(refs->new_sha1));
  55                }
  56                refs = refs->next;
  57        }
  58        args[i] = NULL;
  59        execvp("git-rev-list", args);
  60        die("git-rev-list exec failed (%s)", strerror(errno));
  61}
  62
  63static void rev_list(int fd, struct ref *refs)
  64{
  65        int pipe_fd[2];
  66        pid_t pack_objects_pid;
  67
  68        if (pipe(pipe_fd) < 0)
  69                die("rev-list setup: pipe failed");
  70        pack_objects_pid = fork();
  71        if (!pack_objects_pid) {
  72                dup2(pipe_fd[0], 0);
  73                dup2(fd, 1);
  74                close(pipe_fd[0]);
  75                close(pipe_fd[1]);
  76                close(fd);
  77                exec_pack_objects();
  78                die("pack-objects setup failed");
  79        }
  80        if (pack_objects_pid < 0)
  81                die("pack-objects fork failed");
  82        dup2(pipe_fd[1], 1);
  83        close(pipe_fd[0]);
  84        close(pipe_fd[1]);
  85        close(fd);
  86        exec_rev_list(refs);
  87}
  88
  89static int pack_objects(int fd, struct ref *refs)
  90{
  91        pid_t rev_list_pid;
  92
  93        rev_list_pid = fork();
  94        if (!rev_list_pid) {
  95                rev_list(fd, refs);
  96                die("rev-list setup failed");
  97        }
  98        if (rev_list_pid < 0)
  99                die("rev-list fork failed");
 100        /*
 101         * We don't wait for the rev-list pipeline in the parent:
 102         * we end up waiting for the other end instead
 103         */
 104        return 0;
 105}
 106
 107static int read_ref(const char *ref, unsigned char *sha1)
 108{
 109        int fd, ret;
 110        char buffer[60];
 111
 112        fd = open(git_path("%s", ref), O_RDONLY);
 113        if (fd < 0)
 114                return -1;
 115        ret = -1;
 116        if (read(fd, buffer, sizeof(buffer)) >= 40)
 117                ret = get_sha1_hex(buffer, sha1);
 118        close(fd);
 119        return ret;
 120}
 121
 122static int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
 123{
 124        struct commit *new, *old;
 125        struct commit_list *list;
 126
 127        if (force_update)
 128                return 1;
 129        old = lookup_commit_reference(old_sha1);
 130        if (!old)
 131                return 0;
 132        new = lookup_commit_reference(new_sha1);
 133        if (!new)
 134                return 0;
 135        if (parse_commit(new) < 0)
 136                return 0;
 137        list = NULL;
 138        commit_list_insert(new, &list);
 139        while (list) {
 140                new = pop_most_recent_commit(&list, 1);
 141                if (new == old)
 142                        return 1;
 143        }
 144        return 0;
 145}
 146
 147static int local_ref_nr_match;
 148static char **local_ref_match;
 149static struct ref *local_ref_list;
 150static struct ref **local_last_ref;
 151
 152static int try_to_match(const char *refname, const unsigned char *sha1)
 153{
 154        struct ref *ref;
 155        int len;
 156
 157        if (!path_match(refname, local_ref_nr_match, local_ref_match)) {
 158                if (!send_all)
 159                        return 0;
 160
 161                /* If we have it listed already, skip it */
 162                for (ref = local_ref_list ; ref ; ref = ref->next) {
 163                        if (!strcmp(ref->name, refname))
 164                                return 0;
 165                }
 166        }
 167
 168        len = strlen(refname)+1;
 169        ref = xmalloc(sizeof(*ref) + len);
 170        memset(ref->old_sha1, 0, 20);
 171        memcpy(ref->new_sha1, sha1, 20);
 172        memcpy(ref->name, refname, len);
 173        ref->next = NULL;
 174        *local_last_ref = ref;
 175        local_last_ref = &ref->next;
 176        return 0;
 177}
 178
 179static int send_pack(int in, int out, int nr_match, char **match)
 180{
 181        struct ref *ref_list, **last_ref;
 182        struct ref *ref;
 183        int new_refs;
 184
 185        /* First we get all heads, whether matching or not.. */
 186        last_ref = get_remote_heads(in, &ref_list, 0, NULL);
 187
 188        /*
 189         * Go through the refs, see if we want to update
 190         * any of them..
 191         */
 192        for (ref = ref_list; ref; ref = ref->next) {
 193                unsigned char new_sha1[20];
 194                char *name = ref->name;
 195
 196                if (nr_match && !path_match(name, nr_match, match))
 197                        continue;
 198
 199                if (read_ref(name, new_sha1) < 0)
 200                        continue;
 201
 202                if (!memcmp(ref->old_sha1, new_sha1, 20)) {
 203                        fprintf(stderr, "'%s' unchanged\n", name);
 204                        continue;
 205                }
 206
 207                if (!has_sha1_file(ref->old_sha1)) {
 208                        error("remote '%s' object %s does not exist on local",
 209                              name, sha1_to_hex(ref->old_sha1));
 210                        continue;
 211                }
 212
 213                if (!ref_newer(new_sha1, ref->old_sha1)) {
 214                        error("remote '%s' isn't a strict parent of local", name);
 215                        continue;
 216                }
 217
 218                /* Ok, mark it for update */
 219                memcpy(ref->new_sha1, new_sha1, 20);
 220        }
 221
 222        /*
 223         * See if we have any refs that the other end didn't have
 224         */
 225        if (nr_match || send_all) {
 226                local_ref_nr_match = nr_match;
 227                local_ref_match = match;
 228                local_ref_list = ref_list;
 229                local_last_ref = last_ref;
 230                for_each_ref(try_to_match);
 231        }
 232
 233        /*
 234         * Finally, tell the other end!
 235         */
 236        new_refs = 0;
 237        for (ref = ref_list; ref; ref = ref->next) {
 238                char old_hex[60], *new_hex;
 239                if (is_zero_sha1(ref->new_sha1))
 240                        continue;
 241                new_refs++;
 242                strcpy(old_hex, sha1_to_hex(ref->old_sha1));
 243                new_hex = sha1_to_hex(ref->new_sha1);
 244                packet_write(out, "%s %s %s", old_hex, new_hex, ref->name);
 245                fprintf(stderr, "'%s': updating from %s to %s\n", ref->name, old_hex, new_hex);
 246        }
 247        
 248        packet_flush(out);
 249        if (new_refs)
 250                pack_objects(out, ref_list);
 251        close(out);
 252        return 0;
 253}
 254
 255int main(int argc, char **argv)
 256{
 257        int i, nr_heads = 0;
 258        char *dest = NULL;
 259        char **heads = NULL;
 260        int fd[2], ret;
 261        pid_t pid;
 262
 263        argv++;
 264        for (i = 1; i < argc; i++, argv++) {
 265                char *arg = *argv;
 266
 267                if (*arg == '-') {
 268                        if (!strncmp(arg, "--exec=", 7)) {
 269                                exec = arg + 7;
 270                                continue;
 271                        }
 272                        if (!strcmp(arg, "--all")) {
 273                                send_all = 1;
 274                                continue;
 275                        }
 276                        if (!strcmp(arg, "--force")) {
 277                                force_update = 1;
 278                                continue;
 279                        }
 280                        usage(send_pack_usage);
 281                }
 282                if (!dest) {
 283                        dest = arg;
 284                        continue;
 285                }
 286                heads = argv;
 287                nr_heads = argc - i;
 288                break;
 289        }
 290        if (!dest)
 291                usage(send_pack_usage);
 292        if (heads && send_all)
 293                usage(send_pack_usage);
 294        pid = git_connect(fd, dest, exec);
 295        if (pid < 0)
 296                return 1;
 297        ret = send_pack(fd[0], fd[1], nr_heads, heads);
 298        close(fd[0]);
 299        close(fd[1]);
 300        finish_connect(pid);
 301        return ret;
 302}