Git development
 help / color / mirror / Atom feed
* [PATCH 0/7] setup: drop global state
@ 2026-06-10  6:56 Patrick Steinhardt
  2026-06-10  6:56 ` [PATCH 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable Patrick Steinhardt
                   ` (7 more replies)
  0 siblings, 8 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-10  6:56 UTC (permalink / raw)
  To: git

Hi,

this patch series continues to refactor "setup.c", where the focus is to
drop remaining global state that we have in "setup.c". The most
important consequence of this is that we don't need to rely on
`the_repository` in `is_bare_repository()` anymore.

This series is built on top of 1ff279f340 (The 13th batch, 2026-06-09)
with ps/setup-centralize-odb-creation at 42b9d3dc9d (setup: construct
object database in `apply_repository_format()`, 2026-06-04) merged into
it.

Thanks!

Patrick

---
Patrick Steinhardt (7):
      builtin/init: stop modifying global `git_work_tree_cfg` variable
      builtin/init: simplify logic to configure worktree
      setup: remove global `git_work_tree_cfg` variable
      builtin/init: stop modifying `is_bare_repository_cfg`
      environment: split up concerns of `is_bare_repository_cfg`
      environment: stop using `the_repository` in `is_bare_repository()`
      treewide: drop USE_THE_REPOSITORY_VARIABLE

 attr.c                  |  4 ++--
 builtin/bisect.c        |  2 +-
 builtin/blame.c         |  2 +-
 builtin/check-attr.c    |  2 +-
 builtin/fetch.c         |  2 +-
 builtin/gc.c            |  2 +-
 builtin/history.c       |  2 +-
 builtin/init-db.c       | 44 +++++++++++++++++++++++++++-----------------
 builtin/repack.c        |  3 +--
 builtin/repo.c          |  2 +-
 builtin/reset.c         |  2 +-
 builtin/rev-parse.c     |  2 +-
 environment.c           | 10 +++-------
 environment.h           |  6 ++----
 git.c                   |  2 +-
 mailmap.c               |  6 ++----
 refs/files-backend.c    |  2 +-
 refs/reftable-backend.c |  4 +---
 repository.c            |  1 +
 repository.h            |  7 +++++++
 setup.c                 | 45 ++++++++++++++++++++++++---------------------
 setup.h                 |  6 ++++++
 transport.c             |  4 ++--
 worktree.c              |  4 ++--
 24 files changed, 91 insertions(+), 75 deletions(-)


---
base-commit: f5a08a09a0fdf0fc2a355eba7979e2cfd65659e5
change-id: 20260422-b4-pks-setup-drop-global-state-6b1374aed5db


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable
  2026-06-10  6:56 [PATCH 0/7] setup: drop global state Patrick Steinhardt
