mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-24 18:02:30 +00:00
Fix branch creation when branch name matches namespace of previously deleted branch
This commit is contained in:
parent
f83c19c87d
commit
1589a93aa6
@ -1771,6 +1771,15 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* If the new branch matches part of the namespace of a previously deleted branch,
|
||||
* there maybe an obsolete/unused directory (or directory hierarchy) in the way.
|
||||
*/
|
||||
if (git_path_isdir(git_buf_cstr(&path)) &&
|
||||
(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) {
|
||||
error = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error = git_futils_writebuffer(&buf, git_buf_cstr(&path), O_WRONLY|O_CREAT|O_APPEND, GIT_REFLOG_FILE_MODE);
|
||||
|
||||
cleanup:
|
||||
|
@ -196,3 +196,107 @@ void test_refs_branches_create__can_create_branch_with_unicode(void)
|
||||
branch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that we can create a branch with a name that matches the
|
||||
* namespace of a previously delete branch.
|
||||
*
|
||||
* git branch level_one/level_two
|
||||
* git branch -D level_one/level_two
|
||||
* git branch level_one
|
||||
*
|
||||
* We expect the delete to have deleted the files:
|
||||
* ".git/refs/heads/level_one/level_two"
|
||||
* ".git/logs/refs/heads/level_one/level_two"
|
||||
* It may or may not have deleted the (now empty)
|
||||
* containing directories. To match git.git behavior,
|
||||
* the second create needs to implicilty delete the
|
||||
* directories and create the new files.
|
||||
* "refs/heads/level_one"
|
||||
* "logs/refs/heads/level_one"
|
||||
*
|
||||
* We should not fail to create the branch or its
|
||||
* reflog because of an obsolete namespace container
|
||||
* directory.
|
||||
*/
|
||||
void test_refs_branches_create__name_vs_namespace(void)
|
||||
{
|
||||
const char * name;
|
||||
struct item {
|
||||
const char *first;
|
||||
const char *second;
|
||||
};
|
||||
static const struct item item[] = {
|
||||
{ "level_one/level_two", "level_one" },
|
||||
{ "a/b/c/d/e", "a/b/c/d" },
|
||||
{ "ss/tt/uu/vv/ww", "ss" },
|
||||
/* And one test case that is deeper. */
|
||||
{ "xx1/xx2/xx3/xx4", "xx1/xx2/xx3/xx4/xx5/xx6" },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
const struct item *p;
|
||||
|
||||
retrieve_known_commit(&target, repo);
|
||||
|
||||
for (p=item; p->first; p++) {
|
||||
cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0, NULL, NULL));
|
||||
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
|
||||
cl_git_pass(git_branch_name(&name, branch));
|
||||
cl_assert_equal_s(name, p->first);
|
||||
|
||||
cl_git_pass(git_branch_delete(branch));
|
||||
git_reference_free(branch);
|
||||
branch = NULL;
|
||||
|
||||
cl_git_pass(git_branch_create(&branch, repo, p->second, target, 0, NULL, NULL));
|
||||
git_reference_free(branch);
|
||||
branch = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We still need to fail if part of the namespace is
|
||||
* still in use.
|
||||
*/
|
||||
void test_refs_branches_create__name_vs_namespace_fail(void)
|
||||
{
|
||||
const char * name;
|
||||
struct item {
|
||||
const char *first;
|
||||
const char *first_alternate;
|
||||
const char *second;
|
||||
};
|
||||
static const struct item item[] = {
|
||||
{ "level_one/level_two", "level_one/alternate", "level_one" },
|
||||
{ "a/b/c/d/e", "a/b/c/d/alternate", "a/b/c/d" },
|
||||
{ "ss/tt/uu/vv/ww", "ss/alternate", "ss" },
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
const struct item *p;
|
||||
|
||||
retrieve_known_commit(&target, repo);
|
||||
|
||||
for (p=item; p->first; p++) {
|
||||
cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0, NULL, NULL));
|
||||
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
|
||||
cl_git_pass(git_branch_name(&name, branch));
|
||||
cl_assert_equal_s(name, p->first);
|
||||
|
||||
cl_git_pass(git_branch_delete(branch));
|
||||
git_reference_free(branch);
|
||||
branch = NULL;
|
||||
|
||||
cl_git_pass(git_branch_create(&branch, repo, p->first_alternate, target, 0, NULL, NULL));
|
||||
cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target)));
|
||||
cl_git_pass(git_branch_name(&name, branch));
|
||||
cl_assert_equal_s(name, p->first_alternate);
|
||||
|
||||
/* we do not delete the alternate. */
|
||||
git_reference_free(branch);
|
||||
branch = NULL;
|
||||
|
||||
cl_git_fail(git_branch_create(&branch, repo, p->second, target, 0, NULL, NULL));
|
||||
git_reference_free(branch);
|
||||
branch = NULL;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user