4343#include "bundle-uri.h"
4444
4545#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
46-
4746static 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;
8887static int progress = -1 ;
8988static int tags = TAGS_DEFAULT , update_shallow , deepen ;
9089static int atomic_fetch ;
90+ static int packfile_report ;
91+ static int prune_missing_refspecs ;
9192static enum transport_family family ;
9293static const char * depth ;
9394static 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+
485496static 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+
882975static 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
14411535out :
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