Commit f9793884 by John Fultz Committed by Patrick Steinhardt

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.
parent e3298a33
...@@ -58,16 +58,17 @@ static int create_branch( ...@@ -58,16 +58,17 @@ static int create_branch(
const char *from, const char *from,
int force) int force)
{ {
int is_head = 0; int is_unmovable_head = 0;
git_reference *branch = NULL; git_reference *branch = NULL;
git_buf canonical_branch_name = GIT_BUF_INIT, git_buf canonical_branch_name = GIT_BUF_INIT,
log_message = GIT_BUF_INIT; log_message = GIT_BUF_INIT;
int error = -1; int error = -1;
int bare = git_repository_is_bare(repository);
assert(branch_name && commit && ref_out); assert(branch_name && commit && ref_out);
assert(git_object_owner((const git_object *)commit) == repository); 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); error = git_branch_is_head(branch);
git_reference_free(branch); git_reference_free(branch);
branch = NULL; branch = NULL;
...@@ -75,10 +76,10 @@ static int create_branch( ...@@ -75,10 +76,10 @@ static int create_branch(
if (error < 0) if (error < 0)
goto cleanup; 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 " giterr_set(GITERR_REFERENCE, "Cannot force update branch '%s' as it is "
"the current HEAD of the repository.", branch_name); "the current HEAD of the repository.", branch_name);
error = -1; error = -1;
......
...@@ -65,10 +65,14 @@ void test_refs_branches_create__can_force_create_over_an_existing_branch(void) ...@@ -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)); 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; const git_oid *oid;
git_reference *branch2; 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); retrieve_known_commit(&target, repo);
cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL)); 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) ...@@ -84,6 +88,26 @@ void test_refs_branches_create__cannot_force_create_over_current_branch(void)
git_reference_free(branch2); 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) void test_refs_branches_create__creating_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void)
{ {
retrieve_known_commit(&target, repo); retrieve_known_commit(&target, repo);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment