8000 worktree: mimic 'git worktree add' behavior. · libgit2/libgit2@23eee13 · GitHub
[go: up one dir, main page]

Skip to content

Commit 23eee13

Browse files
committed
worktree: mimic 'git worktree add' behavior.
When adding a worktree using 'git worktree add <path>', if a reference named 'refs/heads/$(basename <path>)' already exist, it is checkouted in the worktree. Mimic this behavior in libgit2. Signed-off-by: Gregory Herrero <gregory.herrero@oracle.com>
1 parent 6bd37c3 commit 23eee13

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

src/worktree.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ int git_worktree_add(git_worktree **out, git_repository *repo,
278278
const char *name, const char *worktree,
279279
const git_worktree_add_options *opts)
280280
{
281-
git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT, buf = GIT_BUF_INIT;
281+
git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT;
282+
git_buf buf = GIT_BUF_INIT, ref_buf = GIT_BUF_INIT;
282283
git_reference *ref = NULL, *head = NULL;
283284
git_commit *commit = NULL;
284285
git_repository *wt = NULL;
@@ -365,12 +366,24 @@ int git_worktree_add(git_worktree **out, git_repository *repo,
365366
if ((err = git_reference_dup(&ref, wtopts.ref)) < 0)
366367
goto out;
367368
} else {
368-
if ((err = git_repository_head(&head, repo)) < 0)
369-
goto out;
370-
if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0)
371-
goto out;
372-
if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0)
369+
if ((err = git_buf_printf(&ref_buf, "refs/heads/%s", name)) < 0)
373370
goto out;
371+
if (!git_reference_lookup(&ref, repo, ref_buf.ptr)) {
372+
if (git_branch_is_checked_out(ref)) {
373+
git_error_set(GIT_ERROR_WORKTREE,
374+
"reference %s is already checked out",
375+
ref_buf.ptr);
376+
err = -1;
377+
goto out;
378+
}
379+
} else {
380+
if ((err = git_repository_head(&head, repo)) < 0)
381+
goto out;
382+
if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0)
383+
goto out;
384+
if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0)
385+
goto out;
386+
}
374387
}
375388

376389
/* Set worktree's HEAD */
@@ -392,6 +405,7 @@ int git_worktree_add(git_worktree **out, git_repository *repo,
392405
git_buf_dispose(&gitdir);
393406
git_buf_dispose(&wddir);
394407
git_buf_dispose(&buf);
408+
git_buf_dispose(&ref_buf);
395409
git_reference_free(ref);
396410
git_reference_free(head);
397411
git_commit_free(commit);

tests/worktree/worktree.c

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,48 @@ void test_worktree_worktree__init(void)
216216
git_repository_free(repo);
217217
}
218218

219+
void test_worktree_worktree__add_remove_add(void)
220+
{
221+
git_worktree *wt;
222+
git_repository *repo;
223+
git_reference *branch;
224+
git_buf path = GIT_BUF_INIT;
225+
226+
git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
227+
228+
/* Add the worktree */
229+
cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-add-remove-add"));
230+
cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, NULL));
231+
232+
/* Open and verify created repo */
233+
cl_git_pass(git_repository_open(&repo, path.ptr));
234+
cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-add-remove-add/") == 0);
235+
cl_git_pass(git_branch_lookup(&branch, repo, "worktree-add-remove-add", GIT_BRANCH_LOCAL));
236+
237+
238+
/* Prune the worktree */
239+
opts.flags = GIT_WORKTREE_PRUNE_VALID|GIT_WORKTREE_PRUNE_WORKING_TREE;
240+
cl_git_pass(git_worktree_prune(wt, &opts));
241+
cl_assert(!git_path_exists(wt->gitdir_path));
242+
cl_assert(!git_path_exists(wt->gitlink_path));
243+
git_worktree_free(wt);
244+
245+
/* Add the worktree back */
246+
cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-add-remove-add", path.ptr, NULL));
247+
248+
/* Open and verify created repo */
249+
cl_git_pass(git_repository_open(&repo, path.ptr));
250+
cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-add-remove-add/") == 0);
251+
cl_git_pass(git_branch_lookup(&branch, repo, "worktree-add-remove-add", GIT_BRANCH_LOCAL));
252+
253+
254+
git_buf_dispose(&path);
255+
git_worktree_free(wt);
256+
git_reference_free(branch);
257+
git_repository_free(repo);
258+
}
259+
260+
219261
void test_worktree_worktree__add_locked(void)
220262
{
221263
git_worktree *wt;
@@ -250,12 +292,13 @@ void test_worktree_worktree__init_existing_branch(void)
250292

251293
cl_git_pass(git_repository_head(&head, fixture.repo));
252294
cl_git_pass(git_commit_lookup(&commit, fixture.repo, &head->target.oid));
253-
cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new", commit, false));
295+
cl_git_pass(git_branch_create(&branch, fixture.repo, "worktree-new-exist", commit, false));
254296

255-
cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new"));
256-
cl_git_fail(git_worktree_add(&wt, fixture.repo, "worktree-new", path.ptr, NULL));
297+
cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-new-exist"));
298+
cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-new-exist", path.ptr, NULL));
257299

258300
git_buf_dispose(&path);
301+
git_worktree_free(wt);
259302
git_commit_free(commit);
260303
git_reference_free(head);
261304
git_reference_free(branch);

0 commit comments

Comments
 (0)
0