Fixing GIT Branch and Tag Name Collisions

A basic understanding in Git is that Tags are aliases to a commit hash (A single entry in the history of commits) whereas a Branch is the name for a diverged chain of commits that share a common history and ancestor. Confusion can be had when assuming a branch is always the HEAD, or most recent, commit in the fork of the code. While this can be true, this is not what a Branch represents and may lead to Tags being used interchangeably with Branches. When Tags and Branches are both used, they give flexibility to teams to share commit history and easily communicate important changes in code, but naming them similarly will lead to collisions if not well thought out.

Take care naming tags and branches to keep from confusing Git

Assume there is a master branch of code and a develop branch of code. Daily work is in the develop branch. Moving code into a master branch creates a release-able set of code. If the team wishes to be able to maintain the release for any period of time, a Tag should be created at the point in which the code has diverged.

You should never name a tag and a branch the same name!

It makes sense in a case like this to use naming conventions on the tags to keep from colliding on the branch names.

1
2
3
git tag develop-v1.0.0
// or
git tag v1.0.0-beta

Versus when we releasing code from the master branch.

1
2
3
git tag release/v1.0.0-rc1
// or
git tag release/v1.0.0

You can find the common parent in git using merge-base to do a Tag on code from the past.

1
2
git merge-base branch1 branch2
0f345000facddd090939209dcaef... // etc

If the team is only using master and develop collisions with these two branches will be very rare. However, feature branches and release branches bring in much more opportunities.

How to fix when you have a collision

If a collision has occurred Git will relay that with a message like the following. Assume we have mistakenly created a Tag release/v1.0.0 and a Branch release/v1.0.0. What will happen if we tell git to ‘checkout’?

1
2
3
git co release/v1.0.0
warning: refname 'release/v1.0.0' is ambiguous.
Switched to branch 'release/v1.0.0'

By default, git has chosen the Branch. If we meant to ‘checkout’ the Tag, being more specific is required.

1
2
3
4
5
6
git co refs/tags/release/v1.0.0
Note: checking out 'refs/tags/release/v1.0.0'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

Notice how we added refs/tags/. This is what can be found within the .git folder. The folder structure is the same that is would needed to append. We could also specify refs/heads/ if we wanted the branch.

At this point, any git command can specific enough check out any branch or tag without “ambiguity”, it’s best to rename the branch by creating a new one and deleting the previous branch; or remove and create a new tag so that the two do not have this collision.