diff options
| author | Edward Thomson <ethomson@edwardthomson.com> | 2017-03-22 20:32:55 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-03-22 20:32:55 +0000 |
| commit | f623cf894a7e2591e7b4424b24143d1a7584cf9e (patch) | |
| tree | eff28ba6a1a91f51fb71a07969e688fcf1ecc8cd /src | |
| parent | 6fd6c67824d2caad9f8716a676820d8319f79a9d (diff) | |
| parent | b0c9bc920fabfd814946d555738ac7ba042154d7 (diff) | |
| download | libgit2-f623cf894a7e2591e7b4424b24143d1a7584cf9e.tar.gz | |
Merge pull request #4163 from pks-t/pks/submodules-with-worktrees
Worktree fixes
Diffstat (limited to 'src')
| -rw-r--r-- | src/refdb_fs.c | 10 | ||||
| -rw-r--r-- | src/submodule.c | 24 | ||||
| -rw-r--r-- | src/worktree.c | 148 | ||||
| -rw-r--r-- | src/worktree.h | 2 |
4 files changed, 135 insertions, 49 deletions
diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 450b3f3ec..b325d2763 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -739,6 +739,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * { int error, filebuf_flags; git_buf ref_path = GIT_BUF_INIT; + const char *basedir; assert(file && backend && name); @@ -747,13 +748,18 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * return GIT_EINVALIDSPEC; } + if (is_per_worktree_ref(name)) + basedir = backend->gitpath; + else + basedir = backend->commonpath; + /* Remove a possibly existing empty directory hierarchy * 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; - if (git_buf_joinpath(&ref_path, backend->gitpath, name) < 0) + if (git_buf_joinpath(&ref_path, basedir, name) < 0) return -1; filebuf_flags = GIT_FILEBUF_FORCE; diff --git a/src/submodule.c b/src/submodule.c index 191cdf3dd..ddd4b0663 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -22,6 +22,7 @@ #include "iterator.h" #include "path.h" #include "index.h" +#include "worktree.h" #define GIT_MODULES_FILE ".gitmodules" @@ -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) { int error; + git_worktree *wt = 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)); - git_remote_free(remote); - } - else if (error == GIT_ENOTFOUND) { - /* if repository does not have a default remote, use workdir instead */ + goto out; + } else if (error != GIT_ENOTFOUND) + goto out; + else 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)); - } + +out: + git_remote_free(remote); + git_worktree_free(wt); return error; } diff --git a/src/worktree.c b/src/worktree.c index 5abc98945..393a088fe 100644 --- a/src/worktree.c +++ b/src/worktree.c @@ -14,11 +14,20 @@ #include "repository.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_path_contains_file(dir, "gitdir") - && git_path_contains_file(dir, "HEAD"); + git_buf buf = GIT_BUF_INIT; + int error; + + 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) @@ -47,7 +56,7 @@ int git_worktree_list(git_strarray *wts, git_repository *repo) git_buf_truncate(&path, len); git_buf_puts(&path, worktree); - if (!is_worktree_dir(&path)) { + if (!is_worktree_dir(path.ptr)) { git_vector_remove(&worktrees, i); git__free(worktree); } @@ -112,6 +121,46 @@ out: 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) { git_buf path = GIT_BUF_INIT; @@ -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) goto out; - if (!is_worktree_dir(&path)) { - error = -1; + if ((error = (open_worktree_dir(out, git_repository_workdir(repo), path.ptr, name))) < 0) 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; goto out; } - if ((wt->name = git__strdup(name)) == 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; + gitdir = git_repository_path(repo); + commondir = git_repository_commondir(repo); + + if ((error = git_path_prettify_dir(&parent, "..", commondir)) < 0) 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: - git_buf_free(&path); + if ((error = open_worktree_dir(out, parent.ptr, gitdir, name)) < 0) + goto out; +out: if (error) - git_worktree_free(wt); + free(name); + git_buf_free(&parent); return error; } @@ -177,7 +240,7 @@ int git_worktree_validate(const git_worktree *wt) assert(wt); git_buf_puts(&buf, wt->gitdir_path); - if (!is_worktree_dir(&buf)) { + if (!is_worktree_dir(buf.ptr)) { giterr_set(GITERR_WORKTREE, "Worktree gitdir ('%s') is not valid", wt->gitlink_path); @@ -209,7 +272,7 @@ out: 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_commit *commit = NULL; git_repository *wt = NULL; @@ -220,35 +283,39 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, *out = NULL; - /* Create worktree related files in commondir */ - if ((err = git_buf_joinpath(&path, repo->commondir, "worktrees")) < 0) + /* Create gitdir directory ".git/worktrees/<name>" */ + if ((err = git_buf_joinpath(&gitdir, repo->commondir, "worktrees")) < 0) goto out; - if (!git_path_exists(path.ptr)) - if ((err = git_futils_mkdir(path.ptr, 0755, GIT_MKDIR_EXCL)) < 0) + if (!git_path_exists(gitdir.ptr)) + if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0) goto out; - if ((err = git_buf_joinpath(&path, path.ptr, name)) < 0) + if ((err = git_buf_joinpath(&gitdir, gitdir.ptr, name)) < 0) + goto out; + if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0) 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; /* Create worktree work dir */ if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0) goto out; + if ((err = git_path_prettify_dir(&wddir, worktree, NULL)) < 0) + goto out; /* 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; - if ((err = write_wtfile(worktree, ".git", &buf)) < 0) + if ((err = write_wtfile(wddir.ptr, ".git", &buf)) < 0) goto out; - /* Create commondir files */ - if ((err = git_buf_sets(&buf, repo->commondir)) < 0 + /* Create gitdir files */ + if ((err = git_path_prettify_dir(&buf, repo->commondir, NULL) < 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; - 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 = write_wtfile(path.ptr, "gitdir", &buf)) < 0) + || (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0) goto out; /* Create new branch */ @@ -260,9 +327,9 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, goto out; /* 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; - if ((err = git_repository_open(&wt, worktree)) < 0) + if ((err = git_repository_open(&wt, wddir.ptr)) < 0) goto out; /* Checkout worktree's HEAD */ @@ -275,7 +342,8 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, goto out; out: - git_buf_free(&path); + git_buf_free(&gitdir); + git_buf_free(&wddir); git_buf_free(&buf); git_reference_free(ref); git_reference_free(head); @@ -394,7 +462,7 @@ int git_worktree_prune(git_worktree *wt, unsigned flags) } /* 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; if (!git_path_exists(path.ptr)) { diff --git a/src/worktree.h b/src/worktree.h index b8e527968..57c2e65f0 100644 --- a/src/worktree.h +++ b/src/worktree.h @@ -24,7 +24,7 @@ struct git_worktree { /* Path to the common directory contained in the parent * repository */ char *commondir_path; - /* Path to the parent's .git directory */ + /* Path to the parent's working directory */ char *parent_path; int locked:1; |
