fetch: add --refetch option

Teach fetch and transports the --refetch option to force a full fetch without negotiating common commits with the remote. Use when applying a new partial clone filter to refetch all matching objects. 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 3c7bab06e12922fbcb375187eb60ac426fc72a3a
5 files changed +34 -1
Documentation/fetch-options.txt
+9
@@ -163,6 +163,15 @@ endif::git-pull[]
163 behavior for a remote may be specified with the remote.<name>.tagOpt
164 setting. See linkgit:git-config[1].
165
166 +ifndef::git-pull[]
167 +--refetch::
168 + Instead of negotiating with the server to avoid transferring commits and
169 + associated objects that are already present locally, this option fetches
170 + all objects as a fresh clone would. Use this to reapply a partial clone
171 + filter from configuration or using `--filter=` when the filter
172 + definition has changed.
173 +endif::git-pull[]
174 +
175 --refmap=<refspec>::
176 When fetching refs listed on the command line, use the
177 specified refspec (can be given more than once) to map the
builtin/fetch.c
+14 -1
@@ -59,7 +59,7 @@ static int prune_tags = -1; /* unspecified */
59
60 static int all, append, dry_run, force, keep, multiple, update_head_ok;
61 static int write_fetch_head = 1;
62 -static int verbosity, deepen_relative, set_upstream;
62 +static int verbosity, deepen_relative, set_upstream, refetch;
63 static int progress = -1;
64 static int enable_auto_gc = 1;
65 static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
@@ -190,6 +190,9 @@ static struct option builtin_fetch_options[] = {
190 OPT_SET_INT_F(0, "unshallow", &unshallow,
191 N_("convert to a complete repository"),
192 1, PARSE_OPT_NONEG),
193 + OPT_SET_INT_F(0, "refetch", &refetch,
194 + N_("re-fetch without negotiating common commits"),
195 + 1, PARSE_OPT_NONEG),
196 { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
197 N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
198 OPT_CALLBACK_F(0, "recurse-submodules-default",
@@ -1296,6 +1299,14 @@ static int check_exist_and_connected(struct ref *ref_map)
1299 if (deepen)
1300 return -1;
1301
1302 + /*
1303 + * Similarly, if we need to refetch, we always want to perform a full
1304 + * fetch ignoring existing objects.
1305 + */
1306 + if (refetch)
1307 + return -1;
1308 +
1309 +
1310 /*
1311 * check_connected() allows objects to merely be promised, but
1312 * we need all direct targets to exist.
@@ -1492,6 +1503,8 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
1503 set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, "yes");
1504 if (update_shallow)
1505 set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
1506 + if (refetch)
1507 + set_option(transport, TRANS_OPT_REFETCH, "yes");
1508 if (filter_options.choice) {
1509 const char *spec =
1510 expand_list_objects_filter_spec(&filter_options);
transport-helper.c
+3
@@ -715,6 +715,9 @@ static int fetch_refs(struct transport *transport,
715 if (data->transport_options.update_shallow)
716 set_helper_option(transport, "update-shallow", "true");
717
718 + if (data->transport_options.refetch)
719 + set_helper_option(transport, "refetch", "true");
720 +
721 if (data->transport_options.filter_options.choice) {
722 const char *spec = expand_list_objects_filter_spec(
723 &data->transport_options.filter_options);
transport.c
+4
@@ -243,6 +243,9 @@ static int set_git_option(struct git_transport_options *opts,
243 list_objects_filter_die_if_populated(&opts->filter_options);
244 parse_list_objects_filter(&opts->filter_options, value);
245 return 0;
246 + } else if (!strcmp(name, TRANS_OPT_REFETCH)) {
247 + opts->refetch = !!value;
248 + return 0;
249 } else if (!strcmp(name, TRANS_OPT_REJECT_SHALLOW)) {
250 opts->reject_shallow = !!value;
251 return 0;
@@ -377,6 +380,7 @@ static int fetch_refs_via_pack(struct transport *transport,
380 args.update_shallow = data->options.update_shallow;
381 args.from_promisor = data->options.from_promisor;
382 args.filter_options = data->options.filter_options;
383 + args.refetch = data->options.refetch;
384 args.stateless_rpc = transport->stateless_rpc;
385 args.server_options = transport->server_options;
386 args.negotiation_tips = data->options.negotiation_tips;
transport.h
+4
@@ -16,6 +16,7 @@ struct git_transport_options {
16 unsigned update_shallow : 1;
17 unsigned reject_shallow : 1;
18 unsigned deepen_relative : 1;
19 + unsigned refetch : 1;
20
21 /* see documentation of corresponding flag in fetch-pack.h */
22 unsigned from_promisor : 1;
@@ -216,6 +217,9 @@ void transport_check_allowed(const char *type);
217 /* Filter objects for partial clone and fetch */
218 #define TRANS_OPT_LIST_OBJECTS_FILTER "filter"
219
220 +/* Refetch all objects without negotiating */
221 +#define TRANS_OPT_REFETCH "refetch"
222 +
223 /* Request atomic (all-or-nothing) updates when pushing */
224 #define TRANS_OPT_ATOMIC "atomic"
225