Git development
 help / color / mirror / Atom feed
From: Pablo Sabater <pabloosabaterr@gmail.com>
To: git@vger.kernel.org
Cc: Derrick Stolee <stolee@gmail.com>,
	 Pablo Sabater <pabloosabaterr@gmail.com>
Subject: [PATCH RFC 5/5] backfill: report total size of missing blobs in --dry-run
Date: Wed, 30 Sep 2026 01:21:50 +0100	[thread overview]
Message-ID: <20260930-backfill-dryrun-v1-5-1128f247ee01@gmail.com> (raw)
In-Reply-To: <20260930-backfill-dryrun-v1-0-1128f247ee01@gmail.com>

The number of missing blobs says little about how much data a backfill
will transfer.  In --dry-run mode, if the server has the object-info
capability enabled, fetch the size of the objects to be fetched and show
the total size, if the server doesn't have the capability enabled, fall
back to printing only the count.

The reported size is the sum of the uncompressed object sizes, so it
is an upper bound: once fetched, the blobs are stored compressed and
possibly deltified in a packfile, and usually take less space on disk.

Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com>
---
 Documentation/git-backfill.adoc |  6 +++-
 builtin/backfill.c              | 70 ++++++++++++++++++++++++++++++++++++++---
 t/t5620-backfill.sh             | 22 +++++++++++++
 3 files changed, 92 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-backfill.adoc b/Documentation/git-backfill.adoc
index 08f19fea17..660e1c17c0 100644
--- a/Documentation/git-backfill.adoc
+++ b/Documentation/git-backfill.adoc
@@ -72,7 +72,11 @@ OPTIONS
 
 `--dry-run`::
 	Do not download any objects. Instead, print the number of
-	missing blobs that would be downloaded.
+	missing blobs that would be downloaded and, if the promisor
+	remote supports the `object-info` capability, their total
+	size. This is the sum of the uncompressed sizes of the blobs,
+	so the space used on disk after a real backfill is usually
+	smaller.
 
 `<revision-range>`::
 	Backfill only blobs reachable from commits in the specified
diff --git a/builtin/backfill.c b/builtin/backfill.c
index 6019112966..caf1a64e95 100644
--- a/builtin/backfill.c
+++ b/builtin/backfill.c
@@ -24,6 +24,9 @@
 #include "progress.h"
 #include "packfile.h"
 #include "path-walk.h"
+#include "transport.h"
+#include "remote.h"
+#include "fetch-object-info.h"
 
 static const char * const builtin_backfill_usage[] = {
 	N_("git backfill [--min-batch-size=<n>] [--[no-]sparse] [--[no-]include-edges] [--dry-run] [<revision-range>]"),
@@ -37,7 +40,11 @@ struct backfill_context {
 	int sparse;
 	int include_edges;
 	int dry_run;
+	int object_info_enabled;
+	size_t total_batch_size;
 	size_t total_batch_nr;
+	struct transport *object_info_transport;
+	struct fetch_object_info_results object_info_results;
 	struct rev_info revs;
 };
 
@@ -62,10 +69,47 @@ static void download_batch(struct backfill_context *ctx)
 
 static void dry_run_batch(struct backfill_context *ctx)
 {
+	struct fetch_object_info_results *results = &ctx->object_info_results;
+	enum fetch_object_info_status status;
+
 	if (!ctx->current_batch.nr)
 		return;
 
 	ctx->total_batch_nr += ctx->current_batch.nr;
+
+	if (!ctx->object_info_enabled)
+		goto cleanup;
+
+	if (!ctx->object_info_transport) {
+		struct promisor_remote *promise =
+			repo_promisor_remote_find(ctx->repo, NULL);
+		struct remote *remote = NULL;
+
+		if (!promise || !(remote = remote_get(promise->name)))
+			die(_("--dry-run requires a promisor remote"));
+
+		ctx->object_info_transport = transport_get(remote, NULL);
+
+		if (!ctx->object_info_transport->smart_options)
+			die(_("failed to get object info: smart options required"));
+	}
+
+	results->wants_size = 1;
+	status = transport_fetch_object_info(ctx->object_info_transport,
+					     &ctx->current_batch,
+					     results);
+
+	if (status == FETCH_OBJECT_INFO_NOT_ENABLED ||
+	    !results->sizes) {
+		ctx->object_info_enabled = 0;
+		goto cleanup;
+	}
+
+	for (size_t i = 0; i < results->nr; i++)
+		ctx->total_batch_size += results->sizes[i];
+
+cleanup:
+	free_fetch_object_info_results(&ctx->object_info_results);
 	oid_array_clear(&ctx->current_batch);
 }
 
@@ -157,12 +201,25 @@ static int do_backfill(struct backfill_context *ctx)
 
 	dry_run_batch(ctx);
 
-	printf(Q_("After backfill, %" PRIuMAX " blob would be fetched.\n",
-		  "After backfill, %" PRIuMAX " blobs would be fetched.\n",
-		  (unsigned long)ctx->total_batch_nr),
-	       (uintmax_t)ctx->total_batch_nr);
+	if (ctx->object_info_enabled && ctx->total_batch_nr) {
+		struct strbuf size = STRBUF_INIT;
+
+		strbuf_humanise_bytes(&size, ctx->total_batch_size);
+		printf(Q_("After backfill, %" PRIuMAX " blob would be fetched (%s).\n",
+			  "After backfill, %" PRIuMAX " blobs would be fetched (%s).\n",
+			  (unsigned long)ctx->total_batch_nr),
+		       (uintmax_t)ctx->total_batch_nr, size.buf);
+		strbuf_release(&size);
+	} else {
+		printf(Q_("After backfill, %" PRIuMAX " blob would be fetched.\n",
+			  "After backfill, %" PRIuMAX " blobs would be fetched.\n",
+			  (unsigned long)ctx->total_batch_nr),
+		       (uintmax_t)ctx->total_batch_nr);
+	}
 
 end:
+	if (ctx->object_info_transport)
+		transport_disconnect(ctx->object_info_transport);
 	path_walk_info_clear(&info);
 	return ret;
 }
