зеркало из https://github.com/microsoft/git.git
Merge branch 'jc/upload-pack'
* jc/upload-pack: upload-pack: stop the other side when they have more roots than we do.
This commit is contained in:
Коммит
3fbe2d54d7
101
upload-pack.c
101
upload-pack.c
|
@ -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)
|
|||
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)
|
|||
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)
|
|||
}
|
||||
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)
|
|||
}
|
||||
else if (have_obj.nr == 1)
|
||||
packet_write(1, "ACK %s\n", hex);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче