clone-pack.con commit Make sure alternates are carried over from the original repository. (0f87f89)
   1#include "cache.h"
   2#include "refs.h"
   3#include "pkt-line.h"
   4#include <sys/wait.h>
   5
   6static int quiet;
   7static const char clone_pack_usage[] = "git-clone-pack [-q] [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
   8static const char *exec = "git-upload-pack";
   9
  10static void clone_handshake(int fd[2], struct ref *ref)
  11{
  12        unsigned char sha1[20];
  13
  14        while (ref) {
  15                packet_write(fd[1], "want %s\n", sha1_to_hex(ref->old_sha1));
  16                ref = ref->next;
  17        }
  18        packet_flush(fd[1]);
  19
  20        /* We don't have nuttin' */
  21        packet_write(fd[1], "done\n");
  22        if (get_ack(fd[0], sha1))
  23                error("Huh! git-clone-pack got positive ack for %s", sha1_to_hex(sha1));
  24}
  25
  26static int is_master(struct ref *ref)
  27{
  28        return !strcmp(ref->name, "refs/heads/master");
  29}
  30
  31static void write_one_ref(struct ref *ref)
  32{
  33        char *path = git_path("%s", ref->name);
  34        int fd;
  35        char *hex;
  36
  37        if (safe_create_leading_directories(path))
  38                die("unable to create leading directory for %s", ref->name);
  39        fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0666);
  40        if (fd < 0)
  41                die("unable to create ref %s", ref->name);
  42        hex = sha1_to_hex(ref->old_sha1);
  43        hex[40] = '\n';
  44        if (write(fd, hex, 41) != 41)
  45                die("unable to write ref %s", ref->name);
  46        close(fd);
  47}
  48
  49static void write_refs(struct ref *ref)
  50{
  51        struct ref *head = NULL, *head_ptr, *master_ref;
  52        char *head_path;
  53
  54        if (!strcmp(ref->name, "HEAD")) {
  55                head = ref;
  56                ref = ref->next;
  57        }
  58        head_ptr = NULL;
  59        master_ref = NULL;
  60        while (ref) {
  61                if (is_master(ref))
  62                        master_ref = ref;
  63                if (head && !memcmp(ref->old_sha1, head->old_sha1, 20)) {
  64                        if (!head_ptr || ref == master_ref)
  65                                head_ptr = ref;
  66                }
  67                write_one_ref(ref);
  68                ref = ref->next;
  69        }
  70        if (!head)
  71                return;
  72
  73        head_path = git_path("HEAD");
  74        if (!head_ptr) {
  75                /*
  76                 * If we had a master ref, and it wasn't HEAD, we need to undo the
  77                 * symlink, and write a standalone HEAD. Give a warning, because that's
  78                 * really really wrong.
  79                 */
  80                if (master_ref) {
  81                        error("HEAD doesn't point to any refs! Making standalone HEAD");
  82                        unlink(head_path);
  83                }
  84                write_one_ref(head);
  85                return;
  86        }
  87
  88        /* We reset to the master branch if it's available */
  89        if (master_ref)
  90                return;
  91
  92        /*
  93         * Uhhuh. Other end didn't have master. We start HEAD off with
  94         * the first branch with the same value.
  95         */
  96        unlink(head_path);
  97        if (symlink(head_ptr->name, head_path) < 0)
  98                die("unable to link HEAD to %s", head_ptr->name);
  99}
 100
 101static int clone_pack(int fd[2], int nr_match, char **match)
 102{
 103        struct ref *refs;
 104        int status;
 105        pid_t pid;
 106
 107        get_remote_heads(fd[0], &refs, nr_match, match);
 108        if (!refs) {
 109                packet_flush(fd[1]);
 110                die("no matching remote head");
 111        }
 112        clone_handshake(fd, refs);
 113        pid = fork();
 114        if (pid < 0)
 115                die("git-clone-pack: unable to fork off git-unpack-objects");
 116        if (!pid) {
 117                dup2(fd[0], 0);
 118                close(fd[0]);
 119                close(fd[1]);
 120                execlp("git-unpack-objects", "git-unpack-objects",
 121                        quiet ? "-q" : NULL, NULL);
 122                die("git-unpack-objects exec failed");
 123        }
 124        close(fd[0]);
 125        close(fd[1]);
 126        while (waitpid(pid, &status, 0) < 0) {
 127                if (errno != EINTR)
 128                        die("waiting for git-unpack-objects: %s", strerror(errno));
 129        }
 130        if (WIFEXITED(status)) {
 131                int code = WEXITSTATUS(status);
 132                if (code)
 133                        die("git-unpack-objects died with error code %d", code);
 134                write_refs(refs);
 135                return 0;
 136        }
 137        if (WIFSIGNALED(status)) {
 138                int sig = WTERMSIG(status);
 139                die("git-unpack-objects died of signal %d", sig);
 140        }
 141        die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
 142}
 143
 144int main(int argc, char **argv)
 145{
 146        int i, ret, nr_heads;
 147        char *dest = NULL, **heads;
 148        int fd[2];
 149        pid_t pid;
 150
 151        nr_heads = 0;
 152        heads = NULL;
 153        for (i = 1; i < argc; i++) {
 154                char *arg = argv[i];
 155
 156                if (*arg == '-') {
 157                        if (!strcmp("-q", arg)) {
 158                                quiet = 1;
 159                                continue;
 160                        }
 161                        if (!strncmp("--exec=", arg, 7)) {
 162                                exec = arg + 7;
 163                                continue;
 164                        }
 165                        usage(clone_pack_usage);
 166                }
 167                dest = arg;
 168                heads = argv + i + 1;
 169                nr_heads = argc - i - 1;
 170                break;
 171        }
 172        if (!dest)
 173                usage(clone_pack_usage);
 174        pid = git_connect(fd, dest, exec);
 175        if (pid < 0)
 176                return 1;
 177        ret = clone_pack(fd, nr_heads, heads);
 178        close(fd[0]);
 179        close(fd[1]);
 180        finish_connect(pid);
 181        return ret;
 182}