Merge branch 'fix'
[gitweb.git] / fetch-pack.c
index 58ba2094dc6eda7e0429cf83730f8c4c84e4c084..a3bcad016f52c09897c836112e03eec859a5eb1e 100644 (file)
@@ -3,13 +3,13 @@
 #include "pkt-line.h"
 #include "commit.h"
 #include "tag.h"
-#include <time.h>
-#include <sys/wait.h>
 
+static int keep_pack;
 static int quiet;
 static int verbose;
+static int fetch_all;
 static const char fetch_pack_usage[] =
-"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
+"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...";
 static const char *exec = "git-upload-pack";
 
 #define COMPLETE       (1U << 0)
@@ -19,7 +19,7 @@ static const char *exec = "git-upload-pack";
 #define POPPED         (1U << 4)
 
 static struct commit_list *rev_list = NULL;
-static int non_common_revs = 0, multi_ack = 0;
+static int non_common_revs = 0, multi_ack = 0, use_thin_pack = 0;
 
 static void rev_list_push(struct commit *commit, int mark)
 {
@@ -83,7 +83,7 @@ static void mark_common(struct commit *commit,
   Get the next rev to send, ignoring the common.
 */
 
-static const unsigned char* get_rev()
+static const unsigned char* get_rev(void)
 {
        struct commit *commit = NULL;
 
@@ -157,8 +157,9 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                        continue;
                }
 
-               packet_write(fd[1], "want %s%s\n", sha1_to_hex(remote),
-                       multi_ack ? " multi_ack" : "");
+               packet_write(fd[1], "want %s%s%s\n", sha1_to_hex(remote),
+                            (multi_ack ? " multi_ack" : ""),
+                            (use_thin_pack ? " thin-pack" : ""));
                fetching++;
        }
        packet_flush(fd[1]);
@@ -263,14 +264,12 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
 {
        struct ref *prev, *current, *next;
 
-       if (!nr_match)
-               return;
-
        for (prev = NULL, current = *refs; current; current = next) {
                next = current->next;
                if ((!memcmp(current->name, "refs/", 5) &&
-                                       check_ref_format(current->name + 5)) ||
-                               !path_match(current->name, nr_match, match)) {
+                    check_ref_format(current->name + 5)) ||
+                   (!fetch_all &&
+                    !path_match(current->name, nr_match, match))) {
                        if (prev == NULL)
                                *refs = next;
                        else
@@ -363,7 +362,6 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
        struct ref *ref;
        unsigned char sha1[20];
        int status;
-       pid_t pid;
 
        get_remote_heads(fd[0], &ref, 0, NULL, 0);
        if (server_supports("multi_ack")) {
@@ -380,41 +378,27 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
                goto all_done;
        }
        if (find_common(fd, sha1, ref) < 0)
-               fprintf(stderr, "warning: no common commits\n");
-       pid = fork();
-       if (pid < 0)
-               die("git-fetch-pack: unable to fork off git-unpack-objects");
-       if (!pid) {
-               dup2(fd[0], 0);
-               close(fd[0]);
-               close(fd[1]);
-               execlp("git-unpack-objects", "git-unpack-objects",
-                      quiet ? "-q" : NULL, NULL);
-               die("git-unpack-objects exec failed");
-       }
-       close(fd[0]);
-       close(fd[1]);
-       while (waitpid(pid, &status, 0) < 0) {
-               if (errno != EINTR)
-                       die("waiting for git-unpack-objects: %s", strerror(errno));
-       }
-       if (WIFEXITED(status)) {
-               int code = WEXITSTATUS(status);
-               if (code)
-                       die("git-unpack-objects died with error code %d", code);
-all_done:
-               while (ref) {
-                       printf("%s %s\n",
-                              sha1_to_hex(ref->old_sha1), ref->name);
-                       ref = ref->next;
-               }
-               return 0;
-       }
-       if (WIFSIGNALED(status)) {
-               int sig = WTERMSIG(status);
-               die("git-unpack-objects died of signal %d", sig);
+               if (!keep_pack)
+                       /* When cloning, it is not unusual to have
+                        * no common commit.
+                        */
+                       fprintf(stderr, "warning: no common commits\n");
+
+       if (keep_pack)
+               status = receive_keep_pack(fd, "git-fetch-pack", quiet);
+       else
+               status = receive_unpack_pack(fd, "git-fetch-pack", quiet);
+
+       if (status)
+               die("git-fetch-pack: fetch failed.");
+
+ all_done:
+       while (ref) {
+               printf("%s %s\n",
+                      sha1_to_hex(ref->old_sha1), ref->name);
+               ref = ref->next;
        }
-       die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
+       return 0;
 }
 
 int main(int argc, char **argv)
@@ -436,10 +420,22 @@ int main(int argc, char **argv)
                                exec = arg + 7;
                                continue;
                        }
-                       if (!strcmp("-q", arg)) {
+                       if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
                                quiet = 1;
                                continue;
                        }
+                       if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
+                               keep_pack = 1;
+                               continue;
+                       }
+                       if (!strcmp("--thin", arg)) {
+                               use_thin_pack = 1;
+                               continue;
+                       }
+                       if (!strcmp("--all", arg)) {
+                               fetch_all = 1;
+                               continue;
+                       }
                        if (!strcmp("-v", arg)) {
                                verbose = 1;
                                continue;
@@ -453,6 +449,8 @@ int main(int argc, char **argv)
        }
        if (!dest)
                usage(fetch_pack_usage);
+       if (keep_pack)
+               use_thin_pack = 0;
        pid = git_connect(fd, dest, exec);
        if (pid < 0)
                return 1;