Skip to content

Commit f2db854

Browse files
committed
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 <[email protected]>
1 parent def2499 commit f2db854

File tree

5 files changed

+89
-53
lines changed

5 files changed

+89
-53
lines changed

builtin/fetch-pack.c

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,31 @@ static const char fetch_pack_usage[] =
77
"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
88
"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
99

10+
static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
11+
const char *name, int namelen)
12+
{
13+
struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);
14+
15+
memcpy(ref->name, name, namelen);
16+
ref->name[namelen] = '\0';
17+
(*nr)++;
18+
ALLOC_GROW(*sought, *nr, *alloc);
19+
(*sought)[*nr - 1] = ref;
20+
}
21+
22+
static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
23+
const char *string)
24+
{
25+
add_sought_entry_mem(sought, nr, alloc, string, strlen(string));
26+
}
27+
1028
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
1129
{
1230
int i, ret;
1331
struct ref *ref = NULL;
1432
const char *dest = NULL;
15-
struct string_list sought = STRING_LIST_INIT_DUP;
33+
struct ref **sought = NULL;
34+
int nr_sought = 0, alloc_sought = 0;
1635
int fd[2];
1736
char *pack_lockfile = NULL;
1837
char **pack_lockfile_ptr = NULL;
@@ -94,7 +113,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
94113
* refs from the standard input:
95114
*/
96115
for (; i < argc; i++)
97-
string_list_append(&sought, xstrdup(argv[i]));
116+
add_sought_entry(&sought, &nr_sought, &alloc_sought, argv[i]);
98117
if (args.stdin_refs) {
99118
if (args.stateless_rpc) {
100119
/* 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)
107126
break;
108127
if (line[n-1] == '\n')
109128
n--;
110-
string_list_append(&sought, xmemdupz(line, n));
129+
add_sought_entry_mem(&sought, &nr_sought, &alloc_sought, line, n);
111130
}
112131
}
113132
else {
114133
/* read from stdin one ref per line, until EOF */
115134
struct strbuf line = STRBUF_INIT;
116135
while (strbuf_getline(&line, stdin, '\n') != EOF)
117-
string_list_append(&sought, strbuf_detach(&line, NULL));
136+
add_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf);
118137
strbuf_release(&line);
119138
}
120139
}
@@ -131,7 +150,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
131150
get_remote_heads(fd[0], &ref, 0, NULL);
132151

