Git Version Control – Is Creating a Tag with a Deleted Branch Name a Bad Idea?

branchinggitgitflowversion control

I have a project with a git branching model that roughly follows that of nvie's git-flow.

Our release branches are named in a SemVer format, e.g. v1.5.2

Once a release branch is given the green light for production, we close the branch, by merging it into master, applying a tag, and then deleting the branch.

As we immediately delete the release branch, we've been using the same identifier for tagging the branch, e.g. v1.5.2

Here's the commands we'd use to close a release branch:

$ git checkout master
$ git merge v1.5.2
$ git tag -a v1.5.2 -m "Version 1.5.2 - foo bar, baz, etc"
$ git branch -d v1.5.2
$ git branch -dr origin/v1.5.2
$ git push origin :v1.5.2
$ git push
$ git push --tags

This seems to work in the majority of cases, however it's causing an issue in the scenario where another instance of the git repo (e.g. another dev machine, or staging environment) has a local checkout of the v1.5.2 branch.

The git push origin :v1.5.2 command will delete the branch in the remote, but does not delete the local version of the branch (if it exists) in all repos.

This leads to an ambiguous reference, when trying checkout v1.5.2 in those repos:

$ git checkout v1.5.2
warning: refname 'v1.5.2' is ambiguous.

Can this be avoided without using a different syntax for the branches, e.g. release-v1.5.2, or v1.5.2-rc?

Or is it unavoidable, and therefore a fundamentally bad idea to create a tag with the same name as a deleted branch?

Best Answer

If you absolutely want to keep this naming scheme, you might:

Decide that you don't care about these warnings

That is, if you're happy with the fact that:

  • git checkout <ref> will check out refs/heads/<ref> over refs/tags/<ref> (see git-checkout)
  • other commands will use refs/tags/<ref> over refs/heads/<ref> (see gitrevisions)

For example, in this test repository, the v1.5.2 branch points to commit B, but the v1.5.2 tag points to commit A.

% git log --oneline --decorate
8060f6f (HEAD, v1.5.2, master) commit B
0e69483 (tag: v1.5.2) commit A

git checkout prefers branch names:

% git checkout v1.5.2
warning: refname 'v1.5.2' is ambiguous.
Switched to branch 'v1.5.2'
% git log --decorate --oneline -1
8060f6f (HEAD, v1.5.2, master) commit B

but git log will use the tag name:

% git log --decorate --oneline -1 v1.5.2
warning: refname 'v1.5.2' is ambiguous.
0e69483 (tag: v1.5.2) commit A

This could be confusing.

Train people to delete their local branches when they see a new tag

This might be hard/awkward depending on the size of your organisation.

Write a wrapper around "git pull" and "git fetch"

That is, write a wrapper that checks if there are any tags that shadow branch names, and warn about (or delete) those branches. This sounds painful, and it could be undesirable if the shadowed branch is currently checked out.

Unfortunately, it sounds like the easiest way to solve this problem might be to change the way you name your branches. The link you posted uses different naming schemes for tags and branches: if you're already mostly following that method, adopting its naming scheme might be the easiest solution.