Skip to content

Commit 1674d48

Browse files
committed
fetch: implement --packfile-report
Signed-off-by: Vicent Marti <vmg@strn.cat>
1 parent c69baaf commit 1674d48

2 files changed

Lines changed: 206 additions & 19 deletions

File tree

builtin/fetch.c

Lines changed: 159 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
#include "bundle-uri.h"
4444

4545
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
46-
4746
static const char * const builtin_fetch_usage[] = {
4847
N_("git fetch [<options>] [<repository> [<refspec>...]]"),
4948
N_("git fetch [<options>] <group>"),
@@ -88,6 +87,8 @@ static int verbosity, deepen_relative, set_upstream, refetch;
8887
static int progress = -1;
8988
static int tags = TAGS_DEFAULT, update_shallow, deepen;
9089
static int atomic_fetch;
90+
static int packfile_report;
91+
static int prune_missing_refspecs;
9192
static enum transport_family family;
9293
static const char *depth;
9394
static const char *deepen_since;
@@ -482,6 +483,16 @@ static void filter_prefetch_refspec(struct refspec *rs)
482483
}
483484
}
484485

486+
static int refspec_allows_missing_for_prune(const struct refspec_item *item)
487+
{
488+
return prune_missing_refspecs &&
489+
prune &&
490+
item->dst && item->dst[0] &&
491+
!item->pattern &&
492+
!item->negative &&
493+
!item->exact_sha1;
494+
}
495+
485496
static struct ref *get_ref_map(struct remote *remote,
486497
const struct ref *remote_refs,
487498
struct refspec *rs,
@@ -506,7 +517,8 @@ static struct ref *get_ref_map(struct remote *remote,
506517
struct refspec *fetch_refspec;
507518

508519
for (i = 0; i < rs->nr; i++) {
509-
get_fetch_map(remote_refs, &rs->items[i], &tail, 0);
520+
get_fetch_map(remote_refs, &rs->items[i], &tail,
521+
refspec_allows_missing_for_prune(&rs->items[i]));
510522
if (rs->items[i].dst && rs->items[i].dst[0])
511523
*autotags = 1;
512524
}
@@ -552,7 +564,8 @@ static struct ref *get_ref_map(struct remote *remote,
552564
/* Note: has_merge implies non-NULL branch->remote_name */
553565
(has_merge && !strcmp(branch->remote_name, remote->name)))) {
554566
for (i = 0; i < remote->fetch.nr; i++) {
555-
get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0);
567+
get_fetch_map(remote_refs, &remote->fetch.items[i], &tail,
568+
refspec_allows_missing_for_prune(&remote->fetch.items[i]));
556569
if (remote->fetch.items[i].dst &&
557570
remote->fetch.items[i].dst[0])
558571
*autotags = 1;
@@ -879,6 +892,86 @@ struct ref_update_display_info_array {
879892
size_t alloc, nr;
880893
};
881894

895+
struct packfile_report_pack {
896+
char *pack_path;
897+
};
898+
899+
struct packfile_report {
900+
struct packfile_report_pack *packs;
901+
size_t packs_alloc, packs_nr;
902+
};
903+
904+
static void packfile_report_init(struct packfile_report *report)
905+
{
906+
memset(report, 0, sizeof(*report));
907+
}
908+
909+
static void packfile_report_release(struct packfile_report *report)
910+
{
911+
size_t i;
912+
913+
for (i = 0; i < report->packs_nr; i++) {
914+
free(report->packs[i].pack_path);
915+
}
916+
free(report->packs);
917+
}
918+
919+
static int packfile_report_add_pack(struct packfile_report *report,
920+
const char *keep_path)
921+
{
922+
const char *filename;
923+
size_t base_len;
924+
struct packfile_report_pack *pack;
925+
struct strbuf base_path = STRBUF_INIT;
926+
struct strbuf pack_path = STRBUF_INIT;
927+
928+
if (!report || !strip_suffix(keep_path, ".keep", &base_len))
929+
return 0;
930+
931+
strbuf_add(&base_path, keep_path, base_len);
932+
strbuf_addbuf(&pack_path, &base_path);
933+
strbuf_addstr(&pack_path, ".pack");
934+
935+
filename = strrchr(base_path.buf, '/');
936+
filename = filename ? filename + 1 : base_path.buf;
937+
if (!starts_with(filename, "pack-")) {
938+
strbuf_release(&base_path);
939+
strbuf_release(&pack_path);
940+
return error(_("unexpected pack keepfile name '%s'"), keep_path);
941+
}
942+
943+
ALLOC_GROW(report->packs, report->packs_nr + 1, report->packs_alloc);
944+
pack = &report->packs[report->packs_nr++];
945+
pack->pack_path = strbuf_detach(&pack_path, NULL);
946+
947+
strbuf_release(&base_path);
948+
return 0;
949+
}
950+
951+
static int packfile_report_add_pack_lockfiles(struct packfile_report *report,
952+
struct transport *transport)
953+
{
954+
size_t i;
955+
956+
if (!report)
957+
return 0;
958+
959+
for (i = 0; i < transport->pack_lockfiles.nr; i++)
960+
if (packfile_report_add_pack(report,
961+
transport->pack_lockfiles.items[i].string))
962+
return -1;
963+
964+
return 0;
965+
}
966+
967+
static void packfile_report_print(const struct packfile_report *report)
968+
{
969+
size_t i;
970+
971+
for (i = 0; i < report->packs_nr; i++)
972+
printf("p %s\n", report->packs[i].pack_path);
973+
}
974+
882975
static struct ref_update_display_info *ref_update_display_info_append(
883976
struct ref_update_display_info_array *array,
884977
char success_code,
@@ -1332,7 +1425,7 @@ static int store_updated_refs(struct display_state *display_state,
13321425
rc |= update_local_ref(ref, transaction, rm,
13331426
config, display_array);
13341427
free(ref);
1335-
} else if (write_fetch_head || dry_run) {
1428+
} else if (!packfile_report && (write_fetch_head || dry_run)) {
13361429
/*
13371430
* Display fetches written to FETCH_HEAD (or
13381431
* would be written to FETCH_HEAD, if --dry-run
@@ -1412,7 +1505,8 @@ static int fetch_and_consume_refs(struct display_state *display_state,
14121505
struct ref *ref_map,
14131506
struct fetch_head *fetch_head,
14141507
const struct fetch_config *config,
1415-
struct ref_update_display_info_array *display_array)
1508+
struct ref_update_display_info_array *display_array,
1509+
struct packfile_report *report)
14161510
{
14171511
int connectivity_checked = 1;
14181512
int ret;
@@ -1439,6 +1533,8 @@ static int fetch_and_consume_refs(struct display_state *display_state,
14391533
trace2_region_leave("fetch", "consume_refs", the_repository);
14401534

14411535
out:
1536+
if (!ret && packfile_report_add_pack_lockfiles(report, transport))
1537+
ret = -1;
14421538
transport_unlock_pack(transport, 0);
14431539
return ret;
14441540
}
@@ -1657,7 +1753,8 @@ static int backfill_tags(struct display_state *display_state,
16571753
struct fetch_head *fetch_head,
16581754
const struct fetch_config *config,
16591755
struct ref_update_display_info_array *display_array,
1660-
struct list_objects_filter_options *filter_options)
1756+
struct list_objects_filter_options *filter_options,
1757+
struct packfile_report *report)
16611758
{
16621759
int retcode, cannot_reuse;
16631760

@@ -1679,7 +1776,7 @@ static int backfill_tags(struct display_state *display_state,
16791776
transport_set_option(transport, TRANS_OPT_DEPTH, "0");
16801777
transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
16811778
retcode = fetch_and_consume_refs(display_state, transport, transaction, ref_map,
1682-
fetch_head, config, display_array);
1779+
fetch_head, config, display_array, report);
16831780

16841781
if (gsecondary) {
16851782
transport_disconnect(gsecondary);
@@ -1900,8 +1997,12 @@ static int do_fetch(struct transport *transport,
19001997
int do_set_head = 0;
19011998
struct ref_update_display_info_array display_array = { 0 };
19021999
struct strmap rejected_refs = STRMAP_INIT;
2000+
struct packfile_report report;
19032001
int summary_width = 0;
19042002

2003+
if (packfile_report)
2004+
packfile_report_init(&report);
2005+
19052006
if (tags == TAGS_DEFAULT) {
19062007
if (transport->remote->fetch_tags == 2)
19072008
tags = TAGS_SET;
@@ -1979,7 +2080,7 @@ static int do_fetch(struct transport *transport,
19792080
display_state_init(&display_state, ref_map, transport->url,
19802081
config->display_format);
19812082

1982-
if (atomic_fetch) {
2083+
if (atomic_fetch && !packfile_report) {
19832084
transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
19842085
0, &err);
19852086
if (!transaction) {
@@ -2015,7 +2116,7 @@ static int do_fetch(struct transport *transport,
20152116
* can delete and create refs (with F/D conflicts) in the same transaction
20162117
* and this can be moved above the 'prune_refs()' block.
20172118
*/
2018-
if (!transaction) {
2119+
if (!transaction && !packfile_report) {
20192120
transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
20202121
REF_TRANSACTION_ALLOW_FAILURE, &err);
20212122
if (!transaction) {
@@ -2025,7 +2126,8 @@ static int do_fetch(struct transport *transport,
20252126
}
20262127

20272128
if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map,
2028-
&fetch_head, config, &display_array)) {
2129+
&fetch_head, config, &display_array,
2130+
packfile_report ? &report : NULL)) {
20292131
retcode = 1;
20302132
goto cleanup;
20312133
}
@@ -2048,7 +2150,8 @@ static int do_fetch(struct transport *transport,
20482150
* the transaction and don't commit anything.
20492151
*/
20502152
if (backfill_tags(&display_state, transport, transaction, tags_ref_map,
2051-
&fetch_head, config, &display_array, filter_options))
2153+
&fetch_head, config, &display_array, filter_options,
2154+
packfile_report ? &report : NULL))
20522155
retcode = 1;
20532156
}
20542157

@@ -2061,19 +2164,21 @@ static int do_fetch(struct transport *transport,
20612164
if (verbosity >= 0)
20622165
summary_width = transport_summary_width(ref_map);
20632166

2064-
retcode = commit_ref_transaction(&transaction, atomic_fetch,
2065-
transport->remote->name,
2066-
&rejected_refs, &err);
2167+
if (!packfile_report)
2168+
retcode = commit_ref_transaction(&transaction, atomic_fetch,
2169+
transport->remote->name,
2170+
&rejected_refs, &err);
20672171
/*
20682172
* With '--atomic', bail out if the transaction fails. Without '--atomic',
20692173
* continue to fetch head and perform other post-fetch operations.
20702174
*/
20712175
if (retcode && atomic_fetch)
20722176
goto cleanup;
20732177

2074-
commit_fetch_head(&fetch_head);
2178+
if (!packfile_report)
2179+
commit_fetch_head(&fetch_head);
20752180

2076-
if (set_upstream) {
2181+
if (!packfile_report && set_upstream) {
20772182
struct branch *branch = branch_get("HEAD");
20782183
struct ref *rm;
20792184
struct ref *source_ref = NULL;
@@ -2126,7 +2231,7 @@ static int do_fetch(struct transport *transport,
21262231
"you need to specify exactly one branch with the --set-upstream option"));
21272232
}
21282233
}
2129-
if (do_set_head) {
2234+
if (do_set_head && !packfile_report) {
21302235
/*
21312236
* Way too many cases where this can go wrong so let's just
21322237
* ignore errors and fail silently for now.
@@ -2139,7 +2244,7 @@ static int do_fetch(struct transport *transport,
21392244
* When using batched updates, we want to commit the non-rejected
21402245
* updates and also handle the rejections.
21412246
*/
2142-
if (retcode && !atomic_fetch && transaction)
2247+
if (retcode && !atomic_fetch && transaction && !packfile_report)
21432248
commit_ref_transaction(&transaction, false,
21442249
transport->remote->name,
21452250
&rejected_refs, &err);
@@ -2153,6 +2258,9 @@ static int do_fetch(struct transport *transport,
21532258
ref_update_display_info_free(info);
21542259
}
21552260

2261+
if (packfile_report)
2262+
packfile_report_print(&report);
2263+
21562264
if (retcode) {
21572265
if (err.len) {
21582266
error("%s", err.buf);
@@ -2168,6 +2276,8 @@ static int do_fetch(struct transport *transport,
21682276
ref_transaction_free(transaction);
21692277

21702278
free(display_array.info);
2279+
if (packfile_report)
2280+
packfile_report_release(&report);
21712281
strmap_clear(&rejected_refs, 0);
21722282
display_state_release(&display_state);
21732283
close_fetch_head(&fetch_head);
@@ -2455,6 +2565,9 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
24552565
prune = PRUNE_BY_DEFAULT;
24562566
}
24572567

2568+
if (prune_missing_refspecs && !prune)
2569+
die(_("--prune-missing-refspecs requires --prune"));
2570+
24582571
if (prune_tags < 0) {
24592572
/* no command line request */
24602573
if (0 <= remote->prune_tags)
@@ -2629,6 +2742,12 @@ int cmd_fetch(int argc,
26292742
N_("write the commit-graph after fetching")),
26302743
OPT_BOOL(0, "stdin", &stdin_refspecs,
26312744
N_("accept refspecs from stdin")),
2745+
OPT_BOOL_F(0, "packfile-report", &packfile_report,
2746+
N_("download packs and report pack paths without updating refs"),
2747+
PARSE_OPT_HIDDEN),
2748+
OPT_BOOL_F(0, "prune-missing-refspecs", &prune_missing_refspecs,
2749+
N_("allow missing exact source refspecs to be pruned"),
2750+
PARSE_OPT_HIDDEN),
26322751
OPT_END()
26332752
};
26342753

@@ -2658,6 +2777,23 @@ int cmd_fetch(int argc,
26582777
if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
26592778
config.recurse_submodules = recurse_submodules_cli;
26602779

2780+
if (packfile_report) {
2781+
dry_run = 1;
2782+
porcelain = 1;
2783+
write_fetch_head = 0;
2784+
keep = 1;
2785+
enable_auto_gc = 0;
2786+
fetch_write_commit_graph = 0;
2787+
config.recurse_submodules = RECURSE_SUBMODULES_OFF;
2788+
if (set_upstream)
2789+
die(_("options '%s' and '%s' cannot be used together"),
2790+
"--packfile-report", "--set-upstream");
2791+
if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT &&
2792+
recurse_submodules_cli != RECURSE_SUBMODULES_OFF)
2793+
die(_("options '%s' and '%s' cannot be used together"),
2794+
"--packfile-report", "--recurse-submodules");
2795+
}
2796+
26612797
if (negotiate_only) {
26622798
switch (recurse_submodules_cli) {
26632799
case RECURSE_SUBMODULES_OFF:
@@ -2734,7 +2870,8 @@ int cmd_fetch(int argc,
27342870
if (!max_jobs)
27352871
max_jobs = online_cpus();
27362872

2737-
if (!repo_config_get_string_tmp(the_repository, "fetch.bundleuri", &bundle_uri) &&
2873+
if (!packfile_report &&
2874+
!repo_config_get_string_tmp(the_repository, "fetch.bundleuri", &bundle_uri) &&
27382875
fetch_bundle_uri(the_repository, bundle_uri, NULL))
27392876
warning(_("failed to fetch bundles from '%s'"), bundle_uri);
27402877

@@ -2783,6 +2920,9 @@ int cmd_fetch(int argc,
27832920
}
27842921
string_list_remove_duplicates(&list, 0);
27852922

2923+
if (packfile_report && (all || multiple || !remote))
2924+
die(_("--packfile-report can only be used when fetching from one remote"));
2925+
27862926
if (negotiate_only) {
27872927
struct oidset acked_commits = OIDSET_INIT;
27882928
struct oidset_iter iter;

0 commit comments

Comments
 (0)