133152
ref = fetch_pack(&args, fd, conn, ref, dest,
134-
&sought, pack_lockfile_ptr);
153+
sought, nr_sought, pack_lockfile_ptr);
135154
if (pack_lockfile) {
136155
printf("lock %s\n", pack_lockfile);
137156
fflush(stdout);
@@ -141,16 +160,21 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
141160
if (finish_connect(conn))
142161
return 1;
143162

144-
ret = !ref || sought.nr;
163+
ret = !ref;
145164

146165
/*
147166
* If the heads to pull were given, we should have consumed
148167
* all of them by matching the remote. Otherwise, 'git fetch
149168
* remote no-such-ref' would silently succeed without issuing
150169
* an error.
151170
*/
152-
for (i = 0; i < sought.nr; i++)
153-
error("no such remote ref %s", sought.items[i].string);
171+
for (i = 0; i < nr_sought; i++) {
172+
if (!sought[i] || sought[i]->matched)
173+
continue;
174+
error("no such remote ref %s", sought[i]->name);
175+
ret = 1;
176+
}
177+
154178
while (ref) {
155179
printf("%s %s\n",
156180
sha1_to_hex(ref->old_sha1), ref->name);

cache.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1013,7 +1013,8 @@ struct ref {
10131013
nonfastforward:1,
10141014
not_forwardable:1,
10151015
update:1,
1016-
deletion:1;
1016+
deletion:1,
1017+
matched:1;
10171018
enum {
10181019
REF_STATUS_NONE = 0,
10191020
REF_STATUS_OK,

fetch-pack.c

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -520,47 +520,37 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,
520520
}
521521
}
522522

523-
static int non_matching_ref(struct string_list_item *item, void *unused)
524-
{
525-
if (item->util) {
526-
item->util = NULL;
527-
return 0;
528-
}
529-
else
530-
return 1;
531-
}
532-
533523
static void filter_refs(struct fetch_pack_args *args,
534-
struct ref **refs, struct string_list *sought)
524+
struct ref **refs,
525+
struct ref **sought, int nr_sought)
535526
{
536527
struct ref *newlist = NULL;
537528
struct ref **newtail = &newlist;
538529
struct ref *ref, *next;
539-
int sought_pos;
530+
int i;
540531

541-
sought_pos = 0;
532+
i = 0;
542533
for (ref = *refs; ref; ref = next) {
543534
int keep = 0;
544535
next = ref->next;
536+
545537
if (!memcmp(ref->name, "refs/", 5) &&
546538
check_refname_format(ref->name + 5, 0))
547539
; /* trash */
548540
else {
549-
while (sought_pos < sought->nr) {
550-
int cmp = strcmp(ref->name, sought->items[sought_pos].string);
541+
while (i < nr_sought) {
542+
int cmp = strcmp(ref->name, sought[i]->name);
551543
if (cmp < 0)
552544
break; /* definitely do not have it */
553545
else if (cmp == 0) {
554546
keep = 1; /* definitely have it */
555-
sought->items[sought_pos++].util = "matched";
556-
break;
547+
sought[i]->matched = 1;
557548
}
558-
else
559-
sought_pos++; /* might have it; keep looking */
549+
i++;
560550
}
561551
}
562552

563-
if (! keep && args->fetch_all &&
553+
if (!keep && args->fetch_all &&
564554
(!args->depth || prefixcmp(ref->name, "refs/tags/")))
565555
keep = 1;
566556

@@ -573,7 +563,6 @@ static void filter_refs(struct fetch_pack_args *args,
573563
}
574564
}
575565

576-
filter_string_list(sought, 0, non_matching_ref, NULL);
577566
*refs = newlist;
578567
}
579568

@@ -583,7 +572,8 @@ static void mark_alternate_complete(const struct ref *ref, void *unused)
583572
}
584573

585574
static int everything_local(struct fetch_pack_args *args,
586-
struct ref **refs, struct string_list *sought)
575+
struct ref **refs,
576+
struct ref **sought, int nr_sought)
587577
{
588578
struct ref *ref;
589579
int retval;
@@ -634,7 +624,7 @@ static int everything_local(struct fetch_pack_args *args,
634624
}
635625
}
636626

637-
filter_refs(args, refs, sought);
627+
filter_refs(args, refs, sought, nr_sought);
638628

639629
for (retval = 1, ref = *refs; ref ; ref = ref->next) {
640630
const unsigned char *remote = ref->old_sha1;
@@ -764,10 +754,17 @@ static int get_pack(struct fetch_pack_args *args,
764754
return 0;
765755
}
766756

757+
static int cmp_ref_by_name(const void *a_, const void *b_)
758+
{
759+
const struct ref *a = *((const struct ref **)a_);
760+
const struct ref *b = *((const struct ref **)b_);
761+
return strcmp(a->name, b->name);
762+
}
763+
767764
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
768765
int fd[2],
769766
const struct ref *orig_ref,
770-
struct string_list *sought,
767+
struct ref **sought, int nr_sought,
771768
char **pack_lockfile)
772769
{
773770
struct ref *ref = copy_ref_list(orig_ref);
@@ -776,6 +773,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
776773
int agent_len;
777774

778775
sort_ref_list(&ref, ref_compare_name);
776+
qsort(sought, nr_sought, sizeof(*sought), cmp_ref_by_name);
779777

780778
if (is_repository_shallow() && !server_supports("shallow"))
781779
die("Server does not support shallow clients");
@@ -824,7 +822,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
824822
agent_len, agent_feature);
825823
}
826824

827-
if (everything_local(args, &ref, sought)) {
825+
if (everything_local(args, &ref, sought, nr_sought)) {
828826
packet_flush(fd[1]);
829827
goto all_done;
830828
}
@@ -887,11 +885,32 @@ static void fetch_pack_setup(void)
887885
did_setup = 1;
888886
}
889887

