diff options
-rw-r--r-- | src/repository.c | 36 | ||||
-rw-r--r-- | src/worktree.c | 6 | ||||
-rw-r--r-- | src/worktree.h | 2 | ||||
-rw-r--r-- | tests/worktree/open.c | 33 | ||||
-rw-r--r-- | tests/worktree/worktree.c | 1 |
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); |