bos@196: \chapter{Managing releases and branchy development} bos@187: \label{chap:branch} bos@187: bos@197: Mercurial provides several mechanisms for you to manage a project that bos@197: is making progress on multiple fronts at once. To understand these bos@197: mechanisms, let's first take a brief look at a fairly normal software bos@197: project structure. bos@187: bos@196: Many software projects issue periodic ``major'' releases that contain bos@196: substantial new features. In parallel, they may issue ``minor'' bos@196: releases. These are usually identical to the major releases off which bos@196: they're based, but with a few bugs fixed. bos@196: bos@197: In this chapter, we'll start by talking about how to keep records of bos@197: project milestones such as releases. We'll then continue on to talk bos@197: about the flow of work between different phases of a project, and how bos@197: Mercurial can help you to isolate and manage this work. bos@197: bos@196: \section{Giving a persistent name to a revision} bos@196: bos@196: Once you decide that you'd like to call a particular revision a bos@196: ``release'', it's a good idea to record the identity of that revision. bos@196: This will let you reproduce that release at a later date, for whatever bos@196: purpose you might need at the time (reproducing a bug, porting to a bos@196: new platform, etc). bos@196: \interaction{tag.init} bos@196: bos@196: Mercurial lets you give a permanent name to any revision using the bos@196: \hgcmd{tag} command. Not surprisingly, these names are called bos@196: ``tags''. bos@196: \interaction{tag.tag} bos@196: bos@196: A tag is nothing more than a ``symbolic name'' for a revision. Tags bos@196: exist purely for your convenience, so that you have a handy permanent bos@196: way to refer to a revision; Mercurial doesn't interpret the tag names bos@196: you use in any way. Neither does Mercurial place any restrictions on bos@196: the name of a tag, beyond a few that are necessary to ensure that a bos@196: tag can be parsed unambiguously. A tag name cannot contain any of the bos@196: following characters: bos@196: \begin{itemize} bos@196: \item Colon (ASCII 58, ``\texttt{:}'') bos@196: \item Carriage return (ASCII 13, ``\texttt{$\backslash$r}'') bos@196: \item Newline (ASCII 10, ``\texttt{$\backslash$n}'') bos@196: \end{itemize} bos@196: bos@196: You can use the \hgcmd{tags} command to display the tags present in bos@196: your repository. In the output, each tagged revision is identified bos@196: first by its name, then by revision number, and finally by the unique bos@196: hash of the revision. bos@196: \interaction{tag.tags} bos@196: Notice that \texttt{tip} is listed in the output of \hgcmd{tags}. The bos@196: \texttt{tip} tag is a special ``floating'' tag, which always bos@196: identifies the newest revision in the repository. bos@196: bos@196: In the output of the \hgcmd{tags} command, tags are listed in reverse bos@196: order, by revision number. This usually means that recent tags are bos@196: listed before older tags. It also means that \texttt{tip} is always bos@196: going to be the first tag listed in the output of \hgcmd{tags}. bos@196: bos@196: When you run \hgcmd{log}, if it displays a revision that has tags bos@196: associated with it, it will print those tags. bos@196: \interaction{tag.log} bos@196: bos@196: Any time you need to provide a revision~ID to a Mercurial command, the bos@196: command will accept a tag name in its place. Internally, Mercurial bos@196: will translate your tag name into the corresponding revision~ID, then bos@196: use that. bos@196: \interaction{tag.log.v1.0} bos@196: bos@196: There's no limit on the number of tags you can have in a repository, bos@196: or on the number of tags that a single revision can have. As a bos@196: practical matter, it's not a great idea to have ``too many'' (a number bos@196: which will vary from project to project), simply because tags are bos@196: supposed to help you to find revisions. If you have lots of tags, the bos@196: ease of using them to identify revisions diminishes rapidly. bos@196: bos@196: For example, if your project has milestones as frequent as every few bos@196: days, it's perfectly reasonable to tag each one of those. But if you bos@196: have a continuous build system that makes sure every revision can be bos@196: built cleanly, you'd be introducing a lot of noise if you were to tag bos@196: every clean build. Instead, you could tag failed builds (on the bos@196: assumption that they're rare!), or simply not use tags to track bos@196: buildability. bos@196: bos@196: If you want to remove a tag that you no longer want, use bos@196: \hgcmdargs{tag}{--remove}. bos@196: \interaction{tag.remove} bos@196: You can also modify a tag at any time, so that it identifies a bos@196: different revision, by simply issuing a new \hgcmd{tag} command. bos@196: You'll have to use the \hgopt{tag}{-f} option to tell Mercurial that bos@196: you \emph{really} want to update the tag. bos@196: \interaction{tag.replace} bos@196: There will still be a permanent record of the previous identity of the bos@197: tag, but Mercurial will no longer use it. There's thus no penalty to bos@197: tagging the wrong revision; all you have to do is turn around and tag bos@197: the correct revision once you discover your error. bos@196: bos@196: Mercurial stores tags in a normal revision-controlled file in your bos@196: repository. If you've created any tags, you'll find them in a file bos@196: named \sfilename{.hgtags}. When you run the \hgcmd{tag} command, bos@196: Mercurial modifies this file, then automatically commits the change to bos@196: it. This means that every time you run \hgcmd{tag}, you'll see a bos@196: corresponding changeset in the output of \hgcmd{log}. bos@196: \interaction{tag.tip} bos@196: bos@196: \subsection{Handling tag conflicts during a merge} bos@196: bos@196: You won't often need to care about the \sfilename{.hgtags} file, but bos@196: it sometimes makes its presence known during a merge. The format of bos@196: the file is simple: it consists of a series of lines. Each line bos@196: starts with a changeset hash, followed by a space, followed by the bos@196: name of a tag. bos@196: bos@196: If you're resolving a conflict in the \sfilename{.hgtags} file during bos@196: a merge, there's one twist to modifying the \sfilename{.hgtags} file: bos@196: when Mercurial is parsing the tags in a repository, it \emph{never} bos@196: reads the working copy of the \sfilename{.hgtags} file. Instead, it bos@196: reads the \emph{most recently committed} revision of the file. bos@196: bos@196: An unfortunate consequence of this design is that you can't actually bos@196: verify that your merged \sfilename{.hgtags} file is correct until bos@196: \emph{after} you've committed a change. So if you find yourself bos@196: resolving a conflict on \sfilename{.hgtags} during a merge, be sure to bos@196: run \hgcmd{tags} after you commit. If it finds an error in the bos@196: \sfilename{.hgtags} file, it will report the location of the error, bos@196: which you can then fix and commit. You should then run \hgcmd{tags} bos@196: again, just to be sure that your fix is correct. bos@187: bos@197: \subsection{When permanent tags are too much} bos@197: bos@197: Since Mercurial's tags are revision controlled and carried around with bos@197: a project's history, everyone you work with will see the tags you bos@197: create. But giving names to revisions has uses beyond simply noting bos@197: that revision \texttt{4237e45506ee} is really \texttt{v2.0.2}. If bos@197: you're trying to track down a subtle bug, you might want a tag to bos@197: remind you of something like ``Anne saw the symptoms with this bos@197: revision''. bos@197: bos@197: For cases like this, what you might want to use are \emph{local} tags. bos@197: You can create a local tag with the \hgopt{tag}{-l} option to the bos@197: \hgcmd{tag} command. This will store the tag in a file called bos@197: \sfilename{.hg/localtags}. Unlike \sfilename{.hgtags}, bos@197: \sfilename{.hg/localtags} is not revision controlled. Any tags you bos@197: create using \hgopt{tag}{-l} remain strictly local to the repository bos@197: you're currently working in. bos@197: bos@197: bos@187: %%% Local Variables: bos@187: %%% mode: latex bos@187: %%% TeX-master: "00book" bos@187: %%% End: