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

[PATCH v3 02/12] worktree: skip reading HEAD when repairing worktrees

From
Patrick Steinhardt <ps@pks.im>
Date
Dec 29, 2023, 07:26 UTC
Message-ID
<77c7213c66d6b5caf2c24e17578d3e42f7b745a7.1703833819.git.ps@pks.im>
In-Reply-To
<cover.1703833818.git.ps@pks.im>

When calling `git init --separate-git-dir=<new-path>` on a preexisting repository, we move the Git directory of that repository to the new path specified by the user. If there are worktrees present in the repository, we need to repair the worktrees so that their gitlinks point to the new location of the repository.

This repair logic will load repositories via `get_worktrees()`, which will enumerate up and initialize all worktrees. Part of initialization is logic that we resolve their respective worktree HEADs, even though that information may not actually be needed in the end by all callers.

Although not a problem presently with the file-based reference backend, it will become a problem with the upcoming reftable backend. In the context of git-init(1) we do not have a fully-initialized repository set up via `setup_git_directory()` or friends. Consequently, we do not know about the repository format when `repair_worktrees()` is called, and properly setting up all parts of the repositroy in `init_db()` before we try to repair worktrees is not an easy task. With the introduction of the reftable backend, we would ultimately try to look up the worktree HEADs before we have figured out the reference format, which does not work.

We do not require the worktree HEADs at all to repair worktrees. So let's fix this issue by skipping over the step that reads them.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 worktree.c | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/worktree.c b/worktree.c
index a56a6c2a3d..cc34a3419b 100644
--- a/worktree.c
+++ b/worktree.c
@@ -51,7 +51,7 @@ static void add_head_info(struct worktree *wt)
 /**
  * get the main worktree
  */
-static struct worktree *get_main_worktree(void)
+static struct worktree *get_main_worktree(int skip_reading_head)
 {
 	struct worktree *worktree = NULL;
 	struct strbuf worktree_path = STRBUF_INIT;
@@ -70,11 +70,13 @@ static struct worktree *get_main_worktree(void)
 	 */
 	worktree->is_bare = (is_bare_repository_cfg == 1) ||
 		is_bare_repository();
-	add_head_info(worktree);
+	if (!skip_reading_head)
+		add_head_info(worktree);
 	return worktree;
 }
 
-static struct worktree *get_linked_worktree(const char *id)
+static struct worktree *get_linked_worktree(const char *id,
+					    int skip_reading_head)
 {
 	struct worktree *worktree = NULL;
 	struct strbuf path = STRBUF_INIT;
@@ -93,7 +95,8 @@ static struct worktree *get_linked_worktree(const char *id)
 	CALLOC_ARRAY(worktree, 1);
 	worktree->path = strbuf_detach(&worktree_path, NULL);
 	worktree->id = xstrdup(id);
-	add_head_info(worktree);
+	if (!skip_reading_head)
+		add_head_info(worktree);
 
 done:
 	strbuf_release(&path);
@@ -118,7 +121,14 @@ static void mark_current_worktree(struct worktree **worktrees)
 	free(git_dir);
 }
 
