fetch-pack.con commit git-fetch-pack: avoid unnecessary zero packing (844ac7f)
   1#include "cache.h"
   2#include "refs.h"
   3#include "pkt-line.h"
   4#include <sys/wait.h>
   5
   6static int quiet;
   7static int verbose;
   8static const char fetch_pack_usage[] =
   9"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
  10static const char *exec = "git-upload-pack";
  11
  12static int find_common(int fd[2], unsigned char *result_sha1,
  13                       struct ref *refs)
  14{
  15        int fetching;
  16        static char line[1000];
  17        int count = 0, flushes = 0, retval;
  18        FILE *revs;
  19
  20        revs = popen("git-rev-list $(git-rev-parse --all)", "r");
  21        if (!revs)
  22                die("unable to run 'git-rev-list'");
  23
  24        fetching = 0;
  25        for ( ; refs ; refs = refs->next) {
  26                unsigned char *remote = refs->old_sha1;
  27                unsigned char *local = refs->new_sha1;
  28
  29                if (!memcmp(remote, local, 20))
  30                        continue;
  31                packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
  32                fetching++;
  33        }
  34        packet_flush(fd[1]);
  35        if (!fetching)
  36                return 1;
  37        flushes = 1;
  38        retval = -1;
  39        while (fgets(line, sizeof(line), revs) != NULL) {
  40                unsigned char sha1[20];
  41                if (get_sha1_hex(line, sha1))
  42                        die("git-fetch-pack: expected object name, got crud");
  43                packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
  44                if (verbose)
  45                        fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
  46                if (!(31 & ++count)) {
  47                        packet_flush(fd[1]);
  48                        flushes++;
  49
  50                        /*
  51                         * We keep one window "ahead" of the other side, and
  52                         * will wait for an ACK only on the next one
  53                         */
  54                        if (count == 32)
  55                                continue;
  56                        if (get_ack(fd[0], result_sha1)) {
  57                                flushes = 0;
  58                                retval = 0;
  59                                if (verbose)
  60                                        fprintf(stderr, "got ack\n");
  61                                break;
  62                        }
  63                        flushes--;
  64                }
  65        }
  66        pclose(revs);
  67        packet_write(fd[1], "done\n");
  68        if (verbose)
  69                fprintf(stderr, "done\n");
  70        while (flushes) {
  71                flushes--;
  72                if (get_ack(fd[0], result_sha1)) {
  73                        if (verbose)
  74                                fprintf(stderr, "got ack\n");
  75                        return 0;
  76                }
  77        }
  78        return retval;
  79}
  80
  81static int everything_local(struct ref *refs)
  82{
  83        int retval;
  84
  85        for (retval = 1; refs ; refs = refs->next) {
  86                const unsigned char *remote = refs->old_sha1;
  87                unsigned char local[20];
  88
  89                if (read_ref(git_path("%s", refs->name), local) < 0 ||
  90                    memcmp(remote, local, 20)) {
  91                        retval = 0;
  92                        if (!verbose)
  93                                continue;
  94                        fprintf(stderr,
  95                                "want %s (%s)\n", sha1_to_hex(remote),
  96                                refs->name);
  97                        continue;
  98                }
  99
 100                memcpy(refs->new_sha1, local, 20);
 101                if (!verbose)
 102                        continue;
 103                fprintf(stderr,
 104                        "already have %s (%s)\n", sha1_to_hex(remote),
 105                        refs->name);
 106        }
 107        return retval;
 108}
 109
 110static int fetch_pack(int fd[2], int nr_match, char **match)
 111{
 112        struct ref *ref;
 113        unsigned char sha1[20];
 114        int status;
 115        pid_t pid;
 116
 117        get_remote_heads(fd[0], &ref, nr_match, match, 1);
 118        if (!ref) {
 119                packet_flush(fd[1]);
 120                die("no matching remote head");
 121        }
 122        if (everything_local(ref)) {
 123                packet_flush(fd[1]);
 124                goto all_done;
 125        }
 126        if (find_common(fd, sha1, ref) < 0)
 127                fprintf(stderr, "warning: no common commits\n");
 128        pid = fork();
 129        if (pid < 0)
 130                die("git-fetch-pack: unable to fork off git-unpack-objects");
 131        if (!pid) {
 132                dup2(fd[0], 0);
 133                close(fd[0]);
 134                close(fd[1]);
 135                execlp("git-unpack-objects", "git-unpack-objects",
 136                       quiet ? "-q" : NULL, NULL);
 137                die("git-unpack-objects exec failed");
 138        }
 139        close(fd[0]);
 140        close(fd[1]);
 141        while (waitpid(pid, &status, 0) < 0) {
 142                if (errno != EINTR)
 143                        die("waiting for git-unpack-objects: %s", strerror(errno));
 144        }
 145        if (WIFEXITED(status)) {
 146                int code = WEXITSTATUS(status);
 147                if (code)
 148                        die("git-unpack-objects died with error code %d", code);
 149all_done:
 150                while (ref) {
 151                        printf("%s %s\n",
 152                               sha1_to_hex(ref->old_sha1), ref->name);
 153                        ref = ref->next;
 154                }
 155                return 0;
 156        }
 157        if (WIFSIGNALED(status)) {
 158                int sig = WTERMSIG(status);
 159                die("git-unpack-objects died of signal %d", sig);
 160        }
 161        die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
 162}
 163
 164int main(int argc, char **argv)
 165{
 166        int i, ret, nr_heads;
 167        char *dest = NULL, **heads;
 168        int fd[2];
 169        pid_t pid;
 170
 171        nr_heads = 0;
 172        heads = NULL;
 173        for (i = 1; i < argc; i++) {
 174                char *arg = argv[i];
 175
 176                if (*arg == '-') {
 177                        if (!strncmp("--exec=", arg, 7)) {
 178                                exec = arg + 7;
 179                                continue;
 180                        }
 181                        if (!strcmp("-q", arg)) {
 182                                quiet = 1;
 183                                continue;
 184                        }
 185                        if (!strcmp("-v", arg)) {
 186                                verbose = 1;
 187                                continue;
 188                        }
 189                        usage(fetch_pack_usage);
 190                }
 191                dest = arg;
 192                heads = argv + i + 1;
 193                nr_heads = argc - i - 1;
 194                break;
 195        }
 196        if (!dest)
 197                usage(fetch_pack_usage);
 198        pid = git_connect(fd, dest, exec);
 199        if (pid < 0)
 200                return 1;
 201        ret = fetch_pack(fd, nr_heads, heads);
 202        close(fd[0]);
 203        close(fd[1]);
 204        finish_connect(pid);
 205        return ret;
 206}