Skip to content

push: --delete silently succeeds without deleting a tag (short names qualified as refs/heads/ only, exit 0) #465

Description

@genedna

Summary

libra push origin --delete <tag> prints Everything up-to-date, exits 0, and deletes nothing. The tag stays published while the user is told the operation succeeded.

The cause is that a short deletion target is unconditionally qualified as refs/heads/<name>, so a tag name resolves to a branch that does not exist, and a deletion request naming a ref the remote does not advertise is treated as "nothing to do" rather than an error.

Reproduction

With a tag that exists on the remote:

$ libra ls-remote origin | grep tag
12de8a8b15f61e5c32bc315049632e16355903f1	refs/tags/v0.1.0

$ libra push origin --delete v0.1.0
Everything up-to-date

$ libra ls-remote origin | grep tag
12de8a8b15f61e5c32bc315049632e16355903f1	refs/tags/v0.1.0     # still there

The fully-qualified refspec form works:

$ libra push origin :refs/tags/v0.1.0
To git@github.com:libra-tools/skills.git
 - [deleted]         v0.1.0

Expected: libra push origin --delete v0.1.0 deletes the tag, as git push --delete v0.1.0 does.

The exit code is 0 even for a ref that does not exist at all

$ libra push origin --delete zz-nonexistent-probe
Everything up-to-date
$ echo $?
0

Git refuses this: error: unable to delete 'zz-nonexistent-probe': remote ref does not exist, exit 1. Scripts and agents branching on the exit code are told a deletion happened when none did — this is the part that makes the bug more than a missing feature.

Root cause

apply_delete_flag (src/command/push.rs:729) rewrites --delete v0.1.0 into the deletion refspec :v0.1.0, which is the documented design. The destination is then qualified (src/command/push.rs:1433-1438):

if input.starts_with("refs/heads/") {
    // ...
} else {
    ensure_valid_ref(format!("refs/heads/{input}"), input)
}

Any short name becomes refs/heads/<input>, so the request becomes "delete refs/heads/v0.1.0". The remote has no such ref, the plan comes out empty, and push reports Everything up-to-date.

Git instead resolves the name against the refs the remote advertises and deletes the single match (erroring when the name is ambiguous).

Docs contradiction

docs/commands/push.md:428 states the equivalence directly:

| Delete remote branch | libra push -d origin branch or libra push origin :branch | git push -d origin branch / git push origin :branch |

and docs/commands/push.md:61 documents -d, --delete as "Delete the named remote refs", with no branches-only restriction. So either the behaviour or the documentation is wrong.

Suggested fix

Two independent changes; the second is worth making even if the first is deferred.

  1. Resolve a short deletion target against the remote's advertised refs — try refs/heads/<name> then refs/tags/<name>, and refuse an ambiguous name the way Git does, instead of hardcoding the refs/heads/ prefix.
  2. Fail a deletion that names a ref the remote does not advertise. Today that path is indistinguishable from an up-to-date push. Making it an error surfaces the missing resolution in (1) rather than hiding it, and stops --delete from reporting success for a ref it never touched.

A regression test that pushes a tag, deletes it with --delete <short name>, and asserts it is gone from ls-remote would cover both.

Possibly the same family as #464

#464 is also a short-name-versus-fully-qualified-ref mismatch: status looks a remote-tracking ref up by its short name while clone/fetch/push store it fully qualified. Different commands and different fixes, but it may be worth auditing every place a ref name is qualified with a hardcoded refs/heads/ prefix.

Environment

libra 0.22.10
Linux 7.1.9-arch1-2 x86_64
remote: github.com over SSH

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingvcs

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions