Code

Merge branch 'mg/x-years-12-months' into maint
[git.git] / upload-pack.c
index dc464d78b35659705ffb0cd233b80ab27e24e8bc..bba053f0aac8eef982d6779983dc6fd979d69d69 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,7 +106,7 @@ static void show_edge(struct commit *commit)
        fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
 }
 
-static int do_rev_list(int in, int out, void *create_full_pack)
+static int do_rev_list(int in, int out, void *user_data)
 {
        int i;
        struct rev_info revs;
@@ -118,23 +119,18 @@ static int do_rev_list(int in, int out, 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);
@@ -371,7 +367,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;
@@ -392,7 +388,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;
@@ -434,6 +430,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;
 
@@ -442,25 +441,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);
@@ -487,7 +501,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;
 
@@ -531,6 +545,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"))
@@ -554,7 +570,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);
@@ -630,8 +647,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;
@@ -686,6 +704,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;