Skip to content

Commit fda52a1

Browse files
committed
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/<id>/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.) Signed-off-by: Olga Pilipenco <[email protected]>
1 parent f93ff17 commit fda52a1

File tree

2 files changed

+38
-9
lines changed

2 files changed

+38
-9
lines changed

t/t3200-branch.sh

+14
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,20 @@ test_expect_success 'bare main worktree has HEAD at branch deleted by secondary
410410
git -C secondary branch -D main
411411
'
412412

413+
test_expect_success 'secondary worktrees recognize core.bare=true in main config.worktree' '
414+
test_when_finished "rm -rf bare_repo non_bare_repo secondary_worktree" &&
415+
git init -b main non_bare_repo &&
416+
test_commit -C non_bare_repo x &&
417+
418+
git clone --bare non_bare_repo bare_repo &&
419+
git -C bare_repo config extensions.worktreeConfig true &&
420+
git -C bare_repo config unset core.bare &&
421+
git -C bare_repo config --worktree core.bare true &&
422+
423+
git -C bare_repo worktree add ../secondary_worktree &&
424+
git -C secondary_worktree checkout main
425+
'
426+
413427
test_expect_success 'git branch --list -v with --abbrev' '
414428
test_when_finished "git branch -D t" &&
415429
git branch t &&

worktree.c

+24-9
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,26 @@ static int is_current_worktree(struct worktree *wt)
6565
return is_current;
6666
}
6767

68+
static int is_main_worktree_bare(void)
69+
{
70+
int bare = 0;
71+
struct config_set cs = {0};
72+
const char *common_dir = repo_get_common_dir(the_repository);
73+
char *config_file = xstrfmt("%s/config", common_dir);
74+
char *worktree_config_file = xstrfmt("%s/config.worktree", common_dir);
75+
76+
git_configset_init(&cs);
77+
git_configset_add_file(&cs, config_file);
78+
git_configset_add_file(&cs, worktree_config_file);
79+
80+
git_configset_get_bool(&cs, "core.bare", &bare);
81+
82+
git_configset_clear(&cs);
83+
free(config_file);
84+
free(worktree_config_file);
85+
return bare;
86+
}
87+
6888
/**
6989
* get the main worktree
7090
*/
@@ -79,16 +99,11 @@ static struct worktree *get_main_worktree(int skip_reading_head)
7999
CALLOC_ARRAY(worktree, 1);
80100
worktree->repo = the_repository;
81101
worktree->path = strbuf_detach(&worktree_path, NULL);
82-
/*
83-
* NEEDSWORK: If this function is called from a secondary worktree and
84-
* config.worktree is present, is_bare_repository_cfg will reflect the
85-
* contents of config.worktree, not the contents of the main worktree.
86-
* This means that worktree->is_bare may be set to 0 even if the main
87-
* worktree is configured to be bare.
88-
*/
89-
worktree->is_bare = (is_bare_repository_cfg == 1) ||
90-
is_bare_repository();
91102
worktree->is_current = is_current_worktree(worktree);
103+
worktree->is_bare = (is_bare_repository_cfg == 1) ||
104+
is_bare_repository() ||
105+
(!worktree->is_current && is_main_worktree_bare());
106+
92107
if (!skip_reading_head)
93108
add_head_info(worktree);
94109
return worktree;

0 commit comments

Comments
 (0)