Merge branch 'rs/git-blame-mapcar-mapc' into maint
[gitweb.git] / builtin / fetch-pack.c
index 80e72df494e8d4a80a1fe131534e34f91b3977b5..149db88726b8b5f924e6d136828008ec952bc88e 100644 (file)
@@ -60,9 +60,9 @@ static void rev_list_push(struct commit *commit, int mark)
        }
 }
 
-static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
-       struct object *o = deref_tag(parse_object(sha1), path, 0);
+       struct object *o = deref_tag(parse_object(sha1), refname, 0);
 
        if (o && o->type == OBJ_COMMIT)
                rev_list_push((struct commit *)o, SEEN);
@@ -70,9 +70,9 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int
        return 0;
 }
 
-static int clear_marks(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
-       struct object *o = deref_tag(parse_object(sha1), path, 0);
+       struct object *o = deref_tag(parse_object(sha1), refname, 0);
 
        if (o && o->type == OBJ_COMMIT)
                clear_commit_marks((struct commit *)o,
@@ -258,11 +258,6 @@ static void insert_one_alternate_ref(const struct ref *ref, void *unused)
        rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
 }
 
-static void insert_alternate_refs(void)
-{
-       for_each_alternate_ref(insert_one_alternate_ref, NULL);
-}
-
 #define INITIAL_FLUSH 16
 #define PIPESAFE_FLUSH 32
 #define LARGE_FLUSH 1024
@@ -297,7 +292,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
        marked = 1;
 
        for_each_ref(rev_list_insert_ref, NULL);
-       insert_alternate_refs();
+       for_each_alternate_ref(insert_one_alternate_ref, NULL);
 
        fetching = 0;
        for ( ; refs ; refs = refs->next) {
@@ -495,7 +490,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
 
 static struct commit_list *complete;
 
-static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
+static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
        struct object *o = parse_object(sha1);
 
@@ -533,6 +528,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
        struct ref **newtail = &newlist;
        struct ref *ref, *next;
        struct ref *fastarray[32];
+       int match_pos;
 
        if (nr_match && !args.fetch_all) {
                if (ARRAY_SIZE(fastarray) < nr_match)
@@ -545,6 +541,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
        else
                return_refs = NULL;
 
+       match_pos = 0;
        for (ref = *refs; ref; ref = next) {
                next = ref->next;
                if (!memcmp(ref->name, "refs/", 5) &&
@@ -558,15 +555,20 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
                        continue;
                }
                else {
-                       int i;
-                       for (i = 0; i < nr_match; i++) {
-                               if (!strcmp(ref->name, match[i])) {
-                                       match[i][0] = '\0';
-                                       return_refs[i] = ref;
+                       int cmp = -1;
+                       while (match_pos < nr_match) {
+                               cmp = strcmp(ref->name, match[match_pos]);
+                               if (cmp < 0) /* definitely do not have it */
+                                       break;
+                               else if (cmp == 0) { /* definitely have it */
+                                       match[match_pos][0] = '\0';
+                                       return_refs[match_pos] = ref;
                                        break;
                                }
+                               else /* might have it; keep looking */
+                                       match_pos++;
                        }
-                       if (i < nr_match)
+                       if (!cmp)
                                continue; /* we will link it later */
                }
                free(ref);
@@ -588,6 +590,11 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
        *refs = newlist;
 }
 
+static void mark_alternate_complete(const struct ref *ref, void *unused)
+{
+       mark_complete(NULL, ref->old_sha1, 0, NULL);
+}
+
 static int everything_local(struct ref **refs, int nr_match, char **match)
 {
        struct ref *ref;
@@ -616,6 +623,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
 
        if (!args.depth) {
                for_each_ref(mark_complete, NULL);
+               for_each_alternate_ref(mark_alternate_complete, NULL);
                if (cutoff)
                        mark_recent_complete_commits(cutoff);
        }
@@ -738,7 +746,7 @@ static int get_pack(int xd[2], char **pack_lockfile)
        }
        else {
                *av++ = "unpack-objects";
-               if (args.quiet)
+               if (args.quiet || args.no_progress)
                        *av++ = "-q";
        }
        if (*hdr_arg)
@@ -776,6 +784,8 @@ static struct ref *do_fetch_pack(int fd[2],
        struct ref *ref = copy_ref_list(orig_ref);
        unsigned char sha1[20];
 
+       sort_ref_list(&ref, ref_compare_name);
+
        if (is_repository_shallow() && !server_supports("shallow"))
                die("Server does not support shallow clients");
        if (server_supports("multi_ack_detailed")) {
@@ -833,21 +843,12 @@ static int remove_duplicates(int nr_heads, char **heads)
 {
        int src, dst;
 
-       for (src = dst = 0; src < nr_heads; src++) {
-               /* If heads[src] is different from any of
-                * heads[0..dst], push it in.
-                */
-               int i;
-               for (i = 0; i < dst; i++) {
-                       if (!strcmp(heads[i], heads[src]))
-                               break;
-               }
-               if (i < dst)
-                       continue;
-               if (src != dst)
-                       heads[dst] = heads[src];
-               dst++;
-       }
+       if (!nr_heads)
+               return 0;
+
+       for (src = dst = 1; src < nr_heads; src++)
+               if (strcmp(heads[src], heads[dst-1]))
+                       heads[dst++] = heads[src];
        return dst;
 }
 
@@ -1053,6 +1054,11 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        return ret;
 }
 
+static int compare_heads(const void *a, const void *b)
+{
+       return strcmp(*(const char **)a, *(const char **)b);
+}
+
 struct ref *fetch_pack(struct fetch_pack_args *my_args,
                       int fd[], struct child_process *conn,
                       const struct ref *ref,
@@ -1072,8 +1078,11 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
                        st.st_mtime = 0;
        }
 
-       if (heads && nr_heads)
+       if (heads && nr_heads) {
+               qsort(heads, nr_heads, sizeof(*heads), compare_heads);
                nr_heads = remove_duplicates(nr_heads, heads);
+       }
+
        if (!ref) {
                packet_flush(fd[1]);
                die("no matching remote head");