setup: mark bogus worktree in `apply_repository_format()`

When a repository is configured to have both "core.worktree" and "core.bare" we emit a warning and mark the worktree configuration as bogus so that the next call to `setup_work_tree()` will cause us to die. This allows us to still use the misconfigured repository, at least as long as we don't try to use its worktree. This condition is handled in `setup_explicit_git_dir()`. In a subsequent commit we'll refactor this function so that it doesn't receive a repo as input anymore though, and consequently we cannot set the "bogus" bit anymore. Move the logic into `apply_repository_format()` instead to prepare for this. While at it, fix up formatting a bit. Note that this change requires us to also explicitly unset the value of "core.worktree" in case we have the "GIT_WORK_TREE" environment variable set. This is because the environment variable overrides the repository's configuration, and we don't want to warn or die in case the work tree has been configured explicitly regardless of whether or not "core.bare" is set. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jul 7, 2026 at 09:21 UTC c6799958b1e6c269a570e9a617986e4035e5756c
1 file changed +21 -16
setup.c
+21 -16
@@ -1147,24 +1147,24 @@ static const char *setup_explicit_git_dir(struct repository *repo,
1147 }
1148
1149 /* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
1150 - if (work_tree_env)
1150 + if (work_tree_env) {
1151 + /*
1152 + * The environment variable overrides "core.worktree". This
1153 + * also has the consequence that we don't want to flag cases as
1154 + * bogus where we have both "core.worktree" and "core.bare", so
1155 + * we have to explicitly unset the configuration.
1156 + */
1157 + FREE_AND_NULL(repo_fmt->work_tree);
1158 set_git_work_tree(repo, work_tree_env);
1152 - else if (repo_fmt->is_bare > 0) {
1153 - if (repo_fmt->work_tree) {
1154 - /* #22.2, #30 */
1155 - warning("core.bare and core.worktree do not make sense");
1156 - repo->worktree_config_is_bogus = true;
1157 - }
1158 -
1159 + } else if (repo_fmt->is_bare > 0) {
1160 /* #18, #26 */
1161 set_git_dir(repo, gitdirenv, 0);
1162 free(gitfile);
1163 return NULL;
1163 - }
1164 - else if (repo_fmt->work_tree) { /* #6, #14 */
1165 - if (is_absolute_path(repo_fmt->work_tree))
1164 + } else if (repo_fmt->work_tree) { /* #6, #14 */
1165 + if (is_absolute_path(repo_fmt->work_tree)) {
1166 set_git_work_tree(repo, repo_fmt->work_tree);
1167 - else {
1167 + } else {
1168 char *core_worktree;
1169 if (chdir(gitdirenv))
1170 die_errno(_("cannot chdir to '%s'"), gitdirenv);
@@ -1176,15 +1176,14 @@ static const char *setup_explicit_git_dir(struct repository *repo,
1176 set_git_work_tree(repo, core_worktree);
1177 free(core_worktree);
1178 }
1179 - }
1180 - else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) {
1179 + } else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) {
1180 /* #16d */
1181 set_git_dir(repo, gitdirenv, 0);
1182 free(gitfile);
1183 return NULL;
1185 - }
1186 - else /* #2, #10 */
1184 + } else { /* #2, #10 */
1185 set_git_work_tree(repo, ".");
1186 + }
1187
1188 /* set_git_work_tree() must have been called by now */
1189 worktree = repo_get_work_tree(repo);
@@ -1768,6 +1767,12 @@ int apply_repository_format(struct repository *repo,
1767 if (verify_repository_format(format, err) < 0)
1768 return -1;
1769
1770 + if (format->is_bare > 0 && format->work_tree) {
1771 + /* #22.2, #30 */
1772 + warning("core.bare and core.worktree do not make sense");
1773 + repo->worktree_config_is_bogus = true;
1774 + }
1775 +
1776 if (flags & APPLY_REPOSITORY_FORMAT_HONOR_ENV) {
1777 object_directory = xstrdup_or_null(getenv(DB_ENVIRONMENT));
1778 alternate_object_directories = xstrdup_or_null(getenv(ALTERNATE_DB_ENVIRONMENT));