Skip to content

Commit 45f2b7a

Browse files
committed
worktree: implement git_worktree_list
Add new module for working trees with the `git_worktree_list` function. The function lists names for all working trees of a certain repository.
1 parent 854b5c7 commit 45f2b7a

File tree

3 files changed

+202
-0
lines changed

3 files changed

+202
-0
lines changed

include/git2/worktree.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
#ifndef INCLUDE_git_worktree_h__
8+
#define INCLUDE_git_worktree_h__
9+
10+
#include "common.h"
11+
#include "types.h"
12+
#include "strarray.h"
13+
14+
/**
15+
* @file git2/worktrees.h
16+
* @brief Git worktree related functions
17+
* @defgroup git_commit Git worktree related functions
18+
* @ingroup Git
19+
* @{
20+
*/
21+
GIT_BEGIN_DECL
22+
23+
/**
24+
* List names of linked working trees
25+
*
26+
* The returned list should be released with `git_strarray_free`
27+
* when no longer needed.
28+
*
29+
* @param out pointer to the array of working tree names
30+
* @param repo the repo to use when listing working trees
31+
* @return 0 or an error code
32+
*/
33+
GIT_EXTERN(int) git_worktree_list(git_strarray *out, git_repository *repo);
34+
35+
/** @} */
36+
GIT_END_DECL
37+
#endif

src/worktree.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include "git2/worktree.h"
9+
10+
#include "common.h"
11+
#include "repository.h"
12+
13+
static bool is_worktree_dir(git_buf *dir)
14+
{
15+
return git_path_contains_file(dir, "commondir")
16+
&& git_path_contains_file(dir, "gitdir")
17+
&& git_path_contains_file(dir, "HEAD");
18+
}
19+
20+
int git_worktree_list(git_strarray *wts, git_repository *repo)
21+
{
22+
git_vector worktrees = GIT_VECTOR_INIT;
23+
git_buf path = GIT_BUF_INIT;
24+
char *worktree;
25+
unsigned i, len;
26+
int error;
27+
28+
assert(wts && repo);
29+
30+
wts->count = 0;
31+
wts->strings = NULL;
32+
33+
if ((error = git_buf_printf(&path, "%s/worktrees/", repo->commondir)) < 0)
34+
goto exit;
35+
if (!git_path_exists(path.ptr) || git_path_is_empty_dir(path.ptr))
36+
goto exit;
37+
if ((error = git_path_dirload(&worktrees, path.ptr, path.size, 0x0)) < 0)
38+
goto exit;
39+
40+
len = path.size;
41+
42+
git_vector_foreach(&worktrees, i, worktree) {
43+
git_buf_truncate(&path, len);
44+
git_buf_puts(&path, worktree);
45+
46+
if (!is_worktree_dir(&path)) {
47+
git_vector_remove(&worktrees, i);
48+
git__free(worktree);
49+
}
50+
}
51+
52+
wts->strings = (char **)git_vector_detach(&wts->count, NULL, &worktrees);
53+
54+
exit:
55+
git_buf_free(&path);
56+
57+
return error;
58+
}

tests/worktree/worktree.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include "clar_libgit2.h"
2+
#include "worktree_helpers.h"
3+
4+
#include "git2/worktree.h"
5+
#include "repository.h"
6+
7+
#define COMMON_REPO "testrepo"
8+
#define WORKTREE_REPO "testrepo-worktree"
9+
10+
static worktree_fixture fixture =
11+
WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
12+
13+
void test_worktree_worktree__initialize(void)
14+
{
15+
setup_fixture_worktree(&fixture);
16+
}
17+
18+
void test_worktree_worktree__cleanup(void)
19+
{
20+
cleanup_fixture_worktree(&fixture);
21+
}
22+
23+
void test_worktree_worktree__list(void)
24+
{
25+
git_strarray wts;
26+
27+
cl_git_pass(git_worktree_list(&wts, fixture.repo));
28+
cl_assert_equal_i(wts.count, 1);
29+
cl_assert_equal_s(wts.strings[0], "testrepo-worktree");
30+
31+
git_strarray_free(&wts);
32+
}
33+
34+
void test_worktree_worktree__list_with_invalid_worktree_dirs(void)
35+
{
36+
const char *filesets[3][2] = {
37+
{ "gitdir", "commondir" },
38+
{ "gitdir", "HEAD" },
39+
{ "HEAD", "commondir" },
40+
};
41+
git_buf path = GIT_BUF_INIT;
42+
git_strarray wts;
43+
unsigned i, j, len;
44+
45+
cl_git_pass(git_buf_printf(&path, "%s/worktrees/invalid",
46+
fixture.repo->commondir));
47+
cl_git_pass(p_mkdir(path.ptr, 0755));
48+
49+
len = path.size;
50+
51+
for (i = 0; i < ARRAY_SIZE(filesets); i++) {
52+
53+
for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) {
54+
git_buf_truncate(&path, len);
55+
cl_git_pass(git_buf_joinpath(&path, path.ptr, filesets[i][j]));
56+
cl_git_pass(p_close(p_creat(path.ptr, 0644)));
57+
}
58+
59+
cl_git_pass(git_worktree_list(&wts, fixture.worktree));
60+
cl_assert_equal_i(wts.count, 1);
61+
cl_assert_equal_s(wts.strings[0], "testrepo-worktree");
62+
git_strarray_free(&wts);
63+
64+
for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) {
65+
git_buf_truncate(&path, len);
66+
cl_git_pass(git_buf_joinpath(&path, path.ptr, filesets[i][j]));
67+
p_unlink(path.ptr);
68+
}
69+
}
70+
71+
git_buf_free(&path);
72+
}
73+
74+
void test_worktree_worktree__list_in_worktree_repo(void)
75+
{
76+
git_strarray wts;
77+
78+
cl_git_pass(git_worktree_list(&wts, fixture.worktree));
79+
cl_assert_equal_i(wts.count, 1);
80+
cl_assert_equal_s(wts.strings[0], "testrepo-worktree");
81+
82+
git_strarray_free(&wts);
83+
}
84+
85+
void test_worktree_worktree__list_bare(void)
86+
{
87+
git_repository *repo;
88+
git_strarray wts;
89+
90+
repo = cl_git_sandbox_init("testrepo.git");
91+
cl_git_pass(git_worktree_list(&wts, repo));
92+
cl_assert_equal_i(wts.count, 0);
93+
94+
git_repository_free(repo);
95+
}
96+
97+
void test_worktree_worktree__list_without_worktrees(void)
98+
{
99+
git_repository *repo;
100+
git_strarray wts;
101+
102+
repo = cl_git_sandbox_init("testrepo2");
103+
cl_git_pass(git_worktree_list(&wts, repo));
104+
cl_assert_equal_i(wts.count, 0);
105+
106+
git_repository_free(repo);
107+
}

0 commit comments

Comments
 (0)