diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index ccfa6a720d090c..819228a3344bcf 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -411,6 +411,20 @@ test_expect_success 'bare main worktree has HEAD at branch deleted by secondary git -C secondary branch -D main ' +test_expect_success 'secondary worktree can switch to main if common dir is bare worktree' ' + test_when_finished "rm -rf bare_repo non_bare_repo secondary_worktree" && + git init -b main non_bare_repo && + test_commit -C non_bare_repo x && + + git clone --bare non_bare_repo bare_repo && + git -C bare_repo config extensions.worktreeConfig true && + git -C bare_repo config unset core.bare && + git -C bare_repo config --worktree core.bare true && + + git -C bare_repo worktree add ../secondary_worktree && + git -C secondary_worktree checkout main +' + test_expect_success 'git branch --list -v with --abbrev' ' test_when_finished "git branch -D t" && git branch t && diff --git a/worktree.c b/worktree.c index 77ff484d3ec48c..af591b7a86d66e 100644 --- a/worktree.c +++ b/worktree.c @@ -64,6 +64,29 @@ static int is_current_worktree(struct worktree *wt) return is_current; } +static int is_bare_git_dir(const char *git_dir) +{ + int bare = 0; + struct config_set cs = { { 0 } }; + char *config_file; + char *worktree_config_file; + + config_file = xstrfmt("%s/config", git_dir); + worktree_config_file = xstrfmt("%s/config.worktree", git_dir); + + git_configset_init(&cs); + git_configset_add_file(&cs, config_file); + git_configset_add_file(&cs, worktree_config_file); + + git_configset_get_bool(&cs, "core.bare", &bare); + +cleanup: + git_configset_clear(&cs); + free(config_file); + free(worktree_config_file); + return bare; +} + /** * get the main worktree */ @@ -76,18 +99,16 @@ static struct worktree *get_main_worktree(int skip_reading_head) strbuf_strip_suffix(&worktree_path, "/.git"); CALLOC_ARRAY(worktree, 1); + /* + * NEEDSWORK: the_repository is not always main worktree's repository + */ 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() || + !worktree->is_current && is_bare_git_dir(repo_get_common_dir(the_repository)); + if (!skip_reading_head) add_head_info(worktree); return worktree;