summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Fultz <jfultz@wolfram.com>2016-10-28 14:32:01 -0500
committerPatrick Steinhardt <ps@pks.im>2016-11-04 18:12:35 +0100
commitf9793884a3fc895a17a2a70709d32cbc2214377b (patch)
tree3fb3a18416cfa1bbdb6472cfa1b9f62a4be2bd69
parente3298a330835af8d4760bf593500c28728398747 (diff)
downloadlibgit2-f9793884a3fc895a17a2a70709d32cbc2214377b.tar.gz
branch: fix forced branch creation on HEAD of a bare repo
The code correctly detects that forced creation of a branch on a nonbare repo should not be able to overwrite a branch which is the HEAD reference. But there's no reason to prevent this on a bare repo, and in fact, git allows this. I.e., git branch -f master new_sha works on a bare repo with HEAD set to master. This change fixes that problem, and updates tests so that, for this case, both the bare and nonbare cases are checked for correct behavior.
-rw-r--r--src/branch.c9
-rw-r--r--tests/refs/branches/create.c26
2 files changed, 30 insertions, 5 deletions
diff --git a/src/branch.c b/src/branch.c
index 51c35d7ff..8d1ed6577 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -58,16 +58,17 @@ static int create_branch(
const char *from,
int force)
{
- int is_head = 0;
+ int is_unmovable_head = 0;
git_reference *branch = NULL;
git_buf canonical_branch_name = GIT_BUF_INIT,
log_message = GIT_BUF_INIT;
int error = -1;
+ int bare = git_repository_is_bare(repository);
assert(branch_name && commit && ref_out);
assert(git_object_owner((const git_object *)commit) == repository);
- if (force && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
+ if (force && !bare && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) {
error = git_branch_is_head(branch);
git_reference_free(branch);
branch = NULL;
@@ -75,10 +76,10 @@ static int create_branch(
if (error < 0)
goto cleanup;
- is_head = error;
+ is_unmovable_head = error;
}
- if (is_head && force) {
+ if (is_unmovable_head && force) {
giterr_set(GITERR_REFERENCE, "Cannot force update branch '%s' as it is "
"the current HEAD of the repository.", branch_name);
error = -1;
diff --git a/tests/refs/branches/create.c b/tests/refs/branches/create.c
index 31dec0678..69488e6c7 100644
--- a/tests/refs/branches/create.c
+++ b/tests/refs/branches/create.c
@@ -65,10 +65,14 @@ void test_refs_branches_create__can_force_create_over_an_existing_branch(void)
cl_assert_equal_s("refs/heads/br2", git_reference_name(branch));
}
-void test_refs_branches_create__cannot_force_create_over_current_branch(void)
+void test_refs_branches_create__cannot_force_create_over_current_branch_in_nonbare_repo(void)
{
const git_oid *oid;
git_reference *branch2;
+
+ /* Default repo for these tests is a bare repo, but this test requires a non-bare one */
+ cl_git_sandbox_cleanup();
+ repo = cl_git_sandbox_init("testrepo");
retrieve_known_commit(&target, repo);
cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL));
@@ -84,6 +88,26 @@ void test_refs_branches_create__cannot_force_create_over_current_branch(void)
git_reference_free(branch2);
}
+void test_refs_branches_create__can_force_create_over_current_branch_in_bare_repo(void)
+{
+ const git_oid *oid;
+ git_reference *branch2;
+ retrieve_known_commit(&target, repo);
+
+ cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL));
+ cl_assert_equal_s("refs/heads/master", git_reference_name(branch2));
+ cl_assert_equal_i(true, git_branch_is_head(branch2));
+ oid = git_commit_id(target);
+
+ cl_git_pass(git_branch_create(&branch, repo, "master", target, 1));
+ git_reference_free(branch);
+ branch = NULL;
+ cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
+ cl_assert_equal_s("refs/heads/master", git_reference_name(branch));
+ cl_git_pass(git_oid_cmp(git_reference_target(branch), oid));
+ git_reference_free(branch2);
+}
+
void test_refs_branches_create__creating_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
retrieve_known_commit(&target, repo);