#define POPPED (1U << 4)
static struct commit_list *rev_list = NULL;
-static int non_common_revs = 0;
+static int non_common_revs = 0, multi_ack = 0;
static void rev_list_push(struct commit *commit, int mark)
{
static int rev_list_insert_ref(const char *path, const unsigned char *sha1)
{
- struct object *o = deref_tag(parse_object(sha1));
+ struct object *o = deref_tag(parse_object(sha1), path, 0);
- if (o->type == commit_type)
+ if (o && o->type == commit_type)
rev_list_push((struct commit *)o, SEEN);
return 0;
* reachable and we have already scanned it.
*/
if (((o = lookup_object(remote)) != NULL) &&
- (o->flags & COMPLETE)) {
- o = deref_tag(o);
-
- if (o->type == commit_type) {
- struct commit *commit = (struct commit *)o;
-
- rev_list_push(commit, COMMON_REF | SEEN);
-
- mark_common(commit, 1, 1);
- }
+ (o->flags & COMPLETE)) {
continue;
}
- packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
+ packet_write(fd[1], "want %s%s\n", sha1_to_hex(remote),
+ multi_ack ? " multi_ack" : "");
fetching++;
}
packet_flush(fd[1]);
if (verbose)
fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
if (!(31 & ++count)) {
+ int ack;
+
packet_flush(fd[1]);
flushes++;
*/
if (count == 32)
continue;
- if (get_ack(fd[0], result_sha1)) {
- flushes = 0;
- retval = 0;
- if (verbose)
- fprintf(stderr, "got ack\n");
- break;
- }
+
+ do {
+ ack = get_ack(fd[0], result_sha1);
+ if (verbose && ack)
+ fprintf(stderr, "got ack %d %s\n", ack,
+ sha1_to_hex(result_sha1));
+ if (ack == 1) {
+ flushes = 0;
+ multi_ack = 0;
+ retval = 0;
+ goto done;
+ } else if (ack == 2) {
+ struct commit *commit =
+ lookup_commit(result_sha1);
+ mark_common(commit, 0, 1);
+ retval = 0;
+ }
+ } while (ack);
flushes--;
}
}
-
+done:
packet_write(fd[1], "done\n");
if (verbose)
fprintf(stderr, "done\n");
- if (retval != 0)
+ if (retval != 0) {
+ multi_ack = 0;
flushes++;
- while (flushes) {
- flushes--;
- if (get_ack(fd[0], result_sha1)) {
+ }
+ while (flushes || multi_ack) {
+ int ack = get_ack(fd[0], result_sha1);
+ if (ack) {
if (verbose)
- fprintf(stderr, "got ack\n");
- return 0;
+ fprintf(stderr, "got ack (%d) %s\n", ack,
+ sha1_to_hex(result_sha1));
+ if (ack == 1)
+ return 0;
+ multi_ack = 1;
+ continue;
}
+ flushes--;
}
return retval;
}
}
}
-static int everything_local(struct ref *refs)
+static void filter_refs(struct ref **refs, int nr_match, char **match)
+{
+ struct ref *prev, *current, *next;
+
+ if (!nr_match)
+ return;
+
+ 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;
+ }
+}
+
+static int everything_local(struct ref **refs, int nr_match, char **match)
{
struct ref *ref;
int retval;
track_object_refs = 0;
save_commit_buffer = 0;
- for (ref = refs; ref; ref = ref->next) {
+ for (ref = *refs; ref; ref = ref->next) {
struct object *o;
o = parse_object(ref->old_sha1);
if (cutoff)
mark_recent_complete_commits(cutoff);
- for (retval = 1; refs ; refs = refs->next) {
- const unsigned char *remote = refs->old_sha1;
+ /*
+ * Mark all complete remote refs as common refs.
+ * Don't mark them common yet; the server has to be told so first.
+ */
+ for (ref = *refs; ref; ref = ref->next) {
+ struct object *o = deref_tag(lookup_object(ref->old_sha1),
+ NULL, 0);
+
+ if (!o || o->type != commit_type || !(o->flags & COMPLETE))
+ continue;
+
+ if (!(o->flags & SEEN)) {
+ rev_list_push((struct commit *)o, COMMON_REF | SEEN);
+
+ mark_common((struct commit *)o, 1, 1);
+ }
+ }
+
+ filter_refs(refs, nr_match, match);
+
+ for (retval = 1, ref = *refs; ref ; ref = ref->next) {
+ const unsigned char *remote = ref->old_sha1;
unsigned char local[20];
struct object *o;
- o = parse_object(remote);
+ o = lookup_object(remote);
if (!o || !(o->flags & COMPLETE)) {
retval = 0;
if (!verbose)
continue;
fprintf(stderr,
"want %s (%s)\n", sha1_to_hex(remote),
- refs->name);
+ ref->name);
continue;
}
- memcpy(refs->new_sha1, local, 20);
+ memcpy(ref->new_sha1, local, 20);
if (!verbose)
continue;
fprintf(stderr,
"already have %s (%s)\n", sha1_to_hex(remote),
- refs->name);
+ ref->name);
}
return retval;
}
int status;
pid_t pid;
- get_remote_heads(fd[0], &ref, nr_match, match, 1);
+ get_remote_heads(fd[0], &ref, 0, NULL, 0);
+ if (server_supports("multi_ack")) {
+ if (verbose)
+ fprintf(stderr, "Server supports multi_ack\n");
+ multi_ack = 1;
+ }
if (!ref) {
packet_flush(fd[1]);
die("no matching remote head");
}
- if (everything_local(ref)) {
+ if (everything_local(&ref, nr_match, match)) {
packet_flush(fd[1]);
goto all_done;
}