The 'git-maintenance(1)' command provides tooling to run maintenance
tasks over Git repositories. The 'run' subcommand, as the name suggests,
runs the maintenance tasks. When used with the '--auto' flag, it uses
heuristics to determine if the required thresholds are met for running
said maintenance tasks.
There is however a lack of insight into these heuristics. Meaning, the
checks are linked to the execution.
Add a new 'is-needed' subcommand to 'git-maintenance(1)' which allows
users to simply check if it is needed to run maintenance without
performing it.
This subcommand can check if it is needed to run maintenance without
actually running it. Ideally it should be used with the '--auto' flag,
which would allow users to check if the thresholds required are met. The
subcommand also supports the '--task' flag which can be used to check
specific maintenance tasks.
While adding the respective tests in 't/t7900-maintenance.sh', remove a
duplicate of the test: 'worktree-prune task with --auto honors
maintenance.worktree-prune.auto'.
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Acked-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Karthik Nayak committedNov 8, 2025 at 22:51 UTC28b83e6f08ae022d54d79e518e72933ae0930091
3 files changed+113-17
Documentation/git-maintenance.adoc
+13
index 540b5cf68b..bda616f14c 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
builtin/gc.c
+62-1
index 85e9a38d10..928c805f02 100644--- a/builtin/gc.c+++ b/builtin/gc.c@@ -3253,7 +3253,67 @@ 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 always require maintenance right now.+ *+ * TODO: this certainly is too eager, as some maintenance tasks may+ * decide to not do anything because the data structures are already+ * fully optimized. We may eventually want to extend the auto+ * condition to also cover non-auto runs so that we can detect such+ * cases.+ */+ 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 +3330,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(), };