Commit 62eafd06 by Vicent Marti

Merge branch 'branch-delete-ref' into development

Conflicts:
	include/git2/refs.h
parents bd2887a5 1c947daa
......@@ -55,21 +55,13 @@ GIT_EXTERN(int) git_branch_create(
/**
* Delete an existing branch reference.
*
* @param repo Repository where lives the branch.
* If the branch is successfully deleted, the passed reference
* object will be freed and invalidated.
*
* @param branch_name Name of the branch to be deleted;
* this name is validated for consistency.
*
* @param branch_type Type of the considered branch. This should
* be valued with either GIT_BRANCH_LOCAL or GIT_BRANCH_REMOTE.
*
* @return 0 on success, GIT_ENOTFOUND if the branch
* doesn't exist or an error code.
* @param branch A valid reference representing a branch
* @return 0 on success, or an error code.
*/
GIT_EXTERN(int) git_branch_delete(
git_repository *repo,
const char *branch_name,
git_branch_t branch_type);
GIT_EXTERN(int) git_branch_delete(git_reference *branch);
/**
* Loop over all the branches and issue a callback for each one.
......
......@@ -376,6 +376,16 @@ GIT_EXTERN(int) git_reference_has_log(git_reference *ref);
*/
GIT_EXTERN(int) git_reference_is_branch(git_reference *ref);
/**
* Check if a reference is a remote tracking branch
*
* @param ref A git reference
*
* @return 1 when the reference lives in the refs/remotes
* namespace; 0 otherwise.
*/
GIT_EXTERN(int) git_reference_is_remote(git_reference *ref);
enum {
GIT_REF_FORMAT_NORMAL = 0,
......
......@@ -50,6 +50,12 @@ static int create_error_invalid(const char *msg)
return -1;
}
static int not_a_local_branch(git_reference *ref)
{
giterr_set(GITERR_INVALID, "Reference '%s' is not a local branch.", git_reference_name(ref));
return -1;
}
int git_branch_create(
git_reference **ref_out,
git_repository *repository,
......@@ -84,19 +90,19 @@ cleanup:
return error;
}
int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_t branch_type)
int git_branch_delete(git_reference *branch)
{
git_reference *branch = NULL;
git_reference *head = NULL;
int error;
assert(repo && branch_name);
assert((branch_type == GIT_BRANCH_LOCAL) || (branch_type == GIT_BRANCH_REMOTE));
assert(branch);
if ((error = retrieve_branch_reference(&branch, repo, branch_name, branch_type == GIT_BRANCH_REMOTE)) < 0)
return error;
if (!git_reference_is_branch(branch) &&
!git_reference_is_remote(branch)) {
giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch));
return -1;
}
if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0) {
if (git_reference_lookup(&head, git_reference_owner(branch), GIT_HEAD_FILE) < 0) {
giterr_set(GITERR_REFERENCE, "Cannot locate HEAD.");
goto on_error;
}
......@@ -104,7 +110,7 @@ int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_
if ((git_reference_type(head) == GIT_REF_SYMBOLIC)
&& (strcmp(git_reference_target(head), git_reference_name(branch)) == 0)) {
giterr_set(GITERR_REFERENCE,
"Cannot delete branch '%s' as it is the current HEAD of the repository.", branch_name);
"Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch));
goto on_error;
}
......@@ -116,7 +122,6 @@ int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_
on_error:
git_reference_free(head);
git_reference_free(branch);
return -1;
}
......@@ -163,12 +168,6 @@ int git_branch_foreach(
return git_reference_foreach(repo, GIT_REF_LISTALL, &branch_foreach_cb, (void *)&filter);
}
static int not_a_local_branch(git_reference *ref)
{
giterr_set(GITERR_INVALID, "Reference '%s' is not a local branch.", git_reference_name(ref));
return -1;
}
int git_branch_move(
git_reference *branch,
const char *new_branch_name,
......
......@@ -1836,6 +1836,11 @@ int git_reference_has_log(
int git_reference_is_branch(git_reference *ref)
{
assert(ref);
return git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR) == 0;
}
int git_reference_is_remote(git_reference *ref)
{
assert(ref);
return git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR) == 0;
}
......@@ -31,6 +31,8 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
mflag = MAP_SHARED;
else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE)
mflag = MAP_PRIVATE;
else
mflag = MAP_SHARED;
out->data = mmap(NULL, len, mprot, mflag, fd, offset);
......
......@@ -23,37 +23,37 @@ void test_refs_branches_delete__cleanup(void)
cl_fixture_cleanup("testrepo.git");
}
void test_refs_branches_delete__can_not_delete_a_non_existing_branch(void)
{
cl_git_fail(git_branch_delete(repo, "i-am-not-a-local-branch", GIT_BRANCH_LOCAL));
cl_git_fail(git_branch_delete(repo, "neither/a-remote-one", GIT_BRANCH_REMOTE));
}
void test_refs_branches_delete__can_not_delete_a_branch_pointed_at_by_HEAD(void)
{
git_reference *head;
git_reference *branch;
/* Ensure HEAD targets the local master branch */
cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
cl_assert(strcmp("refs/heads/master", git_reference_target(head)) == 0);
git_reference_free(head);
cl_git_fail(git_branch_delete(repo, "master", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
cl_git_fail(git_branch_delete(branch));
git_reference_free(branch);
}
void test_refs_branches_delete__can_not_delete_a_branch_if_HEAD_is_missing(void)
{
git_reference *head;
git_reference *branch = NULL;
cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
git_reference_delete(head);
cl_git_fail(git_branch_delete(repo, "br2", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
cl_git_fail(git_branch_delete(branch));
git_reference_free(branch);
}
void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD(void)
{
git_reference *master, *head;
git_reference *master, *head, *branch;
/* Detach HEAD and make it target the commit that "master" points to */
cl_git_pass(git_reference_lookup(&master, repo, "refs/heads/master"));
......@@ -61,30 +61,21 @@ void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD(
git_reference_free(head);
git_reference_free(master);
cl_git_pass(git_branch_delete(repo, "master", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_delete(branch));
}
void test_refs_branches_delete__can_delete_a_local_branch(void)
{
cl_git_pass(git_branch_delete(repo, "br2", GIT_BRANCH_LOCAL));
git_reference *branch;
cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
cl_git_pass(git_branch_delete(branch));
}
void test_refs_branches_delete__can_delete_a_remote_branch(void)
{
cl_git_pass(git_branch_delete(repo, "nulltoken/master", GIT_BRANCH_REMOTE));
git_reference *branch;
cl_git_pass(git_branch_lookup(&branch, repo, "nulltoken/master", GIT_BRANCH_REMOTE));
cl_git_pass(git_branch_delete(branch));
}
static void assert_non_exisitng_branch_removal(const char *branch_name, git_branch_t branch_type)
{
int error;
error = git_branch_delete(repo, branch_name, branch_type);
cl_git_fail(error);
cl_assert_equal_i(GIT_ENOTFOUND, error);
}
void test_refs_branches_delete__deleting_a_non_existing_branch_returns_ENOTFOUND(void)
{
assert_non_exisitng_branch_removal("i-do-not-locally-exist", GIT_BRANCH_LOCAL);
assert_non_exisitng_branch_removal("neither/remotely", GIT_BRANCH_REMOTE);
}
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