# HG changeset patch # User Romain PELISSE # Date 1250438885 -7200 # Node ID 108c5ecc8232687fca0bb7958527dfff67064a94 # Parent 48b202b19e2bea3a8dabd52061e94b0d0bd4bb6f fix merge with Bryan on this particular file diff -r 48b202b19e2b -r 108c5ecc8232 en/ch02-tour-basic.xml --- a/en/ch02-tour-basic.xml Sun Aug 16 17:24:16 2009 +0200 +++ b/en/ch02-tour-basic.xml Sun Aug 16 18:08:05 2009 +0200 @@ -1,624 +1,1035 @@ -\chapter{A tour of Mercurial: the basics} -\label{chap:tour-basic} - -\section{Installing Mercurial on your system} -\label{sec:tour:install} - -Prebuilt binary packages of Mercurial are available for every popular -operating system. These make it easy to start using Mercurial on your -computer immediately. - -\subsection{Linux} - -Because each Linux distribution has its own packaging tools, policies, -and rate of development, it's difficult to give a comprehensive set of -instructions on how to install Mercurial binaries. The version of -Mercurial that you will end up with can vary depending on how active -the person is who maintains the package for your distribution. - -To keep things simple, I will focus on installing Mercurial from the -command line under the most popular Linux distributions. Most of -these distributions provide graphical package managers that will let -you install Mercurial with a single click; the package name to look -for is \texttt{mercurial}. - -\begin{itemize} -\item[Debian] - \begin{codesample4} - apt-get install mercurial - \end{codesample4} - -\item[Fedora Core] - \begin{codesample4} - yum install mercurial - \end{codesample4} - -\item[Gentoo] - \begin{codesample4} - emerge mercurial - \end{codesample4} - -\item[OpenSUSE] - \begin{codesample4} - yum install mercurial - \end{codesample4} - -\item[Ubuntu] Ubuntu's Mercurial package is based on Debian's. To - install it, run the following command. - \begin{codesample4} - apt-get install mercurial - \end{codesample4} - The Ubuntu package for Mercurial tends to lag behind the Debian - version by a considerable time margin (at the time of writing, seven - months), which in some cases will mean that on Ubuntu, you may run - into problems that have since been fixed in the Debian package. -\end{itemize} - -\subsection{Solaris} - -SunFreeWare, at \url{http://www.sunfreeware.com}, is a good source for a -large number of pre-built Solaris packages for 32 and 64 bit Intel and -Sparc architectures, including current versions of Mercurial. - -\subsection{Mac OS X} - -Lee Cantey publishes an installer of Mercurial for Mac OS~X at -\url{http://mercurial.berkwood.com}. This package works on both -Intel-~and Power-based Macs. Before you can use it, you must install -a compatible version of Universal MacPython~\cite{web:macpython}. This -is easy to do; simply follow the instructions on Lee's site. - -It's also possible to install Mercurial using Fink or MacPorts, -two popular free package managers for Mac OS X. If you have Fink, -use \command{sudo fink install mercurial-py25}. If MacPorts, -\command{sudo port install mercurial}. - -\subsection{Windows} - -Lee Cantey publishes an installer of Mercurial for Windows at -\url{http://mercurial.berkwood.com}. This package has no external -dependencies; it ``just works''. - -\begin{note} - The Windows version of Mercurial does not automatically convert line - endings between Windows and Unix styles. If you want to share work - with Unix users, you must do a little additional configuration - work. XXX Flesh this out. -\end{note} - -\section{Getting started} - -To begin, we'll use the \hgcmd{version} command to find out whether -Mercurial is actually installed properly. The actual version -information that it prints isn't so important; it's whether it prints -anything at all that we care about. -\interaction{tour.version} - -\subsection{Built-in help} - -Mercurial provides a built-in help system. This is invaluable for those -times when you find yourself stuck trying to remember how to run a -command. If you are completely stuck, simply run \hgcmd{help}; it -will print a brief list of commands, along with a description of what -each does. If you ask for help on a specific command (as below), it -prints more detailed information. -\interaction{tour.help} -For a more impressive level of detail (which you won't usually need) -run \hgcmdargs{help}{\hggopt{-v}}. The \hggopt{-v} option is short -for \hggopt{--verbose}, and tells Mercurial to print more information -than it usually would. - -\section{Working with a repository} - -In Mercurial, everything happens inside a \emph{repository}. The -repository for a project contains all of the files that ``belong to'' -that project, along with a historical record of the project's files. - -There's nothing particularly magical about a repository; it is simply -a directory tree in your filesystem that Mercurial treats as special. -You can rename or delete a repository any time you like, using either the -command line or your file browser. - -\subsection{Making a local copy of a repository} - -\emph{Copying} a repository is just a little bit special. While you -could use a normal file copying command to make a copy of a -repository, it's best to use a built-in command that Mercurial -provides. This command is called \hgcmd{clone}, because it creates an -identical copy of an existing repository. -\interaction{tour.clone} -If our clone succeeded, we should now have a local directory called -\dirname{hello}. This directory will contain some files. -\interaction{tour.ls} -These files have the same contents and history in our repository as -they do in the repository we cloned. - -Every Mercurial repository is complete, self-contained, and -independent. It contains its own private copy of a project's files -and history. A cloned repository remembers the location of the -repository it was cloned from, but it does not communicate with that -repository, or any other, unless you tell it to. - -What this means for now is that we're free to experiment with our -repository, safe in the knowledge that it's a private ``sandbox'' that -won't affect anyone else. - -\subsection{What's in a repository?} - -When we take a more detailed look inside a repository, we can see that -it contains a directory named \dirname{.hg}. This is where Mercurial -keeps all of its metadata for the repository. -\interaction{tour.ls-a} - -The contents of the \dirname{.hg} directory and its subdirectories are -private to Mercurial. Every other file and directory in the -repository is yours to do with as you please. - -To introduce a little terminology, the \dirname{.hg} directory is the -``real'' repository, and all of the files and directories that coexist -with it are said to live in the \emph{working directory}. An easy way -to remember the distinction is that the \emph{repository} contains the -\emph{history} of your project, while the \emph{working directory} -contains a \emph{snapshot} of your project at a particular point in -history. - -\section{A tour through history} - -One of the first things we might want to do with a new, unfamiliar -repository is understand its history. The \hgcmd{log} command gives -us a view of history. -\interaction{tour.log} -By default, this command prints a brief paragraph of output for each -change to the project that was recorded. In Mercurial terminology, we -call each of these recorded events a \emph{changeset}, because it can -contain a record of changes to several files. - -The fields in a record of output from \hgcmd{log} are as follows. -\begin{itemize} -\item[\texttt{changeset}] This field has the format of a number, - followed by a colon, followed by a hexadecimal string. These are - \emph{identifiers} for the changeset. There are two identifiers - because the number is shorter and easier to type than the hex - string. -\item[\texttt{user}] The identity of the person who created the - changeset. This is a free-form field, but it most often contains a - person's name and email address. -\item[\texttt{date}] The date and time on which the changeset was - created, and the timezone in which it was created. (The date and - time are local to that timezone; they display what time and date it - was for the person who created the changeset.) -\item[\texttt{summary}] The first line of the text message that the - creator of the changeset entered to describe the changeset. -\end{itemize} -The default output printed by \hgcmd{log} is purely a summary; it is -missing a lot of detail. - -Figure~\ref{fig:tour-basic:history} provides a graphical representation of -the history of the \dirname{hello} repository, to make it a little -easier to see which direction history is ``flowing'' in. We'll be -returning to this figure several times in this chapter and the chapter -that follows. - -\begin{figure}[ht] - \centering - \grafix{tour-history} - \caption{Graphical history of the \dirname{hello} repository} - \label{fig:tour-basic:history} -\end{figure} - -\subsection{Changesets, revisions, and talking to other - people} - -As English is a notoriously sloppy language, and computer science has -a hallowed history of terminological confusion (why use one term when -four will do?), revision control has a variety of words and phrases -that mean the same thing. If you are talking about Mercurial history -with other people, you will find that the word ``changeset'' is often -compressed to ``change'' or (when written) ``cset'', and sometimes a -changeset is referred to as a ``revision'' or a ``rev''. - -While it doesn't matter what \emph{word} you use to refer to the -concept of ``a~changeset'', the \emph{identifier} that you use to -refer to ``a~\emph{specific} changeset'' is of great importance. -Recall that the \texttt{changeset} field in the output from -\hgcmd{log} identifies a changeset using both a number and a -hexadecimal string. -\begin{itemize} -\item The revision number is \emph{only valid in that repository}, -\item while the hex string is the \emph{permanent, unchanging - identifier} that will always identify that exact changeset in - \emph{every} copy of the repository. -\end{itemize} -This distinction is important. If you send someone an email talking -about ``revision~33'', there's a high likelihood that their -revision~33 will \emph{not be the same} as yours. The reason for this -is that a revision number depends on the order in which changes -arrived in a repository, and there is no guarantee that the same -changes will happen in the same order in different repositories. -Three changes $a,b,c$ can easily appear in one repository as $0,1,2$, -while in another as $1,0,2$. - -Mercurial uses revision numbers purely as a convenient shorthand. If -you need to discuss a changeset with someone, or make a record of a -changeset for some other reason (for example, in a bug report), use -the hexadecimal identifier. - -\subsection{Viewing specific revisions} - -To narrow the output of \hgcmd{log} down to a single revision, use the -\hgopt{log}{-r} (or \hgopt{log}{--rev}) option. You can use either a -revision number or a long-form changeset identifier, and you can -provide as many revisions as you want. \interaction{tour.log-r} - -If you want to see the history of several revisions without having to -list each one, you can use \emph{range notation}; this lets you -express the idea ``I want all revisions between $a$ and $b$, -inclusive''. -\interaction{tour.log.range} -Mercurial also honours the order in which you specify revisions, so -\hgcmdargs{log}{-r 2:4} prints $2,3,4$ while \hgcmdargs{log}{-r 4:2} -prints $4,3,2$. - -\subsection{More detailed information} - -While the summary information printed by \hgcmd{log} is useful if you -already know what you're looking for, you may need to see a complete -description of the change, or a list of the files changed, if you're -trying to decide whether a changeset is the one you're looking for. -The \hgcmd{log} command's \hggopt{-v} (or \hggopt{--verbose}) -option gives you this extra detail. -\interaction{tour.log-v} - -If you want to see both the description and content of a change, add -the \hgopt{log}{-p} (or \hgopt{log}{--patch}) option. This displays -the content of a change as a \emph{unified diff} (if you've never seen -a unified diff before, see section~\ref{sec:mq:patch} for an overview). -\interaction{tour.log-vp} - -\section{All about command options} - -Let's take a brief break from exploring Mercurial commands to discuss -a pattern in the way that they work; you may find this useful to keep -in mind as we continue our tour. - -Mercurial has a consistent and straightforward approach to dealing -with the options that you can pass to commands. It follows the -conventions for options that are common to modern Linux and Unix -systems. -\begin{itemize} -\item Every option has a long name. For example, as we've already - seen, the \hgcmd{log} command accepts a \hgopt{log}{--rev} option. -\item Most options have short names, too. Instead of - \hgopt{log}{--rev}, we can use \hgopt{log}{-r}. (The reason that - some options don't have short names is that the options in question - are rarely used.) -\item Long options start with two dashes (e.g.~\hgopt{log}{--rev}), - while short options start with one (e.g.~\hgopt{log}{-r}). -\item Option naming and usage is consistent across commands. For - example, every command that lets you specify a changeset~ID or - revision number accepts both \hgopt{log}{-r} and \hgopt{log}{--rev} - arguments. -\end{itemize} -In the examples throughout this book, I use short options instead of -long. This just reflects my own preference, so don't read anything -significant into it. - -Most commands that print output of some kind will print more output -when passed a \hggopt{-v} (or \hggopt{--verbose}) option, and less -when passed \hggopt{-q} (or \hggopt{--quiet}). - -\section{Making and reviewing changes} - -Now that we have a grasp of viewing history in Mercurial, let's take a -look at making some changes and examining them. - -The first thing we'll do is isolate our experiment in a repository of -its own. We use the \hgcmd{clone} command, but we don't need to -clone a copy of the remote repository. Since we already have a copy -of it locally, we can just clone that instead. This is much faster -than cloning over the network, and cloning a local repository uses -less disk space in most cases, too. -\interaction{tour.reclone} -As an aside, it's often good practice to keep a ``pristine'' copy of a -remote repository around, which you can then make temporary clones of -to create sandboxes for each task you want to work on. This lets you -work on multiple tasks in parallel, each isolated from the others -until it's complete and you're ready to integrate it back. Because -local clones are so cheap, there's almost no overhead to cloning and -destroying repositories whenever you want. - -In our \dirname{my-hello} repository, we have a file -\filename{hello.c} that contains the classic ``hello, world'' program. -Let's use the ancient and venerable \command{sed} command to edit this -file so that it prints a second line of output. (I'm only using -\command{sed} to do this because it's easy to write a scripted example -this way. Since you're not under the same constraint, you probably -won't want to use \command{sed}; simply use your preferred text editor to -do the same thing.) -\interaction{tour.sed} - -Mercurial's \hgcmd{status} command will tell us what Mercurial knows -about the files in the repository. -\interaction{tour.status} -The \hgcmd{status} command prints no output for some files, but a line -starting with ``\texttt{M}'' for \filename{hello.c}. Unless you tell -it to, \hgcmd{status} will not print any output for files that have -not been modified. - -The ``\texttt{M}'' indicates that Mercurial has noticed that we -modified \filename{hello.c}. We didn't need to \emph{inform} -Mercurial that we were going to modify the file before we started, or -that we had modified the file after we were done; it was able to -figure this out itself. - -It's a little bit helpful to know that we've modified -\filename{hello.c}, but we might prefer to know exactly \emph{what} -changes we've made to it. To do this, we use the \hgcmd{diff} -command. -\interaction{tour.diff} - -\section{Recording changes in a new changeset} - -We can modify files, build and test our changes, and use -\hgcmd{status} and \hgcmd{diff} to review our changes, until we're -satisfied with what we've done and arrive at a natural stopping point -where we want to record our work in a new changeset. - -The \hgcmd{commit} command lets us create a new changeset; we'll -usually refer to this as ``making a commit'' or ``committing''. - -\subsection{Setting up a username} - -When you try to run \hgcmd{commit} for the first time, it is not -guaranteed to succeed. Mercurial records your name and address with -each change that you commit, so that you and others will later be able -to tell who made each change. Mercurial tries to automatically figure -out a sensible username to commit the change with. It will attempt -each of the following methods, in order: -\begin{enumerate} -\item If you specify a \hgopt{commit}{-u} option to the \hgcmd{commit} - command on the command line, followed by a username, this is always - given the highest precedence. -\item If you have set the \envar{HGUSER} environment variable, this is - checked next. -\item If you create a file in your home directory called - \sfilename{.hgrc}, with a \rcitem{ui}{username} entry, that will be - used next. To see what the contents of this file should look like, - refer to section~\ref{sec:tour-basic:username} below. -\item If you have set the \envar{EMAIL} environment variable, this - will be used next. -\item Mercurial will query your system to find out your local user - name and host name, and construct a username from these components. - Since this often results in a username that is not very useful, it - will print a warning if it has to do this. -\end{enumerate} -If all of these mechanisms fail, Mercurial will fail, printing an -error message. In this case, it will not let you commit until you set -up a username. - -You should think of the \envar{HGUSER} environment variable and the -\hgopt{commit}{-u} option to the \hgcmd{commit} command as ways to -\emph{override} Mercurial's default selection of username. For normal -use, the simplest and most robust way to set a username for yourself -is by creating a \sfilename{.hgrc} file; see below for details. - -\subsubsection{Creating a Mercurial configuration file} -\label{sec:tour-basic:username} - -To set a user name, use your favourite editor to create a file called -\sfilename{.hgrc} in your home directory. Mercurial will use this -file to look up your personalised configuration settings. The initial -contents of your \sfilename{.hgrc} should look like this. -\begin{codesample2} - # This is a Mercurial configuration file. - [ui] - username = Firstname Lastname -\end{codesample2} -The ``\texttt{[ui]}'' line begins a \emph{section} of the config file, -so you can read the ``\texttt{username = ...}'' line as meaning ``set -the value of the \texttt{username} item in the \texttt{ui} section''. -A section continues until a new section begins, or the end of the -file. Mercurial ignores empty lines and treats any text from -``\texttt{\#}'' to the end of a line as a comment. - -\subsubsection{Choosing a user name} - -You can use any text you like as the value of the \texttt{username} -config item, since this information is for reading by other people, -but for interpreting by Mercurial. The convention that most people -follow is to use their name and email address, as in the example -above. - -\begin{note} - Mercurial's built-in web server obfuscates email addresses, to make - it more difficult for the email harvesting tools that spammers use. - This reduces the likelihood that you'll start receiving more junk - email if you publish a Mercurial repository on the web. -\end{note} - -\subsection{Writing a commit message} - -When we commit a change, Mercurial drops us into a text editor, to -enter a message that will describe the modifications we've made in -this changeset. This is called the \emph{commit message}. It will be -a record for readers of what we did and why, and it will be printed by -\hgcmd{log} after we've finished committing. -\interaction{tour.commit} - -The editor that the \hgcmd{commit} command drops us into will contain -an empty line, followed by a number of lines starting with -``\texttt{HG:}''. -\begin{codesample2} - \emph{empty line} - HG: changed hello.c -\end{codesample2} -Mercurial ignores the lines that start with ``\texttt{HG:}''; it uses -them only to tell us which files it's recording changes to. Modifying -or deleting these lines has no effect. - -\subsection{Writing a good commit message} - -Since \hgcmd{log} only prints the first line of a commit message by -default, it's best to write a commit message whose first line stands -alone. Here's a real example of a commit message that \emph{doesn't} -follow this guideline, and hence has a summary that is not readable. -\begin{codesample2} - changeset: 73:584af0e231be - user: Censored Person - date: Tue Sep 26 21:37:07 2006 -0700 - summary: include buildmeister/commondefs. Add an exports and install -\end{codesample2} - -As far as the remainder of the contents of the commit message are -concerned, there are no hard-and-fast rules. Mercurial itself doesn't -interpret or care about the contents of the commit message, though -your project may have policies that dictate a certain kind of -formatting. - -My personal preference is for short, but informative, commit messages -that tell me something that I can't figure out with a quick glance at -the output of \hgcmdargs{log}{--patch}. - -\subsection{Aborting a commit} - -If you decide that you don't want to commit while in the middle of -editing a commit message, simply exit from your editor without saving -the file that it's editing. This will cause nothing to happen to -either the repository or the working directory. - -If we run the \hgcmd{commit} command without any arguments, it records -all of the changes we've made, as reported by \hgcmd{status} and -\hgcmd{diff}. - -\subsection{Admiring our new handiwork} - -Once we've finished the commit, we can use the \hgcmd{tip} command to -display the changeset we just created. This command produces output -that is identical to \hgcmd{log}, but it only displays the newest -revision in the repository. -\interaction{tour.tip} -We refer to the newest revision in the repository as the tip revision, -or simply the tip. - -\section{Sharing changes} - -We mentioned earlier that repositories in Mercurial are -self-contained. This means that the changeset we just created exists -only in our \dirname{my-hello} repository. Let's look at a few ways -that we can propagate this change into other repositories. - -\subsection{Pulling changes from another repository} -\label{sec:tour:pull} - -To get started, let's clone our original \dirname{hello} repository, -which does not contain the change we just committed. We'll call our -temporary repository \dirname{hello-pull}. -\interaction{tour.clone-pull} - -We'll use the \hgcmd{pull} command to bring changes from -\dirname{my-hello} into \dirname{hello-pull}. However, blindly -pulling unknown changes into a repository is a somewhat scary -prospect. Mercurial provides the \hgcmd{incoming} command to tell us -what changes the \hgcmd{pull} command \emph{would} pull into the -repository, without actually pulling the changes in. -\interaction{tour.incoming} -(Of course, someone could cause more changesets to appear in the -repository that we ran \hgcmd{incoming} in, before we get a chance to -\hgcmd{pull} the changes, so that we could end up pulling changes that we -didn't expect.) - -Bringing changes into a repository is a simple matter of running the -\hgcmd{pull} command, and telling it which repository to pull from. -\interaction{tour.pull} -As you can see from the before-and-after output of \hgcmd{tip}, we -have successfully pulled changes into our repository. There remains -one step before we can see these changes in the working directory. - -\subsection{Updating the working directory} - -We have so far glossed over the relationship between a repository and -its working directory. The \hgcmd{pull} command that we ran in -section~\ref{sec:tour:pull} brought changes into the repository, but -if we check, there's no sign of those changes in the working -directory. This is because \hgcmd{pull} does not (by default) touch -the working directory. Instead, we use the \hgcmd{update} command to -do this. -\interaction{tour.update} - -It might seem a bit strange that \hgcmd{pull} doesn't update the -working directory automatically. There's actually a good reason for -this: you can use \hgcmd{update} to update the working directory to -the state it was in at \emph{any revision} in the history of the -repository. If you had the working directory updated to an old -revision---to hunt down the origin of a bug, say---and ran a -\hgcmd{pull} which automatically updated the working directory to a -new revision, you might not be terribly happy. - -However, since pull-then-update is such a common thing to do, -Mercurial lets you combine the two by passing the \hgopt{pull}{-u} -option to \hgcmd{pull}. -\begin{codesample2} - hg pull -u -\end{codesample2} -If you look back at the output of \hgcmd{pull} in -section~\ref{sec:tour:pull} when we ran it without \hgopt{pull}{-u}, -you can see that it printed a helpful reminder that we'd have to take -an explicit step to update the working directory: -\begin{codesample2} - (run 'hg update' to get a working copy) -\end{codesample2} - -To find out what revision the working directory is at, use the -\hgcmd{parents} command. -\interaction{tour.parents} -If you look back at figure~\ref{fig:tour-basic:history}, you'll see -arrows connecting each changeset. The node that the arrow leads -\emph{from} in each case is a parent, and the node that the arrow -leads \emph{to} is its child. The working directory has a parent in -just the same way; this is the changeset that the working directory -currently contains. - -To update the working directory to a particular revision, give a -revision number or changeset~ID to the \hgcmd{update} command. -\interaction{tour.older} -If you omit an explicit revision, \hgcmd{update} will update to the -tip revision, as shown by the second call to \hgcmd{update} in the -example above. - -\subsection{Pushing changes to another repository} - -Mercurial lets us push changes to another repository, from the -repository we're currently visiting. As with the example of -\hgcmd{pull} above, we'll create a temporary repository to push our -changes into. -\interaction{tour.clone-push} -The \hgcmd{outgoing} command tells us what changes would be pushed -into another repository. -\interaction{tour.outgoing} -And the \hgcmd{push} command does the actual push. -\interaction{tour.push} -As with \hgcmd{pull}, the \hgcmd{push} command does not update the -working directory in the repository that it's pushing changes into. -(Unlike \hgcmd{pull}, \hgcmd{push} does not provide a \texttt{-u} -option that updates the other repository's working directory.) - -What happens if we try to pull or push changes and the receiving -repository already has those changes? Nothing too exciting. -\interaction{tour.push.nothing} - -\subsection{Sharing changes over a network} - -The commands we have covered in the previous few sections are not -limited to working with local repositories. Each works in exactly the -same fashion over a network connection; simply pass in a URL instead -of a local path. -\interaction{tour.outgoing.net} -In this example, we can see what changes we could push to the remote -repository, but the repository is understandably not set up to let -anonymous users push to it. -\interaction{tour.push.net} - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: "00book" -%%% End: + + + + + A tour of Mercurial: the basics + + + Installing Mercurial on your system + + Prebuilt binary packages of Mercurial are available for + every popular operating system. These make it easy to start + using Mercurial on your computer immediately. + + + Windows + + The best version of Mercurial for Windows is + TortoiseHg, which can be found at http://bitbucket.org/tortoisehg/stable/wiki/Home. + This package has no external dependencies; it just + works. It provides both command line and graphical + user interfaces. + + + + + Mac OS X + + Lee Cantey publishes an installer of Mercurial + for Mac OS X at http://mercurial.berkwood.com. + + + + Linux + + Because each Linux distribution has its own packaging + tools, policies, and rate of development, it's difficult to + give a comprehensive set of instructions on how to install + Mercurial binaries. The version of Mercurial that you will + end up with can vary depending on how active the person is who + maintains the package for your distribution. + + To keep things simple, I will focus on installing + Mercurial from the command line under the most popular Linux + distributions. Most of these distributions provide graphical + package managers that will let you install Mercurial with a + single click; the package name to look for is + mercurial. + + + Ubuntu and Debian: + apt-get install mercurial + Fedora: + yum install mercurial + OpenSUSE: + zypper install mercurial + Gentoo: + emerge mercurial + + + + + Solaris + + SunFreeWare, at http://www.sunfreeware.com, + provides prebuilt packages of Mercurial. + + + + + + + Getting started + + To begin, we'll use the hg + version command to find out whether Mercurial is + installed properly. The actual version information that it + prints isn't so important; we simply care whether the command + runs and prints anything at all. + + &interaction.tour.version; + + + Built-in help + + Mercurial provides a built-in help system. This is + invaluable for those times when you find yourself stuck + trying to remember how to run a command. If you are + completely stuck, simply run hg + help; it will print a brief list of commands, + along with a description of what each does. If you ask for + help on a specific command (as below), it prints more + detailed information. + + &interaction.tour.help; + + For a more impressive level of detail (which you won't + usually need) run hg help . The option is short for + , and tells + Mercurial to print more information than it usually + would. + + + + + Working with a repository + + In Mercurial, everything happens inside a + repository. The repository for a project + contains all of the files that belong to that + project, along with a historical record of the project's + files. + + There's nothing particularly magical about a repository; it + is simply a directory tree in your filesystem that Mercurial + treats as special. You can rename or delete a repository any + time you like, using either the command line or your file + browser. + + + Making a local copy of a repository + + Copying a repository is just a little + bit special. While you could use a normal file copying + command to make a copy of a repository, it's best to use a + built-in command that Mercurial provides. This command is + called hg clone, because it + makes an identical copy of an existing repository. + + &interaction.tour.clone; + + One advantage of using hg + clone is that, as we can see above, it lets us clone + repositories over the network. Another is that it remembers + where we cloned from, which we'll find useful soon when we + want to fetch new changes from another repository. + + If our clone succeeded, we should now have a local + directory called hello. + This directory will contain some files. + + &interaction.tour.ls; + + These files have the same contents and history in our + repository as they do in the repository we cloned. + + Every Mercurial repository is complete, + self-contained, and independent. It contains its own private + copy of a project's files and history. As we just mentioned, + a cloned repository remembers the location of the repository + it was cloned from, but Mercurial will not communicate with + that repository, or any other, unless you tell it to. + + What this means for now is that we're free to experiment + with our repository, safe in the knowledge that it's a private + sandbox that won't affect anyone else. + + + + What's in a repository? + + When we take a more detailed look inside a repository, we + can see that it contains a directory named .hg. This is where Mercurial + keeps all of its metadata for the repository. + + &interaction.tour.ls-a; + + The contents of the .hg directory and its + subdirectories are private to Mercurial. Every other file and + directory in the repository is yours to do with as you + please. + + To introduce a little terminology, the .hg directory is the + real repository, and all of the files and + directories that coexist with it are said to live in the + working directory. An easy way to + remember the distinction is that the + repository contains the + history of your project, while the + working directory contains a + snapshot of your project at a particular + point in history. + + + + + A tour through history + + One of the first things we might want to do with a new, + unfamiliar repository is understand its history. The hg log command gives us a view of + the history of changes in the repository. + + &interaction.tour.log; + + By default, this command prints a brief paragraph of output + for each change to the project that was recorded. In Mercurial + terminology, we call each of these recorded events a + changeset, because it can contain a record + of changes to several files. + + The fields in a record of output from hg log are as follows. + + + changeset: This + field has the format of a number, followed by a colon, + followed by a hexadecimal (or hex) + string. These are identifiers for the + changeset. The hex string is a unique identifier: the same + hex string will always refer to the same changeset in every + copy of this repository. The + number is shorter and easier to type than the hex string, + but it isn't unique: the same number in two different clones + of a repository may identify different changesets. + + user: The identity of the + person who created the changeset. This is a free-form + field, but it most often contains a person's name and email + address. + date: The date and time on + which the changeset was created, and the timezone in which + it was created. (The date and time are local to that + timezone; they display what time and date it was for the + person who created the changeset.) + summary: The first line of + the text message that the creator of the changeset entered + to describe the changeset. + + Some changesets, such as the first in the list above, + have a tag field. A tag is another way + to identify a changeset, by giving it an easy-to-remember + name. (The tag named tip is special: it + always refers to the newest change in a repository.) + + + + The default output printed by hg log is purely a summary; it is + missing a lot of detail. + + provides + a graphical representation of the history of the hello repository, to make it a + little easier to see which direction history is + flowing in. We'll be returning to this figure + several times in this chapter and the chapter that + follows. + +
+ Graphical history of the <filename + class="directory">hello</filename> repository + + + XXX add text + +
+ + + Changesets, revisions, and talking to other + people + + As English is a notoriously sloppy language, and computer + science has a hallowed history of terminological confusion + (why use one term when four will do?), revision control has a + variety of words and phrases that mean the same thing. If you + are talking about Mercurial history with other people, you + will find that the word changeset is often + compressed to change or (when written) + cset, and sometimes a changeset is referred to + as a revision or a rev. + + While it doesn't matter what word you + use to refer to the concept of a changeset, the + identifier that you use to refer to + a specific changeset is of + great importance. Recall that the changeset + field in the output from hg + log identifies a changeset using both a number and + a hexadecimal string. + + The revision number is a handy + notation that is only valid in that + repository. + The hexadecimal string is the + permanent, unchanging identifier that + will always identify that exact changeset in + every copy of the + repository. + + This distinction is important. If you send + someone an email talking about revision 33, + there's a high likelihood that their revision 33 will + not be the same as yours. The reason for + this is that a revision number depends on the order in which + changes arrived in a repository, and there is no guarantee + that the same changes will happen in the same order in + different repositories. Three changes a,b,c + can easily appear in one repository as + 0,1,2, while in another as + 0,2,1. + + Mercurial uses revision numbers purely as a convenient + shorthand. If you need to discuss a changeset with someone, + or make a record of a changeset for some other reason (for + example, in a bug report), use the hexadecimal + identifier. + + + + Viewing specific revisions + + To narrow the output of hg + log down to a single revision, use the (or ) option. You can use + either a revision number or a hexadecimal identifier, + and you can provide as many revisions as you want. + + &interaction.tour.log-r; + + If you want to see the history of several revisions + without having to list each one, you can use range + notation; this lets you express the idea I + want all revisions between abc and + def, inclusive. + + &interaction.tour.log.range; + + Mercurial also honours the order in which you specify + revisions, so hg log -r 2:4 + prints 2, 3, and 4. while hg log -r + 4:2 prints 4, 3, and 2. + + + + More detailed information + + While the summary information printed by hg log is useful if you already know + what you're looking for, you may need to see a complete + description of the change, or a list of the files changed, if + you're trying to decide whether a changeset is the one you're + looking for. The hg log + command's (or ) option gives you + this extra detail. + + &interaction.tour.log-v; + + If you want to see both the description and + content of a change, add the (or ) option. This displays + the content of a change as a unified diff + (if you've never seen a unified diff before, see for an overview). + + &interaction.tour.log-vp; + + The option is + tremendously useful, so it's well worth remembering. + + +
+ + + All about command options + + Let's take a brief break from exploring Mercurial commands + to discuss a pattern in the way that they work; you may find + this useful to keep in mind as we continue our tour. + + Mercurial has a consistent and straightforward approach to + dealing with the options that you can pass to commands. It + follows the conventions for options that are common to modern + Linux and Unix systems. + + + + Every option has a long name. For example, as + we've already seen, the hg + log command accepts a option. + + + Most options have short names, too. Instead + of , we can use + . (The reason that + some options don't have short names is that the options in + question are rarely used.) + + + Long options start with two dashes (e.g. + ), while short + options start with one (e.g. ). + + + Option naming and usage is consistent across + commands. For example, every command that lets you specify + a changeset ID or revision number accepts both and arguments. + + + If you are using short options, you can save typing by + running them together. For example, the command hg log -v -p -r 2 can be written + as hg log -vpr2. + + + + In the examples throughout this book, I usually + use short options instead of long. This simply reflects my own + preference, so don't read anything significant into it. + + Most commands that print output of some kind will print more + output when passed a + (or ) option, and + less when passed (or + ). + + + Option naming consistency + + Almost always, Mercurial commands use consistent option + names to refer to the same concepts. For instance, if a + command deals with changesets, you'll always identify them + with or . This consistent use of + option names makes it easier to remember what options a + particular command takes. + + + + + Making and reviewing changes + + Now that we have a grasp of viewing history in Mercurial, + let's take a look at making some changes and examining + them. + + The first thing we'll do is isolate our experiment in a + repository of its own. We use the hg + clone command, but we don't need to clone a copy of + the remote repository. Since we already have a copy of it + locally, we can just clone that instead. This is much faster + than cloning over the network, and cloning a local repository + uses less disk space in most cases, too + The saving of space arises when source and destination + repositories are on the same filesystem, in which case + Mercurial will use hardlinks to do copy-on-write sharing of + its internal metadata. If that explanation meant nothing to + you, don't worry: everything happens transparently and + automatically, and you don't need to understand it. + . + + &interaction.tour.reclone; + + As an aside, it's often good practice to keep a + pristine copy of a remote repository around, + which you can then make temporary clones of to create sandboxes + for each task you want to work on. This lets you work on + multiple tasks in parallel, each isolated from the others until + it's complete and you're ready to integrate it back. Because + local clones are so cheap, there's almost no overhead to cloning + and destroying repositories whenever you want. + + In our my-hello + repository, we have a file hello.c that + contains the classic hello, world program. + + &interaction.tour.cat1; + + Let's edit this file so that it prints a second line of + output. + + &interaction.tour.cat2; + + Mercurial's hg status + command will tell us what Mercurial knows about the files in the + repository. + + &interaction.tour.status; + + The hg status command + prints no output for some files, but a line starting with + M for + hello.c. Unless you tell it to, hg status will not print any output + for files that have not been modified. + + The M indicates that + Mercurial has noticed that we modified + hello.c. We didn't need to + inform Mercurial that we were going to + modify the file before we started, or that we had modified the + file after we were done; it was able to figure this out + itself. + + It's somewhat helpful to know that we've modified + hello.c, but we might prefer to know + exactly what changes we've made to it. To + do this, we use the hg diff + command. + + &interaction.tour.diff; + + + Understanding patches + + Remember to take a look at if you don't know how to read + output above. + + + + Recording changes in a new changeset + + We can modify files, build and test our changes, and use + hg status and hg diff to review our changes, until + we're satisfied with what we've done and arrive at a natural + stopping point where we want to record our work in a new + changeset. + + The hg commit command lets + us create a new changeset; we'll usually refer to this as + making a commit or + committing. + + + Setting up a username + + When you try to run hg + commit for the first time, it is not guaranteed to + succeed. Mercurial records your name and address with each + change that you commit, so that you and others will later be + able to tell who made each change. Mercurial tries to + automatically figure out a sensible username to commit the + change with. It will attempt each of the following methods, + in order: + + If you specify a option to the hg commit command on the command + line, followed by a username, this is always given the + highest precedence. + If you have set the HGUSER + environment variable, this is checked + next. + If you create a file in your home + directory called .hgrc, with a username entry, that will be + used next. To see what the contents of this file should + look like, refer to + below. + If you have set the EMAIL + environment variable, this will be used + next. + Mercurial will query your system to find out + your local user name and host name, and construct a + username from these components. Since this often results + in a username that is not very useful, it will print a + warning if it has to do + this. + + If all of these mechanisms fail, Mercurial will + fail, printing an error message. In this case, it will not + let you commit until you set up a + username. + You should think of the HGUSER environment + variable and the + option to the hg commit + command as ways to override Mercurial's + default selection of username. For normal use, the simplest + and most robust way to set a username for yourself is by + creating a .hgrc file; see + below for details. + + Creating a Mercurial configuration file + + To set a user name, use your favorite editor + to create a file called .hgrc in your home directory. + Mercurial will use this file to look up your personalised + configuration settings. The initial contents of your + .hgrc should look like + this. + + + <quote>Home directory</quote> on Windows + + When we refer to your home directory, on an English + language installation of Windows this will usually be a + folder named after your user name in + C:\Documents and Settings. You can + find out the exact name of your home directory by opening + a command prompt window and running the following + command. + + C:\> echo %UserProfile% + + + # This is a Mercurial configuration file. +[ui] +username = Firstname Lastname <email.address@example.net> + + The [ui] line begins a + section of the config file, so you can + read the username = ... + line as meaning set the value of the + username item in the + ui section. A section continues + until a new section begins, or the end of the file. + Mercurial ignores empty lines and treats any text from + # to the end of a line as + a comment. + + + + Choosing a user name + + You can use any text you like as the value of + the username config item, since this + information is for reading by other people, but will not be + interpreted by Mercurial. The convention that most people + follow is to use their name and email address, as in the + example above. + + Mercurial's built-in web server obfuscates + email addresses, to make it more difficult for the email + harvesting tools that spammers use. This reduces the + likelihood that you'll start receiving more junk email if + you publish a Mercurial repository on the + web. + + + + Writing a commit message + + When we commit a change, Mercurial drops us into + a text editor, to enter a message that will describe the + modifications we've made in this changeset. This is called + the commit message. It will be a record + for readers of what we did and why, and it will be printed by + hg log after we've finished + committing. + + &interaction.tour.commit; + + The editor that the hg + commit command drops us into will contain an empty + line or two, followed by a number of lines starting with + HG:. + + +This is where I type my commit comment. + +HG: Enter commit message. Lines beginning with 'HG:' are removed. +HG: -- +HG: user: Bryan O'Sullivan <bos@serpentine.com> +HG: branch 'default' +HG: changed hello.c + + Mercurial ignores the lines that start with + HG:; it uses them only to + tell us which files it's recording changes to. Modifying or + deleting these lines has no effect. + + + Writing a good commit message + + Since hg log + only prints the first line of a commit message by default, + it's best to write a commit message whose first line stands + alone. Here's a real example of a commit message that + doesn't follow this guideline, and hence + has a summary that is not readable. + + +changeset: 73:584af0e231be +user: Censored Person <censored.person@example.org> +date: Tue Sep 26 21:37:07 2006 -0700 +summary: include buildmeister/commondefs. Add exports. + + As far as the remainder of the contents of the + commit message are concerned, there are no hard-and-fast + rules. Mercurial itself doesn't interpret or care about the + contents of the commit message, though your project may have + policies that dictate a certain kind of formatting. + My personal preference is for short, but + informative, commit messages that tell me something that I + can't figure out with a quick glance at the output of hg log --patch. + If we run the hg + commit command without any arguments, it records + all of the changes we've made, as reported by hg status and hg diff. + + + A surprise for Subversion users + + Like other Mercurial commands, if we don't supply + explicit names to commit to the hg + commit, it will operate across a repository's + entire working directory. Be wary of this if you're coming + from the Subversion or CVS world, since you might expect it + to operate only on the current directory that you happen to + be visiting and its subdirectories. + + + + + Aborting a commit + + If you decide that you don't want to commit + while in the middle of editing a commit message, simply exit + from your editor without saving the file that it's editing. + This will cause nothing to happen to either the repository or + the working directory. + + + + Admiring our new handiwork + + Once we've finished the commit, we can use the + hg tip command to display the + changeset we just created. This command produces output that + is identical to hg log, but + it only displays the newest revision in the repository. + + &interaction.tour.tip; + + We refer to the newest revision in the + repository as the tip revision, or simply + the tip. + + By the way, the hg tip + command accepts many of the same options as hg log, so above indicates be + verbose, + specifies print a patch. The use of to print patches is another + example of the consistent naming we mentioned earlier. + + + + + Sharing changes + + We mentioned earlier that repositories in + Mercurial are self-contained. This means that the changeset we + just created exists only in our my-hello repository. Let's look + at a few ways that we can propagate this change into other + repositories. + + + Pulling changes from another repository + + To get started, let's clone our original + hello repository, which + does not contain the change we just committed. We'll call our + temporary repository hello-pull. + + &interaction.tour.clone-pull; + + We'll use the hg + pull command to bring changes from my-hello into hello-pull. However, blindly + pulling unknown changes into a repository is a somewhat scary + prospect. Mercurial provides the hg + incoming command to tell us what changes the + hg pull command + would pull into the repository, without + actually pulling the changes in. + + &interaction.tour.incoming; + + Bringing changes into a repository is a simple + matter of running the hg pull + command, and optionally telling it which repository to pull from. + + &interaction.tour.pull; + + As you can see from the before-and-after output + of hg tip, we have + successfully pulled changes into our repository. However, + Mercurial separates pulling changes in from updating the + working directory. There remains one step before we will see + the changes that we just pulled appear in the working + directory. + + + Pulling specific changes + + It is possible that due to the delay between + running hg incoming and + hg pull, you may not see + all changesets that will be brought from the other + repository. Suppose you're pulling changes from a repository + on the network somewhere. While you are looking at the + hg incoming output, and + before you pull those changes, someone might have committed + something in the remote repository. This means that it's + possible to pull more changes than you saw when using + hg incoming. + + If you only want to pull precisely the changes that were + listed by hg incoming, or + you have some other reason to pull a subset of changes, + simply identify the change that you want to pull by its + changeset ID, e.g. hg pull + -r7e95bb. + + + + + Updating the working directory + + We have so far glossed over the relationship + between a repository and its working directory. The hg pull command that we ran in + brought changes into the + repository, but if we check, there's no sign of those changes + in the working directory. This is because hg pull does not (by default) touch + the working directory. Instead, we use the hg update command to do this. + + &interaction.tour.update; + + It might seem a bit strange that hg pull doesn't update the working + directory automatically. There's actually a good reason for + this: you can use hg update + to update the working directory to the state it was in at + any revision in the history of the + repository. If you had the working directory updated to an + old revision&emdash;to hunt down the origin of a bug, + say&emdash;and ran a hg pull + which automatically updated the working directory to a new + revision, you might not be terribly happy. + + Since pull-then-update is such a common sequence + of operations, Mercurial lets you combine the two by passing + the option to hg pull. + + If you look back at the output of hg pull in when we ran it without , you can see that it printed + a helpful reminder that we'd have to take an explicit step to + update the working directory. + + To find out what revision the working directory + is at, use the hg parents + command. + + &interaction.tour.parents; + + If you look back at , you'll see arrows + connecting each changeset. The node that the arrow leads + from in each case is a parent, and the + node that the arrow leads to is its + child. The working directory has a parent in just the same + way; this is the changeset that the working directory + currently contains. + + To update the working directory to a particular + revision, give a revision number or changeset ID to the + hg update command. + + &interaction.tour.older; + + If you omit an explicit revision, hg update will update to the tip + revision, as shown by the second call to hg update in the example + above. + + + + Pushing changes to another repository + + Mercurial lets us push changes to another + repository, from the repository we're currently visiting. As + with the example of hg pull + above, we'll create a temporary repository to push our changes + into. + + &interaction.tour.clone-push; + + The hg outgoing + command tells us what changes would be pushed into another + repository. + + &interaction.tour.outgoing; + + And the hg push + command does the actual push. + + &interaction.tour.push; + + As with hg + pull, the hg push + command does not update the working directory in the + repository that it's pushing changes into. Unlike hg pull, hg + push does not provide a -u + option that updates the other repository's working directory. + This asymmetry is deliberate: the repository we're pushing to + might be on a remote server and shared between several people. + If we were to update its working directory while someone was + working in it, their work would be disrupted. + + What happens if we try to pull or push changes + and the receiving repository already has those changes? + Nothing too exciting. + + &interaction.tour.push.nothing; + + + + Default locations + + When we clone a repository, Mercurial records the location + of the repository we cloned in the + .hg/hgrc file of the new repository. If + we don't supply a location to hg pull from + or hg push to, those commands will use this + location as a default. The hg incoming + and hg outgoing commands do so too. + + If you open a repository's .hg/hgrc + file in a text editor, you will see contents like the + following. + + [paths] +default = http://www.selenic.com/repo/hg + + It is possible&emdash;and often useful&emdash;to have the + default location for hg push and + hg outgoing be different from those for + hg pull and hg incoming. + We can do this by adding a default-push + entry to the [paths] section of the + .hg/hgrc file, as follows. + + [paths] +default = http://www.selenic.com/repo/hg +default-push = http://hg.example.com/hg + + + + Sharing changes over a network + + The commands we have covered in the previous few + sections are not limited to working with local repositories. + Each works in exactly the same fashion over a network + connection; simply pass in a URL instead of a local + path. + + &interaction.tour.outgoing.net; + + In this example, we can see what changes we + could push to the remote repository, but the repository is + understandably not set up to let anonymous users push to + it. + + &interaction.tour.push.net; + + + + + Starting a new project + + It is just as easy to begin a new project as to work on one + that already exists. The hg init command + creates a new, empty Mercurial repository. + + &interaction.ch01-new.init; + + This simply creates a repository named + myproject in the current directory. + + &interaction.ch01-new.ls; + + We can tell that myproject is a + Mercurial repository, because it contains a + .hg directory. + + &interaction.ch01-new.ls2; + + If we want to add some pre-existing files to the repository, + we copy them into place, and tell Mercurial to start tracking + them using the hg add command. + + &interaction.ch01-new.add; + + Once we are satisfied that our project looks right, we + commit our changes. + + &interaction.ch01-new.commit; + + It takes just a few moments to start using Mercurial on a + new project, which is part of its appeal. Revision control is + now so easy to work with, we can use it on the smallest of + projects that we might not have considered with a more + complicated tool. + +
+ +