git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 9/9] refs: add a '--required' flag to 'git refs optimize'

From
Karthik Nayak <karthik.188@gmail.com>
Date
Oct 10, 2025, 10:27 UTC
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 <karthik.188@gmail.com>
---
 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 <pattern>] [--exclude <pattern>]
+                [--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=<count>] [--shell|--perl|--python|--tcl]
 		   [ --stdin | (<pattern>...)]
 git refs exists <ref>
 git refs optimize [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]
+		  [--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 <ref>")
 
 #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 <pattern>] [--exclude <pattern>]"
+#define PACK_REFS_OPTS_SPACES_14 "              "
+#define PACK_REFS_OPTS_SPACES_18 "                  "
+#define PACK_REFS_OPTS(spaces)                                                        \
+	"[--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]\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 <stdin &&
+		test_path_is_missing .git/packed-refs &&
+		test_must_fail git ${pack_refs} --all --auto --required &&
+
+		# Create the 16th reference, which should cause us to repack.
+		git update-ref refs/heads/loose-15 HEAD &&
+		git ${pack_refs} --all --auto --required
+	)
+'
-- 
2.51.0
Previous: Karthik NayakNext: Patrick Steinhardt
Message 25 of 36 in “refs: add a '--required' flag to 'git refs optimize'”
  1. 0/9 refs: add a '--required' flag to 'git refs optimize'Karthik Nayak, Oct 10, 2025
  2. 1/9 refs: move to using the '.optimize' functionsKarthik Nayak, Oct 10, 2025
  3. Patrick SteinhardtOct 10, 2025
  4. Karthik NayakOct 13, 2025
  5. 2/9 refs: cleanup code around optimizationKarthik Nayak, Oct 10, 2025
  6. Patrick SteinhardtOct 10, 2025
  7. Karthik NayakOct 13, 2025
  8. 3/9 refs: rename 'pack_refs_opts' to 'optimize_refs_opts'Karthik Nayak, Oct 10, 2025
  9. Patrick SteinhardtOct 10, 2025
  10. Karthik NayakOct 13, 2025
  11. 4/9 t/pack-refs-tests: move the 'test_done' to calleesKarthik Nayak, Oct 10, 2025
  12. Patrick SteinhardtOct 10, 2025
  13. Karthik NayakOct 13, 2025
  14. 5/9 t/t0450: split whitespace consistency check per subcommandKarthik Nayak, Oct 10, 2025
  15. 6/9 reftable/stack: return stack segments directlyKarthik Nayak, Oct 10, 2025
  16. Patrick SteinhardtOct 10, 2025
  17. Karthik NayakOct 13, 2025
  18. Patrick SteinhardtOct 13, 2025
  19. 7/9 reftable/stack: add function to check if optimization is requiredKarthik Nayak, Oct 10, 2025
  20. Patrick SteinhardtOct 10, 2025
  21. Karthik NayakOct 13, 2025
  22. 8/9 refs: add a `optimize_required` field to `struct ref_storage_be`Karthik Nayak, Oct 10, 2025
  23. Patrick SteinhardtOct 10, 2025
  24. Karthik NayakOct 13, 2025
  25. 9/9 refs: add a '--required' flag to 'git refs optimize'Karthik Nayak, Oct 10, 2025
  26. Patrick SteinhardtOct 10, 2025
  27. Karthik NayakOct 13, 2025
  28. Junio C HamanoOct 13, 2025
  29. Junio C HamanoOct 13, 2025
  30. Karthik NayakOct 14, 2025
  31. Junio C HamanoOct 14, 2025
  32. Srivastava, NitinOct 15, 2025
  33. Karthik NayakOct 15, 2025
  34. Karthik NayakOct 15, 2025
  35. Patrick SteinhardtOct 15, 2025
  36. Junio C HamanoOct 15, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.