send-pack.con commit git-send-pack: documentation (9553d20)
   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 ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
 108{
 109        struct commit *new, *old;
 110        struct commit_list *list;
 111
 112        if (force_update)
 113                return 1;
 114        old = lookup_commit_reference(old_sha1);
 115        if (!old)
 116                return 0;
 117        new = lookup_commit_reference(new_sha1);
 118        if (!new)
 119                return 0;
 120        if (parse_commit(new) < 0)
 121                return 0;
 122        list = NULL;
 123        commit_list_insert(new, &list);
 124        while (list) {
 125                new = pop_most_recent_commit(&list, 1);
 126                if (new == old)
 127                        return 1;
 128        }
 129        return 0;
 130}
 131
 132static struct ref *local_refs, **local_tail;
 133static struct ref *remote_refs, **remote_tail;
 134
 135static int one_local_ref(const char *refname, const unsigned char *sha1)
 136{
 137        struct ref *ref;
 138        int len = strlen(refname) + 1;
 139        ref = xcalloc(1, sizeof(*ref) + len);
 140        memcpy(ref->new_sha1, sha1, 20);
 141        memcpy(ref->name, refname, len);
 142        *local_tail = ref;
 143        local_tail = &ref->next;
 144        return 0;
 145}
 146
 147static void get_local_heads(void)
 148{
 149        local_tail = &local_refs;
 150        for_each_ref(one_local_ref);
 151}
 152
 153static int send_pack(int in, int out, int nr_refspec, char **refspec)
 154{
 155        struct ref *ref;
 156        int new_refs;
 157
 158        /* No funny business with the matcher */
 159        remote_tail = get_remote_heads(in, &remote_refs, 0, NULL);
 160        get_local_heads();
 161
 162        /* match them up */
 163        if (!remote_tail)
 164                remote_tail = &remote_refs;
 165        if (match_refs(local_refs, remote_refs, &remote_tail,
 166                       nr_refspec, refspec, send_all))
 167                return -1;
 168        /*
 169         * Finally, tell the other end!
 170         */
 171        new_refs = 0;
 172        for (ref = remote_refs; ref; ref = ref->next) {
 173                char old_hex[60], *new_hex;
 174                if (!ref->peer_ref)
 175                        continue;
 176                if (!is_zero_sha1(ref->old_sha1)) {
 177                        if (!has_sha1_file(ref->old_sha1)) {
 178                                error("remote '%s' object %s does not "
 179                                      "exist on local",
 180                                      ref->name, sha1_to_hex(ref->old_sha1));
 181                                continue;
 182                        }
 183                        if (!ref_newer(ref->peer_ref->new_sha1,
 184                                       ref->old_sha1)) {
 185                                error("remote ref '%s' is not a strict "
 186                                      "subset of local ref '%s'.", ref->name,
 187                                      ref->peer_ref->name);
 188                                continue;
 189                        }
 190                }
 191                if (!memcmp(ref->old_sha1, ref->peer_ref->new_sha1, 20)) {
 192                        fprintf(stderr, "'%s': up-to-date\n", ref->name);
 193                        continue;
 194                }
 195                memcpy(ref->new_sha1, ref->peer_ref->new_sha1, 20);
 196                if (is_zero_sha1(ref->new_sha1)) {
 197                        error("cannot happen anymore");
 198                        continue;
 199                }
 200                new_refs++;
 201                strcpy(old_hex, sha1_to_hex(ref->old_sha1));
 202                new_hex = sha1_to_hex(ref->new_sha1);
 203                packet_write(out, "%s %s %s", old_hex, new_hex, ref->name);
 204                fprintf(stderr, "updating '%s'", ref->name);
 205                if (strcmp(ref->name, ref->peer_ref->name))
 206                        fprintf(stderr, " using '%s'", ref->peer_ref->name);
 207                fprintf(stderr, "\n  from %s\n  to   %s\n", old_hex, new_hex);
 208        }
 209
 210        packet_flush(out);
 211        if (new_refs)
 212                pack_objects(out, remote_refs);
 213        close(out);
 214        return 0;
 215}
 216
 217
 218int main(int argc, char **argv)
 219{
 220        int i, nr_heads = 0;
 221        char *dest = NULL;
 222        char **heads = NULL;
 223        int fd[2], ret;
 224        pid_t pid;
 225
 226        argv++;
 227        for (i = 1; i < argc; i++, argv++) {
 228                char *arg = *argv;
 229
 230                if (*arg == '-') {
 231                        if (!strncmp(arg, "--exec=", 7)) {
 232                                exec = arg + 7;
 233                                continue;
 234                        }
 235                        if (!strcmp(arg, "--all")) {
 236                                send_all = 1;
 237                                continue;
 238                        }
 239                        if (!strcmp(arg, "--force")) {
 240                                force_update = 1;
 241                                continue;
 242                        }
 243                        usage(send_pack_usage);
 244                }
 245                if (!dest) {
 246                        dest = arg;
 247                        continue;
 248                }
 249                heads = argv;
 250                nr_heads = argc - i;
 251                break;
 252        }
 253        if (!dest)
 254                usage(send_pack_usage);
 255        if (heads && send_all)
 256                usage(send_pack_usage);
 257        pid = git_connect(fd, dest, exec);
 258        if (pid < 0)
 259                return 1;
 260        ret = send_pack(fd[0], fd[1], nr_heads, heads);
 261        close(fd[0]);
 262        close(fd[1]);
 263        finish_connect(pid);
 264        return ret;
 265}