Skip to content

Commit 8c8d726

Browse files
committed
worktree: implement git_repository_open_from_worktree
Add function `git_repository_open_from_worktree`, which allows to open a `git_worktree` as repository.
1 parent d3bc09e commit 8c8d726

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

include/git2/repository.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ GIT_BEGIN_DECL
3535
* @return 0 or an error code
3636
*/
3737
GIT_EXTERN(int) git_repository_open(git_repository **out, const char *path);
38+
/**
39+
* Open working tree as a repository
40+
*
41+
* Open the working directory of the working tree as a normal
42+
* repository that can then be worked on.
43+
*
44+
* @param out Output pointer containing opened repository
45+
* @param wt Working tree to open
46+
* @return 0 or an error code
47+
*/
48+
GIT_EXTERN(int) git_repository_open_from_worktree(git_repository **out, git_worktree *wt);
3849

3950
/**
4051
* Create a "fake" repository to wrap an object database

src/repository.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "diff_driver.h"
2929
#include "annotated_commit.h"
3030
#include "submodule.h"
31+
#include "worktree.h"
3132

3233
GIT__USE_STRMAP
3334
#include "strmap.h"
@@ -817,6 +818,36 @@ int git_repository_open(git_repository **repo_out, const char *path)
817818
repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL);
818819
}
819820

821+
int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *wt)
822+
{
823+
git_buf path = GIT_BUF_INIT;
824+
git_repository *repo = NULL;
825+
int len, err;
826+
827+
assert(repo_out && wt);
828+
829+
*repo_out = NULL;
830+
len = strlen(wt->gitlink_path);
831+
832+
if (len <= 4 || strcasecmp(wt->gitlink_path + len - 4, ".git")) {
833+
err = -1;
834+
goto out;
835+
}
836+
837+
if ((err = git_buf_set(&path, wt->gitlink_path, len - 4)) < 0)
838+
goto out;
839+
840+
if ((err = git_repository_open(&repo, path.ptr)) < 0)
841+
goto out;
842+
843+
*repo_out = repo;
844+
845+
out:
846+
git_buf_free(&path);
847+
848+
return err;
849+
}
850+
820851
int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb)
821852
{
822853
git_repository *repo;

tests/worktree/worktree.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,75 @@ void test_worktree_worktree__lookup_nonexistent_worktree(void)
131131
cl_git_fail(git_worktree_lookup(&wt, fixture.repo, "nonexistent"));
132132
cl_assert_equal_p(wt, NULL);
133133
}
134+
135+
void test_worktree_worktree__open(void)
136+
{
137+
git_worktree *wt;
138+
git_repository *repo;
139+
140+
cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
141+
142+
cl_git_pass(git_repository_open_from_worktree(&repo, wt));
143+
cl_assert_equal_s(git_repository_workdir(repo),
144+
git_repository_workdir(fixture.worktree));
145+
146+
git_repository_free(repo);
147+
git_worktree_free(wt);
148+
}
149+
150+
void test_worktree_worktree__open_invalid_commondir(void)
151+
{
152+
git_worktree *wt;
153+
git_repository *repo;
154+
git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
155+
156+
cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/commondir"));
157+
cl_git_pass(git_buf_printf(&path,
158+
"%s/worktrees/testrepo-worktree/commondir",
159+
fixture.repo->commondir));
160+
cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644));
161+
162+
cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
163+
cl_git_fail(git_repository_open_from_worktree(&repo, wt));
164+
165+
git_buf_free(&buf);
166+
git_buf_free(&path);
167+
git_worktree_free(wt);
168+
}
169+
170+
void test_worktree_worktree__open_invalid_gitdir(void)
171+
{
172+
git_worktree *wt;
173+
git_repository *repo;
174+
git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
175+
176+
cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/gitdir"));
177+
cl_git_pass(git_buf_printf(&path,
178+
"%s/worktrees/testrepo-worktree/gitdir",
179+
fixture.repo->commondir));
180+
cl_git_pass(git_futils_writebuffer(&buf, path.ptr, O_RDWR, 0644));
181+
182+
cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
183+
cl_git_fail(git_repository_open_from_worktree(&repo, wt));
184+
185+
git_buf_free(&buf);
186+
git_buf_free(&path);
187+
git_worktree_free(wt);
188+
}
189+
190+
void test_worktree_worktree__open_invalid_parent(void)
191+
{
192+
git_worktree *wt;
193+
git_repository *repo;
194+
git_buf buf = GIT_BUF_INIT;
195+
196+
cl_git_pass(git_buf_sets(&buf, "/path/to/nonexistent/gitdir"));
197+
cl_git_pass(git_futils_writebuffer(&buf,
198+
fixture.worktree->path_gitlink, O_RDWR, 0644));
199+
200+
cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
201+
cl_git_fail(git_repository_open_from_worktree(&repo, wt));
202+
203+
git_buf_free(&buf);
204+
git_worktree_free(wt);
205+
}

0 commit comments

Comments
 (0)