-struct worktree **get_worktrees(void)
+/*
+ * NEEDSWORK: This function exists so that we can look up metadata of a
+ * worktree without trying to access any of its internals like the refdb. It
+ * would be preferable to instead have a corruption-tolerant function for
+ * retrieving worktree metadata that could be used when the worktree is known
+ * to not be in a healthy state, e.g. when creating or repairing it.
+ */
+static struct worktree **get_worktrees_internal(int skip_reading_head)
 {
 	struct worktree **list = NULL;
 	struct strbuf path = STRBUF_INIT;
@@ -128,7 +138,7 @@ struct worktree **get_worktrees(void)
 
 	ALLOC_ARRAY(list, alloc);
 
-	list[counter++] = get_main_worktree();
+	list[counter++] = get_main_worktree(skip_reading_head);
 
 	strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
 	dir = opendir(path.buf);
@@ -137,7 +147,7 @@ struct worktree **get_worktrees(void)
 		while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
 			struct worktree *linked = NULL;
 
-			if ((linked = get_linked_worktree(d->d_name))) {
+			if ((linked = get_linked_worktree(d->d_name, skip_reading_head))) {
 				ALLOC_GROW(list, counter + 1, alloc);
 				list[counter++] = linked;
 			}
@@ -151,6 +161,11 @@ struct worktree **get_worktrees(void)
 	return list;
 }
 
+struct worktree **get_worktrees(void)
+{
+	return get_worktrees_internal(0);
+}
+
 const char *get_worktree_git_dir(const struct worktree *wt)
 {
 	if (!wt)
@@ -591,7 +606,7 @@ static void repair_noop(int iserr UNUSED,
 
 void repair_worktrees(worktree_repair_fn fn, void *cb_data)
 {
-	struct worktree **worktrees = get_worktrees();
+	struct worktree **worktrees = get_worktrees_internal(1);
 	struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
 
 	if (!fn)
-- 
2.43.GIT
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 49 of 60 in “Introduce `refStorage` extension”
  1. 00/12 Introduce `refStorage` extensionPatrick Steinhardt, Dec 20, 2023
  2. 01/12 t: introduce DEFAULT_REPO_FORMAT prereqPatrick Steinhardt, Dec 20, 2023
  3. Karthik NayakDec 22, 2023
  4. Patrick SteinhardtDec 28, 2023
  5. 02/12 worktree: skip reading HEAD when repairing worktreesPatrick Steinhardt, Dec 20, 2023
  6. Karthik NayakDec 22, 2023
  7. 03/12 refs: refactor logic to look up storage backendsPatrick Steinhardt, Dec 20, 2023
  8. Karthik NayakDec 22, 2023
  9. Patrick SteinhardtDec 28, 2023
  10. 04/12 setup: start tracking ref storage format whenPatrick Steinhardt, Dec 20, 2023
  11. Junio C HamanoDec 20, 2023
  12. Patrick SteinhardtDec 28, 2023
  13. Junio C HamanoDec 28, 2023
  14. Patrick SteinhardtDec 28, 2023
  15. Karthik NayakDec 22, 2023
  16. Patrick SteinhardtDec 28, 2023
  17. 05/12 setup: set repository's formats on initPatrick Steinhardt, Dec 20, 2023
  18. 06/12 setup: introduce "extensions.refStorage" extensionPatrick Steinhardt, Dec 20, 2023
  19. 07/12 setup: introduce GIT_DEFAULT_REF_FORMAT envvarPatrick Steinhardt, Dec 20, 2023
  20. 08/12 t: introduce GIT_TEST_DEFAULT_REF_FORMAT envvarPatrick Steinhardt, Dec 20, 2023
  21. 09/12 builtin/rev-parse: introduce `--show-ref-format` flagPatrick Steinhardt, Dec 20, 2023
  22. 10/12 builtin/init: introduce `--ref-format=` value flagPatrick Steinhardt, Dec 20, 2023
  23. 11/12 builtin/clone: introduce `--ref-format=` value flagPatrick Steinhardt, Dec 20, 2023
  24. 12/12 t9500: write "extensions.refstorage" into configPatrick Steinhardt, Dec 20, 2023
  25. Karthik NayakDec 22, 2023
  26. Karthik NayakDec 22, 2023
  27. Junio C HamanoDec 26, 2023
  28. 00/12 Introduce `refStorage` extensionPatrick Steinhardt, Dec 28, 2023
  29. 01/12 t: introduce DEFAULT_REPO_FORMAT prereqPatrick Steinhardt, Dec 28, 2023
  30. 02/12 worktree: skip reading HEAD when repairing worktreesPatrick Steinhardt, Dec 28, 2023
  31. Eric SunshineDec 28, 2023
  32. Eric SunshineDec 28, 2023
  33. Patrick SteinhardtDec 28, 2023
  34. 03/12 refs: refactor logic to look up storage backendsPatrick Steinhardt, Dec 28, 2023
  35. Junio C HamanoDec 28, 2023
  36. Patrick SteinhardtDec 28, 2023
  37. Junio C HamanoDec 28, 2023
  38. 04/12 setup: start tracking ref storage formatPatrick Steinhardt, Dec 28, 2023
  39. 05/12 setup: set repository's formats on initPatrick Steinhardt, Dec 28, 2023
  40. 06/12 setup: introduce "extensions.refStorage" extensionPatrick Steinhardt, Dec 28, 2023
  41. 07/12 setup: introduce GIT_DEFAULT_REF_FORMAT envvarPatrick Steinhardt, Dec 28, 2023
  42. 08/12 t: introduce GIT_TEST_DEFAULT_REF_FORMAT envvarPatrick Steinhardt, Dec 28, 2023
  43. 09/12 builtin/rev-parse: introduce `--show-ref-format` flagPatrick Steinhardt, Dec 28, 2023
  44. 10/12 builtin/init: introduce `--ref-format=` value flagPatrick Steinhardt, Dec 28, 2023
  45. 11/12 builtin/clone: introduce `--ref-format=` value flagPatrick Steinhardt, Dec 28, 2023
  46. 12/12 t9500: write "extensions.refstorage" into configPatrick Steinhardt, Dec 28, 2023
  47. 00/12 Introduce `refStorage` extensionPatrick Steinhardt, Dec 29, 2023
  48. 01/12 t: introduce DEFAULT_REPO_FORMAT prereqPatrick Steinhardt, Dec 29, 2023
  49. 02/12 worktree: skip reading HEAD when repairing worktreesPatrick Steinhardt, Dec 29, 2023
  50. 03/12 refs: refactor logic to look up storage backendsPatrick Steinhardt, Dec 29, 2023
  51. 04/12 setup: start tracking ref storage formatPatrick Steinhardt, Dec 29, 2023
  52. 05/12 setup: set repository's formats on initPatrick Steinhardt, Dec 29, 2023
  53. 06/12 setup: introduce "extensions.refStorage" extensionPatrick Steinhardt, Dec 29, 2023
  54. 07/12 setup: introduce GIT_DEFAULT_REF_FORMAT envvarPatrick Steinhardt, Dec 29, 2023
  55. 08/12 t: introduce GIT_TEST_DEFAULT_REF_FORMAT envvarPatrick Steinhardt, Dec 29, 2023
  56. 09/12 builtin/rev-parse: introduce `--show-ref-format` flagPatrick Steinhardt, Dec 29, 2023
  57. 10/12 builtin/init: introduce `--ref-format=` value flagPatrick Steinhardt, Dec 29, 2023
  58. 11/12 builtin/clone: introduce `--ref-format=` value flagPatrick Steinhardt, Dec 29, 2023
  59. 12/12 t9500: write "extensions.refstorage" into configPatrick Steinhardt, Dec 29, 2023
  60. Eric SunshineDec 29, 2023

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.