17

At the moment I'm forced to push to a new branch on every change I make. And that branch must be deleted since the error appears again on every newly created branch.

git push origin main gives the following output

error: dst refspec refs/heads/main matches more than one
error: failed to push some refs to 'https://github.com/CarloCattano/fastesTube'

My git tag outputs:

refs/heads/dev
refs/heads/dev2
refs/heads/dev3
refs/heads/main
v1.1
win64 

no matter if I manually delete them with -d. Even tried to migrate the project to a new repo , and the problem persists after a few pushes.

git remote -v

origin  https://github.com/CarloCattano/fastesTube (fetch)
origin  https://github.com/CarloCattano/fastesTube (push)

git ls-remote

ac4cac50b79ff682ddd01f6c0c3913d0bd765e64        HEAD
77273d612953f96e72ce305ab94f0a535a4c332d        refs/heads/dev3
3c344e7af2feb33db2d05f08866cad5fe624b57c        refs/heads/develop
ac4cac50b79ff682ddd01f6c0c3913d0bd765e64        refs/heads/main
fde3bb1ed7c770a5b8eb94a368bb34f25566f00e        refs/pull/1/head
ffe33059c3fcc12899953bc588772072d9a18bf0        refs/pull/2/head
77273d612953f96e72ce305ab94f0a535a4c332d        refs/pull/3/head
3c344e7af2feb33db2d05f08866cad5fe624b57c        refs/pull/4/head
b9d1c3f8b83ea1ac868143ec647776d03f9bacc7        refs/tags/refs/heads/dev
ffe33059c3fcc12899953bc588772072d9a18bf0        refs/tags/refs/heads/dev2
77273d612953f96e72ce305ab94f0a535a4c332d        refs/tags/refs/heads/dev3
4098ea71b5a0873db6be41e859e5b8242d81c708        refs/tags/refs/heads/main
a42341ba40635bd5063a0bf988eab6c00b0e62d1        refs/tags/v1.1
37220afec1d13dcac99c61ef766ac800fc6438f5        refs/tags/win64

Force pushing also doesn't seem to work.

It might be I wrongly configured the .yml file and creates tags for every release.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Carlo Cattano
  • 341
  • 1
  • 2
  • 10

4 Answers4

35

The problem here is that you have created tags named refs/heads/... (fill in the three dots).

