Skip to content

Commit 465a22b

Browse files
pks-tgitster
authored andcommitted
worktree: skip reading HEAD when repairing worktrees
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bb0372c commit 465a22b

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

worktree.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ static void add_head_info(struct worktree *wt)
5151
/**
5252
* get the main worktree
5353
*/
54-
static struct worktree *get_main_worktree(void)
54+
static struct worktree *get_main_worktree(int skip_reading_head)
5555
{
5656
struct worktree *worktree = NULL;
5757
struct strbuf worktree_path = STRBUF_INIT;
@@ -70,11 +70,13 @@ static struct worktree *get_main_worktree(void)
7070
*/
7171
worktree->is_bare = (is_bare_repository_cfg == 1) ||
7272
is_bare_repository();
73-
add_head_info(worktree);
73+
if (!skip_reading_head)
74+
add_head_info(worktree);
7475
return worktree;
7576
}
7677

77-
static struct worktree *get_linked_worktree(const char *id)
78+
static struct worktree *get_linked_worktree(const char *id,
79+
int skip_reading_head)
7880
{
7981
struct worktree *worktree = NULL;
8082
struct strbuf path = STRBUF_INIT;
@@ -93,7 +95,8 @@ static struct worktree *get_linked_worktree(const char *id)
9395
CALLOC_ARRAY(worktree, 1);
9496
worktree->path = strbuf_detach(&worktree_path, NULL);
9597
worktree->id = xstrdup(id);
96-
add_head_info(worktree);
98+
if (!skip_reading_head)
99+
add_head_info(worktree);
97100

98101
done:
99102
strbuf_release(&path);
@@ -118,7 +121,14 @@ static void mark_current_worktree(struct worktree **worktrees)
118121
free(git_dir);
119122
}
120123

121-
struct worktree **get_worktrees(void)
124+
/*
125+
* NEEDSWORK: This function exists so that we can look up metadata of a
126+
* worktree without trying to access any of its internals like the refdb. It
127+
* would be preferable to instead have a corruption-tolerant function for
128+
* retrieving worktree metadata that could be used when the worktree is known
129+
* to not be in a healthy state, e.g. when creating or repairing it.
130+
*/
131+
static struct worktree **get_worktrees_internal(int skip_reading_head)
122132
{
123133
struct worktree **list = NULL;
124134
struct strbuf path = STRBUF_INIT;
@@ -128,7 +138,7 @@ struct worktree **get_worktrees(void)
128138

129139
ALLOC_ARRAY(list, alloc);
130140

131-
list[counter++] = get_main_worktree();
141+
list[counter++] = get_main_worktree(skip_reading_head);
132142

133143
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
134144
dir = opendir(path.buf);
@@ -137,7 +147,7 @@ struct worktree **get_worktrees(void)
137147
while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
138148
struct worktree *linked = NULL;
139149

140-
if ((linked = get_linked_worktree(d->d_name))) {
150+
if ((linked = get_linked_worktree(d->d_name, skip_reading_head))) {
141151
ALLOC_GROW(list, counter + 1, alloc);
142152
list[counter++] = linked;
143153
}
@@ -151,6 +161,11 @@ struct worktree **get_worktrees(void)
151161
return list;
152162
}
153163

164+
struct worktree **get_worktrees(void)
165+
{
166+
return get_worktrees_internal(0);
167+
}
168+
154169
const char *get_worktree_git_dir(const struct worktree *wt)
155170
{
156171
if (!wt)
@@ -591,7 +606,7 @@ static void repair_noop(int iserr UNUSED,
591606

592607
void repair_worktrees(worktree_repair_fn fn, void *cb_data)
593608
{
594-
struct worktree **worktrees = get_worktrees();
609+
struct worktree **worktrees = get_worktrees_internal(1);
595610
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
596611

597612
if (!fn)

0 commit comments

Comments
 (0)