Avoid git push --tags
Today I learned that there are better ways to push Git tags to an upstream
repository than the bad habit I’d gotten into, i.e.: git push --tags
. It
turns out that it’s best to avoid git push --tags
if at all possible and
to push tags individually.

git push --tags
.
The situation
On a recent project,1 I had the problem that git push --tags
raised an error, telling me that various tags already existed upstream:
! [rejected] 1.8.1 -> 1.8.1 (already exists)
error: failed to push some refs to '<project-repo>.git'
hint: Updates were rejected because the tag already exists in the remote.
This was somewhat confusing as I thought the tags should be up to date and the tags in my local repo would be consistent with the tags upstream.2 It turns out that things weren’t consistent between the two.
The reason that the error occurred at all was due to PEBKAC. I’d updated some of the commits to use a different email address and hence the upstream tags3 pointed to a different SHA than what I had in my local repo. However, I’m not sure why my local tags were pointing to the correct commits (from the point of view of content and metadata) and yet the upstream was somehow pointing to commits with the old email address. I thought that the filter-repo process I used to update the email address would have fixed that as well. Obviously, I missed something somewhere. Oh well.
Looking in the frontend for the upstream repo, I found that the conflicting tags were attached to commits referring to the old email address. Yet the same commit ids4 in the local repo pointed to the new email address. Weird. Also, tags in the local repo pointed to different commit ids from what the frontend for the upstream repo was showing. This discrepancy seems to be what was causing the conflict and hence Git wouldn’t let me push the tags without forcing the situation.
What’s interesting is that in my local dev repo, the old commit id is still there, but with the new email address, and Git tells me it’s been replaced:
(local repo) $ git show -p 12001164
commit 12001164d37b3fb8428d2690973e67bc0a0ac605 (replaced)
Referring to the tag in the local repo, however, points to the correct commit (with the correct contents):
(local repo) $ git show -p 1.8.1
commit 50731f636f203b93339239b66c0273977021f088 (tag: 1.8.1)
Curious! For instance, I’d have thought that Git would have garbage collected the replaced commit long ago; I mean, it’s from 2018 originally and there’s no tag pointing to it. That would imply that there’s a reference still pointing to the commit, so more digging here might be necessary.
I also found that grabbing a fresh clone from upstream showed that the old email address was still being used for commits referenced by tags that were showing conflicts, e.g.
(fresh clone) $ git show -p 1.8.1
commit 12001164d37b3fb8428d2690973e67bc0a0ac605 (tag: 1.8.1)
The correct commit (i.e. the one with the SHA I expect to see given the state of my local repo) exists in the fresh clone from upstream:
(fresh clone) $ git show -p 50731f63
commit 50731f636f203b93339239b66c0273977021f088
but doesn’t have a tag associated with it, as git show
, erm, shows.
Checking the situation with my trusty companion,
tig
shows that this commit is part of the
DAG5 for
master
. Because the commit with this SHA contains the correct committer
email address and is associated with the correct tag (at least locally), I
know that the upstream tag is incorrect and needs to be replaced. That’s
good to know, as it tells me how to proceed: I need to force-push the
conflicting tags from my local repo to the upstream repo to fix the
situation.
The solution
How did I get here again? Oh yeah, when adding a new tag to the project, I
wanted to update the tags in the upstream repo with git push --tags
. This
gave the error with upstream tags conflicting with the local tags. The
solution? Avoid git push --tags
:-)
That’s not an overly helpful solution suggestion. So what should one do instead? The proper way to add a new tag is like so:
$ git push origin tag <tag-name>
All I need to do now is to force-push the tags I screwed up so that things are consistent between my local dev copy and the upstream repo.
When is git push --tags
ok?
So when should one use git push --tags
? The only situation I can think of
now is when creating a new upstream repo from a pre-existing local repo.
That’s about it. I guess that’s the reason why GitHub and GitLab recommend
this step when initialising a blank project from an existing Git repository,
e.g. with git push --set-upstream origin --tags
.
Conclusion
In the end, the lesson is: avoid git push --tags
if at all possible. You
probably should use git push origin tag <tag-name>
instead.
I also learned something new today, which is always nice :-)
-
I’m available for freelance Python/Perl backend development and maintenance work. Contact me at paul@peateasea.de and let’s discuss how I can help solve your business’ hairiest problems. ↩
-
By “upstream” I mean the “origin” repository. ↩
-
Where I’m being sloppy and using the phrases “commit id” and “commit SHA” interchangeably. ↩
-
Not to be confused with the antipodean term. ↩
Support
If you liked this post and want to see more like this, please buy me a coffee!
