summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/repository.c36
-rw-r--r--src/worktree.c6
-rw-r--r--src/worktree.h2
-rw-r--r--tests/worktree/open.c33
-rw-r--r--tests/worktree/worktree.c1
5 files changed, 66 insertions, 12 deletions
diff --git a/src/repository.c b/src/repository.c
index 55724845f..4b937be20 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -61,6 +61,7 @@ static const struct {
static int check_repositoryformatversion(git_config *config);
#define GIT_COMMONDIR_FILE "commondir"
+#define GIT_GITDIR_FILE "gitdir"
#define GIT_FILE_CONTENT_PREFIX "gitdir:"
@@ -275,9 +276,10 @@ static int load_config_data(git_repository *repo, const git_config *config)
static int load_workdir(git_repository *repo, git_config *config, git_buf *parent_path)
{
- int error;
+ int error;
git_config_entry *ce;
- git_buf worktree = GIT_BUF_INIT;
+ git_buf worktree = GIT_BUF_INIT;
+ git_buf path = GIT_BUF_INIT;
if (repo->is_bare)
return 0;
@@ -286,7 +288,24 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren
&ce, config, "core.worktree", false)) < 0)
return error;
- if (ce && ce->value) {
+ if (repo->is_worktree) {
+ char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE);
+ if (!gitlink) {
+ error = -1;
+ goto cleanup;
+ }
+
+ git_buf_attach(&worktree, gitlink, 0);
+
+ if ((git_path_dirname_r(&worktree, worktree.ptr)) < 0 ||
+ git_path_to_dir(&worktree) < 0) {
+ error = -1;
+ goto cleanup;
+ }
+
+ repo->workdir = git_buf_detach(&worktree);
+ }
+ else if (ce && ce->value) {
if ((error = git_path_prettify_dir(
&worktree, ce->value, repo->gitdir)) < 0)
goto cleanup;
@@ -307,6 +326,7 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren
GITERR_CHECK_ALLOC(repo->workdir);
cleanup:
+ git_buf_free(&path);
git_config_entry_free(ce);
return error;
}
@@ -465,6 +485,9 @@ static int find_repo(
git_path_to_dir(&path);
git_buf_set(repo_path, path.ptr, path.size);
+ if (link_path)
+ git_buf_attach(link_path,
+ git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0);
if (common_path)
git_buf_swap(&common_link, common_path);
@@ -775,7 +798,11 @@ int git_repository_open_ext(
GITERR_CHECK_ALLOC(repo->commondir);
}
- if (repo->gitlink && repo->commondir && strcmp(repo->gitlink, repo->commondir))
+ if ((error = git_buf_joinpath(&path, repo->gitdir, "gitdir")) < 0)
+ goto cleanup;
+ /* A 'gitdir' file inside a git directory is currently
+ * only used when the repository is a working tree. */
+ if (git_path_exists(path.ptr))
repo->is_worktree = 1;
/*
@@ -801,6 +828,7 @@ int git_repository_open_ext(
}
cleanup:
+ git_buf_free(&path);
git_buf_free(&parent);
git_config_free(config);
diff --git a/src/worktree.c b/src/worktree.c
index 95a2757fe..a3fe07a23 100644
--- a/src/worktree.c
+++ b/src/worktree.c
@@ -61,7 +61,7 @@ exit:
return error;
}
-static char *read_link(const char *base, const char *file)
+char *git_worktree__read_link(const char *base, const char *file)
{
git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT;
@@ -136,8 +136,8 @@ int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *na
}
if ((wt->name = git__strdup(name)) == NULL
- || (wt->commondir_path = read_link(path.ptr, "commondir")) == NULL
- || (wt->gitlink_path = read_link(path.ptr, "gitdir")) == NULL
+ || (wt->commondir_path = git_worktree__read_link(path.ptr, "commondir")) == NULL
+ || (wt->gitlink_path = git_worktree__read_link(path.ptr, "gitdir")) == NULL
|| (wt->parent_path = git__strdup(git_repository_path(repo))) == NULL) {
error = -1;
goto out;
diff --git a/src/worktree.h b/src/worktree.h
index 0e1a88d98..b8e527968 100644
--- a/src/worktree.h
+++ b/src/worktree.h
@@ -30,4 +30,6 @@ struct git_worktree {
int locked:1;
};
+char *git_worktree__read_link(const char *base, const char *file);
+
#endif
diff --git a/tests/worktree/open.c b/tests/worktree/open.c
index 54a8af4a3..f5b668177 100644
--- a/tests/worktree/open.c
+++ b/tests/worktree/open.c
@@ -5,10 +5,13 @@
#define WORKTREE_PARENT "submodules-worktree-parent"
#define WORKTREE_CHILD "submodules-worktree-child"
+#define COMMON_REPO "testrepo"
+#define WORKTREE_REPO "testrepo-worktree"
+
void test_worktree_open__repository(void)
{
worktree_fixture fixture =
- WORKTREE_FIXTURE_INIT("testrepo", "testrepo-worktree");
+ WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
setup_fixture_worktree(&fixture);
cl_assert(git_repository_path(fixture.worktree) != NULL);
@@ -20,18 +23,38 @@ void test_worktree_open__repository(void)
cleanup_fixture_worktree(&fixture);
}
+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_repository *repo;
+
+ setup_fixture_worktree(&fixture);
+
+ cl_git_pass(git_repository_discover(&path,
+ git_repository_workdir(fixture.worktree), false, NULL));
+ cl_git_pass(git_repository_open(&repo, path.ptr));
+ cl_assert_equal_s(git_repository_workdir(fixture.worktree),
+ git_repository_workdir(repo));
+
+ git_buf_free(&path);
+ git_repository_free(repo);
+ cleanup_fixture_worktree(&fixture);
+}
+
void test_worktree_open__repository_with_nonexistent_parent(void)
{
git_repository *repo;
- cl_fixture_sandbox("testrepo-worktree");
- cl_git_pass(p_chdir("testrepo-worktree"));
+ cl_fixture_sandbox(WORKTREE_REPO);
+ cl_git_pass(p_chdir(WORKTREE_REPO));
cl_git_pass(cl_rename(".gitted", ".git"));
cl_git_pass(p_chdir(".."));
- cl_git_fail(git_repository_open(&repo, "testrepo-worktree"));
+ cl_git_fail(git_repository_open(&repo, WORKTREE_REPO));
- cl_fixture_cleanup("testrepo-worktree");
+ cl_fixture_cleanup(WORKTREE_REPO);
}
void test_worktree_open__submodule_worktree_parent(void)
diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c
index 81d592951..959c56520 100644
--- a/tests/worktree/worktree.c
+++ b/tests/worktree/worktree.c
@@ -217,6 +217,7 @@ void test_worktree_worktree__init(void)
/* Open and verify created repo */
cl_git_pass(git_repository_open(&repo, path.ptr));
+ cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-new/") == 0);
cl_git_pass(git_branch_lookup(&branch, repo, "worktree-new", GIT_BRANCH_LOCAL));
git_buf_free(&path);