git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v4] worktree: detect from secondary worktree if main worktree is bare

From
Olga Pilipenco via GitGitGadget <gitgitgadget@gmail.com>
Date
Feb 5, 2025, 06:30 UTC
Message-ID
<pull.1829.v4.git.1738737014194.gitgitgadget@gmail.com>
In-Reply-To
<pull.1829.v3.git.1738346881907.gitgitgadget@gmail.com>
From: Olga Pilipenco <olga.pilipenco@shopify.com>

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.)

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Olga Pilipenco <olga.pilipenco@shopify.com>
---
    worktree: detect from secondary worktree if main worktree is bare
    
    Changes since v3:
    
     * added a comment to explain why extra check is needed to detect if
       main worktree bare
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1829%2Folga-mcbfe%2Ffix-bare-repo-detection-with-worktree-config-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1829/olga-mcbfe/fix-bare-repo-detection-with-worktree-config-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/1829
Range-diff vs v3:
 1:  f9207746b38 ! 1:  a34459b5681 worktree: detect from secondary worktree if main worktree is bare
     @@ worktree.c: static struct worktree *get_main_worktree(int skip_reading_head)
       	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)
 t/t3200-branch.sh | 14 ++++++++++++++
 worktree.c        | 41 ++++++++++++++++++++++++++++++++---------
 2 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index a3a21c54cf6..f3e720dc10d 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -410,6 +410,20 @@ test_expect_success 'bare main worktree has HEAD at branch deleted by secondary
 	git -C secondary branch -D main
 '
 
+test_expect_success 'secondary worktrees recognize core.bare=true in main config.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 248bbb39d43..d4a68c9c235 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/<id>/
+* 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;

base-commit: f93ff170b93a1782659637824b25923245ac9dd1
-- 
gitgitgadget
Previous: Olga PilipencoNext: Eric Sunshine
Message 15 of 19 in “worktree: detect from secondary worktree if main worktree is bare”
  1. worktree: detect from secondary worktree if main worktree is bareOlga Pilipenco via GitGitGadget, Nov 15, 2024
  2. worktree: detect from secondary worktree if main worktree is bareOlga Pilipenco via GitGitGadget, Jan 16, 2025
  3. Eric SunshineJan 19, 2025
  4. Olga PilipencoJan 28, 2025
  5. Eric SunshineJan 29, 2025
  6. Junio C HamanoJan 29, 2025
  7. worktree: detect from secondary worktree if main worktree is bareOlga Pilipenco via GitGitGadget, Jan 31, 2025
  8. Junio C HamanoJan 31, 2025
  9. Junio C HamanoJan 31, 2025
  10. Olga PilipencoJan 31, 2025
  11. Junio C HamanoJan 31, 2025
  12. Olga PilipencoFeb 4, 2025
  13. Junio C HamanoFeb 4, 2025
  14. Olga PilipencoFeb 4, 2025
  15. worktree: detect from secondary worktree if main worktree is bareOlga Pilipenco via GitGitGadget, Feb 5, 2025
  16. Eric SunshineJan 30, 2025
  17. Eric SunshineJan 30, 2025
  18. Olga PilipencoJan 31, 2025
  19. Eric SunshineJan 31, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.