summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2017-05-02 10:11:28 +0200
committerPatrick Steinhardt <ps@pks.im>2017-05-05 15:39:25 +0200
commit8264a30f4fbfce96f433f01fa6fe537e5cb3570d (patch)
treea944129c72e1f6a7268d96ad2e285948ff87be06
parenta7aa73a535a7f21357e9c7dece8376f30a29681f (diff)
downloadlibgit2-8264a30f4fbfce96f433f01fa6fe537e5cb3570d.tar.gz
worktree: support creating locked worktrees
When creating a new worktree, we do have a potential race with us creating the worktree and another process trying to delete the same worktree as it is being created. As such, the upstream git project has introduced a flag `git worktree add --locked`, which will cause the newly created worktree to be locked immediately after its creation. This mitigates the race condition. We want to be able to mirror the same behavior. As such, a new flag `locked` is added to the options structure of `git_worktree_add` which allows the user to enable this behavior.
-rw-r--r--include/git2/worktree.h4
-rw-r--r--src/worktree.c15
-rw-r--r--tests/worktree/worktree.c25
3 files changed, 43 insertions, 1 deletions
diff --git a/include/git2/worktree.h b/include/git2/worktree.h
index bc1e40243..84e2bc92e 100644
--- a/include/git2/worktree.h
+++ b/include/git2/worktree.h
@@ -76,10 +76,12 @@ GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt);
typedef struct git_worktree_add_options {
unsigned int version;
+
+ char lock; /**< lock newly created worktree */
} git_worktree_add_options;
#define GIT_WORKTREE_ADD_OPTIONS_VERSION 1
-#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION}
+#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0}
/**
* Initializes a `git_worktree_add_options` with default vaules.
diff --git a/src/worktree.c b/src/worktree.c
index 6e797f362..b9ed75991 100644
--- a/src/worktree.c
+++ b/src/worktree.c
@@ -318,6 +318,21 @@ int git_worktree_add(git_worktree **out, git_repository *repo,
if ((err = git_path_prettify_dir(&wddir, worktree, NULL)) < 0)
goto out;
+ if (wtopts.lock) {
+ int fd;
+
+ if ((err = git_buf_joinpath(&buf, gitdir.ptr, "locked")) < 0)
+ goto out;
+
+ if ((fd = p_creat(buf.ptr, 0644)) < 0) {
+ err = fd;
+ goto out;
+ }
+
+ p_close(fd);
+ git_buf_clear(&buf);
+ }
+
/* Create worktree .git file */
if ((err = git_buf_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0)
goto out;
diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c
index f90895822..7ab86cceb 100644
--- a/tests/worktree/worktree.c
+++ b/tests/worktree/worktree.c
@@ -228,6 +228,31 @@ void test_worktree_worktree__init(void)
git_repository_free(repo);
}
+void test_worktree_worktree__add_locked(void)
+{
+ git_worktree *wt;
+ git_repository *repo;
+ git_reference *branch;
+ git_buf path = GIT_BUF_INIT;
+ git_worktree_add_options opts = GIT_WORKTREE_ADD_OPTIONS_INIT;
+
+ opts.lock = 1;
+
+ cl_git_pass(git_buf_joinpath(&path, fixture.repo->workdir, "../worktree-locked"));
+ cl_git_pass(git_worktree_add(&wt, fixture.repo, "worktree-locked", path.ptr, &opts));
+
+ /* Open and verify created repo */
+ cl_assert(git_worktree_is_locked(NULL, wt));
+ cl_git_pass(git_repository_open(&repo, path.ptr));
+ cl_assert(git__suffixcmp(git_repository_workdir(repo), "worktree-locked/") == 0);
+ cl_git_pass(git_branch_lookup(&branch, repo, "worktree-locked", GIT_BRANCH_LOCAL));
+
+ git_buf_free(&path);
+ git_worktree_free(wt);
+ git_reference_free(branch);
+ git_repository_free(repo);
+}
+
void test_worktree_worktree__init_existing_branch(void)
{
git_reference *head, *branch;