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 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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
diff --git a/src/repository.c b/src/repository.c
index 5e818fb..6c73703 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -2254,6 +2254,51 @@ out:
return error;
}
+int git_repository_foreach_worktree(git_repository *repo,
+ git_repository_foreach_worktree_cb cb,
+ void *payload)
+{
+ git_strarray worktrees = {0};
+ git_repository *worktree_repo = NULL;
+ git_worktree *worktree = NULL;
+ int error;
+ size_t i;
+
+ if ((error = git_repository_open(&worktree_repo, repo->commondir)) < 0 ||
+ (error = cb(worktree_repo, payload) != 0))
+ goto out;
+
+ git_repository_free(worktree_repo);
+ worktree_repo = NULL;
+
+ if ((error = git_worktree_list(&worktrees, repo)) < 0)
+ goto out;
+
+ for (i = 0; i < worktrees.count; i++) {
+ git_repository_free(worktree_repo);
+ worktree_repo = NULL;
+ git_worktree_free(worktree);
+ worktree = NULL;
+
+ if ((error = git_worktree_lookup(&worktree, repo, worktrees.strings[i]) < 0) ||
+ (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0) {
+ if (error != GIT_ENOTFOUND)
+ goto out;
+ error = 0;
+ continue;
+ }
+
+ if ((error = cb(worktree_repo, payload)) != 0)
+ goto out;
+ }
+
+out:
+ git_strarray_dispose(&worktrees);
+ git_repository_free(worktree_repo);
+ git_worktree_free(worktree);
+ return error;
+}
+
int git_repository_foreach_head(git_repository *repo,
git_repository_foreach_head_cb cb,
int flags, void *payload)
diff --git a/src/repository.h b/src/repository.h
index bafdb58..a823bdc 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -166,6 +166,12 @@ GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo)
int git_repository_head_tree(git_tree **tree, git_repository *repo);
int git_repository_create_head(const char *git_dir, const char *ref_name);
+typedef int (*git_repository_foreach_worktree_cb)(git_repository *, void *);
+
+int git_repository_foreach_worktree(git_repository *repo,
+ git_repository_foreach_worktree_cb cb,
+ void *payload);
+
/*
* Called for each HEAD.
*
diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c
index 716d0aa..a08c305 100644
--- a/tests/worktree/worktree.c
+++ b/tests/worktree/worktree.c
@@ -623,3 +623,33 @@ void test_worktree_worktree__foreach_head_gives_same_results_in_wt_and_repo(void
git_vector_free(&repo_refs);
git_vector_free(&worktree_refs);
}
+
+static int foreach_worktree_cb(git_repository *worktree, void *payload)
+{
+ int *counter = (int *)payload;
+
+ switch (*counter) {
+ case 0:
+ cl_assert_equal_s(git_repository_path(fixture.repo),
+ git_repository_path(worktree));
+ cl_assert(!git_repository_is_worktree(worktree));
+ break;
+ case 1:
+ cl_assert_equal_s(git_repository_path(fixture.worktree),
+ git_repository_path(worktree));
+ cl_assert(git_repository_is_worktree(worktree));
+ break;
+ default:
+ cl_fail("more worktrees found than expected");
+ }
+
+ (*counter)++;
+
+ return 0;
+}
+
+void test_worktree_worktree__foreach_worktree_lists_all_worktrees(void)
+{
+ int counter = 0;
+ cl_git_pass(git_repository_foreach_worktree(fixture.repo, foreach_worktree_cb, &counter));
+}