36
36
#include "trace2.h"
37
37
#include "shallow.h"
38
38
#include "promisor-remote.h"
39
+ #include "pack-mtimes.h"
39
40
40
41
/*
41
42
* Objects we are going to pack are collected in the `to_pack` structure.
@@ -194,6 +195,8 @@ static int reuse_delta = 1, reuse_object = 1;
194
195
static int keep_unreachable , unpack_unreachable , include_tag ;
195
196
static timestamp_t unpack_unreachable_expiration ;
196
197
static int pack_loose_unreachable ;
198
+ static int cruft ;
199
+ static timestamp_t cruft_expiration ;
197
200
static int local ;
198
201
static int have_non_local_packs ;
199
202
static int incremental ;
@@ -1260,6 +1263,9 @@ static void write_pack_file(void)
1260
1263
& to_pack , written_list , nr_written );
1261
1264
}
1262
1265
1266
+ if (cruft )
1267
+ pack_idx_opts .flags |= WRITE_MTIMES ;
1268
+
1263
1269
stage_tmp_packfiles (& tmpname , pack_tmp_name ,
1264
1270
written_list , nr_written ,
1265
1271
& to_pack , & pack_idx_opts , hash ,
@@ -3397,6 +3403,135 @@ static void read_packs_list_from_stdin(void)
3397
3403
string_list_clear (& exclude_packs , 0 );
3398
3404
}
3399
3405
3406
+ static void add_cruft_object_entry (const struct object_id * oid , enum object_type type ,
3407
+ struct packed_git * pack , off_t offset ,
3408
+ const char * name , uint32_t mtime )
3409
+ {
3410
+ struct object_entry * entry ;
3411
+
3412
+ display_progress (progress_state , ++ nr_seen );
3413
+
3414
+ entry = packlist_find (& to_pack , oid );
3415
+ if (entry ) {
3416
+ if (name ) {
3417
+ entry -> hash = pack_name_hash (name );
3418
+ entry -> no_try_delta = no_try_delta (name );
3419
+ }
3420
+ } else {
3421
+ if (!want_object_in_pack (oid , 0 , & pack , & offset ))
3422
+ return ;
3423
+ if (!pack && type == OBJ_BLOB && !has_loose_object (oid )) {
3424
+ /*
3425
+ * If a traversed tree has a missing blob then we want
3426
+ * to avoid adding that missing object to our pack.
3427
+ *
3428
+ * This only applies to missing blobs, not trees,
3429
+ * because the traversal needs to parse sub-trees but
3430
+ * not blobs.
3431
+ *
3432
+ * Note we only perform this check when we couldn't
3433
+ * already find the object in a pack, so we're really
3434
+ * limited to "ensure non-tip blobs which don't exist in
3435
+ * packs do exist via loose objects". Confused?
3436
+ */
3437
+ return ;
3438
+ }
3439
+
3440
+ entry = create_object_entry (oid , type , pack_name_hash (name ),
3441
+ 0 , name && no_try_delta (name ),
3442
+ pack , offset );
3443
+ }
3444
+
3445
+ if (mtime > oe_cruft_mtime (& to_pack , entry ))
3446
+ oe_set_cruft_mtime (& to_pack , entry , mtime );
3447
+ return ;
3448
+ }
3449
+
3450
+ static void mark_pack_kept_in_core (struct string_list * packs , unsigned keep )
3451
+ {
3452
+ struct string_list_item * item = NULL ;
3453
+ for_each_string_list_item (item , packs ) {
3454
+ struct packed_git * p = item -> util ;
3455
+ if (!p )
3456
+ die (_ ("could not find pack '%s'" ), item -> string );
3457
+ p -> pack_keep_in_core = keep ;
3458
+ }
3459
+ }
3460
+
3461
+ static void add_unreachable_loose_objects (void );
3462
+ static void add_objects_in_unpacked_packs (void );
3463
+
3464
+ static void enumerate_cruft_objects (void )
3465
+ {
3466
+ if (progress )
3467
+ progress_state = start_progress (_ ("Enumerating cruft objects" ), 0 );
3468
+
3469
+ add_objects_in_unpacked_packs ();
3470
+ add_unreachable_loose_objects ();
3471
+
3472
+ stop_progress (& progress_state );
3473
+ }
3474
+
3475
+ static void read_cruft_objects (void )
3476
+ {
3477
+ struct strbuf buf = STRBUF_INIT ;
3478
+ struct string_list discard_packs = STRING_LIST_INIT_DUP ;
3479
+ struct string_list fresh_packs = STRING_LIST_INIT_DUP ;
3480
+ struct packed_git * p ;
3481
+
3482
+ ignore_packed_keep_in_core = 1 ;
3483
+
3484
+ while (strbuf_getline (& buf , stdin ) != EOF ) {
3485
+ if (!buf .len )
3486
+ continue ;
3487
+
3488
+ if (* buf .buf == '-' )
3489
+ string_list_append (& discard_packs , buf .buf + 1 );
3490
+ else
3491
+ string_list_append (& fresh_packs , buf .buf );
3492
+ strbuf_reset (& buf );
3493
+ }
3494
+
3495
+ string_list_sort (& discard_packs );
3496
+ string_list_sort (& fresh_packs );
3497
+
3498
+ for (p = get_all_packs (the_repository ); p ; p = p -> next ) {
3499
+ const char * pack_name = pack_basename (p );
3500
+ struct string_list_item * item ;
3501
+
3502
+ item = string_list_lookup (& fresh_packs , pack_name );
3503
+ if (!item )
3504
+ item = string_list_lookup (& discard_packs , pack_name );
3505
+
3506
+ if (item ) {
3507
+ item -> util = p ;
3508
+ } else {
3509
+ /*
3510
+ * This pack wasn't mentioned in either the "fresh" or
3511
+ * "discard" list, so the caller didn't know about it.
3512
+ *
3513
+ * Mark it as kept so that its objects are ignored by
3514
+ * add_unseen_recent_objects_to_traversal(). We'll
3515
+ * unmark it before starting the traversal so it doesn't
3516
+ * halt the traversal early.
3517
+ */
3518
+ p -> pack_keep_in_core = 1 ;
3519
+ }
3520
+ }
3521
+
3522
+ mark_pack_kept_in_core (& fresh_packs , 1 );
3523
+ mark_pack_kept_in_core (& discard_packs , 0 );
3524
+
3525
+ if (cruft_expiration )
3526
+ die ("--cruft-expiration not yet implemented" );
3527
+ else
3528
+ enumerate_cruft_objects ();
3529
+
3530
+ strbuf_release (& buf );
3531
+ string_list_clear (& discard_packs , 0 );
3532
+ string_list_clear (& fresh_packs , 0 );
3533
+ }
3534
+
3400
3535
static void read_object_list_from_stdin (void )
3401
3536
{
3402
3537
char line [GIT_MAX_HEXSZ + 1 + PATH_MAX + 2 ];
@@ -3529,7 +3664,24 @@ static int add_object_in_unpacked_pack(const struct object_id *oid,
3529
3664
uint32_t pos ,
3530
3665
void * _data )
3531
3666
{
3532
- add_object_entry (oid , OBJ_NONE , "" , 0 );
3667
+ if (cruft ) {
3668
+ off_t offset ;
3669
+ time_t mtime ;
3670
+
3671
+ if (pack -> is_cruft ) {
3672
+ if (load_pack_mtimes (pack ) < 0 )
3673
+ die (_ ("could not load cruft pack .mtimes" ));
3674
+ mtime = nth_packed_mtime (pack , pos );
3675
+ } else {
3676
+ mtime = pack -> mtime ;
3677
+ }
3678
+ offset = nth_packed_object_offset (pack , pos );
3679
+
3680
+ add_cruft_object_entry (oid , OBJ_NONE , pack , offset ,
3681
+ NULL , mtime );
3682
+ } else {
3683
+ add_object_entry (oid , OBJ_NONE , "" , 0 );
3684
+ }
3533
3685
return 0 ;
3534
3686
}
3535
3687
@@ -3553,7 +3705,19 @@ static int add_loose_object(const struct object_id *oid, const char *path,
3553
3705
return 0 ;
3554
3706
}
3555
3707
3556
- add_object_entry (oid , type , "" , 0 );
3708
+ if (cruft ) {
3709
+ struct stat st ;
3710
+ if (stat (path , & st ) < 0 ) {
3711
+ if (errno == ENOENT )
3712
+ return 0 ;
3713
+ return error_errno ("unable to stat %s" , oid_to_hex (oid ));
3714
+ }
3715
+
3716
+ add_cruft_object_entry (oid , type , NULL , 0 , NULL ,
3717
+ st .st_mtime );
3718
+ } else {
3719
+ add_object_entry (oid , type , "" , 0 );
3720
+ }
3557
3721
return 0 ;
3558
3722
}
3559
3723
@@ -3870,6 +4034,20 @@ static int option_parse_unpack_unreachable(const struct option *opt,
3870
4034
return 0 ;
3871
4035
}
3872
4036
4037
+ static int option_parse_cruft_expiration (const struct option * opt ,
4038
+ const char * arg , int unset )
4039
+ {
4040
+ if (unset ) {
4041
+ cruft = 0 ;
4042
+ cruft_expiration = 0 ;
4043
+ } else {
4044
+ cruft = 1 ;
4045
+ if (arg )
4046
+ cruft_expiration = approxidate (arg );
4047
+ }
4048
+ return 0 ;
4049
+ }
4050
+
3873
4051
struct po_filter_data {
3874
4052
unsigned have_revs :1 ;
3875
4053
struct rev_info revs ;
@@ -3959,6 +4137,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
3959
4137
OPT_CALLBACK_F (0 , "unpack-unreachable" , NULL , N_ ("time" ),
3960
4138
N_ ("unpack unreachable objects newer than <time>" ),
3961
4139
PARSE_OPT_OPTARG , option_parse_unpack_unreachable ),
4140
+ OPT_BOOL (0 , "cruft" , & cruft , N_ ("create a cruft pack" )),
4141
+ OPT_CALLBACK_F (0 , "cruft-expiration" , NULL , N_ ("time" ),
4142
+ N_ ("expire cruft objects older than <time>" ),
4143
+ PARSE_OPT_OPTARG , option_parse_cruft_expiration ),
3962
4144
OPT_BOOL (0 , "sparse" , & sparse ,
3963
4145
N_ ("use the sparse reachability algorithm" )),
3964
4146
OPT_BOOL (0 , "thin" , & thin ,
@@ -4085,7 +4267,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
4085
4267
4086
4268
if (!HAVE_THREADS && delta_search_threads != 1 )
4087
4269
warning (_ ("no threads support, ignoring --threads" ));
4088
- if (!pack_to_stdout && !pack_size_limit )
4270
+ if (!pack_to_stdout && !pack_size_limit && ! cruft )
4089
4271
pack_size_limit = pack_size_limit_cfg ;
4090
4272
if (pack_to_stdout && pack_size_limit )
4091
4273
die (_ ("--max-pack-size cannot be used to build a pack for transfer" ));
@@ -4112,6 +4294,15 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
4112
4294
if (stdin_packs && use_internal_rev_list )
4113
4295
die (_ ("cannot use internal rev list with --stdin-packs" ));
4114
4296
4297
+ if (cruft ) {
4298
+ if (use_internal_rev_list )
4299
+ die (_ ("cannot use internal rev list with --cruft" ));
4300
+ if (stdin_packs )
4301
+ die (_ ("cannot use --stdin-packs with --cruft" ));
4302
+ if (pack_size_limit )
4303
+ die (_ ("cannot use --max-pack-size with --cruft" ));
4304
+ }
4305
+
4115
4306
/*
4116
4307
* "soft" reasons not to use bitmaps - for on-disk repack by default we want
4117
4308
*
@@ -4168,14 +4359,16 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
4168
4359
the_repository );
4169
4360
prepare_packing_data (the_repository , & to_pack );
4170
4361
4171
- if (progress )
4362
+ if (progress && ! cruft )
4172
4363
progress_state = start_progress (_ ("Enumerating objects" ), 0 );
4173
4364
if (stdin_packs ) {
4174
4365
/* avoids adding objects in excluded packs */
4175
4366
ignore_packed_keep_in_core = 1 ;
4176
4367
read_packs_list_from_stdin ();
4177
4368
if (rev_list_unpacked )
4178
4369
add_unreachable_loose_objects ();
4370
+ } else if (cruft ) {
4371
+ read_cruft_objects ();
4179
4372
} else if (!use_internal_rev_list ) {
4180
4373
read_object_list_from_stdin ();
4181
4374
} else if (pfd .have_revs ) {
0 commit comments