X-Git-Url: https://git.octo.it/?p=git.git;a=blobdiff_plain;f=fetch-pack.c;h=7d23a8071a9c2923b1f9bcf1d897e590e04f432b;hp=aa6f42ae1b45c896395fc146990db22cb61e2f60;hb=HEAD;hpb=5ee2ad654bc7d19ec4f08e11dc4fed8b97a59222 diff --git a/fetch-pack.c b/fetch-pack.c index aa6f42ae..7d23a807 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -7,8 +7,9 @@ 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] [-k] [--exec=upload-pack] [host:]directory ..."; +"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory ..."; static const char *exec = "git-upload-pack"; #define COMPLETE (1U << 0) @@ -17,8 +18,14 @@ 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; +static int non_common_revs = 0, multi_ack = 0, use_thin_pack = 0; static void rev_list_push(struct commit *commit, int mark) { @@ -39,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; @@ -82,7 +89,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; @@ -133,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); @@ -156,8 +165,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]); @@ -170,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; @@ -198,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: @@ -233,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); @@ -260,21 +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)) || - !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) @@ -297,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; @@ -316,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)) { @@ -375,7 +430,11 @@ 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"); + 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); @@ -421,6 +480,14 @@ int main(int argc, char **argv) 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; @@ -434,6 +501,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;