1818#include "pack-bitmap.h"
1919#include "refs.h"
2020
21+ #define ALL_INTO_ONE 1
22+ #define LOOSEN_UNREACHABLE 2
23+ #define PACK_CRUFT 4
24+
25+ static int pack_everything ;
2126static int delta_base_offset = 1 ;
2227static int pack_kept_objects = -1 ;
2328static int write_bitmaps = -1 ;
2429static int use_delta_islands ;
2530static char * packdir , * packtmp_name , * packtmp ;
31+ static char * cruft_expiration ;
2632
2733static const char * const git_repack_usage [] = {
2834 N_ ("git repack [<options>]" ),
@@ -54,6 +60,7 @@ static int repack_config(const char *var, const char *value, void *cb)
5460 use_delta_islands = git_config_bool (var , value );
5561 return 0 ;
5662 }
63+
5764 return git_default_config (var , value , cb );
5865}
5966
@@ -300,9 +307,6 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
300307 die (_ ("could not finish pack-objects to repack promisor objects" ));
301308}
302309
303- #define ALL_INTO_ONE 1
304- #define LOOSEN_UNREACHABLE 2
305-
306310struct pack_geometry {
307311 struct packed_git * * pack ;
308312 uint32_t pack_nr , pack_alloc ;
@@ -339,6 +343,8 @@ static void init_pack_geometry(struct pack_geometry **geometry_p)
339343 for (p = get_all_packs (the_repository ); p ; p = p -> next ) {
340344 if (!pack_kept_objects && p -> pack_keep )
341345 continue ;
346+ if (p -> is_cruft )
347+ continue ;
342348
343349 ALLOC_GROW (geometry -> pack ,
344350 geometry -> pack_nr + 1 ,
@@ -600,6 +606,67 @@ static int write_midx_included_packs(struct string_list *include,
600606 return finish_command (& cmd );
601607}
602608
609+ static int write_cruft_pack (const struct pack_objects_args * args ,
610+ const char * pack_prefix ,
611+ struct string_list * names ,
612+ struct string_list * existing_packs ,
613+ struct string_list * existing_kept_packs )
614+ {
615+ struct child_process cmd = CHILD_PROCESS_INIT ;
616+ struct strbuf line = STRBUF_INIT ;
617+ struct string_list_item * item ;
618+ FILE * in , * out ;
619+ int ret ;
620+
621+ prepare_pack_objects (& cmd , args );
622+
623+ strvec_push (& cmd .args , "--cruft" );
624+ if (cruft_expiration )
625+ strvec_pushf (& cmd .args , "--cruft-expiration=%s" ,
626+ cruft_expiration );
627+
628+ strvec_push (& cmd .args , "--honor-pack-keep" );
629+ strvec_push (& cmd .args , "--non-empty" );
630+ strvec_push (& cmd .args , "--max-pack-size=0" );
631+
632+ cmd .in = -1 ;
633+
634+ ret = start_command (& cmd );
635+ if (ret )
636+ return ret ;
637+
638+ /*
639+ * names has a confusing double use: it both provides the list
640+ * of just-written new packs, and accepts the name of the cruft
641+ * pack we are writing.
642+ *
643+ * By the time it is read here, it contains only the pack(s)
644+ * that were just written, which is exactly the set of packs we
645+ * want to consider kept.
646+ */
647+ in = xfdopen (cmd .in , "w" );
648+ for_each_string_list_item (item , names )
649+ fprintf (in , "%s-%s.pack\n" , pack_prefix , item -> string );
650+ for_each_string_list_item (item , existing_packs )
651+ fprintf (in , "-%s.pack\n" , item -> string );
652+ for_each_string_list_item (item , existing_kept_packs )
653+ fprintf (in , "%s.pack\n" , item -> string );
654+ fclose (in );
655+
656+ out = xfdopen (cmd .out , "r" );
657+ while (strbuf_getline_lf (& line , out ) != EOF ) {
658+ if (line .len != the_hash_algo -> hexsz )
659+ die (_ ("repack: Expecting full hex object ID lines only "
660+ "from pack-objects." ));
661+ string_list_append (names , line .buf );
662+ }
663+ fclose (out );
664+
665+ strbuf_release (& line );
666+
667+ return finish_command (& cmd );
668+ }
669+
603670int cmd_repack (int argc , const char * * argv , const char * prefix )
604671{
605672 struct child_process cmd = CHILD_PROCESS_INIT ;
@@ -616,7 +683,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
616683 int show_progress ;
617684
618685 /* variables to be filled by option parsing */
619- int pack_everything = 0 ;
620686 int delete_redundant = 0 ;
621687 const char * unpack_unreachable = NULL ;
622688 int keep_unreachable = 0 ;
@@ -632,6 +698,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
632698 OPT_BIT ('A' , NULL , & pack_everything ,
633699 N_ ("same as -a, and turn unreachable objects loose" ),
634700 LOOSEN_UNREACHABLE | ALL_INTO_ONE ),
701+ OPT_BIT (0 , "cruft" , & pack_everything ,
702+ N_ ("same as -a, pack unreachable cruft objects separately" ),
703+ PACK_CRUFT ),
704+ OPT_STRING (0 , "cruft-expiration" , & cruft_expiration , N_ ("approxidate" ),
705+ N_ ("with -C, expire objects older than this" )),
635706 OPT_BOOL ('d' , NULL , & delete_redundant ,
636707 N_ ("remove redundant packs, and run git-prune-packed" )),
637708 OPT_BOOL ('f' , NULL , & po_args .no_reuse_delta ,
@@ -684,6 +755,15 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
684755 (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE )))
685756 die (_ ("options '%s' and '%s' cannot be used together" ), "--keep-unreachable" , "-A" );
686757
758+ if (pack_everything & PACK_CRUFT ) {
759+ pack_everything |= ALL_INTO_ONE ;
760+
761+ if (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE ))
762+ die (_ ("options '%s' and '%s' cannot be used together" ), "--cruft" , "-A" );
763+ if (keep_unreachable )
764+ die (_ ("options '%s' and '%s' cannot be used together" ), "--cruft" , "-k" );
765+ }
766+
687767 if (write_bitmaps < 0 ) {
688768 if (!write_midx &&
689769 (!(pack_everything & ALL_INTO_ONE ) || !is_bare_repository ()))
@@ -767,7 +847,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
767847 if (pack_everything & ALL_INTO_ONE ) {
768848 repack_promisor_objects (& po_args , & names );
769849
770- if (existing_nonkept_packs .nr && delete_redundant ) {
850+ if (existing_nonkept_packs .nr && delete_redundant &&
851+ !(pack_everything & PACK_CRUFT )) {
771852 for_each_string_list_item (item , & names ) {
772853 strvec_pushf (& cmd .args , "--keep-pack=%s-%s.pack" ,
773854 packtmp_name , item -> string );
@@ -829,6 +910,21 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
829910 if (!names .nr && !po_args .quiet )
830911 printf_ln (_ ("Nothing new to pack." ));
831912
913+ if (pack_everything & PACK_CRUFT ) {
914+ const char * pack_prefix ;
915+ if (!skip_prefix (packtmp , packdir , & pack_prefix ))
916+ die (_ ("pack prefix %s does not begin with objdir %s" ),
917+ packtmp , packdir );
918+ if (* pack_prefix == '/' )
919+ pack_prefix ++ ;
920+
921+ ret = write_cruft_pack (& po_args , pack_prefix , & names ,
922+ & existing_nonkept_packs ,
923+ & existing_kept_packs );
924+ if (ret )
925+ return ret ;
926+ }
927+
832928 for_each_string_list_item (item , & names ) {
833929 item -> util = (void * )(uintptr_t )populate_pack_exts (item -> string );
834930 }
0 commit comments