Browse Source

upload-pack: Do not choke on too many heads request.

Cloning from a repository with more than 256 refs (heads and tags
included) will choke, because upload-pack has a built-in limit of
feeding not more than MAX_NEEDS (currently 256) heads to underlying
git-rev-list.  This is a problem when cloning a repository with many
tags, like http://www.linux-mips.org/pub/scm/linux.git, which has 290+
tags.

This commit introduces a new flag, --all, to git-rev-list, to include
all refs in the repository.  Updated upload-pack detects requests that
ask more than MAX_NEEDS refs, and sends everything back instead.

We may probably want to tweak the definitions of MAX_NEEDS and
MAX_HAS, but that is a separate topic.

Signed-off-by: Junio C Hamano <junkio@cox.net>
maint
Junio C Hamano 19 years ago
parent
commit
e091eb9325
  1. 21
      rev-list.c
  2. 1
      rev-parse.c
  3. 50
      upload-pack.c

21
rev-list.c

@ -1,4 +1,5 @@
#include "cache.h" #include "cache.h"
#include "refs.h"
#include "tag.h" #include "tag.h"
#include "commit.h" #include "commit.h"
#include "tree.h" #include "tree.h"
@ -489,6 +490,22 @@ static void handle_one_commit(struct commit *com, struct commit_list **lst)
commit_list_insert(com, lst); commit_list_insert(com, lst);
} }


/* for_each_ref() callback does not allow user data -- Yuck. */
static struct commit_list **global_lst;

static int include_one_commit(const char *path, const unsigned char *sha1)
{
struct commit *com = get_commit_reference(path, 0);
handle_one_commit(com, global_lst);
return 0;
}

static void handle_all(struct commit_list **lst)
{
global_lst = lst;
for_each_ref(include_one_commit);
global_lst = NULL;
}


int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@ -542,6 +559,10 @@ int main(int argc, char **argv)
bisect_list = 1; bisect_list = 1;
continue; continue;
} }
if (!strcmp(arg, "--all")) {
handle_all(&list);
continue;
}
if (!strcmp(arg, "--objects")) { if (!strcmp(arg, "--objects")) {
tag_objects = 1; tag_objects = 1;
tree_objects = 1; tree_objects = 1;

1
rev-parse.c

@ -32,6 +32,7 @@ static int revs_count = 0;
static int is_rev_argument(const char *arg) static int is_rev_argument(const char *arg)
{ {
static const char *rev_args[] = { static const char *rev_args[] = {
"--all",
"--bisect", "--bisect",
"--header", "--header",
"--max-age=", "--max-age=",

50
upload-pack.c

@ -30,10 +30,18 @@ static void create_pack_file(void)


if (!pid) { if (!pid) {
int i; int i;
int args = nr_has + nr_needs + 5; int args;
char **argv = xmalloc(args * sizeof(char *)); char **argv;
char *buf = xmalloc(args * 45); char *buf;
char **p = argv; char **p;

if (MAX_NEEDS <= nr_needs)
args = nr_has + 10;
else
args = nr_has + nr_needs + 5;
argv = xmalloc(args * sizeof(char *));
buf = xmalloc(args * 45);
p = argv;


dup2(fd[1], 1); dup2(fd[1], 1);
close(0); close(0);
@ -41,10 +49,14 @@ static void create_pack_file(void)
close(fd[1]); close(fd[1]);
*p++ = "git-rev-list"; *p++ = "git-rev-list";
*p++ = "--objects"; *p++ = "--objects";
for (i = 0; i < nr_needs; i++) { if (MAX_NEEDS <= nr_needs)
*p++ = buf; *p++ = "--all";
memcpy(buf, sha1_to_hex(needs_sha1[i]), 41); else {
buf += 41; for (i = 0; i < nr_needs; i++) {
*p++ = buf;
memcpy(buf, sha1_to_hex(needs_sha1[i]), 41);
buf += 41;
}
} }
for (i = 0; i < nr_has; i++) { for (i = 0; i < nr_has; i++) {
*p++ = buf; *p++ = buf;
@ -129,18 +141,24 @@ static int receive_needs(void)


needs = 0; needs = 0;
for (;;) { for (;;) {
unsigned char dummy[20], *sha1_buf;
len = packet_read_line(0, line, sizeof(line)); len = packet_read_line(0, line, sizeof(line));
if (!len) if (!len)
return needs; return needs;


/* sha1_buf = dummy;
* This is purely theoretical right now: git-fetch-pack only if (needs == MAX_NEEDS) {
* ever asks for a single HEAD fprintf(stderr,
*/ "warning: supporting only a max of %d requests. "
if (needs >= MAX_NEEDS) "sending everything instead.\n",
die("I'm only doing a max of %d requests", MAX_NEEDS); MAX_NEEDS);
if (strncmp("want ", line, 5) || get_sha1_hex(line+5, needs_sha1[needs])) }
die("git-upload-pack: protocol error, expected to get sha, not '%s'", line); else if (needs < MAX_NEEDS)
sha1_buf = needs_sha1[needs];

if (strncmp("want ", line, 5) || get_sha1_hex(line+5, sha1_buf))
die("git-upload-pack: protocol error, "
"expected to get sha, not '%s'", line);
needs++; needs++;
} }
} }

Loading…
Cancel
Save