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>
Junio C Hamano committed
Jan 29, 2013 at 14:02 UTC
f2db854d24f32de7b03dde5a7d7134f5e31100b9
5 files changed
+89
-53
builtin/fetch-pack.c
+32
-8
@@ -7,12 +7,31 @@ static const char fetch_pack_usage[] =
7
"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
8
"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
9
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
+
28
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
29
{
30
int i, ret;
31
struct ref *ref = NULL;
32
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;
35
int fd[2];
36
char *pack_lockfile = NULL;
37
char **pack_lockfile_ptr = NULL;
@@ -94,7 +113,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
113
* refs from the standard input:
114
*/
115
for (; i < argc; i++)
97
- string_list_append(&sought, xstrdup(argv[i]));
116
+ add_sought_entry(&sought, &nr_sought, &alloc_sought, argv[i]);
117
if (args.stdin_refs) {
118
if (args.stateless_rpc) {
119
/* 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)
126
break;
127
if (line[n-1] == '\n')
128
n--;
110
- string_list_append(&sought, xmemdupz(line, n));
129
+ add_sought_entry_mem(&sought, &nr_sought, &alloc_sought, line, n);
130
}
131
}
132
else {
133
/* read from stdin one ref per line, until EOF */
134
struct strbuf line = STRBUF_INIT;
135
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);
137
strbuf_release(&line);
138
}
139
}
@@ -131,7 +150,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
150
get_remote_heads(fd[0], &ref, 0, NULL);
151
152
ref = fetch_pack(&args, fd, conn, ref, dest,
134
- &sought, pack_lockfile_ptr);
153
+ sought, nr_sought, pack_lockfile_ptr);
154
if (pack_lockfile) {
155
printf("lock %s\n", pack_lockfile);
156
fflush(stdout);
@@ -141,7 +160,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
160
if (finish_connect(conn))
161
return 1;
162
144
- ret = !ref || sought.nr;
163
+ ret = !ref;
164
165
/*
166
* 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)
168
* remote no-such-ref' would silently succeed without issuing
169
* an error.
170
*/
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
+
178
while (ref) {
179
printf("%s %s\n",
180
sha1_to_hex(ref->old_sha1), ref->name);
cache.h
+2
-1
@@ -1013,7 +1013,8 @@ struct ref {
1013
nonfastforward:1,
1014
not_forwardable:1,
1015
update:1,
1016
- deletion:1;
1016
+ deletion:1,
1017
+ matched:1;
1018
enum {
1019
REF_STATUS_NONE = 0,
1020
REF_STATUS_OK,
fetch-pack.c
+48
-31
@@ -520,47 +520,37 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,
520
}
521
}
522
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
-
523
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)
526
{
527
struct ref *newlist = NULL;
528
struct ref **newtail = &newlist;
529
struct ref *ref, *next;
539
- int sought_pos;
530
+ int i;
531
541
- sought_pos = 0;
532
+ i = 0;
533
for (ref = *refs; ref; ref = next) {
534
int keep = 0;
535
next = ref->next;
536
+
537
if (!memcmp(ref->name, "refs/", 5) &&
538
check_refname_format(ref->name + 5, 0))
539
; /* trash */
540
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);
543
if (cmp < 0)
544
break; /* definitely do not have it */
545
else if (cmp == 0) {
546
keep = 1; /* definitely have it */
555
- sought->items[sought_pos++].util = "matched";
556
- break;
547
+ sought[i]->matched = 1;
548
}
558
- else
559
- sought_pos++; /* might have it; keep looking */
549
+ i++;
550
}
551
}
552
563
- if (! keep && args->fetch_all &&
553
+ if (!keep && args->fetch_all &&
554
(!args->depth || prefixcmp(ref->name, "refs/tags/")))
555
keep = 1;
556
@@ -573,7 +563,6 @@ static void filter_refs(struct fetch_pack_args *args,
563
}
564
}
565
576
- filter_string_list(sought, 0, non_matching_ref, NULL);
566
*refs = newlist;
567
}
568
@@ -583,7 +572,8 @@ static void mark_alternate_complete(const struct ref *ref, void *unused)
572
}
573
574
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)
577
{
578
struct ref *ref;
579
int retval;
@@ -634,7 +624,7 @@ static int everything_local(struct fetch_pack_args *args,
624
}
625
}
626
637
- filter_refs(args, refs, sought);
627
+ filter_refs(args, refs, sought, nr_sought);
628
629
for (retval = 1, ref = *refs; ref ; ref = ref->next) {
630
const unsigned char *remote = ref->old_sha1;
@@ -764,10 +754,17 @@ static int get_pack(struct fetch_pack_args *args,
754
return 0;
755
}
756
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
+
764
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
765
int fd[2],
766
const struct ref *orig_ref,
770
- struct string_list *sought,
767
+ struct ref **sought, int nr_sought,
768
char **pack_lockfile)
769
{
770
struct ref *ref = copy_ref_list(orig_ref);
@@ -776,6 +773,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
773
int agent_len;
774
775
sort_ref_list(&ref, ref_compare_name);
776
+ qsort(sought, nr_sought, sizeof(*sought), cmp_ref_by_name);
777
778
if (is_repository_shallow() && !server_supports("shallow"))
779
die("Server does not support shallow clients");
@@ -824,7 +822,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
822
agent_len, agent_feature);
823
}
824
827
- if (everything_local(args, &ref, sought)) {
825
+ if (everything_local(args, &ref, sought, nr_sought)) {
826
packet_flush(fd[1]);
827
goto all_done;
828
}
@@ -887,11 +885,32 @@ static void fetch_pack_setup(void)
885
did_setup = 1;
886
}
887
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
+
909
struct ref *fetch_pack(struct fetch_pack_args *args,
910
int fd[], struct child_process *conn,
911
const struct ref *ref,
912
const char *dest,
894
- struct string_list *sought,
913
+ struct ref **sought, int nr_sought,
914
char **pack_lockfile)
915
{
916
struct stat st;
@@ -903,16 +922,14 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
922
st.st_mtime = 0;
923
}
924
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);
927
928
if (!ref) {
929
packet_flush(fd[1]);
930
die("no matching remote head");
931
}
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);
933
934
if (args->depth > 0) {
935
static struct lock_file lock;
fetch-pack.h
+5
-6
@@ -20,17 +20,16 @@ struct fetch_pack_args {
20
};
21
22
/*
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.
26
*/
27
struct ref *fetch_pack(struct fetch_pack_args *args,
28
int fd[], struct child_process *conn,
29
const struct ref *ref,
30
const char *dest,
33
- struct string_list *sought,
31
+ struct ref **sought,
32
+ int nr_sought,
33
char **pack_lockfile);
34
35
#endif
transport.c
+2
-7
@@ -518,11 +518,9 @@ static int fetch_refs_via_pack(struct transport *transport,
518
int nr_heads, struct ref **to_fetch)
519
{
520
struct git_transport_data *data = transport->data;
521
- struct string_list sought = STRING_LIST_INIT_DUP;
521
const struct ref *refs;
522
char *dest = xstrdup(transport->url);
523
struct fetch_pack_args args;
525
- int i;
524
struct ref *refs_tmp = NULL;
525
526
memset(&args, 0, sizeof(args));
@@ -536,9 +534,6 @@ static int fetch_refs_via_pack(struct transport *transport,
534
args.no_progress = !transport->progress;
535
args.depth = data->options.depth;
536
539
- for (i = 0; i < nr_heads; i++)
540
- string_list_append(&sought, to_fetch[i]->name);
541
-
537
if (!data->got_remote_heads) {
538
connect_setup(transport, 0, 0);
539
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL);
@@ -547,7 +542,8 @@ static int fetch_refs_via_pack(struct transport *transport,
542
543
refs = fetch_pack(&args, data->fd, data->conn,
544
refs_tmp ? refs_tmp : transport->remote_refs,
550
- dest, &sought, &transport->pack_lockfile);
545
+ dest, to_fetch, nr_heads,
546
+ &transport->pack_lockfile);
547
close(data->fd[0]);
548
close(data->fd[1]);
549
if (finish_connect(data->conn))
@@ -557,7 +553,6 @@ static int fetch_refs_via_pack(struct transport *transport,
553
554
free_refs(refs_tmp);
555
560
- string_list_clear(&sought, 0);
556
free(dest);
557
return (refs ? 0 : -1);
558
}