fetch-pack: put shallow info in output parameter

Expand the transport fetch method signature, by adding an output parameter, to allow transports to return information about the refs they have fetched. Then communicate shallow status information through this mechanism instead of by modifying the input list of refs. This does require clients to sometimes generate the ref map twice: once from the list of refs provided by the remote (as is currently done) and potentially once from the new list of refs that the fetch mechanism provides. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed Jun 27, 2018 at 15:30 UTC 989b8c4452f63f415c276df348defce6df613696
8 files changed +77 -24
builtin/clone.c
+2 -2
@@ -1155,7 +1155,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1155 }
1156
1157 if (!is_local && !complete_refs_before_fetch)
1158 - transport_fetch_refs(transport, mapped_refs);
1158 + transport_fetch_refs(transport, mapped_refs, NULL);
1159
1160 remote_head = find_ref_by_name(refs, "HEAD");
1161 remote_head_points_at =
@@ -1197,7 +1197,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
1197 if (is_local)
1198 clone_local(path, git_dir);
1199 else if (refs && complete_refs_before_fetch)
1200 - transport_fetch_refs(transport, mapped_refs);
1200 + transport_fetch_refs(transport, mapped_refs, NULL);
1201
1202 update_remote_refs(refs, mapped_refs, remote_head_points_at,
1203 branch_top.buf, reflog_msg.buf, transport,
builtin/fetch.c
+24 -4
@@ -946,11 +946,13 @@ static int quickfetch(struct ref *ref_map)
946 return check_connected(iterate_ref_map, &rm, &opt);
947 }
948
949 -static int fetch_refs(struct transport *transport, struct ref *ref_map)
949 +static int fetch_refs(struct transport *transport, struct ref *ref_map,
950 + struct ref **updated_remote_refs)
951 {
952 int ret = quickfetch(ref_map);
953 if (ret)
953 - ret = transport_fetch_refs(transport, ref_map);
954 + ret = transport_fetch_refs(transport, ref_map,
955 + updated_remote_refs);
956 if (!ret)
957 /*
958 * Keep the new pack's ".keep" file around to allow the caller
@@ -1112,7 +1114,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
1114 transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
1115 transport_set_option(transport, TRANS_OPT_DEPTH, "0");
1116 transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
1115 - if (!fetch_refs(transport, ref_map))
1117 + if (!fetch_refs(transport, ref_map, NULL))
1118 consume_refs(transport, ref_map);
1119
1120 if (gsecondary) {
@@ -1128,6 +1130,7 @@ static int do_fetch(struct transport *transport,
1130 int autotags = (transport->remote->fetch_tags == 1);
1131 int retcode = 0;
1132 const struct ref *remote_refs;
1133 + struct ref *updated_remote_refs = NULL;
1134 struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
1135
1136 if (tags == TAGS_DEFAULT) {
@@ -1178,7 +1181,24 @@ static int do_fetch(struct transport *transport,
1181 transport->url);
1182 }
1183 }
1181 - if (fetch_refs(transport, ref_map) || consume_refs(transport, ref_map)) {
1184 +
1185 + if (fetch_refs(transport, ref_map, &updated_remote_refs)) {
1186 + free_refs(ref_map);
1187 + retcode = 1;
1188 + goto cleanup;
1189 + }
1190 + if (updated_remote_refs) {
1191 + /*
1192 + * Regenerate ref_map using the updated remote refs. This is
1193 + * to account for additional information which may be provided
1194 + * by the transport (e.g. shallow info).
1195 + */
1196 + free_refs(ref_map);
1197 + ref_map = get_ref_map(transport->remote, updated_remote_refs, rs,
1198 + tags, &autotags);
1199 + free_refs(updated_remote_refs);
1200 + }
1201 + if (consume_refs(transport, ref_map)) {
1202 free_refs(ref_map);
1203 retcode = 1;
1204 goto cleanup;
fetch-object.c
+1 -1
@@ -19,7 +19,7 @@ static void fetch_refs(const char *remote_name, struct ref *ref)
19
20 transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
21 transport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, "1");
22 - transport_fetch_refs(transport, ref);
22 + transport_fetch_refs(transport, ref, NULL);
23 fetch_if_missing = original_fetch_if_missing;
24 }
25
fetch-pack.c
+8 -7
@@ -1470,12 +1470,13 @@ static int remove_duplicates_in_refs(struct ref **ref, int nr)
1470 }
1471
1472 static void update_shallow(struct fetch_pack_args *args,
1473 - struct ref **sought, int nr_sought,
1473 + struct ref *refs,
1474 struct shallow_info *si)
1475 {
1476 struct oid_array ref = OID_ARRAY_INIT;
1477 int *status;
1478 int i;
1479 + struct ref *r;
1480
1481 if (args->deepen && alternate_shallow_file) {
1482 if (*alternate_shallow_file == '\0') { /* --unshallow */
@@ -1517,8 +1518,8 @@ static void update_shallow(struct fetch_pack_args *args,
1518 remove_nonexistent_theirs_shallow(si);
1519 if (!si->nr_ours && !si->nr_theirs)
1520 return;
1520 - for (i = 0; i < nr_sought; i++)
1521 - oid_array_append(&ref, &sought[i]->old_oid);
1521 + for (r = refs; r; r = r->next)
1522 + oid_array_append(&ref, &r->old_oid);
1523 si->ref = &ref;
1524
1525 if (args->update_shallow) {
@@ -1552,12 +1553,12 @@ static void update_shallow(struct fetch_pack_args *args,
1553 * remote is also shallow, check what ref is safe to update
1554 * without updating .git/shallow
1555 */
1555 - status = xcalloc(nr_sought, sizeof(*status));
1556 + status = xcalloc(ref.nr, sizeof(*status));
1557 assign_shallow_commits_to_refs(si, NULL, status);
1558 if (si->nr_ours || si->nr_theirs) {
1558 - for (i = 0; i < nr_sought; i++)
1559 + for (r = refs, i = 0; r; r = r->next, i++)
1560 if (status[i])
1560 - sought[i]->status = REF_STATUS_REJECT_SHALLOW;
1561 + r->status = REF_STATUS_REJECT_SHALLOW;
1562 }
1563 free(status);
1564 oid_array_clear(&ref);
@@ -1591,7 +1592,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
1592 ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
1593 &si, pack_lockfile);
1594 reprepare_packed_git(the_repository);
1594 - update_shallow(args, sought, nr_sought, &si);
1595 + update_shallow(args, ref_cpy, &si);
1596 clear_shallow_info(&si);
1597 return ref_cpy;
1598 }
transport-helper.c
+4 -2
@@ -651,14 +651,16 @@ static int connect_helper(struct transport *transport, const char *name,
651 }
652
653 static int fetch(struct transport *transport,
654 - int nr_heads, struct ref **to_fetch)
654 + int nr_heads, struct ref **to_fetch,
655 + struct ref **fetched_refs)
656 {
657 struct helper_data *data = transport->data;
658 int i, count;
659
660 if (process_connect(transport, 0)) {
661 do_take_over(transport);
661 - return transport->vtable->fetch(transport, nr_heads, to_fetch);
662 + return transport->vtable->fetch(transport, nr_heads, to_fetch,
663 + fetched_refs);
664 }
665
666 count = 0;
transport-internal.h
+8 -1
@@ -36,11 +36,18 @@ struct transport_vtable {
36 * Fetch the objects for the given refs. Note that this gets
37 * an array, and should ignore the list structure.
38 *
39 + * The transport *may* provide, in fetched_refs, the list of refs that
40 + * it fetched. If the transport knows anything about the fetched refs
41 + * that the caller does not know (for example, shallow status), it
42 + * should provide that list of refs and include that information in the
43 + * list.
44 + *
45 * If the transport did not get hashes for refs in
46 * get_refs_list(), it should set the old_sha1 fields in the
47 * provided refs now.
48 **/
43 - int (*fetch)(struct transport *transport, int refs_nr, struct ref **refs);
49 + int (*fetch)(struct transport *transport, int refs_nr, struct ref **refs,
50 + struct ref **fetched_refs);
51
52 /**
53 * Push the objects and refs. Send the necessary objects, and
transport.c
+28 -6
@@ -151,7 +151,8 @@ static struct ref *get_refs_from_bundle(struct transport *transport,
151 }
152
153 static int fetch_refs_from_bundle(struct transport *transport,
154 - int nr_heads, struct ref **to_fetch)
154 + int nr_heads, struct ref **to_fetch,
155 + struct ref **fetched_refs)
156 {
157 struct bundle_transport_data *data = transport->data;
158 return unbundle(&data->header, data->fd,
@@ -287,7 +288,8 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
288 }
289
290 static int fetch_refs_via_pack(struct transport *transport,
290 - int nr_heads, struct ref **to_fetch)
291 + int nr_heads, struct ref **to_fetch,
292 + struct ref **fetched_refs)
293 {
294 int ret = 0;
295 struct git_transport_data *data = transport->data;
@@ -354,8 +356,12 @@ static int fetch_refs_via_pack(struct transport *transport,
356 if (report_unmatched_refs(to_fetch, nr_heads))
357 ret = -1;
358
359 + if (fetched_refs)
360 + *fetched_refs = refs;
361 + else
362 + free_refs(refs);
363 +
364 free_refs(refs_tmp);
358 - free_refs(refs);
365 free(dest);
366 return ret;
367 }
@@ -1215,19 +1221,31 @@ const struct ref *transport_get_remote_refs(struct transport *transport,
1221 return transport->remote_refs;
1222 }
1223
1218 -int transport_fetch_refs(struct transport *transport, struct ref *refs)
1224 +int transport_fetch_refs(struct transport *transport, struct ref *refs,
1225 + struct ref **fetched_refs)
1226 {
1227 int rc;
1228 int nr_heads = 0, nr_alloc = 0, nr_refs = 0;
1229 struct ref **heads = NULL;
1230 + struct ref *nop_head = NULL, **nop_tail = &nop_head;
1231 struct ref *rm;
1232
1233 for (rm = refs; rm; rm = rm->next) {
1234 nr_refs++;
1235 if (rm->peer_ref &&
1236 !is_null_oid(&rm->old_oid) &&
1229 - !oidcmp(&rm->peer_ref->old_oid, &rm->old_oid))
1237 + !oidcmp(&rm->peer_ref->old_oid, &rm->old_oid)) {
1238 + /*
1239 + * These need to be reported as fetched, but we don't
1240 + * actually need to fetch them.
1241 + */
1242 + if (fetched_refs) {
1243 + struct ref *nop_ref = copy_ref(rm);
1244 + *nop_tail = nop_ref;
1245 + nop_tail = &nop_ref->next;
1246 + }
1247 continue;
1248 + }
1249 ALLOC_GROW(heads, nr_heads + 1, nr_alloc);
1250 heads[nr_heads++] = rm;
1251 }
@@ -1245,7 +1263,11 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
1263 heads[nr_heads++] = rm;
1264 }
1265
1248 - rc = transport->vtable->fetch(transport, nr_heads, heads);
1266 + rc = transport->vtable->fetch(transport, nr_heads, heads, fetched_refs);
1267 + if (fetched_refs && nop_head) {
1268 + *nop_tail = *fetched_refs;
1269 + *fetched_refs = nop_head;
1270 + }
1271
1272 free(heads);
1273 return rc;
transport.h
+2 -1
@@ -218,7 +218,8 @@ int transport_push(struct transport *connection,
218 const struct ref *transport_get_remote_refs(struct transport *transport,
219 const struct argv_array *ref_prefixes);
220
221 -int transport_fetch_refs(struct transport *transport, struct ref *refs);
221 +int transport_fetch_refs(struct transport *transport, struct ref *refs,
222 + struct ref **fetched_refs);
223 void transport_unlock_pack(struct transport *transport);
224 int transport_disconnect(struct transport *transport);
225 char *transport_anonymize_url(const char *url);