fetch-pack: add refetch

Allow a "refetch" where the contents of the local object store are ignored and a full fetch is performed, not attempting to find or negotiate common commits with the remote. A key use case is to apply a new partial clone blob/tree filter and refetch all the associated matching content, which would otherwise not be transferred when the commit objects are already present locally. Signed-off-by: Robert Coup <robert@coup.net.nz> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Robert Coup committed Mar 28, 2022 at 14:02 UTC 4dfd0925cbba78cc737e3af29faa5774bbc7b6a3
2 files changed +30 -17
fetch-pack.c
+29 -17
@@ -312,19 +312,21 @@ static int find_common(struct fetch_negotiator *negotiator,
312 const char *remote_hex;
313 struct object *o;
314
315 - /*
316 - * If that object is complete (i.e. it is an ancestor of a
317 - * local ref), we tell them we have it but do not have to
318 - * tell them about its ancestors, which they already know
319 - * about.
320 - *
321 - * We use lookup_object here because we are only
322 - * interested in the case we *know* the object is
323 - * reachable and we have already scanned it.
324 - */
325 - if (((o = lookup_object(the_repository, remote)) != NULL) &&
326 - (o->flags & COMPLETE)) {
327 - continue;
315 + if (!args->refetch) {
316 + /*
317 + * If that object is complete (i.e. it is an ancestor of a
318 + * local ref), we tell them we have it but do not have to
319 + * tell them about its ancestors, which they already know
320 + * about.
321 + *
322 + * We use lookup_object here because we are only
323 + * interested in the case we *know* the object is
324 + * reachable and we have already scanned it.
325 + */
326 + if (((o = lookup_object(the_repository, remote)) != NULL) &&
327 + (o->flags & COMPLETE)) {
328 + continue;
329 + }
330 }
331
332 remote_hex = oid_to_hex(remote);
@@ -692,6 +694,9 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
694 int old_save_commit_buffer = save_commit_buffer;
695 timestamp_t cutoff = 0;
696
697 + if (args->refetch)
698 + return;
699 +
700 save_commit_buffer = 0;
701
702 trace2_region_enter("fetch-pack", "parse_remote_refs_and_find_cutoff", NULL);
@@ -1028,7 +1033,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
1033 struct fetch_negotiator *negotiator;
1034
1035 negotiator = &negotiator_alloc;
1031 - fetch_negotiator_init(r, negotiator);
1036 + if (args->refetch) {
1037 + fetch_negotiator_init_noop(negotiator);
1038 + } else {
1039 + fetch_negotiator_init(r, negotiator);
1040 + }
1041
1042 sort_ref_list(&ref, ref_compare_name);
1043 QSORT(sought, nr_sought, cmp_ref_by_name);
@@ -1121,7 +1130,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
1130
1131 mark_complete_and_common_ref(negotiator, args, &ref);
1132 filter_refs(args, &ref, sought, nr_sought);
1124 - if (everything_local(args, &ref)) {
1133 + if (!args->refetch && everything_local(args, &ref)) {
1134 packet_flush(fd[1]);
1135 goto all_done;
1136 }
@@ -1587,7 +1596,10 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1596 struct strvec index_pack_args = STRVEC_INIT;
1597
1598 negotiator = &negotiator_alloc;
1590 - fetch_negotiator_init(r, negotiator);
1599 + if (args->refetch)
1600 + fetch_negotiator_init_noop(negotiator);
1601 + else
1602 + fetch_negotiator_init(r, negotiator);
1603
1604 packet_reader_init(&reader, fd[0], NULL, 0,
1605 PACKET_READ_CHOMP_NEWLINE |
@@ -1613,7 +1625,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1625 /* Filter 'ref' by 'sought' and those that aren't local */
1626 mark_complete_and_common_ref(negotiator, args, &ref);
1627 filter_refs(args, &ref, sought, nr_sought);
1616 - if (everything_local(args, &ref))
1628 + if (!args->refetch && everything_local(args, &ref))
1629 state = FETCH_DONE;
1630 else
1631 state = FETCH_SEND_REQUEST;
fetch-pack.h
+1
@@ -42,6 +42,7 @@ struct fetch_pack_args {
42 unsigned update_shallow:1;
43 unsigned reject_shallow_remote:1;
44 unsigned deepen:1;
45 + unsigned refetch:1;
46
47 /*
48 * Indicate that the remote of this request is a promisor remote. The