Merge branch 'rs/branch-del-symref' into maint

A symbolic ref refs/heads/SYM was not correctly removed with "git
branch -d SYM"; the command removed the ref pointed by SYM instead.

* rs/branch-del-symref:
  branch: show targets of deleted symrefs, not sha1s
  branch: skip commit checks when deleting symref branches
  branch: delete symref branch, not its target
  branch: factor out delete_branch_config()
  branch: factor out check_branch_commit()
This commit is contained in:
Junio C Hamano 2012-11-18 19:32:58 -08:00
commit 3a9866919c
2 changed files with 68 additions and 26 deletions

View File

@ -154,10 +154,37 @@ static int branch_merged(int kind, const char *name,
return merged;
}
static int check_branch_commit(const char *branchname, const char *refname,
unsigned char *sha1, struct commit *head_rev,
int kinds, int force)
{
struct commit *rev = lookup_commit_reference(sha1);
if (!rev) {
error(_("Couldn't look up commit object for '%s'"), refname);
return -1;
}
if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
error(_("The branch '%s' is not fully merged.\n"
"If you are sure you want to delete it, "
"run 'git branch -D %s'."), branchname, branchname);
return -1;
}
return 0;
}
static void delete_branch_config(const char *branchname)
{
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "branch.%s", branchname);
if (git_config_rename_section(buf.buf, NULL) < 0)
warning(_("Update of config-file failed"));
strbuf_release(&buf);
}
static int delete_branches(int argc, const char **argv, int force, int kinds,
int quiet)
{
struct commit *rev, *head_rev = NULL;
struct commit *head_rev = NULL;
unsigned char sha1[20];
char *name = NULL;
const char *fmt;
@ -187,6 +214,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
die(_("Couldn't look up commit object for HEAD"));
}
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
const char *target;
int flags = 0;
strbuf_branchname(&bname, argv[i]);
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
error(_("Cannot delete the branch '%s' "
@ -198,7 +228,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
free(name);
name = mkpathdup(fmt, bname.buf);
if (read_ref(name, sha1)) {
target = resolve_ref_unsafe(name, sha1, 0, &flags);
if (!target ||
(!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) {
error(remote_branch
? _("remote branch '%s' not found.")
: _("branch '%s' not found."), bname.buf);
@ -206,40 +238,31 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
continue;
}
rev = lookup_commit_reference(sha1);
if (!rev) {
error(_("Couldn't look up commit object for '%s'"), name);
if (!(flags & REF_ISSYMREF) &&
check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
force)) {
ret = 1;
continue;
}
if (!force && !branch_merged(kinds, bname.buf, rev, head_rev)) {
error(_("The branch '%s' is not fully merged.\n"
"If you are sure you want to delete it, "
"run 'git branch -D %s'."), bname.buf, bname.buf);
ret = 1;
continue;
}
if (delete_ref(name, sha1, 0)) {
if (delete_ref(name, sha1, REF_NODEREF)) {
error(remote_branch
? _("Error deleting remote branch '%s'")
: _("Error deleting branch '%s'"),
bname.buf);
ret = 1;
} else {
struct strbuf buf = STRBUF_INIT;
if (!quiet)
continue;
}
if (!quiet) {
printf(remote_branch
? _("Deleted remote branch %s (was %s).\n")
: _("Deleted branch %s (was %s).\n"),
bname.buf,
find_unique_abbrev(sha1, DEFAULT_ABBREV));
strbuf_addf(&buf, "branch.%s", bname.buf);
if (git_config_rename_section(buf.buf, NULL) < 0)
warning(_("Update of config-file failed"));
strbuf_release(&buf);
(flags & REF_ISSYMREF)
? target
: find_unique_abbrev(sha1, DEFAULT_ABBREV));
}
delete_branch_config(bname.buf);
}
free(name);

View File

@ -262,6 +262,25 @@ test_expect_success 'config information was renamed, too' \
"test $(git config branch.s.dummy) = Hello &&
test_must_fail git config branch.s/s/dummy"
test_expect_success 'deleting a symref' '
git branch target &&
git symbolic-ref refs/heads/symref refs/heads/target &&
echo "Deleted branch symref (was refs/heads/target)." >expect &&
git branch -d symref >actual &&
test_path_is_file .git/refs/heads/target &&
test_path_is_missing .git/refs/heads/symref &&
test_i18ncmp expect actual
'
test_expect_success 'deleting a dangling symref' '
git symbolic-ref refs/heads/dangling-symref nowhere &&
test_path_is_file .git/refs/heads/dangling-symref &&
echo "Deleted branch dangling-symref (was nowhere)." >expect &&
git branch -d dangling-symref >actual &&
test_path_is_missing .git/refs/heads/dangling-symref &&
test_i18ncmp expect actual
'
test_expect_success 'renaming a symref is not allowed' \
'
git symbolic-ref refs/heads/master2 refs/heads/master &&