On the Perils of Importing Remote Tags in Git

Posted in: Technical Track

So mothers keep your hackers at home
Don’t let them journey all alone
Tell them this world is full of danger
And to shun the repositories of strangers

– The Tag Set of Strangers,
(with apologies to) Nick Cave and the Bad Seeds

One of the things I love about Git is how I can add branches from remote repositories in mine at will without fearing messing up anything. The remote branches will not clash with mine, even if they share the same names, because they are referenced as repository/branch. However, as for anything else, you can still poke yourself in the eye if you try hard enough:

$ git remote
$ git checkout -b bob/baroque
Switched to a new branch 'bob/baroque'
$ git fetch bob
From ../bob
* [new branch]      baroque    -> bob/baroque
$ git checkout bob/baroque
warning: refname 'bob/baroque' is ambiguous.
Already on 'bob/baroque'

Here, I created a local branch called bob/baroque, which will end up having the same name as the branch baroque imported from Bob’s repository. Confusing, but not the end of the world. I can still see the different branches with gitk and access the local and remote branches via git checkout remotes/bob/baroque and git checkout remotes/bob/baroque.[1] The lesson to take from this, of course, is simply not to use slashes in branch names and sidestep the whole issue.

[1] The fiendish-minded reader probably wonders at this point what would happen if I were to create another local branch called remotes/bob/baroque. I would deserve to be shot, that’s what would happen.

With tags, surprisingly, the matter is much more prickly. Not only are tags not kept in the ”namespace” of their repository of origin, but git fetch has a very dangerous default behavior:

$ git log -n 1 somework
commit 483d008c6207554236232fef4e8cd22cfb4b9bb8
Author: Yanick Champoux <[email protected]>
Date:   Wed Mar 3 21:14:43 2010 -0500
    some work on my repo
$ git fetch --tags bob
From ../b
- [tag update]      somework   -> somework
$ git log -n 1 somework
commit 5f7f8eddd2d44e359fe8bc0d1a2f1642d073cad9
Author: Yanick Champoux <[email protected]>
Date:   Wed Mar 3 21:15:25 2010 -0500
    some work from Bob

Yup, that’s right, if there is a conflict, fetch --tags will silently clobber the local tags with their remote counterparts. Hope you remember all the commits you painstakingly tagged in the last six months… This behavior is so mind-bogglingly dangerous that, to this day, I wonder if I’m not missing something obvious.

Now, granted, it’s fairly rare to import tags from remote repositories. But there are instances, like when adding the gitpan history of your module to your repository, where it’s relevant. In those cases, for your own sake, make sure that the remote tags won’t clash with yours. Even better, don’t use --tags at all. Instead, do something akin to:

$ git ls-remote --tags bob | \
   perl -nae'$F[1]=~s#refs/tags#bob#; `git tag $F[1] $F[0]`'

This will name remote tags using the repository/tag convention. Also, if the tag already exist, Git will complain and it won’t be clobbered by the new version.

Want to talk with an expert? Schedule a call with our team to get the conversation started.

No comments

Leave a Reply

Your email address will not be published. Required fields are marked *