Git fork

gc: add `--expire-to` option

This commit extends the functionality of `git gc`
by adding a new option, `--expire-to=<dir>`. Previously,
this feature was implemented in 91badeba32 (builtin/repack.c:
implement `--expire-to` for storing pruned objects, 2022-10-24),
which allowing users to specify a directory where unreachable
and expired cruft packs are stored during garbage collection.
However, users had to run `git repack --cruft --expire-to=<dir>`
followed by `git prune` to achieve similar results within `git gc`.

By introducing `--expire-to=<dir>` directly into `git gc`,
we simplify the process for users who wish to manage their
repository's cleanup more efficiently. This change involves
passing the `--expire-to=<dir>` parameter through to `git repack`,
making it easier for users to set up a backup location for cruft
packs that will be pruned.

Due to the original `git gc --prune=now` deleting all unreachable
objects by passing the `-a` parameter to git repack. With the
addition of the `--cruft` and `--expire-to` options, it is necessary
to modify this default behavior: instead of deleting these
unreachable objects, they should be merged into a cruft pack and
collected in a specified directory. Therefore, we do not pass `-a`
to the repack command but instead pass `--cruft`, `--expire-to`,
and `--cruft-expiration=now` to repack.

Signed-off-by: ZheNing Hu <adlternative@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

ZheNing Hu and committed by
Junio C Hamano
08032fa3 92999a42

+47 -2
+7
Documentation/git-gc.txt
··· 69 69 the `--max-cruft-size` option of linkgit:git-repack[1] for 70 70 more. 71 71 72 + --expire-to=<dir>:: 73 + When packing unreachable objects into a cruft pack, write a cruft 74 + pack containing pruned objects (if any) to the directory `<dir>`. 75 + This option only has an effect when used together with `--cruft`. 76 + See the `--expire-to` option of linkgit:git-repack[1] for 77 + more information. 78 + 72 79 --prune=<date>:: 73 80 Prune loose objects older than date (default is 2 weeks ago, 74 81 overridable by the config variable `gc.pruneExpire`).
+7 -2
builtin/gc.c
··· 136 136 char *prune_worktrees_expire; 137 137 char *repack_filter; 138 138 char *repack_filter_to; 139 + char *repack_expire_to; 139 140 unsigned long big_pack_threshold; 140 141 unsigned long max_delta_cache_size; 141 142 }; ··· 432 433 static void add_repack_all_option(struct gc_config *cfg, 433 434 struct string_list *keep_pack) 434 435 { 435 - if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now")) 436 + if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now") 437 + && !(cfg->cruft_packs && cfg->repack_expire_to)) 436 438 strvec_push(&repack, "-a"); 437 439 else if (cfg->cruft_packs) { 438 440 strvec_push(&repack, "--cruft"); ··· 441 443 if (cfg->max_cruft_size) 442 444 strvec_pushf(&repack, "--max-cruft-size=%lu", 443 445 cfg->max_cruft_size); 446 + if (cfg->repack_expire_to) 447 + strvec_pushf(&repack, "--expire-to=%s", cfg->repack_expire_to); 444 448 } else { 445 449 strvec_push(&repack, "-A"); 446 450 if (cfg->prune_expire) ··· 675 679 const char *prune_expire_sentinel = "sentinel"; 676 680 const char *prune_expire_arg = prune_expire_sentinel; 677 681 int ret; 678 - 679 682 struct option builtin_gc_options[] = { 680 683 OPT__QUIET(&quiet, N_("suppress progress reporting")), 681 684 { OPTION_STRING, 0, "prune", &prune_expire_arg, N_("date"), ··· 694 697 PARSE_OPT_NOCOMPLETE), 695 698 OPT_BOOL(0, "keep-largest-pack", &keep_largest_pack, 696 699 N_("repack all other packs except the largest pack")), 700 + OPT_STRING(0, "expire-to", &cfg.repack_expire_to, N_("dir"), 701 + N_("pack prefix to store a pack containing pruned objects")), 697 702 OPT_END() 698 703 }; 699 704
+33
t/t6500-gc.sh
··· 339 339 test_subcommand $cruft_max_size_opts --max-cruft-size=3145728 <trace2.txt 340 340 ' 341 341 342 + test_expect_success '--expire-to sets repack --expire-to' ' 343 + rm -rf expired && 344 + mkdir expired && 345 + expire_to="$(pwd)/expired/pack" && 346 + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --cruft --expire-to="$expire_to" && 347 + test_subcommand $cruft_max_size_opts --expire-to="$expire_to" <trace2.txt 348 + ' 349 + 350 + test_expect_success '--expire-to with --prune=now sets repack --expire-to' ' 351 + rm -rf expired && 352 + mkdir expired && 353 + expire_to="$(pwd)/expired/pack" && 354 + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --cruft --prune=now --expire-to="$expire_to" && 355 + test_subcommand git repack -d -l --cruft --cruft-expiration=now --expire-to="$expire_to" <trace2.txt 356 + ' 357 + 358 + 359 + test_expect_success '--expire-to with --no-cruft sets repack -A' ' 360 + rm -rf expired && 361 + mkdir expired && 362 + expire_to="$(pwd)/expired/pack" && 363 + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --no-cruft --expire-to="$expire_to" && 364 + test_subcommand git repack -d -l -A --unpack-unreachable=2.weeks.ago <trace2.txt 365 + ' 366 + 367 + test_expect_success '--expire-to with --no-cruft sets repack -a' ' 368 + rm -rf expired && 369 + mkdir expired && 370 + expire_to="$(pwd)/expired/pack" && 371 + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --no-cruft --prune=now --expire-to="$expire_to" && 372 + test_subcommand git repack -d -l -a <trace2.txt 373 + ' 374 + 342 375 run_and_wait_for_gc () { 343 376 # We read stdout from gc for the side effect of waiting until the 344 377 # background gc process exits, closing its fd 9. Furthermore, the