bisect: introduce support for --no-checkout option.
[gitweb.git] / upload-pack.c
index df151813f9c12a681dcac85608f5ff2262c12879..ce5cbbea6be45a6dfa79bcc8c8244ae0b99c7ca3 100644 (file)
@@ -11,7 +11,7 @@
 #include "list-objects.h"
 #include "run-command.h"
 
-static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=nn] <dir>";
+static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<n>] <dir>";
 
 /* bits #0..7 in revision.h, #8..10 in commit.c */
 #define THEY_HAVE      (1u << 11)
@@ -27,6 +27,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=n
 static unsigned long oldest_have;
 
 static int multi_ack, nr_our_refs;
+static int no_done;
 static int use_thin_pack, use_ofs_delta, use_include_tag;
 static int no_progress, daemon_mode;
 static int shallow_nr;
@@ -105,12 +106,12 @@ static void show_edge(struct commit *commit)
        fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
 }
 
-static int do_rev_list(int fd, void *create_full_pack)
+static int do_rev_list(int in, int out, void *user_data)
 {
        int i;
        struct rev_info revs;
 
-       pack_pipe = xfdopen(fd, "w");
+       pack_pipe = xfdopen(out, "w");
        init_revisions(&revs, NULL);
        revs.tag_objects = 1;
        revs.tree_objects = 1;
@@ -118,23 +119,18 @@ static int do_rev_list(int fd, void *create_full_pack)
        if (use_thin_pack)
                revs.edge_hint = 1;
 
-       if (create_full_pack) {
-               const char *args[] = {"rev-list", "--all", NULL};
-               setup_revisions(2, args, &revs, NULL);
-       } else {
-               for (i = 0; i < want_obj.nr; i++) {
-                       struct object *o = want_obj.objects[i].item;
-                       /* why??? */
-                       o->flags &= ~UNINTERESTING;
-                       add_pending_object(&revs, o, NULL);
-               }
-               for (i = 0; i < have_obj.nr; i++) {
-                       struct object *o = have_obj.objects[i].item;
-                       o->flags |= UNINTERESTING;
-                       add_pending_object(&revs, o, NULL);
-               }
-               setup_revisions(0, NULL, &revs, NULL);
+       for (i = 0; i < want_obj.nr; i++) {
+               struct object *o = want_obj.objects[i].item;
+               /* why??? */
+               o->flags &= ~UNINTERESTING;
+               add_pending_object(&revs, o, NULL);
+       }
+       for (i = 0; i < have_obj.nr; i++) {
+               struct object *o = have_obj.objects[i].item;
+               o->flags |= UNINTERESTING;
+               add_pending_object(&revs, o, NULL);
        }
+       setup_revisions(0, NULL, &revs, NULL);
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
        mark_edges_uninteresting(revs.commits, &revs, show_edge);
@@ -161,14 +157,8 @@ static void create_pack_file(void)
        const char *argv[10];
        int arg = 0;
 
-       if (shallow_nr) {
-               rev_list.proc = do_rev_list;
-               rev_list.data = 0;
-               if (start_async(&rev_list))
-                       die("git upload-pack: unable to fork git-rev-list");
-               argv[arg++] = "pack-objects";
-       } else {
-               argv[arg++] = "pack-objects";
+       argv[arg++] = "pack-objects";
+       if (!shallow_nr) {
                argv[arg++] = "--revs";
                if (create_full_pack)
                        argv[arg++] = "--all";
@@ -186,7 +176,7 @@ static void create_pack_file(void)
        argv[arg++] = NULL;
 
        memset(&pack_objects, 0, sizeof(pack_objects));
-       pack_objects.in = shallow_nr ? rev_list.out : -1;
+       pack_objects.in = -1;
        pack_objects.out = -1;
        pack_objects.err = -1;
        pack_objects.git_cmd = 1;
@@ -195,8 +185,14 @@ static void create_pack_file(void)
        if (start_command(&pack_objects))
                die("git upload-pack: unable to fork git-pack-objects");
 
-       /* pass on revisions we (don't) want */
-       if (!shallow_nr) {
+       if (shallow_nr) {
+               memset(&rev_list, 0, sizeof(rev_list));
+               rev_list.proc = do_rev_list;
+               rev_list.out = pack_objects.in;
+               if (start_async(&rev_list))
+                       die("git upload-pack: unable to fork git-rev-list");
+       }
+       else {
                FILE *pipe_fd = xfdopen(pack_objects.in, "w");
                if (!create_full_pack) {
                        int i;
@@ -370,7 +366,7 @@ static int reachable(struct commit *want)
 {
        struct commit_list *work = NULL;
 
-       insert_by_date(want, &work);
+       commit_list_insert_by_date(want, &work);
        while (work) {
                struct commit_list *list = work->next;
                struct commit *commit = work->item;
@@ -391,7 +387,7 @@ static int reachable(struct commit *want)
                for (list = commit->parents; list; list = list->next) {
                        struct commit *parent = list->item;
                        if (!(parent->object.flags & REACHABLE))
-                               insert_by_date(parent, &work);
+                               commit_list_insert_by_date(parent, &work);
                }
        }
        want->object.flags |= REACHABLE;
@@ -433,6 +429,9 @@ static int get_common_commits(void)
        static char line[1000];
        unsigned char sha1[20];
        char last_hex[41];
+       int got_common = 0;
+       int got_other = 0;
+       int sent_ready = 0;
 
        save_commit_buffer = 0;
 
@@ -441,25 +440,40 @@ static int get_common_commits(void)
                reset_timeout();
 
                if (!len) {
+                       if (multi_ack == 2 && got_common
+                           && !got_other && ok_to_give_up()) {
+                               sent_ready = 1;
+                               packet_write(1, "ACK %s ready\n", last_hex);
+                       }
                        if (have_obj.nr == 0 || multi_ack)
                                packet_write(1, "NAK\n");
+
+                       if (no_done && sent_ready) {
+                               packet_write(1, "ACK %s\n", last_hex);
+                               return 0;
+                       }
                        if (stateless_rpc)
                                exit(0);
+                       got_common = 0;
+                       got_other = 0;
                        continue;
                }
                strip(line, len);
                if (!prefixcmp(line, "have ")) {
                        switch (got_sha1(line+5, sha1)) {
                        case -1: /* they have what we do not */
+                               got_other = 1;
                                if (multi_ack && ok_to_give_up()) {
                                        const char *hex = sha1_to_hex(sha1);
-                                       if (multi_ack == 2)
+                                       if (multi_ack == 2) {
+                                               sent_ready = 1;
                                                packet_write(1, "ACK %s ready\n", hex);
-                                       else
+                                       else
                                                packet_write(1, "ACK %s continue\n", hex);
                                }
                                break;
                        default:
+                               got_common = 1;
                                memcpy(last_hex, sha1_to_hex(sha1), 41);
                                if (multi_ack == 2)
                                        packet_write(1, "ACK %s common\n", last_hex);
@@ -486,7 +500,7 @@ static int get_common_commits(void)
 
 static void receive_needs(void)
 {
-       struct object_array shallows = {0, 0, NULL};
+       struct object_array shallows = OBJECT_ARRAY_INIT;
        static char line[1000];
        int len, depth = 0;
 
@@ -530,6 +544,8 @@ static void receive_needs(void)
                        multi_ack = 2;
                else if (strstr(line+45, "multi_ack"))
                        multi_ack = 1;
+               if (strstr(line+45, "no-done"))
+                       no_done = 1;
                if (strstr(line+45, "thin-pack"))
                        use_thin_pack = 1;
                if (strstr(line+45, "ofs-delta"))
@@ -553,7 +569,8 @@ static void receive_needs(void)
                 */
                o = lookup_object(sha1_buf);
                if (!o || !(o->flags & OUR_REF))
-                       die("git upload-pack: not our ref %s", line+5);
+                       die("git upload-pack: not our ref %s",
+                           sha1_to_hex(sha1_buf));
                if (!(o->flags & WANTED)) {
                        o->flags |= WANTED;
                        add_object_array(o, NULL, &want_obj);
@@ -629,8 +646,9 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
                die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));
 
        if (capabilities)
-               packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname,
-                       0, capabilities);
+               packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname,
+                            0, capabilities,
+                            stateless_rpc ? " no-done" : "");
        else
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname);
        capabilities = NULL;
@@ -685,6 +703,7 @@ int main(int argc, char **argv)
        int i;
        int strict = 0;
 
+       packet_trace_identity("upload-pack");
        git_extract_argv0_path(argv[0]);
        read_replace_refs = 0;