888+
static int remove_duplicates_in_refs(struct ref **ref, int nr)
889+
{
890+
struct string_list names = STRING_LIST_INIT_NODUP;
891+
int src, dst;
892+
893+
for (src = dst = 0; src < nr; src++) {
894+
struct string_list_item *item;
895+
item = string_list_insert(&names, ref[src]->name);
896+
if (item->util)
897+
continue; /* already have it */
898+
item->util = ref[src];
899+
if (src != dst)
900+
ref[dst] = ref[src];
901+
dst++;
902+
}
903+
for (src = dst; src < nr; src++)
904+
ref[src] = NULL;
905+
string_list_clear(&names, 0);
906+
return dst;
907+
}
908+
890909
struct ref *fetch_pack(struct fetch_pack_args *args,
891910
int fd[], struct child_process *conn,
892911
const struct ref *ref,
893912
const char *dest,
894-
struct string_list *sought,
913+
struct ref **sought, int nr_sought,
895914
char **pack_lockfile)
896915
{
897916
struct stat st;
@@ -903,16 +922,14 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
903922
st.st_mtime = 0;
904923
}
905924

906-
if (sought->nr) {
907-
sort_string_list(sought);
908-
string_list_remove_duplicates(sought, 0);
909-
}
925+
if (nr_sought)
926+
nr_sought = remove_duplicates_in_refs(sought, nr_sought);
910927

911928
if (!ref) {
912929
packet_flush(fd[1]);
913930
die("no matching remote head");
914931
}
915-
ref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile);
932+
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile);
916933

917934
if (args->depth > 0) {
918935
static struct lock_file lock;

fetch-pack.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,16 @@ struct fetch_pack_args {
2020
};
2121

2222
/*
23-
* sought contains the full names of remote references that should be
24-
* updated from. On return, the names that were found on the remote
25-
* will have been removed from the list. The util members of the
26-
* string_list_items are used internally; they must be NULL on entry
27-
* (and will be NULL on exit).
23+
* sought represents remote references that should be updated from.
24+
* On return, the names that were found on the remote will have been
25+
* marked as such.
2826
*/
2927
struct ref *fetch_pack(struct fetch_pack_args *args,
3028
int fd[], struct child_process *conn,
3129
const struct ref *ref,
3230
const char *dest,
33-
struct string_list *sought,
31+
struct ref **sought,
32+
int nr_sought,
3433
char **pack_lockfile);
3534

3635
#endif

transport.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -518,11 +518,9 @@ static int fetch_refs_via_pack(struct transport *transport,
518518
int nr_heads, struct ref **to_fetch)
519519
{
520520
struct git_transport_data *data = transport->data;
521-
struct string_list sought = STRING_LIST_INIT_DUP;
522521
const struct ref *refs;
523522
char *dest = xstrdup(transport->url);
524523
struct fetch_pack_args args;
525-
int i;
526524
struct ref *refs_tmp = NULL;
527525

528526
memset(&args, 0, sizeof(args));
@@ -536,9 +534,6 @@ static int fetch_refs_via_pack(struct transport *transport,
536534
args.no_progress = !transport->progress;
537535
args.depth = data->options.depth;
538536

539-
for (i = 0; i < nr_heads; i++)
540-
string_list_append(&sought, to_fetch[i]->name);
541-
542537
if (!data->got_remote_heads) {
543538
connect_setup(transport, 0, 0);
544539
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL);
@@ -547,7 +542,8 @@ static int fetch_refs_via_pack(struct transport *transport,
547542

548543
refs = fetch_pack(&args, data->fd, data->conn,
549544
refs_tmp ? refs_tmp : transport->remote_refs,
550-
dest, &sought, &transport->pack_lockfile);
545+
dest, to_fetch, nr_heads,
546+
&transport->pack_lockfile);
551547
close(data->fd[0]);
552548
close(data->fd[1]);
553549
if (finish_connect(data->conn))
@@ -557,7 +553,6 @@ static int fetch_refs_via_pack(struct transport *transport,
557553

558554
free_refs(refs_tmp);
559555

560-
string_list_clear(&sought, 0);
561556
free(dest);
562557
return (refs ? 0 : -1);
563558
}

0 commit comments

Comments
 (0)