Commit f623cf89 by Edward Thomson Committed by GitHub

Merge pull request #4163 from pks-t/pks/submodules-with-worktrees

Worktree fixes
parents 6fd6c678 b0c9bc92
...@@ -44,6 +44,18 @@ GIT_EXTERN(int) git_worktree_list(git_strarray *out, git_repository *repo); ...@@ -44,6 +44,18 @@ GIT_EXTERN(int) git_worktree_list(git_strarray *out, git_repository *repo);
GIT_EXTERN(int) git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name); GIT_EXTERN(int) git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name);
/** /**
* Open a worktree of a given repository
*
* If a repository is not the main tree but a worktree, this
* function will look up the worktree inside the parent
* repository and create a new `git_worktree` structure.
*
* @param out Out-pointer for the newly allocated worktree
* @param repo Repository to look up worktree for
*/
GIT_EXTERN(int) git_worktree_open_from_repository(git_worktree **out, git_repository *repo);
/**
* Free a previously allocated worktree * Free a previously allocated worktree
* *
* @param wt worktree handle to close. If NULL nothing occurs. * @param wt worktree handle to close. If NULL nothing occurs.
......
...@@ -739,6 +739,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * ...@@ -739,6 +739,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
{ {
int error, filebuf_flags; int error, filebuf_flags;
git_buf ref_path = GIT_BUF_INIT; git_buf ref_path = GIT_BUF_INIT;
const char *basedir;
assert(file && backend && name); assert(file && backend && name);
...@@ -747,13 +748,18 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * ...@@ -747,13 +748,18 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
return GIT_EINVALIDSPEC; return GIT_EINVALIDSPEC;
} }
if (is_per_worktree_ref(name))
basedir = backend->gitpath;
else
basedir = backend->commonpath;
/* Remove a possibly existing empty directory hierarchy /* Remove a possibly existing empty directory hierarchy
* which name would collide with the reference name * which name would collide with the reference name
*/ */
if ((error = git_futils_rmdir_r(name, backend->gitpath, GIT_RMDIR_SKIP_NONEMPTY)) < 0) if ((error = git_futils_rmdir_r(name, basedir, GIT_RMDIR_SKIP_NONEMPTY)) < 0)
return error; return error;
if (git_buf_joinpath(&ref_path, backend->gitpath, name) < 0) if (git_buf_joinpath(&ref_path, basedir, name) < 0)
return -1; return -1;
filebuf_flags = GIT_FILEBUF_FORCE; filebuf_flags = GIT_FILEBUF_FORCE;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "iterator.h" #include "iterator.h"
#include "path.h" #include "path.h"
#include "index.h" #include "index.h"
#include "worktree.h"
#define GIT_MODULES_FILE ".gitmodules" #define GIT_MODULES_FILE ".gitmodules"
...@@ -2038,17 +2039,28 @@ static int lookup_default_remote(git_remote **remote, git_repository *repo) ...@@ -2038,17 +2039,28 @@ static int lookup_default_remote(git_remote **remote, git_repository *repo)
static int get_url_base(git_buf *url, git_repository *repo) static int get_url_base(git_buf *url, git_repository *repo)
{ {
int error; int error;
git_worktree *wt = NULL;
git_remote *remote = NULL; git_remote *remote = NULL;
if (!(error = lookup_default_remote(&remote, repo))) { if ((error = lookup_default_remote(&remote, repo)) == 0) {
error = git_buf_sets(url, git_remote_url(remote)); error = git_buf_sets(url, git_remote_url(remote));
git_remote_free(remote); goto out;
} } else if (error != GIT_ENOTFOUND)
else if (error == GIT_ENOTFOUND) { goto out;
/* if repository does not have a default remote, use workdir instead */ else
giterr_clear(); giterr_clear();
/* if repository does not have a default remote, use workdir instead */
if (git_repository_is_worktree(repo)) {
if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
goto out;
error = git_buf_sets(url, wt->parent_path);
} else
error = git_buf_sets(url, git_repository_workdir(repo)); error = git_buf_sets(url, git_repository_workdir(repo));
}
out:
git_remote_free(remote);
git_worktree_free(wt);
return error; return error;
} }
......
...@@ -14,11 +14,20 @@ ...@@ -14,11 +14,20 @@
#include "repository.h" #include "repository.h"
#include "worktree.h" #include "worktree.h"
static bool is_worktree_dir(git_buf *dir) static bool is_worktree_dir(const char *dir)
{ {
return git_path_contains_file(dir, "commondir") git_buf buf = GIT_BUF_INIT;
&& git_path_contains_file(dir, "gitdir") int error;
&& git_path_contains_file(dir, "HEAD");
if (git_buf_sets(&buf, dir) < 0)
return -1;
error = git_path_contains_file(&buf, "commondir")
&& git_path_contains_file(&buf, "gitdir")
&& git_path_contains_file(&buf, "HEAD");
git_buf_free(&buf);
return error;
} }
int git_worktree_list(git_strarray *wts, git_repository *repo) int git_worktree_list(git_strarray *wts, git_repository *repo)
...@@ -47,7 +56,7 @@ int git_worktree_list(git_strarray *wts, git_repository *repo) ...@@ -47,7 +56,7 @@ int git_worktree_list(git_strarray *wts, git_repository *repo)
git_buf_truncate(&path, len); git_buf_truncate(&path, len);
git_buf_puts(&path, worktree); git_buf_puts(&path, worktree);
if (!is_worktree_dir(&path)) { if (!is_worktree_dir(path.ptr)) {
git_vector_remove(&worktrees, i); git_vector_remove(&worktrees, i);
git__free(worktree); git__free(worktree);
} }
...@@ -112,6 +121,46 @@ out: ...@@ -112,6 +121,46 @@ out:
return err; return err;
} }
static int open_worktree_dir(git_worktree **out, const char *parent, const char *dir, const char *name)
{
git_buf gitdir = GIT_BUF_INIT;
git_worktree *wt = NULL;
int error = 0;
if (!is_worktree_dir(dir)) {
error = -1;
goto out;
}
if ((wt = git__calloc(1, sizeof(struct git_repository))) == NULL) {
error = -1;
goto out;
}
if ((wt->name = git__strdup(name)) == NULL
|| (wt->commondir_path = git_worktree__read_link(dir, "commondir")) == NULL
|| (wt->gitlink_path = git_worktree__read_link(dir, "gitdir")) == NULL
|| (wt->parent_path = git__strdup(parent)) == NULL) {
error = -1;
goto out;
}
if ((error = git_path_prettify_dir(&gitdir, dir, NULL)) < 0)
goto out;
wt->gitdir_path = git_buf_detach(&gitdir);
wt->locked = !!git_worktree_is_locked(NULL, wt);
*out = wt;
out:
if (error)
git_worktree_free(wt);
git_buf_free(&gitdir);
return error;
}
int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name) int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name)
{ {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
...@@ -125,33 +174,47 @@ int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *na ...@@ -125,33 +174,47 @@ int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *na
if ((error = git_buf_printf(&path, "%s/worktrees/%s", repo->commondir, name)) < 0) if ((error = git_buf_printf(&path, "%s/worktrees/%s", repo->commondir, name)) < 0)
goto out; goto out;
if (!is_worktree_dir(&path)) { if ((error = (open_worktree_dir(out, git_repository_workdir(repo), path.ptr, name))) < 0)
error = -1;
goto out; goto out;
}
if ((wt = git__malloc(sizeof(struct git_repository))) == NULL) { out:
git_buf_free(&path);
if (error)
git_worktree_free(wt);
return error;
}
int git_worktree_open_from_repository(git_worktree **out, git_repository *repo)
{
git_buf parent = GIT_BUF_INIT;
const char *gitdir, *commondir;
char *name = NULL;
int error = 0;
if (!git_repository_is_worktree(repo)) {
giterr_set(GITERR_WORKTREE, "cannot open worktree of a non-worktree repo");
error = -1; error = -1;
goto out; goto out;
} }
if ((wt->name = git__strdup(name)) == NULL gitdir = git_repository_path(repo);
|| (wt->commondir_path = git_worktree__read_link(path.ptr, "commondir")) == NULL commondir = git_repository_commondir(repo);
|| (wt->gitlink_path = git_worktree__read_link(path.ptr, "gitdir")) == NULL
|| (wt->parent_path = git__strdup(git_repository_path(repo))) == NULL) { if ((error = git_path_prettify_dir(&parent, "..", commondir)) < 0)
error = -1;
goto out; goto out;
}
wt->gitdir_path = git_buf_detach(&path);
wt->locked = !!git_worktree_is_locked(NULL, wt);
(*out) = wt; /* The name is defined by the last component in '.git/worktree/%s' */
name = git_path_basename(gitdir);
out: if ((error = open_worktree_dir(out, parent.ptr, gitdir, name)) < 0)
git_buf_free(&path); goto out;
out:
if (error) if (error)
git_worktree_free(wt); free(name);
git_buf_free(&parent);
return error; return error;
} }
...@@ -177,7 +240,7 @@ int git_worktree_validate(const git_worktree *wt) ...@@ -177,7 +240,7 @@ int git_worktree_validate(const git_worktree *wt)
assert(wt); assert(wt);
git_buf_puts(&buf, wt->gitdir_path); git_buf_puts(&buf, wt->gitdir_path);
if (!is_worktree_dir(&buf)) { if (!is_worktree_dir(buf.ptr)) {
giterr_set(GITERR_WORKTREE, giterr_set(GITERR_WORKTREE,
"Worktree gitdir ('%s') is not valid", "Worktree gitdir ('%s') is not valid",
wt->gitlink_path); wt->gitlink_path);
...@@ -209,7 +272,7 @@ out: ...@@ -209,7 +272,7 @@ out:
int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *worktree) int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *worktree)
{ {
git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT; git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT, buf = GIT_BUF_INIT;
git_reference *ref = NULL, *head = NULL; git_reference *ref = NULL, *head = NULL;
git_commit *commit = NULL; git_commit *commit = NULL;
git_repository *wt = NULL; git_repository *wt = NULL;
...@@ -220,35 +283,39 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, ...@@ -220,35 +283,39 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name,
*out = NULL; *out = NULL;
/* Create worktree related files in commondir */ /* Create gitdir directory ".git/worktrees/<name>" */
if ((err = git_buf_joinpath(&path, repo->commondir, "worktrees")) < 0) if ((err = git_buf_joinpath(&gitdir, repo->commondir, "worktrees")) < 0)
goto out; goto out;
if (!git_path_exists(path.ptr)) if (!git_path_exists(gitdir.ptr))
if ((err = git_futils_mkdir(path.ptr, 0755, GIT_MKDIR_EXCL)) < 0) if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0)
goto out;
if ((err = git_buf_joinpath(&gitdir, gitdir.ptr, name)) < 0)
goto out; goto out;
if ((err = git_buf_joinpath(&path, path.ptr, name)) < 0) if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0)
goto out; goto out;
if ((err = git_futils_mkdir(path.ptr, 0755, GIT_MKDIR_EXCL)) < 0) if ((err = git_path_prettify_dir(&gitdir, gitdir.ptr, NULL)) < 0)
goto out; goto out;
/* Create worktree work dir */ /* Create worktree work dir */
if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0) if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0)
goto out; goto out;
if ((err = git_path_prettify_dir(&wddir, worktree, NULL)) < 0)
goto out;
/* Create worktree .git file */ /* Create worktree .git file */
if ((err = git_buf_printf(&buf, "gitdir: %s\n", path.ptr)) < 0) if ((err = git_buf_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0)
goto out; goto out;
if ((err = write_wtfile(worktree, ".git", &buf)) < 0) if ((err = write_wtfile(wddir.ptr, ".git", &buf)) < 0)
goto out; goto out;
/* Create commondir files */ /* Create gitdir files */
if ((err = git_buf_sets(&buf, repo->commondir)) < 0 if ((err = git_path_prettify_dir(&buf, repo->commondir, NULL) < 0)
|| (err = git_buf_putc(&buf, '\n')) < 0 || (err = git_buf_putc(&buf, '\n')) < 0
|| (err = write_wtfile(path.ptr, "commondir", &buf)) < 0) || (err = write_wtfile(gitdir.ptr, "commondir", &buf)) < 0)
goto out; goto out;
if ((err = git_buf_joinpath(&buf, worktree, ".git")) < 0 if ((err = git_buf_joinpath(&buf, wddir.ptr, ".git")) < 0
|| (err = git_buf_putc(&buf, '\n')) < 0 || (err = git_buf_putc(&buf, '\n')) < 0
|| (err = write_wtfile(path.ptr, "gitdir", &buf)) < 0) || (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0)
goto out; goto out;
/* Create new branch */ /* Create new branch */
...@@ -260,9 +327,9 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, ...@@ -260,9 +327,9 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name,
goto out; goto out;
/* Set worktree's HEAD */ /* Set worktree's HEAD */
if ((err = git_repository_create_head(path.ptr, name)) < 0) if ((err = git_repository_create_head(gitdir.ptr, git_reference_name(ref))) < 0)
goto out; goto out;
if ((err = git_repository_open(&wt, worktree)) < 0) if ((err = git_repository_open(&wt, wddir.ptr)) < 0)
goto out; goto out;
/* Checkout worktree's HEAD */ /* Checkout worktree's HEAD */
...@@ -275,7 +342,8 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, ...@@ -275,7 +342,8 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name,
goto out; goto out;
out: out:
git_buf_free(&path); git_buf_free(&gitdir);
git_buf_free(&wddir);
git_buf_free(&buf); git_buf_free(&buf);
git_reference_free(ref); git_reference_free(ref);
git_reference_free(head); git_reference_free(head);
...@@ -394,7 +462,7 @@ int git_worktree_prune(git_worktree *wt, unsigned flags) ...@@ -394,7 +462,7 @@ int git_worktree_prune(git_worktree *wt, unsigned flags)
} }
/* Delete gitdir in parent repository */ /* Delete gitdir in parent repository */
if ((err = git_buf_printf(&path, "%s/worktrees/%s", wt->parent_path, wt->name)) < 0) if ((err = git_buf_printf(&path, "%s/worktrees/%s", wt->commondir_path, wt->name)) < 0)
goto out; goto out;
if (!git_path_exists(path.ptr)) if (!git_path_exists(path.ptr))
{ {
......
...@@ -24,7 +24,7 @@ struct git_worktree { ...@@ -24,7 +24,7 @@ struct git_worktree {
/* Path to the common directory contained in the parent /* Path to the common directory contained in the parent
* repository */ * repository */
char *commondir_path; char *commondir_path;
/* Path to the parent's .git directory */ /* Path to the parent's working directory */
char *parent_path; char *parent_path;
int locked:1; int locked:1;
......
...@@ -4,9 +4,6 @@ ...@@ -4,9 +4,6 @@
bare = false bare = false
logallrefupdates = true logallrefupdates = true
ignorecase = true ignorecase = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = /Users/rb/src/libgit2/tests/resources/testrepo.git
[branch "master"] [branch "master"]
remote = origin remote = origin
merge = refs/heads/master merge = refs/heads/master
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "repository.h" #include "repository.h"
#include "worktree.h"
#include "worktree_helpers.h" #include "worktree_helpers.h"
#define WORKTREE_PARENT "submodules-worktree-parent"
#define WORKTREE_CHILD "submodules-worktree-child"
#define COMMON_REPO "testrepo" #define COMMON_REPO "testrepo"
#define WORKTREE_REPO "testrepo-worktree" #define WORKTREE_REPO "testrepo-worktree"
static worktree_fixture fixture =
WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
static void assert_worktree_valid(git_repository *wt, const char *parentdir, const char *wtdir) static void assert_worktree_valid(git_repository *wt, const char *parentdir, const char *wtdir)
{ {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
...@@ -34,56 +35,46 @@ static void assert_worktree_valid(git_repository *wt, const char *parentdir, con ...@@ -34,56 +35,46 @@ static void assert_worktree_valid(git_repository *wt, const char *parentdir, con
git_buf_free(&path); git_buf_free(&path);
} }
void test_worktree_open__repository(void) void test_worktree_open__initialize(void)
{ {
worktree_fixture fixture =
WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
setup_fixture_worktree(&fixture); setup_fixture_worktree(&fixture);
}
assert_worktree_valid(fixture.worktree, COMMON_REPO, WORKTREE_REPO); void test_worktree_open__cleanup(void)
{
cleanup_fixture_worktree(&fixture); cleanup_fixture_worktree(&fixture);
} }
void test_worktree_open__repository(void)
{
assert_worktree_valid(fixture.worktree, COMMON_REPO, WORKTREE_REPO);
}
void test_worktree_open__repository_through_workdir(void) void test_worktree_open__repository_through_workdir(void)
{ {
worktree_fixture fixture =
WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
git_repository *wt; git_repository *wt;
setup_fixture_worktree(&fixture);
cl_git_pass(git_repository_open(&wt, WORKTREE_REPO)); cl_git_pass(git_repository_open(&wt, WORKTREE_REPO));
assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO);
git_repository_free(wt); git_repository_free(wt);
cleanup_fixture_worktree(&fixture);
} }
void test_worktree_open__repository_through_gitlink(void) void test_worktree_open__repository_through_gitlink(void)
{ {
worktree_fixture fixture =
WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
git_repository *wt; git_repository *wt;
setup_fixture_worktree(&fixture);
cl_git_pass(git_repository_open(&wt, WORKTREE_REPO "/.git")); cl_git_pass(git_repository_open(&wt, WORKTREE_REPO "/.git"));
assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO); assert_worktree_valid(wt, COMMON_REPO, WORKTREE_REPO);
git_repository_free(wt); git_repository_free(wt);
cleanup_fixture_worktree(&fixture);
} }
void test_worktree_open__repository_through_gitdir(void) void test_worktree_open__repository_through_gitdir(void)
{ {
worktree_fixture fixture =
WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
git_buf gitdir_path = GIT_BUF_INIT; git_buf gitdir_path = GIT_BUF_INIT;
git_repository *wt; git_repository *wt;
setup_fixture_worktree(&fixture);
cl_git_pass(git_buf_joinpath(&gitdir_path, COMMON_REPO, ".git")); cl_git_pass(git_buf_joinpath(&gitdir_path, COMMON_REPO, ".git"));
cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "worktrees")); cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "worktrees"));
cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "testrepo-worktree")); cl_git_pass(git_buf_joinpath(&gitdir_path, gitdir_path.ptr, "testrepo-worktree"));
...@@ -93,18 +84,13 @@ void test_worktree_open__repository_through_gitdir(void) ...@@ -93,18 +84,13 @@ void test_worktree_open__repository_through_gitdir(void)
git_buf_free(&gitdir_path); git_buf_free(&gitdir_path);
git_repository_free(wt); git_repository_free(wt);
cleanup_fixture_worktree(&fixture);
} }
void test_worktree_open__open_discovered_worktree(void) void test_worktree_open__open_discovered_worktree(void)
{ {
worktree_fixture fixture =
WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
git_repository *repo; git_repository *repo;
setup_fixture_worktree(&fixture);
cl_git_pass(git_repository_discover(&path, cl_git_pass(git_repository_discover(&path,
git_repository_workdir(fixture.worktree), false, NULL)); git_repository_workdir(fixture.worktree), false, NULL));
cl_git_pass(git_repository_open(&repo, path.ptr)); cl_git_pass(git_repository_open(&repo, path.ptr));
...@@ -113,13 +99,14 @@ void test_worktree_open__open_discovered_worktree(void) ...@@ -113,13 +99,14 @@ void test_worktree_open__open_discovered_worktree(void)
git_buf_free(&path); git_buf_free(&path);
git_repository_free(repo); git_repository_free(repo);
cleanup_fixture_worktree(&fixture);
} }
void test_worktree_open__repository_with_nonexistent_parent(void) void test_worktree_open__repository_with_nonexistent_parent(void)
{ {
git_repository *repo; git_repository *repo;
cleanup_fixture_worktree(&fixture);
cl_fixture_sandbox(WORKTREE_REPO); cl_fixture_sandbox(WORKTREE_REPO);
cl_git_pass(p_chdir(WORKTREE_REPO)); cl_git_pass(p_chdir(WORKTREE_REPO));
cl_git_pass(cl_rename(".gitted", ".git")); cl_git_pass(cl_rename(".gitted", ".git"));
...@@ -130,65 +117,27 @@ void test_worktree_open__repository_with_nonexistent_parent(void) ...@@ -130,65 +117,27 @@ void test_worktree_open__repository_with_nonexistent_parent(void)
cl_fixture_cleanup(WORKTREE_REPO); cl_fixture_cleanup(WORKTREE_REPO);
} }
void test_worktree_open__submodule_worktree_parent(void) void test_worktree_open__open_from_repository(void)
{ {
worktree_fixture fixture = git_worktree *opened, *lookedup;
WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT);
setup_fixture_worktree(&fixture);
cl_assert(git_repository_path(fixture.worktree) != NULL); cl_git_pass(git_worktree_open_from_repository(&opened, fixture.worktree));
cl_assert(git_repository_workdir(fixture.worktree) != NULL); cl_git_pass(git_worktree_lookup(&lookedup, fixture.repo, WORKTREE_REPO));
cl_assert(!fixture.repo->is_worktree); cl_assert_equal_s(opened->name, lookedup->name);
cl_assert(fixture.worktree->is_worktree); cl_assert_equal_s(opened->gitdir_path, lookedup->gitdir_path);
cl_assert_equal_s(opened->gitlink_path, lookedup->gitlink_path);
cl_assert_equal_s(opened->parent_path, lookedup->parent_path);
cl_assert_equal_s(opened->commondir_path, lookedup->commondir_path);
cl_assert_equal_i(opened->locked, lookedup->locked);
cleanup_fixture_worktree(&fixture); git_worktree_free(opened);
git_worktree_free(lookedup);
} }
void test_worktree_open__submodule_worktree_child(void) void test_worktree_open__open_from_nonworktree_fails(void)
{ {
worktree_fixture parent_fixture = git_worktree *wt;
WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT);
worktree_fixture child_fixture =
WORKTREE_FIXTURE_INIT(NULL, WORKTREE_CHILD);
setup_fixture_worktree(&parent_fixture);
cl_git_pass(p_rename(
"submodules/testrepo/.gitted",
"submodules/testrepo/.git"));
setup_fixture_worktree(&child_fixture);
cl_assert(!parent_fixture.repo->is_worktree);
cl_assert(parent_fixture.worktree->is_worktree);
cl_assert(child_fixture.worktree->is_worktree);
cleanup_fixture_worktree(&child_fixture);
cleanup_fixture_worktree(&parent_fixture);
}
void test_worktree_open__open_discovered_submodule_worktree(void) cl_git_fail(git_worktree_open_from_repository(&wt, fixture.repo));
{
worktree_fixture parent_fixture =
WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT);
worktree_fixture child_fixture =
WORKTREE_FIXTURE_INIT(NULL, WORKTREE_CHILD);
git_buf path = GIT_BUF_INIT;
git_repository *repo;
setup_fixture_worktree(&parent_fixture);
cl_git_pass(p_rename(
"submodules/testrepo/.gitted",
"submodules/testrepo/.git"));
setup_fixture_worktree(&child_fixture);
cl_git_pass(git_repository_discover(&path,
git_repository_workdir(child_fixture.worktree), false, NULL));
cl_git_pass(git_repository_open(&repo, path.ptr));
cl_assert_equal_s(git_repository_workdir(child_fixture.worktree),
git_repository_workdir(repo));
git_buf_free(&path);
git_repository_free(repo);
cleanup_fixture_worktree(&child_fixture);
cleanup_fixture_worktree(&parent_fixture);
} }
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "path.h"
#include "refs.h"
#include "worktree.h" #include "worktree.h"
#include "worktree_helpers.h" #include "worktree_helpers.h"
...@@ -128,3 +130,27 @@ void test_worktree_refs__delete_succeeds_after_pruning_worktree(void) ...@@ -128,3 +130,27 @@ void test_worktree_refs__delete_succeeds_after_pruning_worktree(void)
cl_git_pass(git_branch_delete(branch)); cl_git_pass(git_branch_delete(branch));
git_reference_free(branch); git_reference_free(branch);
} }
void test_worktree_refs__creating_refs_uses_commondir(void)
{
git_reference *head, *branch, *lookup;
git_commit *commit;
git_buf refpath = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&refpath,
git_repository_commondir(fixture.worktree), "refs/heads/testbranch"));
cl_assert(!git_path_exists(refpath.ptr));
cl_git_pass(git_repository_head(&head, fixture.worktree));
cl_git_pass(git_commit_lookup(&commit, fixture.worktree, git_reference_target(head)));
cl_git_pass(git_branch_create(&branch, fixture.worktree, "testbranch", commit, 0));
cl_git_pass(git_branch_lookup(&lookup, fixture.worktree, "testbranch", GIT_BRANCH_LOCAL));
cl_assert(git_reference_cmp(branch, lookup) == 0);
cl_assert(git_path_exists(refpath.ptr));
git_reference_free(lookup);
git_reference_free(branch);
git_reference_free(head);
git_commit_free(commit);
git_buf_free(&refpath);
}
#include "clar_libgit2.h"
#include "repository.h"
#include "worktree.h"
#include "worktree_helpers.h"
#define WORKTREE_PARENT "submodules-worktree-parent"
#define WORKTREE_CHILD "submodules-worktree-child"
static worktree_fixture parent
= WORKTREE_FIXTURE_INIT("submodules", WORKTREE_PARENT);
static worktree_fixture child
= WORKTREE_FIXTURE_INIT(NULL, WORKTREE_CHILD);
void test_worktree_submodule__initialize(void)
{
setup_fixture_worktree(&parent);
cl_git_pass(p_rename(
"submodules/testrepo/.gitted",
"submodules/testrepo/.git"));
setup_fixture_worktree(&child);
}
void test_worktree_submodule__cleanup(void)
{
cleanup_fixture_worktree(&child);
cleanup_fixture_worktree(&parent);
}
void test_worktree_submodule__submodule_worktree_parent(void)
{
cl_assert(git_repository_path(parent.worktree) != NULL);
cl_assert(git_repository_workdir(parent.worktree) != NULL);
cl_assert(!parent.repo->is_worktree);
cl_assert(parent.worktree->is_worktree);
}
void test_worktree_submodule__submodule_worktree_child(void)
{
cl_assert(!parent.repo->is_worktree);
cl_assert(parent.worktree->is_worktree);
cl_assert(child.worktree->is_worktree);
}
void test_worktree_submodule__open_discovered_submodule_worktree(void)
{
git_buf path = GIT_BUF_INIT;
git_repository *repo;
cl_git_pass(git_repository_discover(&path,
git_repository_workdir(child.worktree), false, NULL));
cl_git_pass(git_repository_open(&repo, path.ptr));
cl_assert_equal_s(git_repository_workdir(child.worktree),
git_repository_workdir(repo));
git_buf_free(&path);
git_repository_free(repo);
}
void test_worktree_submodule__resolve_relative_url(void)
{
git_buf wt_path = GIT_BUF_INIT;
git_buf sm_relative_path = GIT_BUF_INIT, wt_relative_path = GIT_BUF_INIT;
git_repository *repo;
git_worktree *wt;
cl_git_pass(git_futils_mkdir("subdir", 0755, GIT_MKDIR_PATH));
cl_git_pass(git_path_prettify_dir(&wt_path, "subdir", NULL));
cl_git_pass(git_buf_joinpath(&wt_path, wt_path.ptr, "wt"));
/* Open child repository, which is a submodule */
cl_git_pass(git_repository_open(&child.repo, WORKTREE_CHILD));
/* Create worktree of submodule repository */
cl_git_pass(git_worktree_add(&wt, child.repo, "subdir", wt_path.ptr));
cl_git_pass(git_repository_open_from_worktree(&repo, wt));
cl_git_pass(git_submodule_resolve_url(&sm_relative_path, repo,
"../" WORKTREE_CHILD));
cl_git_pass(git_submodule_resolve_url(&wt_relative_path, child.repo,
"../" WORKTREE_CHILD));
cl_assert_equal_s(sm_relative_path.ptr, wt_relative_path.ptr);
git_worktree_free(wt);
git_repository_free(repo);
git_buf_free(&wt_path);
git_buf_free(&sm_relative_path);
git_buf_free(&wt_relative_path);
}
...@@ -115,11 +115,12 @@ void test_worktree_worktree__lookup(void) ...@@ -115,11 +115,12 @@ void test_worktree_worktree__lookup(void)
cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
git_buf_printf(&gitdir_path, "%s/worktrees/%s", fixture.repo->commondir, "testrepo-worktree"); cl_git_pass(git_buf_joinpath(&gitdir_path, fixture.repo->commondir, "worktrees/testrepo-worktree/"));
cl_assert_equal_s(wt->gitdir_path, gitdir_path.ptr); cl_assert_equal_s(wt->gitdir_path, gitdir_path.ptr);
cl_assert_equal_s(wt->parent_path, fixture.repo->gitdir); cl_assert_equal_s(wt->parent_path, fixture.repo->workdir);
cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink); cl_assert_equal_s(wt->gitlink_path, fixture.worktree->gitlink);
cl_assert_equal_s(wt->commondir_path, fixture.repo->gitdir);
cl_assert_equal_s(wt->commondir_path, fixture.repo->commondir); cl_assert_equal_s(wt->commondir_path, fixture.repo->commondir);
git_buf_free(&gitdir_path); git_buf_free(&gitdir_path);
...@@ -305,7 +306,9 @@ void test_worktree_worktree__init_submodule(void) ...@@ -305,7 +306,9 @@ void test_worktree_worktree__init_submodule(void)
cl_git_pass(git_worktree_add(&worktree, sm, "repo-worktree", path.ptr)); cl_git_pass(git_worktree_add(&worktree, sm, "repo-worktree", path.ptr));
cl_git_pass(git_repository_open_from_worktree(&wt, worktree)); cl_git_pass(git_repository_open_from_worktree(&wt, worktree));
cl_git_pass(git_path_prettify_dir(&path, path.ptr, NULL));
cl_assert_equal_s(path.ptr, wt->workdir); cl_assert_equal_s(path.ptr, wt->workdir);
cl_git_pass(git_path_prettify_dir(&path, sm->commondir, NULL));
cl_assert_equal_s(sm->commondir, wt->commondir); cl_assert_equal_s(sm->commondir, wt->commondir);
cl_git_pass(git_buf_joinpath(&path, sm->gitdir, "worktrees/repo-worktree/")); cl_git_pass(git_buf_joinpath(&path, sm->gitdir, "worktrees/repo-worktree/"));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment