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

[PATCH 3/3] init: do not set core.worktree more often than necessary

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Sep 8, 2016, 13:47 UTC
Message-ID
<20160908134719.27955-4-pclouds@gmail.com>
In-Reply-To
<20160908134719.27955-1-pclouds@gmail.com>

When "git init" is called with GIT_WORK_TREE environment set, we want to keep this worktree's location in core.worktree so the user does not have to set the environment again and again. See ef6f0af (git-init: set core.worktree if GIT_WORK_TREE is specified - 2007-07-04)

We detect that by this logic (in needs_work_tree_config): normally worktree's top dir would contains ".git" directory, if this is not true, worktree is probably set to elsewhere by the user.

Unfortunately when it calls get_git_dir() it does not take ".git" files into account. When we find a .git file, we immediately follow the file until we find the real ".git" directory. The location of this first ".git" file is lost.

The .git file would satisfy the logic above and not create core.worktree (correct). But because the final .git's location is used, needs_work_tree_config() is misled and creates core.worktree anyway.

This would not be a huge deal normally. But if this happens in a multiple worktree setup it becomes a real problem because up until now, core.worktree will be applied to the main worktree only. If you accidentally do "git init" from a linked worktree, you set core.worktree (for the main repo) pointing to the _linked_ worktree. After that point, may you live in interesting times.

Record the .git file location and use it here.
Noticed-by: Max Nordlund <max.nordlund@sqore.com>
Helped-by: Michael J Gruber <git@drmicha.warpmail.net>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/init-db.c |  2 +-
 cache.h           |  1 +
 environment.c     | 16 +++++++++++++++-
 t/t0001-init.sh   |  2 ++
 4 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 6d9552e..36255f2 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -254,7 +254,7 @@ static int create_default_files(const char *template_path)
 		/* allow template config file to override the default */
 		if (log_all_ref_updates == -1)
 			git_config_set("core.logallrefupdates", "true");
-		if (needs_work_tree_config(get_git_dir(), work_tree))
+		if (needs_work_tree_config(get_first_git_dir(), work_tree))
 			git_config_set("core.worktree", work_tree);
 	}
 
diff --git a/cache.h b/cache.h
index b780a91..e6c05f8 100644
--- a/cache.h
+++ b/cache.h
@@ -460,6 +460,7 @@ extern char *git_work_tree_cfg;
 extern int is_inside_work_tree(void);
 extern const char *get_git_dir(void);
 extern const char *get_git_common_dir(void);
+extern const char *get_first_git_dir(void);
 extern char *get_object_directory(void);
 extern char *get_index_file(void);
 extern char *get_graft_file(void);
diff --git a/environment.c b/environment.c
index ca72464..8cfb8f3 100644
--- a/environment.c
+++ b/environment.c
@@ -100,7 +100,7 @@ static char *work_tree;
 static const char *namespace;
 static size_t namespace_len;
 
-static const char *git_dir, *git_common_dir;
+static const char *git_dir, *git_common_dir, *first_git_dir;
 static char *git_object_dir, *git_index_file, *git_graft_file;
 int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
 
@@ -168,6 +168,8 @@ static void setup_git_env(void)
 	if (!git_dir)
 		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 	gitfile = read_gitfile(git_dir);
+	if (gitfile && !first_git_dir)
+		first_git_dir = xstrdup(git_dir);
 	git_dir = xstrdup(gitfile ? gitfile : git_dir);
 	if (get_common_dir(&sb, git_dir))
 		git_common_dir_env = 1;
@@ -203,6 +205,18 @@ const char *get_git_dir(void)
 	return git_dir;
 }
 
+/*
+ * Return the first ".git" that we have encountered.
+ * FIXME this function for not entirely correct because
+ * setup_git_directory() and enter_repo() do not update first_git_dir
+ * when they follow .git files. The function in its current state is
+ * only suitable for "git init".
+ */
+const char *get_first_git_dir(void)
+{
+	return first_git_dir ? first_git_dir : git_dir;
+}
+
 const char *get_git_common_dir(void)
 {
 	return git_common_dir;
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 393c940..d59669a 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -393,9 +393,11 @@ test_expect_success 're-init from a linked worktree' '
 		test_commit first &&
 		git worktree add ../linked-worktree &&
 		mv .git/info/exclude expected-exclude &&
+		cp .git/config expected-config &&
 		find .git/worktrees -print | sort >expected &&
 		git -C ../linked-worktree init &&
 		test_cmp expected-exclude .git/info/exclude &&
+		test_cmp expected-config .git/config &&
 		find .git/worktrees -print | sort >actual &&
 		test_cmp expected actual
 	)
-- 
2.8.2.524.g6ff3d78
Previous: Jacob KellerNext: Junio C Hamano
Message 14 of 34 in “Bug with git worktrees and git init”
  1. Max NordlundAug 23, 2016
  2. Michael J GruberAug 23, 2016
  3. Duy NguyenAug 24, 2016
  4. 0/3 Fix git-init in linked worktreesNguyễn Thái Ngọc Duy, Sep 8, 2016
  5. 1/3 init: correct re-initialization from a linked worktreeNguyễn Thái Ngọc Duy, Sep 8, 2016
  6. Junio C HamanoSep 8, 2016
  7. Duy NguyenSep 9, 2016
  8. 2/3 t0001: work around the bug that reads config file before repo setupNguyễn Thái Ngọc Duy, Sep 8, 2016
  9. Junio C HamanoSep 8, 2016
  10. Jeff KingSep 8, 2016
  11. Duy NguyenSep 9, 2016
  12. Jeff KingSep 9, 2016
  13. Jacob KellerSep 9, 2016
  14. 3/3 init: do not set core.worktree more often than necessaryNguyễn Thái Ngọc Duy, Sep 8, 2016
  15. Junio C HamanoSep 8, 2016
  16. Duy NguyenSep 9, 2016
  17. 0/3 Fix git-init in linked worktreesNguyễn Thái Ngọc Duy, Sep 21, 2016
  18. 1/3 init: correct re-initialization from a linked worktreeNguyễn Thái Ngọc Duy, Sep 21, 2016
  19. 2/3 init: do not set core.worktree more often than necessaryNguyễn Thái Ngọc Duy, Sep 21, 2016
  20. Junio C HamanoSep 21, 2016
  21. Duy NguyenSep 22, 2016
  22. Junio C HamanoSep 22, 2016
  23. 4/3 init: combine set_git_dir_init() and init_db() into oneNguyễn Thái Ngọc Duy, Sep 23, 2016
  24. Junio C HamanoSep 23, 2016
  25. Junio C HamanoSep 23, 2016
  26. Junio C HamanoSep 24, 2016
  27. Duy NguyenSep 25, 2016
  28. 1/5 init: correct re-initialization from a linked worktreeNguyễn Thái Ngọc Duy, Sep 25, 2016
  29. 2/5 init: call set_git_dir_init() from within init_db()Nguyễn Thái Ngọc Duy, Sep 25, 2016
  30. 3/5 init: kill set_git_dir_init()Nguyễn Thái Ngọc Duy, Sep 25, 2016
  31. 4/5 init: do not set unnecessary core.worktreeNguyễn Thái Ngọc Duy, Sep 25, 2016
  32. 5/5 init: kill git_link variableNguyễn Thái Ngọc Duy, Sep 25, 2016
  33. 3/3 init: reuse original_git_dir in set_git_dir_init()Nguyễn Thái Ngọc Duy, Sep 21, 2016
  34. Junio C HamanoSep 21, 2016

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.