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

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

From
Olga Pilipenco via GitGitGadget <gitgitgadget@gmail.com>
Date
Nov 15, 2024, 06:52 UTC
Message-ID
<pull.1829.git.1731653548549.gitgitgadget@gmail.com>
From: Olga Pilipenco <olga.pilipenco@shopify.com>
Setup:
1. Have a bare repo with core.bare = true in config.worktree
2. Create a new worktree

Behavior: From the secondary worktree the main worktree appears as non-bare.

Expected: From the secondary worktree the main worktree should appear as bare.

Why current behavior is not good? If the main worktree is detected as not bare it doesn't allow checking out the branch of the main worktree. There are possibly other problems associated with that behavior.

Why is it happening? While we're inside the secondary worktree we don't initialize the main worktree's repository with its configuration.

How is it fixed? Load actual configs of the main worktree. Also, skip the config loading step if we're already inside the current worktree because in that case we rely on is_bare_repository() to return the correct result.

Other solutions considered: Alternatively, instead of incorrectly always using `the_repository` as the main worktree's repository, we can detect and load the actual repository of the main worktree and then use that repository's `is_bare` value extracted from correct configs. However, this approach is a bit riskier and could also affect performance. Since we had the assignment `worktree->repo = the_repository` for a long time already, I decided it's safe to keep it as it is for now; it can be still fixed separately from this change.

Real life use case:
1. Have a bare repo
2. Create a worktree from the bare repo
3. In the secondary worktree enable sparse-checkout - this enables
extensions.worktreeConfig and keeps core.bare=true setting in
config.worktree of the bare worktree
4. The secondary worktree or any other non-bare worktree created
won't be able to use branch main (not even once), but it should be
able to.
Signed-off-by: Olga Pilipenco <olga.pilipenco@shopify.com>
---
    worktree: detect from secondary worktree if main worktree is bare
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1829%2Folga-mcbfe%2Ffix-bare-repo-detection-with-worktree-config-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1829/olga-mcbfe/fix-bare-repo-detection-with-worktree-config-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1829
 t/t3200-branch.sh | 14 ++++++++++++++
 worktree.c        | 38 +++++++++++++++++++++++++++++---------
 2 files changed, 43 insertions(+), 9 deletions(-)
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index ccfa6a720d0..819228a3344 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 77ff484d3ec..1bce505bdd7 100644
--- a/worktree.c
+++ b/worktree.c
@@ -64,6 +64,28 @@ 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);
+
+	git_configset_clear(&cs);
+	free(config_file);
+	free(worktree_config_file);
+	return bare;
+}
+
 /**
  * get the main worktree
  */
@@ -76,18 +98,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;

base-commit: 25b0f41288718625b18495de23cc066394c09a92
-- 
gitgitgadget
Next: Olga Pilipenco via GitGitGadget
Message 1 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.