|
|
|
@ -12,9 +12,15 @@
@@ -12,9 +12,15 @@
|
|
|
|
|
|
|
|
|
|
static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>"; |
|
|
|
|
|
|
|
|
|
#define THEY_HAVE (1U << 0) |
|
|
|
|
#define OUR_REF (1U << 1) |
|
|
|
|
#define WANTED (1U << 2) |
|
|
|
|
/* bits #0..7 in revision.h, #8..10 in commit.c */ |
|
|
|
|
#define THEY_HAVE (1u << 11) |
|
|
|
|
#define OUR_REF (1u << 12) |
|
|
|
|
#define WANTED (1u << 13) |
|
|
|
|
#define COMMON_KNOWN (1u << 14) |
|
|
|
|
#define REACHABLE (1u << 15) |
|
|
|
|
|
|
|
|
|
static unsigned long oldest_have; |
|
|
|
|
|
|
|
|
|
static int multi_ack, nr_our_refs; |
|
|
|
|
static int use_thin_pack, use_ofs_delta; |
|
|
|
|
static struct object_array have_obj; |
|
|
|
@ -303,11 +309,12 @@ static void create_pack_file(void)
@@ -303,11 +309,12 @@ static void create_pack_file(void)
|
|
|
|
|
static int got_sha1(char *hex, unsigned char *sha1) |
|
|
|
|
{ |
|
|
|
|
struct object *o; |
|
|
|
|
int we_knew_they_have = 0; |
|
|
|
|
|
|
|
|
|
if (get_sha1_hex(hex, sha1)) |
|
|
|
|
die("git-upload-pack: expected SHA1 object, got '%s'", hex); |
|
|
|
|
if (!has_sha1_file(sha1)) |
|
|
|
|
return 0; |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
o = lookup_object(sha1); |
|
|
|
|
if (!(o && o->parsed)) |
|
|
|
@ -316,15 +323,84 @@ static int got_sha1(char *hex, unsigned char *sha1)
@@ -316,15 +323,84 @@ static int got_sha1(char *hex, unsigned char *sha1)
|
|
|
|
|
die("oops (%s)", sha1_to_hex(sha1)); |
|
|
|
|
if (o->type == OBJ_COMMIT) { |
|
|
|
|
struct commit_list *parents; |
|
|
|
|
struct commit *commit = (struct commit *)o; |
|
|
|
|
if (o->flags & THEY_HAVE) |
|
|
|
|
return 0; |
|
|
|
|
o->flags |= THEY_HAVE; |
|
|
|
|
for (parents = ((struct commit*)o)->parents; |
|
|
|
|
we_knew_they_have = 1; |
|
|
|
|
else |
|
|
|
|
o->flags |= THEY_HAVE; |
|
|
|
|
if (!oldest_have || (commit->date < oldest_have)) |
|
|
|
|
oldest_have = commit->date; |
|
|
|
|
for (parents = commit->parents; |
|
|
|
|
parents; |
|
|
|
|
parents = parents->next) |
|
|
|
|
parents->item->object.flags |= THEY_HAVE; |
|
|
|
|
} |
|
|
|
|
add_object_array(o, NULL, &have_obj); |
|
|
|
|
if (!we_knew_they_have) { |
|
|
|
|
add_object_array(o, NULL, &have_obj); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int reachable(struct commit *want) |
|
|
|
|
{ |
|
|
|
|
struct commit_list *work = NULL; |
|
|
|
|
|
|
|
|
|
insert_by_date(want, &work); |
|
|
|
|
while (work) { |
|
|
|
|
struct commit_list *list = work->next; |
|
|
|
|
struct commit *commit = work->item; |
|
|
|
|
free(work); |
|
|
|
|
work = list; |
|
|
|
|
|
|
|
|
|
if (commit->object.flags & THEY_HAVE) { |
|
|
|
|
want->object.flags |= COMMON_KNOWN; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (!commit->object.parsed) |
|
|
|
|
parse_object(commit->object.sha1); |
|
|
|
|
if (commit->object.flags & REACHABLE) |
|
|
|
|
continue; |
|
|
|
|
commit->object.flags |= REACHABLE; |
|
|
|
|
if (commit->date < oldest_have) |
|
|
|
|
continue; |
|
|
|
|
for (list = commit->parents; list; list = list->next) { |
|
|
|
|
struct commit *parent = list->item; |
|
|
|
|
if (!(parent->object.flags & REACHABLE)) |
|
|
|
|
insert_by_date(parent, &work); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
want->object.flags |= REACHABLE; |
|
|
|
|
clear_commit_marks(want, REACHABLE); |
|
|
|
|
free_commit_list(work); |
|
|
|
|
return (want->object.flags & COMMON_KNOWN); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ok_to_give_up(void) |
|
|
|
|
{ |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
if (!have_obj.nr) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < want_obj.nr; i++) { |
|
|
|
|
struct object *want = want_obj.objects[i].item; |
|
|
|
|
|
|
|
|
|
if (want->flags & COMMON_KNOWN) |
|
|
|
|
continue; |
|
|
|
|
want = deref_tag(want, "a want line", 0); |
|
|
|
|
if (!want || want->type != OBJ_COMMIT) { |
|
|
|
|
/* no way to tell if this is reachable by |
|
|
|
|
* looking at the ancestry chain alone, so |
|
|
|
|
* leave a note to ourselves not to worry about |
|
|
|
|
* this object anymore. |
|
|
|
|
*/ |
|
|
|
|
want_obj.objects[i].item->flags |= COMMON_KNOWN; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (!reachable((struct commit *)want)) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -349,7 +425,13 @@ static int get_common_commits(void)
@@ -349,7 +425,13 @@ static int get_common_commits(void)
|
|
|
|
|
} |
|
|
|
|
len = strip(line, len); |
|
|
|
|
if (!strncmp(line, "have ", 5)) { |
|
|
|
|
if (got_sha1(line+5, sha1)) { |
|
|
|
|
switch (got_sha1(line+5, sha1)) { |
|
|
|
|
case -1: /* they have what we do not */ |
|
|
|
|
if (multi_ack && ok_to_give_up()) |
|
|
|
|
packet_write(1, "ACK %s continue\n", |
|
|
|
|
sha1_to_hex(sha1)); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
memcpy(hex, sha1_to_hex(sha1), 41); |
|
|
|
|
if (multi_ack) { |
|
|
|
|
const char *msg = "ACK %s continue\n"; |
|
|
|
@ -358,6 +440,7 @@ static int get_common_commits(void)
@@ -358,6 +440,7 @@ static int get_common_commits(void)
|
|
|
|
|
} |
|
|
|
|
else if (have_obj.nr == 1) |
|
|
|
|
packet_write(1, "ACK %s\n", hex); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|