fetch: use struct ref to represent refs to be fetched

Even though "git fetch" has full infrastructure to parse refspecs to
be fetched and match them against the list of refs to come up with
the final list of refs to be fetched, the list of refs that are
requested to be fetched were internally converted to a plain list of
strings at the transport layer and then passed to the underlying
fetch-pack driver.

Stop this conversion and instead pass around an array of refs.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2013-01-29 14:02:15 -08:00
Родитель def249911a
Коммит f2db854d24
5 изменённых файлов: 89 добавлений и 53 удалений

Просмотреть файл

@ -7,12 +7,31 @@ static const char fetch_pack_usage[] =
"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
const char *name, int namelen)
{
struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);
memcpy(ref->name, name, namelen);
ref->name[namelen] = '\0';
(*nr)++;
ALLOC_GROW(*sought, *nr, *alloc);
(*sought)[*nr - 1] = ref;
}
static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
const char *string)
{
add_sought_entry_mem(sought, nr, alloc, string, strlen(string));
}
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
{
int i, ret;
struct ref *ref = NULL;
const char *dest = NULL;
struct string_list sought = STRING_LIST_INIT_DUP;
struct ref **sought = NULL;
int nr_sought = 0, alloc_sought = 0;
int fd[2];
char *pack_lockfile = NULL;
char **pack_lockfile_ptr = NULL;
@ -94,7 +113,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
* refs from the standard input:
*/
for (; i < argc; i++)
string_list_append(&sought, xstrdup(argv[i]));
add_sought_entry(&sought, &nr_sought, &alloc_sought, argv[i]);
if (args.stdin_refs) {
if (args.stateless_rpc) {
/* in stateless RPC mode we use pkt-line to read
@ -107,14 +126,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
break;
if (line[n-1] == '\n')
n--;
string_list_append(&sought, xmemdupz(line, n));
add_sought_entry_mem(&sought, &nr_sought, &alloc_sought, line, n);
}
}
else {
/* read from stdin one ref per line, until EOF */
struct strbuf line = STRBUF_INIT;
while (strbuf_getline(&line, stdin, '\n') != EOF)
string_list_append(&sought, strbuf_detach(&line, NULL));
add_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf);
strbuf_release(&line);
}
}
@ -131,7 +150,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
get_remote_heads(fd[0], &ref, 0, NULL);
ref = fetch_pack(&args, fd, conn, ref, dest,
&sought, pack_lockfile_ptr);
sought, nr_sought, pack_lockfile_ptr);
if (pack_lockfile) {
printf("lock %s\n", pack_lockfile);
fflush(stdout);
@ -141,7 +160,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
if (finish_connect(conn))
return 1;
ret = !ref || sought.nr;
ret = !ref;
/*
* If the heads to pull were given, we should have consumed
@ -149,8 +168,13 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
* remote no-such-ref' would silently succeed without issuing
* an error.
*/
for (i = 0; i < sought.nr; i++)
error("no such remote ref %s", sought.items[i].string);
for (i = 0; i < nr_sought; i++) {
if (!sought[i] || sought[i]->matched)
continue;
error("no such remote ref %s", sought[i]->name);
ret = 1;
}
while (ref) {
printf("%s %s\n",
sha1_to_hex(ref->old_sha1), ref->name);

Просмотреть файл

@ -1013,7 +1013,8 @@ struct ref {
nonfastforward:1,
not_forwardable:1,
update:1,
deletion:1;
deletion:1,
matched:1;
enum {
REF_STATUS_NONE = 0,
REF_STATUS_OK,

Просмотреть файл

@ -520,47 +520,37 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,
}
}
static int non_matching_ref(struct string_list_item *item, void *unused)
{
if (item->util) {
item->util = NULL;
return 0;
}
else
return 1;
}
static void filter_refs(struct fetch_pack_args *args,
struct ref **refs, struct string_list *sought)
struct ref **refs,
struct ref **sought, int nr_sought)
{
struct ref *newlist = NULL;
struct ref **newtail = &newlist;
struct ref *ref, *next;
int sought_pos;
int i;
sought_pos = 0;
i = 0;
for (ref = *refs; ref; ref = next) {
int keep = 0;
next = ref->next;
if (!memcmp(ref->name, "refs/", 5) &&
check_refname_format(ref->name + 5, 0))
; /* trash */
else {
while (sought_pos < sought->nr) {
int cmp = strcmp(ref->name, sought->items[sought_pos].string);
while (i < nr_sought) {
int cmp = strcmp(ref->name, sought[i]->name);
if (cmp < 0)
break; /* definitely do not have it */
else if (cmp == 0) {
keep = 1; /* definitely have it */
sought->items[sought_pos++].util = "matched";
break;
sought[i]->matched = 1;
}
else
sought_pos++; /* might have it; keep looking */
i++;
}
}
if (! keep && args->fetch_all &&
if (!keep && args->fetch_all &&
(!args->depth || prefixcmp(ref->name, "refs/tags/")))
keep = 1;
@ -573,7 +563,6 @@ static void filter_refs(struct fetch_pack_args *args,
}
}
filter_string_list(sought, 0, non_matching_ref, NULL);
*refs = newlist;
}
@ -583,7 +572,8 @@ static void mark_alternate_complete(const struct ref *ref, void *unused)
}
static int everything_local(struct fetch_pack_args *args,
struct ref **refs, struct string_list *sought)
struct ref **refs,
struct ref **sought, int nr_sought)
{
struct ref *ref;
int retval;
@ -634,7 +624,7 @@ static int everything_local(struct fetch_pack_args *args,
}
}
filter_refs(args, refs, sought);
filter_refs(args, refs, sought, nr_sought);
for (retval = 1, ref = *refs; ref ; ref = ref->next) {
const unsigned char *remote = ref->old_sha1;
@ -764,10 +754,17 @@ static int get_pack(struct fetch_pack_args *args,
return 0;
}
static int cmp_ref_by_name(const void *a_, const void *b_)
{
const struct ref *a = *((const struct ref **)a_);
const struct ref *b = *((const struct ref **)b_);
return strcmp(a->name, b->name);
}
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int fd[2],
const struct ref *orig_ref,
struct string_list *sought,
struct ref **sought, int nr_sought,
char **pack_lockfile)
{
struct ref *ref = copy_ref_list(orig_ref);
@ -776,6 +773,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int agent_len;
sort_ref_list(&ref, ref_compare_name);
qsort(sought, nr_sought, sizeof(*sought), cmp_ref_by_name);
if (is_repository_shallow() && !server_supports("shallow"))
die("Server does not support shallow clients");
@ -824,7 +822,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
agent_len, agent_feature);
}
if (everything_local(args, &ref, sought)) {
if (everything_local(args, &ref, sought, nr_sought)) {
packet_flush(fd[1]);
goto all_done;
}
@ -887,11 +885,32 @@ static void fetch_pack_setup(void)
did_setup = 1;
}
static int remove_duplicates_in_refs(struct ref **ref, int nr)
{
struct string_list names = STRING_LIST_INIT_NODUP;
int src, dst;
for (src = dst = 0; src < nr; src++) {
struct string_list_item *item;
item = string_list_insert(&names, ref[src]->name);
if (item->util)
continue; /* already have it */
item->util = ref[src];
if (src != dst)
ref[dst] = ref[src];
dst++;
}
for (src = dst; src < nr; src++)
ref[src] = NULL;
string_list_clear(&names, 0);
return dst;
}
struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
const struct ref *ref,
const char *dest,
struct string_list *sought,
struct ref **sought, int nr_sought,
char **pack_lockfile)
{
struct stat st;
@ -903,16 +922,14 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
st.st_mtime = 0;
}
if (sought->nr) {
sort_string_list(sought);
string_list_remove_duplicates(sought, 0);
}
if (nr_sought)
nr_sought = remove_duplicates_in_refs(sought, nr_sought);
if (!ref) {
packet_flush(fd[1]);
die("no matching remote head");
}
ref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile);
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile);
if (args->depth > 0) {
static struct lock_file lock;

Просмотреть файл

@ -20,17 +20,16 @@ struct fetch_pack_args {
};
/*
* sought contains the full names of remote references that should be
* updated from. On return, the names that were found on the remote
* will have been removed from the list. The util members of the
* string_list_items are used internally; they must be NULL on entry
* (and will be NULL on exit).
* sought represents remote references that should be updated from.
* On return, the names that were found on the remote will have been
* marked as such.
*/
struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
const struct ref *ref,
const char *dest,
struct string_list *sought,
struct ref **sought,
int nr_sought,
char **pack_lockfile);
#endif

