]> git.ipfire.org Git - thirdparty/git.git/commitdiff
environment: split up concerns of `is_bare_repository_cfg`
authorPatrick Steinhardt <ps@pks.im>
Thu, 11 Jun 2026 06:44:43 +0000 (08:44 +0200)
committerJunio C Hamano <gitster@pobox.com>
Thu, 11 Jun 2026 12:05:54 +0000 (05:05 -0700)
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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/init-db.c
environment.c
environment.h
git.c
repository.c
repository.h
setup.c
setup.h
worktree.c

index 52aa92fb0a4c87276a4770c9db56c92d0db47e37..566732c9f4a8eeb0231acec546b798a65ffdf309 100644 (file)
@@ -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;
index 4e86335f250f2aee0324f18785b33048d726ccbd..9d7c908c55012a4c5500734c3c58a1bb7364fc51 100644 (file)
@@ -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;
        }
 
index 5d6e4e6c1bc0cfd45948795a7533f48bfef6f296..afb5bcf197d6746ecd0a85a7511e755bad32f5a5 100644 (file)
@@ -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 36f08891ef5476ec446657d9f489b3b67dc916e5..387eabe38c19516fc1a94bc3b92cb26661c5e02c 100644 (file)
--- 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);
index 187dd471c4e607910f093aec6cdb641f382d1229..c1e91eb0da7b3a4927d88655209fb3fe8716b2e1 100644 (file)
@@ -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_);
 
        /*
index 36e2db26332c0ee7c3c3dbd52eb53749c6b9c439..7d649e32e7fad3781befb430c5045c2a12357c8a 100644 (file)
@@ -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 71fc6b33da142b2c294022d33bf0adb2e9fc0240..32f14a868860eacb982de2cad5151f7d7fe9b8cc 100644 (file)
--- 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 705d1d6ff796852b103ac2e9ab0ba493501a6379..b9fd96bea6e639d207a39ce09cf7d0a745425cba 100644 (file)
--- 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;
index 97eddc391669532e2bcae0302d8603ab4b76e109..7d70f2c1dab15f9f790ab77b5d0ff2d2df15509d 100644 (file)
@@ -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