Git made distributed code development very easy and convenient. Reference specifications (refspecs for short) tell Git what to fetch from a remote repository. By default, when you add or clone a remote repository, Git assumes some default refspecs. For example, if you were to examine — using the command git config -e — the repository's config file immediately after a clone, you'd find:
[remote "origin"] url = ... fetch = +refs/heads/*:refs/remotes/origin/*
This means that Git will fetch everything under refs/heads from the remote repository and place them under refs/remotes/origin in your local repository. This is a sensible thing to do. As you see, the refspecs are properly namespaced (in this case under origin), so that you know what came from origin.
What you'd soon realize is that tags are not handled the same way. By default, Git fetches all tags refspecs from refs/tags and dumps them into refs/tags of your local repository. That means they aren't namespaced by default. For most cases, this works alright because you tend to track similar repositories, and it's reasonable to expect that same tags in all of them actually points to the same object.
However, this assumption may lead to some annoyance. For example, you might want to track two Linux repositories, both with lot of experimental tags. Although it's unlikely that two tags with the same name in two repositories point to different objects, it'd be hard to identify what came from where. Looking at the tag dumping yard, it'd be difficult to discern which tag actually belongs to which repository. Yet another one is that, since your local tags too go into refs/tags, you'd be mixing remote and local tags.
Thankfully, with a little bit of extra work and habit, this can be solved by adding an extra refspec for tags. Git allows more than one refspec per remote repository, so adding more than one is alright. Here's what to do: append the following lines to the relevant remote section of the configuration:
fetch = +refs/tags/*:refs/tags/origin/* tagopt = --no-tags
These do two things: one is to instruct Git not to fetch tags implicitly during future fetches (above via. tagopt). But worry not; to mitigate not fetching tags, we add an explicit refspec — as is the case with remote branches — to fetch tags and place them under respective remote's name. I.e. effectively, we namespaced tags too!
In the event that you forgot to add those lines before fetching repositories, or even after a fresh clone, you can do the following to have tags namespaced again (after having necessary refspecs in place, of course):
git tag | xargs git tag -d git remote update
The commands above deletes all tags in the repository, and fetches updates afresh. Since tags were missing in the local repository, they'll be fetched, but this time properly namespaced.
A minor inconvenience is that Git will complain when you rename remotes. It won't automatically rename the extra configurations added above; nor would it rename tags that had already been namespaced. You'd have to do them both manually. To namespace tags again, you only need to run the command above (or a more selective version of it).
Understandably, it takes time and habit to make these changes to your work flow. I personally find it neat to keep references properly namespaced. Your mileage may vary.
No comments:
Post a Comment