Skip to content

Commit 2fcb4f2

Browse files
committed
repository: introduce new function to iterate over all worktrees
Given a Git repository, it's non-trivial to iterate over all worktrees that are associated with it, including the "main" repository. This commit adds a new internal function `git_repository_foreach_worktree` that does this for us.
1 parent d6c6285 commit 2fcb4f2

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

src/repository.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,6 +2254,51 @@ int git_repository_head_for_worktree(git_reference **out, git_repository *repo,
22542254
return error;
22552255
}
22562256

2257+
int git_repository_foreach_worktree(git_repository *repo,
2258+
git_repository_foreach_worktree_cb cb,
2259+
void *payload)
2260+
{
2261+
git_strarray worktrees = {0};
2262+
git_repository *worktree_repo = NULL;
2263+
git_worktree *worktree = NULL;
2264+
int error;
2265+
size_t i;
2266+
2267+
if ((error = git_repository_open(&worktree_repo, repo->commondir)) < 0 ||
2268+
(error = cb(worktree_repo, payload) != 0))
2269+
goto out;
2270+
2271+
git_repository_free(worktree_repo);
2272+
worktree_repo = NULL;
2273+
2274+
if ((error = git_worktree_list(&worktrees, repo)) < 0)
2275+
goto out;
2276+
2277+
for (i = 0; i < worktrees.count; i++) {
2278+
git_repository_free(worktree_repo);
2279+
worktree_repo = NULL;
2280+
git_worktree_free(worktree);
2281+
worktree = NULL;
2282+
2283+
if ((error = git_worktree_lookup(&worktree, repo, worktrees.strings[i]) < 0) ||
2284+
(error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0) {
2285+
if (error != GIT_ENOTFOUND)
2286+
goto out;
2287+
error = 0;
2288+
continue;
2289+
}
2290+
2291+
if ((error = cb(worktree_repo, payload)) != 0)
2292+
goto out;
2293+
}
2294+
2295+
out:
2296+
git_strarray_dispose(&worktrees);
2297+
git_repository_free(worktree_repo);
2298+
git_worktree_free(worktree);
2299+
return error;
2300+
}
2301+
22572302
int git_repository_foreach_head(git_repository *repo,
22582303
git_repository_foreach_head_cb cb,
22592304
int flags, void *payload)

src/repository.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo)
166166
int git_repository_head_tree(git_tree **tree, git_repository *repo);
167167
int git_repository_create_head(const char *git_dir, const char *ref_name);
168168

169+
typedef int (*git_repository_foreach_worktree_cb)(git_repository *, void *);
170+
171+
int git_repository_foreach_worktree(git_repository *repo,
172+
git_repository_foreach_worktree_cb cb,
173+
void *payload);
174+
169175
/*
170176
* Called for each HEAD.
171177
*

tests/worktree/worktree.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,3 +623,33 @@ void test_worktree_worktree__foreach_head_gives_same_results_in_wt_and_repo(void
623623
git_vector_free(&repo_refs);
624624
git_vector_free(&worktree_refs);
625625
}
626+
627+
static int foreach_worktree_cb(git_repository *worktree, void *payload)
628+
{
629+
int *counter = (int *)payload;
630+
631+
switch (*counter) {
632+
case 0:
633+
cl_assert_equal_s(git_repository_path(fixture.repo),
634+
git_repository_path(worktree));
635+
cl_assert(!git_repository_is_worktree(worktree));
636+
break;
637+
case 1:
638+
cl_assert_equal_s(git_repository_path(fixture.worktree),
639+
git_repository_path(worktree));
640+
cl_assert(git_repository_is_worktree(worktree));
641+
break;
642+
default:
643+
cl_fail("more worktrees found than expected");
644+
}
645+
646+
(*counter)++;
647+
648+
return 0;
649+
}
650+
651+
void test_worktree_worktree__foreach_worktree_lists_all_worktrees(void)
652+
{
653+
int counter = 0;
654+
cl_git_pass(git_repository_foreach_worktree(fixture.repo, foreach_worktree_cb, &counter));
655+
}

0 commit comments

Comments
 (0)