I don't use Mercurial, but i'd like to start, so i'm reading about it. The only SCM system i've used extensively is CVS. Most of what i've read about Mercurial makes sense, and sounds good. But i'm alternately shocked and perplexed by that way it does tags.
A tag is just a nickname for a changeset (and by 'changeset' we really mean the state resulting from the changeset). Cool. The mapping from tags to changeset IDs is stored in the .hgtags
file. Also cool. The .hgtags
file is versioned.
What?
This has lots of counterintuitive consequences. For instance, if i commit a changeset which i then want to tag (say, the code which will form release 1.0), i have to commit again after tagging, to put the updated tag file into the repository. And if i then update to that tagged changeset at some later date, the working copy won't contain any knowledge of that tag. If i do some work, thus founding a new branch (say, for bugfixes, heading towards 1.1), that branch won't have any knowledge of the tag from which it grew. Unless i copy it over manually, that is.
And as development continues both on the original trunk and my new branch, with tags being created to mark important changesets (the 2.0 release on the trunk, the 1.1 and 1.2 bugfix releases on the branch), both branches will proceed in ignorance of the other branch's tags. So, if i finish working on one branch, and want to switch to some particular changeset on another (say, i finish the 1.2 bugfix release, but now have to start on the 2.1 bugfix, based on 2.0), i am now stuffed. My current changeset doesn't know about 2.0!
What can i do?
hgtags
file outside the repository, and use a couple of hooks to pull in a copy on an update, overwriting the local copy, and to copy back any changes on a commit. I'm not sure how this would work in a multi-user environment, where developers are pushing changes to a shared repository; i might need a separate repository just for the hgtags
file.localtags
file between developers.None of these solutions seem totally great. What should i do?
An assumption here is that i'm managing branches using named branches in a single repository, rather than repository-per-branch. Would the situation be any better if i did the latter?
Thus Mercurial stores tags as a file in the working dir. This file is called . hgtags and consists of a list of changeset IDs and their corresponding tags. To add a tag to the system, simply add a line to this file and then commit it for it to take effect.
If you want to remove a tag that you no longer want, use hg tag --remove . You can also modify a tag at any time, so that it identifies a different revision, by simply issuing a new hg tag command. You'll have to use the -f option to tell Mercurial that you really want to update the tag.
In the Status bar, click the Mercurial Branch widget to open the Branches popup. Select the branch or bookmark to which you want to switch and in the menu that opens, click Update.
Creating a branch Branching can happen by committing a changeset within a single repository or by committing diverging changes in distinct (but related) repositories. Two repositories are said to be related if they were once cloned from the same repository but later may have diverged.
Versioning the .hgtags
file allows you to
However, there are some confusion going on here.
You write that
[...] And if i then update to that tagged changeset at some later date, the working copy won't contain any knowledge of that tag. [...]
That is wrong, tags are collected from the .hgtags
files found in all heads. That means that you can update to an old tag (hg update 0.1
) and still see all your tags (hg tags
).
You ask if branches are universally visible. Yes they are -- the names of named branches can be used in any context where you need to specify a changeset, as can tags.
Make sure you understand what named branches are before you begin using them. They are actually not necessary for making a bugfix branch. You can instead choose to simply go back (hg update 1.0
) and fix the bug and then commit. That will create a new head, which your line of development towards 1.1 (this gives you multiple heads). So you don't have to create a named branch to add a new branch of development to your repository.
Having multiple heads is completely equivalent to having multiple clones. You can even convert back and forth: you can use
% hg clone -r X-head repo repo-X
to untangle the X-head
changeset and its ancestors from the other changesets in repo
. And you can combine multiple clones by simply pulling all changesets into one big clone.
Named branches are similar, yet different. They allow you to embed a named in each changeset. So you can have several changesets in your history with the name "foo". When you do hg update foo
you will end up at the tip-most of these changesets. In this way, named branches function as a kind of floating tag.
If you are uncomfortable with the idea of a permanent label for your changesets, you can instead try the bookmarks extension. That will also give you "floating tags" which you can use for updating, but they wont be permanently part of the history since they aren't versioned.
I hope this helps a bit.
The choice of method for tagging definitely has some odd side effects, but they're explained well in this wiki. It's also suggested that you clone an entire repo and then update to the point of interest to avoid the case where you will have created a repo that does not contain the tag that was used to create it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With