repository: restrict checking out checked out branches If a branch is already checked out in a working tree we are not allowed to check out that branch in another repository. Introduce this restriction when setting a repository's HEAD.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
diff --git a/src/repository.c b/src/repository.c
index 445005e..8753636 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -2529,6 +2529,12 @@ int git_repository_set_head(
if (error < 0 && error != GIT_ENOTFOUND)
goto cleanup;
+ if (ref && current->type == GIT_REF_SYMBOLIC && git__strcmp(current->target.symbolic, ref->name) &&
+ git_reference_is_branch(ref) && git_branch_is_checked_out(ref)) {
+ error = -1;
+ goto cleanup;
+ }
+
if (!error) {
if (git_reference_is_branch(ref)) {
error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
diff --git a/tests/worktree/refs.c b/tests/worktree/refs.c
index 38f6127..ccac8be 100644
--- a/tests/worktree/refs.c
+++ b/tests/worktree/refs.c
@@ -68,6 +68,41 @@ void test_worktree_refs__read_head(void)
git_reference_free(head);
}
+void test_worktree_refs__set_head_fails_when_worktree_wants_linked_repos_HEAD(void)
+{
+ git_reference *head;
+
+ cl_git_pass(git_repository_head(&head, fixture.repo));
+ cl_git_fail(git_repository_set_head(fixture.worktree, git_reference_name(head)));
+
+ git_reference_free(head);
+}
+
+void test_worktree_refs__set_head_fails_when_main_repo_wants_worktree_head(void)
+{
+ git_reference *head;
+
+ cl_git_pass(git_repository_head(&head, fixture.worktree));
+ cl_git_fail(git_repository_set_head(fixture.repo, git_reference_name(head)));
+
+ git_reference_free(head);
+}
+
+void test_worktree_refs__set_head_works_for_current_HEAD(void)
+{
+ git_reference *head;
+
+ cl_git_pass(git_repository_head(&head, fixture.repo));
+ cl_git_pass(git_repository_set_head(fixture.repo, git_reference_name(head)));
+
+ git_reference_free(head);
+}
+
+void test_worktree_refs__set_head_fails_when_already_checked_out(void)
+{
+ cl_git_fail(git_repository_set_head(fixture.repo, "refs/heads/testrepo-worktree"));
+}
+
void test_worktree_refs__delete_fails_for_checked_out_branch(void)
{
git_reference *branch;