repository: retrieve worktree HEAD via refdb The function `git_repository_head_for_worktree` currently uses `git_reference__read_head` to directly read a given worktree's HEAD from the filesystem. This is broken in case the repository uses a different refdb implementation than the filesystem-based one, so let's instead open the worktree as a real repository and use `git_reference_lookup`. This also fixes the case where the worktree's HEAD is not a symref, but a detached HEAD, which would have resulted in an error previously.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
diff --git a/src/repository.c b/src/repository.c
index 89d8ab1..ebb9daa 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -2177,12 +2177,6 @@ int git_repository_head_detached(git_repository *repo)
return exists;
}
-static int get_worktree_file_path(git_buf *out, git_repository *repo, const char *worktree, const char *file)
-{
- git_buf_clear(out);
- return git_buf_printf(out, "%s/worktrees/%s/%s", repo->commondir, worktree, file);
-}
-
int git_repository_head_detached_for_worktree(git_repository *repo, const char *name)
{
git_reference *ref = NULL;
@@ -2223,7 +2217,8 @@ int git_repository_head(git_reference **head_out, git_repository *repo)
int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name)
{
- git_buf path = GIT_BUF_INIT;
+ git_repository *worktree_repo = NULL;
+ git_worktree *worktree = NULL;
git_reference *head = NULL;
int error;
@@ -2231,26 +2226,23 @@ int git_repository_head_for_worktree(git_reference **out, git_repository *repo,
*out = NULL;
- if ((error = get_worktree_file_path(&path, repo, name, GIT_HEAD_FILE)) < 0 ||
- (error = git_reference__read_head(&head, repo, path.ptr)) < 0)
+ if ((error = git_worktree_lookup(&worktree, repo, name)) < 0 ||
+ (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0 ||
+ (error = git_reference_lookup(&head, worktree_repo, GIT_HEAD_FILE)) < 0)
goto out;
if (git_reference_type(head) != GIT_REFERENCE_DIRECT) {
- git_reference *resolved;
-
- error = git_reference_lookup_resolved(&resolved, repo, git_reference_symbolic_target(head), -1);
- git_reference_free(head);
- head = resolved;
+ if ((error = git_reference_lookup_resolved(out, worktree_repo, git_reference_symbolic_target(head), -1)) < 0)
+ goto out;
+ } else {
+ *out = head;
+ head = NULL;
}
- *out = head;
-
out:
- if (error)
- git_reference_free(head);
-
- git_buf_dispose(&path);
-
+ git_reference_free(head);
+ git_worktree_free(worktree);
+ git_repository_free(worktree_repo);
return error;
}
diff --git a/tests/worktree/repository.c b/tests/worktree/repository.c
index ca56413..c4eeadd 100644
--- a/tests/worktree/repository.c
+++ b/tests/worktree/repository.c
@@ -50,9 +50,12 @@ void test_worktree_repository__head_detached(void)
cl_assert(git_repository_head_detached(fixture.worktree));
cl_assert(git_repository_head_detached_for_worktree(fixture.repo, "testrepo-worktree"));
- cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree"));
+ cl_git_pass(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree"));
+
+ cl_assert_equal_oid(&ref->target.oid, &head->target.oid);
git_reference_free(ref);
+ git_reference_free(head);
}
void test_worktree_repository__head_detached_fails_for_invalid_worktree(void)