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 4/5] backfill: add --dry-run option
Date: Wed, 30 Sep 2026 01:21:49 +0100 [thread overview]
Message-ID: <20260930-backfill-dryrun-v1-4-1128f247ee01@gmail.com> (raw)
In-Reply-To: <20260930-backfill-dryrun-v1-0-1128f247ee01@gmail.com>
Users have no way to know how many blobs git backfill is going to
download before running it.
Add a new --dry-run option to the backfill command. The objects are
walked as usual, but instead of fetching each batch of missing blobs
they are only counted, and the total is printed at the end.
A subsequent commit will also print their size when the server supports
the object-info capability.
Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com>
---
Documentation/git-backfill.adoc | 6 +++++-
builtin/backfill.c | 37 +++++++++++++++++++++++++++++++++----
t/t5620-backfill.sh | 26 ++++++++++++++++++++++++++
3 files changed, 64 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-backfill.adoc b/Documentation/git-backfill.adoc
index 82d6a1969d..08f19fea17 100644
--- a/Documentation/git-backfill.adoc
+++ b/Documentation/git-backfill.adoc
@@ -9,7 +9,7 @@ git-backfill - Download missing objects in a partial clone
SYNOPSIS
--------
[synopsis]
-git backfill [--min-batch-size=<n>] [--[no-]sparse] [--[no-]include-edges] [<revision-range>]
+git backfill [--min-batch-size=<n>] [--[no-]sparse] [--[no-]include-edges] [--dry-run] [<revision-range>]
DESCRIPTION
-----------
@@ -70,6 +70,10 @@ OPTIONS
--onto TARGET A..B`, where A..B normally excludes A but you need
the blobs from A as well. `--include-edges` is the default.
+`--dry-run`::
+ Do not download any objects. Instead, print the number of
+ missing blobs that would be downloaded.
+
`<revision-range>`::
Backfill only blobs reachable from commits in the specified
revision range. When no _<revision-range>_ is specified, it
diff --git a/builtin/backfill.c b/builtin/backfill.c
index e71e0f4742..6019112966 100644
--- a/builtin/backfill.c
+++ b/builtin/backfill.c
@@ -26,7 +26,7 @@
#include "path-walk.h"
static const char * const builtin_backfill_usage[] = {
- N_("git backfill [--min-batch-size=<n>] [--[no-]sparse] [--[no-]include-edges] [<revision-range>]"),
+ N_("git backfill [--min-batch-size=<n>] [--[no-]sparse] [--[no-]include-edges] [--dry-run] [<revision-range>]"),
NULL
};
@@ -36,6 +36,8 @@ struct backfill_context {
size_t min_batch_size;
int sparse;
int include_edges;
+ int dry_run;
+ size_t total_batch_nr;
struct rev_info revs;
};
@@ -58,6 +60,15 @@ static void download_batch(struct backfill_context *ctx)
odb_reprepare(ctx->repo->objects);
}
+static void dry_run_batch(struct backfill_context *ctx)
+{
+ if (!ctx->current_batch.nr)
+ return;
+
+ ctx->total_batch_nr += ctx->current_batch.nr;
+ oid_array_clear(&ctx->current_batch);
+}
+
static int fill_missing_blobs(const char *path UNUSED,
struct oid_array *list,
enum object_type type,
@@ -73,8 +84,12 @@ static int fill_missing_blobs(const char *path UNUSED,
oid_array_append(&ctx->current_batch, &list->oid[i]);
}
- if (ctx->current_batch.nr >= ctx->min_batch_size)
- download_batch(ctx);
+ if (ctx->current_batch.nr >= ctx->min_batch_size) {
+ if (ctx->dry_run)
+ dry_run_batch(ctx);
+ else
+ download_batch(ctx);
+ }
return 0;
}
@@ -131,10 +146,23 @@ static int do_backfill(struct backfill_context *ctx)
ret = walk_objects_by_path(&info);
+ if (ret)
+ goto end;
+
/* Download the objects that did not fill a batch. */
- if (!ret)
+ if (!ctx->dry_run) {
download_batch(ctx);
+ goto end;
+ }
+
+ 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);
+end:
path_walk_info_clear(&info);
return ret;
}
@@ -157,6 +185,7 @@ 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_END(),
};
struct repo_config_values *cfg = repo_config_values(the_repository);
diff --git a/t/t5620-backfill.sh b/t/t5620-backfill.sh
index 7462280470..e76fa6081b 100755
--- a/t/t5620-backfill.sh
+++ b/t/t5620-backfill.sh
@@ -141,6 +141,32 @@ test_expect_success 'do partial clone 2, backfill min batch size' '
test_line_count = 0 revs2
'
+test_expect_success '--dry-run reports missing blobs without fetching them' '
+ test_when_finished "rm -rf backfill-dry-run dry-trace" &&
+ git clone --no-checkout --filter=blob:none \
+ --single-branch --branch=main \
+ "file://$(pwd)/srv.bare" backfill-dry-run &&
+
+ GIT_TRACE2_EVENT="$(pwd)/dry-trace" git \
+ -C backfill-dry-run backfill --dry-run >out &&
+
+ test_grep "48 blobs would be fetched" out &&
+ test_grep ! fetch_count dry-trace &&
+ git -C backfill-dry-run rev-list --quiet --objects --missing=print HEAD >missing &&
+ test_line_count = 48 missing
+'
+
+test_expect_success '--dry-run with no missing blobs' '
+ 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 &&
+
+ git -C backfill-dry-run backfill --dry-run >out &&
+ test_grep "0 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
next prev 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 ` Pablo Sabater [this message]
2026-09-30 11:06 ` [PATCH RFC 4/5] backfill: add --dry-run option Karthik Nayak
2026-09-30 12:19 ` Pablo Sabater
2026-09-30 0:21 ` [PATCH RFC 5/5] backfill: report total size of missing blobs in --dry-run Pablo Sabater
2026-09-30 17:17 ` 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-4-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