@@ -177,6 +234,8 @@ int cmd_backfill(int argc, const char **argv, const char *prefix, struct reposit
 		.sparse = -1,
 		.revs = REV_INFO_INIT,
 		.include_edges = 1,
+		.object_info_results = FETCH_OBJECT_INFO_RESULTS_INIT,
+		.object_info_enabled = 1,
 	};
 	struct option options[] = {
 		OPT_UNSIGNED(0, "min-batch-size", &ctx.min_batch_size,
@@ -185,7 +244,8 @@ int cmd_backfill(int argc, const char **argv, const char *prefix, struct reposit
 			 N_("Restrict the missing objects to the current sparse-checkout")),
 		OPT_BOOL(0, "include-edges", &ctx.include_edges,
 			 N_("Include blobs from boundary commits in the backfill")),
-		OPT__DRY_RUN(&ctx.dry_run, N_("Preview the number of blobs to be fetched")),
+		OPT__DRY_RUN(&ctx.dry_run, N_("Preview the number of blobs and their total "
+					      "size to be fetched")),
 		OPT_END(),
 	};
 	struct repo_config_values *cfg = repo_config_values(the_repository);
diff --git a/t/t5620-backfill.sh b/t/t5620-backfill.sh
index e76fa6081b..b21feb625c 100755
--- a/t/t5620-backfill.sh
+++ b/t/t5620-backfill.sh
@@ -167,6 +167,28 @@ test_expect_success '--dry-run with no missing blobs' '
 	test_grep "0 blobs would be fetched" out
 '
 
+test_expect_success '--dry-run reports total size with object-info' '
+	test_config -C srv.bare transfer.advertiseobjectinfo true &&
+	test_when_finished rm -rf backfill-dry-run &&
+	git clone --no-checkout --filter=blob:none \
+		--single-branch --branch=main \
+		"file://$(pwd)/srv.bare" backfill-dry-run &&
+
+	git -C backfill-dry-run backfill --dry-run >out &&
+	test_grep "48 blobs would be fetched (.*)" out
+'
+
+test_expect_success '--dry-run reports only the count without object-info' '
+	test_config -C srv.bare transfer.advertiseobjectinfo false &&
+	test_when_finished rm -rf backfill-dry-run &&
+	git clone --no-checkout --filter=blob:none \
+		--single-branch --branch=main \
+		"file://$(pwd)/srv.bare" backfill-dry-run &&
+
+	git -C backfill-dry-run backfill --dry-run >out &&
+	test_grep "48 blobs would be fetched\.$" out
+'
+
 test_expect_success 'backfill --sparse without sparse-checkout fails' '
 	git init not-sparse &&
 	test_must_fail git -C not-sparse backfill --sparse 2>err &&

-- 
2.54.0


  parent reply	other threads:[~2026-09-30  0:22 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-30  0:21 [PATCH RFC 0/5] Add --dry-run option to git-backfill(1) Pablo Sabater
2026-09-30  0:21 ` [PATCH RFC 1/5] transport-internal: update fetch_object_info comment Pablo Sabater
2026-09-30  0:21 ` [PATCH RFC 2/5] fetch-object-info: add enum for fetch_object_info() statuses Pablo Sabater
2026-09-30 10:56   ` Karthik Nayak
2026-09-30 11:59     ` Pablo Sabater
2026-09-30  0:21 ` [PATCH RFC 3/5] fetch-object-info: return a status instead of dying Pablo Sabater
2026-09-30 17:07   ` Junio C Hamano
2026-09-30 18:03     ` Pablo Sabater
2026-09-30 20:01       ` Junio C Hamano
2026-09-30  0:21 ` [PATCH RFC 4/5] backfill: add --dry-run option Pablo Sabater
2026-09-30 11:06   ` Karthik Nayak
2026-09-30 12:19     ` Pablo Sabater
2026-09-30  0:21 ` Pablo Sabater [this message]
2026-09-30 17:17   ` [PATCH RFC 5/5] backfill: report total size of missing blobs in --dry-run Junio C Hamano
2026-09-30 18:31     ` Pablo Sabater
2026-09-30 18:14 ` [PATCH RFC 0/5] Add --dry-run option to git-backfill(1) Derrick Stolee
2026-09-30 19:06   ` Pablo Sabater
2026-09-30 20:03   ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260930-backfill-dryrun-v1-5-1128f247ee01@gmail.com \
    --to=pabloosabaterr@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=stolee@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox