From: Karthik Nayak Date: Fri, 10 Oct 2025 10:27:13 GMT Subject: [PATCH 9/9] refs: add a '--required' flag to 'git refs optimize' Message-ID: <20251010-562-add-option-to-check-if-reference-backend-needs-repacking-v1-9-c7962be584fa@gmail.com> In-Reply-To: <20251010-562-add-option-to-check-if-reference-backend-needs-repacking-v1-0-c7962be584fa@gmail.com> The 'git pack-refs' and 'git refs optimize' commands allow users to optimize their reference backends. However they provide no functionality to check if optimization is required without performing it. Add a '--required' flag to these commands to do that. This is useful on the server side where this information can be utilized to perform more targetted maintenance runs of the repository. Add a corresponding test for the files backend. For the reftable backend, this cannot be tested easily as it performs auto-compaction. However, an earlier commit ensured the functionality was covered by unit test. Signed-off-by: Karthik Nayak --- Documentation/git-pack-refs.adoc | 1 + Documentation/git-refs.adoc | 1 + Documentation/pack-refs-options.adoc | 5 +++++ builtin/pack-refs.c | 2 +- builtin/refs.c | 2 +- pack-refs.c | 11 ++++++++++- pack-refs.h | 10 ++++++++-- refs.c | 7 +++++++ refs.h | 7 +++++++ t/pack-refs-tests.sh | 20 ++++++++++++++++++++ 10 files changed, 61 insertions(+), 5 deletions(-) diff --git a/Documentation/git-pack-refs.adoc b/Documentation/git-pack-refs.adoc index fde9f2f294..62bc01b29b 100644 --- a/Documentation/git-pack-refs.adoc +++ b/Documentation/git-pack-refs.adoc @@ -9,6 +9,7 @@ SYNOPSIS -------- [verse] 'git pack-refs' [--all] [--no-prune] [--auto] [--include ] [--exclude ] + [--required] DESCRIPTION ----------- diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc index fa33680cc7..4df28b7d92 100644 --- a/Documentation/git-refs.adoc +++ b/Documentation/git-refs.adoc @@ -20,6 +20,7 @@ git refs list [--count=] [--shell|--perl|--python|--tcl] [ --stdin | (...)] git refs exists git refs optimize [--all] [--no-prune] [--auto] [--include ] [--exclude ] + [--required] DESCRIPTION ----------- diff --git a/Documentation/pack-refs-options.adoc b/Documentation/pack-refs-options.adoc index 0b11282941..66d69530b9 100644 --- a/Documentation/pack-refs-options.adoc +++ b/Documentation/pack-refs-options.adoc @@ -50,3 +50,8 @@ the provided `--exclude` patterns. + When used with `--include`, refs provided to `--include`, minus refs that are provided to `--exclude` will be packed. + +--required:: + +Check if pack-refs is required to run, without actually performing the changes. +Returns an exit code of 0 if optimization is required. diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c index 3446b84cda..bd2df4d0b7 100644 --- a/builtin/pack-refs.c +++ b/builtin/pack-refs.c @@ -8,7 +8,7 @@ int cmd_pack_refs(int argc, struct repository *repo) { static char const * const pack_refs_usage[] = { - N_("git pack-refs " PACK_REFS_OPTS), + N_("git pack-refs " PACK_REFS_OPTS(PACK_REFS_OPTS_SPACES_14)), NULL }; diff --git a/builtin/refs.c b/builtin/refs.c index 3064f888b2..fca55997be 100644 --- a/builtin/refs.c +++ b/builtin/refs.c @@ -20,7 +20,7 @@ N_("git refs exists ") #define REFS_OPTIMIZE_USAGE \ - N_("git refs optimize " PACK_REFS_OPTS) + N_("git refs optimize " PACK_REFS_OPTS(PACK_REFS_OPTS_SPACES_18)) static int cmd_refs_migrate(int argc, const char **argv, const char *prefix, struct repository *repo UNUSED) diff --git a/pack-refs.c b/pack-refs.c index fee77fbf9f..5d4d4266de 100644 --- a/pack-refs.c +++ b/pack-refs.c @@ -21,6 +21,7 @@ int pack_refs_core(int argc, }; struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP; struct string_list_item *item; + bool check_required = false; int pack_all = 0; int ret; @@ -28,6 +29,7 @@ int pack_refs_core(int argc, OPT_BOOL(0, "all", &pack_all, N_("pack everything")), OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), OPTIMIZE_REFS_PRUNE), OPT_BIT(0, "auto", &pack_refs_opts.flags, N_("auto-pack refs as needed"), OPTIMIZE_REFS_AUTO), + OPT_BOOL(0, "required", &check_required, N_("check if optimization is required")), OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"), N_("references to include")), OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"), @@ -47,7 +49,14 @@ int pack_refs_core(int argc, if (!pack_refs_opts.includes->nr) string_list_append(pack_refs_opts.includes, "refs/tags/*"); - ret = refs_optimize(get_main_ref_store(repo), &pack_refs_opts); + if (check_required) { + bool required = false; + ret = refs_optimize_required(get_main_ref_store(repo), &pack_refs_opts, + &required); + ret |= !required; + } else { + ret = refs_optimize(get_main_ref_store(repo), &pack_refs_opts); + } clear_ref_exclusions(&excludes); string_list_clear(&included_refs, 0); diff --git a/pack-refs.h b/pack-refs.h index 5de27e7da8..59951ff692 100644 --- a/pack-refs.h +++ b/pack-refs.h @@ -7,9 +7,15 @@ struct repository; * Shared usage string for options common to git-pack-refs(1) * and git-refs-optimize(1). The command-specific part (e.g., "git refs optimize ") * must be prepended by the caller. + * + * Since multiple commands use the same opts, they need to provide the appropriate + * spaces for correct alignment. */ -#define PACK_REFS_OPTS \ - "[--all] [--no-prune] [--auto] [--include ] [--exclude ]" +#define PACK_REFS_OPTS_SPACES_14 " " +#define PACK_REFS_OPTS_SPACES_18 " " +#define PACK_REFS_OPTS(spaces) \ + "[--all] [--no-prune] [--auto] [--include ] [--exclude ]\n" \ + spaces "[--required]" /* * The core logic for pack-refs and its clones. diff --git a/refs.c b/refs.c index 514fb85af2..59a48b36b7 100644 --- a/refs.c +++ b/refs.c @@ -2317,6 +2317,13 @@ int refs_optimize(struct ref_store *refs, struct optimize_refs_opts *opts) return refs->be->optimize(refs, opts); } +int refs_optimize_required(struct ref_store *refs, + struct optimize_refs_opts *opts, + bool *required) +{ + return refs->be->optimize_required(refs, opts, required); +} + int reference_get_peeled_oid(struct repository *repo, const struct reference *ref, struct object_id *peeled_oid) diff --git a/refs.h b/refs.h index 58b222ac02..59f0e519c0 100644 --- a/refs.h +++ b/refs.h @@ -522,6 +522,13 @@ struct optimize_refs_opts { */ int refs_optimize(struct ref_store *refs, struct optimize_refs_opts *opts); +/* + * Check if refs backend can be optimized by calling 'refs_optimize'. + */ +int refs_optimize_required(struct ref_store *ref_store, + struct optimize_refs_opts *opts, + bool *required); + /* * Setup reflog before using. Fill in err and return -1 on failure. */ diff --git a/t/pack-refs-tests.sh b/t/pack-refs-tests.sh index 6a71838ffa..d3e58572e2 100644 --- a/t/pack-refs-tests.sh +++ b/t/pack-refs-tests.sh @@ -460,3 +460,23 @@ test_expect_success 'pack-refs does not store invalid peeled tag value' ' ) ' +test_expect_success "refs optimize --required works as expected" ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + git commit --allow-empty --message "initial" && + test_must_fail git ${pack_refs} --all --auto --required && + + # Create 14 additional references, which brings us to + # 15 together with the default branch. + printf "create refs/heads/loose-%d HEAD\n" $(test_seq 14) >stdin && + git update-ref --stdin