diff --git a/attr.c b/attr.c index c61472a4e6..0e63f1b6de 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 @@ parse_done: 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 c26c93ee0f..d32af422af 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/init-db.c b/builtin/init-db.c index c55517ad94..566732c9f4 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 = startup_info->force_bare_repository ? 1 : -1; 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=) not allowed without " "specifying %s (or --git-dir=)"), GIT_WORK_TREE_ENVIRONMENT, @@ -224,22 +225,31 @@ 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 (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)); diff --git a/builtin/repack.c b/builtin/repack.c index 1524a9c13a..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())) + (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(repo))) write_bitmaps = 0; } if (po_args.pack_kept_objects < 0) diff --git a/builtin/repo.c b/builtin/repo.c index 69f3626467..cb33a8b851 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 ba2c60103f..bee2cd621a 100644 --- a/environment.c +++ b/environment.c @@ -46,7 +46,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 */ char *git_commit_encoding; char *git_log_output_encoding; char *apply_default_whitespace; @@ -92,9 +91,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. */ @@ -128,10 +124,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 is_bare_repository_cfg && !repo_get_work_tree(the_repository); + return repo->bare_cfg && !repo_get_work_tree(repo); } int have_git_dir(void) @@ -337,7 +333,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 6f18286955..f5b9b33c90 100644 --- a/environment.h +++ b/environment.h @@ -135,6 +135,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 @@ -157,10 +159,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); -extern char *git_work_tree_cfg; - /* Environment bits from configuration mechanism */ extern int trust_executable_bit; extern int has_symlinks; 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/mailmap.c b/mailmap.c index 72b639e602..1386ab208c 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()) + if (!mailmap_blob && is_bare_repository(repo)) mailmap_blob = xstrdup("HEAD:.mailmap"); - if (!startup_info->have_repository || !is_bare_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/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..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() ? 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/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 b4652651df..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" @@ -795,14 +794,23 @@ 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; - } - if (candidate->work_tree) { - free(git_work_tree_cfg); - git_work_tree_cfg = xstrdup(candidate->work_tree); - } + 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); } return 0; @@ -1141,8 +1149,8 @@ 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) { - if (git_work_tree_cfg) { + 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"); repo->worktree_config_is_bogus = true; @@ -1153,15 +1161,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")); @@ -1214,7 +1222,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; @@ -1228,7 +1236,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")); @@ -1264,7 +1272,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); @@ -1765,6 +1773,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); @@ -2574,7 +2583,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 @@ -2600,7 +2609,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(repo)) repo_config_set(repo, "core.bare", "true"); else { repo_config_set(repo, "core.bare", "false"); 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/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 97eddc3916..30125827fd 100644 --- a/worktree.c +++ b/worktree.c @@ -123,8 +123,8 @@ 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) || - is_bare_repository() || + worktree->is_bare = (the_repository->bare_cfg == 1) || + 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.