A ref or reference, in Git, is a string that normally starts with refs/ and goes on to have a namespace qualifier:

  • refs/heads/* are branch names: the part that matches the * is the branch name;
  • refs/tags/* are tag names: the part that matches the * is the tag name;
  • refs/remotes/* are remote-tracking names;

and so on. Typically you can give Git a shortened name, such as main or v1.1, and it can figure out whether this name is a branch name or a tag name by looking at the existing names:

  • There's normally a refs/heads/main or refs/heads/master, but no refs/tags/main or refs/tags/master, so main or master is therefore a branch name.
  • There may be a refs/tags/v1.1, but typically there isn't a refs/heads/v1.1 if so, so v1.1 is therefore a tag name.

When using this kind of scheme, you provide an ambiguous name like main or v1.1 and Git figures out if it's a branch or tag name on its own, or you provide a full name like refs/heads/main and Git immediately knows that it's a branch name. The short name, without the refs/heads/ or refs/tags/ qualifier in front, is an unqualified name. The full name is a qualified name.

The git push command is more complicated than most other Git commands (except that git fetch is similarly complicated) because it has to deal with two Git repositories, rather than just one. So instead of a ref, git push can take a refspec, which is a pair of refs separated by a colon :. If you use a full refspec:

git push origin refs/heads/main:refs/tags/v1.2

then the parts on the left and right are each refs and each one is either unqualified or qualified. Unqualified names can be resolved by looking at the local Git repository's names (for those that are local) or remote's name (for those that are remote).

If, however, you use a partial refspec:

git push origin main

then Git isn't sure whether you meant "main as found locally" or "main as found on the remote". So Git will look in both places to make its best guesses.

In this case, however, the destination Git—the one whose references are shown in your git ls-remote output—has both refs/heads/main and refs/tags/refs/heads/main. So, your Git has looked up main locally and found refs/heads/main; it now looks that up in the set of refs in the other Git repository, and can't translate it to just one ref since both refs/heads/main—a fully-qualified branch name—and refs/tags/refs/heads/main—a fully-qualified tag name—match the potentially-unqualified refs/heads/main. The result is that you get this error message.

Whether you'd get this error for git push origin refs/heads/main:refs/heads/main, I don't know. The best fix, though, is to correct the set of names on the destination, so that there are no refs/tags/refs/* names any more. That is, these four names:

b9d1c3f8b83ea1ac868143ec647776d03f9bacc7        refs/tags/refs/heads/dev
ffe33059c3fcc12899953bc588772072d9a18bf0        refs/tags/refs/heads/dev2
77273d612953f96e72ce305ab94f0a535a4c332d        refs/tags/refs/heads/dev3
4098ea71b5a0873db6be41e859e5b8242d81c708        refs/tags/refs/heads/main

should be adjusted (or deleted entirely) so that no tag name in the Git repository over on GitHub starts with refs/. Ideally, these tag names should not match any branch names either: tag names should generally conform to the v* form, or to some other "clearly a tag" pattern so that nobody will accidentally think they're branch names, or vice versa.

Once you fix that, simple git push commands will work again.

torek
  • 448,244
  • 59
  • 642
  • 775
  • 1
    Thank you for such a detailed answer. Deleting the tags and extra branches did the trick. Just had some interesting error about "email privacy settings" , had to revert it to public to be able to push but thats it. Such a detailed and informative answer thanks again! – Carlo Cattano Jan 05 '22 at 06:52
2

As correctly explained, there are tag collisions. I could see on the GitHub website that my tag was not listed (was not pushed remotely). The problematic tag was actually a branch name that got misunderstood as a tag by GitHub Desktop.

The problematic tag was indicated by the error. It was listed using the git tag command.

The following command allows deleting the tag in GitBash (as shared previously):

git tag --delete tagname

After that, it again became possible to push to the remote.

I also tried downloading the newest Beta, as it was said "repositories with existing branches named this way can still push updates to those branches." Using the newer version of GitHub Desktop didn't fix that for me, however.

Denis G. Labrecque
  • 1,023
  • 13
  • 29
0

UPDATE: Not sure how reliable this is for more than one push! I seem to have encountered some weirdness. I my branch name stored under multiple refs when looking at git ls-remote

I worked around this by doing:

git push origin -u --force <sha>:origin/feature/branch

I think all I really needed was the origin/ prefix, probably did not need origin -u

Devin Rhode
  • 23,026
  • 8
  • 58
  • 72
0

My git tag outputs:

refs/heads/dev
...

Good news: that is no longer possible to push such "tag" names to GitHub since March 2023:

Block ambiguous branch and tag names (Mar. 2023)

GitHub blocks branch and tag names which begin with refs/.

Under the hood, all Git refs begin with a prefix (refs/heads/ for branches and refs/tags/ for tags).
In typical use, though, users rarely see these prefixes, so they're silently handled by GitHub, the Git client, and other tools.

When a similar string is used as the beginning of the visible part of the branch or tag name, this results in ambiguity: did the user intend refs/heads/feature or refs/heads/refs/heads/feature?
In nearly all cases, refs/ in front of a branch or tag name is accidental and becomes a problematic surprise later.

This change blocks new introductions of such names.
Repositories with existing branches named this way can still push updates to those branches.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Still having the same issue with a repo I installed in April 2023, so I'm not so sure of that. – Vincent Tobiaz May 18 '23 at 16:40
  • @VincentTobiaz Interesting, that would need to be reported to GitHub support, since this policy is (supposed to be) enforced on GitHub side. – VonC May 18 '23 at 16:41
  • @VincentTobiaz Let me know what GitHub support says: I will edit this answer. – VonC May 18 '23 at 19:18