@ 2026-06-10  6:56 ` Patrick Steinhardt
  2026-06-10 21:15   ` Justin Tobler
  2026-06-10  6:56 ` [PATCH 2/7] builtin/init: simplify logic to configure worktree Patrick Steinhardt
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-10  6:56 UTC (permalink / raw)
  To: git

When executing git-init(1) we need to figure out the final location of
the worktree. This location can be configured in a couple of ways: via
an environment variable, via the preexisting "core.worktree" config in
case we're reinitializing, or implicitly when reinitializing a non-bare
repository.

When checking for the worktree location in "builtin/init-db.c" we
populate any potentially-discovered value both by setting the global
`git_work_tree_cfg` variable and via `set_git_work_tree()`, which
ultimately ends up modifying `struct repository::worktree`.

Modifying `git_work_tree_cfg` is unnecessary though: we configure the
worktree in `create_default_files()`, and that function derives the
worktree location via `repo_get_work_tree()`. Consequently, propagating
the worktree via `set_git_work_tree()` is sufficient.

Stop munging `git_work_tree_cfg` and make it file-local to "setup.c" and
function-local to `cmd_init_db()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/init-db.c | 4 ++++
 environment.c     | 3 ---
 environment.h     | 1 -
 setup.c           | 3 +++
 4 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index c55517ad94..01bc27904e 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -229,6 +229,8 @@ int cmd_init_db(int argc,
 
 	if (!is_bare_repository_cfg) {
 		const char *git_dir_parent = strrchr(git_dir, '/');
+		char *git_work_tree_cfg = NULL;
+
 		if (git_dir_parent) {
 			char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
 			git_work_tree_cfg = real_pathdup(rel, 1);
@@ -243,6 +245,8 @@ int cmd_init_db(int argc,
 		if (access(repo_get_work_tree(the_repository), X_OK))
 			die_errno (_("Cannot access work tree '%s'"),
 				   repo_get_work_tree(the_repository));
+
+		free(git_work_tree_cfg);
 	}
 	else {
 		if (real_git_dir)
diff --git a/environment.c b/environment.c
index fc3ed8bb1c..4e86335f25 100644
--- a/environment.c
+++ b/environment.c
@@ -100,9 +100,6 @@ int auto_comment_line_char;
 bool warn_on_auto_comment_char;
 #endif /* !WITH_BREAKING_CHANGES */
 
-/* This is set by setup_git_directory_gently() and/or git_default_config() */
-char *git_work_tree_cfg;
-
 /*
  * Repository-local GIT_* environment variables; see environment.h for details.
  */
diff --git a/environment.h b/environment.h
index ccfcf37bfb..5d6e4e6c1b 100644
--- a/environment.h
+++ b/environment.h
@@ -149,7 +149,6 @@ int have_git_dir(void);
 
 extern int is_bare_repository_cfg;
 int is_bare_repository(void);
-extern char *git_work_tree_cfg;
 
 /* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
diff --git a/setup.c b/setup.c
index b4652651df..52228b42a1 100644
--- a/setup.c
+++ b/setup.c
@@ -31,6 +31,9 @@ enum allowed_bare_repo {
 	ALLOWED_BARE_REPO_ALL,
 };
 
+/* This is set by setup_git_directory_gently() and/or git_default_config() */
+static char *git_work_tree_cfg;
+
 static struct startup_info the_startup_info;
 struct startup_info *startup_info = &the_startup_info;
 const char *tmp_original_cwd;

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 2/7] builtin/init: simplify logic to configure worktree
  2026-06-10  6:56 [PATCH 0/7] setup: drop global state Patrick Steinhardt
  2026-06-10  6:56 ` [PATCH 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable Patrick Steinhardt
@ 2026-06-10  6:56 ` Patrick Steinhardt
  2026-06-10 21:29   ` Justin Tobler
  2026-06-10  6:56 ` [PATCH 3/7] setup: remove global `git_work_tree_cfg` variable Patrick Steinhardt
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-10  6:56 UTC (permalink / raw)
  To: git

In the preceding commit we have stopped modifying the global
`git_work_tree_cfg` variable. With this change there's now some code
paths where we end up setting the local `git_work_tree_cfg` variable,
but without actually using the value for anything.

Refactor the code a bit so that we only set the worktree configuration
in case it's actually needed. Furthermore, reflow it a bit to make the
code easier to follow.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/init-db.c | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index 01bc27904e..b4343c2804 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -229,24 +229,29 @@ int cmd_init_db(int argc,
 
 	if (!is_bare_repository_cfg) {
 		const char *git_dir_parent = strrchr(git_dir, '/');
-		char *git_work_tree_cfg = NULL;
 
-		if (git_dir_parent) {
-			char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
-			git_work_tree_cfg = real_pathdup(rel, 1);
-			free(rel);
-		}
-		if (!git_work_tree_cfg)
-			git_work_tree_cfg = xgetcwd();
-		if (work_tree)
+		if (work_tree) {
 			set_git_work_tree(the_repository, work_tree);
-		else
-			set_git_work_tree(the_repository, git_work_tree_cfg);
+		} else {
+			char *work_tree_cfg = NULL;
+
+			if (git_dir_parent) {
+				char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
+				work_tree_cfg = real_pathdup(rel, 1);
+				free(rel);
+			}
+
+			if (!work_tree_cfg)
+				work_tree_cfg = xgetcwd();
+
+			set_git_work_tree(the_repository, work_tree_cfg);
+
+			free(work_tree_cfg);
+		}
+
 		if (access(repo_get_work_tree(the_repository), X_OK))
 			die_errno (_("Cannot access work tree '%s'"),
 				   repo_get_work_tree(the_repository));
-
-		free(git_work_tree_cfg);
 	}
 	else {
 		if (real_git_dir)

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 3/7] setup: remove global `git_work_tree_cfg` variable
  2026-06-10  6:56 [PATCH 0/7] setup: drop global state Patrick Steinhardt
  2026-06-10  6:56 ` [PATCH 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable Patrick Steinhardt
  2026-06-10  6:56 ` [PATCH 2/7] builtin/init: simplify logic to configure worktree Patrick Steinhardt
@ 2026-06-10  6:56 ` Patrick Steinhardt
  2026-06-10 21:52   ` Justin Tobler
  2026-06-10  6:56 ` [PATCH 4/7] builtin/init: stop modifying `is_bare_repository_cfg` Patrick Steinhardt
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-10  6:56 UTC (permalink / raw)
  To: git

The global `git_work_tree_cfg` variable used to be modified by both
"setup.c" and by "builtin/init-db.c". We have refactored the latter user
to not use that variable at all anymore in a preceding commit, which
makes "setup.c" the only remaining user.

Even for "setup.c" it is unnecessary though, as we only ever set it to
the value we have stored in the discovered repository format. The
consequence is that we only ever set it in case we already have it set
to the same value in our discovered repository format, which makes it
redundant.

Refactor the code so that we instead use the worktree configuration as
discovered via the repository format. Drop the global variable.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 setup.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/setup.c b/setup.c
index 52228b42a1..71fc6b33da 100644
--- a/setup.c
+++ b/setup.c
@@ -31,9 +31,6 @@ enum allowed_bare_repo {
 	ALLOWED_BARE_REPO_ALL,
 };
 
-/* This is set by setup_git_directory_gently() and/or git_default_config() */
-static char *git_work_tree_cfg;
-
 static struct startup_info the_startup_info;
 struct startup_info *startup_info = &the_startup_info;
 const char *tmp_original_cwd;
@@ -799,13 +796,10 @@ static int check_repository_format_gently(const char *gitdir,
 	}
 
 	if (!has_common) {
-		if (candidate->is_bare != -1) {
+		if (candidate->is_bare != -1)
 			is_bare_repository_cfg = candidate->is_bare;
-		}
-		if (candidate->work_tree) {
-			free(git_work_tree_cfg);
-			git_work_tree_cfg = xstrdup(candidate->work_tree);
-		}
+	} else {
+		FREE_AND_NULL(candidate->work_tree);
 	}
 
 	return 0;
@@ -1145,7 +1139,7 @@ static const char *setup_explicit_git_dir(struct repository *repo,
 	if (work_tree_env)
 		set_git_work_tree(repo, work_tree_env);
 	else if (is_bare_repository_cfg > 0) {
-		if (git_work_tree_cfg) {
+		if (repo_fmt->work_tree) {
 			/* #22.2, #30 */
 			warning("core.bare and core.worktree do not make sense");
 			repo->worktree_config_is_bogus = true;
@@ -1156,15 +1150,15 @@ static const char *setup_explicit_git_dir(struct repository *repo,
 		free(gitfile);
 		return NULL;
 	}
-	else if (git_work_tree_cfg) { /* #6, #14 */
-		if (is_absolute_path(git_work_tree_cfg))
-			set_git_work_tree(repo, git_work_tree_cfg);
+	else if (repo_fmt->work_tree) { /* #6, #14 */
+		if (is_absolute_path(repo_fmt->work_tree))
+			set_git_work_tree(repo, repo_fmt->work_tree);
 		else {
 			char *core_worktree;
 			if (chdir(gitdirenv))
 				die_errno(_("cannot chdir to '%s'"), gitdirenv);
-			if (chdir(git_work_tree_cfg))
-				die_errno(_("cannot chdir to '%s'"), git_work_tree_cfg);
+			if (chdir(repo_fmt->work_tree))
+				die_errno(_("cannot chdir to '%s'"), repo_fmt->work_tree);
 			core_worktree = xgetcwd();
 			if (chdir(cwd->buf))
 				die_errno(_("cannot come back to cwd"));
@@ -1217,7 +1211,7 @@ static const char *setup_discovered_git_dir(struct repository *repo,
 		return NULL;
 
 	/* --work-tree is set without --git-dir; use discovered one */
-	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || repo_fmt->work_tree) {
 		char *to_free = NULL;
 		const char *ret;
 
@@ -1267,7 +1261,7 @@ static const char *setup_bare_git_dir(struct repository *repo,
 	setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
 
 	/* --work-tree is set without --git-dir; use discovered one */
-	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || repo_fmt->work_tree) {
 		static const char *gitdir;
 
 		gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 4/7] builtin/init: stop modifying `is_bare_repository_cfg`
  2026-06-10  6:56 [PATCH 0/7] setup: drop global state Patrick Steinhardt
                   ` (2 preceding siblings ...)
  2026-06-10  6:56 ` [PATCH 3/7] setup: remove global `git_work_tree_cfg` variable Patrick Steinhardt
@ 2026-06-10  6:56 ` Patrick Steinhardt
  2026-06-10  6:56 ` [PATCH 5/7] environment: split up concerns of `is_bare_repository_cfg` Patrick Steinhardt
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-10  6:56 UTC (permalink / raw)
  To: git

We're modifying `is_bare_repository_cfg` in "builtin/init.c" to indicate
whether the newly created repository is supposed to be a bare repository
or not.

This is ultimately unnecessary though: when initializing the repository
in `init_db()` we eventually set `is_bare_repository_cfg = !work_tree`,
so all that matters is whether or not we have a working tree configured,
and the working tree is set up in the non-bare in "builtin/init.c".

Stop modifying the global variable in "builtin/init.c" in favor of a
local variable.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/init-db.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index b4343c2804..52aa92fb0a 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -81,6 +81,7 @@ int cmd_init_db(int argc,
 	const char *template_dir = NULL;
 	char *template_dir_to_free = NULL;
 	unsigned int flags = 0;
+	int bare = is_bare_repository_cfg;
 	const char *object_format = NULL;
 	const char *ref_format = NULL;
 	const char *initial_branch = NULL;
@@ -90,7 +91,7 @@ int cmd_init_db(int argc,
 	const struct option init_db_options[] = {
 		OPT_STRING(0, "template", &template_dir, N_("template-directory"),
 				N_("directory from which templates will be used")),
-		OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
+		OPT_SET_INT(0, "bare", &bare,
 				N_("create a bare repository"), 1),
 		{
 			.type = OPTION_CALLBACK,
@@ -116,7 +117,7 @@ int cmd_init_db(int argc,
 
 	argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
 
-	if (real_git_dir && is_bare_repository_cfg == 1)
+	if (real_git_dir && bare == 1)
 		die(_("options '%s' and '%s' cannot be used together"), "--separate-git-dir", "--bare");
 
 	if (real_git_dir && !is_absolute_path(real_git_dir))
@@ -160,7 +161,7 @@ int cmd_init_db(int argc,
 	} else if (0 < argc) {
 		usage(init_db_usage[0]);
 	}
-	if (is_bare_repository_cfg == 1) {
+	if (bare == 1) {
 		char *cwd = xgetcwd();
 		setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0);
 		free(cwd);
@@ -187,7 +188,7 @@ int cmd_init_db(int argc,
 	 */
 	git_dir = xstrdup_or_null(getenv(GIT_DIR_ENVIRONMENT));
 	work_tree = xstrdup_or_null(getenv(GIT_WORK_TREE_ENVIRONMENT));
-	if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
+	if ((!git_dir || bare == 1) && work_tree)
 		die(_("%s (or --work-tree=<directory>) not allowed without "
 			  "specifying %s (or --git-dir=<directory>)"),
 		    GIT_WORK_TREE_ENVIRONMENT,
@@ -224,10 +225,10 @@ int cmd_init_db(int argc,
 		strbuf_release(&sb);
 	}
 
-	if (is_bare_repository_cfg < 0)
-		is_bare_repository_cfg = guess_repository_type(git_dir);
+	if (bare < 0)
+		bare = guess_repository_type(git_dir);
 
-	if (!is_bare_repository_cfg) {
+	if (!bare) {
 		const char *git_dir_parent = strrchr(git_dir, '/');
 
 		if (work_tree) {

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 5/7] environment: split up concerns of `is_bare_repository_cfg`
  2026-06-10  6:56 [PATCH 0/7] setup: drop global state Patrick Steinhardt
                   ` (3 preceding siblings ...)
  2026-06-10  6:56 ` [PATCH 4/7] builtin/init: stop modifying `is_bare_repository_cfg` Patrick Steinhardt
@ 2026-06-10  6:56 ` Patrick Steinhardt
  2026-06-10 22:22   ` Justin Tobler
  2026-06-10  6:56 ` [PATCH 6/7] environment: stop using `the_repository` in `is_bare_repository()` Patrick Steinhardt
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-10  6:56 UTC (permalink / raw)
  To: git

The `is_bare_repository_cfg` variable tracks two different pieces of
information:

  - It tracks whether the user has invoked git with the "--bare" flag,
    which makes us treat any discovered Git repository as if it was a
    bare repository.

  - Otherwise it tracks whether the discovered `the_repository` is bare.

This makes the flag extremely confusing and creates a bit of a challenge
when handling multiple repositories in the same process.

Split up the concerns of this variable into two pieces:

  - `startup_info.force_bare_repository` tracks whether the user has
    passed the "--bare" flag. This is used as a hint to treat newly set
    up repositories as bare regardless of whether or not they have a
    worktree.

  - `struct repository::bare_cfg` tracks whether or not a repository is
    considered bare. This takes into account both whether the user has
    passed "--bare" and the discovered state of the repository itself.

Whether or not a repository is bare is now resolved when checking the
repository's format, and is then later applied to the repository itself
via `apply_repository_format()`.

This enables a subsequent change where we make `is_bare_repository()`
not depend on global state anymore.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/init-db.c |  2 +-
 environment.c     |  5 ++---
 environment.h     |  1 -
 git.c             |  2 +-
 repository.c      |  1 +
 repository.h      |  7 +++++++
 setup.c           | 21 ++++++++++++++-------
 setup.h           |  6 ++++++
 worktree.c        |  2 +-
 9 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index 52aa92fb0a..566732c9f4 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -81,7 +81,7 @@ int cmd_init_db(int argc,
 	const char *template_dir = NULL;
 	char *template_dir_to_free = NULL;
 	unsigned int flags = 0;
-	int bare = is_bare_repository_cfg;
+	int bare = startup_info->force_bare_repository ? 1 : -1;
 	const char *object_format = NULL;
 	const char *ref_format = NULL;
 	const char *initial_branch = NULL;
diff --git a/environment.c b/environment.c
index 4e86335f25..9d7c908c55 100644
--- a/environment.c
+++ b/environment.c
@@ -48,7 +48,6 @@ int has_symlinks = 1;
 int minimum_abbrev = 4, default_abbrev = -1;
 int ignore_case;
 int assume_unchanged;
-int is_bare_repository_cfg = -1; /* unspecified */
 int warn_on_object_refname_ambiguity = 1;
 char *git_commit_encoding;
 char *git_log_output_encoding;
@@ -136,7 +135,7 @@ const char *getenv_safe(struct strvec *argv, const char *name)
 int is_bare_repository(void)
 {
 	/* if core.bare is not 'false', let's see if there is a work tree */
-	return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
+	return the_repository->bare_cfg && !repo_get_work_tree(the_repository);
 }
 
 int have_git_dir(void)
@@ -342,7 +341,7 @@ int git_default_core_config(const char *var, const char *value,
 	}
 
 	if (!strcmp(var, "core.bare")) {
-		is_bare_repository_cfg = git_config_bool(var, value);
+		the_repository->bare_cfg = git_config_bool(var, value);
 		return 0;
 	}
 
diff --git a/environment.h b/environment.h
index 5d6e4e6c1b..afb5bcf197 100644
--- a/environment.h
+++ b/environment.h
@@ -147,7 +147,6 @@ void repo_config_values_init(struct repo_config_values *cfg);
  */
 int have_git_dir(void);
 
-extern int is_bare_repository_cfg;
 int is_bare_repository(void);
 
 /* Environment bits from configuration mechanism */
diff --git a/git.c b/git.c
index 36f08891ef..387eabe38c 100644
--- a/git.c
+++ b/git.c
@@ -255,7 +255,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 				*envchanged = 1;
 		} else if (!strcmp(cmd, "--bare")) {
 			char *cwd = xgetcwd();
-			is_bare_repository_cfg = 1;
+			startup_info->force_bare_repository = true;
 			setenv(GIT_DIR_ENVIRONMENT, cwd, 0);
 			free(cwd);
 			setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
diff --git a/repository.c b/repository.c
index 187dd471c4..c1e91eb0da 100644
--- a/repository.c
+++ b/repository.c
@@ -73,6 +73,7 @@ void initialize_repository(struct repository *repo)
 	ALLOC_ARRAY(repo->index, 1);
 	index_state_init(repo->index, repo);
 	repo->check_deprecated_config = true;
+	repo->bare_cfg = -1;
 	repo_config_values_init(&repo->config_values_private_);
 
 	/*
diff --git a/repository.h b/repository.h
index 36e2db2633..7d649e32e7 100644
--- a/repository.h
+++ b/repository.h
@@ -117,6 +117,13 @@ struct repository {
 	bool worktree_initialized;
 	bool worktree_config_is_bogus;
 
+	/*
+	 * Whether the repository is bare, as set by "core.bare" config or
+	 * inferred during repository discovery. -1 means unset/unknown, 0
+	 * means non-bare, 1 means bare.
+	 */
+	int bare_cfg;
+
 	/*
 	 * Path from the root of the top-level superproject down to this
 	 * repository.  This is only non-NULL if the repository is initialized
diff --git a/setup.c b/setup.c
index 71fc6b33da..2b690da8ca 100644
--- a/setup.c
+++ b/setup.c
@@ -795,10 +795,16 @@ static int check_repository_format_gently(const char *gitdir,
 		has_common = 0;
 	}
 
-	if (!has_common) {
-		if (candidate->is_bare != -1)
-			is_bare_repository_cfg = candidate->is_bare;
-	} else {
+	if (startup_info->force_bare_repository) {
+		candidate->is_bare = 1;
+		FREE_AND_NULL(candidate->work_tree);
+	} else if (has_common) {
+		/*
+		 * When sharing a common dir with another repository (e.g. a
+		 * linked worktree), do not let this repository's config
+		 * dictate bareness; it is inherited from the main worktree.
+		 */
+		candidate->is_bare = -1;
 		FREE_AND_NULL(candidate->work_tree);
 	}
 
@@ -1138,7 +1144,7 @@ static const char *setup_explicit_git_dir(struct repository *repo,
 	/* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
 	if (work_tree_env)
 		set_git_work_tree(repo, work_tree_env);
-	else if (is_bare_repository_cfg > 0) {
+	else if (repo_fmt->is_bare > 0) {
 		if (repo_fmt->work_tree) {
 			/* #22.2, #30 */
 			warning("core.bare and core.worktree do not make sense");
@@ -1225,7 +1231,7 @@ static const char *setup_discovered_git_dir(struct repository *repo,
 	}
 
 	/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
-	if (is_bare_repository_cfg > 0) {
+	if (repo_fmt->is_bare > 0) {
 		set_git_dir(repo, gitdir, (offset != cwd->len));
 		if (chdir(cwd->buf))
 			die_errno(_("cannot come back to cwd"));
@@ -1762,6 +1768,7 @@ int apply_repository_format(struct repository *repo,
 		alternate_object_directories = xstrdup_or_null(getenv(ALTERNATE_DB_ENVIRONMENT));
 	}
 
+	repo->bare_cfg = format->is_bare;
 	repo_set_hash_algo(repo, format->hash_algo);
 	repo->objects = odb_new(repo, object_directory,
 				alternate_object_directories);
@@ -2571,7 +2578,7 @@ static int create_default_files(struct repository *repo,
 		repo_settings_set_shared_repository(repo,
 						    init_shared_repository);
 
-	is_bare_repository_cfg = !work_tree;
+	repo->bare_cfg = !work_tree;
 
 	/*
 	 * We would have created the above under user's umask -- under
diff --git a/setup.h b/setup.h
index 705d1d6ff7..b9fd96bea6 100644
--- a/setup.h
+++ b/setup.h
@@ -292,6 +292,12 @@ enum sharedrepo {
 int git_config_perm(const char *var, const char *value);
 
 struct startup_info {
+	/*
+	 * Whether the user is asking us to treat the repository as bare via
+	 * `git --bare`, even if it's not.
+	 */
+	bool force_bare_repository;
+
 	int have_repository;
 	const char *prefix;
 	const char *original_cwd;
diff --git a/worktree.c b/worktree.c
index 97eddc3916..7d70f2c1da 100644
--- a/worktree.c
+++ b/worktree.c
@@ -123,7 +123,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
 	worktree->repo = the_repository;
 	worktree->path = strbuf_detach(&worktree_path, NULL);
 	worktree->is_current = is_current_worktree(worktree);
-	worktree->is_bare = (is_bare_repository_cfg == 1) ||
+	worktree->is_bare = (the_repository->bare_cfg == 1) ||
 		is_bare_repository() ||
 		/*
 		 * When in a secondary worktree we have to also verify if the main

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 6/7] environment: stop using `the_repository` in `is_bare_repository()`
  2026-06-10  6:56 [PATCH 0/7] setup: drop global state Patrick Steinhardt
                   ` (4 preceding siblings ...)
  2026-06-10  6:56 ` [PATCH 5/7] environment: split up concerns of `is_bare_repository_cfg` Patrick Steinhardt
@ 2026-06-10  6:56 ` Patrick Steinhardt
  2026-06-10  6:56 ` [PATCH 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE Patrick Steinhardt
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
  7 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-10  6:56 UTC (permalink / raw)
  To: git

Refactor `is_bare_repository()` to take in a repository parameter so
that we no longer depend on `the_repository`. Adjust callers
accordingly.

Furthermore, move the function outside of the declarations that are only
available when `USE_THE_REPOSITORY_VARIABLE` is set, as it no longer
depends on that variable.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 attr.c                  | 4 ++--
 builtin/bisect.c        | 2 +-
 builtin/blame.c         | 2 +-
 builtin/check-attr.c    | 2 +-
 builtin/fetch.c         | 2 +-
 builtin/gc.c            | 2 +-
 builtin/history.c       | 2 +-
 builtin/repack.c        | 2 +-
 builtin/repo.c          | 2 +-
 builtin/reset.c         | 2 +-
 builtin/rev-parse.c     | 2 +-
 environment.c           | 4 ++--
 environment.h           | 4 ++--
 mailmap.c               | 4 ++--
 refs/files-backend.c    | 2 +-
 refs/reftable-backend.c | 2 +-
 setup.c                 | 2 +-
 transport.c             | 4 ++--
 worktree.c              | 2 +-
 19 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/attr.c b/attr.c
index 75369547b3..04cb284954 100644
--- a/attr.c
+++ b/attr.c
@@ -681,7 +681,7 @@ static enum git_attr_direction direction;
 
 void git_attr_set_direction(enum git_attr_direction new_direction)
 {
-	if (is_bare_repository() && new_direction != GIT_ATTR_INDEX)
+	if (is_bare_repository(the_repository) && new_direction != GIT_ATTR_INDEX)
 		BUG("non-INDEX attr direction in a bare repo");
 
 	if (new_direction != direction)
@@ -848,7 +848,7 @@ static struct attr_stack *read_attr(struct index_state *istate,
 		res = read_attr_from_index(istate, path, flags);
 	} else if (tree_oid) {
 		res = read_attr_from_blob(istate, tree_oid, path, flags);
-	} else if (!is_bare_repository()) {
+	} else if (!is_bare_repository(the_repository)) {
 		if (direction == GIT_ATTR_CHECKOUT) {
 			res = read_attr_from_index(istate, path, flags);
 			if (!res)
diff --git a/builtin/bisect.c b/builtin/bisect.c
index e7c2d2f3bb..798e28f501 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -724,7 +724,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
 	struct object_id oid;
 	const char *head;
 
-	if (is_bare_repository())
+	if (is_bare_repository(the_repository))
 		no_checkout = 1;
 
 	/*
diff --git a/builtin/blame.c b/builtin/blame.c
index ffbd3ce5c5..553f4cb780 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1163,7 +1163,7 @@ int cmd_blame(int argc,
 
 	revs.disable_stdin = 1;
 	setup_revisions(argc, argv, &revs, NULL);
-	if (!revs.pending.nr && is_bare_repository()) {
+	if (!revs.pending.nr && is_bare_repository(the_repository)) {
 		struct commit *head_commit;
 		struct object_id head_oid;
 
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 98f64d5b92..217d83ea7d 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -116,7 +116,7 @@ int cmd_check_attr(int argc,
 	struct object_id initialized_oid;
 	int cnt, i, doubledash, filei;
 
-	if (!is_bare_repository())
+	if (!is_bare_repository(the_repository))
 		setup_work_tree(the_repository);
 
 	repo_config(the_repository, git_default_config, NULL);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index c1d7c672f4..44b8c70da1 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1764,7 +1764,7 @@ static int set_head(const struct ref *remote_refs, struct remote *remote)
 
 	if (!head_name)
 		goto cleanup;
-	baremirror = is_bare_repository() && remote->mirror;
+	baremirror = is_bare_repository(the_repository) && remote->mirror;
 	create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !baremirror;
 	if (baremirror) {
 		strbuf_addstr(&b_head, "HEAD");
diff --git a/builtin/gc.c b/builtin/gc.c
index 84a66d3240..61da30de9f 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -902,7 +902,7 @@ int cmd_gc(int argc,
 		die(_("failed to parse gc.logExpiry value %s"), cfg.gc_log_expire);
 
 	if (cfg.pack_refs < 0)
-		cfg.pack_refs = !is_bare_repository();
+		cfg.pack_refs = !is_bare_repository(the_repository);
 
 	argc = parse_options(argc, argv, prefix, builtin_gc_options,
 			     builtin_gc_usage, 0);
diff --git a/builtin/history.c b/builtin/history.c
index 091465a59e..fd83de8265 100644
--- a/builtin/history.c
+++ b/builtin/history.c
@@ -525,7 +525,7 @@ static int cmd_history_fixup(int argc,
 	if (action == REF_ACTION_DEFAULT)
 		action = REF_ACTION_BRANCHES;
 
-	if (is_bare_repository()) {
+	if (is_bare_repository(repo)) {
 		ret = error(_("cannot run fixup in a bare repository"));
 		goto out;
 	}
diff --git a/builtin/repack.c b/builtin/repack.c
index 1524a9c13a..bbc6f51639 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -265,7 +265,7 @@ int cmd_repack(int argc,
 
 	if (write_bitmaps < 0) {
 		if (write_midx == REPACK_WRITE_MIDX_NONE &&
-		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
+		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(the_repository)))
 			write_bitmaps = 0;
 	}
 	if (po_args.pack_kept_objects < 0)
diff --git a/builtin/repo.c b/builtin/repo.c
index 71a5c1c29c..34e96514bc 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -58,7 +58,7 @@ struct repo_info_field {
 
 static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
 {
-	strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
+	strbuf_addstr(buf, is_bare_repository(the_repository) ? "true" : "false");
 	return 0;
 }
 
diff --git a/builtin/reset.c b/builtin/reset.c
index 3be6bd0121..78e69bd84b 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -470,7 +470,7 @@ int cmd_reset(int argc,
 	if (reset_type != SOFT && (reset_type != MIXED || repo_get_work_tree(the_repository)))
 		setup_work_tree(the_repository);
 
-	if (reset_type == MIXED && is_bare_repository())
+	if (reset_type == MIXED && is_bare_repository(the_repository))
 		die(_("%s reset is not allowed in a bare repository"),
 		    _(reset_type_names[reset_type]));
 
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index bb882678fe..090e5cfbb0 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -1084,7 +1084,7 @@ int cmd_rev_parse(int argc,
 				continue;
 			}
 			if (!strcmp(arg, "--is-bare-repository")) {
-				printf("%s\n", is_bare_repository() ? "true"
+				printf("%s\n", is_bare_repository(the_repository) ? "true"
 						: "false");
 				continue;
 			}
diff --git a/environment.c b/environment.c
index 9d7c908c55..bf20953415 100644
--- a/environment.c
+++ b/environment.c
@@ -132,10 +132,10 @@ const char *getenv_safe(struct strvec *argv, const char *name)
 	return argv->v[argv->nr - 1];
 }
 
-int is_bare_repository(void)
+int is_bare_repository(struct repository *repo)
 {
 	/* if core.bare is not 'false', let's see if there is a work tree */
-	return the_repository->bare_cfg && !repo_get_work_tree(the_repository);
+	return repo->bare_cfg && !repo_get_work_tree(repo);
 }
 
 int have_git_dir(void)
diff --git a/environment.h b/environment.h
index afb5bcf197..164a55df2c 100644
--- a/environment.h
+++ b/environment.h
@@ -125,6 +125,8 @@ int git_default_core_config(const char *var, const char *value,
 
 void repo_config_values_init(struct repo_config_values *cfg);
 
+int is_bare_repository(struct repository *repo);
+
 /*
  * TODO: All the below state either explicitly or implicitly relies on
  * `the_repository`. We should eventually get rid of these and make the
@@ -147,8 +149,6 @@ void repo_config_values_init(struct repo_config_values *cfg);
  */
 int have_git_dir(void);
 
-int is_bare_repository(void);
-
 /* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
 extern int trust_ctime;
diff --git a/mailmap.c b/mailmap.c
index 3b2691781d..7d8590cdd6 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -219,10 +219,10 @@ int read_mailmap(struct repository *repo, struct string_list *map)
 	map->strdup_strings = 1;
 	map->cmp = namemap_cmp;
 
-	if (!mailmap_blob && is_bare_repository())
+	if (!mailmap_blob && is_bare_repository(the_repository))
 		mailmap_blob = xstrdup("HEAD:.mailmap");
 
-	if (!startup_info->have_repository || !is_bare_repository())
+	if (!startup_info->have_repository || !is_bare_repository(the_repository))
 		err |= read_mailmap_file(map, ".mailmap",
 					 startup_info->have_repository ?
 					 MAILMAP_NOFOLLOW : 0);
diff --git a/refs/files-backend.c b/refs/files-backend.c
index a4c7858787..2b27091484 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1865,7 +1865,7 @@ static int log_ref_setup(struct files_ref_store *refs,
 	char *logfile;
 
 	if (log_refs_cfg == LOG_REFS_UNSET)
-		log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+		log_refs_cfg = is_bare_repository(the_repository) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
 
 	files_reflog_path(refs, &logfile_sb, refname);
 	logfile = strbuf_detach(&logfile_sb, NULL);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 4ae22922de..101ef29ac8 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -288,7 +288,7 @@ static int should_write_log(struct reftable_ref_store *refs, const char *refname
 {
 	enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
 	if (log_refs_cfg == LOG_REFS_UNSET)
-		log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+		log_refs_cfg = is_bare_repository(the_repository) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
 
 	switch (log_refs_cfg) {
 	case LOG_REFS_NONE:
diff --git a/setup.c b/setup.c
index 2b690da8ca..6b95bf546d 100644
--- a/setup.c
+++ b/setup.c
@@ -2604,7 +2604,7 @@ static int create_default_files(struct repository *repo,
 	}
 	repo_config_set(repo, "core.filemode", filemode ? "true" : "false");
 
-	if (is_bare_repository())
+	if (is_bare_repository(the_repository))
 		repo_config_set(repo, "core.bare", "true");
 	else {
 		repo_config_set(repo, "core.bare", "false");
diff --git a/transport.c b/transport.c
index 0f5ec30247..fc144f0aed 100644
--- a/transport.c
+++ b/transport.c
@@ -1482,7 +1482,7 @@ int transport_push(struct repository *r,
 
 	if ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |
 		      TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&
-	    !is_bare_repository()) {
+	    !is_bare_repository(the_repository)) {
 		struct ref *ref = remote_refs;
 		struct oid_array commits = OID_ARRAY_INIT;
 
@@ -1509,7 +1509,7 @@ int transport_push(struct repository *r,
 	if (((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) ||
 	     ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |
 			TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&
-	      !pretend)) && !is_bare_repository()) {
+	      !pretend)) && !is_bare_repository(the_repository)) {
 		struct ref *ref = remote_refs;
 		struct string_list needs_pushing = STRING_LIST_INIT_DUP;
 		struct oid_array commits = OID_ARRAY_INIT;
diff --git a/worktree.c b/worktree.c
index 7d70f2c1da..30125827fd 100644
--- a/worktree.c
+++ b/worktree.c
@@ -124,7 +124,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
 	worktree->path = strbuf_detach(&worktree_path, NULL);
 	worktree->is_current = is_current_worktree(worktree);
 	worktree->is_bare = (the_repository->bare_cfg == 1) ||
-		is_bare_repository() ||
+		is_bare_repository(the_repository) ||
 		/*
 		 * When in a secondary worktree we have to also verify if the main
 		 * worktree is bare in $commondir/config.worktree.

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE
  2026-06-10  6:56 [PATCH 0/7] setup: drop global state Patrick Steinhardt
                   ` (5 preceding siblings ...)
  2026-06-10  6:56 ` [PATCH 6/7] environment: stop using `the_repository` in `is_bare_repository()` Patrick Steinhardt
@ 2026-06-10  6:56 ` Patrick Steinhardt
  2026-06-10 22:26   ` Justin Tobler
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
  7 siblings, 1 reply; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-10  6:56 UTC (permalink / raw)
  To: git

Adapt a couple of trivial callers of `is_bare_repository()` to instead
use a repository available via the caller's context so that we can drop
the `USE_THE_REPOSITORY_VARIABLE` macro.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/repack.c        | 3 +--
 mailmap.c               | 6 ++----
 refs/reftable-backend.c | 4 +---
 setup.c                 | 3 +--
 4 files changed, 5 insertions(+), 11 deletions(-)

diff --git a/builtin/repack.c b/builtin/repack.c
index bbc6f51639..d0465fb4f5 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "builtin.h"
@@ -265,7 +264,7 @@ int cmd_repack(int argc,
 
 	if (write_bitmaps < 0) {
 		if (write_midx == REPACK_WRITE_MIDX_NONE &&
-		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(the_repository)))
+		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(repo)))
 			write_bitmaps = 0;
 	}
 	if (po_args.pack_kept_objects < 0)
diff --git a/mailmap.c b/mailmap.c
index 7d8590cdd6..2d5514f833 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "environment.h"
 #include "string-list.h"
@@ -219,10 +217,10 @@ int read_mailmap(struct repository *repo, struct string_list *map)
 	map->strdup_strings = 1;
 	map->cmp = namemap_cmp;
 
-	if (!mailmap_blob && is_bare_repository(the_repository))
+	if (!mailmap_blob && is_bare_repository(repo))
 		mailmap_blob = xstrdup("HEAD:.mailmap");
 
-	if (!startup_info->have_repository || !is_bare_repository(the_repository))
+	if (!startup_info->have_repository || !is_bare_repository(repo))
 		err |= read_mailmap_file(map, ".mailmap",
 					 startup_info->have_repository ?
 					 MAILMAP_NOFOLLOW : 0);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 101ef29ac8..c151d331e7 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "../git-compat-util.h"
 #include "../abspath.h"
 #include "../chdir-notify.h"
@@ -288,7 +286,7 @@ static int should_write_log(struct reftable_ref_store *refs, const char *refname
 {
 	enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
 	if (log_refs_cfg == LOG_REFS_UNSET)
-		log_refs_cfg = is_bare_repository(the_repository) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+		log_refs_cfg = is_bare_repository(refs->base.repo) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
 
 	switch (log_refs_cfg) {
 	case LOG_REFS_NONE:
diff --git a/setup.c b/setup.c
index 6b95bf546d..f24a805658 100644
--- a/setup.c
+++ b/setup.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -2604,7 +2603,7 @@ static int create_default_files(struct repository *repo,
 	}
 	repo_config_set(repo, "core.filemode", filemode ? "true" : "false");
 
-	if (is_bare_repository(the_repository))
+	if (is_bare_repository(repo))
 		repo_config_set(repo, "core.bare", "true");
 	else {
 		repo_config_set(repo, "core.bare", "false");

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable
  2026-06-10  6:56 ` [PATCH 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable Patrick Steinhardt
@ 2026-06-10 21:15   ` Justin Tobler
  0 siblings, 0 replies; 25+ messages in thread
From: Justin Tobler @ 2026-06-10 21:15 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git

On 26/06/10 08:56AM, Patrick Steinhardt wrote:
> When executing git-init(1) we need to figure out the final location of
> the worktree. This location can be configured in a couple of ways: via
> an environment variable, via the preexisting "core.worktree" config in
> case we're reinitializing, or implicitly when reinitializing a non-bare
> repository.
> 
> When checking for the worktree location in "builtin/init-db.c" we
> populate any potentially-discovered value both by setting the global
> `git_work_tree_cfg` variable and via `set_git_work_tree()`, which
> ultimately ends up modifying `struct repository::worktree`.

Does `git_work_tree_cfg` have any bearing on the worktree value that
ends up in `struct repository`? Or is it just `set_git_work_tree()`?

> Modifying `git_work_tree_cfg` is unnecessary though: we configure the
> worktree in `create_default_files()`, and that function derives the
> worktree location via `repo_get_work_tree()`. Consequently, propagating
> the worktree via `set_git_work_tree()` is sufficient.

Ok, so IIUC there is really no reason to globally store the
`git_work_tree_cfg` value derived during `cmd_init_db()`. We only care
about the worktree written to `struct repository`.

> Stop munging `git_work_tree_cfg` and make it file-local to "setup.c" and
> function-local to `cmd_init_db()`.

Makes sense.

> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  builtin/init-db.c | 4 ++++
>  environment.c     | 3 ---
>  environment.h     | 1 -
>  setup.c           | 3 +++
>  4 files changed, 7 insertions(+), 4 deletions(-)
> 
> diff --git a/builtin/init-db.c b/builtin/init-db.c
> index c55517ad94..01bc27904e 100644
> --- a/builtin/init-db.c
> +++ b/builtin/init-db.c
> @@ -229,6 +229,8 @@ int cmd_init_db(int argc,
>  
>  	if (!is_bare_repository_cfg) {
>  		const char *git_dir_parent = strrchr(git_dir, '/');
> +		char *git_work_tree_cfg = NULL;

We figure out the worktree locally and continue to set it via
`set_git_work_tree()` without updating a global worktree config value.

> +
>  		if (git_dir_parent) {
>  			char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
>  			git_work_tree_cfg = real_pathdup(rel, 1);
> @@ -243,6 +245,8 @@ int cmd_init_db(int argc,
>  		if (access(repo_get_work_tree(the_repository), X_OK))
>  			die_errno (_("Cannot access work tree '%s'"),
>  				   repo_get_work_tree(the_repository));
> +
> +		free(git_work_tree_cfg);
>  	}
>  	else {
>  		if (real_git_dir)
> diff --git a/environment.c b/environment.c
> index fc3ed8bb1c..4e86335f25 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -100,9 +100,6 @@ int auto_comment_line_char;
>  bool warn_on_auto_comment_char;
>  #endif /* !WITH_BREAKING_CHANGES */
>  
> -/* This is set by setup_git_directory_gently() and/or git_default_config() */
> -char *git_work_tree_cfg;
> -
>  /*
>   * Repository-local GIT_* environment variables; see environment.h for details.
>   */
> diff --git a/environment.h b/environment.h
> index ccfcf37bfb..5d6e4e6c1b 100644
> --- a/environment.h
> +++ b/environment.h
> @@ -149,7 +149,6 @@ int have_git_dir(void);
>  
>  extern int is_bare_repository_cfg;
>  int is_bare_repository(void);
> -extern char *git_work_tree_cfg;
>  
>  /* Environment bits from configuration mechanism */
>  extern int trust_executable_bit;
> diff --git a/setup.c b/setup.c
> index b4652651df..52228b42a1 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -31,6 +31,9 @@ enum allowed_bare_repo {
>  	ALLOWED_BARE_REPO_ALL,
>  };
>  
> +/* This is set by setup_git_directory_gently() and/or git_default_config() */
> +static char *git_work_tree_cfg;

Ok, now `git_work_tree_cfg` is only referenced from "setup.c".

-Justin

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 2/7] builtin/init: simplify logic to configure worktree
  2026-06-10  6:56 ` [PATCH 2/7] builtin/init: simplify logic to configure worktree Patrick Steinhardt
@ 2026-06-10 21:29   ` Justin Tobler
  0 siblings, 0 replies; 25+ messages in thread
From: Justin Tobler @ 2026-06-10 21:29 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git

On 26/06/10 08:56AM, Patrick Steinhardt wrote:
> In the preceding commit we have stopped modifying the global
> `git_work_tree_cfg` variable. With this change there's now some code
> paths where we end up setting the local `git_work_tree_cfg` variable,
> but without actually using the value for anything.
> 
> Refactor the code a bit so that we only set the worktree configuration
> in case it's actually needed. Furthermore, reflow it a bit to make the
> code easier to follow.
> 
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  builtin/init-db.c | 31 ++++++++++++++++++-------------
>  1 file changed, 18 insertions(+), 13 deletions(-)
> 
> diff --git a/builtin/init-db.c b/builtin/init-db.c
> index 01bc27904e..b4343c2804 100644
> --- a/builtin/init-db.c
> +++ b/builtin/init-db.c
> @@ -229,24 +229,29 @@ int cmd_init_db(int argc,
>  
>  	if (!is_bare_repository_cfg) {
>  		const char *git_dir_parent = strrchr(git_dir, '/');
> -		char *git_work_tree_cfg = NULL;
>  
> -		if (git_dir_parent) {
> -			char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
> -			git_work_tree_cfg = real_pathdup(rel, 1);
> -			free(rel);
> -		}
> -		if (!git_work_tree_cfg)
> -			git_work_tree_cfg = xgetcwd();
> -		if (work_tree)
> +		if (work_tree) {
>  			set_git_work_tree(the_repository, work_tree);

Ok, if the worktree is already set via the GIT_WORK_TREE environment
variable, we can just apply it skip everything else.

> -		else
> -			set_git_work_tree(the_repository, git_work_tree_cfg);
> +		} else {
> +			char *work_tree_cfg = NULL;
> +
> +			if (git_dir_parent) {
> +				char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
> +				work_tree_cfg = real_pathdup(rel, 1);
> +				free(rel);
> +			}
> +
> +			if (!work_tree_cfg)
> +				work_tree_cfg = xgetcwd();

When the environment variable is not set, we try to derive the worktree
from the parent directory of the gitdir. If that doesn't work we
fallback to the current working directory.

This matches previous the previous behavior.

> +
> +			set_git_work_tree(the_repository, work_tree_cfg);
> +
> +			free(work_tree_cfg);
> +		}

Good cleanup. I think this is a bit easier to read too.

-Justin

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/7] setup: remove global `git_work_tree_cfg` variable
  2026-06-10  6:56 ` [PATCH 3/7] setup: remove global `git_work_tree_cfg` variable Patrick Steinhardt
@ 2026-06-10 21:52   ` Justin Tobler
  2026-06-11  6:36     ` Patrick Steinhardt
  0 siblings, 1 reply; 25+ messages in thread
From: Justin Tobler @ 2026-06-10 21:52 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git

On 26/06/10 08:56AM, Patrick Steinhardt wrote:
> The global `git_work_tree_cfg` variable used to be modified by both
> "setup.c" and by "builtin/init-db.c". We have refactored the latter user
> to not use that variable at all anymore in a preceding commit, which
> makes "setup.c" the only remaining user.
> 
> Even for "setup.c" it is unnecessary though, as we only ever set it to
> the value we have stored in the discovered repository format. The
> consequence is that we only ever set it in case we already have it set
> to the same value in our discovered repository format, which makes it
> redundant.

Nice. I was wondering in the first patch if there would really be any
need to keep `git_work_tree_cfg` around here at all. Makes sense to me
to just set the repository worktree directly.

> Refactor the code so that we instead use the worktree configuration as
> discovered via the repository format. Drop the global variable.
> 
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  setup.c | 28 +++++++++++-----------------
>  1 file changed, 11 insertions(+), 17 deletions(-)
> 
> diff --git a/setup.c b/setup.c
> index 52228b42a1..71fc6b33da 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -31,9 +31,6 @@ enum allowed_bare_repo {
>  	ALLOWED_BARE_REPO_ALL,
>  };
>  
> -/* This is set by setup_git_directory_gently() and/or git_default_config() */
> -static char *git_work_tree_cfg;
> -
>  static struct startup_info the_startup_info;
>  struct startup_info *startup_info = &the_startup_info;
>  const char *tmp_original_cwd;
> @@ -799,13 +796,10 @@ static int check_repository_format_gently(const char *gitdir,
>  	}
>  
>  	if (!has_common) {
> -		if (candidate->is_bare != -1) {
> +		if (candidate->is_bare != -1)
>  			is_bare_repository_cfg = candidate->is_bare;
> -		}
> -		if (candidate->work_tree) {
> -			free(git_work_tree_cfg);
> -			git_work_tree_cfg = xstrdup(candidate->work_tree);

Ok, we no longer set `git_work_tree_cfg` in favor of just relying on the
worktree specified in the repository format.

> -		}
> +	} else {
> +		FREE_AND_NULL(candidate->work_tree);

Huh, we were not previously freeing the worktree here, but I assume this
to avoid a resource leak?

The remainder of this patch replaces `git_work_tree_cfg` usage with the
repository format worktree and looks good.

-Justin

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 5/7] environment: split up concerns of `is_bare_repository_cfg`
  2026-06-10  6:56 ` [PATCH 5/7] environment: split up concerns of `is_bare_repository_cfg` Patrick Steinhardt
@ 2026-06-10 22:22   ` Justin Tobler
  2026-06-11  9:19     ` Patrick Steinhardt
  0 siblings, 1 reply; 25+ messages in thread
From: Justin Tobler @ 2026-06-10 22:22 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git

On 26/06/10 08:56AM, Patrick Steinhardt wrote:
> The `is_bare_repository_cfg` variable tracks two different pieces of
> information:
> 
>   - It tracks whether the user has invoked git with the "--bare" flag,
>     which makes us treat any discovered Git repository as if it was a
>     bare repository.
> 
>   - Otherwise it tracks whether the discovered `the_repository` is bare.
> 
> This makes the flag extremely confusing and creates a bit of a challenge
> when handling multiple repositories in the same process.

Indeed, this does seem rather confusing.

> Split up the concerns of this variable into two pieces:
> 
>   - `startup_info.force_bare_repository` tracks whether the user has
>     passed the "--bare" flag. This is used as a hint to treat newly set
>     up repositories as bare regardless of whether or not they have a
>     worktree.
> 
>   - `struct repository::bare_cfg` tracks whether or not a repository is
>     considered bare. This takes into account both whether the user has
>     passed "--bare" and the discovered state of the repository itself.
> 
> Whether or not a repository is bare is now resolved when checking the
> repository's format, and is then later applied to the repository itself
> via `apply_repository_format()`.

Nice. These seem like they should be tracked separately, so splitting
them up sounds like a good idea.

> This enables a subsequent change where we make `is_bare_repository()`
> not depend on global state anymore.
> 
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  builtin/init-db.c |  2 +-
>  environment.c     |  5 ++---
>  environment.h     |  1 -
>  git.c             |  2 +-
>  repository.c      |  1 +
>  repository.h      |  7 +++++++
>  setup.c           | 21 ++++++++++++++-------
>  setup.h           |  6 ++++++
>  worktree.c        |  2 +-
>  9 files changed, 33 insertions(+), 14 deletions(-)
> 
> diff --git a/builtin/init-db.c b/builtin/init-db.c
> index 52aa92fb0a..566732c9f4 100644
> --- a/builtin/init-db.c
> +++ b/builtin/init-db.c
> @@ -81,7 +81,7 @@ int cmd_init_db(int argc,
>  	const char *template_dir = NULL;
>  	char *template_dir_to_free = NULL;
>  	unsigned int flags = 0;
> -	int bare = is_bare_repository_cfg;
> +	int bare = startup_info->force_bare_repository ? 1 : -1;

Any particular reason to continue mapping `force_bare_repository=false`
to -1? Or was this to just minimize changes?

>  	const char *object_format = NULL;
>  	const char *ref_format = NULL;
>  	const char *initial_branch = NULL;
[snip]
> diff --git a/repository.h b/repository.h
> index 36e2db2633..7d649e32e7 100644
> --- a/repository.h
> +++ b/repository.h
> @@ -117,6 +117,13 @@ struct repository {
>  	bool worktree_initialized;
>  	bool worktree_config_is_bogus;
>  
> +	/*
> +	 * Whether the repository is bare, as set by "core.bare" config or
> +	 * inferred during repository discovery. -1 means unset/unknown, 0
> +	 * means non-bare, 1 means bare.
> +	 */
> +	int bare_cfg;

Now we track whether a repository is bare in `struct repository` and
removes the need to a separate global to track this state.

> +
>  	/*
>  	 * Path from the root of the top-level superproject down to this
>  	 * repository.  This is only non-NULL if the repository is initialized
> diff --git a/setup.c b/setup.c
> index 71fc6b33da..2b690da8ca 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -795,10 +795,16 @@ static int check_repository_format_gently(const char *gitdir,
>  		has_common = 0;
>  	}
>  
> -	if (!has_common) {
> -		if (candidate->is_bare != -1)
> -			is_bare_repository_cfg = candidate->is_bare;
> -	} else {
> +	if (startup_info->force_bare_repository) {
> +		candidate->is_bare = 1;
> +		FREE_AND_NULL(candidate->work_tree);
> +	} else if (has_common) {
> +		/*
> +		 * When sharing a common dir with another repository (e.g. a
> +		 * linked worktree), do not let this repository's config
> +		 * dictate bareness; it is inherited from the main worktree.
> +		 */
> +		candidate->is_bare = -1;
>  		FREE_AND_NULL(candidate->work_tree);

Previously, when there was a common dir, `candidate->work_tree` was left
untouched, but now we are expclicitly setting it. I'm not sure I fully
understand this change.

-Justin

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE
  2026-06-10  6:56 ` [PATCH 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE Patrick Steinhardt
@ 2026-06-10 22:26   ` Justin Tobler
  0 siblings, 0 replies; 25+ messages in thread
From: Justin Tobler @ 2026-06-10 22:26 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git

On 26/06/10 08:56AM, Patrick Steinhardt wrote:
> Adapt a couple of trivial callers of `is_bare_repository()` to instead
> use a repository available via the caller's context so that we can drop
> the `USE_THE_REPOSITORY_VARIABLE` macro.

Nice cleanup, this patch looks trivially correct. :)

-Justin

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/7] setup: remove global `git_work_tree_cfg` variable
  2026-06-10 21:52   ` Justin Tobler
@ 2026-06-11  6:36     ` Patrick Steinhardt
  0 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  6:36 UTC (permalink / raw)
  To: Justin Tobler; +Cc: git

On Wed, Jun 10, 2026 at 04:52:12PM -0500, Justin Tobler wrote:
> On 26/06/10 08:56AM, Patrick Steinhardt wrote:
> > diff --git a/setup.c b/setup.c
> > index 52228b42a1..71fc6b33da 100644
> > --- a/setup.c
> > +++ b/setup.c
> > @@ -31,9 +31,6 @@ enum allowed_bare_repo {
> >  	ALLOWED_BARE_REPO_ALL,
> >  };
> >  
> > -/* This is set by setup_git_directory_gently() and/or git_default_config() */
> > -static char *git_work_tree_cfg;
> > -
> >  static struct startup_info the_startup_info;
> >  struct startup_info *startup_info = &the_startup_info;
> >  const char *tmp_original_cwd;
> > @@ -799,13 +796,10 @@ static int check_repository_format_gently(const char *gitdir,
> >  	}
> >  
> >  	if (!has_common) {
> > -		if (candidate->is_bare != -1) {
> > +		if (candidate->is_bare != -1)
> >  			is_bare_repository_cfg = candidate->is_bare;
> > -		}
> > -		if (candidate->work_tree) {
> > -			free(git_work_tree_cfg);
> > -			git_work_tree_cfg = xstrdup(candidate->work_tree);
> 
> Ok, we no longer set `git_work_tree_cfg` in favor of just relying on the
> worktree specified in the repository format.
> 
> > -		}
> > +	} else {
> > +		FREE_AND_NULL(candidate->work_tree);
> 
> Huh, we were not previously freeing the worktree here, but I assume this
> to avoid a resource leak?

This is in fact a required change. Before this patch this here was the
place where we populated `git_work_tree_cfg`, and that variable was then
later on applied to the repository. So the implicit `else` branch was
basically just `git_work_tree_cfg = NULL`, but we didn't have to do that
as it already was set to `NULL`.

With the new code though we're not setting `git_work_tree_cfg` anymore
and instead directly populate from `candidate->work_tree`. But that also
means that we now have to clear that variable to retain previous
semantics.

I'll add an explanation to the commit message.

Patrick

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 0/7] setup: drop global state
  2026-06-10  6:56 [PATCH 0/7] setup: drop global state Patrick Steinhardt
                   ` (6 preceding siblings ...)
  2026-06-10  6:56 ` [PATCH 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE Patrick Steinhardt
@ 2026-06-11  6:44 ` Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable Patrick Steinhardt
                     ` (7 more replies)
  7 siblings, 8 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  6:44 UTC (permalink / raw)
  To: git; +Cc: Justin Tobler

Hi,

this patch series continues to refactor "setup.c", where the focus is to
drop remaining global state that we have in "setup.c". The most
important consequence of this is that we don't need to rely on
`the_repository` in `is_bare_repository()` anymore.

This series is built on top of 1ff279f340 (The 13th batch, 2026-06-09)
with ps/setup-centralize-odb-creation at 42b9d3dc9d (setup: construct
object database in `apply_repository_format()`, 2026-06-04) merged into
it.

Changes in v2:
  - Improve documentation for some aspects of `check_repository_format_gently()`.
  - Link to v1: https://patch.msgid.link/20260610-b4-pks-setup-drop-global-state-v1-0-5dff3eec8f06@pks.im

Thanks!

Patrick

---
Patrick Steinhardt (7):
      builtin/init: stop modifying global `git_work_tree_cfg` variable
      builtin/init: simplify logic to configure worktree
      setup: remove global `git_work_tree_cfg` variable
      builtin/init: stop modifying `is_bare_repository_cfg`
      environment: split up concerns of `is_bare_repository_cfg`
      environment: stop using `the_repository` in `is_bare_repository()`
      treewide: drop USE_THE_REPOSITORY_VARIABLE

 attr.c                  |  4 ++--
 builtin/bisect.c        |  2 +-
 builtin/blame.c         |  2 +-
 builtin/check-attr.c    |  2 +-
 builtin/fetch.c         |  2 +-
 builtin/gc.c            |  2 +-
 builtin/history.c       |  2 +-
 builtin/init-db.c       | 44 +++++++++++++++++++++++++-----------------
 builtin/repack.c        |  3 +--
 builtin/repo.c          |  2 +-
 builtin/reset.c         |  2 +-
 builtin/rev-parse.c     |  2 +-
 environment.c           | 10 +++-------
 environment.h           |  6 ++----
 git.c                   |  2 +-
 mailmap.c               |  6 ++----
 refs/files-backend.c    |  2 +-
 refs/reftable-backend.c |  4 +---
 repository.c            |  1 +
 repository.h            |  7 +++++++
 setup.c                 | 51 +++++++++++++++++++++++++++++--------------------
 setup.h                 |  6 ++++++
 transport.c             |  4 ++--
 worktree.c              |  4 ++--
 24 files changed, 97 insertions(+), 75 deletions(-)

Range-diff versus v1:

1:  0281a4bca9 = 1:  96b71f5223 builtin/init: stop modifying global `git_work_tree_cfg` variable
2:  6fdc8d77e8 = 2:  a51c0ff79d builtin/init: simplify logic to configure worktree
3:  ce31595ff5 ! 3:  e06393ddc5 setup: remove global `git_work_tree_cfg` variable
    @@ Commit message
         Refactor the code so that we instead use the worktree configuration as
         discovered via the repository format. Drop the global variable.
     
    +    Note that in `check_repository_format_gently()` we now have to free the
    +    candidate work tree variable. This change is required to retain previous
    +    semantics: before we essentially had an implicit `else` branch where we
    +    set `git_work_tree_cfg = NULL`, but we were able to elide that branch
    +    because we already knew that it would be `NULL` anyway. Now that we use
    +    the candidate work tree directly to populate the repository's work tree
    +    though we have to clear it to retain those semantics.
    +
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
     
      ## setup.c ##
4:  6a69dc853c = 4:  628ed54c8c builtin/init: stop modifying `is_bare_repository_cfg`
5:  afa2d8bbda ! 5:  02ceaf4a20 environment: split up concerns of `is_bare_repository_cfg`
    @@ setup.c: static int check_repository_format_gently(const char *gitdir,
     +		 * dictate bareness; it is inherited from the main worktree.
     +		 */
     +		candidate->is_bare = -1;
    ++
    ++		/*
    ++		 * Furthermore, "core.worktree" is supposed to be ignored when
    ++		 * we have a commondir configured, unless it comes from the
    ++		 * per-worktree configuration.
    ++		 */
      		FREE_AND_NULL(candidate->work_tree);
      	}
      
6:  04849a2cb5 = 6:  a08aef5685 environment: stop using `the_repository` in `is_bare_repository()`
7:  78191c7557 = 7:  f93f6599df treewide: drop USE_THE_REPOSITORY_VARIABLE

---
base-commit: f5a08a09a0fdf0fc2a355eba7979e2cfd65659e5
change-id: 20260422-b4-pks-setup-drop-global-state-6b1374aed5db


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
@ 2026-06-11  6:44   ` Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 2/7] builtin/init: simplify logic to configure worktree Patrick Steinhardt
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  6:44 UTC (permalink / raw)
  To: git; +Cc: Justin Tobler

When executing git-init(1) we need to figure out the final location of
the worktree. This location can be configured in a couple of ways: via
an environment variable, via the preexisting "core.worktree" config in
case we're reinitializing, or implicitly when reinitializing a non-bare
repository.

When checking for the worktree location in "builtin/init-db.c" we
populate any potentially-discovered value both by setting the global
`git_work_tree_cfg` variable and via `set_git_work_tree()`, which
ultimately ends up modifying `struct repository::worktree`.

Modifying `git_work_tree_cfg` is unnecessary though: we configure the
worktree in `create_default_files()`, and that function derives the
worktree location via `repo_get_work_tree()`. Consequently, propagating
the worktree via `set_git_work_tree()` is sufficient.

Stop munging `git_work_tree_cfg` and make it file-local to "setup.c" and
function-local to `cmd_init_db()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/init-db.c | 4 ++++
 environment.c     | 3 ---
 environment.h     | 1 -
 setup.c           | 3 +++
 4 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index c55517ad94..01bc27904e 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -229,6 +229,8 @@ int cmd_init_db(int argc,
 
 	if (!is_bare_repository_cfg) {
 		const char *git_dir_parent = strrchr(git_dir, '/');
+		char *git_work_tree_cfg = NULL;
+
 		if (git_dir_parent) {
 			char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
 			git_work_tree_cfg = real_pathdup(rel, 1);
@@ -243,6 +245,8 @@ int cmd_init_db(int argc,
 		if (access(repo_get_work_tree(the_repository), X_OK))
 			die_errno (_("Cannot access work tree '%s'"),
 				   repo_get_work_tree(the_repository));
+
+		free(git_work_tree_cfg);
 	}
 	else {
 		if (real_git_dir)
diff --git a/environment.c b/environment.c
index fc3ed8bb1c..4e86335f25 100644
--- a/environment.c
+++ b/environment.c
@@ -100,9 +100,6 @@ int auto_comment_line_char;
 bool warn_on_auto_comment_char;
 #endif /* !WITH_BREAKING_CHANGES */
 
-/* This is set by setup_git_directory_gently() and/or git_default_config() */
-char *git_work_tree_cfg;
-
 /*
  * Repository-local GIT_* environment variables; see environment.h for details.
  */
diff --git a/environment.h b/environment.h
index ccfcf37bfb..5d6e4e6c1b 100644
--- a/environment.h
+++ b/environment.h
@@ -149,7 +149,6 @@ int have_git_dir(void);
 
 extern int is_bare_repository_cfg;
 int is_bare_repository(void);
-extern char *git_work_tree_cfg;
 
 /* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
diff --git a/setup.c b/setup.c
index b4652651df..52228b42a1 100644
--- a/setup.c
+++ b/setup.c
@@ -31,6 +31,9 @@ enum allowed_bare_repo {
 	ALLOWED_BARE_REPO_ALL,
 };
 
+/* This is set by setup_git_directory_gently() and/or git_default_config() */
+static char *git_work_tree_cfg;
+
 static struct startup_info the_startup_info;
 struct startup_info *startup_info = &the_startup_info;
 const char *tmp_original_cwd;

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 2/7] builtin/init: simplify logic to configure worktree
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable Patrick Steinhardt
@ 2026-06-11  6:44   ` Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 3/7] setup: remove global `git_work_tree_cfg` variable Patrick Steinhardt
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  6:44 UTC (permalink / raw)
  To: git; +Cc: Justin Tobler

In the preceding commit we have stopped modifying the global
`git_work_tree_cfg` variable. With this change there's now some code
paths where we end up setting the local `git_work_tree_cfg` variable,
but without actually using the value for anything.

Refactor the code a bit so that we only set the worktree configuration
in case it's actually needed. Furthermore, reflow it a bit to make the
code easier to follow.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/init-db.c | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index 01bc27904e..b4343c2804 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -229,24 +229,29 @@ int cmd_init_db(int argc,
 
 	if (!is_bare_repository_cfg) {
 		const char *git_dir_parent = strrchr(git_dir, '/');
-		char *git_work_tree_cfg = NULL;
 
-		if (git_dir_parent) {
-			char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
-			git_work_tree_cfg = real_pathdup(rel, 1);
-			free(rel);
-		}
-		if (!git_work_tree_cfg)
-			git_work_tree_cfg = xgetcwd();
-		if (work_tree)
+		if (work_tree) {
 			set_git_work_tree(the_repository, work_tree);
-		else
-			set_git_work_tree(the_repository, git_work_tree_cfg);
+		} else {
+			char *work_tree_cfg = NULL;
+
+			if (git_dir_parent) {
+				char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
+				work_tree_cfg = real_pathdup(rel, 1);
+				free(rel);
+			}
+
+			if (!work_tree_cfg)
+				work_tree_cfg = xgetcwd();
+
+			set_git_work_tree(the_repository, work_tree_cfg);
+
+			free(work_tree_cfg);
+		}
+
 		if (access(repo_get_work_tree(the_repository), X_OK))
 			die_errno (_("Cannot access work tree '%s'"),
 				   repo_get_work_tree(the_repository));
-
-		free(git_work_tree_cfg);
 	}
 	else {
 		if (real_git_dir)

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 3/7] setup: remove global `git_work_tree_cfg` variable
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 2/7] builtin/init: simplify logic to configure worktree Patrick Steinhardt
@ 2026-06-11  6:44   ` Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 4/7] builtin/init: stop modifying `is_bare_repository_cfg` Patrick Steinhardt
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  6:44 UTC (permalink / raw)
  To: git; +Cc: Justin Tobler

The global `git_work_tree_cfg` variable used to be modified by both
"setup.c" and by "builtin/init-db.c". We have refactored the latter user
to not use that variable at all anymore in a preceding commit, which
makes "setup.c" the only remaining user.

Even for "setup.c" it is unnecessary though, as we only ever set it to
the value we have stored in the discovered repository format. The
consequence is that we only ever set it in case we already have it set
to the same value in our discovered repository format, which makes it
redundant.

Refactor the code so that we instead use the worktree configuration as
discovered via the repository format. Drop the global variable.

Note that in `check_repository_format_gently()` we now have to free the
candidate work tree variable. This change is required to retain previous
semantics: before we essentially had an implicit `else` branch where we
set `git_work_tree_cfg = NULL`, but we were able to elide that branch
because we already knew that it would be `NULL` anyway. Now that we use
the candidate work tree directly to populate the repository's work tree
though we have to clear it to retain those semantics.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 setup.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/setup.c b/setup.c
index 52228b42a1..71fc6b33da 100644
--- a/setup.c
+++ b/setup.c
@@ -31,9 +31,6 @@ enum allowed_bare_repo {
 	ALLOWED_BARE_REPO_ALL,
 };
 
-/* This is set by setup_git_directory_gently() and/or git_default_config() */
-static char *git_work_tree_cfg;
-
 static struct startup_info the_startup_info;
 struct startup_info *startup_info = &the_startup_info;
 const char *tmp_original_cwd;
@@ -799,13 +796,10 @@ static int check_repository_format_gently(const char *gitdir,
 	}
 
 	if (!has_common) {
-		if (candidate->is_bare != -1) {
+		if (candidate->is_bare != -1)
 			is_bare_repository_cfg = candidate->is_bare;
-		}
-		if (candidate->work_tree) {
-			free(git_work_tree_cfg);
-			git_work_tree_cfg = xstrdup(candidate->work_tree);
-		}
+	} else {
+		FREE_AND_NULL(candidate->work_tree);
 	}
 
 	return 0;
@@ -1145,7 +1139,7 @@ static const char *setup_explicit_git_dir(struct repository *repo,
 	if (work_tree_env)
 		set_git_work_tree(repo, work_tree_env);
 	else if (is_bare_repository_cfg > 0) {
-		if (git_work_tree_cfg) {
+		if (repo_fmt->work_tree) {
 			/* #22.2, #30 */
 			warning("core.bare and core.worktree do not make sense");
 			repo->worktree_config_is_bogus = true;
@@ -1156,15 +1150,15 @@ static const char *setup_explicit_git_dir(struct repository *repo,
 		free(gitfile);
 		return NULL;
 	}
-	else if (git_work_tree_cfg) { /* #6, #14 */
-		if (is_absolute_path(git_work_tree_cfg))
-			set_git_work_tree(repo, git_work_tree_cfg);
+	else if (repo_fmt->work_tree) { /* #6, #14 */
+		if (is_absolute_path(repo_fmt->work_tree))
+			set_git_work_tree(repo, repo_fmt->work_tree);
 		else {
 			char *core_worktree;
 			if (chdir(gitdirenv))
 				die_errno(_("cannot chdir to '%s'"), gitdirenv);
-			if (chdir(git_work_tree_cfg))
-				die_errno(_("cannot chdir to '%s'"), git_work_tree_cfg);
+			if (chdir(repo_fmt->work_tree))
+				die_errno(_("cannot chdir to '%s'"), repo_fmt->work_tree);
 			core_worktree = xgetcwd();
 			if (chdir(cwd->buf))
 				die_errno(_("cannot come back to cwd"));
@@ -1217,7 +1211,7 @@ static const char *setup_discovered_git_dir(struct repository *repo,
 		return NULL;
 
 	/* --work-tree is set without --git-dir; use discovered one */
-	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || repo_fmt->work_tree) {
 		char *to_free = NULL;
 		const char *ret;
 
@@ -1267,7 +1261,7 @@ static const char *setup_bare_git_dir(struct repository *repo,
 	setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
 
 	/* --work-tree is set without --git-dir; use discovered one */
-	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || repo_fmt->work_tree) {
 		static const char *gitdir;
 
 		gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 4/7] builtin/init: stop modifying `is_bare_repository_cfg`
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
                     ` (2 preceding siblings ...)
  2026-06-11  6:44   ` [PATCH v2 3/7] setup: remove global `git_work_tree_cfg` variable Patrick Steinhardt
@ 2026-06-11  6:44   ` Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 5/7] environment: split up concerns of `is_bare_repository_cfg` Patrick Steinhardt
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  6:44 UTC (permalink / raw)
  To: git; +Cc: Justin Tobler

We're modifying `is_bare_repository_cfg` in "builtin/init.c" to indicate
whether the newly created repository is supposed to be a bare repository
or not.

This is ultimately unnecessary though: when initializing the repository
in `init_db()` we eventually set `is_bare_repository_cfg = !work_tree`,
so all that matters is whether or not we have a working tree configured,
and the working tree is set up in the non-bare in "builtin/init.c".

Stop modifying the global variable in "builtin/init.c" in favor of a
local variable.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/init-db.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index b4343c2804..52aa92fb0a 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -81,6 +81,7 @@ int cmd_init_db(int argc,
 	const char *template_dir = NULL;
 	char *template_dir_to_free = NULL;
 	unsigned int flags = 0;
+	int bare = is_bare_repository_cfg;
 	const char *object_format = NULL;
 	const char *ref_format = NULL;
 	const char *initial_branch = NULL;
@@ -90,7 +91,7 @@ int cmd_init_db(int argc,
 	const struct option init_db_options[] = {
 		OPT_STRING(0, "template", &template_dir, N_("template-directory"),
 				N_("directory from which templates will be used")),
-		OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
+		OPT_SET_INT(0, "bare", &bare,
 				N_("create a bare repository"), 1),
 		{
 			.type = OPTION_CALLBACK,
@@ -116,7 +117,7 @@ int cmd_init_db(int argc,
 
 	argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
 
-	if (real_git_dir && is_bare_repository_cfg == 1)
+	if (real_git_dir && bare == 1)
 		die(_("options '%s' and '%s' cannot be used together"), "--separate-git-dir", "--bare");
 
 	if (real_git_dir && !is_absolute_path(real_git_dir))
@@ -160,7 +161,7 @@ int cmd_init_db(int argc,
 	} else if (0 < argc) {
 		usage(init_db_usage[0]);
 	}
-	if (is_bare_repository_cfg == 1) {
+	if (bare == 1) {
 		char *cwd = xgetcwd();
 		setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0);
 		free(cwd);
@@ -187,7 +188,7 @@ int cmd_init_db(int argc,
 	 */
 	git_dir = xstrdup_or_null(getenv(GIT_DIR_ENVIRONMENT));
 	work_tree = xstrdup_or_null(getenv(GIT_WORK_TREE_ENVIRONMENT));
-	if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
+	if ((!git_dir || bare == 1) && work_tree)
 		die(_("%s (or --work-tree=<directory>) not allowed without "
 			  "specifying %s (or --git-dir=<directory>)"),
 		    GIT_WORK_TREE_ENVIRONMENT,
@@ -224,10 +225,10 @@ int cmd_init_db(int argc,
 		strbuf_release(&sb);
 	}
 
-	if (is_bare_repository_cfg < 0)
-		is_bare_repository_cfg = guess_repository_type(git_dir);
+	if (bare < 0)
+		bare = guess_repository_type(git_dir);
 
-	if (!is_bare_repository_cfg) {
+	if (!bare) {
 		const char *git_dir_parent = strrchr(git_dir, '/');
 
 		if (work_tree) {

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 5/7] environment: split up concerns of `is_bare_repository_cfg`
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
                     ` (3 preceding siblings ...)
  2026-06-11  6:44   ` [PATCH v2 4/7] builtin/init: stop modifying `is_bare_repository_cfg` Patrick Steinhardt
@ 2026-06-11  6:44   ` Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 6/7] environment: stop using `the_repository` in `is_bare_repository()` Patrick Steinhardt
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  6:44 UTC (permalink / raw)
  To: git; +Cc: Justin Tobler

The `is_bare_repository_cfg` variable tracks two different pieces of
information:

  - It tracks whether the user has invoked git with the "--bare" flag,
    which makes us treat any discovered Git repository as if it was a
    bare repository.

  - Otherwise it tracks whether the discovered `the_repository` is bare.

This makes the flag extremely confusing and creates a bit of a challenge
when handling multiple repositories in the same process.

Split up the concerns of this variable into two pieces:

  - `startup_info.force_bare_repository` tracks whether the user has
    passed the "--bare" flag. This is used as a hint to treat newly set
    up repositories as bare regardless of whether or not they have a
    worktree.

  - `struct repository::bare_cfg` tracks whether or not a repository is
    considered bare. This takes into account both whether the user has
    passed "--bare" and the discovered state of the repository itself.

Whether or not a repository is bare is now resolved when checking the
repository's format, and is then later applied to the repository itself
via `apply_repository_format()`.

This enables a subsequent change where we make `is_bare_repository()`
not depend on global state anymore.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/init-db.c |  2 +-
 environment.c     |  5 ++---
 environment.h     |  1 -
 git.c             |  2 +-
 repository.c      |  1 +
 repository.h      |  7 +++++++
 setup.c           | 27 ++++++++++++++++++++-------
 setup.h           |  6 ++++++
 worktree.c        |  2 +-
 9 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index 52aa92fb0a..566732c9f4 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -81,7 +81,7 @@ int cmd_init_db(int argc,
 	const char *template_dir = NULL;
 	char *template_dir_to_free = NULL;
 	unsigned int flags = 0;
-	int bare = is_bare_repository_cfg;
+	int bare = startup_info->force_bare_repository ? 1 : -1;
 	const char *object_format = NULL;
 	const char *ref_format = NULL;
 	const char *initial_branch = NULL;
diff --git a/environment.c b/environment.c
index 4e86335f25..9d7c908c55 100644
--- a/environment.c
+++ b/environment.c
@@ -48,7 +48,6 @@ int has_symlinks = 1;
 int minimum_abbrev = 4, default_abbrev = -1;
 int ignore_case;
 int assume_unchanged;
-int is_bare_repository_cfg = -1; /* unspecified */
 int warn_on_object_refname_ambiguity = 1;
 char *git_commit_encoding;
 char *git_log_output_encoding;
@@ -136,7 +135,7 @@ const char *getenv_safe(struct strvec *argv, const char *name)
 int is_bare_repository(void)
 {
 	/* if core.bare is not 'false', let's see if there is a work tree */
-	return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
+	return the_repository->bare_cfg && !repo_get_work_tree(the_repository);
 }
 
 int have_git_dir(void)
@@ -342,7 +341,7 @@ int git_default_core_config(const char *var, const char *value,
 	}
 
 	if (!strcmp(var, "core.bare")) {
-		is_bare_repository_cfg = git_config_bool(var, value);
+		the_repository->bare_cfg = git_config_bool(var, value);
 		return 0;
 	}
 
diff --git a/environment.h b/environment.h
index 5d6e4e6c1b..afb5bcf197 100644
--- a/environment.h
+++ b/environment.h
@@ -147,7 +147,6 @@ void repo_config_values_init(struct repo_config_values *cfg);
  */
 int have_git_dir(void);
 
-extern int is_bare_repository_cfg;
 int is_bare_repository(void);
 
 /* Environment bits from configuration mechanism */
diff --git a/git.c b/git.c
index 36f08891ef..387eabe38c 100644
--- a/git.c
+++ b/git.c
@@ -255,7 +255,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 				*envchanged = 1;
 		} else if (!strcmp(cmd, "--bare")) {
 			char *cwd = xgetcwd();
-			is_bare_repository_cfg = 1;
+			startup_info->force_bare_repository = true;
 			setenv(GIT_DIR_ENVIRONMENT, cwd, 0);
 			free(cwd);
 			setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
diff --git a/repository.c b/repository.c
index 187dd471c4..c1e91eb0da 100644
--- a/repository.c
+++ b/repository.c
@@ -73,6 +73,7 @@ void initialize_repository(struct repository *repo)
 	ALLOC_ARRAY(repo->index, 1);
 	index_state_init(repo->index, repo);
 	repo->check_deprecated_config = true;
+	repo->bare_cfg = -1;
 	repo_config_values_init(&repo->config_values_private_);
 
 	/*
diff --git a/repository.h b/repository.h
index 36e2db2633..7d649e32e7 100644
--- a/repository.h
+++ b/repository.h
@@ -117,6 +117,13 @@ struct repository {
 	bool worktree_initialized;
 	bool worktree_config_is_bogus;
 
+	/*
+	 * Whether the repository is bare, as set by "core.bare" config or
+	 * inferred during repository discovery. -1 means unset/unknown, 0
+	 * means non-bare, 1 means bare.
+	 */
+	int bare_cfg;
+
 	/*
 	 * Path from the root of the top-level superproject down to this
 	 * repository.  This is only non-NULL if the repository is initialized
diff --git a/setup.c b/setup.c
index 71fc6b33da..32f14a8688 100644
--- a/setup.c
+++ b/setup.c
@@ -795,10 +795,22 @@ static int check_repository_format_gently(const char *gitdir,
 		has_common = 0;
 	}
 
-	if (!has_common) {
-		if (candidate->is_bare != -1)
-			is_bare_repository_cfg = candidate->is_bare;
-	} else {
+	if (startup_info->force_bare_repository) {
+		candidate->is_bare = 1;
+		FREE_AND_NULL(candidate->work_tree);
+	} else if (has_common) {
+		/*
+		 * When sharing a common dir with another repository (e.g. a
+		 * linked worktree), do not let this repository's config
+		 * dictate bareness; it is inherited from the main worktree.
+		 */
+		candidate->is_bare = -1;
+
+		/*
+		 * Furthermore, "core.worktree" is supposed to be ignored when
+		 * we have a commondir configured, unless it comes from the
+		 * per-worktree configuration.
+		 */
 		FREE_AND_NULL(candidate->work_tree);
 	}
 
@@ -1138,7 +1150,7 @@ static const char *setup_explicit_git_dir(struct repository *repo,
 	/* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
 	if (work_tree_env)
 		set_git_work_tree(repo, work_tree_env);
-	else if (is_bare_repository_cfg > 0) {
+	else if (repo_fmt->is_bare > 0) {
 		if (repo_fmt->work_tree) {
 			/* #22.2, #30 */
 			warning("core.bare and core.worktree do not make sense");
@@ -1225,7 +1237,7 @@ static const char *setup_discovered_git_dir(struct repository *repo,
 	}
 
 	/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
-	if (is_bare_repository_cfg > 0) {
+	if (repo_fmt->is_bare > 0) {
 		set_git_dir(repo, gitdir, (offset != cwd->len));
 		if (chdir(cwd->buf))
 			die_errno(_("cannot come back to cwd"));
@@ -1762,6 +1774,7 @@ int apply_repository_format(struct repository *repo,
 		alternate_object_directories = xstrdup_or_null(getenv(ALTERNATE_DB_ENVIRONMENT));
 	}
 
+	repo->bare_cfg = format->is_bare;
 	repo_set_hash_algo(repo, format->hash_algo);
 	repo->objects = odb_new(repo, object_directory,
 				alternate_object_directories);
@@ -2571,7 +2584,7 @@ static int create_default_files(struct repository *repo,
 		repo_settings_set_shared_repository(repo,
 						    init_shared_repository);
 
-	is_bare_repository_cfg = !work_tree;
+	repo->bare_cfg = !work_tree;
 
 	/*
 	 * We would have created the above under user's umask -- under
diff --git a/setup.h b/setup.h
index 705d1d6ff7..b9fd96bea6 100644
--- a/setup.h
+++ b/setup.h
@@ -292,6 +292,12 @@ enum sharedrepo {
 int git_config_perm(const char *var, const char *value);
 
 struct startup_info {
+	/*
+	 * Whether the user is asking us to treat the repository as bare via
+	 * `git --bare`, even if it's not.
+	 */
+	bool force_bare_repository;
+
 	int have_repository;
 	const char *prefix;
 	const char *original_cwd;
diff --git a/worktree.c b/worktree.c
index 97eddc3916..7d70f2c1da 100644
--- a/worktree.c
+++ b/worktree.c
@@ -123,7 +123,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
 	worktree->repo = the_repository;
 	worktree->path = strbuf_detach(&worktree_path, NULL);
 	worktree->is_current = is_current_worktree(worktree);
-	worktree->is_bare = (is_bare_repository_cfg == 1) ||
+	worktree->is_bare = (the_repository->bare_cfg == 1) ||
 		is_bare_repository() ||
 		/*
 		 * When in a secondary worktree we have to also verify if the main

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 6/7] environment: stop using `the_repository` in `is_bare_repository()`
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
                     ` (4 preceding siblings ...)
  2026-06-11  6:44   ` [PATCH v2 5/7] environment: split up concerns of `is_bare_repository_cfg` Patrick Steinhardt
@ 2026-06-11  6:44   ` Patrick Steinhardt
  2026-06-11  6:44   ` [PATCH v2 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE Patrick Steinhardt
  2026-06-11 15:47   ` [PATCH v2 0/7] setup: drop global state Justin Tobler
  7 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  6:44 UTC (permalink / raw)
  To: git; +Cc: Justin Tobler

Refactor `is_bare_repository()` to take in a repository parameter so
that we no longer depend on `the_repository`. Adjust callers
accordingly.

Furthermore, move the function outside of the declarations that are only
available when `USE_THE_REPOSITORY_VARIABLE` is set, as it no longer
depends on that variable.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 attr.c                  | 4 ++--
 builtin/bisect.c        | 2 +-
 builtin/blame.c         | 2 +-
 builtin/check-attr.c    | 2 +-
 builtin/fetch.c         | 2 +-
 builtin/gc.c            | 2 +-
 builtin/history.c       | 2 +-
 builtin/repack.c        | 2 +-
 builtin/repo.c          | 2 +-
 builtin/reset.c         | 2 +-
 builtin/rev-parse.c     | 2 +-
 environment.c           | 4 ++--
 environment.h           | 4 ++--
 mailmap.c               | 4 ++--
 refs/files-backend.c    | 2 +-
 refs/reftable-backend.c | 2 +-
 setup.c                 | 2 +-
 transport.c             | 4 ++--
 worktree.c              | 2 +-
 19 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/attr.c b/attr.c
index 75369547b3..04cb284954 100644
--- a/attr.c
+++ b/attr.c
@@ -681,7 +681,7 @@ static enum git_attr_direction direction;
 
 void git_attr_set_direction(enum git_attr_direction new_direction)
 {
-	if (is_bare_repository() && new_direction != GIT_ATTR_INDEX)
+	if (is_bare_repository(the_repository) && new_direction != GIT_ATTR_INDEX)
 		BUG("non-INDEX attr direction in a bare repo");
 
 	if (new_direction != direction)
@@ -848,7 +848,7 @@ static struct attr_stack *read_attr(struct index_state *istate,
 		res = read_attr_from_index(istate, path, flags);
 	} else if (tree_oid) {
 		res = read_attr_from_blob(istate, tree_oid, path, flags);
-	} else if (!is_bare_repository()) {
+	} else if (!is_bare_repository(the_repository)) {
 		if (direction == GIT_ATTR_CHECKOUT) {
 			res = read_attr_from_index(istate, path, flags);
 			if (!res)
diff --git a/builtin/bisect.c b/builtin/bisect.c
index e7c2d2f3bb..798e28f501 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -724,7 +724,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
 	struct object_id oid;
 	const char *head;
 
-	if (is_bare_repository())
+	if (is_bare_repository(the_repository))
 		no_checkout = 1;
 
 	/*
diff --git a/builtin/blame.c b/builtin/blame.c
index ffbd3ce5c5..553f4cb780 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1163,7 +1163,7 @@ int cmd_blame(int argc,
 
 	revs.disable_stdin = 1;
 	setup_revisions(argc, argv, &revs, NULL);
-	if (!revs.pending.nr && is_bare_repository()) {
+	if (!revs.pending.nr && is_bare_repository(the_repository)) {
 		struct commit *head_commit;
 		struct object_id head_oid;
 
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 98f64d5b92..217d83ea7d 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -116,7 +116,7 @@ int cmd_check_attr(int argc,
 	struct object_id initialized_oid;
 	int cnt, i, doubledash, filei;
 
-	if (!is_bare_repository())
+	if (!is_bare_repository(the_repository))
 		setup_work_tree(the_repository);
 
 	repo_config(the_repository, git_default_config, NULL);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index c1d7c672f4..44b8c70da1 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1764,7 +1764,7 @@ static int set_head(const struct ref *remote_refs, struct remote *remote)
 
 	if (!head_name)
 		goto cleanup;
-	baremirror = is_bare_repository() && remote->mirror;
+	baremirror = is_bare_repository(the_repository) && remote->mirror;
 	create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !baremirror;
 	if (baremirror) {
 		strbuf_addstr(&b_head, "HEAD");
diff --git a/builtin/gc.c b/builtin/gc.c
index 84a66d3240..61da30de9f 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -902,7 +902,7 @@ int cmd_gc(int argc,
 		die(_("failed to parse gc.logExpiry value %s"), cfg.gc_log_expire);
 
 	if (cfg.pack_refs < 0)
-		cfg.pack_refs = !is_bare_repository();
+		cfg.pack_refs = !is_bare_repository(the_repository);
 
 	argc = parse_options(argc, argv, prefix, builtin_gc_options,
 			     builtin_gc_usage, 0);
diff --git a/builtin/history.c b/builtin/history.c
index 091465a59e..fd83de8265 100644
--- a/builtin/history.c
+++ b/builtin/history.c
@@ -525,7 +525,7 @@ static int cmd_history_fixup(int argc,
 	if (action == REF_ACTION_DEFAULT)
 		action = REF_ACTION_BRANCHES;
 
-	if (is_bare_repository()) {
+	if (is_bare_repository(repo)) {
 		ret = error(_("cannot run fixup in a bare repository"));
 		goto out;
 	}
diff --git a/builtin/repack.c b/builtin/repack.c
index 1524a9c13a..bbc6f51639 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -265,7 +265,7 @@ int cmd_repack(int argc,
 
 	if (write_bitmaps < 0) {
 		if (write_midx == REPACK_WRITE_MIDX_NONE &&
-		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
+		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(the_repository)))
 			write_bitmaps = 0;
 	}
 	if (po_args.pack_kept_objects < 0)
diff --git a/builtin/repo.c b/builtin/repo.c
index 71a5c1c29c..34e96514bc 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -58,7 +58,7 @@ struct repo_info_field {
 
 static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
 {
-	strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
+	strbuf_addstr(buf, is_bare_repository(the_repository) ? "true" : "false");
 	return 0;
 }
 
diff --git a/builtin/reset.c b/builtin/reset.c
index 3be6bd0121..78e69bd84b 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -470,7 +470,7 @@ int cmd_reset(int argc,
 	if (reset_type != SOFT && (reset_type != MIXED || repo_get_work_tree(the_repository)))
 		setup_work_tree(the_repository);
 
-	if (reset_type == MIXED && is_bare_repository())
+	if (reset_type == MIXED && is_bare_repository(the_repository))
 		die(_("%s reset is not allowed in a bare repository"),
 		    _(reset_type_names[reset_type]));
 
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index bb882678fe..090e5cfbb0 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -1084,7 +1084,7 @@ int cmd_rev_parse(int argc,
 				continue;
 			}
 			if (!strcmp(arg, "--is-bare-repository")) {
-				printf("%s\n", is_bare_repository() ? "true"
+				printf("%s\n", is_bare_repository(the_repository) ? "true"
 						: "false");
 				continue;
 			}
diff --git a/environment.c b/environment.c
index 9d7c908c55..bf20953415 100644
--- a/environment.c
+++ b/environment.c
@@ -132,10 +132,10 @@ const char *getenv_safe(struct strvec *argv, const char *name)
 	return argv->v[argv->nr - 1];
 }
 
-int is_bare_repository(void)
+int is_bare_repository(struct repository *repo)
 {
 	/* if core.bare is not 'false', let's see if there is a work tree */
-	return the_repository->bare_cfg && !repo_get_work_tree(the_repository);
+	return repo->bare_cfg && !repo_get_work_tree(repo);
 }
 
 int have_git_dir(void)
diff --git a/environment.h b/environment.h
index afb5bcf197..164a55df2c 100644
--- a/environment.h
+++ b/environment.h
@@ -125,6 +125,8 @@ int git_default_core_config(const char *var, const char *value,
 
 void repo_config_values_init(struct repo_config_values *cfg);
 
+int is_bare_repository(struct repository *repo);
+
 /*
  * TODO: All the below state either explicitly or implicitly relies on
  * `the_repository`. We should eventually get rid of these and make the
@@ -147,8 +149,6 @@ void repo_config_values_init(struct repo_config_values *cfg);
  */
 int have_git_dir(void);
 
-int is_bare_repository(void);
-
 /* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
 extern int trust_ctime;
diff --git a/mailmap.c b/mailmap.c
index 3b2691781d..7d8590cdd6 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -219,10 +219,10 @@ int read_mailmap(struct repository *repo, struct string_list *map)
 	map->strdup_strings = 1;
 	map->cmp = namemap_cmp;
 
-	if (!mailmap_blob && is_bare_repository())
+	if (!mailmap_blob && is_bare_repository(the_repository))
 		mailmap_blob = xstrdup("HEAD:.mailmap");
 
-	if (!startup_info->have_repository || !is_bare_repository())
+	if (!startup_info->have_repository || !is_bare_repository(the_repository))
 		err |= read_mailmap_file(map, ".mailmap",
 					 startup_info->have_repository ?
 					 MAILMAP_NOFOLLOW : 0);
diff --git a/refs/files-backend.c b/refs/files-backend.c
index a4c7858787..2b27091484 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1865,7 +1865,7 @@ static int log_ref_setup(struct files_ref_store *refs,
 	char *logfile;
 
 	if (log_refs_cfg == LOG_REFS_UNSET)
-		log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+		log_refs_cfg = is_bare_repository(the_repository) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
 
 	files_reflog_path(refs, &logfile_sb, refname);
 	logfile = strbuf_detach(&logfile_sb, NULL);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 4ae22922de..101ef29ac8 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -288,7 +288,7 @@ static int should_write_log(struct reftable_ref_store *refs, const char *refname
 {
 	enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
 	if (log_refs_cfg == LOG_REFS_UNSET)
-		log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+		log_refs_cfg = is_bare_repository(the_repository) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
 
 	switch (log_refs_cfg) {
 	case LOG_REFS_NONE:
diff --git a/setup.c b/setup.c
index 32f14a8688..e6db80ab07 100644
--- a/setup.c
+++ b/setup.c
@@ -2610,7 +2610,7 @@ static int create_default_files(struct repository *repo,
 	}
 	repo_config_set(repo, "core.filemode", filemode ? "true" : "false");
 
-	if (is_bare_repository())
+	if (is_bare_repository(the_repository))
 		repo_config_set(repo, "core.bare", "true");
 	else {
 		repo_config_set(repo, "core.bare", "false");
diff --git a/transport.c b/transport.c
index 0f5ec30247..fc144f0aed 100644
--- a/transport.c
+++ b/transport.c
@@ -1482,7 +1482,7 @@ int transport_push(struct repository *r,
 
 	if ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |
 		      TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&
-	    !is_bare_repository()) {
+	    !is_bare_repository(the_repository)) {
 		struct ref *ref = remote_refs;
 		struct oid_array commits = OID_ARRAY_INIT;
 
@@ -1509,7 +1509,7 @@ int transport_push(struct repository *r,
 	if (((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) ||
 	     ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |
 			TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&
-	      !pretend)) && !is_bare_repository()) {
+	      !pretend)) && !is_bare_repository(the_repository)) {
 		struct ref *ref = remote_refs;
 		struct string_list needs_pushing = STRING_LIST_INIT_DUP;
 		struct oid_array commits = OID_ARRAY_INIT;
diff --git a/worktree.c b/worktree.c
index 7d70f2c1da..30125827fd 100644
--- a/worktree.c
+++ b/worktree.c
@@ -124,7 +124,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
 	worktree->path = strbuf_detach(&worktree_path, NULL);
 	worktree->is_current = is_current_worktree(worktree);
 	worktree->is_bare = (the_repository->bare_cfg == 1) ||
-		is_bare_repository() ||
+		is_bare_repository(the_repository) ||
 		/*
 		 * When in a secondary worktree we have to also verify if the main
 		 * worktree is bare in $commondir/config.worktree.

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
                     ` (5 preceding siblings ...)
  2026-06-11  6:44   ` [PATCH v2 6/7] environment: stop using `the_repository` in `is_bare_repository()` Patrick Steinhardt
@ 2026-06-11  6:44   ` Patrick Steinhardt
  2026-06-11 15:47   ` [PATCH v2 0/7] setup: drop global state Justin Tobler
  7 siblings, 0 replies; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  6:44 UTC (permalink / raw)
  To: git; +Cc: Justin Tobler

Adapt a couple of trivial callers of `is_bare_repository()` to instead
use a repository available via the caller's context so that we can drop
the `USE_THE_REPOSITORY_VARIABLE` macro.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/repack.c        | 3 +--
 mailmap.c               | 6 ++----
 refs/reftable-backend.c | 4 +---
 setup.c                 | 3 +--
 4 files changed, 5 insertions(+), 11 deletions(-)

diff --git a/builtin/repack.c b/builtin/repack.c
index bbc6f51639..d0465fb4f5 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "builtin.h"
@@ -265,7 +264,7 @@ int cmd_repack(int argc,
 
 	if (write_bitmaps < 0) {
 		if (write_midx == REPACK_WRITE_MIDX_NONE &&
-		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(the_repository)))
+		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(repo)))
 			write_bitmaps = 0;
 	}
 	if (po_args.pack_kept_objects < 0)
diff --git a/mailmap.c b/mailmap.c
index 7d8590cdd6..2d5514f833 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "git-compat-util.h"
 #include "environment.h"
 #include "string-list.h"
@@ -219,10 +217,10 @@ int read_mailmap(struct repository *repo, struct string_list *map)
 	map->strdup_strings = 1;
 	map->cmp = namemap_cmp;
 
-	if (!mailmap_blob && is_bare_repository(the_repository))
+	if (!mailmap_blob && is_bare_repository(repo))
 		mailmap_blob = xstrdup("HEAD:.mailmap");
 
-	if (!startup_info->have_repository || !is_bare_repository(the_repository))
+	if (!startup_info->have_repository || !is_bare_repository(repo))
 		err |= read_mailmap_file(map, ".mailmap",
 					 startup_info->have_repository ?
 					 MAILMAP_NOFOLLOW : 0);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 101ef29ac8..c151d331e7 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
 #include "../git-compat-util.h"
 #include "../abspath.h"
 #include "../chdir-notify.h"
@@ -288,7 +286,7 @@ static int should_write_log(struct reftable_ref_store *refs, const char *refname
 {
 	enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
 	if (log_refs_cfg == LOG_REFS_UNSET)
-		log_refs_cfg = is_bare_repository(the_repository) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+		log_refs_cfg = is_bare_repository(refs->base.repo) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
 
 	switch (log_refs_cfg) {
 	case LOG_REFS_NONE:
diff --git a/setup.c b/setup.c
index e6db80ab07..65f4ac95a8 100644
--- a/setup.c
+++ b/setup.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
 #define DISABLE_SIGN_COMPARE_WARNINGS
 
 #include "git-compat-util.h"
@@ -2610,7 +2609,7 @@ static int create_default_files(struct repository *repo,
 	}
 	repo_config_set(repo, "core.filemode", filemode ? "true" : "false");
 
-	if (is_bare_repository(the_repository))
+	if (is_bare_repository(repo))
 		repo_config_set(repo, "core.bare", "true");
 	else {
 		repo_config_set(repo, "core.bare", "false");

-- 
2.54.0.1189.g8c84645362.dirty


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 5/7] environment: split up concerns of `is_bare_repository_cfg`
  2026-06-10 22:22   ` Justin Tobler
@ 2026-06-11  9:19     ` Patrick Steinhardt
  2026-06-11 15:33       ` Justin Tobler
  0 siblings, 1 reply; 25+ messages in thread
From: Patrick Steinhardt @ 2026-06-11  9:19 UTC (permalink / raw)
  To: Justin Tobler; +Cc: git

On Wed, Jun 10, 2026 at 05:22:04PM -0500, Justin Tobler wrote:
> On 26/06/10 08:56AM, Patrick Steinhardt wrote:
> > diff --git a/builtin/init-db.c b/builtin/init-db.c
> > index 52aa92fb0a..566732c9f4 100644
> > --- a/builtin/init-db.c
> > +++ b/builtin/init-db.c
> > @@ -81,7 +81,7 @@ int cmd_init_db(int argc,
> >  	const char *template_dir = NULL;
> >  	char *template_dir_to_free = NULL;
> >  	unsigned int flags = 0;
> > -	int bare = is_bare_repository_cfg;
> > +	int bare = startup_info->force_bare_repository ? 1 : -1;
> 
> Any particular reason to continue mapping `force_bare_repository=false`
> to -1? Or was this to just minimize changes?

The `-1` value doesn't mean "false", but it rather means "undecided".
The effect of this is that "core.bare" will eventually override this.

> > diff --git a/setup.c b/setup.c
> > index 71fc6b33da..2b690da8ca 100644
> > --- a/setup.c
> > +++ b/setup.c
> > @@ -795,10 +795,16 @@ static int check_repository_format_gently(const char *gitdir,
> >  		has_common = 0;
> >  	}
> >  
> > -	if (!has_common) {
> > -		if (candidate->is_bare != -1)
> > -			is_bare_repository_cfg = candidate->is_bare;
> > -	} else {
> > +	if (startup_info->force_bare_repository) {
> > +		candidate->is_bare = 1;
> > +		FREE_AND_NULL(candidate->work_tree);
> > +	} else if (has_common) {
> > +		/*
> > +		 * When sharing a common dir with another repository (e.g. a
> > +		 * linked worktree), do not let this repository's config
> > +		 * dictate bareness; it is inherited from the main worktree.
> > +		 */
> > +		candidate->is_bare = -1;
> >  		FREE_AND_NULL(candidate->work_tree);
> 
> Previously, when there was a common dir, `candidate->work_tree` was left
> untouched, but now we are expclicitly setting it. I'm not sure I fully
> understand this change.

I cannot blame you. All of this logic is so unbelievably tangled and
hard to follow.

In any case, I think you might have missed the fact that we `else if`
branch is now `has_common` as compared to `!has_common`? To explain the
different cases a bit:

  - When we have `force_bare_repository` we are being told that the
    repository should be treated as bare. So we set `is_bare` and also
    clear the work tree that may have been discovered.

  - When we have a commondir we know that we're in a worktree.
    Previously we did nothing in this case, and that had the implicit
    effect that `is_bare_repository_cfg` would remain at `-1`. So to
    match that behaviour we have to also reset the candidate's bareness
    to `-1`, so that we parse it via the repository's configuration at a
    later point in time.

    The other part here is that we also reset `candidate->work_tree`.
    This is because the expectation is that `$GIT_DIR/common` should
    override any "core.worktree" settings. Quoting git-config(1):

        If GIT_COMMON_DIR environment variable is set, core.worktree is
        ignored and not used for determining the root of working tree.

  - When we don't have a commondir we previosuly had to also adapt the
    global `is_bare_repository_cfg` variable. This part is not necessary
    anymore, so we basically just drop this case altogether.

Patrick

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 5/7] environment: split up concerns of `is_bare_repository_cfg`
  2026-06-11  9:19     ` Patrick Steinhardt
@ 2026-06-11 15:33       ` Justin Tobler
  0 siblings, 0 replies; 25+ messages in thread
From: Justin Tobler @ 2026-06-11 15:33 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git

On 26/06/11 11:19AM, Patrick Steinhardt wrote:
> On Wed, Jun 10, 2026 at 05:22:04PM -0500, Justin Tobler wrote:
> > On 26/06/10 08:56AM, Patrick Steinhardt wrote:
> > > diff --git a/builtin/init-db.c b/builtin/init-db.c
> > > index 52aa92fb0a..566732c9f4 100644
> > > --- a/builtin/init-db.c
> > > +++ b/builtin/init-db.c
> > > @@ -81,7 +81,7 @@ int cmd_init_db(int argc,
> > >  	const char *template_dir = NULL;
> > >  	char *template_dir_to_free = NULL;
> > >  	unsigned int flags = 0;
> > > -	int bare = is_bare_repository_cfg;
> > > +	int bare = startup_info->force_bare_repository ? 1 : -1;
> > 
> > Any particular reason to continue mapping `force_bare_repository=false`
> > to -1? Or was this to just minimize changes?
> 
> The `-1` value doesn't mean "false", but it rather means "undecided".
> The effect of this is that "core.bare" will eventually override this.

Ok, so `bare` here is still ultimately a combination of
`force_bare_repository` and `bare_cfg`.

> > > diff --git a/setup.c b/setup.c
> > > index 71fc6b33da..2b690da8ca 100644
> > > --- a/setup.c
> > > +++ b/setup.c
> > > @@ -795,10 +795,16 @@ static int check_repository_format_gently(const char *gitdir,
> > >  		has_common = 0;
> > >  	}
> > >  
> > > -	if (!has_common) {
> > > -		if (candidate->is_bare != -1)
> > > -			is_bare_repository_cfg = candidate->is_bare;
> > > -	} else {
> > > +	if (startup_info->force_bare_repository) {
> > > +		candidate->is_bare = 1;
> > > +		FREE_AND_NULL(candidate->work_tree);
> > > +	} else if (has_common) {
> > > +		/*
> > > +		 * When sharing a common dir with another repository (e.g. a
> > > +		 * linked worktree), do not let this repository's config
> > > +		 * dictate bareness; it is inherited from the main worktree.
> > > +		 */
> > > +		candidate->is_bare = -1;
> > >  		FREE_AND_NULL(candidate->work_tree);
> > 
> > Previously, when there was a common dir, `candidate->work_tree` was left
> > untouched, but now we are expclicitly setting it. I'm not sure I fully
> > understand this change.
> 
> I cannot blame you. All of this logic is so unbelievably tangled and
> hard to follow.
> 
> In any case, I think you might have missed the fact that we `else if`
> branch is now `has_common` as compared to `!has_common`? To explain the
> different cases a bit:
> 
>   - When we have `force_bare_repository` we are being told that the
>     repository should be treated as bare. So we set `is_bare` and also
>     clear the work tree that may have been discovered.
> 
>   - When we have a commondir we know that we're in a worktree.
>     Previously we did nothing in this case, and that had the implicit
>     effect that `is_bare_repository_cfg` would remain at `-1`. So to
>     match that behaviour we have to also reset the candidate's bareness
>     to `-1`, so that we parse it via the repository's configuration at a
>     later point in time.
> 
>     The other part here is that we also reset `candidate->work_tree`.
>     This is because the expectation is that `$GIT_DIR/common` should
>     override any "core.worktree" settings. Quoting git-config(1):
> 
>         If GIT_COMMON_DIR environment variable is set, core.worktree is
>         ignored and not used for determining the root of working tree.
> 
>   - When we don't have a commondir we previosuly had to also adapt the
>     global `is_bare_repository_cfg` variable. This part is not necessary
>     anymore, so we basically just drop this case altogether.

Thanks for explaination. This make more sense now.

-Justin

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 0/7] setup: drop global state
  2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
                     ` (6 preceding siblings ...)
  2026-06-11  6:44   ` [PATCH v2 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE Patrick Steinhardt
@ 2026-06-11 15:47   ` Justin Tobler
  7 siblings, 0 replies; 25+ messages in thread
From: Justin Tobler @ 2026-06-11 15:47 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git

On 26/06/11 08:44AM, Patrick Steinhardt wrote:
> Hi,
> 
> this patch series continues to refactor "setup.c", where the focus is to
> drop remaining global state that we have in "setup.c". The most
> important consequence of this is that we don't need to rely on
> `the_repository` in `is_bare_repository()` anymore.
> 
> This series is built on top of 1ff279f340 (The 13th batch, 2026-06-09)
> with ps/setup-centralize-odb-creation at 42b9d3dc9d (setup: construct
> object database in `apply_repository_format()`, 2026-06-04) merged into
> it.
> 
> Changes in v2:
>   - Improve documentation for some aspects of `check_repository_format_gently()`.
>   - Link to v1: https://patch.msgid.link/20260610-b4-pks-setup-drop-global-state-v1-0-5dff3eec8f06@pks.im
> 
> Thanks!
> 
> Patrick
> 
> ---
[snip]
> Range-diff versus v1:
> 
> 1:  0281a4bca9 = 1:  96b71f5223 builtin/init: stop modifying global `git_work_tree_cfg` variable
> 2:  6fdc8d77e8 = 2:  a51c0ff79d builtin/init: simplify logic to configure worktree
> 3:  ce31595ff5 ! 3:  e06393ddc5 setup: remove global `git_work_tree_cfg` variable
>     @@ Commit message
>          Refactor the code so that we instead use the worktree configuration as
>          discovered via the repository format. Drop the global variable.
>      
>     +    Note that in `check_repository_format_gently()` we now have to free the
>     +    candidate work tree variable. This change is required to retain previous
>     +    semantics: before we essentially had an implicit `else` branch where we
>     +    set `git_work_tree_cfg = NULL`, but we were able to elide that branch
>     +    because we already knew that it would be `NULL` anyway. Now that we use
>     +    the candidate work tree directly to populate the repository's work tree
>     +    though we have to clear it to retain those semantics.

I find the additional explaination here quite helpful. Thanks.

>          Signed-off-by: Patrick Steinhardt <ps@pks.im>
>      
>       ## setup.c ##
> 4:  6a69dc853c = 4:  628ed54c8c builtin/init: stop modifying `is_bare_repository_cfg`
> 5:  afa2d8bbda ! 5:  02ceaf4a20 environment: split up concerns of `is_bare_repository_cfg`
>     @@ setup.c: static int check_repository_format_gently(const char *gitdir,
>      +		 * dictate bareness; it is inherited from the main worktree.
>      +		 */
>      +		candidate->is_bare = -1;
>     ++
>     ++		/*
>     ++		 * Furthermore, "core.worktree" is supposed to be ignored when
>     ++		 * we have a commondir configured, unless it comes from the
>     ++		 * per-worktree configuration.
>     ++		 */
>       		FREE_AND_NULL(candidate->work_tree);

Ok, so when we have a commondir set we need to clear
`candidate->work_tree` since we need to ignore core.worktree
configuration in such cases. Makes sense.

The changes in this version of the series looks good to me.

-Justin

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2026-06-11 15:47 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-10  6:56 [PATCH 0/7] setup: drop global state Patrick Steinhardt
2026-06-10  6:56 ` [PATCH 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable Patrick Steinhardt
2026-06-10 21:15   ` Justin Tobler
2026-06-10  6:56 ` [PATCH 2/7] builtin/init: simplify logic to configure worktree Patrick Steinhardt
2026-06-10 21:29   ` Justin Tobler
2026-06-10  6:56 ` [PATCH 3/7] setup: remove global `git_work_tree_cfg` variable Patrick Steinhardt
2026-06-10 21:52   ` Justin Tobler
2026-06-11  6:36     ` Patrick Steinhardt
2026-06-10  6:56 ` [PATCH 4/7] builtin/init: stop modifying `is_bare_repository_cfg` Patrick Steinhardt
2026-06-10  6:56 ` [PATCH 5/7] environment: split up concerns of `is_bare_repository_cfg` Patrick Steinhardt
2026-06-10 22:22   ` Justin Tobler
2026-06-11  9:19     ` Patrick Steinhardt
2026-06-11 15:33       ` Justin Tobler
2026-06-10  6:56 ` [PATCH 6/7] environment: stop using `the_repository` in `is_bare_repository()` Patrick Steinhardt
2026-06-10  6:56 ` [PATCH 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE Patrick Steinhardt
2026-06-10 22:26   ` Justin Tobler
2026-06-11  6:44 ` [PATCH v2 0/7] setup: drop global state Patrick Steinhardt
2026-06-11  6:44   ` [PATCH v2 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable Patrick Steinhardt
2026-06-11  6:44   ` [PATCH v2 2/7] builtin/init: simplify logic to configure worktree Patrick Steinhardt
2026-06-11  6:44   ` [PATCH v2 3/7] setup: remove global `git_work_tree_cfg` variable Patrick Steinhardt
2026-06-11  6:44   ` [PATCH v2 4/7] builtin/init: stop modifying `is_bare_repository_cfg` Patrick Steinhardt
2026-06-11  6:44   ` [PATCH v2 5/7] environment: split up concerns of `is_bare_repository_cfg` Patrick Steinhardt
2026-06-11  6:44   ` [PATCH v2 6/7] environment: stop using `the_repository` in `is_bare_repository()` Patrick Steinhardt
2026-06-11  6:44   ` [PATCH v2 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE Patrick Steinhardt
2026-06-11 15:47   ` [PATCH v2 0/7] setup: drop global state Justin Tobler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox