36
#include "trace2.h"
37
#include "shallow.h"
38
#include "promisor-remote.h"
39
+#include "pack-mtimes.h"
40
41
/*
42
* Objects we are going to pack are collected in the `to_pack` structure.
195
static int keep_unreachable, unpack_unreachable, include_tag;
196
static timestamp_t unpack_unreachable_expiration;
197
static int pack_loose_unreachable;
198
+static int cruft;
199
+static timestamp_t cruft_expiration;
200
static int local;
201
static int have_non_local_packs;
202
static int incremental;
1263
&to_pack, written_list, nr_written);
1264
}
1265
1266
+ if (cruft)
1267
+ pack_idx_opts.flags |= WRITE_MTIMES;
1268
+
1269
stage_tmp_packfiles(&tmpname, pack_tmp_name,
1270
written_list, nr_written,
1271
&to_pack, &pack_idx_opts, hash,
3403
string_list_clear(&exclude_packs, 0);
3404
}
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
+
3535
static void read_object_list_from_stdin(void)
3536
{
3537
char line[GIT_MAX_HEXSZ + 1 + PATH_MAX + 2];
3664
uint32_t pos,
3665
void *_data)
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
+ }
3685
return 0;
3686
}
3687
3705
return 0;
3706
}
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
+ }
3721
return 0;
3722
}
3723
4034
return 0;
4035
}
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
+
4051
struct po_filter_data {
4052
unsigned have_revs:1;
4053
struct rev_info revs;
4137
OPT_CALLBACK_F(0, "unpack-unreachable", NULL, N_("time"),
4138
N_("unpack unreachable objects newer than <time>"),
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),
4144
OPT_BOOL(0, "sparse", &sparse,
4145
N_("use the sparse reachability algorithm")),
4146
OPT_BOOL(0, "thin", &thin,
4267
4268
if (!HAVE_THREADS && delta_search_threads != 1)
4269
warning(_("no threads support, ignoring --threads"));
4088
- if (!pack_to_stdout && !pack_size_limit)
4270
+ if (!pack_to_stdout && !pack_size_limit && !cruft)
4271
pack_size_limit = pack_size_limit_cfg;
4272
if (pack_to_stdout && pack_size_limit)
4273
die(_("--max-pack-size cannot be used to build a pack for transfer"));
4294
if (stdin_packs && use_internal_rev_list)
4295
die(_("cannot use internal rev list with --stdin-packs"));
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
+
4306
/*
4307
* "soft" reasons not to use bitmaps - for on-disk repack by default we want
4308
*
4359
the_repository);
4360
prepare_packing_data(the_repository, &to_pack);
4361
4171
- if (progress)
4362
+ if (progress && !cruft)
4363
progress_state = start_progress(_("Enumerating objects"), 0);
4364
if (stdin_packs) {
4365
/* avoids adding objects in excluded packs */
4367
read_packs_list_from_stdin();
4368
if (rev_list_unpacked)
4369
add_unreachable_loose_objects();
4370
+ } else if (cruft) {
4371
+ read_cruft_objects();
4372
} else if (!use_internal_rev_list) {
4373
read_object_list_from_stdin();
4374
} else if (pfd.have_revs) {