aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-maintenance.adoc13
-rw-r--r--builtin/gc.c55
-rwxr-xr-xt/t7900-maintenance.sh54
3 files changed, 105 insertions, 17 deletions
diff --git a/Documentation/git-maintenance.adoc b/Documentation/git-maintenance.adoc
index 540b5cf68b..37939510d4 100644
--- a/Documentation/git-maintenance.adoc
+++ b/Documentation/git-maintenance.adoc
@@ -12,6 +12,7 @@ SYNOPSIS
'git maintenance' run [<options>]
'git maintenance' start [--scheduler=<scheduler>]
'git maintenance' (stop|register|unregister) [<options>]
+'git maintenance' is-needed [<options>]
DESCRIPTION
@@ -84,6 +85,16 @@ The `unregister` subcommand will report an error if the current repository
is not already registered. Use the `--force` option to return success even
when the current repository is not registered.
+is-needed::
+ Check whether maintenance needs to be run without actually running it.
+ Exits with a 0 status code if maintenance needs to be run, 1 otherwise.
+ Ideally used with the '--auto' flag.
++
+If one or more `--task` options are specified, then those tasks are checked
+in that order. Otherwise, the tasks are determined by which
+`maintenance.<task>.enabled` config options are true. By default, only
+`maintenance.gc.enabled` is true.
+
TASKS
-----
@@ -183,6 +194,8 @@ OPTIONS
in the `gc.auto` config setting, or when the number of pack-files
exceeds the `gc.autoPackLimit` config setting. Not compatible with
the `--schedule` option.
+ When combined with the `is-needed` subcommand, check if the required
+ thresholds are met without actually running maintenance.
--schedule::
When combined with the `run` subcommand, run maintenance tasks
diff --git a/builtin/gc.c b/builtin/gc.c
index c3e7a84ec2..e5ba2a2e72 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -3253,7 +3253,59 @@ static int maintenance_stop(int argc, const char **argv, const char *prefix,
return update_background_schedule(NULL, 0);
}
-static const char * const builtin_maintenance_usage[] = {
+static const char *const builtin_maintenance_is_needed_usage[] = {
+ "git maintenance is-needed [--task=<task>] [--schedule]",
+ NULL
+};
+
+static int maintenance_is_needed(int argc, const char **argv, const char *prefix,
+ struct repository *repo UNUSED)
+{
+ struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
+ struct string_list selected_tasks = STRING_LIST_INIT_DUP;
+ struct gc_config cfg = GC_CONFIG_INIT;
+ struct option options[] = {
+ OPT_BOOL(0, "auto", &opts.auto_flag,
+ N_("run tasks based on the state of the repository")),
+ OPT_CALLBACK_F(0, "task", &selected_tasks, N_("task"),
+ N_("check a specific task"),
+ PARSE_OPT_NONEG, task_option_parse),
+ OPT_END()
+ };
+ bool is_needed = false;
+
+ argc = parse_options(argc, argv, prefix, options,
+ builtin_maintenance_is_needed_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ if (argc)
+ usage_with_options(builtin_maintenance_is_needed_usage, options);
+
+ gc_config(&cfg);
+ initialize_task_config(&opts, &selected_tasks);
+
+ if (opts.auto_flag) {
+ for (size_t i = 0; i < opts.tasks_nr; i++) {
+ if (tasks[opts.tasks[i]].auto_condition &&
+ tasks[opts.tasks[i]].auto_condition(&cfg)) {
+ is_needed = true;
+ break;
+ }
+ }
+ } else {
+ /* When not using --auto, we should always require maintenance. */
+ is_needed = true;
+ }
+
+ string_list_clear(&selected_tasks, 0);
+ maintenance_run_opts_release(&opts);
+ gc_config_release(&cfg);
+
+ if (is_needed)
+ return 0;
+ return 1;
+}
+
+static const char *const builtin_maintenance_usage[] = {
N_("git maintenance <subcommand> [<options>]"),
NULL,
};
@@ -3270,6 +3322,7 @@ int cmd_maintenance(int argc,
OPT_SUBCOMMAND("stop", &fn, maintenance_stop),
OPT_SUBCOMMAND("register", &fn, maintenance_register),
OPT_SUBCOMMAND("unregister", &fn, maintenance_unregister),
+ OPT_SUBCOMMAND("is-needed", &fn, maintenance_is_needed),
OPT_END(),
};
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index ddd273d8dc..a17e2091c2 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -49,7 +49,9 @@ test_expect_success 'run [--auto|--quiet]' '
git maintenance run --auto 2>/dev/null &&
GIT_TRACE2_EVENT="$(pwd)/run-no-quiet.txt" \
git maintenance run --no-quiet 2>/dev/null &&
+ git maintenance is-needed &&
test_subcommand git gc --quiet --no-detach --skip-foreground-tasks <run-no-auto.txt &&
+ ! git maintenance is-needed --auto &&
test_subcommand ! git gc --auto --quiet --no-detach --skip-foreground-tasks <run-auto.txt &&
test_subcommand git gc --no-quiet --no-detach --skip-foreground-tasks <run-no-quiet.txt
'
@@ -180,6 +182,11 @@ test_expect_success 'commit-graph auto condition' '
test_commit first &&
+ ! git -c maintenance.commit-graph.auto=0 \
+ maintenance is-needed --auto --task=commit-graph &&
+ git -c maintenance.commit-graph.auto=1 \
+ maintenance is-needed --auto --task=commit-graph &&
+
GIT_TRACE2_EVENT="$(pwd)/cg-zero-means-no.txt" \
git -c maintenance.commit-graph.auto=0 $COMMAND &&
GIT_TRACE2_EVENT="$(pwd)/cg-one-satisfied.txt" \
@@ -290,16 +297,23 @@ test_expect_success 'maintenance.loose-objects.auto' '
git -c maintenance.loose-objects.auto=1 maintenance \
run --auto --task=loose-objects 2>/dev/null &&
test_subcommand ! git prune-packed --quiet <trace-lo1.txt &&
+
printf data-A | git hash-object -t blob --stdin -w &&
+ ! git -c maintenance.loose-objects.auto=2 \
+ maintenance is-needed --auto --task=loose-objects &&
GIT_TRACE2_EVENT="$(pwd)/trace-loA" \
git -c maintenance.loose-objects.auto=2 \
maintenance run --auto --task=loose-objects 2>/dev/null &&
test_subcommand ! git prune-packed --quiet <trace-loA &&
+
printf data-B | git hash-object -t blob --stdin -w &&
+ git -c maintenance.loose-objects.auto=2 \
+ maintenance is-needed --auto --task=loose-objects &&
GIT_TRACE2_EVENT="$(pwd)/trace-loB" \
git -c maintenance.loose-objects.auto=2 \
maintenance run --auto --task=loose-objects 2>/dev/null &&
test_subcommand git prune-packed --quiet <trace-loB &&
+
GIT_TRACE2_EVENT="$(pwd)/trace-loC" \
git -c maintenance.loose-objects.auto=2 \
maintenance run --auto --task=loose-objects 2>/dev/null &&
@@ -421,10 +435,13 @@ run_incremental_repack_and_verify () {
test_commit A &&
git repack -adk &&
git multi-pack-index write &&
+ ! git -c maintenance.incremental-repack.auto=1 \
+ maintenance is-needed --auto --task=incremental-repack &&
GIT_TRACE2_EVENT="$(pwd)/midx-init.txt" git \
-c maintenance.incremental-repack.auto=1 \
maintenance run --auto --task=incremental-repack 2>/dev/null &&
test_subcommand ! git multi-pack-index write --no-progress <midx-init.txt &&
+
test_commit B &&
git pack-objects --revs .git/objects/pack/pack <<-\EOF &&
HEAD
@@ -434,11 +451,14 @@ run_incremental_repack_and_verify () {
-c maintenance.incremental-repack.auto=2 \
maintenance run --auto --task=incremental-repack 2>/dev/null &&
test_subcommand ! git multi-pack-index write --no-progress <trace-A &&
+
test_commit C &&
git pack-objects --revs .git/objects/pack/pack <<-\EOF &&
HEAD
^HEAD~1
EOF
+ git -c maintenance.incremental-repack.auto=2 \
+ maintenance is-needed --auto --task=incremental-repack &&
GIT_TRACE2_EVENT=$(pwd)/trace-B git \
-c maintenance.incremental-repack.auto=2 \
maintenance run --auto --task=incremental-repack 2>/dev/null &&
@@ -485,9 +505,15 @@ test_expect_success 'reflog-expire task --auto only packs when exceeding limits'
git reflog expire --all --expire=now &&
test_commit reflog-one &&
test_commit reflog-two &&
+
+ ! git -c maintenance.reflog-expire.auto=3 \
+ maintenance is-needed --auto --task=reflog-expire &&
GIT_TRACE2_EVENT="$(pwd)/reflog-expire-auto.txt" \
git -c maintenance.reflog-expire.auto=3 maintenance run --auto --task=reflog-expire &&
test_subcommand ! git reflog expire --all <reflog-expire-auto.txt &&
+
+ git -c maintenance.reflog-expire.auto=2 \
+ maintenance is-needed --auto --task=reflog-expire &&
GIT_TRACE2_EVENT="$(pwd)/reflog-expire-auto.txt" \
git -c maintenance.reflog-expire.auto=2 maintenance run --auto --task=reflog-expire &&
test_subcommand git reflog expire --all <reflog-expire-auto.txt
@@ -514,6 +540,7 @@ test_expect_success 'worktree-prune task --auto only prunes with prunable worktr
test_expect_worktree_prune ! git maintenance run --auto --task=worktree-prune &&
mkdir .git/worktrees &&
: >.git/worktrees/abc &&
+ git maintenance is-needed --auto --task=worktree-prune &&
test_expect_worktree_prune git maintenance run --auto --task=worktree-prune
'
@@ -530,22 +557,7 @@ test_expect_success 'worktree-prune task with --auto honors maintenance.worktree
test_expect_worktree_prune ! git -c maintenance.worktree-prune.auto=0 maintenance run --auto --task=worktree-prune &&
# A positive value should require at least this many prunable worktrees.
test_expect_worktree_prune ! git -c maintenance.worktree-prune.auto=4 maintenance run --auto --task=worktree-prune &&
- test_expect_worktree_prune git -c maintenance.worktree-prune.auto=3 maintenance run --auto --task=worktree-prune
-'
-
-test_expect_success 'worktree-prune task with --auto honors maintenance.worktree-prune.auto' '
- # A negative value should always prune.
- test_expect_worktree_prune git -c maintenance.worktree-prune.auto=-1 maintenance run --auto --task=worktree-prune &&
-
- mkdir .git/worktrees &&
- : >.git/worktrees/first &&
- : >.git/worktrees/second &&
- : >.git/worktrees/third &&
-
- # Zero should never prune.
- test_expect_worktree_prune ! git -c maintenance.worktree-prune.auto=0 maintenance run --auto --task=worktree-prune &&
- # A positive value should require at least this many prunable worktrees.
- test_expect_worktree_prune ! git -c maintenance.worktree-prune.auto=4 maintenance run --auto --task=worktree-prune &&
+ git -c maintenance.worktree-prune.auto=3 maintenance is-needed --auto --task=worktree-prune &&
test_expect_worktree_prune git -c maintenance.worktree-prune.auto=3 maintenance run --auto --task=worktree-prune
'
@@ -554,11 +566,13 @@ test_expect_success 'worktree-prune task honors gc.worktreePruneExpire' '
rm -rf worktree &&
rm -f worktree-prune.txt &&
+ ! git -c gc.worktreePruneExpire=1.week.ago maintenance is-needed --auto --task=worktree-prune &&
GIT_TRACE2_EVENT="$(pwd)/worktree-prune.txt" git -c gc.worktreePruneExpire=1.week.ago maintenance run --auto --task=worktree-prune &&
test_subcommand ! git worktree prune --expire 1.week.ago <worktree-prune.txt &&
test_path_is_dir .git/worktrees/worktree &&
rm -f worktree-prune.txt &&
+ git -c gc.worktreePruneExpire=now maintenance is-needed --auto --task=worktree-prune &&
GIT_TRACE2_EVENT="$(pwd)/worktree-prune.txt" git -c gc.worktreePruneExpire=now maintenance run --auto --task=worktree-prune &&
test_subcommand git worktree prune --expire now <worktree-prune.txt &&
test_path_is_missing .git/worktrees/worktree
@@ -583,10 +597,13 @@ test_expect_success 'rerere-gc task without --auto always collects garbage' '
test_expect_success 'rerere-gc task with --auto only prunes with prunable entries' '
test_when_finished "rm -rf .git/rr-cache" &&
+ ! git maintenance is-needed --auto --task=rerere-gc &&
test_expect_rerere_gc ! git maintenance run --auto --task=rerere-gc &&
mkdir .git/rr-cache &&
+ ! git maintenance is-needed --auto --task=rerere-gc &&
test_expect_rerere_gc ! git maintenance run --auto --task=rerere-gc &&
: >.git/rr-cache/entry &&
+ git maintenance is-needed --auto --task=rerere-gc &&
test_expect_rerere_gc git maintenance run --auto --task=rerere-gc
'
@@ -594,17 +611,22 @@ test_expect_success 'rerere-gc task with --auto honors maintenance.rerere-gc.aut
test_when_finished "rm -rf .git/rr-cache" &&
# A negative value should always prune.
+ git -c maintenance.rerere-gc.auto=-1 maintenance is-needed --auto --task=rerere-gc &&
test_expect_rerere_gc git -c maintenance.rerere-gc.auto=-1 maintenance run --auto --task=rerere-gc &&
# A positive value prunes when there is at least one entry.
+ ! git -c maintenance.rerere-gc.auto=9000 maintenance is-needed --auto --task=rerere-gc &&
test_expect_rerere_gc ! git -c maintenance.rerere-gc.auto=9000 maintenance run --auto --task=rerere-gc &&
mkdir .git/rr-cache &&
+ ! git -c maintenance.rerere-gc.auto=9000 maintenance is-needed --auto --task=rerere-gc &&
test_expect_rerere_gc ! git -c maintenance.rerere-gc.auto=9000 maintenance run --auto --task=rerere-gc &&
: >.git/rr-cache/entry-1 &&
+ git -c maintenance.rerere-gc.auto=9000 maintenance is-needed --auto --task=rerere-gc &&
test_expect_rerere_gc git -c maintenance.rerere-gc.auto=9000 maintenance run --auto --task=rerere-gc &&
# Zero should never prune.
: >.git/rr-cache/entry-1 &&
+ ! git -c maintenance.rerere-gc.auto=0 maintenance is-needed --auto --task=rerere-gc &&
test_expect_rerere_gc ! git -c maintenance.rerere-gc.auto=0 maintenance run --auto --task=rerere-gc
'