gitbranchgit-pushremote-branch

Why does deleting a remote branch by name produce an error while deleting by ref does not?


When I try to delete a non-existent remote Git branch by name, I expectedly get an error:

$ git push origin --delete non/existent
error: unable to delete 'non/existent': remote ref does not exist
error: failed to push some refs to 'git@github.com:<_replaced_>.git'
$ echo $?
1

However, deleting the same branch by ref (e.g. taken from .git/config) is not considered an error:

$ git push origin --delete refs/heads/non/existent
remote: warning: Deleting a non-existent ref.
To github.com:<_replaced_>.git
 - [deleted]         non/existent
$ echo $?
0

Why so? Are these commands equivalent?


Solution

  • They are not equivalent.

    A ref is either fully qualified, i.e., starts with refs/, and is therefore unambiguous, or is not fully qualified, i.e., starts with something other than refs/.

    A not-fully-qualified ref must be converted to a fully-qualified ref. It is up to the target of your git push to do the qualifying. If it finds no fully qualified ref, it reports back to the source of the git push that it was unable to qualify the ref.

    A fully-qualified ref is of course already fully-qualified, so the receiving Git just says "ok, that doesn't exist" and hence the Git asking for the deletion is happy to report that the ref does not exist. So the Git running git push --delete is happy and thinks all is well.

    One can argue that it would be reasonable for the Git doing the git push to realize that "I can't qualify that ref for you" probably means "I don't have anything that would match" which in turn means "whatever ref you meant, it doesn't exist", which could then make the Git running git push --delete happy. But that's not what actually happens.


    Note that with an ambiguous ref, that matches two or more possibilities, I observe the following:

    server-repo$ git for-each-ref
    11ae6ca18f6325c858f1e3ea2b7e6a045666336d commit refs/heads/ambig
    222c4dd303570d096f0346c3cd1dff6ea2c84f83 commit refs/heads/branch
    e068bdfce2fd992dc396cb4969327ef5c4d39a43 commit refs/heads/fix-signal
    d41117433d7b4431a188c0eddec878646bf399c3 commit refs/heads/foobranch
    11ae6ca18f6325c858f1e3ea2b7e6a045666336d commit refs/heads/master
    11ae6ca18f6325c858f1e3ea2b7e6a045666336d commit refs/tags/ambig
    d41117433d7b4431a188c0eddec878646bf399c3 commit refs/tags/tag-foo
    

    and:

    client-repo$ git push --delete origin ambig
    error: dst refspec ambig matches more than one
    error: failed to push some refs to [server URL]