|
19 | 19 | #include "argv-array.h" |
20 | 20 | #include "utf8.h" |
21 | 21 | #include "packfile.h" |
| 22 | +#include "list-objects-filter-options.h" |
22 | 23 |
|
23 | 24 | static const char * const builtin_fetch_usage[] = { |
24 | 25 | N_("git fetch [<options>] [<repository> [<refspec>...]]"), |
@@ -56,6 +57,7 @@ static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND; |
56 | 57 | static int shown_url = 0; |
57 | 58 | static int refmap_alloc, refmap_nr; |
58 | 59 | static const char **refmap_array; |
| 60 | +static struct list_objects_filter_options filter_options; |
59 | 61 |
|
60 | 62 | static int git_fetch_config(const char *k, const char *v, void *cb) |
61 | 63 | { |
@@ -161,6 +163,7 @@ static struct option builtin_fetch_options[] = { |
161 | 163 | TRANSPORT_FAMILY_IPV4), |
162 | 164 | OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), |
163 | 165 | TRANSPORT_FAMILY_IPV6), |
| 166 | + OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options), |
164 | 167 | OPT_END() |
165 | 168 | }; |
166 | 169 |
|
@@ -1045,6 +1048,11 @@ static struct transport *prepare_transport(struct remote *remote, int deepen) |
1045 | 1048 | set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, "yes"); |
1046 | 1049 | if (update_shallow) |
1047 | 1050 | set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes"); |
| 1051 | + if (filter_options.choice) { |
| 1052 | + set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER, |
| 1053 | + filter_options.filter_spec); |
| 1054 | + set_option(transport, TRANS_OPT_FROM_PROMISOR, "1"); |
| 1055 | + } |
1048 | 1056 | return transport; |
1049 | 1057 | } |
1050 | 1058 |
|
@@ -1265,6 +1273,56 @@ static int fetch_multiple(struct string_list *list) |
1265 | 1273 | return result; |
1266 | 1274 | } |
1267 | 1275 |
|
| 1276 | +/* |
| 1277 | + * Fetching from the promisor remote should use the given filter-spec |
| 1278 | + * or inherit the default filter-spec from the config. |
| 1279 | + */ |
| 1280 | +static inline void fetch_one_setup_partial(struct remote *remote) |
| 1281 | +{ |
| 1282 | + /* |
| 1283 | + * Explicit --no-filter argument overrides everything, regardless |
| 1284 | + * of any prior partial clones and fetches. |
| 1285 | + */ |
| 1286 | + if (filter_options.no_filter) |
| 1287 | + return; |
| 1288 | + |
| 1289 | + /* |
| 1290 | + * If no prior partial clone/fetch and the current fetch DID NOT |
| 1291 | + * request a partial-fetch, do a normal fetch. |
| 1292 | + */ |
| 1293 | + if (!repository_format_partial_clone && !filter_options.choice) |
| 1294 | + return; |
| 1295 | + |
| 1296 | + /* |
| 1297 | + * If this is the FIRST partial-fetch request, we enable partial |
| 1298 | + * on this repo and remember the given filter-spec as the default |
| 1299 | + * for subsequent fetches to this remote. |
| 1300 | + */ |
| 1301 | + if (!repository_format_partial_clone && filter_options.choice) { |
| 1302 | + partial_clone_register(remote->name, &filter_options); |
| 1303 | + return; |
| 1304 | + } |
| 1305 | + |
| 1306 | + /* |
| 1307 | + * We are currently limited to only ONE promisor remote and only |
| 1308 | + * allow partial-fetches from the promisor remote. |
| 1309 | + */ |
| 1310 | + if (strcmp(remote->name, repository_format_partial_clone)) { |
| 1311 | + if (filter_options.choice) |
| 1312 | + die(_("--filter can only be used with the remote configured in core.partialClone")); |
| 1313 | + return; |
| 1314 | + } |
| 1315 | + |
| 1316 | + /* |
| 1317 | + * Do a partial-fetch from the promisor remote using either the |
| 1318 | + * explicitly given filter-spec or inherit the filter-spec from |
| 1319 | + * the config. |
| 1320 | + */ |
| 1321 | + if (!filter_options.choice) |
| 1322 | + partial_clone_get_default_filter_spec(&filter_options); |
| 1323 | + return; |
| 1324 | +} |
| 1325 | + |
1268 | 1326 | static int fetch_one(struct remote *remote, int argc, const char **argv) |
1269 | 1327 | { |
1270 | 1328 | static const char **refs = NULL; |
@@ -1320,12 +1378,14 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) |
1320 | 1378 | { |
1321 | 1379 | int i; |
1322 | 1380 | struct string_list list = STRING_LIST_INIT_DUP; |
1323 | | - struct remote *remote; |
| 1381 | + struct remote *remote = NULL; |
1324 | 1382 | int result = 0; |
1325 | 1383 | struct argv_array argv_gc_auto = ARGV_ARRAY_INIT; |
1326 | 1384 |
|
1327 | 1385 | packet_trace_identity("fetch"); |
1328 | 1386 |
|
| 1387 | + fetch_if_missing = 0; |
| 1388 | + |
1329 | 1389 | /* Record the command line for the reflog */ |
1330 | 1390 | strbuf_addstr(&default_rla, "fetch"); |
1331 | 1391 | for (i = 1; i < argc; i++) |
@@ -1359,38 +1419,49 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) |
1359 | 1419 | if (depth || deepen_since || deepen_not.nr) |
1360 | 1420 | deepen = 1; |
1361 | 1421 |
|
| 1422 | + if (filter_options.choice && !repository_format_partial_clone) |
| 1423 | + die("--filter can only be used when extensions.partialClone is set"); |
| 1424 | + |
1362 | 1425 | if (all) { |
1363 | 1426 | if (argc == 1) |
1364 | 1427 | die(_("fetch --all does not take a repository argument")); |
1365 | 1428 | else if (argc > 1) |
1366 | 1429 | die(_("fetch --all does not make sense with refspecs")); |
1367 | 1430 | (void) for_each_remote(get_one_remote_for_fetch, &list); |
1368 | | - result = fetch_multiple(&list); |
1369 | 1431 | } else if (argc == 0) { |
1370 | 1432 | /* No arguments -- use default remote */ |
1371 | 1433 | remote = remote_get(NULL); |
1372 | | - result = fetch_one(remote, argc, argv); |
1373 | 1434 | } else if (multiple) { |
1374 | 1435 | /* All arguments are assumed to be remotes or groups */ |
1375 | 1436 | for (i = 0; i < argc; i++) |
1376 | 1437 | if (!add_remote_or_group(argv[i], &list)) |
1377 | 1438 | die(_("No such remote or remote group: %s"), argv[i]); |
1378 | | - result = fetch_multiple(&list); |
1379 | 1439 | } else { |
1380 | 1440 | /* Single remote or group */ |
1381 | 1441 | (void) add_remote_or_group(argv[0], &list); |
1382 | 1442 | if (list.nr > 1) { |
1383 | 1443 | /* More than one remote */ |
1384 | 1444 | if (argc > 1) |
1385 | 1445 | die(_("Fetching a group and specifying refspecs does not make sense")); |
1386 | | - result = fetch_multiple(&list); |
1387 | 1446 | } else { |
1388 | 1447 | /* Zero or one remotes */ |
1389 | 1448 | remote = remote_get(argv[0]); |
1390 | | - result = fetch_one(remote, argc-1, argv+1); |
| 1449 | + argc--; |
| 1450 | + argv++; |
1391 | 1451 | } |
1392 | 1452 | } |
1393 | 1453 |
|
| 1454 | + if (remote) { |
| 1455 | + if (filter_options.choice || repository_format_partial_clone) |
| 1456 | + fetch_one_setup_partial(remote); |
| 1457 | + result = fetch_one(remote, argc, argv); |
| 1458 | + } else { |
| 1459 | + if (filter_options.choice) |
| 1460 | + die(_("--filter can only be used with the remote configured in core.partialClone")); |
| 1461 | + /* TODO should this also die if we have a previous partial-clone? */ |
| 1462 | + result = fetch_multiple(&list); |
| 1463 | + } |
| 1464 | + |
1394 | 1465 | if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) { |
1395 | 1466 | struct argv_array options = ARGV_ARRAY_INIT; |
1396 | 1467 |
|
|
0 commit comments