Skip to content

Commit d3bc09e

Browse files
committed
worktree: introduce struct git_worktree
Introduce a new `struct git_worktree`, which holds information about a possible working tree connected to a repository. Introduce functions to allow opening working trees for a repository.
1 parent 45f2b7a commit d3bc09e

File tree

5 files changed

+167
-1
lines changed

5 files changed

+167
-1
lines changed

include/git2/types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ typedef struct git_refdb_backend git_refdb_backend;
104104
*/
105105
typedef struct git_repository git_repository;
106106

107+
/** Representation of a working tree */
108+
typedef struct git_worktree git_worktree;
109+
107110
/** Representation of a generic object in a repository */
108111
typedef struct git_object git_object;
109112

include/git2/worktree.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ GIT_BEGIN_DECL
3232
*/
3333
GIT_EXTERN(int) git_worktree_list(git_strarray *out, git_repository *repo);
3434

35+
/**
36+
* Lookup a working tree by its name for a given repository
37+
*
38+
* @param out Output pointer to looked up worktree or `NULL`
39+
* @param repo The repository containing worktrees
40+
* @param name Name of the working tree to look up
41+
* @return 0 or an error code
42+
*/
43+
GIT_EXTERN(int) git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name);
44+
45+
/**
46+
* Free a previously allocated worktree
47+
*
48+
* @param wt worktree handle to close. If NULL nothing occurs.
49+
*/
50+
GIT_EXTERN(void) git_worktree_free(git_worktree *wt);
51+
3552
/** @} */
3653
GIT_END_DECL
3754
#endif

src/worktree.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "common.h"
1111
#include "repository.h"
12+
#include "worktree.h"
1213

1314
static bool is_worktree_dir(git_buf *dir)
1415
{
@@ -56,3 +57,91 @@ int git_worktree_list(git_strarray *wts, git_repository *repo)
5657

5758
return error;
5859
}
60+
61+
static char *read_link(const char *base, const char *file)
62+
{
63+
git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT;
64+
65+
assert(base && file);
66+
67+
if (git_buf_joinpath(&path, base, file) < 0)
68+
goto err;
69+
if (git_futils_readbuffer(&buf, path.ptr) < 0)
70+
goto err;
71+
git_buf_free(&path);
72+
73+
git_buf_rtrim(&buf);
74+
75+
if (!git_path_is_relative(buf.ptr))
76+
return git_buf_detach(&buf);
77+
78+
if (git_buf_sets(&path, base) < 0)
79+
goto err;
80+
if (git_path_apply_relative(&path, buf.ptr) < 0)
81+
goto err;
82+
git_buf_free(&buf);
83+
84+
return git_buf_detach(&path);
85+
86+
err:
87+
git_buf_free(&buf);
88+
git_buf_free(&path);
89+
90+
return NULL;
91+
}
92+
93+
int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name)
94+
{
95+
git_buf path = GIT_BUF_INIT;
96+
git_worktree *wt = NULL;
97+
int error;
98+
99+
assert(repo && name);
100+
101+
*out = NULL;
102+
103+
if ((error = git_buf_printf(&path, "%s/worktrees/%s", repo->commondir, name)) < 0)
104+
goto out;
105+
106+
if (!is_worktree_dir(&path)) {
107+
error = -1;
108+
goto out;
109+
}
110+
111+
if ((wt = git__malloc(sizeof(struct git_repository))) == NULL) {
112+
error = -1;
113+
goto out;
114+
}
115+
116+
if ((wt->name = git__strdup(name)) == NULL
117+
|| (wt->commondir_path = read_link(path.ptr, "commondir")) == NULL
118+
|| (wt->gitlink_path = read_link(path.ptr, "gitdir")) == NULL
119+
|| (wt->parent_path = git__strdup(git_repository_path(repo))) == NULL) {
120+
error = -1;
121+
goto out;
122+
}
123+
wt->gitdir_path = git_buf_detach(&path);
124+
125+
(*out) = wt;
126+
127+
out:
128+
git_buf_free(&path);
129+
130+
if (error)
131+
git_worktree_free(wt);
132+
133+
return error;
134+
}
135+
136+
void git_worktree_free(git_worktree *wt)
137+
{
138+
if (!wt)
139+
return;
140+
141+
git__free(wt->commondir_path);
142+
git__free(wt->gitlink_path);
143+
git__free(wt->gitdir_path);
144+
git__free(wt->parent_path);
145+
git__free(wt->name);
146+
git__free(wt);
147+
}

src/worktree.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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_worktree_h__
8+
#define INCLUDE_worktree_h__
9+
10+
#include "git2/common.h"
11+
#include "git2/worktree.h"
12+
13+
struct git_worktree {
14+
/* Name of the working tree. This is the name of the
15+
* containing directory in the `$PARENT/.git/worktrees/`
16+
* directory. */
17+
char *name;
18+
19+
/* Path to the .git file in the working tree's repository */
20+
char *gitlink_path;
21+
/* Path to the .git directory inside the parent's
22+
* worktrees directory */
23+
char *gitdir_path;
24+
/* Path to the common directory contained in the parent
25+
* repository */
26+
char *commondir_path;
27+
/* Path to the parent's .git directory */
28+
char *parent_path;
29+
};
30+
31+
#endif

tests/worktree/worktree.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include "clar_libgit2.h"
22
#include "worktree_helpers.h"
33

4-
#include "git2/worktree.h"
54
#include "repository.h"
5+
#include "worktree.h"
66

77
#define COMMON_REPO "testrepo"
88
#define WORKTREE_REPO "testrepo-worktree"
@@ -105,3 +105,29 @@ void test_worktree_worktree__list_without_worktrees(void)
105105

106106
git_repository_free(repo);
107107
}
108+
109+
void test_worktree_worktree__lookup(void)
110+
{
111+
git_worktree *wt;
112+
git_buf gitdir_path = GIT_BUF_INIT;
113+
114+
cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
115+
116+
git_buf_printf(&gitdir_path, "%s/worktrees/%s", fixture.repo->commondir, "testrepo-worktree");
117+
118+
cl_assert_equal_s(wt->gitdir_path, gitdir_path.ptr);
119+
cl_assert_equal_s(wt->parent_path, fixture.repo->path_repository);
120+
cl_assert_equal_s(wt->gitlink_path, fixture.worktree->path_gitlink);
121+
cl_assert_equal_s(wt->commondir_path, fixture.repo->commondir);
122+
123+
git_buf_free(&gitdir_path);
124+
git_worktree_free(wt);
125+
}
126+
127+
void test_worktree_worktree__lookup_nonexistent_worktree(void)
128+
{
129+
git_worktree *wt;
130+
131+
cl_git_fail(git_worktree_lookup(&wt, fixture.repo, "nonexistent"));
132+
cl_assert_equal_p(wt, NULL);
133+
}

0 commit comments

Comments
 (0)