#define COMPLETE (1U << 0)
#define COMMON (1U << 1)
-#define COMMON_REF (1U << 2 | COMMON)
+#define COMMON_REF (1U << 2)
#define SEEN (1U << 3)
#define POPPED (1U << 4)
static struct commit_list *rev_list = NULL;
-static struct commit_list *rev_list_end = NULL;
-static unsigned long non_common_revs = 0;
+static int non_common_revs = 0;
-static void rev_list_append(struct commit *commit, int mark)
+static void rev_list_push(struct commit *commit, int mark)
{
if (!(commit->object.flags & mark)) {
commit->object.flags |= mark;
- if (rev_list == NULL) {
- commit_list_insert(commit, &rev_list);
- rev_list_end = rev_list;
- } else {
- commit_list_insert(commit, &(rev_list_end->next));
- rev_list_end = rev_list_end->next;
- }
+ if (!(commit->object.parsed))
+ parse_commit(commit);
+
+ insert_by_date(commit, &rev_list);
if (!(commit->object.flags & COMMON))
non_common_revs++;
}
}
-static int rev_list_append_sha1(const char *path, const unsigned char *sha1)
+static int rev_list_insert_ref(const char *path, const unsigned char *sha1)
{
struct object *o = deref_tag(parse_object(sha1));
if (o->type == commit_type)
- rev_list_append((struct commit *)o, SEEN);
+ rev_list_push((struct commit *)o, SEEN);
return 0;
}
-static void mark_common(struct commit *commit)
+/*
+ This function marks a rev and its ancestors as common.
+ In some cases, it is desirable to mark only the ancestors (for example
+ when only the server does not yet know that they are common).
+*/
+
+static void mark_common(struct commit *commit,
+ int ancestors_only, int dont_parse)
{
if (commit != NULL && !(commit->object.flags & COMMON)) {
struct object *o = (struct object *)commit;
- o->flags |= COMMON;
+
+ if (!ancestors_only)
+ o->flags |= COMMON;
+
if (!(o->flags & SEEN))
- rev_list_append(commit, SEEN);
+ rev_list_push(commit, SEEN);
else {
struct commit_list *parents;
- if (!(o->flags & POPPED))
+ if (!ancestors_only && !(o->flags & POPPED))
non_common_revs--;
- if (!o->parsed)
+ if (!o->parsed && !dont_parse)
parse_commit(commit);
+
for (parents = commit->parents;
parents;
parents = parents->next)
- mark_common(parents->item);
+ mark_common(parents->item, 0, dont_parse);
}
}
}
mark = SEEN;
while (parents) {
+ if (!(parents->item->object.flags & SEEN))
+ rev_list_push(parents->item, mark);
if (mark & COMMON)
- mark_common(parents->item);
- else
- rev_list_append(parents->item, mark);
+ mark_common(parents->item, 1, 0);
parents = parents->next;
}
struct ref *refs)
{
int fetching;
- int count = 0, flushes = 0, multi_ack = 0, retval;
+ int count = 0, flushes = 0, retval;
const unsigned char *sha1;
- for_each_ref(rev_list_append_sha1);
+ for_each_ref(rev_list_insert_ref);
fetching = 0;
for ( ; refs ; refs = refs->next) {
(o->flags & COMPLETE)) {
o = deref_tag(o);
- if (o->type == commit_type)
- rev_list_append((struct commit *)o,
- COMMON_REF | SEEN);
+ if (o->type == commit_type) {
+ struct commit *commit = (struct commit *)o;
+
+ rev_list_push(commit, COMMON_REF | SEEN);
+ mark_common(commit, 1, 1);
+ }
continue;
}
- packet_write(fd[1], "want %s multi_ack\n", sha1_to_hex(remote));
+ packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
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;
-
- 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) {
- if (!multi_ack)
- flushes = 0;
- retval = 0;
- goto done;
- } else if (ack == 2) {
- multi_ack = 1;
- mark_common((struct commit *)
- lookup_object(result_sha1));
- retval = 0;
- }
- } while(ack);
+ if (get_ack(fd[0], result_sha1)) {
+ flushes = 0;
+ retval = 0;
+ if (verbose)
+ fprintf(stderr, "got ack\n");
+ break;
+ }
flushes--;
}
}
-done:
- if (multi_ack) {
- packet_flush(fd[1]);
- flushes++;
- }
+
packet_write(fd[1], "done\n");
if (verbose)
fprintf(stderr, "done\n");
if (retval != 0)
flushes++;
while (flushes) {
+ flushes--;
if (get_ack(fd[0], result_sha1)) {
if (verbose)
- fprintf(stderr, "got ack %s\n",
- sha1_to_hex(result_sha1));
- if (!multi_ack)
- return 0;
- retval = 0;
- continue;
+ fprintf(stderr, "got ack\n");
+ return 0;
}
- flushes--;
}
return retval;
}