branch: skip commit checks when deleting symref branches
authorRené Scharfe <rene.scharfe@lsrfire.ath.cx>
Thu, 18 Oct 2012 12:07:11 +0000 (14:07 +0200)
committerJunio C Hamano <gitster@pobox.com>
Thu, 18 Oct 2012 21:36:17 +0000 (14:36 -0700)
Before a branch is deleted, we check that it points to a valid
commit.  With -d we also check that the commit is a merged; this
check is not done with -D.

The reason for that is that commits pointed to by branches should
never go missing; if they do then something broke and it's better
to stop instead of adding to the mess.  And a non-merged commit
may contain changes that are worth preserving, so we require the
stronger option -D instead of -d to get rid of them.

If a branch consists of a symref, these concerns don't apply.
Deleting such a branch can't make a commit become unreferenced,
so we don't need to check if it is merged, or even if it is
actually a valid commit.  Skip them in that case.  This allows
us to delete dangling symref branches.

Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/branch.c
t/t3200-branch.sh

index 5e1e5b4d68d30e7287e94ff48ecea0b076722b4a..d87035a2f457a40b32174a1173c414b042a3fbeb 100644 (file)
@@ -214,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' "
@@ -225,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);
@@ -233,7 +238,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                        continue;
                }
 
-               if (check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
+               if (!(flags & REF_ISSYMREF) &&
+                   check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
                                        force)) {
                        ret = 1;
                        continue;
index ec5f70eebae65bd5e3b3c7e621ec376e7a31474b..1323f6ff718d876ef06a071504390afa19a885a1 100755 (executable)
@@ -273,6 +273,15 @@ test_expect_success 'deleting a 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 0000000)." >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 &&