Просмотреть файл

@ -518,11 +518,9 @@ static int fetch_refs_via_pack(struct transport *transport,
int nr_heads, struct ref **to_fetch)
{
struct git_transport_data *data = transport->data;
struct string_list sought = STRING_LIST_INIT_DUP;
const struct ref *refs;
char *dest = xstrdup(transport->url);
struct fetch_pack_args args;
int i;
struct ref *refs_tmp = NULL;
memset(&args, 0, sizeof(args));
@ -536,9 +534,6 @@ static int fetch_refs_via_pack(struct transport *transport,
args.no_progress = !transport->progress;
args.depth = data->options.depth;
for (i = 0; i < nr_heads; i++)
string_list_append(&sought, to_fetch[i]->name);
if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL);
@ -547,7 +542,8 @@ static int fetch_refs_via_pack(struct transport *transport,
refs = fetch_pack(&args, data->fd, data->conn,
refs_tmp ? refs_tmp : transport->remote_refs,
dest, &sought, &transport->pack_lockfile);
dest, to_fetch, nr_heads,
&transport->pack_lockfile);
close(data->fd[0]);
close(data->fd[1]);
if (finish_connect(data->conn))
@ -557,7 +553,6 @@ static int fetch_refs_via_pack(struct transport *transport,
free_refs(refs_tmp);
string_list_clear(&sought, 0);
free(dest);
return (refs ? 0 : -1);
}