All of lore.kernel.org
 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: 22+ 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 14:38           ` Junio C Hamano
2026-08-14  7:24         ` Tian Yuchen [this message]
2026-08-14 14:44         ` [PATCH v5 0/2] repository: move fetch_if_missing into struct repository 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=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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.