summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2020-06-17 14:09:04 +0200
committerPatrick Steinhardt <ps@pks.im>2020-07-12 18:12:16 +0200
commit2fcb4f2801ef9a1e74b4281a78deae5e25b0ad43 (patch)
tree956f69765ded9973b8453950b02d0b34a05d61a1
parentd6c62852076005053be9169cb4f3cd9cf9db2aea (diff)
downloadlibgit2-2fcb4f2801ef9a1e74b4281a78deae5e25b0ad43.tar.gz
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.
-rw-r--r--src/repository.c45
-rw-r--r--src/repository.h6
-rw-r--r--tests/worktree/worktree.c30
3 files changed, 81 insertions, 0 deletions
diff --git a/src/repository.c b/src/repository.c
index 5e818fb82..6c7370324 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 bafdb5896..a823bdcd9 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 716d0aa0a..a08c305bc 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));
+}