Git development
 help / color / mirror / Atom feed
From: Tian Yuchen <cat@malon.dev>
To: git@vger.kernel.org
Cc: Tian Yuchen <cat@malon.dev>,
	Christian Couder <christian.couder@gmail.com>,
	Ayush Chandekar <ayu.chandekar@gmail.com>,
	Olamide Caleb Bello <belkid98@gmail.com>
Subject: [PATCH v5 2/2] repository: move fetch_if_missing into struct repository
Date: Fri, 14 Aug 2026 15:24:19 +0800	[thread overview]
Message-ID: <20260814072419.1666358-3-cat@malon.dev> (raw)
In-Reply-To: <20260814072419.1666358-1-cat@malon.dev>

The global variable 'fetch_if_missing' controls whether a missing
object check should prompt a lazy fetch from a promisor remote.
In order to continue the libification effort, move it into
'struct repository' and initialize it to 1 by default to keep the
previous behavior.

builtin/fetch-pack.c, builtin/fsck.c, and builtin/rev-list.c are
entered via commands marked RUN_SETUP in git.c:commands[]. Their
'repo' parameter is only NULL when '-h' is given outside of a
repository, in which case either show_usage_if_asked() or
parse_options()'s own '-h' handling exits the process before
returning. We can therefore drop their UNUSED markers and assign
to 'repo' directly.

builtin/index-pack.c  is entered via RUN_SETUP_GENTLY, so its
'repo' pointer can be NULL any time it is run outside of a
repository, not only with '-h'. We keep a NULL check there and fall
back to 'the_repository'.

builtin/pack-objects.c's call sites were prepared in the preceding
commit to have 'repo' in scope. This commit performs the replacement
of 'fetch_if_missing' with 'repo->fetch_if_missing' there.

Additionally, update the partial clone documentation to reflect
that this is now a per-repository flag.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>
Mentored-by: Olamide Caleb Bello <belkid98@gmail.com>
Signed-off-by: Tian Yuchen <cat@malon.dev>
---
 Documentation/technical/partial-clone.adoc |  2 +-
 builtin/fetch-pack.c                       |  6 +++---
 builtin/fsck.c                             |  6 +++---
 builtin/index-pack.c                       |  8 ++++----
 builtin/pack-objects.c                     | 12 ++++++------
 builtin/prune.c                            |  2 +-
 builtin/rev-list.c                         | 17 +++++++++--------
 common-init.c                              |  2 +-
 git.c                                      |  2 +-
 midx-write.c                               |  2 +-
 odb.c                                      |  4 +---
 odb.h                                      |  8 --------
 repository.c                               |  1 +
 repository.h                               |  6 ++++++
 revision.c                                 |  2 +-
 15 files changed, 39 insertions(+), 41 deletions(-)

diff --git a/Documentation/technical/partial-clone.adoc b/Documentation/technical/partial-clone.adoc
index e513e391ea..18718a3840 100644
--- a/Documentation/technical/partial-clone.adoc
+++ b/Documentation/technical/partial-clone.adoc
@@ -159,7 +159,7 @@ and prefetch those objects in bulk.
 - `repack` in GC has been updated to not touch promisor packfiles at all,
   and to only repack other objects.
 
