From 78a95e0d806677fbb1d436c2985e39c1f8ce3c00 Mon Sep 17 00:00:00 2001 From: Olga Pilipenco Date: Wed, 5 Feb 2025 06:30:13 +0000 Subject: worktree: detect from secondary worktree if main worktree is bare When extensions.worktreeConfig is true and the main worktree is bare -- that is, its config.worktree file contains core.bare=true -- commands run from secondary worktrees incorrectly see the main worktree as not bare. As such, those commands incorrectly think that the repository's default branch (typically "main" or "master") is checked out in the bare repository even though it's not. This makes it impossible, for instance, to checkout or delete the default branch from a secondary worktree, among other shortcomings. This problem occurs because, when extensions.worktreeConfig is true, commands run in secondary worktrees only consult $commondir/config and $commondir/worktrees//config.worktree, thus they never see the main worktree's core.bare=true setting in $commondir/config.worktree. Fix this problem by consulting the main worktree's config.worktree file when checking whether it is bare. (This extra work is performed only when running from a secondary worktree.) Helped-by: Eric Sunshine Signed-off-by: Olga Pilipenco Signed-off-by: Junio C Hamano --- worktree.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'worktree.c') diff --git a/worktree.c b/worktree.c index 248bbb39d4..d4a68c9c23 100644 --- a/worktree.c +++ b/worktree.c @@ -65,6 +65,28 @@ static int is_current_worktree(struct worktree *wt) return is_current; } +/* +* When in a secondary worktree, and when extensions.worktreeConfig +* is true, only $commondir/config and $commondir/worktrees// +* config.worktree are consulted, hence any core.bare=true setting in +* $commondir/config.worktree gets overlooked. Thus, check it manually +* to determine if the repository is bare. +*/ +static int is_main_worktree_bare(struct repository *repo) +{ + int bare = 0; + struct config_set cs = {0}; + char *worktree_config = xstrfmt("%s/config.worktree", repo_get_common_dir(repo)); + + git_configset_init(&cs); + git_configset_add_file(&cs, worktree_config); + git_configset_get_bool(&cs, "core.bare", &bare); + + git_configset_clear(&cs); + free(worktree_config); + return bare; +} + /** * get the main worktree */ @@ -79,16 +101,17 @@ static struct worktree *get_main_worktree(int skip_reading_head) CALLOC_ARRAY(worktree, 1); worktree->repo = the_repository; worktree->path = strbuf_detach(&worktree_path, NULL); - /* - * NEEDSWORK: If this function is called from a secondary worktree and - * config.worktree is present, is_bare_repository_cfg will reflect the - * contents of config.worktree, not the contents of the main worktree. - * This means that worktree->is_bare may be set to 0 even if the main - * worktree is configured to be bare. - */ - worktree->is_bare = (is_bare_repository_cfg == 1) || - is_bare_repository(); worktree->is_current = is_current_worktree(worktree); + worktree->is_bare = (is_bare_repository_cfg == 1) || + is_bare_repository() || + /* + * When in a secondary worktree we have to also verify if the main + * worktree is bare in $commondir/config.worktree. + * This check is unnecessary if we're currently in the main worktree, + * as prior checks already consulted all configs of the current worktree. + */ + (!worktree->is_current && is_main_worktree_bare(the_repository)); + if (!skip_reading_head) add_head_info(worktree); return worktree; -- cgit v1.2.3