X-Git-Url: https://git.octo.it/?p=git.git;a=blobdiff_plain;f=fetch-pack.c;h=7d23a8071a9c2923b1f9bcf1d897e590e04f432b;hp=a3bcad016f52c09897c836112e03eec859a5eb1e;hb=HEAD;hpb=b9aa1f9e9d8f05f350c2e14d6389a5e8596033e9 diff --git a/fetch-pack.c b/fetch-pack.c index a3bcad01..7d23a807 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -18,6 +18,12 @@ static const char *exec = "git-upload-pack"; #define SEEN (1U << 3) #define POPPED (1U << 4) +/* + * After sending this many "have"s if we do not get any new ACK , we + * give up traversing our history. + */ +#define MAX_IN_VAIN 256 + static struct commit_list *rev_list = NULL; static int non_common_revs = 0, multi_ack = 0, use_thin_pack = 0; @@ -40,7 +46,7 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1) { struct object *o = deref_tag(parse_object(sha1), path, 0); - if (o && o->type == commit_type) + if (o && o->type == TYPE_COMMIT) rev_list_push((struct commit *)o, SEEN); return 0; @@ -134,6 +140,8 @@ static int find_common(int fd[2], unsigned char *result_sha1, int fetching; int count = 0, flushes = 0, retval; const unsigned char *sha1; + unsigned in_vain = 0; + int got_continue = 0; for_each_ref(rev_list_insert_ref); @@ -172,6 +180,7 @@ static int find_common(int fd[2], unsigned char *result_sha1, packet_write(fd[1], "have %s\n", sha1_to_hex(sha1)); if (verbose) fprintf(stderr, "have %s\n", sha1_to_hex(sha1)); + in_vain++; if (!(31 & ++count)) { int ack; @@ -200,9 +209,16 @@ static int find_common(int fd[2], unsigned char *result_sha1, lookup_commit(result_sha1); mark_common(commit, 0, 1); retval = 0; + in_vain = 0; + got_continue = 1; } } while (ack); flushes--; + if (got_continue && MAX_IN_VAIN < in_vain) { + if (verbose) + fprintf(stderr, "giving up\n"); + break; /* give up */ + } } } done: @@ -235,14 +251,14 @@ static int mark_complete(const char *path, const unsigned char *sha1) { struct object *o = parse_object(sha1); - while (o && o->type == tag_type) { + while (o && o->type == TYPE_TAG) { struct tag *t = (struct tag *) o; if (!t->tagged) break; /* broken repository */ o->flags |= COMPLETE; o = parse_object(t->tagged->sha1); } - if (o && o->type == commit_type) { + if (o && o->type == TYPE_COMMIT) { struct commit *commit = (struct commit *)o; commit->object.flags |= COMPLETE; insert_by_date(commit, &complete); @@ -262,22 +278,58 @@ static void mark_recent_complete_commits(unsigned long cutoff) static void filter_refs(struct ref **refs, int nr_match, char **match) { - struct ref *prev, *current, *next; - - for (prev = NULL, current = *refs; current; current = next) { - next = current->next; - if ((!memcmp(current->name, "refs/", 5) && - check_ref_format(current->name + 5)) || - (!fetch_all && - !path_match(current->name, nr_match, match))) { - if (prev == NULL) - *refs = next; - else - prev->next = next; - free(current); - } else - prev = current; + struct ref **return_refs; + struct ref *newlist = NULL; + struct ref **newtail = &newlist; + struct ref *ref, *next; + struct ref *fastarray[32]; + + if (nr_match && !fetch_all) { + if (ARRAY_SIZE(fastarray) < nr_match) + return_refs = xcalloc(nr_match, sizeof(struct ref *)); + else { + return_refs = fastarray; + memset(return_refs, 0, sizeof(struct ref *) * nr_match); + } + } + else + return_refs = NULL; + + for (ref = *refs; ref; ref = next) { + next = ref->next; + if (!memcmp(ref->name, "refs/", 5) && + check_ref_format(ref->name + 5)) + ; /* trash */ + else if (fetch_all) { + *newtail = ref; + ref->next = NULL; + newtail = &ref->next; + continue; + } + else { + int order = path_match(ref->name, nr_match, match); + if (order) { + return_refs[order-1] = ref; + continue; /* we will link it later */ + } + } + free(ref); + } + + if (!fetch_all) { + int i; + for (i = 0; i < nr_match; i++) { + ref = return_refs[i]; + if (ref) { + *newtail = ref; + ref->next = NULL; + newtail = &ref->next; + } + } + if (return_refs != fastarray) + free(return_refs); } + *refs = newlist; } static int everything_local(struct ref **refs, int nr_match, char **match) @@ -300,7 +352,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match) * in sync with the other side at some time after * that (it is OK if we guess wrong here). */ - if (o->type == commit_type) { + if (o->type == TYPE_COMMIT) { struct commit *commit = (struct commit *)o; if (!cutoff || cutoff < commit->date) cutoff = commit->date; @@ -319,7 +371,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match) struct object *o = deref_tag(lookup_object(ref->old_sha1), NULL, 0); - if (!o || o->type != commit_type || !(o->flags & COMPLETE)) + if (!o || o->type != TYPE_COMMIT || !(o->flags & COMPLETE)) continue; if (!(o->flags & SEEN)) {