-- The global variable "fetch_if_missing" is used to control whether an
+- The per-repository flag "fetch_if_missing" is used to control whether an
   object lookup will attempt to dynamically fetch a missing object or
   report an error.
 +
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 316badd969..86754296fa 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -49,7 +49,7 @@ static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
 int cmd_fetch_pack(int argc,
 		   const char **argv,
 		   const char *prefix UNUSED,
-		   struct repository *repo UNUSED)
+		   struct repository *repo)
 {
 	int i, ret;
 	struct ref *fetched_refs = NULL, *remote_refs = NULL;
@@ -67,8 +67,6 @@ int cmd_fetch_pack(int argc,
 	struct packet_reader reader;
 	enum protocol_version version;
 
-	fetch_if_missing = 0;
-
 	packet_trace_identity("fetch-pack");
 
 	memset(&args, 0, sizeof(args));
@@ -77,6 +75,8 @@ int cmd_fetch_pack(int argc,
 
 	show_usage_if_asked(argc, argv, fetch_pack_usage);
 
+	repo->fetch_if_missing = 0;
+
 	for (i = 1; i < argc && *argv[i] == '-'; i++) {
 		const char *arg = argv[i];
 
diff --git a/builtin/fsck.c b/builtin/fsck.c
index a6c054e45b..8cfc0e8b26 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -1017,15 +1017,15 @@ int cmd_fsck(int argc,
 		.ref = NULL
 	};
 
-	/* fsck knows how to handle missing promisor objects */
-	fetch_if_missing = 0;
-
 	errors_found = 0;
 	disable_replace_refs();
 	save_commit_buffer = 0;
 
 	argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
 
+	/* fsck knows how to handle missing promisor objects */
+	repo->fetch_if_missing = 0;
+
 	fsck_options_init(&fsck_walk_options, repo, FSCK_OPTIONS_DEFAULT);
 	fsck_walk_options.walk = mark_object;
 
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index bc86925ad0..28f8d01e04 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1886,7 +1886,7 @@ static void repack_local_links(void)
 int cmd_index_pack(int argc,
 		   const char **argv,
 		   const char *prefix,
-		   struct repository *repo UNUSED)
+		   struct repository *repo)
 {
 	int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;
 	const char *curr_index;
@@ -1903,15 +1903,15 @@ int cmd_index_pack(int argc,
 	int report_end_of_input = 0;
 	int hash_algo = 0;
 
+	show_usage_if_asked(argc, argv, index_pack_usage);
+
 	/*
 	 * index-pack never needs to fetch missing objects except when
 	 * REF_DELTA bases are missing (which are explicitly handled). It only
 	 * accesses the repo to do hash collision checks and to check which
 	 * REF_DELTA bases need to be fetched.
 	 */
-	fetch_if_missing = 0;
-
-	show_usage_if_asked(argc, argv, index_pack_usage);
+	(repo ? repo : the_repository)->fetch_if_missing = 0;
 
 	disable_replace_refs();
 
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 2b14dd2f31..7dea8940a0 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -4090,7 +4090,7 @@ static void add_unreachable_loose_objects(struct rev_info *revs);
 static void read_stdin_packs(struct repository *repo,
 			     enum stdin_packs_mode mode, int rev_list_unpacked)
 {
-	int prev_fetch_if_missing = fetch_if_missing;
+	int prev_fetch_if_missing = repo->fetch_if_missing;
 	struct rev_info revs;
 
 	/*
@@ -4098,7 +4098,7 @@ static void read_stdin_packs(struct repository *repo,
 	 * walk is best-effort though we don't want to perform backfill fetches
 	 * for them.
 	 */
-	fetch_if_missing = 0;
+	repo->fetch_if_missing = 0;
 
 	repo_init_revisions(repo, &revs, NULL);
 	/*
@@ -4146,7 +4146,7 @@ static void read_stdin_packs(struct repository *repo,
 	trace2_data_intmax("pack-objects", the_repository, "stdin_packs_hints",
 			   stdin_packs_hints_nr);
 
-	fetch_if_missing = prev_fetch_if_missing;
+	repo->fetch_if_missing = prev_fetch_if_missing;
 }
 
 static void add_cruft_object_entry(const struct object_id *oid, enum object_type type,
@@ -5268,7 +5268,7 @@ int cmd_pack_objects(int argc,
 
 	if (arg_missing_action == MA_ALLOW_ANY ||
 	    arg_missing_action == MA_ALLOW_PROMISOR)
-		fetch_if_missing = 0;
+		repo->fetch_if_missing = 0;
 
 	if (argc) {
 		base_name = argv[0];
@@ -5348,7 +5348,7 @@ int cmd_pack_objects(int argc,
 				  exclude_promisor_objects_best_effort,
 				  "--exclude-promisor-objects-best-effort");
 	if (exclude_promisor_objects) {
-		fetch_if_missing = 0;
+		repo->fetch_if_missing = 0;
 
 		/* --stdin-packs handles promisor objects separately. */
 		if (!stdin_packs) {
@@ -5357,7 +5357,7 @@ int cmd_pack_objects(int argc,
 		}
 	} else if (exclude_promisor_objects_best_effort) {
 		use_internal_rev_list = 1;
-		fetch_if_missing = 0;
+		repo->fetch_if_missing = 0;
 		option_parse_missing_action(NULL, "allow-any", 0);
 		/* revs configured below */
 	}
diff --git a/builtin/prune.c b/builtin/prune.c
index 55635a891f..a7e4678d11 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -194,7 +194,7 @@ int cmd_prune(int argc,
 	if (show_progress == -1)
 		show_progress = isatty(2);
 	if (exclude_promisor_objects) {
-		fetch_if_missing = 0;
+		repo->fetch_if_missing = 0;
 		revs.exclude_promisor_objects = 1;
 	}
 
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 02818b81c6..6b596231ab 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -500,7 +500,8 @@ static void print_disk_usage(off_t size)
 	strbuf_release(&sb);
 }
 
-static inline int parse_missing_action_value(const char *value)
+static inline int parse_missing_action_value(struct repository *repo,
+					     const char *value)
 {
 	if (!strcmp(value, "error")) {
 		arg_missing_action = MA_ERROR;
@@ -509,25 +510,25 @@ static inline int parse_missing_action_value(const char *value)
 
 	if (!strcmp(value, "allow-any")) {
 		arg_missing_action = MA_ALLOW_ANY;
-		fetch_if_missing = 0;
+		repo->fetch_if_missing = 0;
 		return 1;
 	}
 
 	if (!strcmp(value, "print")) {
 		arg_missing_action = MA_PRINT;
-		fetch_if_missing = 0;
+		repo->fetch_if_missing = 0;
 		return 1;
 	}
 
 	if (!strcmp(value, "print-info")) {
 		arg_missing_action = MA_PRINT_INFO;
-		fetch_if_missing = 0;
+		repo->fetch_if_missing = 0;
 		return 1;
 	}
 
 	if (!strcmp(value, "allow-promisor")) {
 		arg_missing_action = MA_ALLOW_PROMISOR;
-		fetch_if_missing = 0;
+		repo->fetch_if_missing = 0;
 		return 1;
 	}
 
@@ -692,7 +693,7 @@ static void prepare_maximal_independent(struct rev_info *revs)
 int cmd_rev_list(int argc,
 		 const char **argv,
 		 const char *prefix,
-		 struct repository *repo UNUSED)
+		 struct repository *repo)
 {
 	struct rev_info revs;
 	struct rev_list_info info;
@@ -745,10 +746,10 @@ int cmd_rev_list(int argc,
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		if (!strcmp(arg, "--exclude-promisor-objects")) {
-			fetch_if_missing = 0;
+			repo->fetch_if_missing = 0;
 			revs.exclude_promisor_objects = 1;
 		} else if (skip_prefix(arg, "--missing=", &arg)) {
-			parse_missing_action_value(arg);
+			parse_missing_action_value(repo, arg);
 		} else if (!strcmp(arg, "-z")) {
 			line_term = '\0';
 			info_term = '\0';
diff --git a/common-init.c b/common-init.c
index d26c9c1f20..4a3fa4d7be 100644
--- a/common-init.c
+++ b/common-init.c
@@ -47,7 +47,7 @@ static void setup_environment(void)
 	update_ref_namespace(NAMESPACE_REPLACE, git_replace_ref_base);
 
 	if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT, 0))
-		fetch_if_missing = 0;
+		the_repository->fetch_if_missing = 0;
 }
 
 void init_git(const char **argv)
diff --git a/git.c b/git.c
index e5f1811b6b..f3ad3aad96 100644
--- a/git.c
+++ b/git.c
@@ -202,7 +202,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 			if (envchanged)
 				*envchanged = 1;
 		} else if (!strcmp(cmd, "--no-lazy-fetch")) {
-			fetch_if_missing = 0;
+			the_repository->fetch_if_missing = 0;
 			setenv(NO_LAZY_FETCH_ENVIRONMENT, "1", 1);
 			if (envchanged)
 				*envchanged = 1;
diff --git a/midx-write.c b/midx-write.c
index 580724d21a..8537102254 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -865,7 +865,7 @@ static void find_commits_for_midx_bitmap(struct commit_stack *commits,
 	 * complain later that we don't have reachability closure (and fail
 	 * appropriately).
 	 */
-	fetch_if_missing = 0;
+	ctx->repo->fetch_if_missing = 0;
 	revs.exclude_promisor_objects = 1;
 
 	if (prepare_revision_walk(&revs))
diff --git a/odb.c b/odb.c
index dabd481f57..110326f063 100644
--- a/odb.c
+++ b/odb.c
@@ -528,8 +528,6 @@ void disable_obj_read_lock(void)
 	pthread_mutex_destroy(&obj_read_mutex);
 }
 
-int fetch_if_missing = 1;
-
 static int register_all_submodule_sources(struct object_database *odb)
 {
 	int ret = odb->submodule_source_paths.nr;
@@ -595,7 +593,7 @@ static int do_oid_object_info_extended(struct object_database *odb,
 			continue;
 
 		/* Check if it is a missing object */
-		if (fetch_if_missing && repo_has_promisor_remote(odb->repo) &&
+		if (odb->repo->fetch_if_missing && repo_has_promisor_remote(odb->repo) &&
 		    !already_retried &&
 		    !(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
 			promisor_remote_get_direct(odb->repo, real, 1);
diff --git a/odb.h b/odb.h
index cbc2f9ced4..d3a1e378b6 100644
--- a/odb.h
+++ b/odb.h
@@ -15,14 +15,6 @@ struct repository;
 struct strbuf;
 struct strvec;
 
-/*
- * Set this to 0 to prevent odb_read_object_info_extended() from fetching missing
- * blobs. This has a difference only if extensions.partialClone is set.
- *
- * Its default value is 1.
- */
-extern int fetch_if_missing;
-
 /*
  * Compute the exact path an alternate is at and returns it. In case of
  * error NULL is returned and the human readable error is added to `err`
diff --git a/repository.c b/repository.c
index 651b0f6933..c2d954cf83 100644
--- a/repository.c
+++ b/repository.c
@@ -74,6 +74,7 @@ void initialize_repository(struct repository *repo)
 	index_state_init(repo->index, repo);
 	repo->check_deprecated_config = true;
 	repo->bare_cfg = -1;
+	repo->fetch_if_missing = 1;
 	repo_config_values_init(&repo->config_values_private_);
 
 	/*
diff --git a/repository.h b/repository.h
index 3b467a2513..11f5c2ed10 100644
--- a/repository.h
+++ b/repository.h
@@ -184,6 +184,12 @@ struct repository {
 	/* True if commit-graph has been disabled within this process. */
 	int commit_graph_disabled;
 
+	/*
+	 * Controls whether the repository should lazily fetch missing
+	 * objects from promisor remotes. Defaults to 1.
+	 */
+	int fetch_if_missing;
+
 	/*
 	 * Lazily-populated cache mapping hook event names to configured hooks.
 	 * NULL until first hook use.
diff --git a/revision.c b/revision.c
index 526bcf3fb5..40cb1cc828 100644
--- a/revision.c
+++ b/revision.c
@@ -2732,7 +2732,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		revs->ignore_missing = 1;
 	} else if (opt && opt->allow_exclude_promisor_objects &&
 		   !strcmp(arg, "--exclude-promisor-objects")) {
-		if (fetch_if_missing)
+		if (revs->repo->fetch_if_missing)
 			BUG("exclude_promisor_objects can only be used when fetch_if_missing is 0");
 		revs->exclude_promisor_objects = 1;
 	} else {
-- 
2.43.0


      parent reply	other threads:[~2026-08-14  7:24 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-15  1:18 [PATCH v1] repository: move fetch_if_missing into struct repository Tian Yuchen
2026-07-15  3:27 ` Junio C Hamano
2026-07-15  4:58   ` Tian Yuchen
2026-07-15  6:35 ` Patrick Steinhardt
2026-07-16  7:06   ` Tian Yuchen
2026-07-16 15:28   ` Junio C Hamano
2026-07-16  7:29 ` [PATCH v2] " Tian Yuchen
2026-08-01 15:53   ` Tian Yuchen
2026-08-04  8:24   ` Patrick Steinhardt
2026-08-04 17:38     ` Junio C Hamano
2026-08-05 12:34       ` Tian Yuchen
2026-08-05 12:10     ` Tian Yuchen
2026-08-07  9:41   ` [PATCH v3] " Tian Yuchen
2026-08-07 17:03     ` Junio C Hamano
2026-08-09 15:00       ` Tian Yuchen
2026-08-13  6:11     ` [PATCH v4] " Tian Yuchen
2026-08-13 16:32       ` Junio C Hamano
2026-08-14  7:24       ` [PATCH v5 0/2] " Tian Yuchen
2026-08-14  7:24         ` [PATCH v5 1/2] pack-objects: give fetch_if_missing call sites access to 'repo' Tian Yuchen
2026-08-14  7:24         ` Tian Yuchen [this message]

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=20260814072419.1666358-3-cat@malon.dev \
    --to=cat@malon.dev \
    --cc=ayu.chandekar@gmail.com \
    --cc=belkid98@gmail.com \
    --cc=christian.couder@gmail.com \
    --cc=git@vger.kernel.org \
    /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