Bismillahirrahmannirahhim~
This commit is contained in:
commit
dda7b72891
22 changed files with 9894 additions and 0 deletions
119
_Al_Fatiha.html
Normal file
119
_Al_Fatiha.html
Normal file
|
@ -0,0 +1,119 @@
|
|||
<!-- -*- html -*- -->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Mercurial: The Definitive Guide</title>
|
||||
<link rel="stylesheet" href="/support/styles.css" type="text/css"/>
|
||||
<link rel="alternate" type="application/atom+xml" title="Comments"
|
||||
href="/feeds/comments/"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"/>
|
||||
<script type="text/javascript" src="/support/jquery.js"></script>
|
||||
<script type="text/javascript" src="/support/form.js"></script>
|
||||
<script type="text/javascript" src="/support/hsbook.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="navheader"><h1 class="booktitle">Mercurial: The Definitive Guide<div class="authors">by Bryan O'Sullivan</div></h1></div>
|
||||
|
||||
<div class="book">
|
||||
<h2>Welcome to Mercurial: The Definitive Guide</h2>
|
||||
|
||||
<p>This is the online home of the book “Mercurial: The
|
||||
Definitive Guide”.
|
||||
It was published in 2009 by O'Reilly Media.</p>
|
||||
|
||||
<p><a href="http://www.selenic.com/mercurial">Mercurial</a> is a
|
||||
fast, lightweight source control management system
|
||||
designed for easy and efficient handling of very large distributed
|
||||
projects. My book tells you what it is, why you should care, and
|
||||
how you can use it effectively.</p>
|
||||
|
||||
<h2>Read it online</h2>
|
||||
|
||||
<p>I make the content freely available online: you
|
||||
can <a href="/read/"><i>read it here</i></a>. If you like it,
|
||||
please <a href="#buy">buy a copy</a>!</p>
|
||||
|
||||
<p>For news updates, please
|
||||
visit <a href="http://www.serpentine.com/blog/">my blog</a>. You
|
||||
should follow me on
|
||||
Twitter <a href="http://twitter.com/bos31337">here</a>.</p>
|
||||
|
||||
<h2><a name="#buy">How</a> to buy</h2>
|
||||
|
||||
<p>If you like the book, please support the work of the Software
|
||||
Freedom Conservancy (<a href="#sfc">see below</a>) by buying a
|
||||
copy.</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://www.amazon.com/gp/product/0596800673?ie=UTF8&tag=reaworhas-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0596800673">Amazon.com</a><img src="http://www.assoc-amazon.com/e/ir?t=reaworhas-20&l=as2&o=1&a=0596800673" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></li>
|
||||
<li><a href="http://oreilly.com/catalog/9780596800673/">O'Reilly Media</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>You should contribute!</h2>
|
||||
|
||||
<p>I publish the source code for this book
|
||||
as <a href="http://bitbucket.org/bos/hgbook">a
|
||||
Mercurial repository</a>. Please feel
|
||||
welcome to clone it, make modifications to your copy, and send me
|
||||
changes. Getting a copy of the source takes just a few seconds if
|
||||
you have Mercurial installed:</p>
|
||||
|
||||
<pre class="screen">hg clone http://bitbucket.org/bos/hgbook</pre>
|
||||
|
||||
<p>The online version of the book includes a comment system
|
||||
that you can use to send feedback involving errors, omissions, and
|
||||
suggestions.</p>
|
||||
|
||||
<p>(If you would like to adapt the comment system for a
|
||||
publishing project of your own, the source for the web application
|
||||
is included with the book source at the link above.)</p>
|
||||
|
||||
<h2><a name="sfc">How</a> I help Mercurial and free software, and
|
||||
you can too</h2>
|
||||
|
||||
<p>Mercurial is a member of the <a href="http://conservancy.softwarefreedom.org/">Software Freedom Conservancy</a>, a
|
||||
wonderful non-profit organisation that offers its member projects
|
||||
legal and administrative advice.</p>
|
||||
|
||||
<p>I donate my royalties from the sales of this book to the
|
||||
Software Freedom Conservancy, and I encourage you to support their
|
||||
work, too.</p>
|
||||
|
||||
<p>The SFC can
|
||||
accept <a href="http://conservancy.softwarefreedom.org/?donate">accept
|
||||
donations</a> (tax-free under IRS 501(c)(3), within the United
|
||||
States) on behalf of its member projects. If you would like to
|
||||
support Mercurial directly, please consider making a donation to
|
||||
the SFC on its behalf.</p>
|
||||
|
||||
<p>If you would like to help free software developers to provide
|
||||
their important public services without being impeded by legal
|
||||
issues, please consider donating to the SFC's sister organisation,
|
||||
the <a href="http://www.softwarefreedom.org/">Software Freedom Law
|
||||
Center</a>.</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hgbookfooter"> <p><img src="/support/figs/rss.png"> Want to stay
|
||||
up to date? Subscribe to comment feeds for any chapter, or
|
||||
the <a class="feed"
|
||||
href="/feeds/comments/">entire book</a>.</p> <p>Copyright
|
||||
2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by
|
||||
<a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a
|
||||
href="http://mattahan.deviantart.com/">Mattahan</a>.</p>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script>
|
||||
</body>
|
||||
</html>
|
61
read/_Al_Fatiha.html
Normal file
61
read/_Al_Fatiha.html
Normal file
|
@ -0,0 +1,61 @@
|
|||
<!-- -*- html -*- -->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Mercurial: The Definitive Guide</title>
|
||||
<link rel="stylesheet" href="/support/styles.css" type="text/css"/>
|
||||
<link rel="alternate" type="application/atom+xml" title="Comments"
|
||||
href="/feeds/comments/"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"/>
|
||||
<script type="text/javascript" src="/support/jquery.js"></script>
|
||||
<script type="text/javascript" src="/support/form.js"></script>
|
||||
<script type="text/javascript" src="/support/hsbook.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="navheader"><h1 class="booktitle">Mercurial: The Definitive Guide<div class="authors">by Bryan O'Sullivan</div></h1></div>
|
||||
<div class="book"><ul class="booktoc">
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:preface/"><img src="/support/figs/rss.png"/></a></span>0. <a href="preface.html">Preface</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:intro/"><img src="/support/figs/rss.png"/></a></span>1. <a href="how-did-we-get-here.html">How did we get here?</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:tour-basic/"><img src="/support/figs/rss.png"/></a></span>2. <a href="a-tour-of-mercurial-the-basics.html">A tour of Mercurial: the basics</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:tour-merge/"><img src="/support/figs/rss.png"/></a></span>3. <a href="a-tour-of-mercurial-merging-work.html">A tour of Mercurial: merging work</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:concepts/"><img src="/support/figs/rss.png"/></a></span>4. <a href="behind-the-scenes.html">Behind the scenes</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:daily/"><img src="/support/figs/rss.png"/></a></span>5. <a href="mercurial-in-daily-use.html">Mercurial in daily use</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/cha:collab/"><img src="/support/figs/rss.png"/></a></span>6. <a href="collaborating-with-other-people.html">Collaborating with other people</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:names/"><img src="/support/figs/rss.png"/></a></span>7. <a href="file-names-and-pattern-matching.html">File names and pattern matching</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:branch/"><img src="/support/figs/rss.png"/></a></span>8. <a href="managing-releases-and-branchy-development.html">Managing releases and branchy development</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:undo/"><img src="/support/figs/rss.png"/></a></span>9. <a href="finding-and-fixing-mistakes.html">Finding and fixing mistakes</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:hook/"><img src="/support/figs/rss.png"/></a></span>10. <a href="handling-repository-events-with-hooks.html">Handling repository events with hooks</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:template/"><img src="/support/figs/rss.png"/></a></span>11. <a href="customizing-the-output-of-mercurial.html">Customizing the output of Mercurial</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:mq/"><img src="/support/figs/rss.png"/></a></span>12. <a href="managing-change-with-mercurial-queues.html">Managing change with Mercurial Queues</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:mq-collab/"><img src="/support/figs/rss.png"/></a></span>13. <a href="advanced-uses-of-mercurial-queues.html">Advanced uses of Mercurial Queues</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:hgext/"><img src="/support/figs/rss.png"/></a></span>14. <a href="adding-functionality-with-extensions.html">Adding functionality with extensions</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-04-28<a href="/feeds/comments/svn/"><img src="/support/figs/rss.png"/></a></span>A. <a href="migrating-to-mercurial.html">Migrating to Mercurial</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-04<a href="/feeds/comments/chap:mqref/"><img src="/support/figs/rss.png"/></a></span>B. <a href="mercurial-queues-reference.html">Mercurial Queues reference</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-03-30<a href="/feeds/comments/chap:srcinstall/"><img src="/support/figs/rss.png"/></a></span>C. <a href="installing-mercurial-from-source.html">Installing Mercurial from source</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-03-30<a href="/feeds/comments/cha:opl/"><img src="/support/figs/rss.png"/></a></span>D. <a href="open-publication-license.html">Open Publication License</a></li>
|
||||
</ul></div>
|
||||
|
||||
|
||||
<div class="hgbookfooter"> <p><img src="/support/figs/rss.png"> Want to stay
|
||||
up to date? Subscribe to comment feeds for any chapter, or
|
||||
the <a class="feed"
|
||||
href="/feeds/comments/">entire book</a>.</p> <p>Copyright
|
||||
2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by
|
||||
<a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a
|
||||
href="http://mattahan.deviantart.com/">Mattahan</a>.</p>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script>
|
||||
</body>
|
||||
</html>
|
384
read/a-tour-of-mercurial-merging-work.html
Normal file
384
read/a-tour-of-mercurial-merging-work.html
Normal file
|
@ -0,0 +1,384 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 3. A tour of Mercurial: merging work</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="a-tour-of-mercurial-the-basics.html" title="Chapter 2. A tour of Mercurial: the basics"><link rel="next" href="behind-the-scenes.html" title="Chapter 4. Behind the scenes"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 3. A tour of Mercurial: merging work</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="a-tour-of-mercurial-the-basics.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="behind-the-scenes.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:tour-merge"><div class="titlepage"><div><div><h2 class="title">Chapter 3. A tour of Mercurial: merging work</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="a-tour-of-mercurial-merging-work.html#id352947">Merging streams of work</a></span></dt><dd><dl><dt><span class="sect2"><a href="a-tour-of-mercurial-merging-work.html#id353683">Head changesets</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-merging-work.html#id353830">Performing the merge</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-merging-work.html#id353997">Committing the results of the merge</a></span></dt></dl></dd><dt><span class="sect1"><a href="a-tour-of-mercurial-merging-work.html#id354262">Merging conflicting changes</a></span></dt><dd><dl><dt><span class="sect2"><a href="a-tour-of-mercurial-merging-work.html#id354379">Using a graphical merge tool</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-merging-work.html#id354524">A worked example</a></span></dt></dl></dd><dt><span class="sect1"><a href="a-tour-of-mercurial-merging-work.html#sec:tour-merge:fetch">Simplifying the pull-merge-commit sequence</a></span></dt><dt><span class="sect1"><a href="a-tour-of-mercurial-merging-work.html#id355904">Renaming, copying, and merging</a></span></dt></dl></div><p id="x_338"><a name="x_338"></a>We've now covered cloning a repository, making changes in a
|
||||
repository, and pulling or pushing changes from one repository
|
||||
into another. Our next step is <span class="emphasis"><em>merging</em></span>
|
||||
changes from separate repositories.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id352947">Merging streams of work</h2></div></div></div><p id="x_339"><a name="x_339"></a>Merging is a fundamental part of working with a distributed
|
||||
revision control tool. Here are a few cases in which the need
|
||||
to merge work arises.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_33a"><a name="x_33a"></a>Alice and Bob each have a personal copy of a
|
||||
repository for a project they're collaborating on. Alice
|
||||
fixes a bug in her repository; Bob adds a new feature in
|
||||
his. They want the shared repository to contain both the
|
||||
bug fix and the new feature.</p></li><li><p id="x_33b"><a name="x_33b"></a>Cynthia frequently works on several different
|
||||
tasks for a single project at once, each safely isolated in
|
||||
its own repository. Working this way means that she often
|
||||
needs to merge one piece of her own work with
|
||||
another.</p></li></ul></div><p id="x_33c"><a name="x_33c"></a>Because we need to merge often, Mercurial makes
|
||||
the process easy. Let's walk through a merge. We'll begin by
|
||||
cloning yet another repository (see how often they spring up?)
|
||||
and making a change in it.</p><pre id="id353643" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone hello my-new-hello</code></strong>
|
||||
updating working directory
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd my-new-hello</code></strong>
|
||||
# Make some simple edits to hello.c.
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>my-text-editor hello.c</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'A new hello for a new day.'</code></strong>
|
||||
</pre><p id="x_33d"><a name="x_33d"></a>We should now have two copies of
|
||||
<code class="filename">hello.c</code> with different contents. The
|
||||
histories of the two repositories have also diverged, as
|
||||
illustrated in <a class="xref" href="a-tour-of-mercurial-merging-work.html#fig:tour-merge:sep-repos" title="Figure 3.1. Divergent recent histories of the my-hello and my-new-hello repositories">Figure 3.1, “Divergent recent histories of the my-hello and my-new-hello
|
||||
repositories”</a>. Here is a copy of our
|
||||
file from one repository.</p><pre id="id353616" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat hello.c</code></strong>
|
||||
/*
|
||||
* Placed in the public domain by Bryan O'Sullivan. This program is
|
||||
* not covered by patents in the United States or other countries.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("once more, hello.\n");
|
||||
printf("hello, world!\");
|
||||
printf("hello again!\n");
|
||||
return 0;
|
||||
}
|
||||
</pre><p id="x_722"><a name="x_722"></a>And here is our slightly different version from the other
|
||||
repository.</p><pre id="id353585" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat ../my-hello/hello.c</code></strong>
|
||||
/*
|
||||
* Placed in the public domain by Bryan O'Sullivan. This program is
|
||||
* not covered by patents in the United States or other countries.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("hello, world!\");
|
||||
printf("hello again!\n");
|
||||
return 0;
|
||||
}
|
||||
</pre><div class="figure"><a name="fig:tour-merge:sep-repos"></a><p class="title"><b>Figure 3.1. Divergent recent histories of the <code class="filename">my-hello</code> and <code class="filename">my-new-hello</code>
|
||||
repositories</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/tour-merge-sep-repos.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_33f"><a name="x_33f"></a>We already know that pulling changes from our <code class="filename">my-hello</code> repository will have no
|
||||
effect on the working directory.</p><pre id="id353533" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg pull ../my-hello</code></strong>
|
||||
pulling from ../my-hello
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files (+1 heads)
|
||||
(run 'hg heads' to see heads, 'hg merge' to merge)
|
||||
</pre><p id="x_340"><a name="x_340"></a>However, the <span class="command"><strong>hg pull</strong></span>
|
||||
command says something about “<span class="quote">heads</span>”.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id353683">Head changesets</h3></div></div></div><p id="x_341"><a name="x_341"></a>Remember that Mercurial records what the parent
|
||||
of each change is. If a change has a parent, we call it a
|
||||
child or descendant of the parent. A head is a change that
|
||||
has no children. The tip revision is thus a head, because the
|
||||
newest revision in a repository doesn't have any children.
|
||||
There are times when a repository can contain more than one
|
||||
head.</p><div class="figure"><a name="fig:tour-merge:pull"></a><p class="title"><b>Figure 3.2. Repository contents after pulling from <code class="filename">my-hello</code> into <code class="filename">my-new-hello</code></b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/tour-merge-pull.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_343"><a name="x_343"></a>In <a class="xref" href="a-tour-of-mercurial-merging-work.html#fig:tour-merge:pull" title="Figure 3.2. Repository contents after pulling from my-hello into my-new-hello">Figure 3.2, “Repository contents after pulling from my-hello into my-new-hello”</a>, you can
|
||||
see the effect of the pull from <code class="filename">my-hello</code> into <code class="filename">my-new-hello</code>. The history that
|
||||
was already present in <code class="filename">my-new-hello</code> is untouched, but
|
||||
a new revision has been added. By referring to <a class="xref" href="a-tour-of-mercurial-merging-work.html#fig:tour-merge:sep-repos" title="Figure 3.1. Divergent recent histories of the my-hello and my-new-hello repositories">Figure 3.1, “Divergent recent histories of the my-hello and my-new-hello
|
||||
repositories”</a>, we can see that the
|
||||
<span class="emphasis"><em>changeset ID</em></span> remains the same in the new
|
||||
repository, but the <span class="emphasis"><em>revision number</em></span> has
|
||||
changed. (This, incidentally, is a fine example of why it's
|
||||
not safe to use revision numbers when discussing changesets.)
|
||||
We can view the heads in a repository using the <span class="command"><strong>hg heads</strong></span> command.</p><pre id="id354126" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg heads</code></strong>
|
||||
changeset: 6:b6fed4f21233
|
||||
tag: tip
|
||||
parent: 4:2278160e78d4
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:53 2009 +0000
|
||||
summary: Added an extra line of output
|
||||
|
||||
changeset: 5:5218ee8aecf3
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:55 2009 +0000
|
||||
summary: A new hello for a new day.
|
||||
|
||||
</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id353830">Performing the merge</h3></div></div></div><p id="x_344"><a name="x_344"></a>What happens if we try to use the normal <span class="command"><strong>hg update</strong></span> command to update to the
|
||||
new tip?</p><pre id="id354203" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg update</code></strong>
|
||||
abort: crosses branches (use 'hg merge' or 'hg update -C')
|
||||
</pre><p id="x_345"><a name="x_345"></a>Mercurial is telling us that the <span class="command"><strong>hg update</strong></span> command won't do a merge;
|
||||
it won't update the working directory when it thinks we might
|
||||
want to do a merge, unless we force it to do so.
|
||||
(Incidentally, forcing the update with <span class="command"><strong>hg update
|
||||
-C</strong></span> would revert any uncommitted changes in the
|
||||
working directory.)</p><p id="x_723"><a name="x_723"></a>To start a merge between the two heads, we use the
|
||||
<span class="command"><strong>hg merge</strong></span> command.</p><pre id="id354163" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
|
||||
merging hello.c
|
||||
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
|
||||
(branch merge, don't forget to commit)
|
||||
</pre><p id="x_347"><a name="x_347"></a>We resolve the contents of <code class="filename">hello.c</code>
|
||||
|
||||
This updates the working directory so that it
|
||||
contains changes from <span class="emphasis"><em>both</em></span> heads, which
|
||||
is reflected in both the output of <span class="command"><strong>hg
|
||||
parents</strong></span> and the contents of
|
||||
<code class="filename">hello.c</code>.</p><pre id="id354360" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong>
|
||||
changeset: 5:5218ee8aecf3
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:55 2009 +0000
|
||||
summary: A new hello for a new day.
|
||||
|
||||
changeset: 6:b6fed4f21233
|
||||
tag: tip
|
||||
parent: 4:2278160e78d4
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:53 2009 +0000
|
||||
summary: Added an extra line of output
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat hello.c</code></strong>
|
||||
/*
|
||||
* Placed in the public domain by Bryan O'Sullivan. This program is
|
||||
* not covered by patents in the United States or other countries.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("once more, hello.\n");
|
||||
printf("hello, world!\");
|
||||
printf("hello again!\n");
|
||||
return 0;
|
||||
}
|
||||
</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id353997">Committing the results of the merge</h3></div></div></div><p id="x_348"><a name="x_348"></a>Whenever we've done a merge, <span class="command"><strong>hg
|
||||
parents</strong></span> will display two parents until we <span class="command"><strong>hg commit</strong></span> the results of the
|
||||
merge.</p><pre id="id354037" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Merged changes'</code></strong>
|
||||
</pre><p id="x_349"><a name="x_349"></a>We now have a new tip revision; notice that it has
|
||||
<span class="emphasis"><em>both</em></span> of our former heads as its parents.
|
||||
These are the same revisions that were previously displayed by
|
||||
<span class="command"><strong>hg parents</strong></span>.</p><pre id="id354110" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 7:ecb0e17b2a4e
|
||||
tag: tip
|
||||
parent: 5:5218ee8aecf3
|
||||
parent: 6:b6fed4f21233
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:56 2009 +0000
|
||||
summary: Merged changes
|
||||
|
||||
</pre><p id="x_34a"><a name="x_34a"></a>In <a class="xref" href="a-tour-of-mercurial-merging-work.html#fig:tour-merge:merge" title="Figure 3.3. Working directory and repository during merge, and following commit">Figure 3.3, “Working directory and repository during merge, and
|
||||
following commit”</a>, you can see a
|
||||
representation of what happens to the working directory during
|
||||
the merge, and how this affects the repository when the commit
|
||||
happens. During the merge, the working directory has two
|
||||
parent changesets, and these become the parents of the new
|
||||
changeset.</p><div class="figure"><a name="fig:tour-merge:merge"></a><p class="title"><b>Figure 3.3. Working directory and repository during merge, and
|
||||
following commit</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/tour-merge-merge.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_69c"><a name="x_69c"></a>We sometimes talk about a merge having
|
||||
<span class="emphasis"><em>sides</em></span>: the left side is the first parent
|
||||
in the output of <span class="command"><strong>hg parents</strong></span>,
|
||||
and the right side is the second. If the working directory
|
||||
was at e.g. revision 5 before we began a merge, that revision
|
||||
will become the left side of the merge.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id354262">Merging conflicting changes</h2></div></div></div><p id="x_34b"><a name="x_34b"></a>Most merges are simple affairs, but sometimes you'll find
|
||||
yourself merging changes where each side modifies the same portions
|
||||
of the same files. Unless both modifications are identical,
|
||||
this results in a <span class="emphasis"><em>conflict</em></span>, where you have
|
||||
to decide how to reconcile the different changes into something
|
||||
coherent.</p><div class="figure"><a name="fig:tour-merge:conflict"></a><p class="title"><b>Figure 3.4. Conflicting changes to a document</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/tour-merge-conflict.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_34d"><a name="x_34d"></a><a class="xref" href="a-tour-of-mercurial-merging-work.html#fig:tour-merge:conflict" title="Figure 3.4. Conflicting changes to a document">Figure 3.4, “Conflicting changes to a document”</a> illustrates
|
||||
an instance of two conflicting changes to a document. We
|
||||
started with a single version of the file; then we made some
|
||||
changes; while someone else made different changes to the same
|
||||
text. Our task in resolving the conflicting changes is to
|
||||
decide what the file should look like.</p><p id="x_34e"><a name="x_34e"></a>Mercurial doesn't have a built-in facility for handling
|
||||
conflicts. Instead, it runs an external program, usually one
|
||||
that displays some kind of graphical conflict resolution
|
||||
interface. By default, Mercurial tries to find one of several
|
||||
different merging tools that are likely to be installed on your
|
||||
system. It first tries a few fully automatic merging tools; if
|
||||
these don't succeed (because the resolution process requires
|
||||
human guidance) or aren't present, it tries a few
|
||||
different graphical merging tools.</p><p id="x_34f"><a name="x_34f"></a>It's also possible to get Mercurial to run a
|
||||
specific program or script, by setting the
|
||||
<code class="envar">HGMERGE</code> environment variable to the name of your
|
||||
preferred program.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id354379">Using a graphical merge tool</h3></div></div></div><p id="x_350"><a name="x_350"></a>My preferred graphical merge tool is
|
||||
<span class="command"><strong>kdiff3</strong></span>, which I'll use to describe the
|
||||
features that are common to graphical file merging tools. You
|
||||
can see a screenshot of <span class="command"><strong>kdiff3</strong></span> in action in
|
||||
<a class="xref" href="a-tour-of-mercurial-merging-work.html#fig:tour-merge:kdiff3" title="Figure 3.5. Using kdiff3 to merge versions of a file">Figure 3.5, “Using kdiff3 to merge versions of a
|
||||
file”</a>. The kind of
|
||||
merge it is performing is called a <span class="emphasis"><em>three-way
|
||||
merge</em></span>, because there are three different versions
|
||||
of the file of interest to us. The tool thus splits the upper
|
||||
portion of the window into three panes:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_351"><a name="x_351"></a>At the left is the <span class="emphasis"><em>base</em></span>
|
||||
version of the file, i.e. the most recent version from
|
||||
which the two versions we're trying to merge are
|
||||
descended.</p></li><li><p id="x_352"><a name="x_352"></a>In the middle is “<span class="quote">our</span>” version of
|
||||
the file, with the contents that we modified.</p></li><li><p id="x_353"><a name="x_353"></a>On the right is “<span class="quote">their</span>” version
|
||||
of the file, the one that from the changeset that we're
|
||||
trying to merge with.</p></li></ul></div><p id="x_354"><a name="x_354"></a>In the pane below these is the current
|
||||
<span class="emphasis"><em>result</em></span> of the merge. Our task is to
|
||||
replace all of the red text, which indicates unresolved
|
||||
conflicts, with some sensible merger of the
|
||||
“<span class="quote">ours</span>” and “<span class="quote">theirs</span>” versions of the
|
||||
file.</p><p id="x_355"><a name="x_355"></a>All four of these panes are <span class="emphasis"><em>locked
|
||||
together</em></span>; if we scroll vertically or horizontally
|
||||
in any of them, the others are updated to display the
|
||||
corresponding sections of their respective files.</p><div class="figure"><a name="fig:tour-merge:kdiff3"></a><p class="title"><b>Figure 3.5. Using <span class="command">kdiff3</span> to merge versions of a
|
||||
file</b></p><div class="figure-contents"><div class="mediaobject"><table border="0" summary="manufactured viewport for HTML img" cellspacing="0" cellpadding="0" width="100%"><tr><td><img src="figs/kdiff3.png" width="100%" alt="XXX add text"></td></tr></table></div></div></div><br class="figure-break"><p id="x_357"><a name="x_357"></a>For each conflicting portion of the file, we can choose to
|
||||
resolve the conflict using some combination of text from the
|
||||
base version, ours, or theirs. We can also manually edit the
|
||||
merged file at any time, in case we need to make further
|
||||
modifications.</p><p id="x_358"><a name="x_358"></a>There are <span class="emphasis"><em>many</em></span> file merging tools
|
||||
available, too many to cover here. They vary in which
|
||||
platforms they are available for, and in their particular
|
||||
strengths and weaknesses. Most are tuned for merging files
|
||||
containing plain text, while a few are aimed at specialised
|
||||
file formats (generally XML).</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id354524">A worked example</h3></div></div></div><p id="x_359"><a name="x_359"></a>In this example, we will reproduce the file modification
|
||||
history of <a class="xref" href="a-tour-of-mercurial-merging-work.html#fig:tour-merge:conflict" title="Figure 3.4. Conflicting changes to a document">Figure 3.4, “Conflicting changes to a document”</a>
|
||||
above. Let's begin by creating a repository with a base
|
||||
version of our document.</p><pre id="id354880" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat > letter.txt <<EOF</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>Greetings!</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>I am Mariam Abacha, the wife of former</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>Nigerian dictator Sani Abacha.</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>EOF</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add letter.txt</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m '419 scam, first draft'</code></strong>
|
||||
</pre><p id="x_35a"><a name="x_35a"></a>We'll clone the repository and make a change to the
|
||||
file.</p><pre id="id354860" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone scam scam-cousin</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd scam-cousin</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat > letter.txt <<EOF</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>Greetings!</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>I am Shehu Musa Abacha, cousin to the former</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>Nigerian dictator Sani Abacha.</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>EOF</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m '419 scam, with cousin'</code></strong>
|
||||
</pre><p id="x_35b"><a name="x_35b"></a>And another clone, to simulate someone else making a
|
||||
change to the file. (This hints at the idea that it's not all
|
||||
that unusual to merge with yourself when you isolate tasks in
|
||||
separate repositories, and indeed to find and resolve
|
||||
conflicts while doing so.)</p><pre id="id354843" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone scam scam-son</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd scam-son</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat > letter.txt <<EOF</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>Greetings!</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>I am Alhaji Abba Abacha, son of the former</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>Nigerian dictator Sani Abacha.</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>EOF</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m '419 scam, with son'</code></strong>
|
||||
</pre><p id="x_35c"><a name="x_35c"></a>Having created two
|
||||
different versions of the file, we'll set up an environment
|
||||
suitable for running our merge.</p><pre id="id355540" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone scam-cousin scam-merge</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd scam-merge</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg pull -u ../scam-son</code></strong>
|
||||
pulling from ../scam-son
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files (+1 heads)
|
||||
not updating, since new heads added
|
||||
(run 'hg heads' to see heads, 'hg merge' to merge)
|
||||
</pre><p id="x_35d"><a name="x_35d"></a>In this example, I'll set
|
||||
<code class="envar">HGMERGE</code> to tell Mercurial to use the
|
||||
non-interactive <span class="command"><strong>merge</strong></span> command. This is
|
||||
bundled with many Unix-like systems. (If you're following this
|
||||
example on your computer, don't bother setting
|
||||
<code class="envar">HGMERGE</code>. You'll get dropped into a GUI file
|
||||
merge tool instead, which is much preferable.)</p><pre id="id355530" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>export HGMERGE=merge</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
|
||||
merging letter.txt
|
||||
merge: warning: conflicts during merge
|
||||
merging letter.txt failed!
|
||||
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
||||
use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat letter.txt</code></strong>
|
||||
Greetings!
|
||||
<<<<<<< /tmp/tour-merge-conflictgW7-1Z/scam-merge/letter.txt
|
||||
I am Shehu Musa Abacha, cousin to the former
|
||||
=======
|
||||
I am Alhaji Abba Abacha, son of the former
|
||||
>>>>>>> /tmp/letter.txt~other.c6Rq0s
|
||||
Nigerian dictator Sani Abacha.
|
||||
</pre><p id="x_35f"><a name="x_35f"></a>Because <span class="command"><strong>merge</strong></span> can't resolve the
|
||||
conflicting changes, it leaves <span class="emphasis"><em>merge
|
||||
markers</em></span> inside the file that has conflicts,
|
||||
indicating which lines have conflicts, and whether they came
|
||||
from our version of the file or theirs.</p><p id="x_360"><a name="x_360"></a>Mercurial can tell from the way <span class="command"><strong>merge</strong></span>
|
||||
exits that it wasn't able to merge successfully, so it tells
|
||||
us what commands we'll need to run if we want to redo the
|
||||
merging operation. This could be useful if, for example, we
|
||||
were running a graphical merge tool and quit because we were
|
||||
confused or realised we had made a mistake.</p><p id="x_361"><a name="x_361"></a>If automatic or manual merges fail, there's nothing to
|
||||
prevent us from “<span class="quote">fixing up</span>” the affected files
|
||||
ourselves, and committing the results of our merge:</p><pre id="id355496" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat > letter.txt <<EOF</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>Greetings!</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>I am Bryan O'Sullivan, no relation of the former</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>Nigerian dictator Sani Abacha.</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>EOF</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg resolve -m letter.txt</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Send me your money'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 3:6f17ad930bf5
|
||||
tag: tip
|
||||
parent: 1:cef8fbca9a6f
|
||||
parent: 2:dc8f64391590
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:57 2009 +0000
|
||||
summary: Send me your money
|
||||
|
||||
</pre><div class="note"><table border="0" summary="Note: Where is the hg resolve command?"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Where is the hg resolve command?</th></tr><tr><td align="left" valign="top"><p id="x_724"><a name="x_724"></a>The <span class="command"><strong>hg resolve</strong></span> command was introduced
|
||||
in Mercurial 1.1, which was released in December 2008. If
|
||||
you are using an older version of Mercurial (run <span class="command"><strong>hg
|
||||
version</strong></span> to see), this command will not be
|
||||
present. If your version of Mercurial is older than 1.1,
|
||||
you should strongly consider upgrading to a newer version
|
||||
before trying to tackle complicated merges.</p></td></tr></table></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:tour-merge:fetch">Simplifying the pull-merge-commit sequence</h2></div></div></div><p id="x_362"><a name="x_362"></a>The process of merging changes as outlined above is
|
||||
straightforward, but requires running three commands in
|
||||
sequence.</p><pre id="id355698" class="programlisting">hg pull -u
|
||||
hg merge
|
||||
hg commit -m 'Merged remote changes'</pre><p id="x_363"><a name="x_363"></a>In the case of the final commit, you also need to enter a
|
||||
commit message, which is almost always going to be a piece of
|
||||
uninteresting “<span class="quote">boilerplate</span>” text.</p><p id="x_364"><a name="x_364"></a>It would be nice to reduce the number of steps needed, if
|
||||
this were possible. Indeed, Mercurial is distributed with an
|
||||
extension called <code class="literal">fetch</code> that
|
||||
does just this.</p><p id="x_365"><a name="x_365"></a>Mercurial provides a flexible extension mechanism that lets
|
||||
people extend its functionality, while keeping the core of
|
||||
Mercurial small and easy to deal with. Some extensions add new
|
||||
commands that you can use from the command line, while others
|
||||
work “<span class="quote">behind the scenes,</span>” for example adding
|
||||
capabilities to Mercurial's built-in server mode.</p><p id="x_366"><a name="x_366"></a>The <code class="literal">fetch</code>
|
||||
extension adds a new command called, not surprisingly, <span class="command"><strong>hg fetch</strong></span>. This extension acts as a
|
||||
combination of <span class="command"><strong>hg pull -u</strong></span>,
|
||||
<span class="command"><strong>hg merge</strong></span> and <span class="command"><strong>hg commit</strong></span>. It begins by pulling
|
||||
changes from another repository into the current repository. If
|
||||
it finds that the changes added a new head to the repository, it
|
||||
updates to the new head, begins a merge, then (if the merge
|
||||
succeeded) commits the result of the merge with an
|
||||
automatically-generated commit message. If no new heads were
|
||||
added, it updates the working directory to the new tip
|
||||
changeset.</p><p id="x_367"><a name="x_367"></a>Enabling the <code class="literal">fetch</code> extension is easy. Edit the
|
||||
<code class="filename">.hgrc</code> file in your home
|
||||
directory, and either go to the <code class="literal">extensions</code> section or create an
|
||||
<code class="literal">extensions</code> section. Then
|
||||
add a line that simply reads
|
||||
“<span class="quote"><code class="literal">fetch=</code></span>”.</p><pre id="id355838" class="programlisting">[extensions]
|
||||
fetch =</pre><p id="x_368"><a name="x_368"></a>(Normally, the right-hand side of the
|
||||
“<span class="quote"><code class="literal">=</code></span>” would indicate where to find
|
||||
the extension, but since the <code class="literal">fetch</code> extension is in the standard
|
||||
distribution, Mercurial knows where to search for it.)</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id355904">Renaming, copying, and merging</h2></div></div></div><p id="x_729"><a name="x_729"></a>During the life of a project, we will often want to change
|
||||
the layout of its files and directories. This can be as simple
|
||||
as renaming a single file, or as complex as restructuring the
|
||||
entire hierarchy of files within the project.</p><p id="x_72a"><a name="x_72a"></a>Mercurial supports these kinds of complex changes fluently,
|
||||
provided we tell it what we're doing. If we want to rename a
|
||||
file, we should use the <span class="command"><strong>hg rename</strong></span><sup>[<a name="id355926" href="#ftn.id355926" class="footnote">2</a>]</sup> command to rename it, so that Mercurial can do the
|
||||
right thing later when we merge.</p><p id="x_72c"><a name="x_72c"></a>We will cover the use of these commands in more detail in
|
||||
<a class="xref" href="mercurial-in-daily-use.html#chap:daily.copy" title="Copying files">the section called “Copying files”</a>.</p></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.id355926" href="#id355926" class="para">2</a>] </sup>If you're a Unix user, you'll be glad to know that the
|
||||
<span class="command"><strong>hg rename</strong></span> command can be abbreviated as
|
||||
<span class="command"><strong>hg mv</strong></span>.</p></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="a-tour-of-mercurial-the-basics.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="behind-the-scenes.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 2. A tour of Mercurial: the basics </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 4. Behind the scenes</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
826
read/a-tour-of-mercurial-the-basics.html
Normal file
826
read/a-tour-of-mercurial-the-basics.html
Normal file
|
@ -0,0 +1,826 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 2. A tour of Mercurial: the basics</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="how-did-we-get-here.html" title="Chapter 1. How did we get here?"><link rel="next" href="a-tour-of-mercurial-merging-work.html" title="Chapter 3. A tour of Mercurial: merging work"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 2. A tour of Mercurial: the basics</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="how-did-we-get-here.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="a-tour-of-mercurial-merging-work.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:tour-basic"><div class="titlepage"><div><div><h2 class="title">Chapter 2. A tour of Mercurial: the basics</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="a-tour-of-mercurial-the-basics.html#sec:tour:install">Installing Mercurial on your system</a></span></dt><dd><dl><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id344575">Windows</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id344904">Mac OS X</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id344922">Linux</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id344998">Solaris</a></span></dt></dl></dd><dt><span class="sect1"><a href="a-tour-of-mercurial-the-basics.html#id345016">Getting started</a></span></dt><dd><dl><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id345318">Built-in help</a></span></dt></dl></dd><dt><span class="sect1"><a href="a-tour-of-mercurial-the-basics.html#id345120">Working with a repository</a></span></dt><dd><dl><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id345147">Making a local copy of a repository</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id345415">What's in a repository?</a></span></dt></dl></dd><dt><span class="sect1"><a href="a-tour-of-mercurial-the-basics.html#id345536">A tour through history</a></span></dt><dd><dl><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id345833">Changesets, revisions, and talking to other
|
||||
people</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id345980">Viewing specific revisions</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id346082">More detailed information</a></span></dt></dl></dd><dt><span class="sect1"><a href="a-tour-of-mercurial-the-basics.html#id346408">All about command options</a></span></dt><dt><span class="sect1"><a href="a-tour-of-mercurial-the-basics.html#id346595">Making and reviewing changes</a></span></dt><dt><span class="sect1"><a href="a-tour-of-mercurial-the-basics.html#id347157">Recording changes in a new changeset</a></span></dt><dd><dl><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id347208">Setting up a username</a></span></dt><dd><dl><dt><span class="sect3"><a href="a-tour-of-mercurial-the-basics.html#sec:tour-basic:username">Creating a Mercurial configuration file</a></span></dt><dt><span class="sect3"><a href="a-tour-of-mercurial-the-basics.html#id347496">Choosing a user name</a></span></dt></dl></dd><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id347526">Writing a commit message</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id347874">Writing a good commit message</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id347674">Aborting a commit</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id347689">Admiring our new handiwork</a></span></dt></dl></dd><dt><span class="sect1"><a href="a-tour-of-mercurial-the-basics.html#id347917">Sharing changes</a></span></dt><dd><dl><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#sec:tour:pull">Pulling changes from another repository</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id348343">Updating the working directory</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id348825">Pushing changes to another repository</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id349161">Default locations</a></span></dt><dt><span class="sect2"><a href="a-tour-of-mercurial-the-basics.html#id349277">Sharing changes over a network</a></span></dt></dl></dd><dt><span class="sect1"><a href="a-tour-of-mercurial-the-basics.html#id349357">Starting a new project</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:tour:install">Installing Mercurial on your system</h2></div></div></div><p id="x_1"><a name="x_1"></a>Prebuilt binary packages of Mercurial are available for
|
||||
every popular operating system. These make it easy to start
|
||||
using Mercurial on your computer immediately.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id344575">Windows</h3></div></div></div><p id="x_c"><a name="x_c"></a>The best version of Mercurial for Windows is
|
||||
TortoiseHg, which can be found at <a class="ulink" href="http://bitbucket.org/tortoisehg/stable/wiki/Home" target="_top">http://bitbucket.org/tortoisehg/stable/wiki/Home</a>.
|
||||
This package has no external dependencies; it “<span class="quote">just
|
||||
works</span>”. It provides both command line and graphical
|
||||
user interfaces.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id344904">Mac OS X</h3></div></div></div><p id="x_a"><a name="x_a"></a>Lee Cantey publishes an installer of Mercurial
|
||||
for Mac OS X at <a class="ulink" href="http://mercurial.berkwood.com" target="_top">http://mercurial.berkwood.com</a>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id344922">Linux</h3></div></div></div><p id="x_2"><a name="x_2"></a>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.</p><p id="x_3"><a name="x_3"></a>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
|
||||
<code class="literal">mercurial</code>.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_4"><a name="x_4"></a>Ubuntu and Debian:</p><pre id="id344957" class="programlisting">apt-get install mercurial</pre></li><li><p id="x_5"><a name="x_5"></a>Fedora:</p><pre id="id344968" class="programlisting">yum install mercurial</pre></li><li><p id="x_715"><a name="x_715"></a>OpenSUSE:</p><pre id="id344980" class="programlisting">zypper install mercurial</pre></li><li><p id="x_6"><a name="x_6"></a>Gentoo:</p><pre id="id344991" class="programlisting">emerge mercurial</pre></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id344998">Solaris</h3></div></div></div><p id="x_9"><a name="x_9"></a>SunFreeWare, at <a class="ulink" href="http://www.sunfreeware.com" target="_top">http://www.sunfreeware.com</a>,
|
||||
provides prebuilt packages of Mercurial.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id345016">Getting started</h2></div></div></div><p id="x_e"><a name="x_e"></a>To begin, we'll use the <span class="command"><strong>hg
|
||||
version</strong></span> 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.</p><pre id="id345379" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg version</code></strong>
|
||||
Mercurial Distributed SCM (version 1.2)
|
||||
|
||||
Copyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
</pre><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id345318">Built-in help</h3></div></div></div><p id="x_f"><a name="x_f"></a>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 <span class="command"><strong>hg
|
||||
help</strong></span>; 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.</p><pre id="id345368" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg help init</code></strong>
|
||||
hg init [-e CMD] [--remotecmd CMD] [DEST]
|
||||
|
||||
create a new repository in the given directory
|
||||
|
||||
Initialize a new repository in the given directory. If the given
|
||||
directory does not exist, it is created.
|
||||
|
||||
If no directory is given, the current directory is used.
|
||||
|
||||
It is possible to specify an ssh:// URL as the destination.
|
||||
See 'hg help urls' for more information.
|
||||
|
||||
options:
|
||||
|
||||
-e --ssh specify ssh command to use
|
||||
--remotecmd specify hg command to run on the remote side
|
||||
|
||||
use "hg -v help init" to show global options
|
||||
</pre><p id="x_10"><a name="x_10"></a>For a more impressive level of detail (which you won't
|
||||
usually need) run <span class="command"><strong>hg help <code class="option">-v</code></strong></span>. The <code class="option">-v</code> option is short for
|
||||
<code class="option">--verbose</code>, and tells
|
||||
Mercurial to print more information than it usually
|
||||
would.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id345120">Working with a repository</h2></div></div></div><p id="x_11"><a name="x_11"></a>In Mercurial, everything happens inside a
|
||||
<span class="emphasis"><em>repository</em></span>. The repository for a project
|
||||
contains all of the files that “<span class="quote">belong to</span>” that
|
||||
project, along with a historical record of the project's
|
||||
files.</p><p id="x_12"><a name="x_12"></a>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.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id345147">Making a local copy of a repository</h3></div></div></div><p id="x_13"><a name="x_13"></a><span class="emphasis"><em>Copying</em></span> 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 <span class="command"><strong>hg clone</strong></span>, because it
|
||||
makes an identical copy of an existing repository.</p><pre id="id345593" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg clone https://bitbucket.org/bos/hg-tutorial-hello</code></strong>
|
||||
destination directory: hello
|
||||
requesting all changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 5 changesets with 5 changes to 2 files
|
||||
updating working directory
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_67c"><a name="x_67c"></a>One advantage of using <span class="command"><strong>hg
|
||||
clone</strong></span> 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.</p><p id="x_14"><a name="x_14"></a>If our clone succeeded, we should now have a local
|
||||
directory called <code class="filename">hello</code>.
|
||||
This directory will contain some files.</p><pre id="id345299" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>ls -l</code></strong>
|
||||
total 4
|
||||
drwxrwxr-x 3 bos bos 4096 May 5 06:55 hello
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls hello</code></strong>
|
||||
Makefile hello.c
|
||||
</pre><p id="x_15"><a name="x_15"></a>These files have the same contents and history in our
|
||||
repository as they do in the repository we cloned.</p><p id="x_16"><a name="x_16"></a>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.</p><p id="x_17"><a name="x_17"></a>What this means for now is that we're free to experiment
|
||||
with our repository, safe in the knowledge that it's a private
|
||||
“<span class="quote">sandbox</span>” that won't affect anyone else.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id345415">What's in a repository?</h3></div></div></div><p id="x_18"><a name="x_18"></a>When we take a more detailed look inside a repository, we
|
||||
can see that it contains a directory named <code class="filename">.hg</code>. This is where Mercurial
|
||||
keeps all of its metadata for the repository.</p><pre id="id345568" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd hello</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls -a</code></strong>
|
||||
. .. .hg Makefile hello.c
|
||||
</pre><p id="x_19"><a name="x_19"></a>The contents of the <code class="filename">.hg</code> directory and its
|
||||
subdirectories are private to Mercurial. Every other file and
|
||||
directory in the repository is yours to do with as you
|
||||
please.</p><p id="x_1a"><a name="x_1a"></a>To introduce a little terminology, the <code class="filename">.hg</code> directory is the
|
||||
“<span class="quote">real</span>” repository, and all of the files and
|
||||
directories that coexist with it are said to live in the
|
||||
<span class="emphasis"><em>working directory</em></span>. An easy way to
|
||||
remember the distinction is that the
|
||||
<span class="emphasis"><em>repository</em></span> contains the
|
||||
<span class="emphasis"><em>history</em></span> of your project, while the
|
||||
<span class="emphasis"><em>working directory</em></span> contains a
|
||||
<span class="emphasis"><em>snapshot</em></span> of your project at a particular
|
||||
point in history.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id345536">A tour through history</h2></div></div></div><p id="x_1b"><a name="x_1b"></a>One of the first things we might want to do with a new,
|
||||
unfamiliar repository is understand its history. The <span class="command"><strong>hg log</strong></span> command gives us a view of
|
||||
the history of changes in the repository.</p><pre id="id345930" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log</code></strong>
|
||||
changeset: 4:2278160e78d4
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:16:53 2008 +0200
|
||||
summary: Trim comments.
|
||||
|
||||
changeset: 3:0272e0d5a517
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:08:02 2008 +0200
|
||||
summary: Get make to generate the final binary from a .o file.
|
||||
|
||||
changeset: 2:fef857204a0c
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:05:04 2008 +0200
|
||||
summary: Introduce a typo into hello.c.
|
||||
|
||||
changeset: 1:82e55d328c8c
|
||||
user: mpm@selenic.com
|
||||
date: Fri Aug 26 01:21:28 2005 -0700
|
||||
summary: Create a makefile
|
||||
|
||||
changeset: 0:0a04b987be5a
|
||||
user: mpm@selenic.com
|
||||
date: Fri Aug 26 01:20:50 2005 -0700
|
||||
summary: Create a standard "hello, world" program
|
||||
|
||||
</pre><p id="x_1c"><a name="x_1c"></a>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
|
||||
<span class="emphasis"><em>changeset</em></span>, because it can contain a record
|
||||
of changes to several files.</p><p id="x_1d"><a name="x_1d"></a>The fields in a record of output from <span class="command"><strong>hg log</strong></span> are as follows.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_1e"><a name="x_1e"></a><code class="literal">changeset</code>: This
|
||||
field has the format of a number, followed by a colon,
|
||||
followed by a hexadecimal (or <span class="emphasis"><em>hex</em></span>)
|
||||
string. These are <span class="emphasis"><em>identifiers</em></span> 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.</p></li><li><p id="x_1f"><a name="x_1f"></a><code class="literal">user</code>: 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.</p></li><li><p id="x_20"><a name="x_20"></a><code class="literal">date</code>: 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.)</p></li><li><p id="x_21"><a name="x_21"></a><code class="literal">summary</code>: The first line of
|
||||
the text message that the creator of the changeset entered
|
||||
to describe the changeset.</p></li><li><p id="x_67d"><a name="x_67d"></a>Some changesets, such as the first in the list above,
|
||||
have a <code class="literal">tag</code> field. A tag is another way
|
||||
to identify a changeset, by giving it an easy-to-remember
|
||||
name. (The tag named <code class="literal">tip</code> is special: it
|
||||
always refers to the newest change in a repository.)</p></li></ul></div><p id="x_22"><a name="x_22"></a>The default output printed by <span class="command"><strong>hg log</strong></span> is purely a summary; it is
|
||||
missing a lot of detail.</p><p id="x_23"><a name="x_23"></a><a class="xref" href="a-tour-of-mercurial-the-basics.html#fig:tour-basic:history" title="Figure 2.1. Graphical history of the hello repository">Figure 2.1, “Graphical history of the hello repository”</a> provides
|
||||
a graphical representation of the history of the <code class="filename">hello</code> repository, to make it a
|
||||
little easier to see which direction history is
|
||||
“<span class="quote">flowing</span>” in. We'll be returning to this figure
|
||||
several times in this chapter and the chapter that
|
||||
follows.</p><div class="figure"><a name="fig:tour-basic:history"></a><p class="title"><b>Figure 2.1. Graphical history of the <code class="filename">hello</code> repository</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/tour-history.png" alt="XXX add text"></div></div></div><br class="figure-break"><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id345833">Changesets, revisions, and talking to other
|
||||
people</h3></div></div></div><p id="x_25"><a name="x_25"></a>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 “<span class="quote">changeset</span>” is often
|
||||
compressed to “<span class="quote">change</span>” or (when written)
|
||||
“<span class="quote">cset</span>”, and sometimes a changeset is referred to
|
||||
as a “<span class="quote">revision</span>” or a “<span class="quote">rev</span>”.</p><p id="x_26"><a name="x_26"></a>While it doesn't matter what <span class="emphasis"><em>word</em></span> you
|
||||
use to refer to the concept of “<span class="quote">a changeset</span>”, the
|
||||
<span class="emphasis"><em>identifier</em></span> that you use to refer to
|
||||
“<span class="quote">a <span class="emphasis"><em>specific</em></span> changeset</span>” is of
|
||||
great importance. Recall that the <code class="literal">changeset</code>
|
||||
field in the output from <span class="command"><strong>hg
|
||||
log</strong></span> identifies a changeset using both a number and
|
||||
a hexadecimal string.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_27"><a name="x_27"></a>The revision number is a handy
|
||||
notation that is <span class="emphasis"><em>only valid in that
|
||||
repository</em></span>.</p></li><li><p id="x_28"><a name="x_28"></a>The hexadecimal string is the
|
||||
<span class="emphasis"><em>permanent, unchanging identifier</em></span> that
|
||||
will always identify that exact changeset in
|
||||
<span class="emphasis"><em>every</em></span> copy of the
|
||||
repository.</p></li></ul></div><p id="x_29"><a name="x_29"></a>This distinction is important. If you send
|
||||
someone an email talking about “<span class="quote">revision 33</span>”,
|
||||
there's a high likelihood that their revision 33 will
|
||||
<span class="emphasis"><em>not be the same</em></span> 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 <code class="literal">a,b,c</code>
|
||||
can easily appear in one repository as
|
||||
<code class="literal">0,1,2</code>, while in another as
|
||||
<code class="literal">0,2,1</code>.</p><p id="x_2a"><a name="x_2a"></a>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.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id345980">Viewing specific revisions</h3></div></div></div><p id="x_2b"><a name="x_2b"></a>To narrow the output of <span class="command"><strong>hg
|
||||
log</strong></span> down to a single revision, use the <code class="option">-r</code> (or <code class="option">--rev</code>) option. You can use
|
||||
either a revision number or a hexadecimal identifier,
|
||||
and you can provide as many revisions as you want.</p><pre id="id346352" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r 3</code></strong>
|
||||
changeset: 3:0272e0d5a517
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:08:02 2008 +0200
|
||||
summary: Get make to generate the final binary from a .o file.
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r 0272e0d5a517</code></strong>
|
||||
changeset: 3:0272e0d5a517
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:08:02 2008 +0200
|
||||
summary: Get make to generate the final binary from a .o file.
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r 1 -r 4</code></strong>
|
||||
changeset: 1:82e55d328c8c
|
||||
user: mpm@selenic.com
|
||||
date: Fri Aug 26 01:21:28 2005 -0700
|
||||
summary: Create a makefile
|
||||
|
||||
changeset: 4:2278160e78d4
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:16:53 2008 +0200
|
||||
summary: Trim comments.
|
||||
|
||||
</pre><p id="x_2c"><a name="x_2c"></a>If you want to see the history of several revisions
|
||||
without having to list each one, you can use <span class="emphasis"><em>range
|
||||
notation</em></span>; this lets you express the idea “<span class="quote">I
|
||||
want all revisions between <code class="literal">abc</code> and
|
||||
<code class="literal">def</code>, inclusive</span>”.</p><pre id="id346245" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r 2:4</code></strong>
|
||||
changeset: 2:fef857204a0c
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:05:04 2008 +0200
|
||||
summary: Introduce a typo into hello.c.
|
||||
|
||||
changeset: 3:0272e0d5a517
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:08:02 2008 +0200
|
||||
summary: Get make to generate the final binary from a .o file.
|
||||
|
||||
changeset: 4:2278160e78d4
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:16:53 2008 +0200
|
||||
summary: Trim comments.
|
||||
|
||||
</pre><p id="x_2d"><a name="x_2d"></a>Mercurial also honours the order in which you specify
|
||||
revisions, so <span class="command"><strong>hg log -r 2:4</strong></span>
|
||||
prints 2, 3, and 4. while <span class="command"><strong>hg log -r
|
||||
4:2</strong></span> prints 4, 3, and 2.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id346082">More detailed information</h3></div></div></div><p id="x_2e"><a name="x_2e"></a>While the summary information printed by <span class="command"><strong>hg log</strong></span> 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 <span class="command"><strong>hg log</strong></span>
|
||||
command's <code class="option">-v</code> (or <code class="option">--verbose</code>) option gives you
|
||||
this extra detail.</p><pre id="id346186" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -v -r 3</code></strong>
|
||||
changeset: 3:0272e0d5a517
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:08:02 2008 +0200
|
||||
files: Makefile
|
||||
description:
|
||||
Get make to generate the final binary from a .o file.
|
||||
|
||||
|
||||
</pre><p id="x_2f"><a name="x_2f"></a>If you want to see both the description and
|
||||
content of a change, add the <code class="option">-p</code> (or <code class="option">--patch</code>) option. This displays
|
||||
the content of a change as a <span class="emphasis"><em>unified diff</em></span>
|
||||
(if you've never seen a unified diff before, see <a class="xref" href="managing-change-with-mercurial-queues.html#sec:mq:patch" title="Understanding patches">the section called “Understanding patches”</a> for an overview).</p><pre id="id346230" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -v -p -r 2</code></strong>
|
||||
changeset: 2:fef857204a0c
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:05:04 2008 +0200
|
||||
files: hello.c
|
||||
description:
|
||||
Introduce a typo into hello.c.
|
||||
|
||||
|
||||
diff -r 82e55d328c8c -r fef857204a0c hello.c
|
||||
--- a/hello.c Fri Aug 26 01:21:28 2005 -0700
|
||||
+++ b/hello.c Sat Aug 16 22:05:04 2008 +0200
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
- printf("hello, world!\n");
|
||||
+ printf("hello, world!\");
|
||||
return 0;
|
||||
}
|
||||
|
||||
</pre><p id="x_67e"><a name="x_67e"></a>The <code class="option">-p</code> option is
|
||||
tremendously useful, so it's well worth remembering.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id346408">All about command options</h2></div></div></div><p id="x_30"><a name="x_30"></a>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.</p><p id="x_31"><a name="x_31"></a>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.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_32"><a name="x_32"></a>Every option has a long name. For example, as
|
||||
we've already seen, the <span class="command"><strong>hg
|
||||
log</strong></span> command accepts a <code class="option">--rev</code> option.</p></li><li><p id="x_33"><a name="x_33"></a>Most options have short names, too. Instead
|
||||
of <code class="option">--rev</code>, we can use
|
||||
<code class="option">-r</code>. (The reason that
|
||||
some options don't have short names is that the options in
|
||||
question are rarely used.)</p></li><li><p id="x_34"><a name="x_34"></a>Long options start with two dashes (e.g.
|
||||
<code class="option">--rev</code>), while short
|
||||
options start with one (e.g. <code class="option">-r</code>).</p></li><li><p id="x_35"><a name="x_35"></a>Option naming and usage is consistent across
|
||||
commands. For example, every command that lets you specify
|
||||
a changeset ID or revision number accepts both <code class="option">-r</code> and <code class="option">--rev</code> arguments.</p></li><li><p id="x_67f"><a name="x_67f"></a>If you are using short options, you can save typing by
|
||||
running them together. For example, the command <span class="command"><strong>hg log -v -p -r 2</strong></span> can be written
|
||||
as <span class="command"><strong>hg log -vpr2</strong></span>.</p></li></ul></div><p id="x_36"><a name="x_36"></a>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.</p><p id="x_37"><a name="x_37"></a>Most commands that print output of some kind will print more
|
||||
output when passed a <code class="option">-v</code>
|
||||
(or <code class="option">--verbose</code>) option, and
|
||||
less when passed <code class="option">-q</code> (or
|
||||
<code class="option">--quiet</code>).</p><div class="note"><table border="0" summary="Note: Option naming consistency"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Option naming consistency</th></tr><tr><td align="left" valign="top"><p id="x_680"><a name="x_680"></a>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 <code class="option">--rev</code> or <code class="option">-r</code>. This consistent use of
|
||||
option names makes it easier to remember what options a
|
||||
particular command takes.</p></td></tr></table></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id346595">Making and reviewing changes</h2></div></div></div><p id="x_38"><a name="x_38"></a>Now that we have a grasp of viewing history in Mercurial,
|
||||
let's take a look at making some changes and examining
|
||||
them.</p><p id="x_39"><a name="x_39"></a>The first thing we'll do is isolate our experiment in a
|
||||
repository of its own. We use the <span class="command"><strong>hg
|
||||
clone</strong></span> 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<sup>[<a name="id346621" href="#ftn.id346621" class="footnote">1</a>]</sup>.</p><pre id="id344876" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone hello my-hello</code></strong>
|
||||
updating working directory
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd my-hello</code></strong>
|
||||
</pre><p id="x_3a"><a name="x_3a"></a>As an aside, it's often good practice to keep a
|
||||
“<span class="quote">pristine</span>” 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.</p><p id="x_3b"><a name="x_3b"></a>In our <code class="filename">my-hello</code>
|
||||
repository, we have a file <code class="filename">hello.c</code> that
|
||||
contains the classic “<span class="quote">hello, world</span>” program.</p><pre id="id347024" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat hello.c</code></strong>
|
||||
/*
|
||||
* Placed in the public domain by Bryan O'Sullivan. This program is
|
||||
* not covered by patents in the United States or other countries.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("hello, world!\");
|
||||
return 0;
|
||||
}
|
||||
</pre><p id="x_682"><a name="x_682"></a>Let's edit this file so that it prints a second line of
|
||||
output.</p><pre id="id346984" class="screen"># ... edit edit edit ...
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat hello.c</code></strong>
|
||||
/*
|
||||
* Placed in the public domain by Bryan O'Sullivan. This program is
|
||||
* not covered by patents in the United States or other countries.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("hello, world!\");
|
||||
printf("hello again!\n");
|
||||
return 0;
|
||||
}
|
||||
</pre><p id="x_3c"><a name="x_3c"></a>Mercurial's <span class="command"><strong>hg status</strong></span>
|
||||
command will tell us what Mercurial knows about the files in the
|
||||
repository.</p><pre id="id346930" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>ls</code></strong>
|
||||
Makefile hello.c
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
M hello.c
|
||||
</pre><p id="x_3d"><a name="x_3d"></a>The <span class="command"><strong>hg status</strong></span> command
|
||||
prints no output for some files, but a line starting with
|
||||
“<span class="quote"><code class="literal">M</code></span>” for
|
||||
<code class="filename">hello.c</code>. Unless you tell it to, <span class="command"><strong>hg status</strong></span> will not print any output
|
||||
for files that have not been modified.</p><p id="x_3e"><a name="x_3e"></a>The “<span class="quote"><code class="literal">M</code></span>” indicates that
|
||||
Mercurial has noticed that we modified
|
||||
<code class="filename">hello.c</code>. We didn't need to
|
||||
<span class="emphasis"><em>inform</em></span> 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.</p><p id="x_3f"><a name="x_3f"></a>It's somewhat helpful to know that we've modified
|
||||
<code class="filename">hello.c</code>, but we might prefer to know
|
||||
exactly <span class="emphasis"><em>what</em></span> changes we've made to it. To
|
||||
do this, we use the <span class="command"><strong>hg diff</strong></span>
|
||||
command.</p><pre id="id347442" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg diff</code></strong>
|
||||
diff -r 2278160e78d4 hello.c
|
||||
--- a/hello.c Sat Aug 16 22:16:53 2008 +0200
|
||||
+++ b/hello.c Tue May 05 06:55:53 2009 +0000
|
||||
@@ -8,5 +8,6 @@
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("hello, world!\");
|
||||
+ printf("hello again!\n");
|
||||
return 0;
|
||||
}
|
||||
</pre><div class="tip"><table border="0" summary="Tip: Understanding patches"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="/support/figs/tip.png"></td><th align="left">Understanding patches</th></tr><tr><td align="left" valign="top"><p id="x_683"><a name="x_683"></a>Remember to take a look at <a class="xref" href="managing-change-with-mercurial-queues.html#sec:mq:patch" title="Understanding patches">the section called “Understanding patches”</a> if you don't know how to read
|
||||
output above.</p></td></tr></table></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id347157">Recording changes in a new changeset</h2></div></div></div><p id="x_40"><a name="x_40"></a>We can modify files, build and test our changes, and use
|
||||
<span class="command"><strong>hg status</strong></span> and <span class="command"><strong>hg diff</strong></span> 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.</p><p id="x_41"><a name="x_41"></a>The <span class="command"><strong>hg commit</strong></span> command lets
|
||||
us create a new changeset; we'll usually refer to this as
|
||||
“<span class="quote">making a commit</span>” or
|
||||
“<span class="quote">committing</span>”.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id347208">Setting up a username</h3></div></div></div><p id="x_42"><a name="x_42"></a>When you try to run <span class="command"><strong>hg
|
||||
commit</strong></span> 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:</p><div class="orderedlist"><ol type="1"><li><p id="x_43"><a name="x_43"></a>If you specify a <code class="option">-u</code> option to the <span class="command"><strong>hg commit</strong></span> command on the command
|
||||
line, followed by a username, this is always given the
|
||||
highest precedence.</p></li><li><p id="x_44"><a name="x_44"></a>If you have set the <code class="envar">HGUSER</code>
|
||||
environment variable, this is checked
|
||||
next.</p></li><li><p id="x_45"><a name="x_45"></a>If you create a file in your home
|
||||
directory called <code class="filename">.hgrc</code>, with a <code class="envar">username</code> entry, that will be
|
||||
used next. To see what the contents of this file should
|
||||
look like, refer to <a class="xref" href="a-tour-of-mercurial-the-basics.html#sec:tour-basic:username" title="Creating a Mercurial configuration file">the section called “Creating a Mercurial configuration file”</a>
|
||||
below.</p></li><li><p id="x_46"><a name="x_46"></a>If you have set the <code class="envar">EMAIL</code>
|
||||
environment variable, this will be used
|
||||
next.</p></li><li><p id="x_47"><a name="x_47"></a>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.</p></li></ol></div><p id="x_48"><a name="x_48"></a>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.</p><p id="x_49"><a name="x_49"></a>You should think of the <code class="envar">HGUSER</code> environment
|
||||
variable and the <code class="option">-u</code>
|
||||
option to the <span class="command"><strong>hg commit</strong></span>
|
||||
command as ways to <span class="emphasis"><em>override</em></span> 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 <code class="filename">.hgrc</code> file; see
|
||||
below for details.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="sec:tour-basic:username">Creating a Mercurial configuration file</h4></div></div></div><p id="x_4a"><a name="x_4a"></a>To set a user name, use your favorite editor
|
||||
to create a file called <code class="filename">.hgrc</code> in your home directory.
|
||||
Mercurial will use this file to look up your personalised
|
||||
configuration settings. The initial contents of your
|
||||
<code class="filename">.hgrc</code> should look like
|
||||
this.</p><div class="tip"><table border="0" summary="Tip: Home directory on Windows"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="/support/figs/tip.png"></td><th align="left">Home directory on Windows</th></tr><tr><td align="left" valign="top"><p id="x_716"><a name="x_716"></a>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
|
||||
<code class="filename">C:\Documents and Settings</code>. You can
|
||||
find out the exact name of your home directory by opening
|
||||
a command prompt window and running the following
|
||||
command.</p><pre id="id347422" class="screen"><code class="prompt">C:\></code> <strong class="userinput"><code>echo %UserProfile%</code></strong></pre></td></tr></table></div><pre id="id347447" class="programlisting"># This is a Mercurial configuration file.
|
||||
[ui]
|
||||
username = Firstname Lastname <email.address@example.net></pre><p id="x_4b"><a name="x_4b"></a>The “<span class="quote"><code class="literal">[ui]</code></span>” line begins a
|
||||
<span class="emphasis"><em>section</em></span> of the config file, so you can
|
||||
read the “<span class="quote"><code class="literal">username = ...</code></span>”
|
||||
line as meaning “<span class="quote">set the value of the
|
||||
<code class="literal">username</code> item in the
|
||||
<code class="literal">ui</code> section</span>”. A section continues
|
||||
until a new section begins, or the end of the file.
|
||||
Mercurial ignores empty lines and treats any text from
|
||||
“<span class="quote"><code class="literal">#</code></span>” to the end of a line as
|
||||
a comment.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id347496">Choosing a user name</h4></div></div></div><p id="x_4c"><a name="x_4c"></a>You can use any text you like as the value of
|
||||
the <code class="literal">username</code> 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.</p><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_4d"><a name="x_4d"></a>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.</p></td></tr></table></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id347526">Writing a commit message</h3></div></div></div><p id="x_4e"><a name="x_4e"></a>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 <span class="emphasis"><em>commit message</em></span>. It will be a record
|
||||
for readers of what we did and why, and it will be printed by
|
||||
<span class="command"><strong>hg log</strong></span> after we've finished
|
||||
committing.</p><pre id="id347893" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg commit</code></strong>
|
||||
</pre><p id="x_4f"><a name="x_4f"></a>The editor that the <span class="command"><strong>hg
|
||||
commit</strong></span> command drops us into will contain an empty
|
||||
line or two, followed by a number of lines starting with
|
||||
“<span class="quote"><code class="literal">HG:</code></span>”.</p><pre id="id347851" class="programlisting">
|
||||
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</pre><p id="x_50"><a name="x_50"></a>Mercurial ignores the lines that start with
|
||||
“<span class="quote"><code class="literal">HG:</code></span>”; it uses them only to
|
||||
tell us which files it's recording changes to. Modifying or
|
||||
deleting these lines has no effect.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id347874">Writing a good commit message</h3></div></div></div><p id="x_51"><a name="x_51"></a>Since <span class="command"><strong>hg log</strong></span>
|
||||
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
|
||||
<span class="emphasis"><em>doesn't</em></span> follow this guideline, and hence
|
||||
has a summary that is not readable.</p><pre id="id347584" class="programlisting">
|
||||
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.</pre><p id="x_52"><a name="x_52"></a>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.</p><p id="x_53"><a name="x_53"></a>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 <span class="command"><strong>hg log --patch</strong></span>.</p><p id="x_55"><a name="x_55"></a>If we run the <span class="command"><strong>hg
|
||||
commit</strong></span> command without any arguments, it records
|
||||
all of the changes we've made, as reported by <span class="command"><strong>hg status</strong></span> and <span class="command"><strong>hg diff</strong></span>.</p><div class="note"><table border="0" summary="Note: A surprise for Subversion users"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">A surprise for Subversion users</th></tr><tr><td align="left" valign="top"><p id="x_717"><a name="x_717"></a>Like other Mercurial commands, if we don't supply
|
||||
explicit names to commit to the <span class="command"><strong>hg
|
||||
commit</strong></span>, 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.</p></td></tr></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id347674">Aborting a commit</h3></div></div></div><p id="x_54"><a name="x_54"></a>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.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id347689">Admiring our new handiwork</h3></div></div></div><p id="x_56"><a name="x_56"></a>Once we've finished the commit, we can use the
|
||||
<span class="command"><strong>hg tip</strong></span> command to display the
|
||||
changeset we just created. This command produces output that
|
||||
is identical to <span class="command"><strong>hg log</strong></span>, but
|
||||
it only displays the newest revision in the repository.</p><pre id="id347781" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tip -vp</code></strong>
|
||||
changeset: 5:b6fed4f21233
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:53 2009 +0000
|
||||
files: hello.c
|
||||
description:
|
||||
Added an extra line of output
|
||||
|
||||
|
||||
diff -r 2278160e78d4 -r b6fed4f21233 hello.c
|
||||
--- a/hello.c Sat Aug 16 22:16:53 2008 +0200
|
||||
+++ b/hello.c Tue May 05 06:55:53 2009 +0000
|
||||
@@ -8,5 +8,6 @@
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("hello, world!\");
|
||||
+ printf("hello again!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
</pre><p id="x_57"><a name="x_57"></a>We refer to the newest revision in the
|
||||
repository as the <span class="emphasis"><em>tip revision</em></span>, or simply
|
||||
the <span class="emphasis"><em>tip</em></span>.</p><p id="x_684"><a name="x_684"></a>By the way, the <span class="command"><strong>hg tip</strong></span>
|
||||
command accepts many of the same options as <span class="command"><strong>hg log</strong></span>, so <code class="option">-v</code> above indicates “<span class="quote">be
|
||||
verbose</span>”, <code class="option">-p</code>
|
||||
specifies “<span class="quote">print a patch</span>”. The use of <code class="option">-p</code> to print patches is another
|
||||
example of the consistent naming we mentioned earlier.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id347917">Sharing changes</h2></div></div></div><p id="x_58"><a name="x_58"></a>We mentioned earlier that repositories in
|
||||
Mercurial are self-contained. This means that the changeset we
|
||||
just created exists only in our <code class="filename">my-hello</code> repository. Let's look
|
||||
at a few ways that we can propagate this change into other
|
||||
repositories.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:tour:pull">Pulling changes from another repository</h3></div></div></div><p id="x_59"><a name="x_59"></a>To get started, let's clone our original
|
||||
<code class="filename">hello</code> repository, which
|
||||
does not contain the change we just committed. We'll call our
|
||||
temporary repository <code class="filename">hello-pull</code>.</p><pre id="id348308" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone hello hello-pull</code></strong>
|
||||
updating working directory
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_5a"><a name="x_5a"></a>We'll use the <span class="command"><strong>hg
|
||||
pull</strong></span> command to bring changes from <code class="filename">my-hello</code> into <code class="filename">hello-pull</code>. However, blindly
|
||||
pulling unknown changes into a repository is a somewhat scary
|
||||
prospect. Mercurial provides the <span class="command"><strong>hg
|
||||
incoming</strong></span> command to tell us what changes the
|
||||
<span class="command"><strong>hg pull</strong></span> command
|
||||
<span class="emphasis"><em>would</em></span> pull into the repository, without
|
||||
actually pulling the changes in.</p><pre id="id348276" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd hello-pull</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg incoming ../my-hello</code></strong>
|
||||
comparing with ../my-hello
|
||||
searching for changes
|
||||
changeset: 5:b6fed4f21233
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:53 2009 +0000
|
||||
summary: Added an extra line of output
|
||||
|
||||
</pre><p id="x_5c"><a name="x_5c"></a>Bringing changes into a repository is a simple
|
||||
matter of running the <span class="command"><strong>hg pull</strong></span>
|
||||
command, and optionally telling it which repository to pull from.</p><pre id="id348143" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 4:2278160e78d4
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:16:53 2008 +0200
|
||||
summary: Trim comments.
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg pull ../my-hello</code></strong>
|
||||
pulling from ../my-hello
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files
|
||||
(run 'hg update' to get a working copy)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 5:b6fed4f21233
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:53 2009 +0000
|
||||
summary: Added an extra line of output
|
||||
|
||||
</pre><p id="x_5d"><a name="x_5d"></a>As you can see from the before-and-after output
|
||||
of <span class="command"><strong>hg tip</strong></span>, 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.</p><div class="tip"><table border="0" summary="Tip: Pulling specific changes"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="/support/figs/tip.png"></td><th align="left">Pulling specific changes</th></tr><tr><td align="left" valign="top"><p id="x_5b"><a name="x_5b"></a>It is possible that due to the delay between
|
||||
running <span class="command"><strong>hg incoming</strong></span> and
|
||||
<span class="command"><strong>hg pull</strong></span>, 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
|
||||
<span class="command"><strong>hg incoming</strong></span> 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
|
||||
<span class="command"><strong>hg incoming</strong></span>.</p><p id="x_718"><a name="x_718"></a>If you only want to pull precisely the changes that were
|
||||
listed by <span class="command"><strong>hg incoming</strong></span>, 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. <span class="command"><strong>hg pull
|
||||
-r7e95bb</strong></span>.</p></td></tr></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id348343">Updating the working directory</h3></div></div></div><p id="x_5e"><a name="x_5e"></a>We have so far glossed over the relationship
|
||||
between a repository and its working directory. The <span class="command"><strong>hg pull</strong></span> command that we ran in
|
||||
<a class="xref" href="a-tour-of-mercurial-the-basics.html#sec:tour:pull" title="Pulling changes from another repository">the section called “Pulling changes from another repository”</a> brought changes into the
|
||||
repository, but if we check, there's no sign of those changes
|
||||
in the working directory. This is because <span class="command"><strong>hg pull</strong></span> does not (by default) touch
|
||||
the working directory. Instead, we use the <span class="command"><strong>hg update</strong></span> command to do this.</p><pre id="id348753" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>grep printf hello.c</code></strong>
|
||||
printf("hello, world!\");
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg update tip</code></strong>
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>grep printf hello.c</code></strong>
|
||||
printf("hello, world!\");
|
||||
printf("hello again!\n");
|
||||
</pre><p id="x_5f"><a name="x_5f"></a>It might seem a bit strange that <span class="command"><strong>hg pull</strong></span> doesn't update the working
|
||||
directory automatically. There's actually a good reason for
|
||||
this: you can use <span class="command"><strong>hg update</strong></span>
|
||||
to update the working directory to the state it was in at
|
||||
<span class="emphasis"><em>any revision</em></span> 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 <span class="command"><strong>hg pull</strong></span>
|
||||
which automatically updated the working directory to a new
|
||||
revision, you might not be terribly happy.</p><p id="x_60"><a name="x_60"></a>Since pull-then-update is such a common sequence
|
||||
of operations, Mercurial lets you combine the two by passing
|
||||
the <code class="option">-u</code> option to <span class="command"><strong>hg pull</strong></span>.</p><p id="x_61"><a name="x_61"></a>If you look back at the output of <span class="command"><strong>hg pull</strong></span> in <a class="xref" href="a-tour-of-mercurial-the-basics.html#sec:tour:pull" title="Pulling changes from another repository">the section called “Pulling changes from another repository”</a> when we ran it without <code class="option">-u</code>, you can see that it printed
|
||||
a helpful reminder that we'd have to take an explicit step to
|
||||
update the working directory.</p><p id="x_62"><a name="x_62"></a>To find out what revision the working directory
|
||||
is at, use the <span class="command"><strong>hg parents</strong></span>
|
||||
command.</p><pre id="id348724" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong>
|
||||
changeset: 5:b6fed4f21233
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:53 2009 +0000
|
||||
summary: Added an extra line of output
|
||||
|
||||
</pre><p id="x_63"><a name="x_63"></a>If you look back at <a class="xref" href="a-tour-of-mercurial-the-basics.html#fig:tour-basic:history" title="Figure 2.1. Graphical history of the hello repository">Figure 2.1, “Graphical history of the hello repository”</a>, you'll see arrows
|
||||
connecting each changeset. The node that the arrow leads
|
||||
<span class="emphasis"><em>from</em></span> in each case is a parent, and the
|
||||
node that the arrow leads <span class="emphasis"><em>to</em></span> is its
|
||||
child. The working directory has a parent in just the same
|
||||
way; this is the changeset that the working directory
|
||||
currently contains.</p><p id="x_64"><a name="x_64"></a>To update the working directory to a particular
|
||||
revision, give a revision number or changeset ID to the
|
||||
<span class="command"><strong>hg update</strong></span> command.</p><pre id="id348699" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg update 2</code></strong>
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong>
|
||||
changeset: 2:fef857204a0c
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Sat Aug 16 22:05:04 2008 +0200
|
||||
summary: Introduce a typo into hello.c.
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg update</code></strong>
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong>
|
||||
changeset: 5:b6fed4f21233
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:53 2009 +0000
|
||||
summary: Added an extra line of output
|
||||
|
||||
</pre><p id="x_65"><a name="x_65"></a>If you omit an explicit revision, <span class="command"><strong>hg update</strong></span> will update to the tip
|
||||
revision, as shown by the second call to <span class="command"><strong>hg update</strong></span> in the example
|
||||
above.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id348825">Pushing changes to another repository</h3></div></div></div><p id="x_66"><a name="x_66"></a>Mercurial lets us push changes to another
|
||||
repository, from the repository we're currently visiting. As
|
||||
with the example of <span class="command"><strong>hg pull</strong></span>
|
||||
above, we'll create a temporary repository to push our changes
|
||||
into.</p><pre id="id349042" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone hello hello-push</code></strong>
|
||||
updating working directory
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_67"><a name="x_67"></a>The <span class="command"><strong>hg outgoing</strong></span>
|
||||
command tells us what changes would be pushed into another
|
||||
repository.</p><pre id="id348976" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd my-hello</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg outgoing ../hello-push</code></strong>
|
||||
comparing with ../hello-push
|
||||
searching for changes
|
||||
changeset: 5:b6fed4f21233
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:53 2009 +0000
|
||||
summary: Added an extra line of output
|
||||
|
||||
</pre><p id="x_68"><a name="x_68"></a>And the <span class="command"><strong>hg push</strong></span>
|
||||
command does the actual push.</p><pre id="id349027" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg push ../hello-push</code></strong>
|
||||
pushing to ../hello-push
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files
|
||||
</pre><p id="x_69"><a name="x_69"></a>As with <span class="command"><strong>hg
|
||||
pull</strong></span>, the <span class="command"><strong>hg push</strong></span>
|
||||
command does not update the working directory in the
|
||||
repository that it's pushing changes into. Unlike <span class="command"><strong>hg pull</strong></span>, <span class="command"><strong>hg
|
||||
push</strong></span> does not provide a <code class="literal">-u</code>
|
||||
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.</p><p id="x_6a"><a name="x_6a"></a>What happens if we try to pull or push changes
|
||||
and the receiving repository already has those changes?
|
||||
Nothing too exciting.</p><pre id="id349466" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg push ../hello-push</code></strong>
|
||||
pushing to ../hello-push
|
||||
searching for changes
|
||||
no changes found
|
||||
</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id349161">Default locations</h3></div></div></div><p id="x_719"><a name="x_719"></a>When we clone a repository, Mercurial records the location
|
||||
of the repository we cloned in the
|
||||
<code class="filename">.hg/hgrc</code> file of the new repository. If
|
||||
we don't supply a location to <span class="command"><strong>hg pull</strong></span> from
|
||||
or <span class="command"><strong>hg push</strong></span> to, those commands will use this
|
||||
location as a default. The <span class="command"><strong>hg incoming</strong></span>
|
||||
and <span class="command"><strong>hg outgoing</strong></span> commands do so too.</p><p id="x_71a"><a name="x_71a"></a>If you open a repository's <code class="filename">.hg/hgrc</code>
|
||||
file in a text editor, you will see contents like the
|
||||
following.</p><pre id="id349215" class="programlisting">[paths]
|
||||
default = http://www.selenic.com/repo/hg</pre><p id="x_71b"><a name="x_71b"></a>It is possible—and often useful—to have the
|
||||
default location for <span class="command"><strong>hg push</strong></span> and
|
||||
<span class="command"><strong>hg outgoing</strong></span> be different from those for
|
||||
<span class="command"><strong>hg pull</strong></span> and <span class="command"><strong>hg incoming</strong></span>.
|
||||
We can do this by adding a <code class="literal">default-push</code>
|
||||
entry to the <code class="literal">[paths]</code> section of the
|
||||
<code class="filename">.hg/hgrc</code> file, as follows.</p><pre id="id349269" class="programlisting">[paths]
|
||||
default = http://www.selenic.com/repo/hg
|
||||
default-push = http://hg.example.com/hg</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id349277">Sharing changes over a network</h3></div></div></div><p id="x_6b"><a name="x_6b"></a>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.</p><pre id="id349432" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg outgoing https://bitbucket.org/bos/hg-tutorial-hello</code></strong>
|
||||
comparing with https://bitbucket.org/bos/hg-tutorial-hello
|
||||
searching for changes
|
||||
changeset: 5:b6fed4f21233
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:53 2009 +0000
|
||||
summary: Added an extra line of output
|
||||
|
||||
</pre><p id="x_6c"><a name="x_6c"></a>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.</p><pre id="id349340" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg push http://bitbucket.org/bos/hg-tutorial-hello</code></strong>
|
||||
pushing to http://bitbucket.org/bos/hg-tutorial-hello
|
||||
searching for changes
|
||||
ssl required
|
||||
</pre></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id349357">Starting a new project</h2></div></div></div><p id="x_71c"><a name="x_71c"></a>It is just as easy to begin a new project as to work on one
|
||||
that already exists. The <span class="command"><strong>hg init</strong></span> command
|
||||
creates a new, empty Mercurial repository.</p><pre id="id349764" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init myproject</code></strong>
|
||||
</pre><p id="x_71d"><a name="x_71d"></a>This simply creates a repository named
|
||||
<code class="filename">myproject</code> in the current directory.</p><pre id="id349756" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>ls -l</code></strong>
|
||||
total 12
|
||||
-rw-rw-r-- 1 bos bos 47 May 5 06:55 goodbye.c
|
||||
-rw-rw-r-- 1 bos bos 45 May 5 06:55 hello.c
|
||||
drwxrwxr-x 3 bos bos 4096 May 5 06:55 myproject
|
||||
</pre><p id="x_71e"><a name="x_71e"></a>We can tell that <code class="filename">myproject</code> is a
|
||||
Mercurial repository, because it contains a
|
||||
<code class="filename">.hg</code> directory.</p><pre id="id349704" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>ls -al myproject</code></strong>
|
||||
total 12
|
||||
drwxrwxr-x 3 bos bos 4096 May 5 06:55 .
|
||||
drwx------ 3 bos bos 4096 May 5 06:55 ..
|
||||
drwxrwxr-x 3 bos bos 4096 May 5 06:55 .hg
|
||||
</pre><p id="x_71f"><a name="x_71f"></a>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 <span class="command"><strong>hg add</strong></span> command.</p><pre id="id349672" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd myproject</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cp ../hello.c .</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cp ../goodbye.c .</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add</code></strong>
|
||||
adding goodbye.c
|
||||
adding hello.c
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
A goodbye.c
|
||||
A hello.c
|
||||
</pre><p id="x_720"><a name="x_720"></a>Once we are satisfied that our project looks right, we
|
||||
commit our changes.</p><pre id="id349661" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Initial commit'</code></strong>
|
||||
</pre><p id="x_721"><a name="x_721"></a>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.</p></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.id346621" href="#id346621" class="para">1</a>] </sup>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.</p></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="how-did-we-get-here.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="a-tour-of-mercurial-merging-work.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 1. How did we get here? </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 3. A tour of Mercurial: merging work</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
335
read/adding-functionality-with-extensions.html
Normal file
335
read/adding-functionality-with-extensions.html
Normal file
|
@ -0,0 +1,335 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 14. Adding functionality with extensions</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="advanced-uses-of-mercurial-queues.html" title="Chapter 13. Advanced uses of Mercurial Queues"><link rel="next" href="migrating-to-mercurial.html" title="Appendix A. Migrating to Mercurial"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 14. Adding functionality with extensions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="advanced-uses-of-mercurial-queues.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="migrating-to-mercurial.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:hgext"><div class="titlepage"><div><div><h2 class="title">Chapter 14. Adding functionality with extensions</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="adding-functionality-with-extensions.html#sec:hgext:inotify">Improve performance with the inotify extension</a></span></dt><dt><span class="sect1"><a href="adding-functionality-with-extensions.html#sec:hgext:extdiff">Flexible diff support with the extdiff extension</a></span></dt><dd><dl><dt><span class="sect2"><a href="adding-functionality-with-extensions.html#id439166">Defining command aliases</a></span></dt></dl></dd><dt><span class="sect1"><a href="adding-functionality-with-extensions.html#sec:hgext:transplant">Cherrypicking changes with the transplant extension</a></span></dt><dt><span class="sect1"><a href="adding-functionality-with-extensions.html#sec:hgext:patchbomb">Send changes via email with the patchbomb extension</a></span></dt><dd><dl><dt><span class="sect2"><a href="adding-functionality-with-extensions.html#id439402">Changing the behavior of patchbombs</a></span></dt></dl></dd></dl></div><p id="x_4fe"><a name="x_4fe"></a>While the core of Mercurial is quite complete from a
|
||||
functionality standpoint, it's deliberately shorn of fancy
|
||||
features. This approach of preserving simplicity keeps the
|
||||
software easy to deal with for both maintainers and users.</p><p id="x_4ff"><a name="x_4ff"></a>However, Mercurial doesn't box you in with an inflexible
|
||||
command set: you can add features to it as
|
||||
<span class="emphasis"><em>extensions</em></span> (sometimes known as
|
||||
<span class="emphasis"><em>plugins</em></span>). We've already discussed a few of
|
||||
these extensions in earlier chapters.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_500"><a name="x_500"></a><a class="xref" href="a-tour-of-mercurial-merging-work.html#sec:tour-merge:fetch" title="Simplifying the pull-merge-commit sequence">the section called “Simplifying the pull-merge-commit sequence”</a>
|
||||
covers the <code class="literal">fetch</code> extension;
|
||||
this combines pulling new changes and merging them with local
|
||||
changes into a single command, <span class="command"><strong>fetch</strong></span>.</p></li><li><p id="x_501"><a name="x_501"></a>In <a class="xref" href="handling-repository-events-with-hooks.html" title="Chapter 10. Handling repository events with hooks">Chapter 10, <i>Handling repository events with hooks</i></a>, we covered
|
||||
several extensions that are useful for hook-related
|
||||
functionality: <code class="literal">acl</code> adds
|
||||
access control lists; <code class="literal">bugzilla</code> adds integration with the
|
||||
Bugzilla bug tracking system; and <code class="literal">notify</code> sends notification emails on
|
||||
new changes.</p></li><li><p id="x_502"><a name="x_502"></a>The Mercurial Queues patch management extension is
|
||||
so invaluable that it merits two chapters and an appendix all
|
||||
to itself. <a class="xref" href="managing-change-with-mercurial-queues.html" title="Chapter 12. Managing change with Mercurial Queues">Chapter 12, <i>Managing change with Mercurial Queues</i></a> covers the
|
||||
basics; <a class="xref" href="advanced-uses-of-mercurial-queues.html" title="Chapter 13. Advanced uses of Mercurial Queues">Chapter 13, <i>Advanced uses of Mercurial Queues</i></a> discusses advanced topics;
|
||||
and <a class="xref" href="mercurial-queues-reference.html" title="Appendix B. Mercurial Queues reference">Appendix B, <i>Mercurial Queues reference</i></a> goes into detail on
|
||||
each
|
||||
command.</p></li></ul></div><p id="x_503"><a name="x_503"></a>In this chapter, we'll cover some of the other extensions that
|
||||
are available for Mercurial, and briefly touch on some of the
|
||||
machinery you'll need to know about if you want to write an
|
||||
extension of your own.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_504"><a name="x_504"></a>In <a class="xref" href="adding-functionality-with-extensions.html#sec:hgext:inotify" title="Improve performance with the inotify extension">the section called “Improve performance with the inotify extension”</a>,
|
||||
we'll discuss the possibility of <span class="emphasis"><em>huge</em></span>
|
||||
performance improvements using the <code class="literal">inotify</code> extension.</p></li></ul></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:hgext:inotify">Improve performance with the <code class="literal">inotify</code> extension</h2></div></div></div><p id="x_505"><a name="x_505"></a>Are you interested in having some of the most common
|
||||
Mercurial operations run as much as a hundred times faster?
|
||||
Read on!</p><p id="x_506"><a name="x_506"></a>Mercurial has great performance under normal circumstances.
|
||||
For example, when you run the <span class="command"><strong>hg
|
||||
status</strong></span> command, Mercurial has to scan almost every
|
||||
directory and file in your repository so that it can display
|
||||
file status. Many other Mercurial commands need to do the same
|
||||
work behind the scenes; for example, the <span class="command"><strong>hg diff</strong></span> command uses the status
|
||||
machinery to avoid doing an expensive comparison operation on
|
||||
files that obviously haven't changed.</p><p id="x_507"><a name="x_507"></a>Because obtaining file status is crucial to good
|
||||
performance, the authors of Mercurial have optimised this code
|
||||
to within an inch of its life. However, there's no avoiding the
|
||||
fact that when you run <span class="command"><strong>hg
|
||||
status</strong></span>, Mercurial is going to have to perform at
|
||||
least one expensive system call for each managed file to
|
||||
determine whether it's changed since the last time Mercurial
|
||||
checked. For a sufficiently large repository, this can take a
|
||||
long time.</p><p id="x_508"><a name="x_508"></a>To put a number on the magnitude of this effect, I created a
|
||||
repository containing 150,000 managed files. I timed <span class="command"><strong>hg status</strong></span> as taking ten seconds to
|
||||
run, even when <span class="emphasis"><em>none</em></span> of those files had been
|
||||
modified.</p><p id="x_509"><a name="x_509"></a>Many modern operating systems contain a file notification
|
||||
facility. If a program signs up to an appropriate service, the
|
||||
operating system will notify it every time a file of interest is
|
||||
created, modified, or deleted. On Linux systems, the kernel
|
||||
component that does this is called
|
||||
<code class="literal">inotify</code>.</p><p id="x_50a"><a name="x_50a"></a>Mercurial's <code class="literal">inotify</code>
|
||||
extension talks to the kernel's <code class="literal">inotify</code>
|
||||
component to optimise <span class="command"><strong>hg status</strong></span>
|
||||
commands. The extension has two components. A daemon sits in
|
||||
the background and receives notifications from the
|
||||
<code class="literal">inotify</code> subsystem. It also listens for
|
||||
connections from a regular Mercurial command. The extension
|
||||
modifies Mercurial's behavior so that instead of scanning the
|
||||
filesystem, it queries the daemon. Since the daemon has perfect
|
||||
information about the state of the repository, it can respond
|
||||
with a result instantaneously, avoiding the need to scan every
|
||||
directory and file in the repository.</p><p id="x_50b"><a name="x_50b"></a>Recall the ten seconds that I measured plain Mercurial as
|
||||
taking to run <span class="command"><strong>hg status</strong></span> on a
|
||||
150,000 file repository. With the <code class="literal">inotify</code> extension enabled, the time
|
||||
dropped to 0.1 seconds, a factor of <span class="emphasis"><em>one
|
||||
hundred</em></span> faster.</p><p id="x_50c"><a name="x_50c"></a>Before we continue, please pay attention to some
|
||||
caveats.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_50d"><a name="x_50d"></a>The <code class="literal">inotify</code>
|
||||
extension is Linux-specific. Because it interfaces directly
|
||||
to the Linux kernel's <code class="literal">inotify</code> subsystem,
|
||||
it does not work on other operating systems.</p></li><li><p id="x_50e"><a name="x_50e"></a>It should work on any Linux distribution that
|
||||
was released after early 2005. Older distributions are
|
||||
likely to have a kernel that lacks
|
||||
<code class="literal">inotify</code>, or a version of
|
||||
<code class="literal">glibc</code> that does not have the necessary
|
||||
interfacing support.</p></li><li><p id="x_50f"><a name="x_50f"></a>Not all filesystems are suitable for use with
|
||||
the <code class="literal">inotify</code> extension.
|
||||
Network filesystems such as NFS are a non-starter, for
|
||||
example, particularly if you're running Mercurial on several
|
||||
systems, all mounting the same network filesystem. The
|
||||
kernel's <code class="literal">inotify</code> system has no way of
|
||||
knowing about changes made on another system. Most local
|
||||
filesystems (e.g. ext3, XFS, ReiserFS) should work
|
||||
fine.</p></li></ul></div><p id="x_510"><a name="x_510"></a>The <code class="literal">inotify</code> extension is
|
||||
not yet shipped with Mercurial as of May 2007, so it's a little
|
||||
more involved to set up than other extensions. But the
|
||||
performance improvement is worth it!</p><p id="x_511"><a name="x_511"></a>The extension currently comes in two parts: a set of patches
|
||||
to the Mercurial source code, and a library of Python bindings
|
||||
to the <code class="literal">inotify</code> subsystem.</p><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_512"><a name="x_512"></a> There are <span class="emphasis"><em>two</em></span> Python
|
||||
<code class="literal">inotify</code> binding libraries. One of them is
|
||||
called <code class="literal">pyinotify</code>, and is packaged by some
|
||||
Linux distributions as <code class="literal">python-inotify</code>.
|
||||
This is <span class="emphasis"><em>not</em></span> the one you'll need, as it is
|
||||
too buggy and inefficient to be practical.</p></td></tr></table></div><p id="x_513"><a name="x_513"></a>To get going, it's best to already have a functioning copy
|
||||
of Mercurial installed.</p><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_514"><a name="x_514"></a> If you follow the instructions below, you'll be
|
||||
<span class="emphasis"><em>replacing</em></span> and overwriting any existing
|
||||
installation of Mercurial that you might already have, using
|
||||
the latest “<span class="quote">bleeding edge</span>” Mercurial code. Don't
|
||||
say you weren't warned!</p></td></tr></table></div><div class="orderedlist"><ol type="1"><li><p id="x_515"><a name="x_515"></a>Clone the Python <code class="literal">inotify</code>
|
||||
binding repository. Build and install it.</p><pre id="id438117" class="programlisting">hg clone http://hg.kublai.com/python/inotify
|
||||
cd inotify
|
||||
python setup.py build --force
|
||||
sudo python setup.py install --skip-build</pre></li><li><p id="x_516"><a name="x_516"></a>Clone the <code class="filename">crew</code> Mercurial repository.
|
||||
Clone the <code class="literal">inotify</code> patch
|
||||
repository so that Mercurial Queues will be able to apply
|
||||
patches to your cope of the <code class="filename">crew</code> repository.</p><pre id="id438158" class="programlisting">hg clone http://hg.intevation.org/mercurial/crew
|
||||
hg clone crew inotify
|
||||
hg clone http://hg.kublai.com/mercurial/patches/inotify inotify/.hg/patches</pre></li><li><p id="x_517"><a name="x_517"></a>Make sure that you have the Mercurial Queues
|
||||
extension, <code class="literal">mq</code>, enabled. If
|
||||
you've never used MQ, read <a class="xref" href="managing-change-with-mercurial-queues.html#sec:mq:start" title="Getting started with Mercurial Queues">the section called “Getting started with Mercurial Queues”</a> to get started
|
||||
quickly.</p></li><li><p id="x_518"><a name="x_518"></a>Go into the <code class="filename">inotify</code> repo, and apply all
|
||||
of the <code class="literal">inotify</code> patches
|
||||
using the <code class="option">hg
|
||||
-a</code> option to the <span class="command"><strong>qpush</strong></span> command.</p><pre id="id438230" class="programlisting">cd inotify
|
||||
hg qpush -a</pre></li><li><p id="x_519"><a name="x_519"></a> If you get an error message from <span class="command"><strong>qpush</strong></span>, you should not continue.
|
||||
Instead, ask for help.</p></li><li><p id="x_51a"><a name="x_51a"></a>Build and install the patched version of
|
||||
Mercurial.</p><pre id="id438263" class="programlisting">python setup.py build --force
|
||||
sudo python setup.py install --skip-build</pre></li></ol></div><p id="x_51b"><a name="x_51b"></a>Once you've build a suitably patched version of Mercurial,
|
||||
all you need to do to enable the <code class="literal">inotify</code> extension is add an entry to
|
||||
your <code class="filename">~/.hgrc</code>.</p><pre id="id438295" class="programlisting">[extensions] inotify =</pre><p id="x_51c"><a name="x_51c"></a>When the <code class="literal">inotify</code> extension
|
||||
is enabled, Mercurial will automatically and transparently start
|
||||
the status daemon the first time you run a command that needs
|
||||
status in a repository. It runs one status daemon per
|
||||
repository.</p><p id="x_51d"><a name="x_51d"></a>The status daemon is started silently, and runs in the
|
||||
background. If you look at a list of running processes after
|
||||
you've enabled the <code class="literal">inotify</code>
|
||||
extension and run a few commands in different repositories,
|
||||
you'll thus see a few <code class="literal">hg</code> processes sitting
|
||||
around, waiting for updates from the kernel and queries from
|
||||
Mercurial.</p><p id="x_51e"><a name="x_51e"></a>The first time you run a Mercurial command in a repository
|
||||
when you have the <code class="literal">inotify</code>
|
||||
extension enabled, it will run with about the same performance
|
||||
as a normal Mercurial command. This is because the status
|
||||
daemon needs to perform a normal status scan so that it has a
|
||||
baseline against which to apply later updates from the kernel.
|
||||
However, <span class="emphasis"><em>every</em></span> subsequent command that does
|
||||
any kind of status check should be noticeably faster on
|
||||
repositories of even fairly modest size. Better yet, the bigger
|
||||
your repository is, the greater a performance advantage you'll
|
||||
see. The <code class="literal">inotify</code> daemon makes
|
||||
status operations almost instantaneous on repositories of all
|
||||
sizes!</p><p id="x_51f"><a name="x_51f"></a>If you like, you can manually start a status daemon using
|
||||
the <span class="command"><strong>inserve</strong></span> command.
|
||||
This gives you slightly finer control over how the daemon ought
|
||||
to run. This command will of course only be available when the
|
||||
<code class="literal">inotify</code> extension is
|
||||
enabled.</p><p id="x_520"><a name="x_520"></a>When you're using the <code class="literal">inotify</code> extension, you should notice
|
||||
<span class="emphasis"><em>no difference at all</em></span> in Mercurial's
|
||||
behavior, with the sole exception of status-related commands
|
||||
running a whole lot faster than they used to. You should
|
||||
specifically expect that commands will not print different
|
||||
output; neither should they give different results. If either of
|
||||
these situations occurs, please report a bug.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:hgext:extdiff">Flexible diff support with the <code class="literal">extdiff</code> extension</h2></div></div></div><p id="x_521"><a name="x_521"></a>Mercurial's built-in <span class="command"><strong>hg
|
||||
diff</strong></span> command outputs plaintext unified diffs.</p><pre id="id438805" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg diff</code></strong>
|
||||
diff -r cfed5c378cc5 myfile
|
||||
--- a/myfile Tue May 05 06:55:34 2009 +0000
|
||||
+++ b/myfile Tue May 05 06:55:34 2009 +0000
|
||||
@@ -1,1 +1,2 @@
|
||||
The first line.
|
||||
+The second line.
|
||||
</pre><p id="x_522"><a name="x_522"></a>If you would like to use an external tool to display
|
||||
modifications, you'll want to use the <code class="literal">extdiff</code> extension. This will let you
|
||||
use, for example, a graphical diff tool.</p><p id="x_523"><a name="x_523"></a>The <code class="literal">extdiff</code> extension is
|
||||
bundled with Mercurial, so it's easy to set up. In the <code class="literal">extensions</code> section of your
|
||||
<code class="filename">~/.hgrc</code>, simply add a
|
||||
one-line entry to enable the extension.</p><pre id="id438765" class="programlisting">[extensions]
|
||||
extdiff =</pre><p id="x_524"><a name="x_524"></a>This introduces a command named <span class="command"><strong>extdiff</strong></span>, which by default uses
|
||||
your system's <span class="command"><strong>diff</strong></span> command to generate a
|
||||
unified diff in the same form as the built-in <span class="command"><strong>hg diff</strong></span> command.</p><pre id="id438707" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg extdiff</code></strong>
|
||||
--- a.cfed5c378cc5/myfile 2009-05-05 06:55:34.000000000 +0000
|
||||
+++ /tmp/extdiffXdA7FH/a/myfile 2009-05-05 06:55:34.000000000 +0000
|
||||
@@ -1 +1,2 @@
|
||||
The first line.
|
||||
+The second line.
|
||||
</pre><p id="x_525"><a name="x_525"></a>The result won't be exactly the same as with the built-in
|
||||
<span class="command"><strong>hg diff</strong></span> variations, because the
|
||||
output of <span class="command"><strong>diff</strong></span> varies from one system to
|
||||
another, even when passed the same options.</p><p id="x_526"><a name="x_526"></a>As the “<span class="quote"><code class="literal">making snapshot</code></span>”
|
||||
lines of output above imply, the <span class="command"><strong>extdiff</strong></span> command works by
|
||||
creating two snapshots of your source tree. The first snapshot
|
||||
is of the source revision; the second, of the target revision or
|
||||
working directory. The <span class="command"><strong>extdiff</strong></span> command generates
|
||||
these snapshots in a temporary directory, passes the name of
|
||||
each directory to an external diff viewer, then deletes the
|
||||
temporary directory. For efficiency, it only snapshots the
|
||||
directories and files that have changed between the two
|
||||
revisions.</p><p id="x_527"><a name="x_527"></a>Snapshot directory names have the same base name as your
|
||||
repository. If your repository path is <code class="filename">/quux/bar/foo</code>, then <code class="filename">foo</code> will be the name of each
|
||||
snapshot directory. Each snapshot directory name has its
|
||||
changeset ID appended, if appropriate. If a snapshot is of
|
||||
revision <code class="literal">a631aca1083f</code>, the directory will be
|
||||
named <code class="filename">foo.a631aca1083f</code>.
|
||||
A snapshot of the working directory won't have a changeset ID
|
||||
appended, so it would just be <code class="filename">foo</code> in this example. To see what
|
||||
this looks like in practice, look again at the <span class="command"><strong>extdiff</strong></span> example above. Notice
|
||||
that the diff has the snapshot directory names embedded in its
|
||||
header.</p><p id="x_528"><a name="x_528"></a>The <span class="command"><strong>extdiff</strong></span> command
|
||||
accepts two important options. The <code class="option">hg -p</code> option
|
||||
lets you choose a program to view differences with, instead of
|
||||
<span class="command"><strong>diff</strong></span>. With the <code class="option">hg -o</code> option,
|
||||
you can change the options that <span class="command"><strong>extdiff</strong></span> passes to the program
|
||||
(by default, these options are
|
||||
“<span class="quote"><code class="literal">-Npru</code></span>”, which only make sense
|
||||
if you're running <span class="command"><strong>diff</strong></span>). In other respects,
|
||||
the <span class="command"><strong>extdiff</strong></span> command
|
||||
acts similarly to the built-in <span class="command"><strong>hg
|
||||
diff</strong></span> command: you use the same option names, syntax,
|
||||
and arguments to specify the revisions you want, the files you
|
||||
want, and so on.</p><p id="x_529"><a name="x_529"></a>As an example, here's how to run the normal system
|
||||
<span class="command"><strong>diff</strong></span> command, getting it to generate context
|
||||
diffs (using the <code class="option">-c</code> option)
|
||||
instead of unified diffs, and five lines of context instead of
|
||||
the default three (passing <code class="literal">5</code> as the argument
|
||||
to the <code class="option">-C</code> option).</p><pre id="id439206" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg extdiff -o -NprcC5</code></strong>
|
||||
*** a.cfed5c378cc5/myfile Tue May 5 06:55:34 2009
|
||||
--- /tmp/extdiffXdA7FH/a/myfile Tue May 5 06:55:34 2009
|
||||
***************
|
||||
*** 1 ****
|
||||
--- 1,2 ----
|
||||
The first line.
|
||||
+ The second line.
|
||||
</pre><p id="x_52a"><a name="x_52a"></a>Launching a visual diff tool is just as easy. Here's how to
|
||||
launch the <span class="command"><strong>kdiff3</strong></span> viewer.</p><pre id="id439133" class="programlisting">hg extdiff -p kdiff3 -o</pre><p id="x_52b"><a name="x_52b"></a>If your diff viewing command can't deal with directories,
|
||||
you can easily work around this with a little scripting. For an
|
||||
example of such scripting in action with the <code class="literal">mq</code> extension and the
|
||||
<span class="command"><strong>interdiff</strong></span> command, see <a class="xref" href="advanced-uses-of-mercurial-queues.html#mq-collab:tips:interdiff" title="Viewing the history of a patch">the section called “Viewing the history of a patch”</a>.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id439166">Defining command aliases</h3></div></div></div><p id="x_52c"><a name="x_52c"></a>It can be cumbersome to remember the options to both the
|
||||
<span class="command"><strong>extdiff</strong></span> command and
|
||||
the diff viewer you want to use, so the <code class="literal">extdiff</code> extension lets you define
|
||||
<span class="emphasis"><em>new</em></span> commands that will invoke your diff
|
||||
viewer with exactly the right options.</p><p id="x_52d"><a name="x_52d"></a>All you need to do is edit your <code class="filename">~/.hgrc</code>, and add a section named
|
||||
<code class="literal">extdiff</code>. Inside this
|
||||
section, you can define multiple commands. Here's how to add
|
||||
a <code class="literal">kdiff3</code> command. Once you've defined
|
||||
this, you can type “<span class="quote"><code class="literal">hg kdiff3</code></span>”
|
||||
and the <code class="literal">extdiff</code> extension
|
||||
will run <span class="command"><strong>kdiff3</strong></span> for you.</p><pre id="id438959" class="programlisting">[extdiff]
|
||||
cmd.kdiff3 =</pre><p id="x_52e"><a name="x_52e"></a>If you leave the right hand side of the definition empty,
|
||||
as above, the <code class="literal">extdiff</code>
|
||||
extension uses the name of the command you defined as the name
|
||||
of the external program to run. But these names don't have to
|
||||
be the same. Here, we define a command named
|
||||
“<span class="quote"><code class="literal">hg wibble</code></span>”, which runs
|
||||
<span class="command"><strong>kdiff3</strong></span>.</p><pre id="id438995" class="programlisting">[extdiff]
|
||||
cmd.wibble = kdiff3</pre><p id="x_52f"><a name="x_52f"></a>You can also specify the default options that you want to
|
||||
invoke your diff viewing program with. The prefix to use is
|
||||
“<span class="quote"><code class="literal">opts.</code></span>”, followed by the name
|
||||
of the command to which the options apply. This example
|
||||
defines a “<span class="quote"><code class="literal">hg vimdiff</code></span>” command
|
||||
that runs the <span class="command"><strong>vim</strong></span> editor's
|
||||
<code class="literal">DirDiff</code> extension.</p><pre id="id439036" class="programlisting">[extdiff]
|
||||
cmd.vimdiff = vim
|
||||
opts.vimdiff = -f '+next' '+execute "DirDiff" argv(0) argv(1)'</pre></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:hgext:transplant">Cherrypicking changes with the <code class="literal">transplant</code> extension</h2></div></div></div><p id="x_530"><a name="x_530"></a>Need to have a long chat with Brendan about this.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:hgext:patchbomb">Send changes via email with the <code class="literal">patchbomb</code> extension</h2></div></div></div><p id="x_531"><a name="x_531"></a>Many projects have a culture of “<span class="quote">change
|
||||
review</span>”, in which people send their modifications to a
|
||||
mailing list for others to read and comment on before they
|
||||
commit the final version to a shared repository. Some projects
|
||||
have people who act as gatekeepers; they apply changes from
|
||||
other people to a repository to which those others don't have
|
||||
access.</p><p id="x_532"><a name="x_532"></a>Mercurial makes it easy to send changes over email for
|
||||
review or application, via its <code class="literal">patchbomb</code> extension. The extension is
|
||||
so named because changes are formatted as patches, and it's usual
|
||||
to send one changeset per email message. Sending a long series
|
||||
of changes by email is thus much like “<span class="quote">bombing</span>” the
|
||||
recipient's inbox, hence “<span class="quote">patchbomb</span>”.</p><p id="x_533"><a name="x_533"></a>As usual, the basic configuration of the <code class="literal">patchbomb</code> extension takes just one or
|
||||
two lines in your <code class="filename">
|
||||
/.hgrc</code>.</p><pre id="id439232" class="programlisting">[extensions]
|
||||
patchbomb =</pre><p id="x_534"><a name="x_534"></a>Once you've enabled the extension, you will have a new
|
||||
command available, named <span class="command"><strong>email</strong></span>.</p><p id="x_535"><a name="x_535"></a>The safest and best way to invoke the <span class="command"><strong>email</strong></span> command is to
|
||||
<span class="emphasis"><em>always</em></span> run it first with the <code class="option">hg -n</code> option.
|
||||
This will show you what the command <span class="emphasis"><em>would</em></span>
|
||||
send, without actually sending anything. Once you've had a
|
||||
quick glance over the changes and verified that you are sending
|
||||
the right ones, you can rerun the same command, with the <code class="option">hg -n</code> option
|
||||
removed.</p><p id="x_536"><a name="x_536"></a>The <span class="command"><strong>email</strong></span> command
|
||||
accepts the same kind of revision syntax as every other
|
||||
Mercurial command. For example, this command will send every
|
||||
revision between 7 and <code class="literal">tip</code>, inclusive.</p><pre id="id439312" class="programlisting">hg email -n 7:tip</pre><p id="x_537"><a name="x_537"></a>You can also specify a <span class="emphasis"><em>repository</em></span> to
|
||||
compare with. If you provide a repository but no revisions, the
|
||||
<span class="command"><strong>email</strong></span> command will
|
||||
send all revisions in the local repository that are not present
|
||||
in the remote repository. If you additionally specify revisions
|
||||
or a branch name (the latter using the <code class="option">hg -b</code> option),
|
||||
this will constrain the revisions sent.</p><p id="x_538"><a name="x_538"></a>It's perfectly safe to run the <span class="command"><strong>email</strong></span> command without the
|
||||
names of the people you want to send to: if you do this, it will
|
||||
just prompt you for those values interactively. (If you're
|
||||
using a Linux or Unix-like system, you should have enhanced
|
||||
<code class="literal">readline</code>-style editing capabilities when
|
||||
entering those headers, too, which is useful.)</p><p id="x_539"><a name="x_539"></a>When you are sending just one revision, the <span class="command"><strong>email</strong></span> command will by
|
||||
default use the first line of the changeset description as the
|
||||
subject of the single email message it sends.</p><p id="x_53a"><a name="x_53a"></a>If you send multiple revisions, the <span class="command"><strong>email</strong></span> command will usually
|
||||
send one message per changeset. It will preface the series with
|
||||
an introductory message, in which you should describe the
|
||||
purpose of the series of changes you're sending.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id439402">Changing the behavior of patchbombs</h3></div></div></div><p id="x_53b"><a name="x_53b"></a>Not every project has exactly the same conventions for
|
||||
sending changes in email; the <code class="literal">patchbomb</code> extension tries to
|
||||
accommodate a number of variations through command line
|
||||
options.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_53c"><a name="x_53c"></a>You can write a subject for the introductory
|
||||
message on the command line using the <code class="option">hg -s</code>
|
||||
option. This takes one argument, the text of the subject
|
||||
to use.</p></li><li><p id="x_53d"><a name="x_53d"></a>To change the email address from which the
|
||||
messages originate, use the <code class="option">hg -f</code>
|
||||
option. This takes one argument, the email address to
|
||||
use.</p></li><li><p id="x_53e"><a name="x_53e"></a>The default behavior is to send unified diffs
|
||||
(see <a class="xref" href="managing-change-with-mercurial-queues.html#sec:mq:patch" title="Understanding patches">the section called “Understanding patches”</a> for a
|
||||
description of the
|
||||
format), one per message. You can send a binary bundle
|
||||
instead with the <code class="option">hg -b</code>
|
||||
option.</p></li><li><p id="x_53f"><a name="x_53f"></a>Unified diffs are normally prefaced with a
|
||||
metadata header. You can omit this, and send unadorned
|
||||
diffs, with the <code class="option">hg
|
||||
--plain</code> option.</p></li><li><p id="x_540"><a name="x_540"></a>Diffs are normally sent “<span class="quote">inline</span>”,
|
||||
in the same body part as the description of a patch. This
|
||||
makes it easiest for the largest number of readers to
|
||||
quote and respond to parts of a diff, as some mail clients
|
||||
will only quote the first MIME body part in a message. If
|
||||
you'd prefer to send the description and the diff in
|
||||
separate body parts, use the <code class="option">hg -a</code>
|
||||
option.</p></li><li><p id="x_541"><a name="x_541"></a>Instead of sending mail messages, you can
|
||||
write them to an <code class="literal">mbox</code>-format mail
|
||||
folder using the <code class="option">hg -m</code>
|
||||
option. That option takes one argument, the name of the
|
||||
file to write to.</p></li><li><p id="x_542"><a name="x_542"></a>If you would like to add a
|
||||
<span class="command"><strong>diffstat</strong></span>-format summary to each patch,
|
||||
and one to the introductory message, use the <code class="option">hg -d</code>
|
||||
option. The <span class="command"><strong>diffstat</strong></span> command displays
|
||||
a table containing the name of each file patched, the
|
||||
number of lines affected, and a histogram showing how much
|
||||
each file is modified. This gives readers a qualitative
|
||||
glance at how complex a patch is.</p></li></ul></div></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="advanced-uses-of-mercurial-queues.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="migrating-to-mercurial.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 13. Advanced uses of Mercurial Queues </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Appendix A. Migrating to Mercurial</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
350
read/advanced-uses-of-mercurial-queues.html
Normal file
350
read/advanced-uses-of-mercurial-queues.html
Normal file
|
@ -0,0 +1,350 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 13. Advanced uses of Mercurial Queues</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="managing-change-with-mercurial-queues.html" title="Chapter 12. Managing change with Mercurial Queues"><link rel="next" href="adding-functionality-with-extensions.html" title="Chapter 14. Adding functionality with extensions"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 13. Advanced uses of Mercurial Queues</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="managing-change-with-mercurial-queues.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="adding-functionality-with-extensions.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:mq-collab"><div class="titlepage"><div><div><h2 class="title">Chapter 13. Advanced uses of Mercurial Queues</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="advanced-uses-of-mercurial-queues.html#id433631">The problem of many targets</a></span></dt><dd><dl><dt><span class="sect2"><a href="advanced-uses-of-mercurial-queues.html#id433704">Tempting approaches that don't work well</a></span></dt></dl></dd><dt><span class="sect1"><a href="advanced-uses-of-mercurial-queues.html#id433787">Conditionally applying patches with guards</a></span></dt><dt><span class="sect1"><a href="advanced-uses-of-mercurial-queues.html#id433935">Controlling the guards on a patch</a></span></dt><dt><span class="sect1"><a href="advanced-uses-of-mercurial-queues.html#id434471">Selecting the guards to use</a></span></dt><dt><span class="sect1"><a href="advanced-uses-of-mercurial-queues.html#id435148">MQ's rules for applying patches</a></span></dt><dt><span class="sect1"><a href="advanced-uses-of-mercurial-queues.html#id434989">Trimming the work environment</a></span></dt><dt><span class="sect1"><a href="advanced-uses-of-mercurial-queues.html#id435034">Dividing up the series
|
||||
file</a></span></dt><dt><span class="sect1"><a href="advanced-uses-of-mercurial-queues.html#id435315">Maintaining the patch series</a></span></dt><dd><dl><dt><span class="sect2"><a href="advanced-uses-of-mercurial-queues.html#id435424">The art of writing backport patches</a></span></dt></dl></dd><dt><span class="sect1"><a href="advanced-uses-of-mercurial-queues.html#id435495">Useful tips for developing with MQ</a></span></dt><dd><dl><dt><span class="sect2"><a href="advanced-uses-of-mercurial-queues.html#id435501">Organising patches in directories</a></span></dt><dt><span class="sect2"><a href="advanced-uses-of-mercurial-queues.html#mq-collab:tips:interdiff">Viewing the history of a patch</a></span></dt></dl></dd></dl></div><p id="x_15d"><a name="x_15d"></a>While it's easy to pick up straightforward uses of Mercurial
|
||||
Queues, use of a little discipline and some of MQ's less
|
||||
frequently used capabilities makes it possible to work in
|
||||
complicated development environments.</p><p id="x_15e"><a name="x_15e"></a>In this chapter, I will use as an example a technique I have
|
||||
used to manage the development of an Infiniband device driver for
|
||||
the Linux kernel. The driver in question is large (at least as
|
||||
drivers go), with 25,000 lines of code spread across 35 source
|
||||
files. It is maintained by a small team of developers.</p><p id="x_15f"><a name="x_15f"></a>While much of the material in this chapter is specific to
|
||||
Linux, the same principles apply to any code base for which you're
|
||||
not the primary owner, and upon which you need to do a lot of
|
||||
development.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id433631">The problem of many targets</h2></div></div></div><p id="x_160"><a name="x_160"></a>The Linux kernel changes rapidly, and has never been
|
||||
internally stable; developers frequently make drastic changes
|
||||
between releases. This means that a version of the driver that
|
||||
works well with a particular released version of the kernel will
|
||||
not even <span class="emphasis"><em>compile</em></span> correctly against,
|
||||
typically, any other version.</p><p id="x_161"><a name="x_161"></a>To maintain a driver, we have to keep a number of distinct
|
||||
versions of Linux in mind.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_162"><a name="x_162"></a>One target is the main Linux kernel development
|
||||
tree. Maintenance of the code is in this case partly shared
|
||||
by other developers in the kernel community, who make
|
||||
“<span class="quote">drive-by</span>” modifications to the driver as they
|
||||
develop and refine kernel subsystems.</p></li><li><p id="x_163"><a name="x_163"></a>We also maintain a number of
|
||||
“<span class="quote">backports</span>” to older versions of the Linux
|
||||
kernel, to support the needs of customers who are running
|
||||
older Linux distributions that do not incorporate our
|
||||
drivers. (To <span class="emphasis"><em>backport</em></span> a piece of code
|
||||
is to modify it to work in an older version of its target
|
||||
environment than the version it was developed for.)</p></li><li><p id="x_164"><a name="x_164"></a>Finally, we make software releases on a schedule
|
||||
that is necessarily not aligned with those used by Linux
|
||||
distributors and kernel developers, so that we can deliver
|
||||
new features to customers without forcing them to upgrade
|
||||
their entire kernels or distributions.</p></li></ul></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id433704">Tempting approaches that don't work well</h3></div></div></div><p id="x_165"><a name="x_165"></a>There are two “<span class="quote">standard</span>” ways to maintain a
|
||||
piece of software that has to target many different
|
||||
environments.</p><p id="x_166"><a name="x_166"></a>The first is to maintain a number of branches, each
|
||||
intended for a single target. The trouble with this approach
|
||||
is that you must maintain iron discipline in the flow of
|
||||
changes between repositories. A new feature or bug fix must
|
||||
start life in a “<span class="quote">pristine</span>” repository, then
|
||||
percolate out to every backport repository. Backport changes
|
||||
are more limited in the branches they should propagate to; a
|
||||
backport change that is applied to a branch where it doesn't
|
||||
belong will probably stop the driver from compiling.</p><p id="x_167"><a name="x_167"></a>The second is to maintain a single source tree filled with
|
||||
conditional statements that turn chunks of code on or off
|
||||
depending on the intended target. Because these
|
||||
“<span class="quote">ifdefs</span>” are not allowed in the Linux kernel
|
||||
tree, a manual or automatic process must be followed to strip
|
||||
them out and yield a clean tree. A code base maintained in
|
||||
this fashion rapidly becomes a rat's nest of conditional
|
||||
blocks that are difficult to understand and maintain.</p><p id="x_168"><a name="x_168"></a>Neither of these approaches is well suited to a situation
|
||||
where you don't “<span class="quote">own</span>” the canonical copy of a
|
||||
source tree. In the case of a Linux driver that is
|
||||
distributed with the standard kernel, Linus's tree contains
|
||||
the copy of the code that will be treated by the world as
|
||||
canonical. The upstream version of “<span class="quote">my</span>” driver
|
||||
can be modified by people I don't know, without me even
|
||||
finding out about it until after the changes show up in
|
||||
Linus's tree.</p><p id="x_169"><a name="x_169"></a>These approaches have the added weakness of making it
|
||||
difficult to generate well-formed patches to submit
|
||||
upstream.</p><p id="x_16a"><a name="x_16a"></a>In principle, Mercurial Queues seems like a good candidate
|
||||
to manage a development scenario such as the above. While
|
||||
this is indeed the case, MQ contains a few added features that
|
||||
make the job more pleasant.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id433787">Conditionally applying patches with guards</h2></div></div></div><p id="x_16b"><a name="x_16b"></a>Perhaps the best way to maintain sanity with so many targets
|
||||
is to be able to choose specific patches to apply for a given
|
||||
situation. MQ provides a feature called “<span class="quote">guards</span>”
|
||||
(which originates with quilt's <code class="literal">guards</code>
|
||||
command) that does just this. To start off, let's create a
|
||||
simple repository for experimenting in.</p><pre id="id434160" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg qinit</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qnew hello.patch</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo hello > hello</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add hello</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qrefresh</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qnew goodbye.patch</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo goodbye > goodbye</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add goodbye</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qrefresh</code></strong>
|
||||
</pre><p id="x_16c"><a name="x_16c"></a>This gives us a tiny repository that contains two patches
|
||||
that don't have any dependencies on each other, because they
|
||||
touch different files.</p><p id="x_16d"><a name="x_16d"></a>The idea behind conditional application is that you can
|
||||
“<span class="quote">tag</span>” a patch with a <span class="emphasis"><em>guard</em></span>,
|
||||
which is simply a text string of your choosing, then tell MQ to
|
||||
select specific guards to use when applying patches. MQ will
|
||||
then either apply, or skip over, a guarded patch, depending on
|
||||
the guards that you have selected.</p><p id="x_16e"><a name="x_16e"></a>A patch can have an arbitrary number of guards; each one is
|
||||
<span class="emphasis"><em>positive</em></span> (“<span class="quote">apply this patch if this
|
||||
guard is selected</span>”) or <span class="emphasis"><em>negative</em></span>
|
||||
(“<span class="quote">skip this patch if this guard is selected</span>”). A
|
||||
patch with no guards is always applied.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id433935">Controlling the guards on a patch</h2></div></div></div><p id="x_16f"><a name="x_16f"></a>The <span class="command"><strong>qguard</strong></span> command lets
|
||||
you determine which guards should apply to a patch, or display
|
||||
the guards that are already in effect. Without any arguments, it
|
||||
displays the guards on the current topmost patch.</p><pre id="id434459" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg qguard</code></strong>
|
||||
goodbye.patch: unguarded
|
||||
</pre><p id="x_170"><a name="x_170"></a>To set a positive guard on a patch, prefix the name of the
|
||||
guard with a “<span class="quote"><code class="literal">+</code></span>”.</p><pre id="id434060" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg qguard +foo</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qguard</code></strong>
|
||||
goodbye.patch: +foo
|
||||
</pre><p id="x_171"><a name="x_171"></a>To set a negative guard
|
||||
on a patch, prefix the name of the guard with a
|
||||
“<span class="quote"><code class="literal">-</code></span>”.</p><pre id="id434440" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg qguard hello.patch -quux</code></strong>
|
||||
hg qguard: option -u not recognized
|
||||
hg qguard [-l] [-n] -- [PATCH] [+GUARD]... [-GUARD]...
|
||||
|
||||
set or print guards for a patch
|
||||
|
||||
Guards control whether a patch can be pushed. A patch with no
|
||||
guards is always pushed. A patch with a positive guard ("+foo") is
|
||||
pushed only if the qselect command has activated it. A patch with
|
||||
a negative guard ("-foo") is never pushed if the qselect command
|
||||
has activated it.
|
||||
|
||||
With no arguments, print the currently active guards.
|
||||
With arguments, set guards for the named patch.
|
||||
NOTE: Specifying negative guards now requires '--'.
|
||||
|
||||
To set guards on another patch:
|
||||
hg qguard -- other.patch +2.6.17 -stable
|
||||
|
||||
options:
|
||||
|
||||
-l --list list all patches and guards
|
||||
-n --none drop all guards
|
||||
|
||||
use "hg -v help qguard" to show global options
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qguard hello.patch</code></strong>
|
||||
hello.patch: unguarded
|
||||
</pre><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_172"><a name="x_172"></a> The <span class="command"><strong>qguard</strong></span> command
|
||||
<span class="emphasis"><em>sets</em></span> the guards on a patch; it doesn't
|
||||
<span class="emphasis"><em>modify</em></span> them. What this means is that if
|
||||
you run <span class="command"><strong>hg qguard +a +b</strong></span> on a
|
||||
patch, then <span class="command"><strong>hg qguard +c</strong></span> on
|
||||
the same patch, the <span class="emphasis"><em>only</em></span> guard that will
|
||||
be set on it afterwards is <code class="literal">+c</code>.</p></td></tr></table></div><p id="x_173"><a name="x_173"></a>Mercurial stores guards in the <code class="filename">series</code> file; the form in which they
|
||||
are stored is easy both to understand and to edit by hand. (In
|
||||
other words, you don't have to use the <span class="command"><strong>qguard</strong></span> command if you don't want
|
||||
to; it's okay to simply edit the <code class="filename">series</code> file.)</p><pre id="id434417" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat .hg/patches/series</code></strong>
|
||||
hello.patch
|
||||
goodbye.patch #+foo
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id434471">Selecting the guards to use</h2></div></div></div><p id="x_174"><a name="x_174"></a>The <span class="command"><strong>qselect</strong></span> command
|
||||
determines which guards are active at a given time. The effect
|
||||
of this is to determine which patches MQ will apply the next
|
||||
time you run <span class="command"><strong>qpush</strong></span>. It has
|
||||
no other effect; in particular, it doesn't do anything to
|
||||
patches that are already applied.</p><p id="x_175"><a name="x_175"></a>With no arguments, the <span class="command"><strong>qselect</strong></span> command lists the guards
|
||||
currently in effect, one per line of output. Each argument is
|
||||
treated as the name of a guard to apply.</p><pre id="id434859" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg qpop -a</code></strong>
|
||||
patch queue now empty
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qselect</code></strong>
|
||||
no active guards
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qselect foo</code></strong>
|
||||
number of unguarded, unapplied patches has changed from 1 to 2
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qselect</code></strong>
|
||||
foo
|
||||
</pre><p id="x_176"><a name="x_176"></a>In case you're interested, the currently selected guards are
|
||||
stored in the <code class="filename">guards</code> file.</p><pre id="id434741" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat .hg/patches/guards</code></strong>
|
||||
foo
|
||||
</pre><p id="x_177"><a name="x_177"></a>We can see the effect the selected guards have when we run
|
||||
<span class="command"><strong>qpush</strong></span>.</p><pre id="id434698" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg qpush -a</code></strong>
|
||||
applying hello.patch
|
||||
applying goodbye.patch
|
||||
now at: goodbye.patch
|
||||
</pre><p id="x_178"><a name="x_178"></a>A guard cannot start with a
|
||||
“<span class="quote"><code class="literal">+</code></span>” or
|
||||
“<span class="quote"><code class="literal">-</code></span>” character. The name of a
|
||||
guard must not contain white space, but most other characters
|
||||
are acceptable. If you try to use a guard with an invalid name,
|
||||
MQ will complain:</p><pre id="id434609" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg qselect +foo</code></strong>
|
||||
abort: guard '+foo' starts with invalid character: '+'
|
||||
</pre><p id="x_179"><a name="x_179"></a>Changing the selected guards changes the patches that are
|
||||
applied.</p><pre id="id435172" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg qselect quux</code></strong>
|
||||
number of guarded, applied patches has changed from 0 to 1
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qpop -a</code></strong>
|
||||
patch queue now empty
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qpush -a</code></strong>
|
||||
applying hello.patch
|
||||
skipping goodbye.patch - guarded by ['+foo']
|
||||
now at: hello.patch
|
||||
</pre><p id="x_17a"><a name="x_17a"></a>You can see in the example below that negative guards take
|
||||
precedence over positive guards.</p><pre id="id435108" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg qselect foo bar</code></strong>
|
||||
number of unguarded, unapplied patches has changed from 0 to 1
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qpop -a</code></strong>
|
||||
patch queue now empty
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg qpush -a</code></strong>
|
||||
applying hello.patch
|
||||
applying goodbye.patch
|
||||
now at: goodbye.patch
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id435148">MQ's rules for applying patches</h2></div></div></div><p id="x_17b"><a name="x_17b"></a>The rules that MQ uses when deciding whether to apply a
|
||||
patch are as follows.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_17c"><a name="x_17c"></a>A patch that has no guards is always
|
||||
applied.</p></li><li><p id="x_17d"><a name="x_17d"></a>If the patch has any negative guard that matches
|
||||
any currently selected guard, the patch is skipped.</p></li><li><p id="x_17e"><a name="x_17e"></a>If the patch has any positive guard that matches
|
||||
any currently selected guard, the patch is applied.</p></li><li><p id="x_17f"><a name="x_17f"></a>If the patch has positive or negative guards,
|
||||
but none matches any currently selected guard, the patch is
|
||||
skipped.</p></li></ul></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id434989">Trimming the work environment</h2></div></div></div><p id="x_180"><a name="x_180"></a>In working on the device driver I mentioned earlier, I don't
|
||||
apply the patches to a normal Linux kernel tree. Instead, I use
|
||||
a repository that contains only a snapshot of the source files
|
||||
and headers that are relevant to Infiniband development. This
|
||||
repository is 1% the size of a kernel repository, so it's easier
|
||||
to work with.</p><p id="x_181"><a name="x_181"></a>I then choose a “<span class="quote">base</span>” version on top of which
|
||||
the patches are applied. This is a snapshot of the Linux kernel
|
||||
tree as of a revision of my choosing. When I take the snapshot,
|
||||
I record the changeset ID from the kernel repository in the
|
||||
commit message. Since the snapshot preserves the
|
||||
“<span class="quote">shape</span>” and content of the relevant parts of the
|
||||
kernel tree, I can apply my patches on top of either my tiny
|
||||
repository or a normal kernel tree.</p><p id="x_182"><a name="x_182"></a>Normally, the base tree atop which the patches apply should
|
||||
be a snapshot of a very recent upstream tree. This best
|
||||
facilitates the development of patches that can easily be
|
||||
submitted upstream with few or no modifications.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id435034">Dividing up the <code class="filename">series</code>
|
||||
file</h2></div></div></div><p id="x_183"><a name="x_183"></a>I categorise the patches in the <code class="filename">series</code> file into a number of logical
|
||||
groups. Each section of like patches begins with a block of
|
||||
comments that describes the purpose of the patches that
|
||||
follow.</p><p id="x_184"><a name="x_184"></a>The sequence of patch groups that I maintain follows. The
|
||||
ordering of these groups is important; I'll describe why after I
|
||||
introduce the groups.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_185"><a name="x_185"></a>The “<span class="quote">accepted</span>” group. Patches that
|
||||
the development team has submitted to the maintainer of the
|
||||
Infiniband subsystem, and which he has accepted, but which
|
||||
are not present in the snapshot that the tiny repository is
|
||||
based on. These are “<span class="quote">read only</span>” patches,
|
||||
present only to transform the tree into a similar state as
|
||||
it is in the upstream maintainer's repository.</p></li><li><p id="x_186"><a name="x_186"></a>The “<span class="quote">rework</span>” group. Patches that I
|
||||
have submitted, but that the upstream maintainer has
|
||||
requested modifications to before he will accept
|
||||
them.</p></li><li><p id="x_187"><a name="x_187"></a>The “<span class="quote">pending</span>” group. Patches that
|
||||
I have not yet submitted to the upstream maintainer, but
|
||||
which we have finished working on. These will be “<span class="quote">read
|
||||
only</span>” for a while. If the upstream maintainer
|
||||
accepts them upon submission, I'll move them to the end of
|
||||
the “<span class="quote">accepted</span>” group. If he requests that I
|
||||
modify any, I'll move them to the beginning of the
|
||||
“<span class="quote">rework</span>” group.</p></li><li><p id="x_188"><a name="x_188"></a>The “<span class="quote">in progress</span>” group. Patches
|
||||
that are actively being developed, and should not be
|
||||
submitted anywhere yet.</p></li><li><p id="x_189"><a name="x_189"></a>The “<span class="quote">backport</span>” group. Patches that
|
||||
adapt the source tree to older versions of the kernel
|
||||
tree.</p></li><li><p id="x_18a"><a name="x_18a"></a>The “<span class="quote">do not ship</span>” group. Patches
|
||||
that for some reason should never be submitted upstream.
|
||||
For example, one such patch might change embedded driver
|
||||
identification strings to make it easier to distinguish, in
|
||||
the field, between an out-of-tree version of the driver and
|
||||
a version shipped by a distribution vendor.</p></li></ul></div><p id="x_18b"><a name="x_18b"></a>Now to return to the reasons for ordering groups of patches
|
||||
in this way. We would like the lowest patches in the stack to
|
||||
be as stable as possible, so that we will not need to rework
|
||||
higher patches due to changes in context. Putting patches that
|
||||
will never be changed first in the <code class="filename">series</code> file serves this
|
||||
purpose.</p><p id="x_18c"><a name="x_18c"></a>We would also like the patches that we know we'll need to
|
||||
modify to be applied on top of a source tree that resembles the
|
||||
upstream tree as closely as possible. This is why we keep
|
||||
accepted patches around for a while.</p><p id="x_18d"><a name="x_18d"></a>The “<span class="quote">backport</span>” and “<span class="quote">do not ship</span>”
|
||||
patches float at the end of the <code class="filename">series</code> file. The backport patches
|
||||
must be applied on top of all other patches, and the “<span class="quote">do
|
||||
not ship</span>” patches might as well stay out of harm's
|
||||
way.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id435315">Maintaining the patch series</h2></div></div></div><p id="x_18e"><a name="x_18e"></a>In my work, I use a number of guards to control which
|
||||
patches are to be applied.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_18f"><a name="x_18f"></a>“<span class="quote">Accepted</span>” patches are guarded with
|
||||
<code class="literal">accepted</code>. I enable this guard most of
|
||||
the time. When I'm applying the patches on top of a tree
|
||||
where the patches are already present, I can turn this patch
|
||||
off, and the patches that follow it will apply
|
||||
cleanly.</p></li><li><p id="x_190"><a name="x_190"></a>Patches that are “<span class="quote">finished</span>”, but
|
||||
not yet submitted, have no guards. If I'm applying the
|
||||
patch stack to a copy of the upstream tree, I don't need to
|
||||
enable any guards in order to get a reasonably safe source
|
||||
tree.</p></li><li><p id="x_191"><a name="x_191"></a>Those patches that need reworking before being
|
||||
resubmitted are guarded with
|
||||
<code class="literal">rework</code>.</p></li><li><p id="x_192"><a name="x_192"></a>For those patches that are still under
|
||||
development, I use <code class="literal">devel</code>.</p></li><li><p id="x_193"><a name="x_193"></a>A backport patch may have several guards, one
|
||||
for each version of the kernel to which it applies. For
|
||||
example, a patch that backports a piece of code to 2.6.9
|
||||
will have a <code class="literal">2.6.9</code> guard.</p></li></ul></div><p id="x_194"><a name="x_194"></a>This variety of guards gives me considerable flexibility in
|
||||
determining what kind of source tree I want to end up with. For
|
||||
most situations, the selection of appropriate guards is
|
||||
automated during the build process, but I can manually tune the
|
||||
guards to use for less common circumstances.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id435424">The art of writing backport patches</h3></div></div></div><p id="x_195"><a name="x_195"></a>Using MQ, writing a backport patch is a simple process.
|
||||
All such a patch has to do is modify a piece of code that uses
|
||||
a kernel feature not present in the older version of the
|
||||
kernel, so that the driver continues to work correctly under
|
||||
that older version.</p><p id="x_196"><a name="x_196"></a>A useful goal when writing a good backport patch is to
|
||||
make your code look as if it was written for the older version
|
||||
of the kernel you're targeting. The less obtrusive the patch,
|
||||
the easier it will be to understand and maintain. If you're
|
||||
writing a collection of backport patches to avoid the
|
||||
“<span class="quote">rat's nest</span>” effect of lots of
|
||||
<code class="literal">#ifdef</code>s (hunks of source code that are only
|
||||
used conditionally) in your code, don't introduce
|
||||
version-dependent <code class="literal">#ifdef</code>s into the patches.
|
||||
Instead, write several patches, each of which makes
|
||||
unconditional changes, and control their application using
|
||||
guards.</p><p id="x_197"><a name="x_197"></a>There are two reasons to divide backport patches into a
|
||||
distinct group, away from the “<span class="quote">regular</span>” patches
|
||||
whose effects they modify. The first is that intermingling the
|
||||
two makes it more difficult to use a tool like the <code class="literal">patchbomb</code> extension to automate the
|
||||
process of submitting the patches to an upstream maintainer.
|
||||
The second is that a backport patch could perturb the context
|
||||
in which a subsequent regular patch is applied, making it
|
||||
impossible to apply the regular patch cleanly
|
||||
<span class="emphasis"><em>without</em></span> the earlier backport patch
|
||||
already being applied.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id435495">Useful tips for developing with MQ</h2></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id435501">Organising patches in directories</h3></div></div></div><p id="x_198"><a name="x_198"></a>If you're working on a substantial project with MQ, it's
|
||||
not difficult to accumulate a large number of patches. For
|
||||
example, I have one patch repository that contains over 250
|
||||
patches.</p><p id="x_199"><a name="x_199"></a>If you can group these patches into separate logical
|
||||
categories, you can if you like store them in different
|
||||
directories; MQ has no problems with patch names that contain
|
||||
path separators.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="mq-collab:tips:interdiff">Viewing the history of a patch</h3></div></div></div><p id="x_19a"><a name="x_19a"></a>If you're developing a set of patches over a long time,
|
||||
it's a good idea to maintain them in a repository, as
|
||||
discussed in <a class="xref" href="managing-change-with-mercurial-queues.html#sec:mq:repo" title="Managing patches in a repository">the section called “Managing patches in a repository”</a>. If you do
|
||||
so, you'll quickly
|
||||
discover that using the <span class="command"><strong>hg
|
||||
diff</strong></span> command to look at the history of changes to
|
||||
a patch is unworkable. This is in part because you're looking
|
||||
at the second derivative of the real code (a diff of a diff),
|
||||
but also because MQ adds noise to the process by modifying
|
||||
time stamps and directory names when it updates a
|
||||
patch.</p><p id="x_19b"><a name="x_19b"></a>However, you can use the <code class="literal">extdiff</code> extension, which is bundled
|
||||
with Mercurial, to turn a diff of two versions of a patch into
|
||||
something readable. To do this, you will need a third-party
|
||||
package called <code class="literal">patchutils</code>
|
||||
[<span class="citation">web:patchutils</span>]. This provides a command
|
||||
named <span class="command"><strong>interdiff</strong></span>, which shows the
|
||||
differences between two diffs as a diff. Used on two versions
|
||||
of the same diff, it generates a diff that represents the diff
|
||||
from the first to the second version.</p><p id="x_19c"><a name="x_19c"></a>You can enable the <code class="literal">extdiff</code> extension in the usual way,
|
||||
by adding a line to the <code class="literal">extensions</code> section of your
|
||||
<code class="filename">~/.hgrc</code>.</p><pre id="id435628" class="programlisting">[extensions]
|
||||
extdiff =</pre><p id="x_19d"><a name="x_19d"></a>The <span class="command"><strong>interdiff</strong></span> command expects to be
|
||||
passed the names of two files, but the <code class="literal">extdiff</code> extension passes the program
|
||||
it runs a pair of directories, each of which can contain an
|
||||
arbitrary number of files. We thus need a small program that
|
||||
will run <span class="command"><strong>interdiff</strong></span> on each pair of files in
|
||||
these two directories. This program is available as <code class="filename">hg-interdiff</code> in the <code class="filename">examples</code> directory of the
|
||||
source code repository that accompanies this book. </p><p id="x_19e"><a name="x_19e"></a>With the <code class="filename">hg-interdiff</code>
|
||||
program in your shell's search path, you can run it as
|
||||
follows, from inside an MQ patch directory:</p><pre id="id435697" class="programlisting">hg extdiff -p hg-interdiff -r A:B my-change.patch</pre><p id="x_19f"><a name="x_19f"></a>Since you'll probably want to use this long-winded command
|
||||
a lot, you can get <code class="literal">hgext</code> to
|
||||
make it available as a normal Mercurial command, again by
|
||||
editing your <code class="filename">~/.hgrc</code>.</p><pre id="id435727" class="programlisting">[extdiff]
|
||||
cmd.interdiff = hg-interdiff</pre><p id="x_1a0"><a name="x_1a0"></a>This directs <code class="literal">hgext</code> to
|
||||
make an <code class="literal">interdiff</code> command available, so you
|
||||
can now shorten the previous invocation of <span class="command"><strong>extdiff</strong></span> to something a
|
||||
little more wieldy.</p><pre id="id435764" class="programlisting">hg interdiff -r A:B my-change.patch</pre><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_1a1"><a name="x_1a1"></a> The <span class="command"><strong>interdiff</strong></span> command works well
|
||||
only if the underlying files against which versions of a
|
||||
patch are generated remain the same. If you create a patch,
|
||||
modify the underlying files, and then regenerate the patch,
|
||||
<span class="command"><strong>interdiff</strong></span> may not produce useful
|
||||
output.</p></td></tr></table></div><p id="x_1a2"><a name="x_1a2"></a>The <code class="literal">extdiff</code> extension is
|
||||
useful for more than merely improving the presentation of MQ
|
||||
patches. To read more about it, go to <a class="xref" href="adding-functionality-with-extensions.html#sec:hgext:extdiff" title="Flexible diff support with the extdiff extension">the section called “Flexible diff support with the extdiff extension”</a>.</p></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="managing-change-with-mercurial-queues.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="adding-functionality-with-extensions.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 12. Managing change with Mercurial Queues </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 14. Adding functionality with extensions</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
431
read/behind-the-scenes.html
Normal file
431
read/behind-the-scenes.html
Normal file
|
@ -0,0 +1,431 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 4. Behind the scenes</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="a-tour-of-mercurial-merging-work.html" title="Chapter 3. A tour of Mercurial: merging work"><link rel="next" href="mercurial-in-daily-use.html" title="Chapter 5. Mercurial in daily use"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 4. Behind the scenes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="a-tour-of-mercurial-merging-work.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="mercurial-in-daily-use.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:concepts"><div class="titlepage"><div><div><h2 class="title">Chapter 4. Behind the scenes</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="behind-the-scenes.html#id357785">Mercurial's historical record</a></span></dt><dd><dl><dt><span class="sect2"><a href="behind-the-scenes.html#id357790">Tracking the history of a single file</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#id357874">Managing tracked files</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#id357891">Recording changeset information</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#id357908">Relationships between revisions</a></span></dt></dl></dd><dt><span class="sect1"><a href="behind-the-scenes.html#id357985">Safe, efficient storage</a></span></dt><dd><dl><dt><span class="sect2"><a href="behind-the-scenes.html#id358000">Efficient storage</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#sec:concepts:txn">Safe operation</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#id358067">Fast retrieval</a></span></dt><dd><dl><dt><span class="sect3"><a href="behind-the-scenes.html#id358134">Aside: the influence of video compression</a></span></dt></dl></dd><dt><span class="sect2"><a href="behind-the-scenes.html#id358156">Identification and strong integrity</a></span></dt></dl></dd><dt><span class="sect1"><a href="behind-the-scenes.html#id358194">Revision history, branching, and merging</a></span></dt><dt><span class="sect1"><a href="behind-the-scenes.html#id358265">The working directory</a></span></dt><dd><dl><dt><span class="sect2"><a href="behind-the-scenes.html#id358342">What happens when you commit</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#id358441">Creating a new head</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#id358589">Merging changes</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#id358735">Merging and renames</a></span></dt></dl></dd><dt><span class="sect1"><a href="behind-the-scenes.html#id358761">Other interesting design features</a></span></dt><dd><dl><dt><span class="sect2"><a href="behind-the-scenes.html#id358780">Clever compression</a></span></dt><dd><dl><dt><span class="sect3"><a href="behind-the-scenes.html#id358828">Network recompression</a></span></dt></dl></dd><dt><span class="sect2"><a href="behind-the-scenes.html#id358901">Read/write ordering and atomicity</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#id358935">Concurrent access</a></span></dt><dd><dl><dt><span class="sect3"><a href="behind-the-scenes.html#id358982">Safe dirstate access</a></span></dt></dl></dd><dt><span class="sect2"><a href="behind-the-scenes.html#id359009">Avoiding seeks</a></span></dt><dt><span class="sect2"><a href="behind-the-scenes.html#id359061">Other contents of the dirstate</a></span></dt></dl></dd></dl></div><p id="x_2e8"><a name="x_2e8"></a>Unlike many revision control systems, the concepts
|
||||
upon which Mercurial is built are simple enough that it's easy to
|
||||
understand how the software really works. Knowing these details
|
||||
certainly isn't necessary, so it is certainly safe to skip this
|
||||
chapter. However, I think you will get more out of the software
|
||||
with a “<span class="quote">mental model</span>” of what's going on.</p><p id="x_2e9"><a name="x_2e9"></a>Being able to understand what's going on behind the
|
||||
scenes gives me confidence that Mercurial has been carefully
|
||||
designed to be both <span class="emphasis"><em>safe</em></span> and
|
||||
<span class="emphasis"><em>efficient</em></span>. And just as importantly, if it's
|
||||
easy for me to retain a good idea of what the software is doing
|
||||
when I perform a revision control task, I'm less likely to be
|
||||
surprised by its behavior.</p><p id="x_2ea"><a name="x_2ea"></a>In this chapter, we'll initially cover the core concepts
|
||||
behind Mercurial's design, then continue to discuss some of the
|
||||
interesting details of its implementation.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id357785">Mercurial's historical record</h2></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id357790">Tracking the history of a single file</h3></div></div></div><p id="x_2eb"><a name="x_2eb"></a>When Mercurial tracks modifications to a file, it stores
|
||||
the history of that file in a metadata object called a
|
||||
<span class="emphasis"><em>filelog</em></span>. Each entry in the filelog
|
||||
contains enough information to reconstruct one revision of the
|
||||
file that is being tracked. Filelogs are stored as files in
|
||||
the <code class="filename">.hg/store/data</code> directory. A
|
||||
filelog contains two kinds of information: revision data, and
|
||||
an index to help Mercurial to find a revision
|
||||
efficiently.</p><p id="x_2ec"><a name="x_2ec"></a>A file that is large, or has a lot of history, has its
|
||||
filelog stored in separate data
|
||||
(“<span class="quote"><code class="literal">.d</code></span>” suffix) and index
|
||||
(“<span class="quote"><code class="literal">.i</code></span>” suffix) files. For
|
||||
small files without much history, the revision data and index
|
||||
are combined in a single “<span class="quote"><code class="literal">.i</code></span>”
|
||||
file. The correspondence between a file in the working
|
||||
directory and the filelog that tracks its history in the
|
||||
repository is illustrated in <a class="xref" href="behind-the-scenes.html#fig:concepts:filelog" title="Figure 4.1. Relationships between files in working directory and filelogs in repository">Figure 4.1, “Relationships between files in working directory and
|
||||
filelogs in repository”</a>.</p><div class="figure"><a name="fig:concepts:filelog"></a><p class="title"><b>Figure 4.1. Relationships between files in working directory and
|
||||
filelogs in repository</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/filelog.png" alt="XXX add text"></div></div></div><br class="figure-break"></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id357874">Managing tracked files</h3></div></div></div><p id="x_2ee"><a name="x_2ee"></a>Mercurial uses a structure called a
|
||||
<span class="emphasis"><em>manifest</em></span> to collect together information
|
||||
about the files that it tracks. Each entry in the manifest
|
||||
contains information about the files present in a single
|
||||
changeset. An entry records which files are present in the
|
||||
changeset, the revision of each file, and a few other pieces
|
||||
of file metadata.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id357891">Recording changeset information</h3></div></div></div><p id="x_2ef"><a name="x_2ef"></a>The <span class="emphasis"><em>changelog</em></span> contains information
|
||||
about each changeset. Each revision records who committed a
|
||||
change, the changeset comment, other pieces of
|
||||
changeset-related information, and the revision of the
|
||||
manifest to use.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id357908">Relationships between revisions</h3></div></div></div><p id="x_2f0"><a name="x_2f0"></a>Within a changelog, a manifest, or a filelog, each
|
||||
revision stores a pointer to its immediate parent (or to its
|
||||
two parents, if it's a merge revision). As I mentioned above,
|
||||
there are also relationships between revisions
|
||||
<span class="emphasis"><em>across</em></span> these structures, and they are
|
||||
hierarchical in nature.</p><p id="x_2f1"><a name="x_2f1"></a>For every changeset in a repository, there is exactly one
|
||||
revision stored in the changelog. Each revision of the
|
||||
changelog contains a pointer to a single revision of the
|
||||
manifest. A revision of the manifest stores a pointer to a
|
||||
single revision of each filelog tracked when that changeset
|
||||
was created. These relationships are illustrated in
|
||||
<a class="xref" href="behind-the-scenes.html#fig:concepts:metadata" title="Figure 4.2. Metadata relationships">Figure 4.2, “Metadata relationships”</a>.</p><div class="figure"><a name="fig:concepts:metadata"></a><p class="title"><b>Figure 4.2. Metadata relationships</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/metadata.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_2f3"><a name="x_2f3"></a>As the illustration shows, there is
|
||||
<span class="emphasis"><em>not</em></span> a “<span class="quote">one to one</span>”
|
||||
relationship between revisions in the changelog, manifest, or
|
||||
filelog. If a file that
|
||||
Mercurial tracks hasn't changed between two changesets, the
|
||||
entry for that file in the two revisions of the manifest will
|
||||
point to the same revision of its filelog<sup>[<a name="id357972" href="#ftn.id357972" class="footnote">3</a>]</sup>.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id357985">Safe, efficient storage</h2></div></div></div><p id="x_2f4"><a name="x_2f4"></a>The underpinnings of changelogs, manifests, and filelogs are
|
||||
provided by a single structure called the
|
||||
<span class="emphasis"><em>revlog</em></span>.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358000">Efficient storage</h3></div></div></div><p id="x_2f5"><a name="x_2f5"></a>The revlog provides efficient storage of revisions using a
|
||||
<span class="emphasis"><em>delta</em></span> mechanism. Instead of storing a
|
||||
complete copy of a file for each revision, it stores the
|
||||
changes needed to transform an older revision into the new
|
||||
revision. For many kinds of file data, these deltas are
|
||||
typically a fraction of a percent of the size of a full copy
|
||||
of a file.</p><p id="x_2f6"><a name="x_2f6"></a>Some obsolete revision control systems can only work with
|
||||
deltas of text files. They must either store binary files as
|
||||
complete snapshots or encoded into a text representation, both
|
||||
of which are wasteful approaches. Mercurial can efficiently
|
||||
handle deltas of files with arbitrary binary contents; it
|
||||
doesn't need to treat text as special.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:concepts:txn">Safe operation</h3></div></div></div><p id="x_2f7"><a name="x_2f7"></a>Mercurial only ever <span class="emphasis"><em>appends</em></span> data to
|
||||
the end of a revlog file. It never modifies a section of a
|
||||
file after it has written it. This is both more robust and
|
||||
efficient than schemes that need to modify or rewrite
|
||||
data.</p><p id="x_2f8"><a name="x_2f8"></a>In addition, Mercurial treats every write as part of a
|
||||
<span class="emphasis"><em>transaction</em></span> that can span a number of
|
||||
files. A transaction is <span class="emphasis"><em>atomic</em></span>: either
|
||||
the entire transaction succeeds and its effects are all
|
||||
visible to readers in one go, or the whole thing is undone.
|
||||
This guarantee of atomicity means that if you're running two
|
||||
copies of Mercurial, where one is reading data and one is
|
||||
writing it, the reader will never see a partially written
|
||||
result that might confuse it.</p><p id="x_2f9"><a name="x_2f9"></a>The fact that Mercurial only appends to files makes it
|
||||
easier to provide this transactional guarantee. The easier it
|
||||
is to do stuff like this, the more confident you should be
|
||||
that it's done correctly.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358067">Fast retrieval</h3></div></div></div><p id="x_2fa"><a name="x_2fa"></a>Mercurial cleverly avoids a pitfall common to
|
||||
all earlier revision control systems: the problem of
|
||||
<span class="emphasis"><em>inefficient retrieval</em></span>. Most revision
|
||||
control systems store the contents of a revision as an
|
||||
incremental series of modifications against a
|
||||
“<span class="quote">snapshot</span>”. (Some base the snapshot on the
|
||||
oldest revision, others on the newest.) To reconstruct a
|
||||
specific revision, you must first read the snapshot, and then
|
||||
every one of the revisions between the snapshot and your
|
||||
target revision. The more history that a file accumulates,
|
||||
the more revisions you must read, hence the longer it takes to
|
||||
reconstruct a particular revision.</p><div class="figure"><a name="fig:concepts:snapshot"></a><p class="title"><b>Figure 4.3. Snapshot of a revlog, with incremental deltas</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/snapshot.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_2fc"><a name="x_2fc"></a>The innovation that Mercurial applies to this problem is
|
||||
simple but effective. Once the cumulative amount of delta
|
||||
information stored since the last snapshot exceeds a fixed
|
||||
threshold, it stores a new snapshot (compressed, of course),
|
||||
instead of another delta. This makes it possible to
|
||||
reconstruct <span class="emphasis"><em>any</em></span> revision of a file
|
||||
quickly. This approach works so well that it has since been
|
||||
copied by several other revision control systems.</p><p id="x_2fd"><a name="x_2fd"></a><a class="xref" href="behind-the-scenes.html#fig:concepts:snapshot" title="Figure 4.3. Snapshot of a revlog, with incremental deltas">Figure 4.3, “Snapshot of a revlog, with incremental deltas”</a> illustrates
|
||||
the idea. In an entry in a revlog's index file, Mercurial
|
||||
stores the range of entries from the data file that it must
|
||||
read to reconstruct a particular revision.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id358134">Aside: the influence of video compression</h4></div></div></div><p id="x_2fe"><a name="x_2fe"></a>If you're familiar with video compression or
|
||||
have ever watched a TV feed through a digital cable or
|
||||
satellite service, you may know that most video compression
|
||||
schemes store each frame of video as a delta against its
|
||||
predecessor frame.</p><p id="x_2ff"><a name="x_2ff"></a>Mercurial borrows this idea to make it
|
||||
possible to reconstruct a revision from a snapshot and a
|
||||
small number of deltas.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358156">Identification and strong integrity</h3></div></div></div><p id="x_300"><a name="x_300"></a>Along with delta or snapshot information, a revlog entry
|
||||
contains a cryptographic hash of the data that it represents.
|
||||
This makes it difficult to forge the contents of a revision,
|
||||
and easy to detect accidental corruption.</p><p id="x_301"><a name="x_301"></a>Hashes provide more than a mere check against corruption;
|
||||
they are used as the identifiers for revisions. The changeset
|
||||
identification hashes that you see as an end user are from
|
||||
revisions of the changelog. Although filelogs and the
|
||||
manifest also use hashes, Mercurial only uses these behind the
|
||||
scenes.</p><p id="x_302"><a name="x_302"></a>Mercurial verifies that hashes are correct when it
|
||||
retrieves file revisions and when it pulls changes from
|
||||
another repository. If it encounters an integrity problem, it
|
||||
will complain and stop whatever it's doing.</p><p id="x_303"><a name="x_303"></a>In addition to the effect it has on retrieval efficiency,
|
||||
Mercurial's use of periodic snapshots makes it more robust
|
||||
against partial data corruption. If a revlog becomes partly
|
||||
corrupted due to a hardware error or system bug, it's often
|
||||
possible to reconstruct some or most revisions from the
|
||||
uncorrupted sections of the revlog, both before and after the
|
||||
corrupted section. This would not be possible with a
|
||||
delta-only storage model.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id358194">Revision history, branching, and merging</h2></div></div></div><p id="x_304"><a name="x_304"></a>Every entry in a Mercurial revlog knows the identity of its
|
||||
immediate ancestor revision, usually referred to as its
|
||||
<span class="emphasis"><em>parent</em></span>. In fact, a revision contains room
|
||||
for not one parent, but two. Mercurial uses a special hash,
|
||||
called the “<span class="quote">null ID</span>”, to represent the idea
|
||||
“<span class="quote">there is no parent here</span>”. This hash is simply a
|
||||
string of zeroes.</p><p id="x_305"><a name="x_305"></a>In <a class="xref" href="behind-the-scenes.html#fig:concepts:revlog" title="Figure 4.4. The conceptual structure of a revlog">Figure 4.4, “The conceptual structure of a revlog”</a>, you can see
|
||||
an example of the conceptual structure of a revlog. Filelogs,
|
||||
manifests, and changelogs all have this same structure; they
|
||||
differ only in the kind of data stored in each delta or
|
||||
snapshot.</p><p id="x_306"><a name="x_306"></a>The first revision in a revlog (at the bottom of the image)
|
||||
has the null ID in both of its parent slots. For a
|
||||
“<span class="quote">normal</span>” revision, its first parent slot contains
|
||||
the ID of its parent revision, and its second contains the null
|
||||
ID, indicating that the revision has only one real parent. Any
|
||||
two revisions that have the same parent ID are branches. A
|
||||
revision that represents a merge between branches has two normal
|
||||
revision IDs in its parent slots.</p><div class="figure"><a name="fig:concepts:revlog"></a><p class="title"><b>Figure 4.4. The conceptual structure of a revlog</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/revlog.png" alt="XXX add text"></div></div></div><br class="figure-break"></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id358265">The working directory</h2></div></div></div><p id="x_307"><a name="x_307"></a>In the working directory, Mercurial stores a snapshot of the
|
||||
files from the repository as of a particular changeset.</p><p id="x_308"><a name="x_308"></a>The working directory “<span class="quote">knows</span>” which changeset
|
||||
it contains. When you update the working directory to contain a
|
||||
particular changeset, Mercurial looks up the appropriate
|
||||
revision of the manifest to find out which files it was tracking
|
||||
at the time that changeset was committed, and which revision of
|
||||
each file was then current. It then recreates a copy of each of
|
||||
those files, with the same contents it had when the changeset
|
||||
was committed.</p><p id="x_309"><a name="x_309"></a>The <span class="emphasis"><em>dirstate</em></span> is a special
|
||||
structure that contains Mercurial's knowledge of the working
|
||||
directory. It is maintained as a file named
|
||||
<code class="filename">.hg/dirstate</code> inside a repository. The
|
||||
dirstate details which changeset the working directory is
|
||||
updated to, and all of the files that Mercurial is tracking in
|
||||
the working directory. It also lets Mercurial quickly notice
|
||||
changed files, by recording their checkout times and
|
||||
sizes.</p><p id="x_30a"><a name="x_30a"></a>Just as a revision of a revlog has room for two parents, so
|
||||
that it can represent either a normal revision (with one parent)
|
||||
or a merge of two earlier revisions, the dirstate has slots for
|
||||
two parents. When you use the <span class="command"><strong>hg
|
||||
update</strong></span> command, the changeset that you update to is
|
||||
stored in the “<span class="quote">first parent</span>” slot, and the null ID
|
||||
in the second. When you <span class="command"><strong>hg
|
||||
merge</strong></span> with another changeset, the first parent
|
||||
remains unchanged, and the second parent is filled in with the
|
||||
changeset you're merging with. The <span class="command"><strong>hg
|
||||
parents</strong></span> command tells you what the parents of the
|
||||
dirstate are.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358342">What happens when you commit</h3></div></div></div><p id="x_30b"><a name="x_30b"></a>The dirstate stores parent information for more than just
|
||||
book-keeping purposes. Mercurial uses the parents of the
|
||||
dirstate as <span class="emphasis"><em>the parents of a new
|
||||
changeset</em></span> when you perform a commit.</p><div class="figure"><a name="fig:concepts:wdir"></a><p class="title"><b>Figure 4.5. The working directory can have two parents</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/wdir.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_30d"><a name="x_30d"></a><a class="xref" href="behind-the-scenes.html#fig:concepts:wdir" title="Figure 4.5. The working directory can have two parents">Figure 4.5, “The working directory can have two parents”</a> shows the
|
||||
normal state of the working directory, where it has a single
|
||||
changeset as parent. That changeset is the
|
||||
<span class="emphasis"><em>tip</em></span>, the newest changeset in the
|
||||
repository that has no children.</p><div class="figure"><a name="fig:concepts:wdir-after-commit"></a><p class="title"><b>Figure 4.6. The working directory gains new parents after a
|
||||
commit</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/wdir-after-commit.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_30f"><a name="x_30f"></a>It's useful to think of the working directory as
|
||||
“<span class="quote">the changeset I'm about to commit</span>”. Any files
|
||||
that you tell Mercurial that you've added, removed, renamed,
|
||||
or copied will be reflected in that changeset, as will
|
||||
modifications to any files that Mercurial is already tracking;
|
||||
the new changeset will have the parents of the working
|
||||
directory as its parents.</p><p id="x_310"><a name="x_310"></a>After a commit, Mercurial will update the
|
||||
parents of the working directory, so that the first parent is
|
||||
the ID of the new changeset, and the second is the null ID.
|
||||
This is shown in <a class="xref" href="behind-the-scenes.html#fig:concepts:wdir-after-commit" title="Figure 4.6. The working directory gains new parents after a commit">Figure 4.6, “The working directory gains new parents after a
|
||||
commit”</a>. Mercurial
|
||||
doesn't touch any of the files in the working directory when
|
||||
you commit; it just modifies the dirstate to note its new
|
||||
parents.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358441">Creating a new head</h3></div></div></div><p id="x_311"><a name="x_311"></a>It's perfectly normal to update the working directory to a
|
||||
changeset other than the current tip. For example, you might
|
||||
want to know what your project looked like last Tuesday, or
|
||||
you could be looking through changesets to see which one
|
||||
introduced a bug. In cases like this, the natural thing to do
|
||||
is update the working directory to the changeset you're
|
||||
interested in, and then examine the files in the working
|
||||
directory directly to see their contents as they were when you
|
||||
committed that changeset. The effect of this is shown in
|
||||
<a class="xref" href="behind-the-scenes.html#fig:concepts:wdir-pre-branch" title="Figure 4.7. The working directory, updated to an older changeset">Figure 4.7, “The working directory, updated to an older
|
||||
changeset”</a>.</p><div class="figure"><a name="fig:concepts:wdir-pre-branch"></a><p class="title"><b>Figure 4.7. The working directory, updated to an older
|
||||
changeset</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/wdir-pre-branch.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_313"><a name="x_313"></a>Having updated the working directory to an
|
||||
older changeset, what happens if you make some changes, and
|
||||
then commit? Mercurial behaves in the same way as I outlined
|
||||
above. The parents of the working directory become the
|
||||
parents of the new changeset. This new changeset has no
|
||||
children, so it becomes the new tip. And the repository now
|
||||
contains two changesets that have no children; we call these
|
||||
<span class="emphasis"><em>heads</em></span>. You can see the structure that
|
||||
this creates in <a class="xref" href="behind-the-scenes.html#fig:concepts:wdir-branch" title="Figure 4.8. After a commit made while synced to an older changeset">Figure 4.8, “After a commit made while synced to an older
|
||||
changeset”</a>.</p><div class="figure"><a name="fig:concepts:wdir-branch"></a><p class="title"><b>Figure 4.8. After a commit made while synced to an older
|
||||
changeset</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/wdir-branch.png" alt="XXX add text"></div></div></div><br class="figure-break"><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_315"><a name="x_315"></a>If you're new to Mercurial, you should keep
|
||||
in mind a common “<span class="quote">error</span>”, which is to use the
|
||||
<span class="command"><strong>hg pull</strong></span> command without any
|
||||
options. By default, the <span class="command"><strong>hg
|
||||
pull</strong></span> command <span class="emphasis"><em>does not</em></span>
|
||||
update the working directory, so you'll bring new changesets
|
||||
into your repository, but the working directory will stay
|
||||
synced at the same changeset as before the pull. If you
|
||||
make some changes and commit afterwards, you'll thus create
|
||||
a new head, because your working directory isn't synced to
|
||||
whatever the current tip is. To combine the operation of a
|
||||
pull, followed by an update, run <span class="command"><strong>hg pull
|
||||
-u</strong></span>.</p><p id="x_316"><a name="x_316"></a>I put the word “<span class="quote">error</span>” in quotes
|
||||
because all that you need to do to rectify the situation
|
||||
where you created a new head by accident is
|
||||
<span class="command"><strong>hg merge</strong></span>, then <span class="command"><strong>hg commit</strong></span>. In other words, this
|
||||
almost never has negative consequences; it's just something
|
||||
of a surprise for newcomers. I'll discuss other ways to
|
||||
avoid this behavior, and why Mercurial behaves in this
|
||||
initially surprising way, later on.</p></td></tr></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358589">Merging changes</h3></div></div></div><p id="x_317"><a name="x_317"></a>When you run the <span class="command"><strong>hg
|
||||
merge</strong></span> command, Mercurial leaves the first parent
|
||||
of the working directory unchanged, and sets the second parent
|
||||
to the changeset you're merging with, as shown in <a class="xref" href="behind-the-scenes.html#fig:concepts:wdir-merge" title="Figure 4.9. Merging two heads">Figure 4.9, “Merging two heads”</a>.</p><div class="figure"><a name="fig:concepts:wdir-merge"></a><p class="title"><b>Figure 4.9. Merging two heads</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/wdir-merge.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_319"><a name="x_319"></a>Mercurial also has to modify the working directory, to
|
||||
merge the files managed in the two changesets. Simplified a
|
||||
little, the merging process goes like this, for every file in
|
||||
the manifests of both changesets.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_31a"><a name="x_31a"></a>If neither changeset has modified a file, do
|
||||
nothing with that file.</p></li><li><p id="x_31b"><a name="x_31b"></a>If one changeset has modified a file, and the
|
||||
other hasn't, create the modified copy of the file in the
|
||||
working directory.</p></li><li><p id="x_31c"><a name="x_31c"></a>If one changeset has removed a file, and the
|
||||
other hasn't (or has also deleted it), delete the file
|
||||
from the working directory.</p></li><li><p id="x_31d"><a name="x_31d"></a>If one changeset has removed a file, but the
|
||||
other has modified the file, ask the user what to do: keep
|
||||
the modified file, or remove it?</p></li><li><p id="x_31e"><a name="x_31e"></a>If both changesets have modified a file,
|
||||
invoke an external merge program to choose the new
|
||||
contents for the merged file. This may require input from
|
||||
the user.</p></li><li><p id="x_31f"><a name="x_31f"></a>If one changeset has modified a file, and the
|
||||
other has renamed or copied the file, make sure that the
|
||||
changes follow the new name of the file.</p></li></ul></div><p id="x_320"><a name="x_320"></a>There are more details—merging has plenty of corner
|
||||
cases—but these are the most common choices that are
|
||||
involved in a merge. As you can see, most cases are
|
||||
completely automatic, and indeed most merges finish
|
||||
automatically, without requiring your input to resolve any
|
||||
conflicts.</p><p id="x_321"><a name="x_321"></a>When you're thinking about what happens when you commit
|
||||
after a merge, once again the working directory is “<span class="quote">the
|
||||
changeset I'm about to commit</span>”. After the <span class="command"><strong>hg merge</strong></span> command completes, the
|
||||
working directory has two parents; these will become the
|
||||
parents of the new changeset.</p><p id="x_322"><a name="x_322"></a>Mercurial lets you perform multiple merges, but
|
||||
you must commit the results of each individual merge as you
|
||||
go. This is necessary because Mercurial only tracks two
|
||||
parents for both revisions and the working directory. While
|
||||
it would be technically feasible to merge multiple changesets
|
||||
at once, Mercurial avoids this for simplicity. With multi-way
|
||||
merges, the risks of user confusion, nasty conflict
|
||||
resolution, and making a terrible mess of a merge would grow
|
||||
intolerable.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358735">Merging and renames</h3></div></div></div><p id="x_69a"><a name="x_69a"></a>A surprising number of revision control systems pay little
|
||||
or no attention to a file's <span class="emphasis"><em>name</em></span> over
|
||||
time. For instance, it used to be common that if a file got
|
||||
renamed on one side of a merge, the changes from the other
|
||||
side would be silently dropped.</p><p id="x_69b"><a name="x_69b"></a>Mercurial records metadata when you tell it to perform a
|
||||
rename or copy. It uses this metadata during a merge to do the
|
||||
right thing in the case of a merge. For instance, if I rename
|
||||
a file, and you edit it without renaming it, when we merge our
|
||||
work the file will be renamed and have your edits
|
||||
applied.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id358761">Other interesting design features</h2></div></div></div><p id="x_323"><a name="x_323"></a>In the sections above, I've tried to highlight some of the
|
||||
most important aspects of Mercurial's design, to illustrate that
|
||||
it pays careful attention to reliability and performance.
|
||||
However, the attention to detail doesn't stop there. There are
|
||||
a number of other aspects of Mercurial's construction that I
|
||||
personally find interesting. I'll detail a few of them here,
|
||||
separate from the “<span class="quote">big ticket</span>” items above, so that
|
||||
if you're interested, you can gain a better idea of the amount
|
||||
of thinking that goes into a well-designed system.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358780">Clever compression</h3></div></div></div><p id="x_324"><a name="x_324"></a>When appropriate, Mercurial will store both snapshots and
|
||||
deltas in compressed form. It does this by always
|
||||
<span class="emphasis"><em>trying to</em></span> compress a snapshot or delta,
|
||||
but only storing the compressed version if it's smaller than
|
||||
the uncompressed version.</p><p id="x_325"><a name="x_325"></a>This means that Mercurial does “<span class="quote">the right
|
||||
thing</span>” when storing a file whose native form is
|
||||
compressed, such as a <code class="literal">zip</code> archive or a JPEG
|
||||
image. When these types of files are compressed a second
|
||||
time, the resulting file is usually bigger than the
|
||||
once-compressed form, and so Mercurial will store the plain
|
||||
<code class="literal">zip</code> or JPEG.</p><p id="x_326"><a name="x_326"></a>Deltas between revisions of a compressed file are usually
|
||||
larger than snapshots of the file, and Mercurial again does
|
||||
“<span class="quote">the right thing</span>” in these cases. It finds that
|
||||
such a delta exceeds the threshold at which it should store a
|
||||
complete snapshot of the file, so it stores the snapshot,
|
||||
again saving space compared to a naive delta-only
|
||||
approach.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id358828">Network recompression</h4></div></div></div><p id="x_327"><a name="x_327"></a>When storing revisions on disk, Mercurial uses the
|
||||
“<span class="quote">deflate</span>” compression algorithm (the same one
|
||||
used by the popular <code class="literal">zip</code> archive format),
|
||||
which balances good speed with a respectable compression
|
||||
ratio. However, when transmitting revision data over a
|
||||
network connection, Mercurial uncompresses the compressed
|
||||
revision data.</p><p id="x_328"><a name="x_328"></a>If the connection is over HTTP, Mercurial recompresses
|
||||
the entire stream of data using a compression algorithm that
|
||||
gives a better compression ratio (the Burrows-Wheeler
|
||||
algorithm from the widely used <code class="literal">bzip2</code>
|
||||
compression package). This combination of algorithm and
|
||||
compression of the entire stream (instead of a revision at a
|
||||
time) substantially reduces the number of bytes to be
|
||||
transferred, yielding better network performance over most
|
||||
kinds of network.</p><p id="x_329"><a name="x_329"></a>If the connection is over
|
||||
<span class="command"><strong>ssh</strong></span>, Mercurial
|
||||
<span class="emphasis"><em>doesn't</em></span> recompress the stream, because
|
||||
<span class="command"><strong>ssh</strong></span> can already do this itself. You can
|
||||
tell Mercurial to always use <span class="command"><strong>ssh</strong></span>'s
|
||||
compression feature by editing the
|
||||
<code class="filename">.hgrc</code> file in your home directory as
|
||||
follows.</p><pre id="id358894" class="programlisting">[ui]
|
||||
ssh = ssh -C</pre></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358901">Read/write ordering and atomicity</h3></div></div></div><p id="x_32a"><a name="x_32a"></a>Appending to files isn't the whole story when
|
||||
it comes to guaranteeing that a reader won't see a partial
|
||||
write. If you recall <a class="xref" href="behind-the-scenes.html#fig:concepts:metadata" title="Figure 4.2. Metadata relationships">Figure 4.2, “Metadata relationships”</a>,
|
||||
revisions in the changelog point to revisions in the manifest,
|
||||
and revisions in the manifest point to revisions in filelogs.
|
||||
This hierarchy is deliberate.</p><p id="x_32b"><a name="x_32b"></a>A writer starts a transaction by writing filelog and
|
||||
manifest data, and doesn't write any changelog data until
|
||||
those are finished. A reader starts by reading changelog
|
||||
data, then manifest data, followed by filelog data.</p><p id="x_32c"><a name="x_32c"></a>Since the writer has always finished writing filelog and
|
||||
manifest data before it writes to the changelog, a reader will
|
||||
never read a pointer to a partially written manifest revision
|
||||
from the changelog, and it will never read a pointer to a
|
||||
partially written filelog revision from the manifest.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id358935">Concurrent access</h3></div></div></div><p id="x_32d"><a name="x_32d"></a>The read/write ordering and atomicity guarantees mean that
|
||||
Mercurial never needs to <span class="emphasis"><em>lock</em></span> a
|
||||
repository when it's reading data, even if the repository is
|
||||
being written to while the read is occurring. This has a big
|
||||
effect on scalability; you can have an arbitrary number of
|
||||
Mercurial processes safely reading data from a repository
|
||||
all at once, no matter whether it's being written to or
|
||||
not.</p><p id="x_32e"><a name="x_32e"></a>The lockless nature of reading means that if you're
|
||||
sharing a repository on a multi-user system, you don't need to
|
||||
grant other local users permission to
|
||||
<span class="emphasis"><em>write</em></span> to your repository in order for
|
||||
them to be able to clone it or pull changes from it; they only
|
||||
need <span class="emphasis"><em>read</em></span> permission. (This is
|
||||
<span class="emphasis"><em>not</em></span> a common feature among revision
|
||||
control systems, so don't take it for granted! Most require
|
||||
readers to be able to lock a repository to access it safely,
|
||||
and this requires write permission on at least one directory,
|
||||
which of course makes for all kinds of nasty and annoying
|
||||
security and administrative problems.)</p><p id="x_32f"><a name="x_32f"></a>Mercurial uses locks to ensure that only one process can
|
||||
write to a repository at a time (the locking mechanism is safe
|
||||
even over filesystems that are notoriously hostile to locking,
|
||||
such as NFS). If a repository is locked, a writer will wait
|
||||
for a while to retry if the repository becomes unlocked, but
|
||||
if the repository remains locked for too long, the process
|
||||
attempting to write will time out after a while. This means
|
||||
that your daily automated scripts won't get stuck forever and
|
||||
pile up if a system crashes unnoticed, for example. (Yes, the
|
||||
timeout is configurable, from zero to infinity.)</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id358982">Safe dirstate access</h4></div></div></div><p id="x_330"><a name="x_330"></a>As with revision data, Mercurial doesn't take a lock to
|
||||
read the dirstate file; it does acquire a lock to write it.
|
||||
To avoid the possibility of reading a partially written copy
|
||||
of the dirstate file, Mercurial writes to a file with a
|
||||
unique name in the same directory as the dirstate file, then
|
||||
renames the temporary file atomically to
|
||||
<code class="filename">dirstate</code>. The file named
|
||||
<code class="filename">dirstate</code> is thus guaranteed to be
|
||||
complete, not partially written.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id359009">Avoiding seeks</h3></div></div></div><p id="x_331"><a name="x_331"></a>Critical to Mercurial's performance is the avoidance of
|
||||
seeks of the disk head, since any seek is far more expensive
|
||||
than even a comparatively large read operation.</p><p id="x_332"><a name="x_332"></a>This is why, for example, the dirstate is stored in a
|
||||
single file. If there were a dirstate file per directory that
|
||||
Mercurial tracked, the disk would seek once per directory.
|
||||
Instead, Mercurial reads the entire single dirstate file in
|
||||
one step.</p><p id="x_333"><a name="x_333"></a>Mercurial also uses a “<span class="quote">copy on write</span>” scheme
|
||||
when cloning a repository on local storage. Instead of
|
||||
copying every revlog file from the old repository into the new
|
||||
repository, it makes a “<span class="quote">hard link</span>”, which is a
|
||||
shorthand way to say “<span class="quote">these two names point to the same
|
||||
file</span>”. When Mercurial is about to write to one of a
|
||||
revlog's files, it checks to see if the number of names
|
||||
pointing at the file is greater than one. If it is, more than
|
||||
one repository is using the file, so Mercurial makes a new
|
||||
copy of the file that is private to this repository.</p><p id="x_334"><a name="x_334"></a>A few revision control developers have pointed out that
|
||||
this idea of making a complete private copy of a file is not
|
||||
very efficient in its use of storage. While this is true,
|
||||
storage is cheap, and this method gives the highest
|
||||
performance while deferring most book-keeping to the operating
|
||||
system. An alternative scheme would most likely reduce
|
||||
performance and increase the complexity of the software, but
|
||||
speed and simplicity are key to the “<span class="quote">feel</span>” of
|
||||
day-to-day use.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id359061">Other contents of the dirstate</h3></div></div></div><p id="x_335"><a name="x_335"></a>Because Mercurial doesn't force you to tell it when you're
|
||||
modifying a file, it uses the dirstate to store some extra
|
||||
information so it can determine efficiently whether you have
|
||||
modified a file. For each file in the working directory, it
|
||||
stores the time that it last modified the file itself, and the
|
||||
size of the file at that time.</p><p id="x_336"><a name="x_336"></a>When you explicitly <span class="command"><strong>hg
|
||||
add</strong></span>, <span class="command"><strong>hg remove</strong></span>,
|
||||
<span class="command"><strong>hg rename</strong></span> or <span class="command"><strong>hg copy</strong></span> files, Mercurial updates the
|
||||
dirstate so that it knows what to do with those files when you
|
||||
commit.</p><p id="x_337"><a name="x_337"></a>The dirstate helps Mercurial to efficiently
|
||||
check the status of files in a repository.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_726"><a name="x_726"></a>When Mercurial checks the state of a file in the
|
||||
working directory, it first checks a file's modification
|
||||
time against the time in the dirstate that records when
|
||||
Mercurial last wrote the file. If the last modified time
|
||||
is the same as the time when Mercurial wrote the file, the
|
||||
file must not have been modified, so Mercurial does not
|
||||
need to check any further.</p></li><li><p id="x_727"><a name="x_727"></a>If the file's size has changed, the file must have
|
||||
been modified. If the modification time has changed, but
|
||||
the size has not, only then does Mercurial need to
|
||||
actually read the contents of the file to see if it has
|
||||
changed.</p></li></ul></div><p id="x_728"><a name="x_728"></a>Storing the modification time and size dramatically
|
||||
reduces the number of read operations that Mercurial needs to
|
||||
perform when we run commands like <span class="command"><strong>hg status</strong></span>.
|
||||
This results in large performance improvements.</p></div></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.id357972" href="#id357972" class="para">3</a>] </sup>It is possible (though unusual) for the manifest to
|
||||
remain the same between two changesets, in which case the
|
||||
changelog entries for those changesets will point to the
|
||||
same revision of the manifest.</p></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="a-tour-of-mercurial-merging-work.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="mercurial-in-daily-use.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 3. A tour of Mercurial: merging work </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 5. Mercurial in daily use</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
967
read/collaborating-with-other-people.html
Normal file
967
read/collaborating-with-other-people.html
Normal file
|
@ -0,0 +1,967 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 6. Collaborating with other people</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="mercurial-in-daily-use.html" title="Chapter 5. Mercurial in daily use"><link rel="next" href="file-names-and-pattern-matching.html" title="Chapter 7. File names and pattern matching"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 6. Collaborating with other people</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="mercurial-in-daily-use.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="file-names-and-pattern-matching.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="cha:collab"><div class="titlepage"><div><div><h2 class="title">Chapter 6. Collaborating with other people</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="collaborating-with-other-people.html#id370764">Mercurial's web interface</a></span></dt><dt><span class="sect1"><a href="collaborating-with-other-people.html#id371206">Collaboration models</a></span></dt><dd><dl><dt><span class="sect2"><a href="collaborating-with-other-people.html#id371225">Factors to keep in mind</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id371265">Informal anarchy</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id371355">A single central repository</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id371424">A hosted central repository</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id371466">Working with multiple branches</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id372365">Feature branches</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id372420">The release train</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id372519">The Linux kernel model</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id372641">Pull-only versus shared-push collaboration</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id372699">Where collaboration meets branch management</a></span></dt></dl></dd><dt><span class="sect1"><a href="collaborating-with-other-people.html#id372723">The technical side of sharing</a></span></dt><dt><span class="sect1"><a href="collaborating-with-other-people.html#sec:collab:serve">Informal sharing with hg
|
||||
serve</a></span></dt><dd><dl><dt><span class="sect2"><a href="collaborating-with-other-people.html#id372918">A few things to keep in mind</a></span></dt></dl></dd><dt><span class="sect1"><a href="collaborating-with-other-people.html#sec:collab:ssh">Using the Secure Shell (ssh) protocol</a></span></dt><dd><dl><dt><span class="sect2"><a href="collaborating-with-other-people.html#id373065">How to read and write ssh URLs</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id373261">Finding an ssh client for your system</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id373312">Generating a key pair</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id373466">Using an authentication agent</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id373568">Configuring the server side properly</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id373965">Using compression with ssh</a></span></dt></dl></dd><dt><span class="sect1"><a href="collaborating-with-other-people.html#sec:collab:cgi">Serving over HTTP using CGI</a></span></dt><dd><dl><dt><span class="sect2"><a href="collaborating-with-other-people.html#id374172">Web server configuration checklist</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id374257">Basic CGI configuration</a></span></dt><dd><dl><dt><span class="sect3"><a href="collaborating-with-other-people.html#sec:collab:wtf">What could possibly go
|
||||
wrong?</a></span></dt><dt><span class="sect3"><a href="collaborating-with-other-people.html#id374655">Configuring lighttpd</a></span></dt></dl></dd><dt><span class="sect2"><a href="collaborating-with-other-people.html#id374764">Sharing multiple repositories with one CGI script</a></span></dt><dd><dl><dt><span class="sect3"><a href="collaborating-with-other-people.html#id375138">Explicitly specifying which repositories to
|
||||
publish</a></span></dt></dl></dd><dt><span class="sect2"><a href="collaborating-with-other-people.html#id375233">Downloading source archives</a></span></dt><dt><span class="sect2"><a href="collaborating-with-other-people.html#id375279">Web configuration options</a></span></dt><dd><dl><dt><span class="sect3"><a href="collaborating-with-other-people.html#id375762">Options specific to an individual repository</a></span></dt><dt><span class="sect3"><a href="collaborating-with-other-people.html#id375833">Options specific to the hg
|
||||
serve command</a></span></dt><dt><span class="sect3"><a href="collaborating-with-other-people.html#id375978">Choosing the right ~/.hgrc file to add web items to</a></span></dt></dl></dd></dl></dd><dt><span class="sect1"><a href="collaborating-with-other-people.html#id376085">System-wide configuration</a></span></dt><dd><dl><dt><span class="sect2"><a href="collaborating-with-other-people.html#id376128">Making Mercurial more trusting</a></span></dt></dl></dd></dl></div><p id="x_44a"><a name="x_44a"></a>As a completely decentralised tool, Mercurial doesn't impose
|
||||
any policy on how people ought to work with each other. However,
|
||||
if you're new to distributed revision control, it helps to have
|
||||
some tools and examples in mind when you're thinking about
|
||||
possible workflow models.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id370764">Mercurial's web interface</h2></div></div></div><p id="x_44b"><a name="x_44b"></a>Mercurial has a powerful web interface that provides several
|
||||
useful capabilities.</p><p id="x_44c"><a name="x_44c"></a>For interactive use, the web interface lets you browse a
|
||||
single repository or a collection of repositories. You can view
|
||||
the history of a repository, examine each change (comments and
|
||||
diffs), and view the contents of each directory and file. You
|
||||
can even get a view of history that gives a graphical view of
|
||||
the relationships between individual changes and merges.</p><p id="x_44d"><a name="x_44d"></a>Also for human consumption, the web interface provides
|
||||
Atom and RSS feeds of the changes in a repository. This lets you
|
||||
“<span class="quote">subscribe</span>” to a repository using your favorite
|
||||
feed reader, and be automatically notified of activity in that
|
||||
repository as soon as it happens. I find this capability much
|
||||
more convenient than the model of subscribing to a mailing list
|
||||
to which notifications are sent, as it requires no additional
|
||||
configuration on the part of whoever is serving the
|
||||
repository.</p><p id="x_44e"><a name="x_44e"></a>The web interface also lets remote users clone a repository,
|
||||
pull changes from it, and (when the server is configured to
|
||||
permit it) push changes back to it. Mercurial's HTTP tunneling
|
||||
protocol aggressively compresses data, so that it works
|
||||
efficiently even over low-bandwidth network connections.</p><p id="x_44f"><a name="x_44f"></a>The easiest way to get started with the web interface is to
|
||||
use your web browser to visit an existing repository, such as
|
||||
the master Mercurial repository at <a class="ulink" href="http://www.selenic.com/repo/hg" target="_top">http://www.selenic.com/repo/hg</a>.</p><p id="x_450"><a name="x_450"></a>If you're interested in providing a web interface
|
||||
to your own repositories, there are several good ways to do
|
||||
this.</p><p id="x_69d"><a name="x_69d"></a>The easiest and fastest way to get started in an informal
|
||||
environment is to use the <span class="command"><strong>hg
|
||||
serve</strong></span> command, which is best suited to short-term
|
||||
“<span class="quote">lightweight</span>” serving. See <a class="xref" href="collaborating-with-other-people.html#sec:collab:serve" title="Informal sharing with hg serve">the section called “Informal sharing with hg
|
||||
serve”</a> below for details of how to use
|
||||
this command.</p><p id="x_69e"><a name="x_69e"></a>For longer-lived repositories that you'd like to
|
||||
have permanently available, there are several public hosting
|
||||
services available. Some are free to open source projects,
|
||||
while others offer paid commercial hosting. An up-to-date list
|
||||
is available at <a class="ulink" href="http://www.selenic.com/mercurial/wiki/index.cgi/MercurialHosting" target="_top">http://www.selenic.com/mercurial/wiki/index.cgi/MercurialHosting</a>.</p><p id="x_6a0"><a name="x_6a0"></a>If you would prefer to host your own repositories, Mercurial
|
||||
has built-in support for several popular hosting technologies,
|
||||
most notably CGI (Common Gateway Interface), and WSGI (Web
|
||||
Services Gateway Interface). See <a class="xref" href="collaborating-with-other-people.html#sec:collab:cgi" title="Serving over HTTP using CGI">the section called “Serving over HTTP using CGI”</a> for details of CGI and WSGI
|
||||
configuration.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id371206">Collaboration models</h2></div></div></div><p id="x_451"><a name="x_451"></a>With a suitably flexible tool, making decisions about
|
||||
workflow is much more of a social engineering challenge than a
|
||||
technical one. Mercurial imposes few limitations on how you can
|
||||
structure the flow of work in a project, so it's up to you and
|
||||
your group to set up and live with a model that matches your own
|
||||
particular needs.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id371225">Factors to keep in mind</h3></div></div></div><p id="x_452"><a name="x_452"></a>The most important aspect of any model that you must keep
|
||||
in mind is how well it matches the needs and capabilities of
|
||||
the people who will be using it. This might seem
|
||||
self-evident; even so, you still can't afford to forget it for
|
||||
a moment.</p><p id="x_453"><a name="x_453"></a>I once put together a workflow model that seemed to make
|
||||
perfect sense to me, but that caused a considerable amount of
|
||||
consternation and strife within my development team. In spite
|
||||
of my attempts to explain why we needed a complex set of
|
||||
branches, and how changes ought to flow between them, a few
|
||||
team members revolted. Even though they were smart people,
|
||||
they didn't want to pay attention to the constraints we were
|
||||
operating under, or face the consequences of those constraints
|
||||
in the details of the model that I was advocating.</p><p id="x_454"><a name="x_454"></a>Don't sweep foreseeable social or technical problems under
|
||||
the rug. Whatever scheme you put into effect, you should plan
|
||||
for mistakes and problem scenarios. Consider adding automated
|
||||
machinery to prevent, or quickly recover from, trouble that
|
||||
you can anticipate. As an example, if you intend to have a
|
||||
branch with not-for-release changes in it, you'd do well to
|
||||
think early about the possibility that someone might
|
||||
accidentally merge those changes into a release branch. You
|
||||
could avoid this particular problem by writing a hook that
|
||||
prevents changes from being merged from an inappropriate
|
||||
branch.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id371265">Informal anarchy</h3></div></div></div><p id="x_455"><a name="x_455"></a>I wouldn't suggest an “<span class="quote">anything goes</span>”
|
||||
approach as something sustainable, but it's a model that's
|
||||
easy to grasp, and it works perfectly well in a few unusual
|
||||
situations.</p><p id="x_456"><a name="x_456"></a>As one example, many projects have a loose-knit group of
|
||||
collaborators who rarely physically meet each other. Some
|
||||
groups like to overcome the isolation of working at a distance
|
||||
by organizing occasional “<span class="quote">sprints</span>”. In a sprint,
|
||||
a number of people get together in a single location (a
|
||||
company's conference room, a hotel meeting room, that kind of
|
||||
place) and spend several days more or less locked in there,
|
||||
hacking intensely on a handful of projects.</p><p id="x_457"><a name="x_457"></a>A sprint or a hacking session in a coffee shop are the perfect places to use the
|
||||
<span class="command"><strong>hg serve</strong></span> command, since
|
||||
<span class="command"><strong>hg serve</strong></span> does not require any
|
||||
fancy server infrastructure. You can get started with
|
||||
<span class="command"><strong>hg serve</strong></span> in moments, by
|
||||
reading <a class="xref" href="collaborating-with-other-people.html#sec:collab:serve" title="Informal sharing with hg serve">the section called “Informal sharing with hg
|
||||
serve”</a> below. Then simply
|
||||
tell the person next to you that you're running a server, send
|
||||
the URL to them in an instant message, and you immediately
|
||||
have a quick-turnaround way to work together. They can type
|
||||
your URL into their web browser and quickly review your
|
||||
changes; or they can pull a bugfix from you and verify it; or
|
||||
they can clone a branch containing a new feature and try it
|
||||
out.</p><p id="x_458"><a name="x_458"></a>The charm, and the problem, with doing things
|
||||
in an ad hoc fashion like this is that only people who know
|
||||
about your changes, and where they are, can see them. Such an
|
||||
informal approach simply doesn't scale beyond a handful
|
||||
people, because each individual needs to know about
|
||||
<span class="emphasis"><em>n</em></span> different repositories to pull
|
||||
from.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id371355">A single central repository</h3></div></div></div><p id="x_459"><a name="x_459"></a>For smaller projects migrating from a centralised revision
|
||||
control tool, perhaps the easiest way to get started is to
|
||||
have changes flow through a single shared central repository.
|
||||
This is also the most common “<span class="quote">building block</span>” for
|
||||
more ambitious workflow schemes.</p><p id="x_45a"><a name="x_45a"></a>Contributors start by cloning a copy of this repository.
|
||||
They can pull changes from it whenever they need to, and some
|
||||
(perhaps all) developers have permission to push a change back
|
||||
when they're ready for other people to see it.</p><p id="x_45b"><a name="x_45b"></a>Under this model, it can still often make sense for people
|
||||
to pull changes directly from each other, without going
|
||||
through the central repository. Consider a case in which I
|
||||
have a tentative bug fix, but I am worried that if I were to
|
||||
publish it to the central repository, it might subsequently
|
||||
break everyone else's trees as they pull it. To reduce the
|
||||
potential for damage, I can ask you to clone my repository
|
||||
into a temporary repository of your own and test it. This
|
||||
lets us put off publishing the potentially unsafe change until
|
||||
it has had a little testing.</p><p id="x_45c"><a name="x_45c"></a>If a team is hosting its own repository in this
|
||||
kind of scenario, people will usually use the
|
||||
<span class="command"><strong>ssh</strong></span> protocol to securely push changes to
|
||||
the central repository, as documented in <a class="xref" href="collaborating-with-other-people.html#sec:collab:ssh" title="Using the Secure Shell (ssh) protocol">the section called “Using the Secure Shell (ssh) protocol”</a>. It's also usual to publish a
|
||||
read-only copy of the repository over HTTP, as in
|
||||
<a class="xref" href="collaborating-with-other-people.html#sec:collab:cgi" title="Serving over HTTP using CGI">the section called “Serving over HTTP using CGI”</a>. Publishing over HTTP
|
||||
satisfies the needs of people who don't have push access, and
|
||||
those who want to use web browsers to browse the repository's
|
||||
history.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id371424">A hosted central repository</h3></div></div></div><p id="x_6a1"><a name="x_6a1"></a>A wonderful thing about public hosting services like
|
||||
<a class="ulink" href="http://bitbucket.org/" target="_top">Bitbucket</a> is that
|
||||
not only do they handle the fiddly server configuration
|
||||
details, such as user accounts, authentication, and secure
|
||||
wire protocols, they provide additional infrastructure to make
|
||||
this model work well.</p><p id="x_6a2"><a name="x_6a2"></a>For instance, a well-engineered hosting service will let
|
||||
people clone their own copies of a repository with a single
|
||||
click. This lets people work in separate spaces and share
|
||||
their changes when they're ready.</p><p id="x_6a3"><a name="x_6a3"></a>In addition, a good hosting service will let people
|
||||
communicate with each other, for instance to say “<span class="quote">there
|
||||
are changes ready for you to review in this
|
||||
tree</span>”.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id371466">Working with multiple branches</h3></div></div></div><p id="x_45d"><a name="x_45d"></a>Projects of any significant size naturally tend to make
|
||||
progress on several fronts simultaneously. In the case of
|
||||
software, it's common for a project to go through periodic
|
||||
official releases. A release might then go into
|
||||
“<span class="quote">maintenance mode</span>” for a while after its first
|
||||
publication; maintenance releases tend to contain only bug
|
||||
fixes, not new features. In parallel with these maintenance
|
||||
releases, one or more future releases may be under
|
||||
development. People normally use the word
|
||||
“<span class="quote">branch</span>” to refer to one of these many slightly
|
||||
different directions in which development is
|
||||
proceeding.</p><p id="x_45e"><a name="x_45e"></a>Mercurial is particularly well suited to managing a number
|
||||
of simultaneous, but not identical, branches. Each
|
||||
“<span class="quote">development direction</span>” can live in its own
|
||||
central repository, and you can merge changes from one to
|
||||
another as the need arises. Because repositories are
|
||||
independent of each other, unstable changes in a development
|
||||
branch will never affect a stable branch unless someone
|
||||
explicitly merges those changes into the stable branch.</p><p id="x_45f"><a name="x_45f"></a>Here's an example of how this can work in practice. Let's
|
||||
say you have one “<span class="quote">main branch</span>” on a central
|
||||
server.</p><pre id="id371865" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init main</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd main</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo 'This is a boring feature.' > myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -A -m 'We have reached an important milestone!'</code></strong>
|
||||
adding myfile
|
||||
</pre><p id="x_460"><a name="x_460"></a>People clone it, make changes locally, test them, and push
|
||||
them back.</p><p id="x_461"><a name="x_461"></a>Once the main branch reaches a release milestone, you can
|
||||
use the <span class="command"><strong>hg tag</strong></span> command to
|
||||
give a permanent name to the milestone revision.</p><pre id="id371755" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tag v1.0</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 1:47867ad65069
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:20 2009 +0000
|
||||
summary: Added tag v1.0 for changeset cefe13bbe8af
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tags</code></strong>
|
||||
tip 1:47867ad65069
|
||||
v1.0 0:cefe13bbe8af
|
||||
</pre><p id="x_462"><a name="x_462"></a>Let's say some ongoing
|
||||
development occurs on the main branch.</p><pre id="id372110" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ../main</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo 'This is exciting and new!' >> myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Add a new feature'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
|
||||
This is a boring feature.
|
||||
This is exciting and new!
|
||||
</pre><p id="x_463"><a name="x_463"></a>Using the tag that was recorded at the milestone, people
|
||||
who clone that repository at any time in the future can use
|
||||
<span class="command"><strong>hg update</strong></span> to get a copy of
|
||||
the working directory exactly as it was when that tagged
|
||||
revision was committed.</p><pre id="id372066" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone -U main main-old</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd main-old</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg update v1.0</code></strong>
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
|
||||
This is a boring feature.
|
||||
</pre><p id="x_464"><a name="x_464"></a>In addition, immediately after the main branch is tagged,
|
||||
we can then clone the main branch on the server to a new
|
||||
“<span class="quote">stable</span>” branch, also on the server.</p><pre id="id372035" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone -rv1.0 main stable</code></strong>
|
||||
requesting all changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_465"><a name="x_465"></a>If we need to make a change to the stable
|
||||
branch, we can then clone <span class="emphasis"><em>that</em></span>
|
||||
repository, make our changes, commit, and push our changes
|
||||
back there.</p><pre id="id372474" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg clone stable stable-fix</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd stable-fix</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo 'This is a fix to a boring feature.' > myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Fix a bug'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg push</code></strong>
|
||||
pushing to /tmp/branching3sONTi/stable
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files
|
||||
</pre><p id="x_466"><a name="x_466"></a>Because Mercurial repositories are independent, and
|
||||
Mercurial doesn't move changes around automatically, the
|
||||
stable and main branches are <span class="emphasis"><em>isolated</em></span>
|
||||
from each other. The changes that we made on the main branch
|
||||
don't “<span class="quote">leak</span>” to the stable branch, and vice
|
||||
versa.</p><p id="x_467"><a name="x_467"></a>We'll often want all of our bugfixes on the stable
|
||||
branch to show up on the main branch, too. Rather than
|
||||
rewrite a bugfix on the main branch, we can simply pull and
|
||||
merge changes from the stable to the main branch, and
|
||||
Mercurial will bring those bugfixes in for us.</p><pre id="id372450" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ../main</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg pull ../stable</code></strong>
|
||||
pulling from ../stable
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files (+1 heads)
|
||||
(run 'hg heads' to see heads, 'hg merge' to merge)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
|
||||
merging myfile
|
||||
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
|
||||
(branch merge, don't forget to commit)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Bring in bugfix from stable branch'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
|
||||
This is a fix to a boring feature.
|
||||
This is exciting and new!
|
||||
</pre><p id="x_468"><a name="x_468"></a>The main branch will still contain changes that
|
||||
are not on the stable branch, but it will also contain all of
|
||||
the bugfixes from the stable branch. The stable branch
|
||||
remains unaffected by these changes, since changes are only
|
||||
flowing from the stable to the main branch, and not the other
|
||||
way.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id372365">Feature branches</h3></div></div></div><p id="x_469"><a name="x_469"></a>For larger projects, an effective way to manage change is
|
||||
to break up a team into smaller groups. Each group has a
|
||||
shared branch of its own, cloned from a single
|
||||
“<span class="quote">master</span>” branch used by the entire project.
|
||||
People working on an individual branch are typically quite
|
||||
isolated from developments on other branches.</p><div class="figure"><a name="fig:collab:feature-branches"></a><p class="title"><b>Figure 6.1. Feature branches</b></p><div class="figure-contents"><div class="mediaobject"><table border="0" summary="manufactured viewport for HTML img" cellspacing="0" cellpadding="0" width="100%"><tr><td><img src="figs/feature-branches.png" width="100%" alt="XXX add text"></td></tr></table></div></div></div><br class="figure-break"><p id="x_46b"><a name="x_46b"></a>When a particular feature is deemed to be in suitable
|
||||
shape, someone on that feature team pulls and merges from the
|
||||
master branch into the feature branch, then pushes back up to
|
||||
the master branch.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id372420">The release train</h3></div></div></div><p id="x_46c"><a name="x_46c"></a>Some projects are organized on a “<span class="quote">train</span>”
|
||||
basis: a release is scheduled to happen every few months, and
|
||||
whatever features are ready when the “<span class="quote">train</span>” is
|
||||
ready to leave are allowed in.</p><p id="x_46d"><a name="x_46d"></a>This model resembles working with feature branches. The
|
||||
difference is that when a feature branch misses a train,
|
||||
someone on the feature team pulls and merges the changes that
|
||||
went out on that train release into the feature branch, and
|
||||
the team continues its work on top of that release so that
|
||||
their feature can make the next release.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id372519">The Linux kernel model</h3></div></div></div><p id="x_46e"><a name="x_46e"></a>The development of the Linux kernel has a shallow
|
||||
hierarchical structure, surrounded by a cloud of apparent
|
||||
chaos. Because most Linux developers use
|
||||
<span class="command"><strong>git</strong></span>, a distributed revision control tool
|
||||
with capabilities similar to Mercurial, it's useful to
|
||||
describe the way work flows in that environment; if you like
|
||||
the ideas, the approach translates well across tools.</p><p id="x_46f"><a name="x_46f"></a>At the center of the community sits Linus Torvalds, the
|
||||
creator of Linux. He publishes a single source repository
|
||||
that is considered the “<span class="quote">authoritative</span>” current
|
||||
tree by the entire developer community. Anyone can clone
|
||||
Linus's tree, but he is very choosy about whose trees he pulls
|
||||
from.</p><p id="x_470"><a name="x_470"></a>Linus has a number of “<span class="quote">trusted lieutenants</span>”.
|
||||
As a general rule, he pulls whatever changes they publish, in
|
||||
most cases without even reviewing those changes. Some of
|
||||
those lieutenants are generally agreed to be
|
||||
“<span class="quote">maintainers</span>”, responsible for specific
|
||||
subsystems within the kernel. If a random kernel hacker wants
|
||||
to make a change to a subsystem that they want to end up in
|
||||
Linus's tree, they must find out who the subsystem's
|
||||
maintainer is, and ask that maintainer to take their change.
|
||||
If the maintainer reviews their changes and agrees to take
|
||||
them, they'll pass them along to Linus in due course.</p><p id="x_471"><a name="x_471"></a>Individual lieutenants have their own approaches to
|
||||
reviewing, accepting, and publishing changes; and for deciding
|
||||
when to feed them to Linus. In addition, there are several
|
||||
well known branches that people use for different purposes.
|
||||
For example, a few people maintain “<span class="quote">stable</span>”
|
||||
repositories of older versions of the kernel, to which they
|
||||
apply critical fixes as needed. Some maintainers publish
|
||||
multiple trees: one for experimental changes; one for changes
|
||||
that they are about to feed upstream; and so on. Others just
|
||||
publish a single tree.</p><p id="x_472"><a name="x_472"></a>This model has two notable features. The first is that
|
||||
it's “<span class="quote">pull only</span>”. You have to ask, convince, or
|
||||
beg another developer to take a change from you, because there
|
||||
are almost no trees to which more than one person can push,
|
||||
and there's no way to push changes into a tree that someone
|
||||
else controls.</p><p id="x_473"><a name="x_473"></a>The second is that it's based on reputation and acclaim.
|
||||
If you're an unknown, Linus will probably ignore changes from
|
||||
you without even responding. But a subsystem maintainer will
|
||||
probably review them, and will likely take them if they pass
|
||||
their criteria for suitability. The more “<span class="quote">good</span>”
|
||||
changes you contribute to a maintainer, the more likely they
|
||||
are to trust your judgment and accept your changes. If you're
|
||||
well-known and maintain a long-lived branch for something
|
||||
Linus hasn't yet accepted, people with similar interests may
|
||||
pull your changes regularly to keep up with your work.</p><p id="x_474"><a name="x_474"></a>Reputation and acclaim don't necessarily cross subsystem
|
||||
or “<span class="quote">people</span>” boundaries. If you're a respected
|
||||
but specialised storage hacker, and you try to fix a
|
||||
networking bug, that change will receive a level of scrutiny
|
||||
from a network maintainer comparable to a change from a
|
||||
complete stranger.</p><p id="x_475"><a name="x_475"></a>To people who come from more orderly project backgrounds,
|
||||
the comparatively chaotic Linux kernel development process
|
||||
often seems completely insane. It's subject to the whims of
|
||||
individuals; people make sweeping changes whenever they deem
|
||||
it appropriate; and the pace of development is astounding.
|
||||
And yet Linux is a highly successful, well-regarded piece of
|
||||
software.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id372641">Pull-only versus shared-push collaboration</h3></div></div></div><p id="x_476"><a name="x_476"></a>A perpetual source of heat in the open source community is
|
||||
whether a development model in which people only ever pull
|
||||
changes from others is “<span class="quote">better than</span>” one in which
|
||||
multiple people can push changes to a shared
|
||||
repository.</p><p id="x_477"><a name="x_477"></a>Typically, the backers of the shared-push model use tools
|
||||
that actively enforce this approach. If you're using a
|
||||
centralised revision control tool such as Subversion, there's
|
||||
no way to make a choice over which model you'll use: the tool
|
||||
gives you shared-push, and if you want to do anything else,
|
||||
you'll have to roll your own approach on top (such as applying
|
||||
a patch by hand).</p><p id="x_478"><a name="x_478"></a>A good distributed revision control tool will
|
||||
support both models. You and your collaborators can then
|
||||
structure how you work together based on your own needs and
|
||||
preferences, not on what contortions your tools force you
|
||||
into.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id372699">Where collaboration meets branch management</h3></div></div></div><p id="x_479"><a name="x_479"></a>Once you and your team set up some shared
|
||||
repositories and start propagating changes back and forth
|
||||
between local and shared repos, you begin to face a related,
|
||||
but slightly different challenge: that of managing the
|
||||
multiple directions in which your team may be moving at once.
|
||||
Even though this subject is intimately related to how your
|
||||
team collaborates, it's dense enough to merit treatment of its
|
||||
own, in <a class="xref" href="managing-releases-and-branchy-development.html" title="Chapter 8. Managing releases and branchy development">Chapter 8, <i>Managing releases and branchy development</i></a>.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id372723">The technical side of sharing</h2></div></div></div><p id="x_47a"><a name="x_47a"></a>The remainder of this chapter is devoted to the question of
|
||||
sharing changes with your collaborators.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:collab:serve">Informal sharing with <span class="command"><strong>hg
|
||||
serve</strong></span></h2></div></div></div><p id="x_47b"><a name="x_47b"></a>Mercurial's <span class="command"><strong>hg serve</strong></span>
|
||||
command is wonderfully suited to small, tight-knit, and
|
||||
fast-paced group environments. It also provides a great way to
|
||||
get a feel for using Mercurial commands over a network.</p><p id="x_47c"><a name="x_47c"></a>Run <span class="command"><strong>hg serve</strong></span> inside a
|
||||
repository, and in under a second it will bring up a specialised
|
||||
HTTP server; this will accept connections from any client, and
|
||||
serve up data for that repository until you terminate it.
|
||||
Anyone who knows the URL of the server you just started, and can
|
||||
talk to your computer over the network, can then use a web
|
||||
browser or Mercurial to read data from that repository. A URL
|
||||
for a <span class="command"><strong>hg serve</strong></span> instance running
|
||||
on a laptop is likely to look something like
|
||||
<code class="literal">http://my-laptop.local:8000/</code>.</p><p id="x_47d"><a name="x_47d"></a>The <span class="command"><strong>hg serve</strong></span> command is
|
||||
<span class="emphasis"><em>not</em></span> a general-purpose web server. It can do
|
||||
only two things:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_47e"><a name="x_47e"></a>Allow people to browse the history of the
|
||||
repository it's serving, from their normal web
|
||||
browsers.</p></li><li><p id="x_47f"><a name="x_47f"></a>Speak Mercurial's wire protocol, so that people
|
||||
can <span class="command"><strong>hg clone</strong></span> or <span class="command"><strong>hg pull</strong></span> changes from that
|
||||
repository.</p></li></ul></div><p id="x_480"><a name="x_480"></a>In particular, <span class="command"><strong>hg serve</strong></span>
|
||||
won't allow remote users to <span class="emphasis"><em>modify</em></span> your
|
||||
repository. It's intended for read-only use.</p><p id="x_481"><a name="x_481"></a>If you're getting started with Mercurial, there's nothing to
|
||||
prevent you from using <span class="command"><strong>hg serve</strong></span>
|
||||
to serve up a repository on your own computer, then use commands
|
||||
like <span class="command"><strong>hg clone</strong></span>, <span class="command"><strong>hg incoming</strong></span>, and so on to talk to that
|
||||
server as if the repository was hosted remotely. This can help
|
||||
you to quickly get acquainted with using commands on
|
||||
network-hosted repositories.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id372918">A few things to keep in mind</h3></div></div></div><p id="x_482"><a name="x_482"></a>Because it provides unauthenticated read access to all
|
||||
clients, you should only use <span class="command"><strong>hg
|
||||
serve</strong></span> in an environment where you either don't
|
||||
care, or have complete control over, who can access your
|
||||
network and pull data from your repository.</p><p id="x_483"><a name="x_483"></a>The <span class="command"><strong>hg serve</strong></span> command
|
||||
knows nothing about any firewall software you might have
|
||||
installed on your system or network. It cannot detect or
|
||||
control your firewall software. If other people are unable to
|
||||
talk to a running <span class="command"><strong>hg serve</strong></span>
|
||||
instance, the second thing you should do
|
||||
(<span class="emphasis"><em>after</em></span> you make sure that they're using
|
||||
the correct URL) is check your firewall configuration.</p><p id="x_484"><a name="x_484"></a>By default, <span class="command"><strong>hg serve</strong></span>
|
||||
listens for incoming connections on port 8000. If another
|
||||
process is already listening on the port you want to use, you
|
||||
can specify a different port to listen on using the <code class="option">-p</code> option.</p><p id="x_485"><a name="x_485"></a>Normally, when <span class="command"><strong>hg serve</strong></span>
|
||||
starts, it prints no output, which can be a bit unnerving. If
|
||||
you'd like to confirm that it is indeed running correctly, and
|
||||
find out what URL you should send to your collaborators, start
|
||||
it with the <code class="option">-v</code>
|
||||
option.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:collab:ssh">Using the Secure Shell (ssh) protocol</h2></div></div></div><p id="x_486"><a name="x_486"></a>You can pull and push changes securely over a network
|
||||
connection using the Secure Shell (<code class="literal">ssh</code>)
|
||||
protocol. To use this successfully, you may have to do a little
|
||||
bit of configuration on the client or server sides.</p><p id="x_487"><a name="x_487"></a>If you're not familiar with ssh, it's the name of
|
||||
both a command and a network protocol that let you securely
|
||||
communicate with another computer. To use it with Mercurial,
|
||||
you'll be setting up one or more user accounts on a server so
|
||||
that remote users can log in and execute commands.</p><p id="x_488"><a name="x_488"></a>(If you <span class="emphasis"><em>are</em></span> familiar with ssh, you'll
|
||||
probably find some of the material that follows to be elementary
|
||||
in nature.)</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id373065">How to read and write ssh URLs</h3></div></div></div><p id="x_489"><a name="x_489"></a>An ssh URL tends to look like this:</p><pre id="id373079" class="programlisting">ssh://bos@hg.serpentine.com:22/hg/hgbook</pre><div class="orderedlist"><ol type="1"><li><p id="x_48a"><a name="x_48a"></a>The “<span class="quote"><code class="literal">ssh://</code></span>”
|
||||
part tells Mercurial to use the ssh protocol.</p></li><li><p id="x_48b"><a name="x_48b"></a>The “<span class="quote"><code class="literal">bos@</code></span>”
|
||||
component indicates what username to log into the server
|
||||
as. You can leave this out if the remote username is the
|
||||
same as your local username.</p></li><li><p id="x_48c"><a name="x_48c"></a>The
|
||||
“<span class="quote"><code class="literal">hg.serpentine.com</code></span>” gives
|
||||
the hostname of the server to log into.</p></li><li><p id="x_48d"><a name="x_48d"></a>The “<span class="quote">:22</span>” identifies the port
|
||||
number to connect to the server on. The default port is
|
||||
22, so you only need to specify a colon and port number if
|
||||
you're <span class="emphasis"><em>not</em></span> using port 22.</p></li><li><p id="x_48e"><a name="x_48e"></a>The remainder of the URL is the local path to
|
||||
the repository on the server.</p></li></ol></div><p id="x_48f"><a name="x_48f"></a>There's plenty of scope for confusion with the path
|
||||
component of ssh URLs, as there is no standard way for tools
|
||||
to interpret it. Some programs behave differently than others
|
||||
when dealing with these paths. This isn't an ideal situation,
|
||||
but it's unlikely to change. Please read the following
|
||||
paragraphs carefully.</p><p id="x_490"><a name="x_490"></a>Mercurial treats the path to a repository on the server as
|
||||
relative to the remote user's home directory. For example, if
|
||||
user <code class="literal">foo</code> on the server has a home directory
|
||||
of <code class="filename">/home/foo</code>, then an
|
||||
ssh URL that contains a path component of <code class="filename">bar</code> <span class="emphasis"><em>really</em></span>
|
||||
refers to the directory <code class="filename">/home/foo/bar</code>.</p><p id="x_491"><a name="x_491"></a>If you want to specify a path relative to another user's
|
||||
home directory, you can use a path that starts with a tilde
|
||||
character followed by the user's name (let's call them
|
||||
<code class="literal">otheruser</code>), like this.</p><pre id="id373236" class="programlisting">ssh://server/~otheruser/hg/repo</pre><p id="x_492"><a name="x_492"></a>And if you really want to specify an
|
||||
<span class="emphasis"><em>absolute</em></span> path on the server, begin the
|
||||
path component with two slashes, as in this example.</p><pre id="id373254" class="programlisting">ssh://server//absolute/path</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id373261">Finding an ssh client for your system</h3></div></div></div><p id="x_493"><a name="x_493"></a>Almost every Unix-like system comes with OpenSSH
|
||||
preinstalled. If you're using such a system, run
|
||||
<code class="literal">which ssh</code> to find out if the
|
||||
<span class="command"><strong>ssh</strong></span> command is installed (it's usually in
|
||||
<code class="filename">/usr/bin</code>). In the
|
||||
unlikely event that it isn't present, take a look at your
|
||||
system documentation to figure out how to install it.</p><p id="x_494"><a name="x_494"></a>On Windows, the TortoiseHg package is bundled
|
||||
with a version of Simon Tatham's excellent
|
||||
<span class="command"><strong>plink</strong></span> command, and you should not need to
|
||||
do any further configuration.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id373312">Generating a key pair</h3></div></div></div><p id="x_499"><a name="x_499"></a>To avoid the need to repetitively type a
|
||||
password every time you need to use your ssh client, I
|
||||
recommend generating a key pair.</p><div class="tip"><table border="0" summary="Tip: Key pairs are not mandatory"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="/support/figs/tip.png"></td><th align="left">Key pairs are not mandatory</th></tr><tr><td align="left" valign="top"><p id="x_6a4"><a name="x_6a4"></a>Mercurial knows nothing about ssh authentication or key
|
||||
pairs. You can, if you like, safely ignore this section and
|
||||
the one that follows until you grow tired of repeatedly
|
||||
typing ssh passwords.</p></td></tr></table></div><div class="itemizedlist"><ul type="disc"><li><p id="x_6a5"><a name="x_6a5"></a>On a Unix-like system, the
|
||||
<span class="command"><strong>ssh-keygen</strong></span> command will do the
|
||||
trick.</p><p id="x_6a6"><a name="x_6a6"></a>On Windows, if you're using TortoiseHg, you may need
|
||||
to download a command named <span class="command"><strong>puttygen</strong></span>
|
||||
from <a class="ulink" href="http://www.chiark.greenend.org.uk/~sgtatham/putty" target="_top">the
|
||||
PuTTY web site</a> to generate a key pair. See
|
||||
<a class="ulink" href="http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter8.html#pubkey-puttygen" target="_top">the
|
||||
<span class="command"><strong>puttygen</strong></span> documentation</a> for
|
||||
details of how use the command.</p></li></ul></div><p id="x_49a"><a name="x_49a"></a>When you generate a key pair, it's usually
|
||||
<span class="emphasis"><em>highly</em></span> advisable to protect it with a
|
||||
passphrase. (The only time that you might not want to do this
|
||||
is when you're using the ssh protocol for automated tasks on a
|
||||
secure network.)</p><p id="x_49b"><a name="x_49b"></a>Simply generating a key pair isn't enough, however.
|
||||
You'll need to add the public key to the set of authorised
|
||||
keys for whatever user you're logging in remotely as. For
|
||||
servers using OpenSSH (the vast majority), this will mean
|
||||
adding the public key to a list in a file called <code class="filename">authorized_keys</code> in their <code class="filename">.ssh</code>
|
||||
directory.</p><p id="x_49c"><a name="x_49c"></a>On a Unix-like system, your public key will have a
|
||||
<code class="filename">.pub</code> extension. If you're using
|
||||
<span class="command"><strong>puttygen</strong></span> on Windows, you can save the
|
||||
public key to a file of your choosing, or paste it from the
|
||||
window it's displayed in straight into the <code class="filename">authorized_keys</code> file.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id373466">Using an authentication agent</h3></div></div></div><p id="x_49d"><a name="x_49d"></a>An authentication agent is a daemon that stores
|
||||
passphrases in memory (so it will forget passphrases if you
|
||||
log out and log back in again). An ssh client will notice if
|
||||
it's running, and query it for a passphrase. If there's no
|
||||
authentication agent running, or the agent doesn't store the
|
||||
necessary passphrase, you'll have to type your passphrase
|
||||
every time Mercurial tries to communicate with a server on
|
||||
your behalf (e.g. whenever you pull or push changes).</p><p id="x_49e"><a name="x_49e"></a>The downside of storing passphrases in an agent is that
|
||||
it's possible for a well-prepared attacker to recover the
|
||||
plain text of your passphrases, in some cases even if your
|
||||
system has been power-cycled. You should make your own
|
||||
judgment as to whether this is an acceptable risk. It
|
||||
certainly saves a lot of repeated typing.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_49f"><a name="x_49f"></a>On Unix-like systems, the agent is called
|
||||
<span class="command"><strong>ssh-agent</strong></span>, and it's often run
|
||||
automatically for you when you log in. You'll need to use
|
||||
the <span class="command"><strong>ssh-add</strong></span> command to add passphrases
|
||||
to the agent's store.</p></li><li><p id="x_6a7"><a name="x_6a7"></a>On Windows, if you're using TortoiseHg, the
|
||||
<span class="command"><strong>pageant</strong></span> command acts as the agent. As
|
||||
with <span class="command"><strong>puttygen</strong></span>, you'll need to <a class="ulink" href="http://www.chiark.greenend.org.uk/%7Esgtatham/putty/download.html" target="_top">download
|
||||
<span class="command"><strong>pageant</strong></span></a> from the PuTTY web
|
||||
site and read <a class="ulink" href="http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter9.html#pageant" target="_top">its
|
||||
documentation</a>. The <span class="command"><strong>pageant</strong></span>
|
||||
command adds an icon to your system tray that will let you
|
||||
manage stored passphrases.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id373568">Configuring the server side properly</h3></div></div></div><p id="x_4a0"><a name="x_4a0"></a>Because ssh can be fiddly to set up if you're new to it,
|
||||
a variety of things can go wrong. Add Mercurial
|
||||
on top, and there's plenty more scope for head-scratching.
|
||||
Most of these potential problems occur on the server side, not
|
||||
the client side. The good news is that once you've gotten a
|
||||
configuration working, it will usually continue to work
|
||||
indefinitely.</p><p id="x_4a1"><a name="x_4a1"></a>Before you try using Mercurial to talk to an ssh server,
|
||||
it's best to make sure that you can use the normal
|
||||
<span class="command"><strong>ssh</strong></span> or <span class="command"><strong>putty</strong></span> command to
|
||||
talk to the server first. If you run into problems with using
|
||||
these commands directly, Mercurial surely won't work. Worse,
|
||||
it will obscure the underlying problem. Any time you want to
|
||||
debug ssh-related Mercurial problems, you should drop back to
|
||||
making sure that plain ssh client commands work first,
|
||||
<span class="emphasis"><em>before</em></span> you worry about whether there's a
|
||||
problem with Mercurial.</p><p id="x_4a2"><a name="x_4a2"></a>The first thing to be sure of on the server side is that
|
||||
you can actually log in from another machine at all. If you
|
||||
can't use <span class="command"><strong>ssh</strong></span> or <span class="command"><strong>putty</strong></span>
|
||||
to log in, the error message you get may give you a few hints
|
||||
as to what's wrong. The most common problems are as
|
||||
follows.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_4a3"><a name="x_4a3"></a>If you get a “<span class="quote">connection refused</span>”
|
||||
error, either there isn't an SSH daemon running on the
|
||||
server at all, or it's inaccessible due to firewall
|
||||
configuration.</p></li><li><p id="x_4a4"><a name="x_4a4"></a>If you get a “<span class="quote">no route to host</span>”
|
||||
error, you either have an incorrect address for the server
|
||||
or a seriously locked down firewall that won't admit its
|
||||
existence at all.</p></li><li><p id="x_4a5"><a name="x_4a5"></a>If you get a “<span class="quote">permission denied</span>”
|
||||
error, you may have mistyped the username on the server,
|
||||
or you could have mistyped your key's passphrase or the
|
||||
remote user's password.</p></li></ul></div><p id="x_4a6"><a name="x_4a6"></a>In summary, if you're having trouble talking to the
|
||||
server's ssh daemon, first make sure that one is running at
|
||||
all. On many systems it will be installed, but disabled, by
|
||||
default. Once you're done with this step, you should then
|
||||
check that the server's firewall is configured to allow
|
||||
incoming connections on the port the ssh daemon is listening
|
||||
on (usually 22). Don't worry about more exotic possibilities
|
||||
for misconfiguration until you've checked these two
|
||||
first.</p><p id="x_4a7"><a name="x_4a7"></a>If you're using an authentication agent on the client side
|
||||
to store passphrases for your keys, you ought to be able to
|
||||
log into the server without being prompted for a passphrase or
|
||||
a password. If you're prompted for a passphrase, there are a
|
||||
few possible culprits.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_4a8"><a name="x_4a8"></a>You might have forgotten to use
|
||||
<span class="command"><strong>ssh-add</strong></span> or <span class="command"><strong>pageant</strong></span>
|
||||
to store the passphrase.</p></li><li><p id="x_4a9"><a name="x_4a9"></a>You might have stored the passphrase for the
|
||||
wrong key.</p></li></ul></div><p id="x_4aa"><a name="x_4aa"></a>If you're being prompted for the remote user's password,
|
||||
there are another few possible problems to check.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_4ab"><a name="x_4ab"></a>Either the user's home directory or their
|
||||
<code class="filename">.ssh</code>
|
||||
directory might have excessively liberal permissions. As
|
||||
a result, the ssh daemon will not trust or read their
|
||||
<code class="filename">authorized_keys</code> file.
|
||||
For example, a group-writable home or <code class="filename">.ssh</code>
|
||||
directory will often cause this symptom.</p></li><li><p id="x_4ac"><a name="x_4ac"></a>The user's <code class="filename">authorized_keys</code> file may have
|
||||
a problem. If anyone other than the user owns or can write
|
||||
to that file, the ssh daemon will not trust or read
|
||||
it.</p></li></ul></div><p id="x_4ad"><a name="x_4ad"></a>In the ideal world, you should be able to run the
|
||||
following command successfully, and it should print exactly
|
||||
one line of output, the current date and time.</p><pre id="id373809" class="programlisting">ssh myserver date</pre><p id="x_4ae"><a name="x_4ae"></a>If, on your server, you have login scripts that print
|
||||
banners or other junk even when running non-interactive
|
||||
commands like this, you should fix them before you continue,
|
||||
so that they only print output if they're run interactively.
|
||||
Otherwise these banners will at least clutter up Mercurial's
|
||||
output. Worse, they could potentially cause problems with
|
||||
running Mercurial commands remotely. Mercurial tries to
|
||||
detect and ignore banners in non-interactive
|
||||
<span class="command"><strong>ssh</strong></span> sessions, but it is not foolproof. (If
|
||||
you're editing your login scripts on your server, the usual
|
||||
way to see if a login script is running in an interactive
|
||||
shell is to check the return code from the command
|
||||
<code class="literal">tty -s</code>.)</p><p id="x_4af"><a name="x_4af"></a>Once you've verified that plain old ssh is working with
|
||||
your server, the next step is to ensure that Mercurial runs on
|
||||
the server. The following command should run
|
||||
successfully:</p><pre id="id373847" class="programlisting">ssh myserver hg version</pre><p id="x_4b0"><a name="x_4b0"></a>If you see an error message instead of normal <span class="command"><strong>hg version</strong></span> output, this is usually
|
||||
because you haven't installed Mercurial to <code class="filename">/usr/bin</code>. Don't worry if this
|
||||
is the case; you don't need to do that. But you should check
|
||||
for a few possible problems.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_4b1"><a name="x_4b1"></a>Is Mercurial really installed on the server at
|
||||
all? I know this sounds trivial, but it's worth
|
||||
checking!</p></li><li><p id="x_4b2"><a name="x_4b2"></a>Maybe your shell's search path (usually set
|
||||
via the <code class="envar">PATH</code> environment variable) is
|
||||
simply misconfigured.</p></li><li><p id="x_4b3"><a name="x_4b3"></a>Perhaps your <code class="envar">PATH</code> environment
|
||||
variable is only being set to point to the location of the
|
||||
<span class="command"><strong>hg</strong></span> executable if the login session is
|
||||
interactive. This can happen if you're setting the path
|
||||
in the wrong shell login script. See your shell's
|
||||
documentation for details.</p></li><li><p id="x_4b4"><a name="x_4b4"></a>The <code class="envar">PYTHONPATH</code> environment
|
||||
variable may need to contain the path to the Mercurial
|
||||
Python modules. It might not be set at all; it could be
|
||||
incorrect; or it may be set only if the login is
|
||||
interactive.</p></li></ul></div><p id="x_4b5"><a name="x_4b5"></a>If you can run <span class="command"><strong>hg version</strong></span>
|
||||
over an ssh connection, well done! You've got the server and
|
||||
client sorted out. You should now be able to use Mercurial to
|
||||
access repositories hosted by that username on that server.
|
||||
If you run into problems with Mercurial and ssh at this point,
|
||||
try using the <code class="option">--debug</code>
|
||||
option to get a clearer picture of what's going on.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id373965">Using compression with ssh</h3></div></div></div><p id="x_4b6"><a name="x_4b6"></a>Mercurial does not compress data when it uses the ssh
|
||||
protocol, because the ssh protocol can transparently compress
|
||||
data. However, the default behavior of ssh clients is
|
||||
<span class="emphasis"><em>not</em></span> to request compression.</p><p id="x_4b7"><a name="x_4b7"></a>Over any network other than a fast LAN (even a wireless
|
||||
network), using compression is likely to significantly speed
|
||||
up Mercurial's network operations. For example, over a WAN,
|
||||
someone measured compression as reducing the amount of time
|
||||
required to clone a particularly large repository from 51
|
||||
minutes to 17 minutes.</p><p id="x_4b8"><a name="x_4b8"></a>Both <span class="command"><strong>ssh</strong></span> and <span class="command"><strong>plink</strong></span>
|
||||
accept a <code class="option">-C</code> option which
|
||||
turns on compression. You can easily edit your <code class="filename">~/.hgrc</code> to enable compression for
|
||||
all of Mercurial's uses of the ssh protocol. Here is how to
|
||||
do so for regular <span class="command"><strong>ssh</strong></span> on Unix-like systems,
|
||||
for example.</p><pre id="id374033" class="programlisting">[ui]
|
||||
ssh = ssh -C</pre><p id="x_4b9"><a name="x_4b9"></a>If you use <span class="command"><strong>ssh</strong></span> on a
|
||||
Unix-like system, you can configure it to always use
|
||||
compression when talking to your server. To do this, edit
|
||||
your <code class="filename">.ssh/config</code> file
|
||||
(which may not yet exist), as follows.</p><pre id="id374061" class="programlisting">Host hg
|
||||
Compression yes
|
||||
HostName hg.example.com</pre><p id="x_4ba"><a name="x_4ba"></a>This defines a hostname alias,
|
||||
<code class="literal">hg</code>. When you use that hostname on the
|
||||
<span class="command"><strong>ssh</strong></span> command line or in a Mercurial
|
||||
<code class="literal">ssh</code>-protocol URL, it will cause
|
||||
<span class="command"><strong>ssh</strong></span> to connect to
|
||||
<code class="literal">hg.example.com</code> and use compression. This
|
||||
gives you both a shorter name to type and compression, each of
|
||||
which is a good thing in its own right.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:collab:cgi">Serving over HTTP using CGI</h2></div></div></div><p id="x_6a8"><a name="x_6a8"></a>The simplest way to host one or more repositories in a
|
||||
permanent way is to use a web server and Mercurial's CGI
|
||||
support.</p><p id="x_4bb"><a name="x_4bb"></a>Depending on how ambitious you are, configuring Mercurial's
|
||||
CGI interface can take anything from a few moments to several
|
||||
hours.</p><p id="x_4bc"><a name="x_4bc"></a>We'll begin with the simplest of examples, and work our way
|
||||
towards a more complex configuration. Even for the most basic
|
||||
case, you're almost certainly going to need to read and modify
|
||||
your web server's configuration.</p><div class="note"><table border="0" summary="Note: High pain tolerance required"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">High pain tolerance required</th></tr><tr><td align="left" valign="top"><p id="x_4bd"><a name="x_4bd"></a>Configuring a web server is a complex, fiddly,
|
||||
and highly system-dependent activity. I can't possibly give
|
||||
you instructions that will cover anything like all of the
|
||||
cases you will encounter. Please use your discretion and
|
||||
judgment in following the sections below. Be prepared to make
|
||||
plenty of mistakes, and to spend a lot of time reading your
|
||||
server's error logs.</p><p id="x_6a9"><a name="x_6a9"></a>If you don't have a strong stomach for tweaking
|
||||
configurations over and over, or a compelling need to host
|
||||
your own services, you might want to try one of the public
|
||||
hosting services that I mentioned earlier.</p></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id374172">Web server configuration checklist</h3></div></div></div><p id="x_4be"><a name="x_4be"></a>Before you continue, do take a few moments to check a few
|
||||
aspects of your system's setup.</p><div class="orderedlist"><ol type="1"><li><p id="x_4bf"><a name="x_4bf"></a>Do you have a web server installed
|
||||
at all? Mac OS X and some Linux distributions ship with
|
||||
Apache, but many other systems may not have a web server
|
||||
installed.</p></li><li><p id="x_4c0"><a name="x_4c0"></a>If you have a web server installed, is it
|
||||
actually running? On most systems, even if one is
|
||||
present, it will be disabled by default.</p></li><li><p id="x_4c1"><a name="x_4c1"></a>Is your server configured to allow you to run
|
||||
CGI programs in the directory where you plan to do so?
|
||||
Most servers default to explicitly disabling the ability
|
||||
to run CGI programs.</p></li></ol></div><p id="x_4c2"><a name="x_4c2"></a>If you don't have a web server installed, and don't have
|
||||
substantial experience configuring Apache, you should consider
|
||||
using the <code class="literal">lighttpd</code> web server instead of
|
||||
Apache. Apache has a well-deserved reputation for baroque and
|
||||
confusing configuration. While <code class="literal">lighttpd</code> is
|
||||
less capable in some ways than Apache, most of these
|
||||
capabilities are not relevant to serving Mercurial
|
||||
repositories. And <code class="literal">lighttpd</code> is undeniably
|
||||
<span class="emphasis"><em>much</em></span> easier to get started with than
|
||||
Apache.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id374257">Basic CGI configuration</h3></div></div></div><p id="x_4c3"><a name="x_4c3"></a>On Unix-like systems, it's common for users to have a
|
||||
subdirectory named something like <code class="filename">public_html</code> in their home
|
||||
directory, from which they can serve up web pages. A file
|
||||
named <code class="filename">foo</code> in this directory will be
|
||||
accessible at a URL of the form
|
||||
<code class="literal">http://www.example.com/username/foo</code>.</p><p id="x_4c4"><a name="x_4c4"></a>To get started, find the <code class="filename">hgweb.cgi</code> script that should be
|
||||
present in your Mercurial installation. If you can't quickly
|
||||
find a local copy on your system, simply download one from the
|
||||
master Mercurial repository at <a class="ulink" href="http://www.selenic.com/repo/hg/raw-file/tip/hgweb.cgi" target="_top">http://www.selenic.com/repo/hg/raw-file/tip/hgweb.cgi</a>.</p><p id="x_4c5"><a name="x_4c5"></a>You'll need to copy this script into your <code class="filename">public_html</code> directory, and
|
||||
ensure that it's executable.</p><pre id="id374331" class="programlisting">cp .../hgweb.cgi ~/public_html
|
||||
chmod 755 ~/public_html/hgweb.cgi</pre><p id="x_4c6"><a name="x_4c6"></a>The <code class="literal">755</code> argument to
|
||||
<span class="command"><strong>chmod</strong></span> is a little more general than just
|
||||
making the script executable: it ensures that the script is
|
||||
executable by anyone, and that “<span class="quote">group</span>” and
|
||||
“<span class="quote">other</span>” write permissions are
|
||||
<span class="emphasis"><em>not</em></span> set. If you were to leave those
|
||||
write permissions enabled, Apache's <code class="literal">suexec</code>
|
||||
subsystem would likely refuse to execute the script. In fact,
|
||||
<code class="literal">suexec</code> also insists that the
|
||||
<span class="emphasis"><em>directory</em></span> in which the script resides
|
||||
must not be writable by others.</p><pre id="id374386" class="programlisting">chmod 755 ~/public_html</pre><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="sec:collab:wtf">What could <span class="emphasis"><em>possibly</em></span> go
|
||||
wrong?</h4></div></div></div><p id="x_4c7"><a name="x_4c7"></a>Once you've copied the CGI script into place,
|
||||
go into a web browser, and try to open the URL
|
||||
<code class="literal">http://myhostname/~myuser/hgweb.cgi</code>,
|
||||
<span class="emphasis"><em>but</em></span> brace yourself for instant failure.
|
||||
There's a high probability that trying to visit this URL
|
||||
will fail, and there are many possible reasons for this. In
|
||||
fact, you're likely to stumble over almost every one of the
|
||||
possible errors below, so please read carefully. The
|
||||
following are all of the problems I ran into on a system
|
||||
running Fedora 7, with a fresh installation of Apache, and a
|
||||
user account that I created specially to perform this
|
||||
exercise.</p><p id="x_4c8"><a name="x_4c8"></a>Your web server may have per-user directories disabled.
|
||||
If you're using Apache, search your config file for a
|
||||
<code class="literal">UserDir</code> directive. If there's none
|
||||
present, per-user directories will be disabled. If one
|
||||
exists, but its value is <code class="literal">disabled</code>, then
|
||||
per-user directories will be disabled. Otherwise, the
|
||||
string after <code class="literal">UserDir</code> gives the name of
|
||||
the subdirectory that Apache will look in under your home
|
||||
directory, for example <code class="filename">public_html</code>.</p><p id="x_4c9"><a name="x_4c9"></a>Your file access permissions may be too restrictive.
|
||||
The web server must be able to traverse your home directory
|
||||
and directories under your <code class="filename">public_html</code> directory, and
|
||||
read files under the latter too. Here's a quick recipe to
|
||||
help you to make your permissions more appropriate.</p><pre id="id374480" class="programlisting">chmod 755 ~
|
||||
find ~/public_html -type d -print0 | xargs -0r chmod 755
|
||||
find ~/public_html -type f -print0 | xargs -0r chmod 644</pre><p id="x_4ca"><a name="x_4ca"></a>The other possibility with permissions is that you might
|
||||
get a completely empty window when you try to load the
|
||||
script. In this case, it's likely that your access
|
||||
permissions are <span class="emphasis"><em>too permissive</em></span>. Apache's
|
||||
<code class="literal">suexec</code> subsystem won't execute a script
|
||||
that's group- or world-writable, for example.</p><p id="x_4cb"><a name="x_4cb"></a>Your web server may be configured to disallow execution
|
||||
of CGI programs in your per-user web directory. Here's
|
||||
Apache's default per-user configuration from my Fedora
|
||||
system.</p><pre id="id374862" class="programlisting"><Directory /home/*/public_html>
|
||||
AllowOverride FileInfo AuthConfig Limit
|
||||
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
|
||||
<Limit GET POST OPTIONS>
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Limit>
|
||||
<LimitExcept GET POST OPTIONS>
|
||||
Order deny,allow Deny from all
|
||||
</LimitExcept>
|
||||
</Directory></pre><p id="x_4cc"><a name="x_4cc"></a>If you find a similar-looking
|
||||
<code class="literal">Directory</code> group in your Apache
|
||||
configuration, the directive to look at inside it is
|
||||
<code class="literal">Options</code>. Add <code class="literal">ExecCGI</code>
|
||||
to the end of this list if it's missing, and restart the web
|
||||
server.</p><p id="x_4cd"><a name="x_4cd"></a>If you find that Apache serves you the text of the CGI
|
||||
script instead of executing it, you may need to either
|
||||
uncomment (if already present) or add a directive like
|
||||
this.</p><pre id="id374571" class="programlisting">AddHandler cgi-script .cgi</pre><p id="x_4ce"><a name="x_4ce"></a>The next possibility is that you might be served with a
|
||||
colourful Python backtrace claiming that it can't import a
|
||||
<code class="literal">mercurial</code>-related module. This is
|
||||
actually progress! The server is now capable of executing
|
||||
your CGI script. This error is only likely to occur if
|
||||
you're running a private installation of Mercurial, instead
|
||||
of a system-wide version. Remember that the web server runs
|
||||
the CGI program without any of the environment variables
|
||||
that you take for granted in an interactive session. If
|
||||
this error happens to you, edit your copy of <code class="filename">hgweb.cgi</code> and follow the
|
||||
directions inside it to correctly set your
|
||||
<code class="envar">PYTHONPATH</code> environment variable.</p><p id="x_4cf"><a name="x_4cf"></a>Finally, you are <span class="emphasis"><em>certain</em></span> to be
|
||||
served with another colourful Python backtrace: this one
|
||||
will complain that it can't find <code class="filename">/path/to/repository</code>. Edit
|
||||
your <code class="filename">hgweb.cgi</code> script
|
||||
and replace the <code class="filename">/path/to/repository</code> string
|
||||
with the complete path to the repository you want to serve
|
||||
up.</p><p id="x_4d0"><a name="x_4d0"></a>At this point, when you try to reload the page, you
|
||||
should be presented with a nice HTML view of your
|
||||
repository's history. Whew!</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id374655">Configuring lighttpd</h4></div></div></div><p id="x_4d1"><a name="x_4d1"></a>To be exhaustive in my experiments, I tried configuring
|
||||
the increasingly popular <code class="literal">lighttpd</code> web
|
||||
server to serve the same repository as I described with
|
||||
Apache above. I had already overcome all of the problems I
|
||||
outlined with Apache, many of which are not server-specific.
|
||||
As a result, I was fairly sure that my file and directory
|
||||
permissions were good, and that my <code class="filename">hgweb.cgi</code> script was properly
|
||||
edited.</p><p id="x_4d2"><a name="x_4d2"></a>Once I had Apache running, getting
|
||||
<code class="literal">lighttpd</code> to serve the repository was a
|
||||
snap (in other words, even if you're trying to use
|
||||
<code class="literal">lighttpd</code>, you should read the Apache
|
||||
section). I first had to edit the
|
||||
<code class="literal">mod_access</code> section of its config file to
|
||||
enable <code class="literal">mod_cgi</code> and
|
||||
<code class="literal">mod_userdir</code>, both of which were disabled
|
||||
by default on my system. I then added a few lines to the
|
||||
end of the config file, to configure these modules.</p><pre id="id374722" class="programlisting">userdir.path = "public_html"
|
||||
cgi.assign = (".cgi" => "" )</pre><p id="x_4d3"><a name="x_4d3"></a>With this done, <code class="literal">lighttpd</code> ran
|
||||
immediately for me. If I had configured
|
||||
<code class="literal">lighttpd</code> before Apache, I'd almost
|
||||
certainly have run into many of the same system-level
|
||||
configuration problems as I did with Apache. However, I
|
||||
found <code class="literal">lighttpd</code> to be noticeably easier to
|
||||
configure than Apache, even though I've used Apache for over
|
||||
a decade, and this was my first exposure to
|
||||
<code class="literal">lighttpd</code>.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id374764">Sharing multiple repositories with one CGI script</h3></div></div></div><p id="x_4d4"><a name="x_4d4"></a>The <code class="filename">hgweb.cgi</code> script
|
||||
only lets you publish a single repository, which is an
|
||||
annoying restriction. If you want to publish more than one
|
||||
without wracking yourself with multiple copies of the same
|
||||
script, each with different names, a better choice is to use
|
||||
the <code class="filename">hgwebdir.cgi</code>
|
||||
script.</p><p id="x_4d5"><a name="x_4d5"></a>The procedure to configure <code class="filename">hgwebdir.cgi</code> is only a little more
|
||||
involved than for <code class="filename">hgweb.cgi</code>. First, you must obtain
|
||||
a copy of the script. If you don't have one handy, you can
|
||||
download a copy from the master Mercurial repository at <a class="ulink" href="http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi" target="_top">http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi</a>.</p><p id="x_4d6"><a name="x_4d6"></a>You'll need to copy this script into your <code class="filename">public_html</code> directory, and
|
||||
ensure that it's executable.</p><pre id="id374844" class="programlisting">cp .../hgwebdir.cgi ~/public_html
|
||||
chmod 755 ~/public_html ~/public_html/hgwebdir.cgi</pre><p id="x_4d7"><a name="x_4d7"></a>With basic configuration out of the way, try to
|
||||
visit <code class="literal">http://myhostname/~myuser/hgwebdir.cgi</code>
|
||||
in your browser. It should
|
||||
display an empty list of repositories. If you get a blank
|
||||
window or error message, try walking through the list of
|
||||
potential problems in <a class="xref" href="collaborating-with-other-people.html#sec:collab:wtf" title="What could possibly go wrong?">the section called “What could possibly go
|
||||
wrong?”</a>.</p><p id="x_4d8"><a name="x_4d8"></a>The <code class="filename">hgwebdir.cgi</code>
|
||||
script relies on an external configuration file. By default,
|
||||
it searches for a file named <code class="filename">hgweb.config</code> in the same directory
|
||||
as itself. You'll need to create this file, and make it
|
||||
world-readable. The format of the file is similar to a
|
||||
Windows “<span class="quote">ini</span>” file, as understood by Python's
|
||||
<code class="literal">ConfigParser</code>
|
||||
[<span class="citation">web:configparser</span>] module.</p><p id="x_4d9"><a name="x_4d9"></a>The easiest way to configure <code class="filename">hgwebdir.cgi</code> is with a section
|
||||
named <code class="literal">collections</code>. This will automatically
|
||||
publish <span class="emphasis"><em>every</em></span> repository under the
|
||||
directories you name. The section should look like
|
||||
this:</p><pre id="id374946" class="programlisting">[collections]
|
||||
/my/root = /my/root</pre><p id="x_4da"><a name="x_4da"></a>Mercurial interprets this by looking at the directory name
|
||||
on the <span class="emphasis"><em>right</em></span> hand side of the
|
||||
“<span class="quote"><code class="literal">=</code></span>” sign; finding repositories
|
||||
in that directory hierarchy; and using the text on the
|
||||
<span class="emphasis"><em>left</em></span> to strip off matching text from the
|
||||
names it will actually list in the web interface. The
|
||||
remaining component of a path after this stripping has
|
||||
occurred is called a “<span class="quote">virtual path</span>”.</p><p id="x_4db"><a name="x_4db"></a>Given the example above, if we have a
|
||||
repository whose local path is <code class="filename">/my/root/this/repo</code>, the CGI
|
||||
script will strip the leading <code class="filename">/my/root</code> from the name, and
|
||||
publish the repository with a virtual path of <code class="filename">this/repo</code>. If the base URL for
|
||||
our CGI script is
|
||||
<code class="literal">http://myhostname/~myuser/hgwebdir.cgi</code>, the
|
||||
complete URL for that repository will be
|
||||
<code class="literal">http://myhostname/~myuser/hgwebdir.cgi/this/repo</code>.</p><p id="x_4dc"><a name="x_4dc"></a>If we replace <code class="filename">/my/root</code> on the left hand side
|
||||
of this example with <code class="filename">/my</code>, then <code class="filename">hgwebdir.cgi</code> will only strip off
|
||||
<code class="filename">/my</code> from the repository
|
||||
name, and will give us a virtual path of <code class="filename">root/this/repo</code> instead of
|
||||
<code class="filename">this/repo</code>.</p><p id="x_4dd"><a name="x_4dd"></a>The <code class="filename">hgwebdir.cgi</code>
|
||||
script will recursively search each directory listed in the
|
||||
<code class="literal">collections</code> section of its configuration
|
||||
file, but it will <code class="literal">not</code> recurse into the
|
||||
repositories it finds.</p><p id="x_4de"><a name="x_4de"></a>The <code class="literal">collections</code> mechanism makes it easy
|
||||
to publish many repositories in a “<span class="quote">fire and
|
||||
forget</span>” manner. You only need to set up the CGI
|
||||
script and configuration file one time. Afterwards, you can
|
||||
publish or unpublish a repository at any time by simply moving
|
||||
it into, or out of, the directory hierarchy in which you've
|
||||
configured <code class="filename">hgwebdir.cgi</code> to
|
||||
look.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id375138">Explicitly specifying which repositories to
|
||||
publish</h4></div></div></div><p id="x_4df"><a name="x_4df"></a>In addition to the <code class="literal">collections</code>
|
||||
mechanism, the <code class="filename">hgwebdir.cgi</code> script allows you
|
||||
to publish a specific list of repositories. To do so,
|
||||
create a <code class="literal">paths</code> section, with contents of
|
||||
the following form.</p><pre id="id375172" class="programlisting">[paths]
|
||||
repo1 = /my/path/to/some/repo
|
||||
repo2 = /some/path/to/another</pre><p id="x_4e0"><a name="x_4e0"></a>In this case, the virtual path (the component that will
|
||||
appear in a URL) is on the left hand side of each
|
||||
definition, while the path to the repository is on the
|
||||
right. Notice that there does not need to be any
|
||||
relationship between the virtual path you choose and the
|
||||
location of a repository in your filesystem.</p><p id="x_4e1"><a name="x_4e1"></a>If you wish, you can use both the
|
||||
<code class="literal">collections</code> and <code class="literal">paths</code>
|
||||
mechanisms simultaneously in a single configuration
|
||||
file.</p><div class="note"><table border="0" summary="Note: Beware duplicate virtual paths"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Beware duplicate virtual paths</th></tr><tr><td align="left" valign="top"><p id="x_4e2"><a name="x_4e2"></a> If several repositories have the same
|
||||
virtual path, <code class="filename">hgwebdir.cgi</code> will not report
|
||||
an error. Instead, it will behave unpredictably.</p></td></tr></table></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id375233">Downloading source archives</h3></div></div></div><p id="x_4e3"><a name="x_4e3"></a>Mercurial's web interface lets users download an archive
|
||||
of any revision. This archive will contain a snapshot of the
|
||||
working directory as of that revision, but it will not contain
|
||||
a copy of the repository data.</p><p id="x_4e4"><a name="x_4e4"></a>By default, this feature is not enabled. To enable it,
|
||||
you'll need to add an <code class="envar">allow_archive</code> item to the
|
||||
<code class="literal">web</code> section of your <code class="filename">~/.hgrc</code>; see below for details.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id375279">Web configuration options</h3></div></div></div><p id="x_4e5"><a name="x_4e5"></a>Mercurial's web interfaces (the <span class="command"><strong>hg
|
||||
serve</strong></span> command, and the <code class="filename">hgweb.cgi</code> and <code class="filename">hgwebdir.cgi</code> scripts) have a
|
||||
number of configuration options that you can set. These
|
||||
belong in a section named <code class="literal">web</code>.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_4e6"><a name="x_4e6"></a><code class="envar">allow_archive</code>: Determines
|
||||
which (if any) archive download mechanisms Mercurial
|
||||
supports. If you enable this feature, users of the web
|
||||
interface will be able to download an archive of whatever
|
||||
revision of a repository they are viewing. To enable the
|
||||
archive feature, this item must take the form of a
|
||||
sequence of words drawn from the list below.</p><div class="itemizedlist"><ul type="circle"><li><p id="x_4e7"><a name="x_4e7"></a><code class="literal">bz2</code>: A
|
||||
<span class="command"><strong>tar</strong></span> archive, compressed using
|
||||
<code class="literal">bzip2</code> compression. This has the
|
||||
best compression ratio, but uses the most CPU time on
|
||||
the server.</p></li><li><p id="x_4e8"><a name="x_4e8"></a><code class="literal">gz</code>: A
|
||||
<span class="command"><strong>tar</strong></span> archive, compressed using
|
||||
<code class="literal">gzip</code> compression.</p></li><li><p id="x_4e9"><a name="x_4e9"></a><code class="literal">zip</code>: A
|
||||
<span class="command"><strong>zip</strong></span> archive, compressed using LZW
|
||||
compression. This format has the worst compression
|
||||
ratio, but is widely used in the Windows world.</p></li></ul></div><p id="x_4ea"><a name="x_4ea"></a> If you provide an empty list, or don't have an
|
||||
<code class="envar">allow_archive</code> entry at
|
||||
all, this feature will be disabled. Here is an example of
|
||||
how to enable all three supported formats.</p><pre id="id375435" class="programlisting">[web]
|
||||
allow_archive = bz2 gz zip</pre></li><li><p id="x_4eb"><a name="x_4eb"></a><code class="envar">allowpull</code>:
|
||||
Boolean. Determines whether the web interface allows
|
||||
remote users to <span class="command"><strong>hg pull</strong></span>
|
||||
and <span class="command"><strong>hg clone</strong></span> this
|
||||
repository over HTTP. If set to <code class="literal">no</code> or
|
||||
<code class="literal">false</code>, only the
|
||||
“<span class="quote">human-oriented</span>” portion of the web interface
|
||||
is available.</p></li><li><p id="x_4ec"><a name="x_4ec"></a><code class="envar">contact</code>:
|
||||
String. A free-form (but preferably brief) string
|
||||
identifying the person or group in charge of the
|
||||
repository. This often contains the name and email
|
||||
address of a person or mailing list. It often makes sense
|
||||
to place this entry in a repository's own <code class="filename">.hg/hgrc</code> file, but it can make
|
||||
sense to use in a global <code class="filename">~/.hgrc</code> if every repository
|
||||
has a single maintainer.</p></li><li><p id="x_4ed"><a name="x_4ed"></a><code class="envar">maxchanges</code>:
|
||||
Integer. The default maximum number of changesets to
|
||||
display in a single page of output.</p></li><li><p id="x_4ee"><a name="x_4ee"></a><code class="envar">maxfiles</code>:
|
||||
Integer. The default maximum number of modified files to
|
||||
display in a single page of output.</p></li><li><p id="x_4ef"><a name="x_4ef"></a><code class="envar">stripes</code>:
|
||||
Integer. If the web interface displays alternating
|
||||
“<span class="quote">stripes</span>” to make it easier to visually align
|
||||
rows when you are looking at a table, this number controls
|
||||
the number of rows in each stripe.</p></li><li><p id="x_4f0"><a name="x_4f0"></a><code class="envar">style</code>: Controls the template
|
||||
Mercurial uses to display the web interface. Mercurial
|
||||
ships with several web templates.</p><div class="itemizedlist"><ul type="circle"><li><p id="x_6aa"><a name="x_6aa"></a><code class="literal">coal</code> is monochromatic.</p></li><li><p id="x_6ab"><a name="x_6ab"></a><code class="literal">gitweb</code> emulates the visual
|
||||
style of git's web interface.</p></li><li><p id="x_6ac"><a name="x_6ac"></a><code class="literal">monoblue</code> uses solid blues and
|
||||
greys.</p></li><li><p id="x_6ad"><a name="x_6ad"></a><code class="literal">paper</code> is the default.</p></li><li><p id="x_6ae"><a name="x_6ae"></a><code class="literal">spartan</code> was the default for a
|
||||
long time.</p></li></ul></div><p id="x_6af"><a name="x_6af"></a>You can
|
||||
also specify a custom template of your own; see
|
||||
<a class="xref" href="customizing-the-output-of-mercurial.html" title="Chapter 11. Customizing the output of Mercurial">Chapter 11, <i>Customizing the output of Mercurial</i></a> for details. Here, you can
|
||||
see how to enable the <code class="literal">gitweb</code>
|
||||
style.</p><pre id="id375687" class="programlisting">[web]
|
||||
style = gitweb</pre></li><li><p id="x_4f1"><a name="x_4f1"></a><code class="envar">templates</code>:
|
||||
Path. The directory in which to search for template
|
||||
files. By default, Mercurial searches in the directory in
|
||||
which it was installed.</p></li></ul></div><p id="x_4f2"><a name="x_4f2"></a>If you are using <code class="filename">hgwebdir.cgi</code>, you can place a few
|
||||
configuration items in a <code class="literal">web</code>
|
||||
section of the <code class="filename">hgweb.config</code> file instead of a
|
||||
<code class="filename">~/.hgrc</code> file, for
|
||||
convenience. These items are <code class="envar">motd</code> and <code class="envar">style</code>.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id375762">Options specific to an individual repository</h4></div></div></div><p id="x_4f3"><a name="x_4f3"></a>A few <code class="literal">web</code> configuration
|
||||
items ought to be placed in a repository's local <code class="filename">.hg/hgrc</code>, rather than a user's
|
||||
or global <code class="filename">~/.hgrc</code>.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_4f4"><a name="x_4f4"></a><code class="envar">description</code>: String. A
|
||||
free-form (but preferably brief) string that describes
|
||||
the contents or purpose of the repository.</p></li><li><p id="x_4f5"><a name="x_4f5"></a><code class="envar">name</code>:
|
||||
String. The name to use for the repository in the web
|
||||
interface. This overrides the default name, which is
|
||||
the last component of the repository's path.</p></li></ul></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id375833">Options specific to the <span class="command"><strong>hg
|
||||
serve</strong></span> command</h4></div></div></div><p id="x_4f6"><a name="x_4f6"></a>Some of the items in the <code class="literal">web</code> section of a <code class="filename">~/.hgrc</code> file are only for use
|
||||
with the <span class="command"><strong>hg serve</strong></span>
|
||||
command.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_4f7"><a name="x_4f7"></a><code class="envar">accesslog</code>:
|
||||
Path. The name of a file into which to write an access
|
||||
log. By default, the <span class="command"><strong>hg
|
||||
serve</strong></span> command writes this information to
|
||||
standard output, not to a file. Log entries are written
|
||||
in the standard “<span class="quote">combined</span>” file format used
|
||||
by almost all web servers.</p></li><li><p id="x_4f8"><a name="x_4f8"></a><code class="envar">address</code>:
|
||||
String. The local address on which the server should
|
||||
listen for incoming connections. By default, the server
|
||||
listens on all addresses.</p></li><li><p id="x_4f9"><a name="x_4f9"></a><code class="envar">errorlog</code>:
|
||||
Path. The name of a file into which to write an error
|
||||
log. By default, the <span class="command"><strong>hg
|
||||
serve</strong></span> command writes this information to
|
||||
standard error, not to a file.</p></li><li><p id="x_4fa"><a name="x_4fa"></a><code class="envar">ipv6</code>:
|
||||
Boolean. Whether to use the IPv6 protocol. By default,
|
||||
IPv6 is not used.</p></li><li><p id="x_4fb"><a name="x_4fb"></a><code class="envar">port</code>:
|
||||
Integer. The TCP port number on which the server should
|
||||
listen. The default port number used is 8000.</p></li></ul></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id375978">Choosing the right <code class="filename">~/.hgrc</code> file to add <code class="literal">web</code> items to</h4></div></div></div><p id="x_4fc"><a name="x_4fc"></a>It is important to remember that a web server like
|
||||
Apache or <code class="literal">lighttpd</code> will run under a user
|
||||
ID that is different to yours. CGI scripts run by your
|
||||
server, such as <code class="filename">hgweb.cgi</code>, will usually also run
|
||||
under that user ID.</p><p id="x_4fd"><a name="x_4fd"></a>If you add <code class="literal">web</code> items to
|
||||
your own personal <code class="filename">~/.hgrc</code> file, CGI scripts won't read that
|
||||
<code class="filename">~/.hgrc</code> file. Those
|
||||
settings will thus only affect the behavior of the <span class="command"><strong>hg serve</strong></span> command when you run it.
|
||||
To cause CGI scripts to see your settings, either create a
|
||||
<code class="filename">~/.hgrc</code> file in the
|
||||
home directory of the user ID that runs your web server, or
|
||||
add those settings to a system-wide <code class="filename">hgrc</code> file.</p></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id376085">System-wide configuration</h2></div></div></div><p id="x_6b0"><a name="x_6b0"></a>On Unix-like systems shared by multiple users (such as a
|
||||
server to which people publish changes), it often makes sense to
|
||||
set up some global default behaviors, such as what theme to use
|
||||
in web interfaces.</p><p id="x_6b1"><a name="x_6b1"></a>If a file named <code class="filename">/etc/mercurial/hgrc</code>
|
||||
exists, Mercurial will read it at startup time and apply any
|
||||
configuration settings it finds in that file. It will also look
|
||||
for files ending in a <code class="literal">.rc</code> extension in a
|
||||
directory named <code class="filename">/etc/mercurial/hgrc.d</code>, and
|
||||
apply any configuration settings it finds in each of those
|
||||
files.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id376128">Making Mercurial more trusting</h3></div></div></div><p id="x_6b2"><a name="x_6b2"></a>One situation in which a global <code class="filename">hgrc</code>
|
||||
can be useful is if users are pulling changes owned by other
|
||||
users. By default, Mercurial will not trust most of the
|
||||
configuration items in a <code class="filename">.hg/hgrc</code> file
|
||||
inside a repository that is owned by a different user. If we
|
||||
clone or pull changes from such a repository, Mercurial will
|
||||
print a warning stating that it does not trust their
|
||||
<code class="filename">.hg/hgrc</code>.</p><p id="x_6b3"><a name="x_6b3"></a>If everyone in a particular Unix group is on the same team
|
||||
and <span class="emphasis"><em>should</em></span> trust each other's
|
||||
configuration settings, or we want to trust particular users,
|
||||
we can override Mercurial's skeptical defaults by creating a
|
||||
system-wide <code class="filename">hgrc</code> file such as the
|
||||
following:</p><pre id="id376179" class="programlisting"># Save this as e.g. /etc/mercurial/hgrc.d/trust.rc
|
||||
[trusted]
|
||||
# Trust all entries in any hgrc file owned by the "editors" or
|
||||
# "www-data" groups.
|
||||
groups = editors, www-data
|
||||
|
||||
# Trust entries in hgrc files owned by the following users.
|
||||
users = apache, bobo
|
||||
</pre></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="mercurial-in-daily-use.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="file-names-and-pattern-matching.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 5. Mercurial in daily use </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 7. File names and pattern matching</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
490
read/customizing-the-output-of-mercurial.html
Normal file
490
read/customizing-the-output-of-mercurial.html
Normal file
|
@ -0,0 +1,490 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 11. Customizing the output of Mercurial</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="handling-repository-events-with-hooks.html" title="Chapter 10. Handling repository events with hooks"><link rel="next" href="managing-change-with-mercurial-queues.html" title="Chapter 12. Managing change with Mercurial Queues"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 11. Customizing the output of Mercurial</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="handling-repository-events-with-hooks.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="managing-change-with-mercurial-queues.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:template"><div class="titlepage"><div><div><h2 class="title">Chapter 11. Customizing the output of Mercurial</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="customizing-the-output-of-mercurial.html#sec:style">Using precanned output styles</a></span></dt><dd><dl><dt><span class="sect2"><a href="customizing-the-output-of-mercurial.html#id414837">Setting a default style</a></span></dt></dl></dd><dt><span class="sect1"><a href="customizing-the-output-of-mercurial.html#id414882">Commands that support styles and templates</a></span></dt><dt><span class="sect1"><a href="customizing-the-output-of-mercurial.html#id414947">The basics of templating</a></span></dt><dt><span class="sect1"><a href="customizing-the-output-of-mercurial.html#sec:template:keyword">Common template keywords</a></span></dt><dt><span class="sect1"><a href="customizing-the-output-of-mercurial.html#sec:template:escape">Escape sequences</a></span></dt><dt><span class="sect1"><a href="customizing-the-output-of-mercurial.html#sec:template:filter">Filtering keywords to change their results</a></span></dt><dd><dl><dt><span class="sect2"><a href="customizing-the-output-of-mercurial.html#id417290">Combining filters</a></span></dt></dl></dd><dt><span class="sect1"><a href="customizing-the-output-of-mercurial.html#id417618">From templates to styles</a></span></dt><dd><dl><dt><span class="sect2"><a href="customizing-the-output-of-mercurial.html#id417353">The simplest of style files</a></span></dt><dt><span class="sect2"><a href="customizing-the-output-of-mercurial.html#id417428">Style file syntax</a></span></dt></dl></dd><dt><span class="sect1"><a href="customizing-the-output-of-mercurial.html#id417656">Style files by example</a></span></dt><dd><dl><dt><span class="sect2"><a href="customizing-the-output-of-mercurial.html#id417669">Identifying mistakes in style files</a></span></dt><dt><span class="sect2"><a href="customizing-the-output-of-mercurial.html#id417853">Uniquely identifying a repository</a></span></dt><dt><span class="sect2"><a href="customizing-the-output-of-mercurial.html#id417978">Listing files on multiple lines</a></span></dt><dt><span class="sect2"><a href="customizing-the-output-of-mercurial.html#id418118">Mimicking Subversion's output</a></span></dt></dl></dd></dl></div><p id="x_578"><a name="x_578"></a>Mercurial provides a powerful mechanism to let you control how
|
||||
it displays information. The mechanism is based on templates.
|
||||
You can use templates to generate specific output for a single
|
||||
command, or to customize the entire appearance of the built-in web
|
||||
interface.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:style">Using precanned output styles</h2></div></div></div><p id="x_579"><a name="x_579"></a>Packaged with Mercurial are some output styles that you can
|
||||
use immediately. A style is simply a precanned template that
|
||||
someone wrote and installed somewhere that Mercurial can
|
||||
find.</p><p id="x_57a"><a name="x_57a"></a>Before we take a look at Mercurial's bundled styles, let's
|
||||
review its normal output.</p><pre id="id415040" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r1</code></strong>
|
||||
changeset: 1:107e439be01c
|
||||
tag: mytag
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:46 2009 +0000
|
||||
summary: added line to end of <<hello>> file.
|
||||
|
||||
</pre><p id="x_57b"><a name="x_57b"></a>This is somewhat informative, but it takes up a lot of
|
||||
space—five lines of output per changeset. The
|
||||
<code class="literal">compact</code> style reduces this to three lines,
|
||||
presented in a sparse manner.</p><pre id="id415023" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log --style compact</code></strong>
|
||||
3[tip] 65efccbd2729 2009-05-05 06:55 +0000 bos
|
||||
Added tag v0.1 for changeset 59abc8be7140
|
||||
|
||||
2[v0.1] 59abc8be7140 2009-05-05 06:55 +0000 bos
|
||||
Added tag mytag for changeset 107e439be01c
|
||||
|
||||
1[mytag] 107e439be01c 2009-05-05 06:55 +0000 bos
|
||||
added line to end of <<hello>> file.
|
||||
|
||||
0 5ce2a492c569 2009-05-05 06:55 +0000 bos
|
||||
added hello
|
||||
|
||||
</pre><p id="x_57c"><a name="x_57c"></a>The <code class="literal">changelog</code> style hints at the
|
||||
expressive power of Mercurial's templating engine. This style
|
||||
attempts to follow the GNU Project's changelog
|
||||
guidelines[<span class="citation">web:changelog</span>].</p><pre id="id414997" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log --style changelog</code></strong>
|
||||
2009-05-05 Bryan O'Sullivan <bos@serpentine.com>
|
||||
|
||||
* .hgtags:
|
||||
Added tag v0.1 for changeset 59abc8be7140
|
||||
[65efccbd2729] [tip]
|
||||
|
||||
* .hgtags:
|
||||
Added tag mytag for changeset 107e439be01c
|
||||
[59abc8be7140] [v0.1]
|
||||
|
||||
* goodbye, hello:
|
||||
added line to end of <<hello>> file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope
|
||||
that some might consider it so) of goodbye.
|
||||
[107e439be01c] [mytag]
|
||||
|
||||
* hello:
|
||||
added hello
|
||||
[5ce2a492c569]
|
||||
|
||||
</pre><p id="x_57d"><a name="x_57d"></a>You will not be shocked to learn that Mercurial's default
|
||||
output style is named <code class="literal">default</code>.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id414837">Setting a default style</h3></div></div></div><p id="x_57e"><a name="x_57e"></a>You can modify the output style that Mercurial will use
|
||||
for every command by editing your <code class="filename">~/.hgrc</code> file, naming the style
|
||||
you would prefer to use.</p><pre id="id414859" class="programlisting">[ui]
|
||||
style = compact</pre><p id="x_57f"><a name="x_57f"></a>If you write a style of your own, you can use it by either
|
||||
providing the path to your style file, or copying your style
|
||||
file into a location where Mercurial can find it (typically
|
||||
the <code class="literal">templates</code> subdirectory of your
|
||||
Mercurial install directory).</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id414882">Commands that support styles and templates</h2></div></div></div><p id="x_580"><a name="x_580"></a>All of Mercurial's
|
||||
“<span class="quote"><code class="literal">log</code>-like</span>” commands let you use
|
||||
styles and templates: <span class="command"><strong>hg
|
||||
incoming</strong></span>, <span class="command"><strong>hg log</strong></span>,
|
||||
<span class="command"><strong>hg outgoing</strong></span>, and <span class="command"><strong>hg tip</strong></span>.</p><p id="x_581"><a name="x_581"></a>As I write this manual, these are so far the only commands
|
||||
that support styles and templates. Since these are the most
|
||||
important commands that need customizable output, there has been
|
||||
little pressure from the Mercurial user community to add style
|
||||
and template support to other commands.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id414947">The basics of templating</h2></div></div></div><p id="x_582"><a name="x_582"></a>At its simplest, a Mercurial template is a piece of text.
|
||||
Some of the text never changes, while other parts are
|
||||
<span class="emphasis"><em>expanded</em></span>, or replaced with new text, when
|
||||
necessary.</p><p id="x_583"><a name="x_583"></a>Before we continue, let's look again at a simple example of
|
||||
Mercurial's normal output.</p><pre id="id415038" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r1</code></strong>
|
||||
changeset: 1:107e439be01c
|
||||
tag: mytag
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:46 2009 +0000
|
||||
summary: added line to end of <<hello>> file.
|
||||
|
||||
</pre><p id="x_584"><a name="x_584"></a>Now, let's run the same command, but using a template to
|
||||
change its output.</p><pre id="id415404" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'i saw a changeset\n'</code></strong>
|
||||
i saw a changeset
|
||||
</pre><p id="x_585"><a name="x_585"></a>The example above illustrates the simplest possible
|
||||
template; it's just a piece of static text, printed once for
|
||||
each changeset. The <code class="option">--template</code> option to the <span class="command"><strong>hg log</strong></span> command tells Mercurial to use
|
||||
the given text as the template when printing each
|
||||
changeset.</p><p id="x_586"><a name="x_586"></a>Notice that the template string above ends with the text
|
||||
“<span class="quote"><code class="literal">\n</code></span>”. This is an
|
||||
<span class="emphasis"><em>escape sequence</em></span>, telling Mercurial to print
|
||||
a newline at the end of each template item. If you omit this
|
||||
newline, Mercurial will run each piece of output together. See
|
||||
<a class="xref" href="customizing-the-output-of-mercurial.html#sec:template:escape" title="Escape sequences">the section called “Escape sequences”</a> for more details
|
||||
of escape sequences.</p><p id="x_587"><a name="x_587"></a>A template that prints a fixed string of text all the time
|
||||
isn't very useful; let's try something a bit more
|
||||
complex.</p><pre id="id415110" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log --template 'i saw a changeset: {desc}\n'</code></strong>
|
||||
i saw a changeset: Added tag v0.1 for changeset 59abc8be7140
|
||||
i saw a changeset: Added tag mytag for changeset 107e439be01c
|
||||
i saw a changeset: added line to end of <<hello>> file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.
|
||||
i saw a changeset: added hello
|
||||
</pre><p id="x_588"><a name="x_588"></a>As you can see, the string
|
||||
“<span class="quote"><code class="literal">{desc}</code></span>” in the template has
|
||||
been replaced in the output with the description of each
|
||||
changeset. Every time Mercurial finds text enclosed in curly
|
||||
braces (“<span class="quote"><code class="literal">{</code></span>” and
|
||||
“<span class="quote"><code class="literal">}</code></span>”), it will try to replace the
|
||||
braces and text with the expansion of whatever is inside. To
|
||||
print a literal curly brace, you must escape it, as described in
|
||||
<a class="xref" href="customizing-the-output-of-mercurial.html#sec:template:escape" title="Escape sequences">the section called “Escape sequences”</a>.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:template:keyword">Common template keywords</h2></div></div></div><p id="x_589"><a name="x_589"></a>You can start writing simple templates immediately using the
|
||||
keywords below.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_58a"><a name="x_58a"></a><code class="literal">author</code>: String. The
|
||||
unmodified author of the changeset.</p></li><li><p id="x_58b"><a name="x_58b"></a><code class="literal">branches</code>: String. The
|
||||
name of the branch on which the changeset was committed.
|
||||
Will be empty if the branch name was
|
||||
<code class="literal">default</code>.</p></li><li><p id="x_58c"><a name="x_58c"></a><code class="literal">date</code>:
|
||||
Date information. The date when the changeset was
|
||||
committed. This is <span class="emphasis"><em>not</em></span> human-readable;
|
||||
you must pass it through a filter that will render it
|
||||
appropriately. See <a class="xref" href="customizing-the-output-of-mercurial.html#sec:template:filter" title="Filtering keywords to change their results">the section called “Filtering keywords to change their results”</a> for more information
|
||||
on filters. The date is expressed as a pair of numbers. The
|
||||
first number is a Unix UTC timestamp (seconds since January
|
||||
1, 1970); the second is the offset of the committer's
|
||||
timezone from UTC, in seconds.</p></li><li><p id="x_58d"><a name="x_58d"></a><code class="literal">desc</code>:
|
||||
String. The text of the changeset description.</p></li><li><p id="x_58e"><a name="x_58e"></a><code class="literal">files</code>: List of strings.
|
||||
All files modified, added, or removed by this
|
||||
changeset.</p></li><li><p id="x_58f"><a name="x_58f"></a><code class="literal">file_adds</code>: List of
|
||||
strings. Files added by this changeset.</p></li><li><p id="x_590"><a name="x_590"></a><code class="literal">file_dels</code>: List of
|
||||
strings. Files removed by this changeset.</p></li><li><p id="x_591"><a name="x_591"></a><code class="literal">node</code>:
|
||||
String. The changeset identification hash, as a
|
||||
40-character hexadecimal string.</p></li><li><p id="x_592"><a name="x_592"></a><code class="literal">parents</code>: List of
|
||||
strings. The parents of the changeset.</p></li><li><p id="x_593"><a name="x_593"></a><code class="literal">rev</code>:
|
||||
Integer. The repository-local changeset revision
|
||||
number.</p></li><li><p id="x_594"><a name="x_594"></a><code class="literal">tags</code>:
|
||||
List of strings. Any tags associated with the
|
||||
changeset.</p></li></ul></div><p id="x_595"><a name="x_595"></a>A few simple experiments will show us what to expect when we
|
||||
use these keywords; you can see the results below.</p><pre id="id415826" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'author: {author}\n'</code></strong>
|
||||
author: Bryan O'Sullivan <bos@serpentine.com>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'desc:\n{desc}\n'</code></strong>
|
||||
desc:
|
||||
added line to end of <<hello>> file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'files: {files}\n'</code></strong>
|
||||
files: goodbye hello
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'file_adds: {file_adds}\n'</code></strong>
|
||||
file_adds: goodbye
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'file_dels: {file_dels}\n'</code></strong>
|
||||
file_dels:
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'node: {node}\n'</code></strong>
|
||||
node: 107e439be01c456e8e32f719558cb7ea693b60fd
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'parents: {parents}\n'</code></strong>
|
||||
parents:
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'rev: {rev}\n'</code></strong>
|
||||
rev: 1
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'tags: {tags}\n'</code></strong>
|
||||
tags: mytag
|
||||
</pre><p id="x_596"><a name="x_596"></a>As we noted above, the date keyword does not produce
|
||||
human-readable output, so we must treat it specially. This
|
||||
involves using a <span class="emphasis"><em>filter</em></span>, about which more
|
||||
in <a class="xref" href="customizing-the-output-of-mercurial.html#sec:template:filter" title="Filtering keywords to change their results">the section called “Filtering keywords to change their results”</a>.</p><pre id="id415717" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'date: {date}\n'</code></strong>
|
||||
date: 1241506546.00
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'date: {date|isodate}\n'</code></strong>
|
||||
date: 2009-05-05 06:55 +0000
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:template:escape">Escape sequences</h2></div></div></div><p id="x_597"><a name="x_597"></a>Mercurial's templating engine recognises the most commonly
|
||||
used escape sequences in strings. When it sees a backslash
|
||||
(“<span class="quote"><code class="literal">\</code></span>”) character, it looks at the
|
||||
following character and substitutes the two characters with a
|
||||
single replacement, as described below.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_598"><a name="x_598"></a><code class="literal">\</code>:
|
||||
Backslash, “<span class="quote"><code class="literal">\</code></span>”, ASCII
|
||||
134.</p></li><li><p id="x_599"><a name="x_599"></a><code class="literal">\n</code>: Newline,
|
||||
ASCII 12.</p></li><li><p id="x_59a"><a name="x_59a"></a><code class="literal">\r</code>: Carriage
|
||||
return, ASCII 15.</p></li><li><p id="x_59b"><a name="x_59b"></a><code class="literal">\t</code>: Tab, ASCII
|
||||
11.</p></li><li><p id="x_59c"><a name="x_59c"></a><code class="literal">\v</code>: Vertical
|
||||
tab, ASCII 13.</p></li><li><p id="x_59d"><a name="x_59d"></a><code class="literal">\{</code>: Open curly
|
||||
brace, “<span class="quote"><code class="literal">{</code></span>”, ASCII
|
||||
173.</p></li><li><p id="x_59e"><a name="x_59e"></a><code class="literal">\}</code>: Close curly
|
||||
brace, “<span class="quote"><code class="literal">}</code></span>”, ASCII
|
||||
175.</p></li></ul></div><p id="x_59f"><a name="x_59f"></a>As indicated above, if you want the expansion of a template
|
||||
to contain a literal “<span class="quote"><code class="literal">\</code></span>”,
|
||||
“<span class="quote"><code class="literal">{</code></span>”, or
|
||||
“<span class="quote"><code class="literal">{</code></span>” character, you must escape
|
||||
it.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:template:filter">Filtering keywords to change their results</h2></div></div></div><p id="x_5a0"><a name="x_5a0"></a>Some of the results of template expansion are not
|
||||
immediately easy to use. Mercurial lets you specify an optional
|
||||
chain of <span class="emphasis"><em>filters</em></span> to modify the result of
|
||||
expanding a keyword. You have already seen a common filter,
|
||||
<code class="literal">isodate</code>, in
|
||||
action above, to make a date readable.</p><p id="x_5a1"><a name="x_5a1"></a>Below is a list of the most commonly used filters that
|
||||
Mercurial supports. While some filters can be applied to any
|
||||
text, others can only be used in specific circumstances. The
|
||||
name of each filter is followed first by an indication of where
|
||||
it can be used, then a description of its effect.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_5a2"><a name="x_5a2"></a><code class="literal">addbreaks</code>: Any text. Add
|
||||
an XHTML “<span class="quote"><code class="literal"><br/></code></span>” tag
|
||||
before the end of every line except the last. For example,
|
||||
“<span class="quote"><code class="literal">foo\nbar</code></span>” becomes
|
||||
“<span class="quote"><code class="literal">foo<br/>\nbar</code></span>”.</p></li><li><p id="x_5a3"><a name="x_5a3"></a><code class="literal">age</code>: <code class="literal">date</code> keyword. Render
|
||||
the age of the date, relative to the current time. Yields a
|
||||
string like “<span class="quote"><code class="literal">10
|
||||
minutes</code></span>”.</p></li><li><p id="x_5a4"><a name="x_5a4"></a><code class="literal">basename</code>: Any text, but
|
||||
most useful for the <code class="literal">files</code> keyword and its
|
||||
relatives. Treat the text as a path, and return the
|
||||
basename. For example,
|
||||
“<span class="quote"><code class="literal">foo/bar/baz</code></span>” becomes
|
||||
“<span class="quote"><code class="literal">baz</code></span>”.</p></li><li><p id="x_5a5"><a name="x_5a5"></a><code class="literal">date</code>: <code class="literal">date</code> keyword. Render a
|
||||
date in a similar format to the Unix <code class="literal">date</code> command, but with
|
||||
timezone included. Yields a string like “<span class="quote"><code class="literal">Mon
|
||||
Sep 04 15:13:13 2006 -0700</code></span>”.</p></li><li><p id="x_5a6"><a name="x_5a6"></a><code class="literal">domain</code>: Any text,
|
||||
but most useful for the <code class="literal">author</code> keyword. Finds
|
||||
the first string that looks like an email address, and
|
||||
extract just the domain component. For example,
|
||||
“<span class="quote"><code class="literal">Bryan O'Sullivan
|
||||
<bos@serpentine.com></code></span>” becomes
|
||||
“<span class="quote"><code class="literal">serpentine.com</code></span>”.</p></li><li><p id="x_5a7"><a name="x_5a7"></a><code class="literal">email</code>: Any text,
|
||||
but most useful for the <code class="literal">author</code> keyword. Extract
|
||||
the first string that looks like an email address. For
|
||||
example, “<span class="quote"><code class="literal">Bryan O'Sullivan
|
||||
<bos@serpentine.com></code></span>” becomes
|
||||
“<span class="quote"><code class="literal">bos@serpentine.com</code></span>”.</p></li><li><p id="x_5a8"><a name="x_5a8"></a><code class="literal">escape</code>: Any text.
|
||||
Replace the special XML/XHTML characters
|
||||
“<span class="quote"><code class="literal">&</code></span>”,
|
||||
“<span class="quote"><code class="literal"><</code></span>” and
|
||||
“<span class="quote"><code class="literal">></code></span>” with XML
|
||||
entities.</p></li><li><p id="x_5a9"><a name="x_5a9"></a><code class="literal">fill68</code>: Any text. Wrap
|
||||
the text to fit in 68 columns. This is useful before you
|
||||
pass text through the <code class="literal">tabindent</code> filter, and
|
||||
still want it to fit in an 80-column fixed-font
|
||||
window.</p></li><li><p id="x_5aa"><a name="x_5aa"></a><code class="literal">fill76</code>: Any text. Wrap
|
||||
the text to fit in 76 columns.</p></li><li><p id="x_5ab"><a name="x_5ab"></a><code class="literal">firstline</code>: Any text.
|
||||
Yield the first line of text, without any trailing
|
||||
newlines.</p></li><li><p id="x_5ac"><a name="x_5ac"></a><code class="literal">hgdate</code>: <code class="literal">date</code> keyword. Render
|
||||
the date as a pair of readable numbers. Yields a string
|
||||
like “<span class="quote"><code class="literal">1157407993
|
||||
25200</code></span>”.</p></li><li><p id="x_5ad"><a name="x_5ad"></a><code class="literal">isodate</code>: <code class="literal">date</code> keyword. Render
|
||||
the date as a text string in ISO 8601 format. Yields a
|
||||
string like “<span class="quote"><code class="literal">2006-09-04 15:13:13
|
||||
-0700</code></span>”.</p></li><li><p id="x_5ae"><a name="x_5ae"></a><code class="literal">obfuscate</code>: Any text, but
|
||||
most useful for the <code class="literal">author</code> keyword. Yield
|
||||
the input text rendered as a sequence of XML entities. This
|
||||
helps to defeat some particularly stupid screen-scraping
|
||||
email harvesting spambots.</p></li><li><p id="x_5af"><a name="x_5af"></a><code class="literal">person</code>: Any text,
|
||||
but most useful for the <code class="literal">author</code> keyword. Yield
|
||||
the text before an email address. For example,
|
||||
“<span class="quote"><code class="literal">Bryan O'Sullivan
|
||||
<bos@serpentine.com></code></span>” becomes
|
||||
“<span class="quote"><code class="literal">Bryan O'Sullivan</code></span>”.</p></li><li><p id="x_5b0"><a name="x_5b0"></a><code class="literal">rfc822date</code>:
|
||||
<code class="literal">date</code> keyword.
|
||||
Render a date using the same format used in email headers.
|
||||
Yields a string like “<span class="quote"><code class="literal">Mon, 04 Sep 2006
|
||||
15:13:13 -0700</code></span>”.</p></li><li><p id="x_5b1"><a name="x_5b1"></a><code class="literal">short</code>: Changeset
|
||||
hash. Yield the short form of a changeset hash, i.e. a
|
||||
12-character hexadecimal string.</p></li><li><p id="x_5b2"><a name="x_5b2"></a><code class="literal">shortdate</code>: <code class="literal">date</code> keyword. Render
|
||||
the year, month, and day of the date. Yields a string like
|
||||
“<span class="quote"><code class="literal">2006-09-04</code></span>”.</p></li><li><p id="x_5b3"><a name="x_5b3"></a><code class="literal">strip</code>:
|
||||
Any text. Strip all leading and trailing whitespace from
|
||||
the string.</p></li><li><p id="x_5b4"><a name="x_5b4"></a><code class="literal">tabindent</code>: Any text.
|
||||
Yield the text, with every line except the first starting
|
||||
with a tab character.</p></li><li><p id="x_5b5"><a name="x_5b5"></a><code class="literal">urlescape</code>: Any text.
|
||||
Escape all characters that are considered
|
||||
“<span class="quote">special</span>” by URL parsers. For example,
|
||||
<code class="literal">foo bar</code> becomes
|
||||
<code class="literal">foo%20bar</code>.</p></li><li><p id="x_5b6"><a name="x_5b6"></a><code class="literal">user</code>: Any text,
|
||||
but most useful for the <code class="literal">author</code> keyword. Return
|
||||
the “<span class="quote">user</span>” portion of an email address. For
|
||||
example, “<span class="quote"><code class="literal">Bryan O'Sullivan
|
||||
<bos@serpentine.com></code></span>” becomes
|
||||
“<span class="quote"><code class="literal">bos</code></span>”.</p></li></ul></div><pre id="id417012" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{author}\n'</code></strong>
|
||||
Bryan O'Sullivan <bos@serpentine.com>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{author|domain}\n'</code></strong>
|
||||
serpentine.com
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{author|email}\n'</code></strong>
|
||||
bos@serpentine.com
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{author|obfuscate}\n' | cut -c-76</code></strong>
|
||||
&#66;&#114;&#121;&#97;&#110;&#32;&#79;&#39;&#83;&#117;&#108;&#108;&#105;&#11
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{author|person}\n'</code></strong>
|
||||
Bryan O'Sullivan
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{author|user}\n'</code></strong>
|
||||
bos
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'looks almost right, but actually garbage: {date}\n'</code></strong>
|
||||
looks almost right, but actually garbage: 1241506546.00
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{date|age}\n'</code></strong>
|
||||
2 seconds
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{date|date}\n'</code></strong>
|
||||
Tue May 05 06:55:46 2009 +0000
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{date|hgdate}\n'</code></strong>
|
||||
1241506546 0
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{date|isodate}\n'</code></strong>
|
||||
2009-05-05 06:55 +0000
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{date|rfc822date}\n'</code></strong>
|
||||
Tue, 05 May 2009 06:55:46 +0000
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{date|shortdate}\n'</code></strong>
|
||||
2009-05-05
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{desc}\n' | cut -c-76</code></strong>
|
||||
added line to end of <<hello>> file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope that some m
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{desc|addbreaks}\n' | cut -c-76</code></strong>
|
||||
added line to end of <<hello>> file.<br/>
|
||||
<br/>
|
||||
in addition, added a file with the helpful name (at least i hope that some m
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{desc|escape}\n' | cut -c-76</code></strong>
|
||||
added line to end of &lt;&lt;hello&gt;&gt; file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope that some m
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{desc|fill68}\n'</code></strong>
|
||||
added line to end of <<hello>> file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope
|
||||
that some might consider it so) of goodbye.
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{desc|fill76}\n'</code></strong>
|
||||
added line to end of <<hello>> file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope that some
|
||||
might consider it so) of goodbye.
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{desc|firstline}\n'</code></strong>
|
||||
added line to end of <<hello>> file.
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{desc|strip}\n' | cut -c-76</code></strong>
|
||||
added line to end of <<hello>> file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope that some m
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{desc|tabindent}\n' | expand | cut -c-76</code></strong>
|
||||
added line to end of <<hello>> file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope tha
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{node}\n'</code></strong>
|
||||
107e439be01c456e8e32f719558cb7ea693b60fd
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template '{node|short}\n'</code></strong>
|
||||
107e439be01c
|
||||
</pre><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_5b7"><a name="x_5b7"></a> If you try to apply a filter to a piece of data that it
|
||||
cannot process, Mercurial will fail and print a Python
|
||||
exception. For example, trying to run the output of the
|
||||
<code class="literal">desc</code> keyword into
|
||||
the <code class="literal">isodate</code>
|
||||
filter is not a good idea.</p></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id417290">Combining filters</h3></div></div></div><p id="x_5b8"><a name="x_5b8"></a>It is easy to combine filters to yield output in the form
|
||||
you would like. The following chain of filters tidies up a
|
||||
description, then makes sure that it fits cleanly into 68
|
||||
columns, then indents it by a further 8 characters (at least
|
||||
on Unix-like systems, where a tab is conventionally 8
|
||||
characters wide).</p><pre id="id417653" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --template 'description:\n\t{desc|strip|fill68|tabindent}\n'</code></strong>
|
||||
description:
|
||||
added line to end of <<hello>> file.
|
||||
|
||||
in addition, added a file with the helpful name (at least i hope
|
||||
that some might consider it so) of goodbye.
|
||||
</pre><p id="x_5b9"><a name="x_5b9"></a>Note the use of “<span class="quote"><code class="literal">\t</code></span>” (a
|
||||
tab character) in the template to force the first line to be
|
||||
indented; this is necessary since <code class="literal">tabindent</code> indents all
|
||||
lines <span class="emphasis"><em>except</em></span> the first.</p><p id="x_5ba"><a name="x_5ba"></a>Keep in mind that the order of filters in a chain is
|
||||
significant. The first filter is applied to the result of the
|
||||
keyword; the second to the result of the first filter; and so
|
||||
on. For example, using <code class="literal">fill68|tabindent</code>
|
||||
gives very different results from
|
||||
<code class="literal">tabindent|fill68</code>.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id417618">From templates to styles</h2></div></div></div><p id="x_5bb"><a name="x_5bb"></a>A command line template provides a quick and simple way to
|
||||
format some output. Templates can become verbose, though, and
|
||||
it's useful to be able to give a template a name. A style file
|
||||
is a template with a name, stored in a file.</p><p id="x_5bc"><a name="x_5bc"></a>More than that, using a style file unlocks the power of
|
||||
Mercurial's templating engine in ways that are not possible
|
||||
using the command line <code class="option">--template</code> option.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id417353">The simplest of style files</h3></div></div></div><p id="x_5bd"><a name="x_5bd"></a>Our simple style file contains just one line:</p><pre id="id417560" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo 'changeset = "rev: {rev}\n"' > rev</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -l1 --style ./rev</code></strong>
|
||||
rev: 3
|
||||
</pre><p id="x_5be"><a name="x_5be"></a>This tells Mercurial, “<span class="quote">if you're printing a
|
||||
changeset, use the text on the right as the
|
||||
template</span>”.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id417428">Style file syntax</h3></div></div></div><p id="x_5bf"><a name="x_5bf"></a>The syntax rules for a style file are simple.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_5c0"><a name="x_5c0"></a>The file is processed one line at a
|
||||
time.</p></li><li><p id="x_5c1"><a name="x_5c1"></a>Leading and trailing white space are
|
||||
ignored.</p></li><li><p id="x_5c2"><a name="x_5c2"></a>Empty lines are skipped.</p></li><li><p id="x_5c3"><a name="x_5c3"></a>If a line starts with either of the characters
|
||||
“<span class="quote"><code class="literal">#</code></span>” or
|
||||
“<span class="quote"><code class="literal">;</code></span>”, the entire line is
|
||||
treated as a comment, and skipped as if empty.</p></li><li><p id="x_5c4"><a name="x_5c4"></a>A line starts with a keyword. This must start
|
||||
with an alphabetic character or underscore, and can
|
||||
subsequently contain any alphanumeric character or
|
||||
underscore. (In regexp notation, a keyword must match
|
||||
<code class="literal">[A-Za-z_][A-Za-z0-9_]*</code>.)</p></li><li><p id="x_5c5"><a name="x_5c5"></a>The next element must be an
|
||||
“<span class="quote"><code class="literal">=</code></span>” character, which can
|
||||
be preceded or followed by an arbitrary amount of white
|
||||
space.</p></li><li><p id="x_5c6"><a name="x_5c6"></a>If the rest of the line starts and ends with
|
||||
matching quote characters (either single or double quote),
|
||||
it is treated as a template body.</p></li><li><p id="x_5c7"><a name="x_5c7"></a>If the rest of the line <span class="emphasis"><em>does
|
||||
not</em></span> start with a quote character, it is
|
||||
treated as the name of a file; the contents of this file
|
||||
will be read and used as a template body.</p></li></ul></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id417656">Style files by example</h2></div></div></div><p id="x_5c8"><a name="x_5c8"></a>To illustrate how to write a style file, we will construct a
|
||||
few by example. Rather than provide a complete style file and
|
||||
walk through it, we'll mirror the usual process of developing a
|
||||
style file by starting with something very simple, and walking
|
||||
through a series of successively more complete examples.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id417669">Identifying mistakes in style files</h3></div></div></div><p id="x_5c9"><a name="x_5c9"></a>If Mercurial encounters a problem in a style file you are
|
||||
working on, it prints a terse error message that, once you
|
||||
figure out what it means, is actually quite useful.</p><pre id="id418030" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat broken.style</code></strong>
|
||||
changeset =
|
||||
</pre><p id="x_5ca"><a name="x_5ca"></a>Notice that <code class="filename">broken.style</code> attempts to
|
||||
define a <code class="literal">changeset</code> keyword, but forgets to
|
||||
give any content for it. When instructed to use this style
|
||||
file, Mercurial promptly complains.</p><pre id="id418015" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r1 --style broken.style</code></strong>
|
||||
abort: broken.style:1: parse error
|
||||
</pre><p id="x_5cb"><a name="x_5cb"></a>This error message looks intimidating, but it is not too
|
||||
hard to follow.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_5cc"><a name="x_5cc"></a>The first component is simply Mercurial's way
|
||||
of saying “<span class="quote">I am giving up</span>”.</p><pre id="id417787" class="programlisting">___abort___: broken.style:1: parse error</pre></li><li><p id="x_5cd"><a name="x_5cd"></a>Next comes the name of the style file that
|
||||
contains the error.</p><pre id="id417803" class="programlisting">abort: ___broken.style___:1: parse error</pre></li><li><p id="x_5ce"><a name="x_5ce"></a>Following the file name is the line number
|
||||
where the error was encountered.</p><pre id="id417818" class="programlisting">abort: broken.style:___1___: parse error</pre></li><li><p id="x_5cf"><a name="x_5cf"></a>Finally, a description of what went
|
||||
wrong.</p><pre id="id417834" class="programlisting">abort: broken.style:1: ___parse error___</pre></li><li><p id="x_5d0"><a name="x_5d0"></a>The description of the problem is not always
|
||||
clear (as in this case), but even when it is cryptic, it
|
||||
is almost always trivial to visually inspect the offending
|
||||
line in the style file and see what is wrong.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id417853">Uniquely identifying a repository</h3></div></div></div><p id="x_5d1"><a name="x_5d1"></a>If you would like to be able to identify a Mercurial
|
||||
repository “<span class="quote">fairly uniquely</span>” using a short string
|
||||
as an identifier, you can use the first revision in the
|
||||
repository.</p><pre id="id418246" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log -r0 --template '{node}'</code></strong>
|
||||
189e736977c29ea3835dfc7e332794a24f479c51</pre><p id="x_5d2"><a name="x_5d2"></a>This is likely to be unique, and so it is
|
||||
useful in many cases. There are a few caveats.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_5d3"><a name="x_5d3"></a>It will not work in a completely empty
|
||||
repository, because such a repository does not have a
|
||||
revision zero.</p></li><li><p id="x_5d4"><a name="x_5d4"></a>Neither will it work in the (extremely rare)
|
||||
case where a repository is a merge of two or more formerly
|
||||
independent repositories, and you still have those
|
||||
repositories around.</p></li></ul></div><p id="x_5d5"><a name="x_5d5"></a>Here are some uses to which you could put this
|
||||
identifier:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_5d6"><a name="x_5d6"></a>As a key into a table for a database that
|
||||
manages repositories on a server.</p></li><li><p id="x_5d7"><a name="x_5d7"></a>As half of a {<span class="emphasis"><em>repository
|
||||
ID</em></span>, <span class="emphasis"><em>revision ID</em></span>} tuple.
|
||||
Save this information away when you run an automated build
|
||||
or other activity, so that you can “<span class="quote">replay</span>”
|
||||
the build later if necessary.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id417978">Listing files on multiple lines</h3></div></div></div><p id="x_714"><a name="x_714"></a>Suppose we want to list the files changed by a changeset,
|
||||
one per line, with a little indentation before each file
|
||||
name.</p><pre id="id418218" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat > multiline << EOF</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>changeset = "Changed in {node|short}:\n{files}"</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>file = " {file}\n"</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>EOF</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log --style multiline</code></strong>
|
||||
Changed in ae47487e0fed:
|
||||
.bashrc
|
||||
.hgrc
|
||||
test.c
|
||||
</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id418118">Mimicking Subversion's output</h3></div></div></div><p id="x_5d8"><a name="x_5d8"></a>Let's try to emulate the default output format used by
|
||||
another revision control tool, Subversion.</p><pre id="id418182" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>svn log -r9653</code></strong>
|
||||
------------------------------------------------------------------------
|
||||
r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines
|
||||
|
||||
On reporting a route error, also include the status for the error,
|
||||
rather than indicating a status of 0 when an error has occurred.
|
||||
|
||||
Signed-off-by: Sean Hefty <sean.hefty@intel.com>
|
||||
|
||||
------------------------------------------------------------------------
|
||||
</pre><p id="x_5d9"><a name="x_5d9"></a>Since Subversion's output style is fairly simple, it is
|
||||
easy to copy-and-paste a hunk of its output into a file, and
|
||||
replace the text produced above by Subversion with the
|
||||
template values we'd like to see expanded.</p><pre id="id418368" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat svn.template</code></strong>
|
||||
r{rev} | {author|user} | {date|isodate} ({date|rfc822date})
|
||||
|
||||
{desc|strip|fill76}
|
||||
|
||||
------------------------------------------------------------------------
|
||||
</pre><p id="x_5da"><a name="x_5da"></a>There are a few small ways in which this template deviates
|
||||
from the output produced by Subversion.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_5db"><a name="x_5db"></a>Subversion prints a “<span class="quote">readable</span>”
|
||||
date (the “<span class="quote"><code class="literal">Wed, 27 Sep 2006</code></span>” in the
|
||||
example output above) in parentheses. Mercurial's
|
||||
templating engine does not provide a way to display a date
|
||||
in this format without also printing the time and time
|
||||
zone.</p></li><li><p id="x_5dc"><a name="x_5dc"></a>We emulate Subversion's printing of
|
||||
“<span class="quote">separator</span>” lines full of
|
||||
“<span class="quote"><code class="literal">-</code></span>” characters by ending
|
||||
the template with such a line. We use the templating
|
||||
engine's <code class="literal">header</code>
|
||||
keyword to print a separator line as the first line of
|
||||
output (see below), thus achieving similar output to
|
||||
Subversion.</p></li><li><p id="x_5dd"><a name="x_5dd"></a>Subversion's output includes a count in the
|
||||
header of the number of lines in the commit message. We
|
||||
cannot replicate this in Mercurial; the templating engine
|
||||
does not currently provide a filter that counts the number
|
||||
of lines the template generates.</p></li></ul></div><p id="x_5de"><a name="x_5de"></a>It took me no more than a minute or two of work to replace
|
||||
literal text from an example of Subversion's output with some
|
||||
keywords and filters to give the template above. The style
|
||||
file simply refers to the template.</p><pre id="id418351" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat svn.style</code></strong>
|
||||
header = '------------------------------------------------------------------------\n\n'
|
||||
changeset = svn.template
|
||||
</pre><p id="x_5df"><a name="x_5df"></a>We could have included the text of the template file
|
||||
directly in the style file by enclosing it in quotes and
|
||||
replacing the newlines with
|
||||
“<span class="quote"><code class="literal">\n</code></span>” sequences, but it would
|
||||
have made the style file too difficult to read. Readability
|
||||
is a good guide when you're trying to decide whether some text
|
||||
belongs in a style file, or in a template file that the style
|
||||
file points to. If the style file will look too big or
|
||||
cluttered if you insert a literal piece of text, drop it into
|
||||
a template instead.</p></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="handling-repository-events-with-hooks.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="managing-change-with-mercurial-queues.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 10. Handling repository events with hooks </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 12. Managing change with Mercurial Queues</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
324
read/file-names-and-pattern-matching.html
Normal file
324
read/file-names-and-pattern-matching.html
Normal file
|
@ -0,0 +1,324 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 7. File names and pattern matching</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="collaborating-with-other-people.html" title="Chapter 6. Collaborating with other people"><link rel="next" href="managing-releases-and-branchy-development.html" title="Chapter 8. Managing releases and branchy development"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 7. File names and pattern matching</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="collaborating-with-other-people.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="managing-releases-and-branchy-development.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:names"><div class="titlepage"><div><div><h2 class="title">Chapter 7. File names and pattern matching</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="file-names-and-pattern-matching.html#id380420">Simple file naming</a></span></dt><dt><span class="sect1"><a href="file-names-and-pattern-matching.html#id380836">Running commands without any file names</a></span></dt><dt><span class="sect1"><a href="file-names-and-pattern-matching.html#id381125">Telling you what's going on</a></span></dt><dt><span class="sect1"><a href="file-names-and-pattern-matching.html#id381184">Using patterns to identify files</a></span></dt><dd><dl><dt><span class="sect2"><a href="file-names-and-pattern-matching.html#id381291">Shell-style glob patterns</a></span></dt><dd><dl><dt><span class="sect3"><a href="file-names-and-pattern-matching.html#id381653">Watch out!</a></span></dt></dl></dd><dt><span class="sect2"><a href="file-names-and-pattern-matching.html#id381804">Regular expression matching with re
|
||||
patterns</a></span></dt></dl></dd><dt><span class="sect1"><a href="file-names-and-pattern-matching.html#id381878">Filtering files</a></span></dt><dt><span class="sect1"><a href="file-names-and-pattern-matching.html#id382104">Permanently ignoring unwanted files and directories</a></span></dt><dt><span class="sect1"><a href="file-names-and-pattern-matching.html#sec:names:case">Case sensitivity</a></span></dt><dd><dl><dt><span class="sect2"><a href="file-names-and-pattern-matching.html#id382327">Safe, portable repository storage</a></span></dt><dt><span class="sect2"><a href="file-names-and-pattern-matching.html#id382348">Detecting case conflicts</a></span></dt><dt><span class="sect2"><a href="file-names-and-pattern-matching.html#id382414">Fixing a case conflict</a></span></dt></dl></dd></dl></div><p id="x_543"><a name="x_543"></a>Mercurial provides mechanisms that let you work with file
|
||||
names in a consistent and expressive way.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id380420">Simple file naming</h2></div></div></div><p id="x_544"><a name="x_544"></a>Mercurial uses a unified piece of machinery “<span class="quote">under the
|
||||
hood</span>” to handle file names. Every command behaves
|
||||
uniformly with respect to file names. The way in which commands
|
||||
work with file names is as follows.</p><p id="x_545"><a name="x_545"></a>If you explicitly name real files on the command line,
|
||||
Mercurial works with exactly those files, as you would expect.
|
||||
|
||||
</p><pre id="id381103" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg add COPYING README examples/simple.py</code></strong>
|
||||
</pre><p>
|
||||
|
||||
</p><p id="x_546"><a name="x_546"></a>When you provide a directory name, Mercurial will interpret
|
||||
this as “<span class="quote">operate on every file in this directory and its
|
||||
subdirectories</span>”. Mercurial traverses the files and
|
||||
subdirectories in a directory in alphabetical order. When it
|
||||
encounters a subdirectory, it will traverse that subdirectory
|
||||
before continuing with the current directory.</p><pre id="id381083" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status src</code></strong>
|
||||
? src/main.py
|
||||
? src/watcher/_watcher.c
|
||||
? src/watcher/watcher.py
|
||||
? src/xyzzy.txt
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id380836">Running commands without any file names</h2></div></div></div><p id="x_547"><a name="x_547"></a>Mercurial's commands that work with file names have useful
|
||||
default behaviors when you invoke them without providing any
|
||||
file names or patterns. What kind of behavior you should
|
||||
expect depends on what the command does. Here are a few rules
|
||||
of thumb you can use to predict what a command is likely to do
|
||||
if you don't give it any names to work with.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_548"><a name="x_548"></a>Most commands will operate on the entire working
|
||||
directory. This is what the <span class="command"><strong>hg
|
||||
add</strong></span> command does, for example.</p></li><li><p id="x_549"><a name="x_549"></a>If the command has effects that are difficult or
|
||||
impossible to reverse, it will force you to explicitly
|
||||
provide at least one name or pattern (see below). This
|
||||
protects you from accidentally deleting files by running
|
||||
<span class="command"><strong>hg remove</strong></span> with no
|
||||
arguments, for example.</p></li></ul></div><p id="x_54a"><a name="x_54a"></a>It's easy to work around these default behaviors if they
|
||||
don't suit you. If a command normally operates on the whole
|
||||
working directory, you can invoke it on just the current
|
||||
directory and its subdirectories by giving it the name
|
||||
“<span class="quote"><code class="filename">.</code></span>”.</p><pre id="id381050" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd src</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add -n</code></strong>
|
||||
adding ../MANIFEST.in
|
||||
adding ../examples/performant.py
|
||||
adding ../setup.py
|
||||
adding main.py
|
||||
adding watcher/_watcher.c
|
||||
adding watcher/watcher.py
|
||||
adding xyzzy.txt
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add -n .</code></strong>
|
||||
adding main.py
|
||||
adding watcher/_watcher.c
|
||||
adding watcher/watcher.py
|
||||
adding xyzzy.txt
|
||||
</pre><p id="x_54b"><a name="x_54b"></a>Along the same lines, some commands normally print file
|
||||
names relative to the root of the repository, even if you're
|
||||
invoking them from a subdirectory. Such a command will print
|
||||
file names relative to your subdirectory if you give it explicit
|
||||
names. Here, we're going to run <span class="command"><strong>hg
|
||||
status</strong></span> from a subdirectory, and get it to operate on
|
||||
the entire working directory while printing file names relative
|
||||
to our subdirectory, by passing it the output of the <span class="command"><strong>hg root</strong></span> command.</p><pre id="id381404" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
A COPYING
|
||||
A README
|
||||
A examples/simple.py
|
||||
? MANIFEST.in
|
||||
? examples/performant.py
|
||||
? setup.py
|
||||
? src/main.py
|
||||
? src/watcher/_watcher.c
|
||||
? src/watcher/watcher.py
|
||||
? src/xyzzy.txt
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status `hg root`</code></strong>
|
||||
A ../COPYING
|
||||
A ../README
|
||||
A ../examples/simple.py
|
||||
? ../MANIFEST.in
|
||||
? ../examples/performant.py
|
||||
? ../setup.py
|
||||
? main.py
|
||||
? watcher/_watcher.c
|
||||
? watcher/watcher.py
|
||||
? xyzzy.txt
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id381125">Telling you what's going on</h2></div></div></div><p id="x_54c"><a name="x_54c"></a>The <span class="command"><strong>hg add</strong></span> example in the
|
||||
preceding section illustrates something else that's helpful
|
||||
about Mercurial commands. If a command operates on a file that
|
||||
you didn't name explicitly on the command line, it will usually
|
||||
print the name of the file, so that you will not be surprised
|
||||
what's going on.</p><p id="x_54d"><a name="x_54d"></a>The principle here is of <span class="emphasis"><em>least
|
||||
surprise</em></span>. If you've exactly named a file on the
|
||||
command line, there's no point in repeating it back at you. If
|
||||
Mercurial is acting on a file <span class="emphasis"><em>implicitly</em></span>, e.g.
|
||||
because you provided no names, or a directory, or a pattern (see
|
||||
below), it is safest to tell you what files it's operating on.</p><p id="x_54e"><a name="x_54e"></a>For commands that behave this way, you can silence them
|
||||
using the <code class="option">-q</code> option. You
|
||||
can also get them to print the name of every file, even those
|
||||
you've named explicitly, using the <code class="option">-v</code> option.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id381184">Using patterns to identify files</h2></div></div></div><p id="x_54f"><a name="x_54f"></a>In addition to working with file and directory names,
|
||||
Mercurial lets you use <span class="emphasis"><em>patterns</em></span> to identify
|
||||
files. Mercurial's pattern handling is expressive.</p><p id="x_550"><a name="x_550"></a>On Unix-like systems (Linux, MacOS, etc.), the job of
|
||||
matching file names to patterns normally falls to the shell. On
|
||||
these systems, you must explicitly tell Mercurial that a name is
|
||||
a pattern. On Windows, the shell does not expand patterns, so
|
||||
Mercurial will automatically identify names that are patterns,
|
||||
and expand them for you.</p><p id="x_551"><a name="x_551"></a>To provide a pattern in place of a regular name on the
|
||||
command line, the mechanism is simple:</p><pre id="id381219" class="programlisting">syntax:patternbody</pre><p id="x_552"><a name="x_552"></a>That is, a pattern is identified by a short text string that
|
||||
says what kind of pattern this is, followed by a colon, followed
|
||||
by the actual pattern.</p><p id="x_553"><a name="x_553"></a>Mercurial supports two kinds of pattern syntax. The most
|
||||
frequently used is called <code class="literal">glob</code>; this is the
|
||||
same kind of pattern matching used by the Unix shell, and should
|
||||
be familiar to Windows command prompt users, too.</p><p id="x_554"><a name="x_554"></a>When Mercurial does automatic pattern matching on Windows,
|
||||
it uses <code class="literal">glob</code> syntax. You can thus omit the
|
||||
“<span class="quote"><code class="literal">glob:</code></span>” prefix on Windows, but
|
||||
it's safe to use it, too.</p><p id="x_555"><a name="x_555"></a>The <code class="literal">re</code> syntax is more powerful; it lets
|
||||
you specify patterns using regular expressions, also known as
|
||||
regexps.</p><p id="x_556"><a name="x_556"></a>By the way, in the examples that follow, notice that I'm
|
||||
careful to wrap all of my patterns in quote characters, so that
|
||||
they won't get expanded by the shell before Mercurial sees
|
||||
them.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id381291">Shell-style <code class="literal">glob</code> patterns</h3></div></div></div><p id="x_557"><a name="x_557"></a>This is an overview of the kinds of patterns you can use
|
||||
when you're matching on glob patterns.</p><p id="x_558"><a name="x_558"></a>The “<span class="quote"><code class="literal">*</code></span>” character matches
|
||||
any string, within a single directory.</p><pre id="id381387" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg add 'glob:*.py'</code></strong>
|
||||
adding main.py
|
||||
</pre><p id="x_559"><a name="x_559"></a>The “<span class="quote"><code class="literal">**</code></span>” pattern matches
|
||||
any string, and crosses directory boundaries. It's not a
|
||||
standard Unix glob token, but it's accepted by several popular
|
||||
Unix shells, and is very useful.</p><pre id="id381744" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status 'glob:**.py'</code></strong>
|
||||
A examples/simple.py
|
||||
A src/main.py
|
||||
? examples/performant.py
|
||||
? setup.py
|
||||
? src/watcher/watcher.py
|
||||
</pre><p id="x_55a"><a name="x_55a"></a>The “<span class="quote"><code class="literal">?</code></span>” pattern matches
|
||||
any single character.</p><pre id="id381494" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status 'glob:**.?'</code></strong>
|
||||
? src/watcher/_watcher.c
|
||||
</pre><p id="x_55b"><a name="x_55b"></a>The “<span class="quote"><code class="literal">[</code></span>” character begins a
|
||||
<span class="emphasis"><em>character class</em></span>. This matches any single
|
||||
character within the class. The class ends with a
|
||||
“<span class="quote"><code class="literal">]</code></span>” character. A class may
|
||||
contain multiple <span class="emphasis"><em>range</em></span>s of the form
|
||||
“<span class="quote"><code class="literal">a-f</code></span>”, which is shorthand for
|
||||
“<span class="quote"><code class="literal">abcdef</code></span>”.</p><pre id="id381693" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status 'glob:**[nr-t]'</code></strong>
|
||||
? MANIFEST.in
|
||||
? src/xyzzy.txt
|
||||
</pre><p id="x_55c"><a name="x_55c"></a>If the first character after the
|
||||
“<span class="quote"><code class="literal">[</code></span>” in a character class is a
|
||||
“<span class="quote"><code class="literal">!</code></span>”, it
|
||||
<span class="emphasis"><em>negates</em></span> the class, making it match any
|
||||
single character not in the class.</p><p id="x_55d"><a name="x_55d"></a>A “<span class="quote"><code class="literal">{</code></span>” begins a group of
|
||||
subpatterns, where the whole group matches if any subpattern
|
||||
in the group matches. The “<span class="quote"><code class="literal">,</code></span>”
|
||||
character separates subpatterns, and
|
||||
“<span class="quote"><code class="literal">}</code></span>” ends the group.</p><pre id="id381665" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status 'glob:*.{in,py}'</code></strong>
|
||||
? MANIFEST.in
|
||||
? setup.py
|
||||
</pre><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id381653">Watch out!</h4></div></div></div><p id="x_55e"><a name="x_55e"></a>Don't forget that if you want to match a pattern in any
|
||||
directory, you should not be using the
|
||||
“<span class="quote"><code class="literal">*</code></span>” match-any token, as this
|
||||
will only match within one directory. Instead, use the
|
||||
“<span class="quote"><code class="literal">**</code></span>” token. This small
|
||||
example illustrates the difference between the two.</p><pre id="id382086" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status 'glob:*.py'</code></strong>
|
||||
? setup.py
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status 'glob:**.py'</code></strong>
|
||||
A examples/simple.py
|
||||
A src/main.py
|
||||
? examples/performant.py
|
||||
? setup.py
|
||||
? src/watcher/watcher.py
|
||||
</pre></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id381804">Regular expression matching with <code class="literal">re</code>
|
||||
patterns</h3></div></div></div><p id="x_55f"><a name="x_55f"></a>Mercurial accepts the same regular expression syntax as
|
||||
the Python programming language (it uses Python's regexp
|
||||
engine internally). This is based on the Perl language's
|
||||
regexp syntax, which is the most popular dialect in use (it's
|
||||
also used in Java, for example).</p><p id="x_560"><a name="x_560"></a>I won't discuss Mercurial's regexp dialect in any detail
|
||||
here, as regexps are not often used. Perl-style regexps are
|
||||
in any case already exhaustively documented on a multitude of
|
||||
web sites, and in many books. Instead, I will focus here on a
|
||||
few things you should know if you find yourself needing to use
|
||||
regexps with Mercurial.</p><p id="x_561"><a name="x_561"></a>A regexp is matched against an entire file name, relative
|
||||
to the root of the repository. In other words, even if you're
|
||||
already in subbdirectory <code class="filename">foo</code>, if you want to match files
|
||||
under this directory, your pattern must start with
|
||||
“<span class="quote"><code class="literal">foo/</code></span>”.</p><p id="x_562"><a name="x_562"></a>One thing to note, if you're familiar with Perl-style
|
||||
regexps, is that Mercurial's are <span class="emphasis"><em>rooted</em></span>.
|
||||
That is, a regexp starts matching against the beginning of a
|
||||
string; it doesn't look for a match anywhere within the
|
||||
string. To match anywhere in a string, start your pattern
|
||||
with “<span class="quote"><code class="literal">.*</code></span>”.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id381878">Filtering files</h2></div></div></div><p id="x_563"><a name="x_563"></a>Not only does Mercurial give you a variety of ways to
|
||||
specify files; it lets you further winnow those files using
|
||||
<span class="emphasis"><em>filters</em></span>. Commands that work with file
|
||||
names accept two filtering options.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_564"><a name="x_564"></a><code class="option">-I</code>, or
|
||||
<code class="option">--include</code>, lets you
|
||||
specify a pattern that file names must match in order to be
|
||||
processed.</p></li><li><p id="x_565"><a name="x_565"></a><code class="option">-X</code>, or
|
||||
<code class="option">--exclude</code>, gives you a
|
||||
way to <span class="emphasis"><em>avoid</em></span> processing files, if they
|
||||
match this pattern.</p></li></ul></div><p id="x_566"><a name="x_566"></a>You can provide multiple <code class="option">-I</code> and <code class="option">-X</code> options on the command line,
|
||||
and intermix them as you please. Mercurial interprets the
|
||||
patterns you provide using glob syntax by default (but you can
|
||||
use regexps if you need to).</p><p id="x_567"><a name="x_567"></a>You can read a <code class="option">-I</code>
|
||||
filter as “<span class="quote">process only the files that match this
|
||||
filter</span>”.</p><pre id="id382042" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status -I '*.in'</code></strong>
|
||||
? MANIFEST.in
|
||||
</pre><p id="x_568"><a name="x_568"></a>The <code class="option">-X</code> filter is best
|
||||
read as “<span class="quote">process only the files that don't match this
|
||||
pattern</span>”.</p><pre id="id382014" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status -X '**.py' src</code></strong>
|
||||
? src/watcher/_watcher.c
|
||||
? src/xyzzy.txt
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id382104">Permanently ignoring unwanted files and directories</h2></div></div></div><p id="x_569"><a name="x_569"></a>When you create a new repository, the chances are
|
||||
that over time it will grow to contain files that ought to
|
||||
<span class="emphasis"><em>not</em></span> be managed by Mercurial, but which you
|
||||
don't want to see listed every time you run <span class="command"><strong>hg
|
||||
status</strong></span>. For instance, “<span class="quote">build products</span>”
|
||||
are files that are created as part of a build but which should
|
||||
not be managed by a revision control system. The most common
|
||||
build products are output files produced by software tools such
|
||||
as compilers. As another example, many text editors litter a
|
||||
directory with lock files, temporary working files, and backup
|
||||
files, which it also makes no sense to manage.</p><p id="x_6b4"><a name="x_6b4"></a>To have Mercurial permanently ignore such files, create a
|
||||
file named <code class="filename">.hgignore</code> in the root of your
|
||||
repository. You <span class="emphasis"><em>should</em></span> <span class="command"><strong>hg
|
||||
add</strong></span> this file so that it gets tracked with the rest of
|
||||
your repository contents, since your collaborators will probably
|
||||
find it useful too.</p><p id="x_6b5"><a name="x_6b5"></a>By default, the <code class="filename">.hgignore</code> file should
|
||||
contain a list of regular expressions, one per line. Empty
|
||||
lines are skipped. Most people prefer to describe the files they
|
||||
want to ignore using the “<span class="quote">glob</span>” syntax that we
|
||||
described above, so a typical <code class="filename">.hgignore</code>
|
||||
file will start with this directive:</p><pre id="id382178" class="programlisting">syntax: glob</pre><p id="x_6b6"><a name="x_6b6"></a>This tells Mercurial to interpret the lines that follow as
|
||||
glob patterns, not regular expressions.</p><p id="x_6b7"><a name="x_6b7"></a>Here is a typical-looking <code class="filename">.hgignore</code>
|
||||
file.</p><pre id="id382204" class="programlisting">syntax: glob
|
||||
# This line is a comment, and will be skipped.
|
||||
# Empty lines are skipped too.
|
||||
|
||||
# Backup files left behind by the Emacs editor.
|
||||
*~
|
||||
|
||||
# Lock files used by the Emacs editor.
|
||||
# Notice that the "#" character is quoted with a backslash.
|
||||
# This prevents it from being interpreted as starting a comment.
|
||||
.\#*
|
||||
|
||||
# Temporary files used by the vim editor.
|
||||
.*.swp
|
||||
|
||||
# A hidden file created by the Mac OS X Finder.
|
||||
.DS_Store
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:names:case">Case sensitivity</h2></div></div></div><p id="x_56a"><a name="x_56a"></a>If you're working in a mixed development environment that
|
||||
contains both Linux (or other Unix) systems and Macs or Windows
|
||||
systems, you should keep in the back of your mind the knowledge
|
||||
that they treat the case (“<span class="quote">N</span>” versus
|
||||
“<span class="quote">n</span>”) of file names in incompatible ways. This is
|
||||
not very likely to affect you, and it's easy to deal with if it
|
||||
does, but it could surprise you if you don't know about
|
||||
it.</p><p id="x_56b"><a name="x_56b"></a>Operating systems and filesystems differ in the way they
|
||||
handle the <span class="emphasis"><em>case</em></span> of characters in file and
|
||||
directory names. There are three common ways to handle case in
|
||||
names.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_56c"><a name="x_56c"></a>Completely case insensitive. Uppercase and
|
||||
lowercase versions of a letter are treated as identical,
|
||||
both when creating a file and during subsequent accesses.
|
||||
This is common on older DOS-based systems.</p></li><li><p id="x_56d"><a name="x_56d"></a>Case preserving, but insensitive. When a file
|
||||
or directory is created, the case of its name is stored, and
|
||||
can be retrieved and displayed by the operating system.
|
||||
When an existing file is being looked up, its case is
|
||||
ignored. This is the standard arrangement on Windows and
|
||||
MacOS. The names <code class="filename">foo</code> and
|
||||
<code class="filename">FoO</code> identify the same file. This
|
||||
treatment of uppercase and lowercase letters as
|
||||
interchangeable is also referred to as <span class="emphasis"><em>case
|
||||
folding</em></span>.</p></li><li><p id="x_56e"><a name="x_56e"></a>Case sensitive. The case of a name
|
||||
is significant at all times. The names
|
||||
<code class="filename">foo</code> and <code class="filename">FoO</code>
|
||||
identify different files. This is the way Linux and Unix
|
||||
systems normally work.</p></li></ul></div><p id="x_56f"><a name="x_56f"></a>On Unix-like systems, it is possible to have any or all of
|
||||
the above ways of handling case in action at once. For example,
|
||||
if you use a USB thumb drive formatted with a FAT32 filesystem
|
||||
on a Linux system, Linux will handle names on that filesystem in
|
||||
a case preserving, but insensitive, way.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id382327">Safe, portable repository storage</h3></div></div></div><p id="x_570"><a name="x_570"></a>Mercurial's repository storage mechanism is <span class="emphasis"><em>case
|
||||
safe</em></span>. It translates file names so that they can
|
||||
be safely stored on both case sensitive and case insensitive
|
||||
filesystems. This means that you can use normal file copying
|
||||
tools to transfer a Mercurial repository onto, for example, a
|
||||
USB thumb drive, and safely move that drive and repository
|
||||
back and forth between a Mac, a PC running Windows, and a
|
||||
Linux box.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id382348">Detecting case conflicts</h3></div></div></div><p id="x_571"><a name="x_571"></a>When operating in the working directory, Mercurial honours
|
||||
the naming policy of the filesystem where the working
|
||||
directory is located. If the filesystem is case preserving,
|
||||
but insensitive, Mercurial will treat names that differ only
|
||||
in case as the same.</p><p id="x_572"><a name="x_572"></a>An important aspect of this approach is that it is
|
||||
possible to commit a changeset on a case sensitive (typically
|
||||
Linux or Unix) filesystem that will cause trouble for users on
|
||||
case insensitive (usually Windows and MacOS) users. If a
|
||||
Linux user commits changes to two files, one named
|
||||
<code class="filename">myfile.c</code> and the other named
|
||||
<code class="filename">MyFile.C</code>, they will be stored correctly
|
||||
in the repository. And in the working directories of other
|
||||
Linux users, they will be correctly represented as separate
|
||||
files.</p><p id="x_573"><a name="x_573"></a>If a Windows or Mac user pulls this change, they will not
|
||||
initially have a problem, because Mercurial's repository
|
||||
storage mechanism is case safe. However, once they try to
|
||||
<span class="command"><strong>hg update</strong></span> the working
|
||||
directory to that changeset, or <span class="command"><strong>hg
|
||||
merge</strong></span> with that changeset, Mercurial will spot the
|
||||
conflict between the two file names that the filesystem would
|
||||
treat as the same, and forbid the update or merge from
|
||||
occurring.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id382414">Fixing a case conflict</h3></div></div></div><p id="x_574"><a name="x_574"></a>If you are using Windows or a Mac in a mixed environment
|
||||
where some of your collaborators are using Linux or Unix, and
|
||||
Mercurial reports a case folding conflict when you try to
|
||||
<span class="command"><strong>hg update</strong></span> or <span class="command"><strong>hg merge</strong></span>, the procedure to fix the
|
||||
problem is simple.</p><p id="x_575"><a name="x_575"></a>Just find a nearby Linux or Unix box, clone the problem
|
||||
repository onto it, and use Mercurial's <span class="command"><strong>hg rename</strong></span> command to change the
|
||||
names of any offending files or directories so that they will
|
||||
no longer cause case folding conflicts. Commit this change,
|
||||
<span class="command"><strong>hg pull</strong></span> or <span class="command"><strong>hg push</strong></span> it across to your Windows or
|
||||
MacOS system, and <span class="command"><strong>hg update</strong></span>
|
||||
to the revision with the non-conflicting names.</p><p id="x_576"><a name="x_576"></a>The changeset with case-conflicting names will remain in
|
||||
your project's history, and you still won't be able to
|
||||
<span class="command"><strong>hg update</strong></span> your working
|
||||
directory to that changeset on a Windows or MacOS system, but
|
||||
you can continue development unimpeded.</p></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="collaborating-with-other-people.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="managing-releases-and-branchy-development.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 6. Collaborating with other people </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 8. Managing releases and branchy development</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
883
read/finding-and-fixing-mistakes.html
Normal file
883
read/finding-and-fixing-mistakes.html
Normal file
|
@ -0,0 +1,883 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 9. Finding and fixing mistakes</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="managing-releases-and-branchy-development.html" title="Chapter 8. Managing releases and branchy development"><link rel="next" href="handling-repository-events-with-hooks.html" title="Chapter 10. Handling repository events with hooks"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 9. Finding and fixing mistakes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="managing-releases-and-branchy-development.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="handling-repository-events-with-hooks.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:undo"><div class="titlepage"><div><div><h2 class="title">Chapter 9. Finding and fixing mistakes</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#id390081">Erasing local history</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id390087">The accidental commit</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#sec:undo:rollback">Rolling back a transaction</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id390858">The erroneous pull</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#sec:undo:rollback-after-push">Rolling back is useless once you've pushed</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id391000">You can only roll back once</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#id391367">Reverting the mistaken change</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#sec:undo:mgmt">File management errors</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#id392218">Dealing with committed changes</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id392287">Backing out a changeset</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id392424">Backing out the tip changeset</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id392766">Backing out a non-tip change</a></span></dt><dd><dl><dt><span class="sect3"><a href="finding-and-fixing-mistakes.html#id392990">Always use the --merge option</a></span></dt></dl></dd><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id393181">Gaining more control of the backout process</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id393814">Why hg backout works as
|
||||
it does</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#sec:undo:aaaiiieee">Changes that should never have been</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id394303">Backing out a merge</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id394612">Protect yourself from escaped
|
||||
changes</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id394667">What to do about sensitive changes that escape</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#sec:undo:bisect">Finding the source of a bug</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id394992">Using the hg bisect
|
||||
command</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396541">Cleaning up after your search</a></span></dt></dl></dd><dt><span class="sect1"><a href="finding-and-fixing-mistakes.html#id396622">Tips for finding bugs effectively</a></span></dt><dd><dl><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396628">Give consistent input</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396884">Automate as much as possible</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396713">Check your results</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396770">Beware interference between bugs</a></span></dt><dt><span class="sect2"><a href="finding-and-fixing-mistakes.html#id396856">Bracket your search lazily</a></span></dt></dl></dd></dl></div><p id="x_d2"><a name="x_d2"></a>To err might be human, but to really handle the consequences
|
||||
well takes a top-notch revision control system. In this chapter,
|
||||
we'll discuss some of the techniques you can use when you find
|
||||
that a problem has crept into your project. Mercurial has some
|
||||
highly capable features that will help you to isolate the sources
|
||||
of problems, and to handle them appropriately.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id390081">Erasing local history</h2></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id390087">The accidental commit</h3></div></div></div><p id="x_d3"><a name="x_d3"></a>I have the occasional but persistent problem of typing
|
||||
rather more quickly than I can think, which sometimes results
|
||||
in me committing a changeset that is either incomplete or
|
||||
plain wrong. In my case, the usual kind of incomplete
|
||||
changeset is one in which I've created a new source file, but
|
||||
forgotten to <span class="command"><strong>hg add</strong></span> it. A
|
||||
“<span class="quote">plain wrong</span>” changeset is not as common, but no
|
||||
less annoying.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:undo:rollback">Rolling back a transaction</h3></div></div></div><p id="x_d4"><a name="x_d4"></a>In <a class="xref" href="behind-the-scenes.html#sec:concepts:txn" title="Safe operation">the section called “Safe operation”</a>, I
|
||||
mentioned that Mercurial treats each modification of a
|
||||
repository as a <span class="emphasis"><em>transaction</em></span>. Every time
|
||||
you commit a changeset or pull changes from another
|
||||
repository, Mercurial remembers what you did. You can undo,
|
||||
or <span class="emphasis"><em>roll back</em></span>, exactly one of these
|
||||
actions using the <span class="command"><strong>hg rollback</strong></span>
|
||||
command. (See <a class="xref" href="finding-and-fixing-mistakes.html#sec:undo:rollback-after-push" title="Rolling back is useless once you've pushed">the section called “Rolling back is useless once you've pushed”</a>
|
||||
for an important caveat about the use of this command.)</p><p id="x_d5"><a name="x_d5"></a>Here's a mistake that I often find myself making:
|
||||
committing a change in which I've created a new file, but
|
||||
forgotten to <span class="command"><strong>hg add</strong></span>
|
||||
it.</p><pre id="id390839" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
M a
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo b > b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Add file b'</code></strong>
|
||||
</pre><p id="x_d6"><a name="x_d6"></a>Looking at the output of <span class="command"><strong>hg
|
||||
status</strong></span> after the commit immediately confirms the
|
||||
error.</p><pre id="id390541" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
? b
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 1:f2db1de2ba4f
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:44 2009 +0000
|
||||
summary: Add file b
|
||||
|
||||
</pre><p id="x_d7"><a name="x_d7"></a>The commit captured the changes to the file
|
||||
<code class="filename">a</code>, but not the new file
|
||||
<code class="filename">b</code>. If I were to push this changeset to a
|
||||
repository that I shared with a colleague, the chances are
|
||||
high that something in <code class="filename">a</code> would refer to
|
||||
<code class="filename">b</code>, which would not be present in their
|
||||
repository when they pulled my changes. I would thus become
|
||||
the object of some indignation.</p><p id="x_d8"><a name="x_d8"></a>However, luck is with me—I've caught my error
|
||||
before I pushed the changeset. I use the <span class="command"><strong>hg rollback</strong></span> command, and Mercurial
|
||||
makes that last changeset vanish.</p><pre id="id391066" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg rollback</code></strong>
|
||||
rolling back last transaction
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 0:cde70bc943e1
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:44 2009 +0000
|
||||
summary: First commit
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
M a
|
||||
? b
|
||||
</pre><p id="x_d9"><a name="x_d9"></a>Notice that the changeset is no longer present in the
|
||||
repository's history, and the working directory once again
|
||||
thinks that the file <code class="filename">a</code> is modified. The
|
||||
commit and rollback have left the working directory exactly as
|
||||
it was prior to the commit; the changeset has been completely
|
||||
erased. I can now safely <span class="command"><strong>hg
|
||||
add</strong></span> the file <code class="filename">b</code>, and rerun my
|
||||
commit.</p><pre id="id391024" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg add b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Add file b, this time for real'</code></strong>
|
||||
</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id390858">The erroneous pull</h3></div></div></div><p id="x_da"><a name="x_da"></a>It's common practice with Mercurial to maintain separate
|
||||
development branches of a project in different repositories.
|
||||
Your development team might have one shared repository for
|
||||
your project's “<span class="quote">0.9</span>” release, and another,
|
||||
containing different changes, for the “<span class="quote">1.0</span>”
|
||||
release.</p><p id="x_db"><a name="x_db"></a>Given this, you can imagine that the consequences could be
|
||||
messy if you had a local “<span class="quote">0.9</span>” repository, and
|
||||
accidentally pulled changes from the shared “<span class="quote">1.0</span>”
|
||||
repository into it. At worst, you could be paying
|
||||
insufficient attention, and push those changes into the shared
|
||||
“<span class="quote">0.9</span>” tree, confusing your entire team (but don't
|
||||
worry, we'll return to this horror scenario later). However,
|
||||
it's more likely that you'll notice immediately, because
|
||||
Mercurial will display the URL it's pulling from, or you will
|
||||
see it pull a suspiciously large number of changes into the
|
||||
repository.</p><p id="x_dc"><a name="x_dc"></a>The <span class="command"><strong>hg rollback</strong></span> command
|
||||
will work nicely to expunge all of the changesets that you
|
||||
just pulled. Mercurial groups all changes from one <span class="command"><strong>hg pull</strong></span> into a single transaction,
|
||||
so one <span class="command"><strong>hg rollback</strong></span> is all you
|
||||
need to undo this mistake.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:undo:rollback-after-push">Rolling back is useless once you've pushed</h3></div></div></div><p id="x_dd"><a name="x_dd"></a>The value of the <span class="command"><strong>hg
|
||||
rollback</strong></span> command drops to zero once you've pushed
|
||||
your changes to another repository. Rolling back a change
|
||||
makes it disappear entirely, but <span class="emphasis"><em>only</em></span> in
|
||||
the repository in which you perform the <span class="command"><strong>hg rollback</strong></span>. Because a rollback
|
||||
eliminates history, there's no way for the disappearance of a
|
||||
change to propagate between repositories.</p><p id="x_de"><a name="x_de"></a>If you've pushed a change to another
|
||||
repository—particularly if it's a shared
|
||||
repository—it has essentially “<span class="quote">escaped into the
|
||||
wild,</span>” and you'll have to recover from your mistake
|
||||
in a different way. If you push a changeset somewhere, then
|
||||
roll it back, then pull from the repository you pushed to, the
|
||||
changeset you thought you'd gotten rid of will simply reappear
|
||||
in your repository.</p><p id="x_df"><a name="x_df"></a>(If you absolutely know for sure that the change
|
||||
you want to roll back is the most recent change in the
|
||||
repository that you pushed to, <span class="emphasis"><em>and</em></span> you
|
||||
know that nobody else could have pulled it from that
|
||||
repository, you can roll back the changeset there, too, but
|
||||
you really should not expect this to work reliably. Sooner or
|
||||
later a change really will make it into a repository that you
|
||||
don't directly control (or have forgotten about), and come
|
||||
back to bite you.)</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id391000">You can only roll back once</h3></div></div></div><p id="x_e0"><a name="x_e0"></a>Mercurial stores exactly one transaction in its
|
||||
transaction log; that transaction is the most recent one that
|
||||
occurred in the repository. This means that you can only roll
|
||||
back one transaction. If you expect to be able to roll back
|
||||
one transaction, then its predecessor, this is not the
|
||||
behavior you will get.</p><pre id="id391424" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg rollback</code></strong>
|
||||
rolling back last transaction
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg rollback</code></strong>
|
||||
no rollback information available
|
||||
</pre><p id="x_e1"><a name="x_e1"></a>Once you've rolled back one transaction in a repository,
|
||||
you can't roll back again in that repository until you perform
|
||||
another commit or pull.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id391367">Reverting the mistaken change</h2></div></div></div><p id="x_e2"><a name="x_e2"></a>If you make a modification to a file, and decide that you
|
||||
really didn't want to change the file at all, and you haven't
|
||||
yet committed your changes, the <span class="command"><strong>hg
|
||||
revert</strong></span> command is the one you'll need. It looks at
|
||||
the changeset that's the parent of the working directory, and
|
||||
restores the contents of the file to their state as of that
|
||||
changeset. (That's a long-winded way of saying that, in the
|
||||
normal case, it undoes your modifications.)</p><p id="x_e3"><a name="x_e3"></a>Let's illustrate how the <span class="command"><strong>hg
|
||||
revert</strong></span> command works with yet another small example.
|
||||
We'll begin by modifying a file that Mercurial is already
|
||||
tracking.</p><pre id="id391316" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat file</code></strong>
|
||||
original content
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo unwanted change >> file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg diff file</code></strong>
|
||||
diff -r b52afd4afc59 file
|
||||
--- a/file Tue May 05 06:55:32 2009 +0000
|
||||
+++ b/file Tue May 05 06:55:32 2009 +0000
|
||||
@@ -1,1 +1,2 @@
|
||||
original content
|
||||
+unwanted change
|
||||
</pre><p id="x_e4"><a name="x_e4"></a>If we don't
|
||||
want that change, we can simply <span class="command"><strong>hg
|
||||
revert</strong></span> the file.</p><pre id="id391251" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
M file
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg revert file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat file</code></strong>
|
||||
original content
|
||||
</pre><p id="x_e5"><a name="x_e5"></a>The <span class="command"><strong>hg revert</strong></span> command
|
||||
provides us with an extra degree of safety by saving our
|
||||
modified file with a <code class="filename">.orig</code>
|
||||
extension.</p><pre id="id391767" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
? file.orig
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat file.orig</code></strong>
|
||||
original content
|
||||
unwanted change
|
||||
</pre><div class="tip"><table border="0" summary="Tip: Be careful with .orig files"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="/support/figs/tip.png"></td><th align="left">Be careful with .orig files</th></tr><tr><td align="left" valign="top"><p id="x_6b8"><a name="x_6b8"></a>It's extremely unlikely that you are either using
|
||||
Mercurial to manage files with <code class="filename">.orig</code>
|
||||
extensions or that you even care about the contents of such
|
||||
files. Just in case, though, it's useful to remember that
|
||||
<span class="command"><strong>hg revert</strong></span> will
|
||||
unconditionally overwrite an existing file with a
|
||||
<code class="filename">.orig</code> extension. For instance, if you
|
||||
already have a file named <code class="filename">foo.orig</code> when
|
||||
you revert <code class="filename">foo</code>, the contents of
|
||||
<code class="filename">foo.orig</code> will be clobbered.</p></td></tr></table></div><p id="x_e6"><a name="x_e6"></a>Here is a summary of the cases that the <span class="command"><strong>hg revert</strong></span> command can deal with. We
|
||||
will describe each of these in more detail in the section that
|
||||
follows.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_e7"><a name="x_e7"></a>If you modify a file, it will restore the file
|
||||
to its unmodified state.</p></li><li><p id="x_e8"><a name="x_e8"></a>If you <span class="command"><strong>hg add</strong></span> a
|
||||
file, it will undo the “<span class="quote">added</span>” state of the
|
||||
file, but leave the file itself untouched.</p></li><li><p id="x_e9"><a name="x_e9"></a>If you delete a file without telling Mercurial,
|
||||
it will restore the file to its unmodified contents.</p></li><li><p id="x_ea"><a name="x_ea"></a>If you use the <span class="command"><strong>hg
|
||||
remove</strong></span> command to remove a file, it will undo
|
||||
the “<span class="quote">removed</span>” state of the file, and restore
|
||||
the file to its unmodified contents.</p></li></ul></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:undo:mgmt">File management errors</h3></div></div></div><p id="x_eb"><a name="x_eb"></a>The <span class="command"><strong>hg revert</strong></span> command is
|
||||
useful for more than just modified files. It lets you reverse
|
||||
the results of all of Mercurial's file management
|
||||
commands—<span class="command"><strong>hg add</strong></span>,
|
||||
<span class="command"><strong>hg remove</strong></span>, and so on.</p><p id="x_ec"><a name="x_ec"></a>If you <span class="command"><strong>hg add</strong></span> a file,
|
||||
then decide that in fact you don't want Mercurial to track it,
|
||||
use <span class="command"><strong>hg revert</strong></span> to undo the
|
||||
add. Don't worry; Mercurial will not modify the file in any
|
||||
way. It will just “<span class="quote">unmark</span>” the file.</p><pre id="id391756" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo oops > oops</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add oops</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status oops</code></strong>
|
||||
A oops
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg revert oops</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
? oops
|
||||
</pre><p id="x_ed"><a name="x_ed"></a>Similarly, if you ask Mercurial to <span class="command"><strong>hg remove</strong></span> a file, you can use
|
||||
<span class="command"><strong>hg revert</strong></span> to restore it to
|
||||
the contents it had as of the parent of the working directory.
|
||||
|
||||
</p><pre id="id392036" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg remove file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
R file
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg revert file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls file</code></strong>
|
||||
file
|
||||
</pre><p>
|
||||
|
||||
This works just as
|
||||
well for a file that you deleted by hand, without telling
|
||||
Mercurial (recall that in Mercurial terminology, this kind of
|
||||
file is called “<span class="quote">missing</span>”).</p><pre id="id391954" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>rm file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
! file
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg revert file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls file</code></strong>
|
||||
file
|
||||
</pre><p id="x_ee"><a name="x_ee"></a>If you revert a <span class="command"><strong>hg copy</strong></span>,
|
||||
the copied-to file remains in your working directory
|
||||
afterwards, untracked. Since a copy doesn't affect the
|
||||
copied-from file in any way, Mercurial doesn't do anything
|
||||
with the copied-from file.</p><pre id="id392181" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg copy file new-file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg revert new-file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
? new-file
|
||||
</pre></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id392218">Dealing with committed changes</h2></div></div></div><p id="x_f5"><a name="x_f5"></a>Consider a case where you have committed a change
|
||||
<span class="emphasis"><em>a</em></span>, and another change
|
||||
<span class="emphasis"><em>b</em></span> on top of it; you then realise that
|
||||
change <span class="emphasis"><em>a</em></span> was incorrect. Mercurial lets you
|
||||
“<span class="quote">back out</span>” an entire changeset automatically, and
|
||||
building blocks that let you reverse part of a changeset by
|
||||
hand.</p><p id="x_f6"><a name="x_f6"></a>Before you read this section, here's something to
|
||||
keep in mind: the <span class="command"><strong>hg backout</strong></span>
|
||||
command undoes the effect of a change by
|
||||
<span class="emphasis"><em>adding</em></span> to your repository's history, not by
|
||||
modifying or erasing it. It's the right tool to use if you're
|
||||
fixing bugs, but not if you're trying to undo some change that
|
||||
has catastrophic consequences. To deal with those, see
|
||||
<a class="xref" href="finding-and-fixing-mistakes.html#sec:undo:aaaiiieee" title="Changes that should never have been">the section called “Changes that should never have been”</a>.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id392287">Backing out a changeset</h3></div></div></div><p id="x_f7"><a name="x_f7"></a>The <span class="command"><strong>hg backout</strong></span> command
|
||||
lets you “<span class="quote">undo</span>” the effects of an entire
|
||||
changeset in an automated fashion. Because Mercurial's
|
||||
history is immutable, this command <span class="emphasis"><em>does
|
||||
not</em></span> get rid of the changeset you want to undo.
|
||||
Instead, it creates a new changeset that
|
||||
<span class="emphasis"><em>reverses</em></span> the effect of the to-be-undone
|
||||
changeset.</p><p id="x_f8"><a name="x_f8"></a>The operation of the <span class="command"><strong>hg
|
||||
backout</strong></span> command is a little intricate, so let's
|
||||
illustrate it with some examples. First, we'll create a
|
||||
repository with some simple changes.</p><pre id="id392685" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init myrepo</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd myrepo</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo first change >> myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'first change'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo second change >> myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'second change'</code></strong>
|
||||
</pre><p id="x_f9"><a name="x_f9"></a>The <span class="command"><strong>hg backout</strong></span> command
|
||||
takes a single changeset ID as its argument; this is the
|
||||
changeset to back out. Normally, <span class="command"><strong>hg
|
||||
backout</strong></span> will drop you into a text editor to write
|
||||
a commit message, so you can record why you're backing the
|
||||
change out. In this example, we provide a commit message on
|
||||
the command line using the <code class="option">-m</code> option.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id392424">Backing out the tip changeset</h3></div></div></div><p id="x_fa"><a name="x_fa"></a>We're going to start by backing out the last changeset we
|
||||
committed.</p><pre id="id392577" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg backout -m 'back out second change' tip</code></strong>
|
||||
reverting myfile
|
||||
changeset 2:01adc4672142 backs out changeset 1:7e341ee3be7a
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
|
||||
first change
|
||||
</pre><p id="x_fb"><a name="x_fb"></a>You can see that the second line from
|
||||
<code class="filename">myfile</code> is no longer present. Taking a
|
||||
look at the output of <span class="command"><strong>hg log</strong></span>
|
||||
gives us an idea of what the <span class="command"><strong>hg
|
||||
backout</strong></span> command has done.
|
||||
|
||||
</p><pre id="id392554" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log --style compact</code></strong>
|
||||
2[tip] 01adc4672142 2009-05-05 06:55 +0000 bos
|
||||
back out second change
|
||||
|
||||
1 7e341ee3be7a 2009-05-05 06:55 +0000 bos
|
||||
second change
|
||||
|
||||
0 56b97fc928f2 2009-05-05 06:55 +0000 bos
|
||||
first change
|
||||
|
||||
</pre><p>
|
||||
|
||||
Notice that the new changeset
|
||||
that <span class="command"><strong>hg backout</strong></span> has created
|
||||
is a child of the changeset we backed out. It's easier to see
|
||||
this in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:backout" title="Figure 9.1. Backing out a change using the hg backout command">Figure 9.1, “Backing out a change using the hg backout command”</a>, which presents a
|
||||
graphical view of the change history. As you can see, the
|
||||
history is nice and linear.</p><div class="figure"><a name="fig:undo:backout"></a><p class="title"><b>Figure 9.1. Backing out a change using the <span class="command">hg backout</span> command</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/undo-simple.png" alt="XXX add text"></div></div></div><br class="figure-break"></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id392766">Backing out a non-tip change</h3></div></div></div><p id="x_fd"><a name="x_fd"></a>If you want to back out a change other than the last one
|
||||
you committed, pass the <code class="option">--merge</code> option to the
|
||||
<span class="command"><strong>hg backout</strong></span> command.</p><pre id="id393141" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone -r1 myrepo non-tip-repo</code></strong>
|
||||
requesting all changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 2 changesets with 2 changes to 1 files
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd non-tip-repo</code></strong>
|
||||
</pre><p id="x_fe"><a name="x_fe"></a>This makes backing out any changeset a
|
||||
“<span class="quote">one-shot</span>” operation that's usually simple and
|
||||
fast.</p><pre id="id392845" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo third change >> myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'third change'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg backout --merge -m 'back out second change' 1</code></strong>
|
||||
reverting myfile
|
||||
created new head
|
||||
changeset 3:abc7fd860049 backs out changeset 1:7e341ee3be7a
|
||||
merging with changeset 3:abc7fd860049
|
||||
merging myfile
|
||||
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
|
||||
(branch merge, don't forget to commit)
|
||||
</pre><p id="x_ff"><a name="x_ff"></a>If you take a look at the contents of
|
||||
<code class="filename">myfile</code> after the backout finishes, you'll
|
||||
see that the first and third changes are present, but not the
|
||||
second.</p><pre id="id392886" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
|
||||
first change
|
||||
third change
|
||||
</pre><p id="x_100"><a name="x_100"></a>As the graphical history in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:backout-non-tip" title="Figure 9.2. Automated backout of a non-tip change using the hg backout command">Figure 9.2, “Automated backout of a non-tip change using the
|
||||
hg backout command”</a> illustrates, Mercurial
|
||||
still commits one change in this kind of situation (the
|
||||
box-shaped node is the ones that Mercurial commits
|
||||
automatically), but the revision graph now looks different.
|
||||
Before Mercurial begins the backout process, it first
|
||||
remembers what the current parent of the working directory is.
|
||||
It then backs out the target changeset, and commits that as a
|
||||
changeset. Finally, it merges back to the previous parent of
|
||||
the working directory, but notice that it <span class="emphasis"><em>does not
|
||||
commit</em></span> the result of the merge. The repository
|
||||
now contains two heads, and the working directory is in a
|
||||
merge state.</p><div class="figure"><a name="fig:undo:backout-non-tip"></a><p class="title"><b>Figure 9.2. Automated backout of a non-tip change using the
|
||||
<span class="command">hg backout</span> command</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/undo-non-tip.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_103"><a name="x_103"></a>The result is that you end up “<span class="quote">back where you
|
||||
were</span>”, only with some extra history that undoes the
|
||||
effect of the changeset you wanted to back out.</p><p id="x_6b9"><a name="x_6b9"></a>You might wonder why Mercurial does not commit the result
|
||||
of the merge that it performed. The reason lies in Mercurial
|
||||
behaving conservatively: a merge naturally has more scope for
|
||||
error than simply undoing the effect of the tip changeset,
|
||||
so your work will be safest if you first inspect (and test!)
|
||||
the result of the merge, <span class="emphasis"><em>then</em></span> commit
|
||||
it.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id392990">Always use the <code class="option">--merge</code> option</h4></div></div></div><p id="x_104"><a name="x_104"></a>In fact, since the <code class="option">--merge</code> option will do the
|
||||
“<span class="quote">right thing</span>” whether or not the changeset
|
||||
you're backing out is the tip (i.e. it won't try to merge if
|
||||
it's backing out the tip, since there's no need), you should
|
||||
<span class="emphasis"><em>always</em></span> use this option when you run the
|
||||
<span class="command"><strong>hg backout</strong></span> command.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id393181">Gaining more control of the backout process</h3></div></div></div><p id="x_105"><a name="x_105"></a>While I've recommended that you always use the <code class="option">--merge</code> option when backing
|
||||
out a change, the <span class="command"><strong>hg backout</strong></span>
|
||||
command lets you decide how to merge a backout changeset.
|
||||
Taking control of the backout process by hand is something you
|
||||
will rarely need to do, but it can be useful to understand
|
||||
what the <span class="command"><strong>hg backout</strong></span> command
|
||||
is doing for you automatically. To illustrate this, let's
|
||||
clone our first repository, but omit the backout change that
|
||||
it contains.</p><pre id="id393568" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone -r1 myrepo newrepo</code></strong>
|
||||
requesting all changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 2 changesets with 2 changes to 1 files
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd newrepo</code></strong>
|
||||
</pre><p id="x_106"><a name="x_106"></a>As with our
|
||||
earlier example, We'll commit a third changeset, then back out
|
||||
its parent, and see what happens.</p><pre id="id393553" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo third change >> myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'third change'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg backout -m 'back out second change' 1</code></strong>
|
||||
reverting myfile
|
||||
created new head
|
||||
changeset 3:abc7fd860049 backs out changeset 1:7e341ee3be7a
|
||||
the backout changeset is a new head - do not forget to merge
|
||||
(use "backout --merge" if you want to auto-merge)
|
||||
</pre><p id="x_107"><a name="x_107"></a>Our new changeset is again a descendant of the changeset
|
||||
we backout out; it's thus a new head, <span class="emphasis"><em>not</em></span>
|
||||
a descendant of the changeset that was the tip. The <span class="command"><strong>hg backout</strong></span> command was quite
|
||||
explicit in telling us this.</p><pre id="id393314" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log --style compact</code></strong>
|
||||
3[tip]:1 abc7fd860049 2009-05-05 06:55 +0000 bos
|
||||
back out second change
|
||||
|
||||
2 bae4005ddac4 2009-05-05 06:55 +0000 bos
|
||||
third change
|
||||
|
||||
1 7e341ee3be7a 2009-05-05 06:55 +0000 bos
|
||||
second change
|
||||
|
||||
0 56b97fc928f2 2009-05-05 06:55 +0000 bos
|
||||
first change
|
||||
|
||||
</pre><p id="x_108"><a name="x_108"></a>Again, it's easier to see what has happened by looking at
|
||||
a graph of the revision history, in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:backout-manual" title="Figure 9.3. Backing out a change using the hg backout command">Figure 9.3, “Backing out a change using the hg backout command”</a>. This makes it clear
|
||||
that when we use <span class="command"><strong>hg backout</strong></span>
|
||||
to back out a change other than the tip, Mercurial adds a new
|
||||
head to the repository (the change it committed is
|
||||
box-shaped).</p><div class="figure"><a name="fig:undo:backout-manual"></a><p class="title"><b>Figure 9.3. Backing out a change using the <span class="command">hg backout</span> command</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/undo-manual.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_10a"><a name="x_10a"></a>After the <span class="command"><strong>hg backout</strong></span>
|
||||
command has completed, it leaves the new
|
||||
“<span class="quote">backout</span>” changeset as the parent of the working
|
||||
directory.</p><pre id="id393912" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong>
|
||||
changeset: 2:bae4005ddac4
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:12 2009 +0000
|
||||
summary: third change
|
||||
|
||||
</pre><p id="x_10b"><a name="x_10b"></a>Now we have two isolated sets of changes.</p><pre id="id393905" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg heads</code></strong>
|
||||
changeset: 3:abc7fd860049
|
||||
tag: tip
|
||||
parent: 1:7e341ee3be7a
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:12 2009 +0000
|
||||
summary: back out second change
|
||||
|
||||
changeset: 2:bae4005ddac4
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:12 2009 +0000
|
||||
summary: third change
|
||||
|
||||
</pre><p id="x_10c"><a name="x_10c"></a>Let's think about what we expect to see as the contents of
|
||||
<code class="filename">myfile</code> now. The first change should be
|
||||
present, because we've never backed it out. The second change
|
||||
should be missing, as that's the change we backed out. Since
|
||||
the history graph shows the third change as a separate head,
|
||||
we <span class="emphasis"><em>don't</em></span> expect to see the third change
|
||||
present in <code class="filename">myfile</code>.</p><pre id="id393884" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
|
||||
first change
|
||||
</pre><p id="x_10d"><a name="x_10d"></a>To get the third change back into the file, we just do a
|
||||
normal merge of our two heads.</p><pre id="id393845" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
|
||||
abort: outstanding uncommitted changes
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'merged backout with previous tip'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat myfile</code></strong>
|
||||
first change
|
||||
</pre><p id="x_10e"><a name="x_10e"></a>Afterwards, the graphical history of our
|
||||
repository looks like
|
||||
<a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:backout-manual-merge" title="Figure 9.4. Manually merging a backout change">Figure 9.4, “Manually merging a backout change”</a>.</p><div class="figure"><a name="fig:undo:backout-manual-merge"></a><p class="title"><b>Figure 9.4. Manually merging a backout change</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/undo-manual-merge.png" alt="XXX add text"></div></div></div><br class="figure-break"></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id393814">Why <span class="command"><strong>hg backout</strong></span> works as
|
||||
it does</h3></div></div></div><p id="x_110"><a name="x_110"></a>Here's a brief description of how the <span class="command"><strong>hg backout</strong></span> command works.</p><div class="orderedlist"><ol type="1"><li><p id="x_111"><a name="x_111"></a>It ensures that the working directory is
|
||||
“<span class="quote">clean</span>”, i.e. that the output of <span class="command"><strong>hg status</strong></span> would be empty.</p></li><li><p id="x_112"><a name="x_112"></a>It remembers the current parent of the working
|
||||
directory. Let's call this changeset
|
||||
<code class="literal">orig</code>.</p></li><li><p id="x_113"><a name="x_113"></a>It does the equivalent of a <span class="command"><strong>hg update</strong></span> to sync the working
|
||||
directory to the changeset you want to back out. Let's
|
||||
call this changeset <code class="literal">backout</code>.</p></li><li><p id="x_114"><a name="x_114"></a>It finds the parent of that changeset. Let's
|
||||
call that changeset <code class="literal">parent</code>.</p></li><li><p id="x_115"><a name="x_115"></a>For each file that the
|
||||
<code class="literal">backout</code> changeset affected, it does the
|
||||
equivalent of a <span class="command"><strong>hg revert -r
|
||||
parent</strong></span> on that file, to restore it to the
|
||||
contents it had before that changeset was
|
||||
committed.</p></li><li><p id="x_116"><a name="x_116"></a>It commits the result as a new changeset.
|
||||
This changeset has <code class="literal">backout</code> as its
|
||||
parent.</p></li><li><p id="x_117"><a name="x_117"></a>If you specify <code class="option">--merge</code> on the command
|
||||
line, it merges with <code class="literal">orig</code>, and commits
|
||||
the result of the merge.</p></li></ol></div><p id="x_118"><a name="x_118"></a>An alternative way to implement the <span class="command"><strong>hg backout</strong></span> command would be to
|
||||
<span class="command"><strong>hg export</strong></span> the
|
||||
to-be-backed-out changeset as a diff, then use the <code class="option">--reverse</code> option to the
|
||||
<span class="command"><strong>patch</strong></span> command to reverse the effect of the
|
||||
change without fiddling with the working directory. This
|
||||
sounds much simpler, but it would not work nearly as
|
||||
well.</p><p id="x_119"><a name="x_119"></a>The reason that <span class="command"><strong>hg
|
||||
backout</strong></span> does an update, a commit, a merge, and
|
||||
another commit is to give the merge machinery the best chance
|
||||
to do a good job when dealing with all the changes
|
||||
<span class="emphasis"><em>between</em></span> the change you're backing out and
|
||||
the current tip.</p><p id="x_11a"><a name="x_11a"></a>If you're backing out a changeset that's 100 revisions
|
||||
back in your project's history, the chances that the
|
||||
<span class="command"><strong>patch</strong></span> command will be able to apply a
|
||||
reverse diff cleanly are not good, because intervening changes
|
||||
are likely to have “<span class="quote">broken the context</span>” that
|
||||
<span class="command"><strong>patch</strong></span> uses to determine whether it can
|
||||
apply a patch (if this sounds like gibberish, see <a class="xref" href="managing-change-with-mercurial-queues.html#sec:mq:patch" title="Understanding patches">the section called “Understanding patches”</a> for a
|
||||
discussion of the <span class="command"><strong>patch</strong></span> command). Also,
|
||||
Mercurial's merge machinery will handle files and directories
|
||||
being renamed, permission changes, and modifications to binary
|
||||
files, none of which <span class="command"><strong>patch</strong></span> can deal
|
||||
with.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:undo:aaaiiieee">Changes that should never have been</h2></div></div></div><p id="x_11b"><a name="x_11b"></a>Most of the time, the <span class="command"><strong>hg
|
||||
backout</strong></span> command is exactly what you need if you want
|
||||
to undo the effects of a change. It leaves a permanent record
|
||||
of exactly what you did, both when committing the original
|
||||
changeset and when you cleaned up after it.</p><p id="x_11c"><a name="x_11c"></a>On rare occasions, though, you may find that you've
|
||||
committed a change that really should not be present in the
|
||||
repository at all. For example, it would be very unusual, and
|
||||
usually considered a mistake, to commit a software project's
|
||||
object files as well as its source files. Object files have
|
||||
almost no intrinsic value, and they're <span class="emphasis"><em>big</em></span>,
|
||||
so they increase the size of the repository and the amount of
|
||||
time it takes to clone or pull changes.</p><p id="x_11d"><a name="x_11d"></a>Before I discuss the options that you have if you commit a
|
||||
“<span class="quote">brown paper bag</span>” change (the kind that's so bad
|
||||
that you want to pull a brown paper bag over your head), let me
|
||||
first discuss some approaches that probably won't work.</p><p id="x_11e"><a name="x_11e"></a>Since Mercurial treats history as
|
||||
accumulative—every change builds on top of all changes
|
||||
that preceded it—you generally can't just make disastrous
|
||||
changes disappear. The one exception is when you've just
|
||||
committed a change, and it hasn't been pushed or pulled into
|
||||
another repository. That's when you can safely use the <span class="command"><strong>hg rollback</strong></span> command, as I detailed in
|
||||
<a class="xref" href="finding-and-fixing-mistakes.html#sec:undo:rollback" title="Rolling back a transaction">the section called “Rolling back a transaction”</a>.</p><p id="x_11f"><a name="x_11f"></a>After you've pushed a bad change to another repository, you
|
||||
<span class="emphasis"><em>could</em></span> still use <span class="command"><strong>hg
|
||||
rollback</strong></span> to make your local copy of the change
|
||||
disappear, but it won't have the consequences you want. The
|
||||
change will still be present in the remote repository, so it
|
||||
will reappear in your local repository the next time you
|
||||
pull.</p><p id="x_120"><a name="x_120"></a>If a situation like this arises, and you know which
|
||||
repositories your bad change has propagated into, you can
|
||||
<span class="emphasis"><em>try</em></span> to get rid of the change from
|
||||
<span class="emphasis"><em>every</em></span> one of those repositories. This is,
|
||||
of course, not a satisfactory solution: if you miss even a
|
||||
single repository while you're expunging, the change is still
|
||||
“<span class="quote">in the wild</span>”, and could propagate further.</p><p id="x_121"><a name="x_121"></a>If you've committed one or more changes
|
||||
<span class="emphasis"><em>after</em></span> the change that you'd like to see
|
||||
disappear, your options are further reduced. Mercurial doesn't
|
||||
provide a way to “<span class="quote">punch a hole</span>” in history, leaving
|
||||
changesets intact.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id394303">Backing out a merge</h3></div></div></div><p id="x_6ba"><a name="x_6ba"></a>Since merges are often complicated, it is not unheard of
|
||||
for a merge to be mangled badly, but committed erroneously.
|
||||
Mercurial provides an important safeguard against bad merges
|
||||
by refusing to commit unresolved files, but human ingenuity
|
||||
guarantees that it is still possible to mess a merge up and
|
||||
commit it.</p><p id="x_6bb"><a name="x_6bb"></a>Given a bad merge that has been committed, usually the
|
||||
best way to approach it is to simply try to repair the damage
|
||||
by hand. A complete disaster that cannot be easily fixed up
|
||||
by hand ought to be very rare, but the <span class="command"><strong>hg backout</strong></span> command may help in
|
||||
making the cleanup easier. It offers a <code class="option">--parent</code> option, which lets
|
||||
you specify which parent to revert to when backing out a
|
||||
merge.</p><div class="figure"><a name="fig:undo:bad-merge-1"></a><p class="title"><b>Figure 9.5. A bad merge</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-1.png" alt="XXX add text"></div></div></div><br class="figure-break"><p id="x_6bc"><a name="x_6bc"></a>Suppose we have a revision graph like that in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-1" title="Figure 9.5. A bad merge">Figure 9.5, “A bad merge”</a>. What we'd like is to
|
||||
<span class="emphasis"><em>redo</em></span> the merge of revisions 2 and
|
||||
3.</p><p id="x_6bd"><a name="x_6bd"></a>One way to do so would be as follows.</p><div class="orderedlist"><ol type="1"><li><p id="x_6be"><a name="x_6be"></a>Call <span class="command"><strong>hg backout --rev=4
|
||||
--parent=2</strong></span>. This tells <span class="command"><strong>hg backout</strong></span> to back out revision
|
||||
4, which is the bad merge, and to when deciding which
|
||||
revision to prefer, to choose parent 2, one of the parents
|
||||
of the merge. The effect can be seen in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-2" title="Figure 9.6. Backing out the merge, favoring one parent">Figure 9.6, “Backing out the merge, favoring one parent”</a>.</p><div class="figure"><a name="fig:undo:bad-merge-2"></a><p class="title"><b>Figure 9.6. Backing out the merge, favoring one parent</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-2.png" alt="XXX add text"></div></div></div><br class="figure-break"></li><li><p id="x_6bf"><a name="x_6bf"></a>Call <span class="command"><strong>hg backout --rev=4
|
||||
--parent=3</strong></span>. This tells <span class="command"><strong>hg backout</strong></span> to back out revision
|
||||
4 again, but this time to choose parent 3, the other
|
||||
parent of the merge. The result is visible in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-3" title="Figure 9.7. Backing out the merge, favoring the other parent">Figure 9.7, “Backing out the merge, favoring the other
|
||||
parent”</a>, in which the repository
|
||||
now contains three heads.</p><div class="figure"><a name="fig:undo:bad-merge-3"></a><p class="title"><b>Figure 9.7. Backing out the merge, favoring the other
|
||||
parent</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-3.png" alt="XXX add text"></div></div></div><br class="figure-break"></li><li><p id="x_6c0"><a name="x_6c0"></a>Redo the bad merge by merging the two backout heads,
|
||||
which reduces the number of heads in the repository to
|
||||
two, as can be seen in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-4" title="Figure 9.8. Merging the backouts">Figure 9.8, “Merging the backouts”</a>.</p><div class="figure"><a name="fig:undo:bad-merge-4"></a><p class="title"><b>Figure 9.8. Merging the backouts</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-4.png" alt="XXX add text"></div></div></div><br class="figure-break"></li><li><p id="x_6c1"><a name="x_6c1"></a>Merge with the commit that was made after the bad
|
||||
merge, as shown in <a class="xref" href="finding-and-fixing-mistakes.html#fig:undo:bad-merge-5" title="Figure 9.9. Merging the backouts">Figure 9.9, “Merging the backouts”</a>.</p><div class="figure"><a name="fig:undo:bad-merge-5"></a><p class="title"><b>Figure 9.9. Merging the backouts</b></p><div class="figure-contents"><div class="mediaobject"><img src="figs/bad-merge-5.png" alt="XXX add text"></div></div></div><br class="figure-break"></li></ol></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id394612">Protect yourself from “<span class="quote">escaped</span>”
|
||||
changes</h3></div></div></div><p id="x_123"><a name="x_123"></a>If you've committed some changes to your local repository
|
||||
and they've been pushed or pulled somewhere else, this isn't
|
||||
necessarily a disaster. You can protect yourself ahead of
|
||||
time against some classes of bad changeset. This is
|
||||
particularly easy if your team usually pulls changes from a
|
||||
central repository.</p><p id="x_124"><a name="x_124"></a>By configuring some hooks on that repository to validate
|
||||
incoming changesets (see chapter <a class="xref" href="handling-repository-events-with-hooks.html" title="Chapter 10. Handling repository events with hooks">Chapter 10, <i>Handling repository events with hooks</i></a>),
|
||||
you can
|
||||
automatically prevent some kinds of bad changeset from being
|
||||
pushed to the central repository at all. With such a
|
||||
configuration in place, some kinds of bad changeset will
|
||||
naturally tend to “<span class="quote">die out</span>” because they can't
|
||||
propagate into the central repository. Better yet, this
|
||||
happens without any need for explicit intervention.</p><p id="x_125"><a name="x_125"></a>For instance, an incoming change hook that
|
||||
verifies that a changeset will actually compile can prevent
|
||||
people from inadvertently “<span class="quote">breaking the
|
||||
build</span>”.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id394667">What to do about sensitive changes that escape</h3></div></div></div><p id="x_6c2"><a name="x_6c2"></a>Even a carefully run project can suffer an unfortunate
|
||||
event such as the committing and uncontrolled propagation of a
|
||||
file that contains important passwords.</p><p id="x_6c3"><a name="x_6c3"></a>If something like this happens to you, and the information
|
||||
that gets accidentally propagated is truly sensitive, your
|
||||
first step should be to mitigate the effect of the leak
|
||||
without trying to control the leak itself. If you are not 100%
|
||||
certain that you know exactly who could have seen the changes,
|
||||
you should immediately change passwords, cancel credit cards,
|
||||
or find some other way to make sure that the information that
|
||||
has leaked is no longer useful. In other words, assume that
|
||||
the change has propagated far and wide, and that there's
|
||||
nothing more you can do.</p><p id="x_6c4"><a name="x_6c4"></a>You might hope that there would be mechanisms you could
|
||||
use to either figure out who has seen a change or to erase the
|
||||
change permanently everywhere, but there are good reasons why
|
||||
these are not possible.</p><p id="x_6c5"><a name="x_6c5"></a>Mercurial does not provide an audit trail of who has
|
||||
pulled changes from a repository, because it is usually either
|
||||
impossible to record such information or trivial to spoof it.
|
||||
In a multi-user or networked environment, you should thus be
|
||||
extremely skeptical of yourself if you think that you have
|
||||
identified every place that a sensitive changeset has
|
||||
propagated to. Don't forget that people can and will send
|
||||
bundles by email, have their backup software save data
|
||||
offsite, carry repositories on USB sticks, and find other
|
||||
completely innocent ways to confound your attempts to track
|
||||
down every copy of a problematic change.</p><p id="x_6c6"><a name="x_6c6"></a>Mercurial also does not provide a way to make a file or
|
||||
changeset completely disappear from history, because there is
|
||||
no way to enforce its disappearance; someone could easily
|
||||
modify their copy of Mercurial to ignore such directives. In
|
||||
addition, even if Mercurial provided such a capability,
|
||||
someone who simply hadn't pulled a “<span class="quote">make this file
|
||||
disappear</span>” changeset wouldn't be affected by it, nor
|
||||
would web crawlers visiting at the wrong time, disk backups,
|
||||
or other mechanisms. Indeed, no distributed revision control
|
||||
system can make data reliably vanish. Providing the illusion
|
||||
of such control could easily give a false sense of security,
|
||||
and be worse than not providing it at all.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:undo:bisect">Finding the source of a bug</h2></div></div></div><p id="x_126"><a name="x_126"></a>While it's all very well to be able to back out a changeset
|
||||
that introduced a bug, this requires that you know which
|
||||
changeset to back out. Mercurial provides an invaluable
|
||||
command, called <span class="command"><strong>hg bisect</strong></span>, that
|
||||
helps you to automate this process and accomplish it very
|
||||
efficiently.</p><p id="x_127"><a name="x_127"></a>The idea behind the <span class="command"><strong>hg
|
||||
bisect</strong></span> command is that a changeset has introduced
|
||||
some change of behavior that you can identify with a simple
|
||||
pass/fail test. You don't know which piece of code introduced the
|
||||
change, but you know how to test for the presence of the bug.
|
||||
The <span class="command"><strong>hg bisect</strong></span> command uses your
|
||||
test to direct its search for the changeset that introduced the
|
||||
code that caused the bug.</p><p id="x_128"><a name="x_128"></a>Here are a few scenarios to help you understand how you
|
||||
might apply this command.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_129"><a name="x_129"></a>The most recent version of your software has a
|
||||
bug that you remember wasn't present a few weeks ago, but
|
||||
you don't know when it was introduced. Here, your binary
|
||||
test checks for the presence of that bug.</p></li><li><p id="x_12a"><a name="x_12a"></a>You fixed a bug in a rush, and now it's time to
|
||||
close the entry in your team's bug database. The bug
|
||||
database requires a changeset ID when you close an entry,
|
||||
but you don't remember which changeset you fixed the bug in.
|
||||
Once again, your binary test checks for the presence of the
|
||||
bug.</p></li><li><p id="x_12b"><a name="x_12b"></a>Your software works correctly, but runs 15%
|
||||
slower than the last time you measured it. You want to know
|
||||
which changeset introduced the performance regression. In
|
||||
this case, your binary test measures the performance of your
|
||||
software, to see whether it's “<span class="quote">fast</span>” or
|
||||
“<span class="quote">slow</span>”.</p></li><li><p id="x_12c"><a name="x_12c"></a>The sizes of the components of your project that
|
||||
you ship exploded recently, and you suspect that something
|
||||
changed in the way you build your project.</p></li></ul></div><p id="x_12d"><a name="x_12d"></a>From these examples, it should be clear that the <span class="command"><strong>hg bisect</strong></span> command is not useful only
|
||||
for finding the sources of bugs. You can use it to find any
|
||||
“<span class="quote">emergent property</span>” of a repository (anything that
|
||||
you can't find from a simple text search of the files in the
|
||||
tree) for which you can write a binary test.</p><p id="x_12e"><a name="x_12e"></a>We'll introduce a little bit of terminology here, just to
|
||||
make it clear which parts of the search process are your
|
||||
responsibility, and which are Mercurial's. A
|
||||
<span class="emphasis"><em>test</em></span> is something that
|
||||
<span class="emphasis"><em>you</em></span> run when <span class="command"><strong>hg
|
||||
bisect</strong></span> chooses a changeset. A
|
||||
<span class="emphasis"><em>probe</em></span> is what <span class="command"><strong>hg
|
||||
bisect</strong></span> runs to tell whether a revision is good.
|
||||
Finally, we'll use the word “<span class="quote">bisect</span>”, as both a
|
||||
noun and a verb, to stand in for the phrase “<span class="quote">search using
|
||||
the <span class="command"><strong>hg bisect</strong></span>
|
||||
command</span>”.</p><p id="x_12f"><a name="x_12f"></a>One simple way to automate the searching process would be
|
||||
simply to probe every changeset. However, this scales poorly.
|
||||
If it took ten minutes to test a single changeset, and you had
|
||||
10,000 changesets in your repository, the exhaustive approach
|
||||
would take on average 35 <span class="emphasis"><em>days</em></span> to find the
|
||||
changeset that introduced a bug. Even if you knew that the bug
|
||||
was introduced by one of the last 500 changesets, and limited
|
||||
your search to those, you'd still be looking at over 40 hours to
|
||||
find the changeset that introduced your bug.</p><p id="x_130"><a name="x_130"></a>What the <span class="command"><strong>hg bisect</strong></span> command
|
||||
does is use its knowledge of the “<span class="quote">shape</span>” of your
|
||||
project's revision history to perform a search in time
|
||||
proportional to the <span class="emphasis"><em>logarithm</em></span> of the number
|
||||
of changesets to check (the kind of search it performs is called
|
||||
a dichotomic search). With this approach, searching through
|
||||
10,000 changesets will take less than three hours, even at ten
|
||||
minutes per test (the search will require about 14 tests).
|
||||
Limit your search to the last hundred changesets, and it will
|
||||
take only about an hour (roughly seven tests).</p><p id="x_131"><a name="x_131"></a>The <span class="command"><strong>hg bisect</strong></span> command is
|
||||
aware of the “<span class="quote">branchy</span>” nature of a Mercurial
|
||||
project's revision history, so it has no problems dealing with
|
||||
branches, merges, or multiple heads in a repository. It can
|
||||
prune entire branches of history with a single probe, which is
|
||||
how it operates so efficiently.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id394992">Using the <span class="command"><strong>hg bisect</strong></span>
|
||||
command</h3></div></div></div><p id="x_132"><a name="x_132"></a>Here's an example of <span class="command"><strong>hg
|
||||
bisect</strong></span> in action.</p><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_133"><a name="x_133"></a> In versions 0.9.5 and earlier of Mercurial, <span class="command"><strong>hg bisect</strong></span> was not a core command:
|
||||
it was distributed with Mercurial as an extension. This
|
||||
section describes the built-in command, not the old
|
||||
extension.</p></td></tr></table></div><p id="x_134"><a name="x_134"></a>Now let's create a repository, so that we can try out the
|
||||
<span class="command"><strong>hg bisect</strong></span> command in
|
||||
isolation.</p><pre id="id395406" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init mybug</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd mybug</code></strong>
|
||||
</pre><p id="x_135"><a name="x_135"></a>We'll simulate a project that has a bug in it in a
|
||||
simple-minded way: create trivial changes in a loop, and
|
||||
nominate one specific change that will have the
|
||||
“<span class="quote">bug</span>”. This loop creates 35 changesets, each
|
||||
adding a single file to the repository. We'll represent our
|
||||
“<span class="quote">bug</span>” with a file that contains the text “<span class="quote">i
|
||||
have a gub</span>”.</p><pre id="id395397" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>buggy_change=22</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>for (( i = 0; i < 35; i++ )); do</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> if [[ $i = $buggy_change ]]; then</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> echo 'i have a gub' > myfile$i</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> hg commit -q -A -m 'buggy changeset'</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> else</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> echo 'nothing to see here, move along' > myfile$i</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> hg commit -q -A -m 'normal changeset'</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> fi</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>done</code></strong>
|
||||
</pre><p id="x_136"><a name="x_136"></a>The next thing that we'd like to do is figure out how to
|
||||
use the <span class="command"><strong>hg bisect</strong></span> command.
|
||||
We can use Mercurial's normal built-in help mechanism for
|
||||
this.</p><pre id="id395535" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg help bisect</code></strong>
|
||||
hg bisect [-gbsr] [-c CMD] [REV]
|
||||
|
||||
subdivision search of changesets
|
||||
|
||||
This command helps to find changesets which introduce problems.
|
||||
To use, mark the earliest changeset you know exhibits the problem
|
||||
as bad, then mark the latest changeset which is free from the
|
||||
problem as good. Bisect will update your working directory to a
|
||||
revision for testing (unless the --noupdate option is specified).
|
||||
Once you have performed tests, mark the working directory as bad
|
||||
or good and bisect will either update to another candidate changeset
|
||||
or announce that it has found the bad revision.
|
||||
|
||||
As a shortcut, you can also use the revision argument to mark a
|
||||
revision as good or bad without checking it out first.
|
||||
|
||||
If you supply a command it will be used for automatic bisection. Its exit
|
||||
status will be used as flag to mark revision as bad or good. In case exit
|
||||
status is 0 the revision is marked as good, 125 - skipped, 127 (command not
|
||||
found) - bisection will be aborted; any other status bigger than 0 will
|
||||
mark revision as bad.
|
||||
|
||||
options:
|
||||
|
||||
-r --reset reset bisect state
|
||||
-g --good mark changeset good
|
||||
-b --bad mark changeset bad
|
||||
-s --skip skip testing changeset
|
||||
-c --command use command to check changeset state
|
||||
-U --noupdate do not update to target
|
||||
|
||||
use "hg -v help bisect" to show global options
|
||||
</pre><p id="x_137"><a name="x_137"></a>The <span class="command"><strong>hg bisect</strong></span> command
|
||||
works in steps. Each step proceeds as follows.</p><div class="orderedlist"><ol type="1"><li><p id="x_138"><a name="x_138"></a>You run your binary test.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_139"><a name="x_139"></a>If the test succeeded, you tell <span class="command"><strong>hg bisect</strong></span> by running the
|
||||
<span class="command"><strong>hg bisect --good</strong></span>
|
||||
command.</p></li><li><p id="x_13a"><a name="x_13a"></a>If it failed, run the <span class="command"><strong>hg bisect --bad</strong></span>
|
||||
command.</p></li></ul></div></li><li><p id="x_13b"><a name="x_13b"></a>The command uses your information to decide
|
||||
which changeset to test next.</p></li><li><p id="x_13c"><a name="x_13c"></a>It updates the working directory to that
|
||||
changeset, and the process begins again.</p></li></ol></div><p id="x_13d"><a name="x_13d"></a>The process ends when <span class="command"><strong>hg
|
||||
bisect</strong></span> identifies a unique changeset that marks
|
||||
the point where your test transitioned from
|
||||
“<span class="quote">succeeding</span>” to “<span class="quote">failing</span>”.</p><p id="x_13e"><a name="x_13e"></a>To start the search, we must run the <span class="command"><strong>hg bisect --reset</strong></span> command.</p><pre id="id395968" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg bisect --reset</code></strong>
|
||||
</pre><p id="x_13f"><a name="x_13f"></a>In our case, the binary test we use is simple: we check to
|
||||
see if any file in the repository contains the string “<span class="quote">i
|
||||
have a gub</span>”. If it does, this changeset contains the
|
||||
change that “<span class="quote">caused the bug</span>”. By convention, a
|
||||
changeset that has the property we're searching for is
|
||||
“<span class="quote">bad</span>”, while one that doesn't is
|
||||
“<span class="quote">good</span>”.</p><p id="x_140"><a name="x_140"></a>Most of the time, the revision to which the working
|
||||
directory is synced (usually the tip) already exhibits the
|
||||
problem introduced by the buggy change, so we'll mark it as
|
||||
“<span class="quote">bad</span>”.</p><pre id="id396047" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg bisect --bad</code></strong>
|
||||
</pre><p id="x_141"><a name="x_141"></a>Our next task is to nominate a changeset that we know
|
||||
<span class="emphasis"><em>doesn't</em></span> have the bug; the <span class="command"><strong>hg bisect</strong></span> command will
|
||||
“<span class="quote">bracket</span>” its search between the first pair of
|
||||
good and bad changesets. In our case, we know that revision
|
||||
10 didn't have the bug. (I'll have more words about choosing
|
||||
the first “<span class="quote">good</span>” changeset later.)</p><pre id="id396032" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg bisect --good 10</code></strong>
|
||||
Testing changeset 22:b8789808fc48 (24 changesets remaining, ~4 tests)
|
||||
0 files updated, 0 files merged, 12 files removed, 0 files unresolved
|
||||
</pre><p id="x_142"><a name="x_142"></a>Notice that this command printed some output.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_143"><a name="x_143"></a>It told us how many changesets it must
|
||||
consider before it can identify the one that introduced
|
||||
the bug, and how many tests that will require.</p></li><li><p id="x_144"><a name="x_144"></a>It updated the working directory to the next
|
||||
changeset to test, and told us which changeset it's
|
||||
testing.</p></li></ul></div><p id="x_145"><a name="x_145"></a>We now run our test in the working directory. We use the
|
||||
<span class="command"><strong>grep</strong></span> command to see if our
|
||||
“<span class="quote">bad</span>” file is present in the working directory.
|
||||
If it is, this revision is bad; if not, this revision is good.
|
||||
|
||||
</p><pre id="id395911" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>if grep -q 'i have a gub' *</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>then</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> result=bad</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>else</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> result=good</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>fi</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo this revision is $result</code></strong>
|
||||
this revision is bad
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg bisect --$result</code></strong>
|
||||
Testing changeset 16:e61fdddff53e (12 changesets remaining, ~3 tests)
|
||||
0 files updated, 0 files merged, 6 files removed, 0 files unresolved
|
||||
</pre><p>
|
||||
|
||||
</p><p id="x_146"><a name="x_146"></a>This test looks like a perfect candidate for automation,
|
||||
so let's turn it into a shell function.</p><pre id="id396435" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mytest() {</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> if grep -q 'i have a gub' *</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> then</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> result=bad</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> else</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> result=good</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> fi</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> echo this revision is $result</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code> hg bisect --$result</code></strong>
|
||||
<code class="prompt">></code> <strong class="userinput"><code>}</code></strong>
|
||||
</pre><p id="x_147"><a name="x_147"></a>We can now run an entire test step with a single command,
|
||||
<code class="literal">mytest</code>.</p><pre id="id396403" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong>
|
||||
this revision is good
|
||||
Testing changeset 19:706df39b003b (6 changesets remaining, ~2 tests)
|
||||
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_148"><a name="x_148"></a>A few more invocations of our canned test step command,
|
||||
and we're done.</p><pre id="id396344" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong>
|
||||
this revision is good
|
||||
Testing changeset 20:bf7ea9a054e6 (3 changesets remaining, ~1 tests)
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong>
|
||||
this revision is good
|
||||
Testing changeset 21:921391dd45c1 (2 changesets remaining, ~1 tests)
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>mytest</code></strong>
|
||||
this revision is good
|
||||
The first bad revision is:
|
||||
changeset: 22:b8789808fc48
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:14 2009 +0000
|
||||
summary: buggy changeset
|
||||
|
||||
</pre><p id="x_149"><a name="x_149"></a>Even though we had 40 changesets to search through, the
|
||||
<span class="command"><strong>hg bisect</strong></span> command let us find
|
||||
the changeset that introduced our “<span class="quote">bug</span>” with only
|
||||
five tests. Because the number of tests that the <span class="command"><strong>hg bisect</strong></span> command performs grows
|
||||
logarithmically with the number of changesets to search, the
|
||||
advantage that it has over the “<span class="quote">brute force</span>”
|
||||
search approach increases with every changeset you add.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396541">Cleaning up after your search</h3></div></div></div><p id="x_14a"><a name="x_14a"></a>When you're finished using the <span class="command"><strong>hg
|
||||
bisect</strong></span> command in a repository, you can use the
|
||||
<span class="command"><strong>hg bisect --reset</strong></span> command to
|
||||
drop the information it was using to drive your search. The
|
||||
command doesn't use much space, so it doesn't matter if you
|
||||
forget to run this command. However, <span class="command"><strong>hg bisect</strong></span> won't let you start a new
|
||||
search in that repository until you do a <span class="command"><strong>hg bisect --reset</strong></span>.</p><pre id="id396936" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg bisect --reset</code></strong>
|
||||
</pre></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id396622">Tips for finding bugs effectively</h2></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396628">Give consistent input</h3></div></div></div><p id="x_14b"><a name="x_14b"></a>The <span class="command"><strong>hg bisect</strong></span> command
|
||||
requires that you correctly report the result of every test
|
||||
you perform. If you tell it that a test failed when it really
|
||||
succeeded, it <span class="emphasis"><em>might</em></span> be able to detect the
|
||||
inconsistency. If it can identify an inconsistency in your
|
||||
reports, it will tell you that a particular changeset is both
|
||||
good and bad. However, it can't do this perfectly; it's about
|
||||
as likely to report the wrong changeset as the source of the
|
||||
bug.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396884">Automate as much as possible</h3></div></div></div><p id="x_14c"><a name="x_14c"></a>When I started using the <span class="command"><strong>hg
|
||||
bisect</strong></span> command, I tried a few times to run my
|
||||
tests by hand, on the command line. This is an approach that
|
||||
I, at least, am not suited to. After a few tries, I found
|
||||
that I was making enough mistakes that I was having to restart
|
||||
my searches several times before finally getting correct
|
||||
results.</p><p id="x_14d"><a name="x_14d"></a>My initial problems with driving the <span class="command"><strong>hg bisect</strong></span> command by hand occurred
|
||||
even with simple searches on small repositories; if the
|
||||
problem you're looking for is more subtle, or the number of
|
||||
tests that <span class="command"><strong>hg bisect</strong></span> must
|
||||
perform increases, the likelihood of operator error ruining
|
||||
the search is much higher. Once I started automating my
|
||||
tests, I had much better results.</p><p id="x_14e"><a name="x_14e"></a>The key to automated testing is twofold:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_14f"><a name="x_14f"></a>always test for the same symptom, and</p></li><li><p id="x_150"><a name="x_150"></a>always feed consistent input to the <span class="command"><strong>hg bisect</strong></span> command.</p></li></ul></div><p id="x_151"><a name="x_151"></a>In my tutorial example above, the <span class="command"><strong>grep</strong></span>
|
||||
command tests for the symptom, and the <code class="literal">if</code>
|
||||
statement takes the result of this check and ensures that we
|
||||
always feed the same input to the <span class="command"><strong>hg
|
||||
bisect</strong></span> command. The <code class="literal">mytest</code>
|
||||
function marries these together in a reproducible way, so that
|
||||
every test is uniform and consistent.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396713">Check your results</h3></div></div></div><p id="x_152"><a name="x_152"></a>Because the output of a <span class="command"><strong>hg
|
||||
bisect</strong></span> search is only as good as the input you
|
||||
give it, don't take the changeset it reports as the absolute
|
||||
truth. A simple way to cross-check its report is to manually
|
||||
run your test at each of the following changesets:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_153"><a name="x_153"></a>The changeset that it reports as the first bad
|
||||
revision. Your test should still report this as
|
||||
bad.</p></li><li><p id="x_154"><a name="x_154"></a>The parent of that changeset (either parent,
|
||||
if it's a merge). Your test should report this changeset
|
||||
as good.</p></li><li><p id="x_155"><a name="x_155"></a>A child of that changeset. Your test should
|
||||
report this changeset as bad.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396770">Beware interference between bugs</h3></div></div></div><p id="x_156"><a name="x_156"></a>It's possible that your search for one bug could be
|
||||
disrupted by the presence of another. For example, let's say
|
||||
your software crashes at revision 100, and worked correctly at
|
||||
revision 50. Unknown to you, someone else introduced a
|
||||
different crashing bug at revision 60, and fixed it at
|
||||
revision 80. This could distort your results in one of
|
||||
several ways.</p><p id="x_157"><a name="x_157"></a>It is possible that this other bug completely
|
||||
“<span class="quote">masks</span>” yours, which is to say that it occurs
|
||||
before your bug has a chance to manifest itself. If you can't
|
||||
avoid that other bug (for example, it prevents your project
|
||||
from building), and so can't tell whether your bug is present
|
||||
in a particular changeset, the <span class="command"><strong>hg
|
||||
bisect</strong></span> command cannot help you directly. Instead,
|
||||
you can mark a changeset as untested by running <span class="command"><strong>hg bisect --skip</strong></span>.</p><p id="x_158"><a name="x_158"></a>A different problem could arise if your test for a bug's
|
||||
presence is not specific enough. If you check for “<span class="quote">my
|
||||
program crashes</span>”, then both your crashing bug and an
|
||||
unrelated crashing bug that masks it will look like the same
|
||||
thing, and mislead <span class="command"><strong>hg
|
||||
bisect</strong></span>.</p><p id="x_159"><a name="x_159"></a>Another useful situation in which to use <span class="command"><strong>hg bisect --skip</strong></span> is if you can't
|
||||
test a revision because your project was in a broken and hence
|
||||
untestable state at that revision, perhaps because someone
|
||||
checked in a change that prevented the project from
|
||||
building.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id396856">Bracket your search lazily</h3></div></div></div><p id="x_15a"><a name="x_15a"></a>Choosing the first “<span class="quote">good</span>” and
|
||||
“<span class="quote">bad</span>” changesets that will mark the end points of
|
||||
your search is often easy, but it bears a little discussion
|
||||
nevertheless. From the perspective of <span class="command"><strong>hg bisect</strong></span>, the “<span class="quote">newest</span>”
|
||||
changeset is conventionally “<span class="quote">bad</span>”, and the older
|
||||
changeset is “<span class="quote">good</span>”.</p><p id="x_15b"><a name="x_15b"></a>If you're having trouble remembering when a suitable
|
||||
“<span class="quote">good</span>” change was, so that you can tell <span class="command"><strong>hg bisect</strong></span>, you could do worse than
|
||||
testing changesets at random. Just remember to eliminate
|
||||
contenders that can't possibly exhibit the bug (perhaps
|
||||
because the feature with the bug isn't present yet) and those
|
||||
where another problem masks the bug (as I discussed
|
||||
above).</p><p id="x_15c"><a name="x_15c"></a>Even if you end up “<span class="quote">early</span>” by thousands of
|
||||
changesets or months of history, you will only add a handful
|
||||
of tests to the total number that <span class="command"><strong>hg
|
||||
bisect</strong></span> must perform, thanks to its logarithmic
|
||||
behavior.</p></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="managing-releases-and-branchy-development.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="handling-repository-events-with-hooks.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 8. Managing releases and branchy development </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 10. Handling repository events with hooks</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
1254
read/handling-repository-events-with-hooks.html
Normal file
1254
read/handling-repository-events-with-hooks.html
Normal file
File diff suppressed because it is too large
Load diff
462
read/how-did-we-get-here.html
Normal file
462
read/how-did-we-get-here.html
Normal file
|
@ -0,0 +1,462 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 1. How did we get here?</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="preface.html" title="Preface"><link rel="next" href="a-tour-of-mercurial-the-basics.html" title="Chapter 2. A tour of Mercurial: the basics"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 1. How did we get here?</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="preface.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="a-tour-of-mercurial-the-basics.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:intro"><div class="titlepage"><div><div><h2 class="title">Chapter 1. How did we get here?</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="how-did-we-get-here.html#id342215">Why revision control? Why Mercurial?</a></span></dt><dd><dl><dt><span class="sect2"><a href="how-did-we-get-here.html#id342565">Why use revision control?</a></span></dt><dt><span class="sect2"><a href="how-did-we-get-here.html#id342807">The many names of revision control</a></span></dt></dl></dd><dt><span class="sect1"><a href="how-did-we-get-here.html#id342862">About the examples in this book</a></span></dt><dt><span class="sect1"><a href="how-did-we-get-here.html#id342932">Trends in the field</a></span></dt><dt><span class="sect1"><a href="how-did-we-get-here.html#id342975">A few of the advantages of distributed revision
|
||||
control</a></span></dt><dd><dl><dt><span class="sect2"><a href="how-did-we-get-here.html#id343018">Advantages for open source projects</a></span></dt><dd><dl><dt><span class="sect3"><a href="how-did-we-get-here.html#id343042">The forking non-problem</a></span></dt></dl></dd><dt><span class="sect2"><a href="how-did-we-get-here.html#id343142">Advantages for commercial projects</a></span></dt></dl></dd><dt><span class="sect1"><a href="how-did-we-get-here.html#id343180">Why choose Mercurial?</a></span></dt><dt><span class="sect1"><a href="how-did-we-get-here.html#id343252">Mercurial compared with other tools</a></span></dt><dd><dl><dt><span class="sect2"><a href="how-did-we-get-here.html#id343265">Subversion</a></span></dt><dt><span class="sect2"><a href="how-did-we-get-here.html#id343368">Git</a></span></dt><dt><span class="sect2"><a href="how-did-we-get-here.html#id343423">CVS</a></span></dt><dt><span class="sect2"><a href="how-did-we-get-here.html#id343482">Commercial tools</a></span></dt><dt><span class="sect2"><a href="how-did-we-get-here.html#id343504">Choosing a revision control tool</a></span></dt></dl></dd><dt><span class="sect1"><a href="how-did-we-get-here.html#id343531">Switching from another tool to Mercurial</a></span></dt><dt><span class="sect1"><a href="how-did-we-get-here.html#id343625">A short history of revision control</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id342215">Why revision control? Why Mercurial?</h2></div></div></div><p id="x_6d"><a name="x_6d"></a>Revision control is the process of managing multiple
|
||||
versions of a piece of information. In its simplest form, this
|
||||
is something that many people do by hand: every time you modify
|
||||
a file, save it under a new name that contains a number, each
|
||||
one higher than the number of the preceding version.</p><p id="x_6e"><a name="x_6e"></a>Manually managing multiple versions of even a single file is
|
||||
an error-prone task, though, so software tools to help automate
|
||||
this process have long been available. The earliest automated
|
||||
revision control tools were intended to help a single user to
|
||||
manage revisions of a single file. Over the past few decades,
|
||||
the scope of revision control tools has expanded greatly; they
|
||||
now manage multiple files, and help multiple people to work
|
||||
together. The best modern revision control tools have no
|
||||
problem coping with thousands of people working together on
|
||||
projects that consist of hundreds of thousands of files.</p><p id="x_6f"><a name="x_6f"></a>The arrival of distributed revision control is relatively
|
||||
recent, and so far this new field has grown due to people's
|
||||
willingness to explore ill-charted territory.</p><p id="x_70"><a name="x_70"></a>I am writing a book about distributed revision control
|
||||
because I believe that it is an important subject that deserves
|
||||
a field guide. I chose to write about Mercurial because it is
|
||||
the easiest tool to learn the terrain with, and yet it scales to
|
||||
the demands of real, challenging environments where many other
|
||||
revision control tools buckle.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id342565">Why use revision control?</h3></div></div></div><p id="x_71"><a name="x_71"></a>There are a number of reasons why you or your team might
|
||||
want to use an automated revision control tool for a
|
||||
project.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_72"><a name="x_72"></a>It will track the history and evolution of
|
||||
your project, so you don't have to. For every change,
|
||||
you'll have a log of <span class="emphasis"><em>who</em></span> made it;
|
||||
<span class="emphasis"><em>why</em></span> they made it;
|
||||
<span class="emphasis"><em>when</em></span> they made it; and
|
||||
<span class="emphasis"><em>what</em></span> the change
|
||||
was.</p></li><li><p id="x_73"><a name="x_73"></a>When you're working with other people,
|
||||
revision control software makes it easier for you to
|
||||
collaborate. For example, when people more or less
|
||||
simultaneously make potentially incompatible changes, the
|
||||
software will help you to identify and resolve those
|
||||
conflicts.</p></li><li><p id="x_74"><a name="x_74"></a>It can help you to recover from mistakes. If
|
||||
you make a change that later turns out to be in error, you
|
||||
can revert to an earlier version of one or more files. In
|
||||
fact, a <span class="emphasis"><em>really</em></span> good revision control
|
||||
tool will even help you to efficiently figure out exactly
|
||||
when a problem was introduced (see <a class="xref" href="finding-and-fixing-mistakes.html#sec:undo:bisect" title="Finding the source of a bug">the section called “Finding the source of a bug”</a> for details).</p></li><li><p id="x_75"><a name="x_75"></a>It will help you to work simultaneously on,
|
||||
and manage the drift between, multiple versions of your
|
||||
project.</p></li></ul></div><p id="x_76"><a name="x_76"></a>Most of these reasons are equally
|
||||
valid—at least in theory—whether you're working
|
||||
on a project by yourself, or with a hundred other
|
||||
people.</p><p id="x_77"><a name="x_77"></a>A key question about the practicality of revision control
|
||||
at these two different scales (“<span class="quote">lone hacker</span>” and
|
||||
“<span class="quote">huge team</span>”) is how its
|
||||
<span class="emphasis"><em>benefits</em></span> compare to its
|
||||
<span class="emphasis"><em>costs</em></span>. A revision control tool that's
|
||||
difficult to understand or use is going to impose a high
|
||||
cost.</p><p id="x_78"><a name="x_78"></a>A five-hundred-person project is likely to collapse under
|
||||
its own weight almost immediately without a revision control
|
||||
tool and process. In this case, the cost of using revision
|
||||
control might hardly seem worth considering, since
|
||||
<span class="emphasis"><em>without</em></span> it, failure is almost
|
||||
guaranteed.</p><p id="x_79"><a name="x_79"></a>On the other hand, a one-person “<span class="quote">quick hack</span>”
|
||||
might seem like a poor place to use a revision control tool,
|
||||
because surely the cost of using one must be close to the
|
||||
overall cost of the project. Right?</p><p id="x_7a"><a name="x_7a"></a>Mercurial uniquely supports <span class="emphasis"><em>both</em></span> of
|
||||
these scales of development. You can learn the basics in just
|
||||
a few minutes, and due to its low overhead, you can apply
|
||||
revision control to the smallest of projects with ease. Its
|
||||
simplicity means you won't have a lot of abstruse concepts or
|
||||
command sequences competing for mental space with whatever
|
||||
you're <span class="emphasis"><em>really</em></span> trying to do. At the same
|
||||
time, Mercurial's high performance and peer-to-peer nature let
|
||||
you scale painlessly to handle large projects.</p><p id="x_7b"><a name="x_7b"></a>No revision control tool can rescue a poorly run project,
|
||||
but a good choice of tools can make a huge difference to the
|
||||
fluidity with which you can work on a project.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id342807">The many names of revision control</h3></div></div></div><p id="x_7c"><a name="x_7c"></a>Revision control is a diverse field, so much so that it is
|
||||
referred to by many names and acronyms. Here are a few of the
|
||||
more common variations you'll encounter:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_7d"><a name="x_7d"></a>Revision control (RCS)</p></li><li><p id="x_7e"><a name="x_7e"></a>Software configuration management (SCM), or
|
||||
configuration management</p></li><li><p id="x_7f"><a name="x_7f"></a>Source code management</p></li><li><p id="x_80"><a name="x_80"></a>Source code control, or source
|
||||
control</p></li><li><p id="x_81"><a name="x_81"></a>Version control
|
||||
(VCS)</p></li></ul></div><p id="x_82"><a name="x_82"></a>Some people claim that these terms actually have different
|
||||
meanings, but in practice they overlap so much that there's no
|
||||
agreed or even useful way to tease them apart.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id342862">About the examples in this book</h2></div></div></div><p id="x_84"><a name="x_84"></a>This book takes an unusual approach to code samples. Every
|
||||
example is “<span class="quote">live</span>”—each one is actually the result
|
||||
of a shell script that executes the Mercurial commands you see.
|
||||
Every time an image of the book is built from its sources, all
|
||||
the example scripts are automatically run, and their current
|
||||
results compared against their expected results.</p><p id="x_85"><a name="x_85"></a>The advantage of this approach is that the examples are
|
||||
always accurate; they describe <span class="emphasis"><em>exactly</em></span> the
|
||||
behavior of the version of Mercurial that's mentioned at the
|
||||
front of the book. If I update the version of Mercurial that
|
||||
I'm documenting, and the output of some command changes, the
|
||||
build fails.</p><p id="x_86"><a name="x_86"></a>There is a small disadvantage to this approach, which is
|
||||
that the dates and times you'll see in examples tend to be
|
||||
“<span class="quote">squashed</span>” together in a way that they wouldn't be
|
||||
if the same commands were being typed by a human. Where a human
|
||||
can issue no more than one command every few seconds, with any
|
||||
resulting timestamps correspondingly spread out, my automated
|
||||
example scripts run many commands in one second.</p><p id="x_87"><a name="x_87"></a>As an instance of this, several consecutive commits in an
|
||||
example can show up as having occurred during the same second.
|
||||
You can see this occur in the <code class="literal">bisect</code> example in <a class="xref" href="finding-and-fixing-mistakes.html#sec:undo:bisect" title="Finding the source of a bug">the section called “Finding the source of a bug”</a>, for instance.</p><p id="x_88"><a name="x_88"></a>So when you're reading examples, don't place too much weight
|
||||
on the dates or times you see in the output of commands. But
|
||||
<span class="emphasis"><em>do</em></span> be confident that the behavior you're
|
||||
seeing is consistent and reproducible.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id342932">Trends in the field</h2></div></div></div><p id="x_89"><a name="x_89"></a>There has been an unmistakable trend in the development and
|
||||
use of revision control tools over the past four decades, as
|
||||
people have become familiar with the capabilities of their tools
|
||||
and constrained by their limitations.</p><p id="x_8a"><a name="x_8a"></a>The first generation began by managing single files on
|
||||
individual computers. Although these tools represented a huge
|
||||
advance over ad-hoc manual revision control, their locking model
|
||||
and reliance on a single computer limited them to small,
|
||||
tightly-knit teams.</p><p id="x_8b"><a name="x_8b"></a>The second generation loosened these constraints by moving
|
||||
to network-centered architectures, and managing entire projects
|
||||
at a time. As projects grew larger, they ran into new problems.
|
||||
With clients needing to talk to servers very frequently, server
|
||||
scaling became an issue for large projects. An unreliable
|
||||
network connection could prevent remote users from being able to
|
||||
talk to the server at all. As open source projects started
|
||||
making read-only access available anonymously to anyone, people
|
||||
without commit privileges found that they could not use the
|
||||
tools to interact with a project in a natural way, as they could
|
||||
not record their changes.</p><p id="x_8c"><a name="x_8c"></a>The current generation of revision control tools is
|
||||
peer-to-peer in nature. All of these systems have dropped the
|
||||
dependency on a single central server, and allow people to
|
||||
distribute their revision control data to where it's actually
|
||||
needed. Collaboration over the Internet has moved from
|
||||
constrained by technology to a matter of choice and consensus.
|
||||
Modern tools can operate offline indefinitely and autonomously,
|
||||
with a network connection only needed when syncing changes with
|
||||
another repository.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id342975">A few of the advantages of distributed revision
|
||||
control</h2></div></div></div><p id="x_8d"><a name="x_8d"></a>Even though distributed revision control tools have for
|
||||
several years been as robust and usable as their
|
||||
previous-generation counterparts, people using older tools have
|
||||
not yet necessarily woken up to their advantages. There are a
|
||||
number of ways in which distributed tools shine relative to
|
||||
centralised ones.</p><p id="x_8e"><a name="x_8e"></a>For an individual developer, distributed tools are almost
|
||||
always much faster than centralised tools. This is for a simple
|
||||
reason: a centralised tool needs to talk over the network for
|
||||
many common operations, because most metadata is stored in a
|
||||
single copy on the central server. A distributed tool stores
|
||||
all of its metadata locally. All else being equal, talking over
|
||||
the network adds overhead to a centralised tool. Don't
|
||||
underestimate the value of a snappy, responsive tool: you're
|
||||
going to spend a lot of time interacting with your revision
|
||||
control software.</p><p id="x_8f"><a name="x_8f"></a>Distributed tools are indifferent to the vagaries of your
|
||||
server infrastructure, again because they replicate metadata to
|
||||
so many locations. If you use a centralised system and your
|
||||
server catches fire, you'd better hope that your backup media
|
||||
are reliable, and that your last backup was recent and actually
|
||||
worked. With a distributed tool, you have many backups
|
||||
available on every contributor's computer.</p><p id="x_90"><a name="x_90"></a>The reliability of your network will affect distributed
|
||||
tools far less than it will centralised tools. You can't even
|
||||
use a centralised tool without a network connection, except for
|
||||
a few highly constrained commands. With a distributed tool, if
|
||||
your network connection goes down while you're working, you may
|
||||
not even notice. The only thing you won't be able to do is talk
|
||||
to repositories on other computers, something that is relatively
|
||||
rare compared with local operations. If you have a far-flung
|
||||
team of collaborators, this may be significant.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id343018">Advantages for open source projects</h3></div></div></div><p id="x_91"><a name="x_91"></a>If you take a shine to an open source project and decide
|
||||
that you would like to start hacking on it, and that project
|
||||
uses a distributed revision control tool, you are at once a
|
||||
peer with the people who consider themselves the
|
||||
“<span class="quote">core</span>” of that project. If they publish their
|
||||
repositories, you can immediately copy their project history,
|
||||
start making changes, and record your work, using the same
|
||||
tools in the same ways as insiders. By contrast, with a
|
||||
centralised tool, you must use the software in a “<span class="quote">read
|
||||
only</span>” mode unless someone grants you permission to
|
||||
commit changes to their central server. Until then, you won't
|
||||
be able to record changes, and your local modifications will
|
||||
be at risk of corruption any time you try to update your
|
||||
client's view of the repository.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id343042">The forking non-problem</h4></div></div></div><p id="x_92"><a name="x_92"></a>It has been suggested that distributed revision control
|
||||
tools pose some sort of risk to open source projects because
|
||||
they make it easy to “<span class="quote">fork</span>” the development of
|
||||
a project. A fork happens when there are differences in
|
||||
opinion or attitude between groups of developers that cause
|
||||
them to decide that they can't work together any longer.
|
||||
Each side takes a more or less complete copy of the
|
||||
project's source code, and goes off in its own
|
||||
direction.</p><p id="x_93"><a name="x_93"></a>Sometimes the camps in a fork decide to reconcile their
|
||||
differences. With a centralised revision control system, the
|
||||
<span class="emphasis"><em>technical</em></span> process of reconciliation is
|
||||
painful, and has to be performed largely by hand. You have
|
||||
to decide whose revision history is going to
|
||||
“<span class="quote">win</span>”, and graft the other team's changes into
|
||||
the tree somehow. This usually loses some or all of one
|
||||
side's revision history.</p><p id="x_94"><a name="x_94"></a>What distributed tools do with respect to forking is
|
||||
they make forking the <span class="emphasis"><em>only</em></span> way to
|
||||
develop a project. Every single change that you make is
|
||||
potentially a fork point. The great strength of this
|
||||
approach is that a distributed revision control tool has to
|
||||
be really good at <span class="emphasis"><em>merging</em></span> forks,
|
||||
because forks are absolutely fundamental: they happen all
|
||||
the time.</p><p id="x_95"><a name="x_95"></a>If every piece of work that everybody does, all the
|
||||
time, is framed in terms of forking and merging, then what
|
||||
the open source world refers to as a “<span class="quote">fork</span>”
|
||||
becomes <span class="emphasis"><em>purely</em></span> a social issue. If
|
||||
anything, distributed tools <span class="emphasis"><em>lower</em></span> the
|
||||
likelihood of a fork:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_96"><a name="x_96"></a>They eliminate the social distinction that
|
||||
centralised tools impose: that between insiders (people
|
||||
with commit access) and outsiders (people
|
||||
without).</p></li><li><p id="x_97"><a name="x_97"></a>They make it easier to reconcile after a
|
||||
social fork, because all that's involved from the
|
||||
perspective of the revision control software is just
|
||||
another merge.</p></li></ul></div><p id="x_98"><a name="x_98"></a>Some people resist distributed tools because they want
|
||||
to retain tight control over their projects, and they
|
||||
believe that centralised tools give them this control.
|
||||
However, if you're of this belief, and you publish your CVS
|
||||
or Subversion repositories publicly, there are plenty of
|
||||
tools available that can pull out your entire project's
|
||||
history (albeit slowly) and recreate it somewhere that you
|
||||
don't control. So while your control in this case is
|
||||
illusory, you are forgoing the ability to fluidly
|
||||
collaborate with whatever people feel compelled to mirror
|
||||
and fork your history.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id343142">Advantages for commercial projects</h3></div></div></div><p id="x_99"><a name="x_99"></a>Many commercial projects are undertaken by teams that are
|
||||
scattered across the globe. Contributors who are far from a
|
||||
central server will see slower command execution and perhaps
|
||||
less reliability. Commercial revision control systems attempt
|
||||
to ameliorate these problems with remote-site replication
|
||||
add-ons that are typically expensive to buy and cantankerous
|
||||
to administer. A distributed system doesn't suffer from these
|
||||
problems in the first place. Better yet, you can easily set
|
||||
up multiple authoritative servers, say one per site, so that
|
||||
there's no redundant communication between repositories over
|
||||
expensive long-haul network links.</p><p id="x_9a"><a name="x_9a"></a>Centralised revision control systems tend to have
|
||||
relatively low scalability. It's not unusual for an expensive
|
||||
centralised system to fall over under the combined load of
|
||||
just a few dozen concurrent users. Once again, the typical
|
||||
response tends to be an expensive and clunky replication
|
||||
facility. Since the load on a central server—if you have
|
||||
one at all—is many times lower with a distributed tool
|
||||
(because all of the data is replicated everywhere), a single
|
||||
cheap server can handle the needs of a much larger team, and
|
||||
replication to balance load becomes a simple matter of
|
||||
scripting.</p><p id="x_9b"><a name="x_9b"></a>If you have an employee in the field, troubleshooting a
|
||||
problem at a customer's site, they'll benefit from distributed
|
||||
revision control. The tool will let them generate custom
|
||||
builds, try different fixes in isolation from each other, and
|
||||
search efficiently through history for the sources of bugs and
|
||||
regressions in the customer's environment, all without needing
|
||||
to connect to your company's network.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id343180">Why choose Mercurial?</h2></div></div></div><p id="x_9c"><a name="x_9c"></a>Mercurial has a unique set of properties that make it a
|
||||
particularly good choice as a revision control system.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_9d"><a name="x_9d"></a>It is easy to learn and use.</p></li><li><p id="x_9e"><a name="x_9e"></a>It is lightweight.</p></li><li><p id="x_9f"><a name="x_9f"></a>It scales excellently.</p></li><li><p id="x_a0"><a name="x_a0"></a>It is easy to
|
||||
customise.</p></li></ul></div><p id="x_a1"><a name="x_a1"></a>If you are at all familiar with revision control systems,
|
||||
you should be able to get up and running with Mercurial in less
|
||||
than five minutes. Even if not, it will take no more than a few
|
||||
minutes longer. Mercurial's command and feature sets are
|
||||
generally uniform and consistent, so you can keep track of a few
|
||||
general rules instead of a host of exceptions.</p><p id="x_a2"><a name="x_a2"></a>On a small project, you can start working with Mercurial in
|
||||
moments. Creating new changes and branches; transferring changes
|
||||
around (whether locally or over a network); and history and
|
||||
status operations are all fast. Mercurial attempts to stay
|
||||
nimble and largely out of your way by combining low cognitive
|
||||
overhead with blazingly fast operations.</p><p id="x_a3"><a name="x_a3"></a>The usefulness of Mercurial is not limited to small
|
||||
projects: it is used by projects with hundreds to thousands of
|
||||
contributors, each containing tens of thousands of files and
|
||||
hundreds of megabytes of source code.</p><p id="x_a4"><a name="x_a4"></a>If the core functionality of Mercurial is not enough for
|
||||
you, it's easy to build on. Mercurial is well suited to
|
||||
scripting tasks, and its clean internals and implementation in
|
||||
Python make it easy to add features in the form of extensions.
|
||||
There are a number of popular and useful extensions already
|
||||
available, ranging from helping to identify bugs to improving
|
||||
performance.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id343252">Mercurial compared with other tools</h2></div></div></div><p id="x_a5"><a name="x_a5"></a>Before you read on, please understand that this section
|
||||
necessarily reflects my own experiences, interests, and (dare I
|
||||
say it) biases. I have used every one of the revision control
|
||||
tools listed below, in most cases for several years at a
|
||||
time.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id343265">Subversion</h3></div></div></div><p id="x_a6"><a name="x_a6"></a>Subversion is a popular revision control tool, developed
|
||||
to replace CVS. It has a centralised client/server
|
||||
architecture.</p><p id="x_a7"><a name="x_a7"></a>Subversion and Mercurial have similarly named commands for
|
||||
performing the same operations, so if you're familiar with
|
||||
one, it is easy to learn to use the other. Both tools are
|
||||
portable to all popular operating systems.</p><p id="x_a8"><a name="x_a8"></a>Prior to version 1.5, Subversion had no useful support for
|
||||
merges. At the time of writing, its merge tracking capability
|
||||
is new, and known to be <a class="ulink" href="http://svnbook.red-bean.com/nightly/en/svn.branchmerge.advanced.html#svn.branchmerge.advanced.finalword" target="_top">complicated
|
||||
and buggy</a>.</p><p id="x_a9"><a name="x_a9"></a>Mercurial has a substantial performance advantage over
|
||||
Subversion on every revision control operation I have
|
||||
benchmarked. I have measured its advantage as ranging from a
|
||||
factor of two to a factor of six when compared with Subversion
|
||||
1.4.3's <span class="emphasis"><em>ra_local</em></span> file store, which is the
|
||||
fastest access method available. In more realistic
|
||||
deployments involving a network-based store, Subversion will
|
||||
be at a substantially larger disadvantage. Because many
|
||||
Subversion commands must talk to the server and Subversion
|
||||
does not have useful replication facilities, server capacity
|
||||
and network bandwidth become bottlenecks for modestly large
|
||||
projects.</p><p id="x_aa"><a name="x_aa"></a>Additionally, Subversion incurs substantial storage
|
||||
overhead to avoid network transactions for a few common
|
||||
operations, such as finding modified files
|
||||
(<code class="literal">status</code>) and displaying modifications
|
||||
against the current revision (<code class="literal">diff</code>). As a
|
||||
result, a Subversion working copy is often the same size as,
|
||||
or larger than, a Mercurial repository and working directory,
|
||||
even though the Mercurial repository contains a complete
|
||||
history of the project.</p><p id="x_ab"><a name="x_ab"></a>Subversion is widely supported by third party tools.
|
||||
Mercurial currently lags considerably in this area. This gap
|
||||
is closing, however, and indeed some of Mercurial's GUI tools
|
||||
now outshine their Subversion equivalents. Like Mercurial,
|
||||
Subversion has an excellent user manual.</p><p id="x_ac"><a name="x_ac"></a>Because Subversion doesn't store revision history on the
|
||||
client, it is well suited to managing projects that deal with
|
||||
lots of large, opaque binary files. If you check in fifty
|
||||
revisions to an incompressible 10MB file, Subversion's
|
||||
client-side space usage stays constant The space used by any
|
||||
distributed SCM will grow rapidly in proportion to the number
|
||||
of revisions, because the differences between each revision
|
||||
are large.</p><p id="x_ad"><a name="x_ad"></a>In addition, it's often difficult or, more usually,
|
||||
impossible to merge different versions of a binary file.
|
||||
Subversion's ability to let a user lock a file, so that they
|
||||
temporarily have the exclusive right to commit changes to it,
|
||||
can be a significant advantage to a project where binary files
|
||||
are widely used.</p><p id="x_ae"><a name="x_ae"></a>Mercurial can import revision history from a Subversion
|
||||
repository. It can also export revision history to a
|
||||
Subversion repository. This makes it easy to “<span class="quote">test the
|
||||
waters</span>” and use Mercurial and Subversion in parallel
|
||||
before deciding to switch. History conversion is incremental,
|
||||
so you can perform an initial conversion, then small
|
||||
additional conversions afterwards to bring in new
|
||||
changes.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id343368">Git</h3></div></div></div><p id="x_af"><a name="x_af"></a>Git is a distributed revision control tool that was
|
||||
developed for managing the Linux kernel source tree. Like
|
||||
Mercurial, its early design was somewhat influenced by
|
||||
Monotone.</p><p id="x_b0"><a name="x_b0"></a>Git has a very large command set, with version 1.5.0
|
||||
providing 139 individual commands. It has something of a
|
||||
reputation for being difficult to learn. Compared to Git,
|
||||
Mercurial has a strong focus on simplicity.</p><p id="x_b1"><a name="x_b1"></a>In terms of performance, Git is extremely fast. In
|
||||
several cases, it is faster than Mercurial, at least on Linux,
|
||||
while Mercurial performs better on other operations. However,
|
||||
on Windows, the performance and general level of support that
|
||||
Git provides is, at the time of writing, far behind that of
|
||||
Mercurial.</p><p id="x_b2"><a name="x_b2"></a>While a Mercurial repository needs no maintenance, a Git
|
||||
repository requires frequent manual “<span class="quote">repacks</span>” of
|
||||
its metadata. Without these, performance degrades, while
|
||||
space usage grows rapidly. A server that contains many Git
|
||||
repositories that are not rigorously and frequently repacked
|
||||
will become heavily disk-bound during backups, and there have
|
||||
been instances of daily backups taking far longer than 24
|
||||
hours as a result. A freshly packed Git repository is
|
||||
slightly smaller than a Mercurial repository, but an unpacked
|
||||
repository is several orders of magnitude larger.</p><p id="x_b3"><a name="x_b3"></a>The core of Git is written in C. Many Git commands are
|
||||
implemented as shell or Perl scripts, and the quality of these
|
||||
scripts varies widely. I have encountered several instances
|
||||
where scripts charged along blindly in the presence of errors
|
||||
that should have been fatal.</p><p id="x_b4"><a name="x_b4"></a>Mercurial can import revision history from a Git
|
||||
repository.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id343423">CVS</h3></div></div></div><p id="x_b5"><a name="x_b5"></a>CVS is probably the most widely used revision control tool
|
||||
in the world. Due to its age and internal untidiness, it has
|
||||
been only lightly maintained for many years.</p><p id="x_b6"><a name="x_b6"></a>It has a centralised client/server architecture. It does
|
||||
not group related file changes into atomic commits, making it
|
||||
easy for people to “<span class="quote">break the build</span>”: one person
|
||||
can successfully commit part of a change and then be blocked
|
||||
by the need for a merge, causing other people to see only a
|
||||
portion of the work they intended to do. This also affects
|
||||
how you work with project history. If you want to see all of
|
||||
the modifications someone made as part of a task, you will
|
||||
need to manually inspect the descriptions and timestamps of
|
||||
the changes made to each file involved (if you even know what
|
||||
those files were).</p><p id="x_b7"><a name="x_b7"></a>CVS has a muddled notion of tags and branches that I will
|
||||
not attempt to even describe. It does not support renaming of
|
||||
files or directories well, making it easy to corrupt a
|
||||
repository. It has almost no internal consistency checking
|
||||
capabilities, so it is usually not even possible to tell
|
||||
whether or how a repository is corrupt. I would not recommend
|
||||
CVS for any project, existing or new.</p><p id="x_b8"><a name="x_b8"></a>Mercurial can import CVS revision history. However, there
|
||||
are a few caveats that apply; these are true of every other
|
||||
revision control tool's CVS importer, too. Due to CVS's lack
|
||||
of atomic changes and unversioned filesystem hierarchy, it is
|
||||
not possible to reconstruct CVS history completely accurately;
|
||||
some guesswork is involved, and renames will usually not show
|
||||
up. Because a lot of advanced CVS administration has to be
|
||||
done by hand and is hence error-prone, it's common for CVS
|
||||
importers to run into multiple problems with corrupted
|
||||
repositories (completely bogus revision timestamps and files
|
||||
that have remained locked for over a decade are just two of
|
||||
the less interesting problems I can recall from personal
|
||||
experience).</p><p id="x_b9"><a name="x_b9"></a>Mercurial can import revision history from a CVS
|
||||
repository.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id343482">Commercial tools</h3></div></div></div><p id="x_ba"><a name="x_ba"></a>Perforce has a centralised client/server architecture,
|
||||
with no client-side caching of any data. Unlike modern
|
||||
revision control tools, Perforce requires that a user run a
|
||||
command to inform the server about every file they intend to
|
||||
edit.</p><p id="x_bb"><a name="x_bb"></a>The performance of Perforce is quite good for small teams,
|
||||
but it falls off rapidly as the number of users grows beyond a
|
||||
few dozen. Modestly large Perforce installations require the
|
||||
deployment of proxies to cope with the load their users
|
||||
generate.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id343504">Choosing a revision control tool</h3></div></div></div><p id="x_bc"><a name="x_bc"></a>With the exception of CVS, all of the tools listed above
|
||||
have unique strengths that suit them to particular styles of
|
||||
work. There is no single revision control tool that is best
|
||||
in all situations.</p><p id="x_bd"><a name="x_bd"></a>As an example, Subversion is a good choice for working
|
||||
with frequently edited binary files, due to its centralised
|
||||
nature and support for file locking.</p><p id="x_be"><a name="x_be"></a>I personally find Mercurial's properties of simplicity,
|
||||
performance, and good merge support to be a compelling
|
||||
combination that has served me well for several years.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id343531">Switching from another tool to Mercurial</h2></div></div></div><p id="x_bf"><a name="x_bf"></a>Mercurial is bundled with an extension named <code class="literal">convert</code>, which can incrementally
|
||||
import revision history from several other revision control
|
||||
tools. By “<span class="quote">incremental</span>”, I mean that you can
|
||||
convert all of a project's history to date in one go, then rerun
|
||||
the conversion later to obtain new changes that happened after
|
||||
the initial conversion.</p><p id="x_c0"><a name="x_c0"></a>The revision control tools supported by <code class="literal">convert</code> are as follows:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_c1"><a name="x_c1"></a>Subversion</p></li><li><p id="x_c2"><a name="x_c2"></a>CVS</p></li><li><p id="x_c3"><a name="x_c3"></a>Git</p></li><li><p id="x_c4"><a name="x_c4"></a>Darcs</p></li></ul></div><p id="x_c5"><a name="x_c5"></a>In addition, <code class="literal">convert</code> can
|
||||
export changes from Mercurial to Subversion. This makes it
|
||||
possible to try Subversion and Mercurial in parallel before
|
||||
committing to a switchover, without risking the loss of any
|
||||
work.</p><p id="x_c6"><a name="x_c6"></a>The <span class="command"><strong>convert</strong></span> command
|
||||
is easy to use. Simply point it at the path or URL of the
|
||||
source repository, optionally give it the name of the
|
||||
destination repository, and it will start working. After the
|
||||
initial conversion, just run the same command again to import
|
||||
new changes.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id343625">A short history of revision control</h2></div></div></div><p id="x_c7"><a name="x_c7"></a>The best known of the old-time revision control tools is
|
||||
SCCS (Source Code Control System), which Marc Rochkind wrote at
|
||||
Bell Labs, in the early 1970s. SCCS operated on individual
|
||||
files, and required every person working on a project to have
|
||||
access to a shared workspace on a single system. Only one
|
||||
person could modify a file at any time; arbitration for access
|
||||
to files was via locks. It was common for people to lock files,
|
||||
and later forget to unlock them, preventing anyone else from
|
||||
modifying those files without the help of an
|
||||
administrator.</p><p id="x_c8"><a name="x_c8"></a>Walter Tichy developed a free alternative to SCCS in the
|
||||
early 1980s; he called his program RCS (Revision Control System).
|
||||
Like SCCS, RCS required developers to work in a single shared
|
||||
workspace, and to lock files to prevent multiple people from
|
||||
modifying them simultaneously.</p><p id="x_c9"><a name="x_c9"></a>Later in the 1980s, Dick Grune used RCS as a building block
|
||||
for a set of shell scripts he initially called cmt, but then
|
||||
renamed to CVS (Concurrent Versions System). The big innovation
|
||||
of CVS was that it let developers work simultaneously and
|
||||
somewhat independently in their own personal workspaces. The
|
||||
personal workspaces prevented developers from stepping on each
|
||||
other's toes all the time, as was common with SCCS and RCS. Each
|
||||
developer had a copy of every project file, and could modify
|
||||
their copies independently. They had to merge their edits prior
|
||||
to committing changes to the central repository.</p><p id="x_ca"><a name="x_ca"></a>Brian Berliner took Grune's original scripts and rewrote
|
||||
them in C, releasing in 1989 the code that has since developed
|
||||
into the modern version of CVS. CVS subsequently acquired the
|
||||
ability to operate over a network connection, giving it a
|
||||
client/server architecture. CVS's architecture is centralised;
|
||||
only the server has a copy of the history of the project. Client
|
||||
workspaces just contain copies of recent versions of the
|
||||
project's files, and a little metadata to tell them where the
|
||||
server is. CVS has been enormously successful; it is probably
|
||||
the world's most widely used revision control system.</p><p id="x_cb"><a name="x_cb"></a>In the early 1990s, Sun Microsystems developed an early
|
||||
distributed revision control system, called TeamWare. A
|
||||
TeamWare workspace contains a complete copy of the project's
|
||||
history. TeamWare has no notion of a central repository. (CVS
|
||||
relied upon RCS for its history storage; TeamWare used
|
||||
SCCS.)</p><p id="x_cc"><a name="x_cc"></a>As the 1990s progressed, awareness grew of a number of
|
||||
problems with CVS. It records simultaneous changes to multiple
|
||||
files individually, instead of grouping them together as a
|
||||
single logically atomic operation. It does not manage its file
|
||||
hierarchy well; it is easy to make a mess of a repository by
|
||||
renaming files and directories. Worse, its source code is
|
||||
difficult to read and maintain, which made the “<span class="quote">pain
|
||||
level</span>” of fixing these architectural problems
|
||||
prohibitive.</p><p id="x_cd"><a name="x_cd"></a>In 2001, Jim Blandy and Karl Fogel, two developers who had
|
||||
worked on CVS, started a project to replace it with a tool that
|
||||
would have a better architecture and cleaner code. The result,
|
||||
Subversion, does not stray from CVS's centralised client/server
|
||||
model, but it adds multi-file atomic commits, better namespace
|
||||
management, and a number of other features that make it a
|
||||
generally better tool than CVS. Since its initial release, it
|
||||
has rapidly grown in popularity.</p><p id="x_ce"><a name="x_ce"></a>More or less simultaneously, Graydon Hoare began working on
|
||||
an ambitious distributed revision control system that he named
|
||||
Monotone. While Monotone addresses many of CVS's design flaws
|
||||
and has a peer-to-peer architecture, it goes beyond earlier (and
|
||||
subsequent) revision control tools in a number of innovative
|
||||
ways. It uses cryptographic hashes as identifiers, and has an
|
||||
integral notion of “<span class="quote">trust</span>” for code from different
|
||||
sources.</p><p id="x_cf"><a name="x_cf"></a>Mercurial began life in 2005. While a few aspects of its
|
||||
design are influenced by Monotone, Mercurial focuses on ease of
|
||||
use, high performance, and scalability to very large
|
||||
projects.</p></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="preface.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="a-tour-of-mercurial-the-basics.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Preface </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 2. A tour of Mercurial: the basics</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
61
read/index.html
Normal file
61
read/index.html
Normal file
|
@ -0,0 +1,61 @@
|
|||
<!-- -*- html -*- -->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Mercurial: The Definitive Guide</title>
|
||||
<link rel="stylesheet" href="/support/styles.css" type="text/css"/>
|
||||
<link rel="alternate" type="application/atom+xml" title="Comments"
|
||||
href="/feeds/comments/"/>
|
||||
<link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"/>
|
||||
<script type="text/javascript" src="/support/jquery.js"></script>
|
||||
<script type="text/javascript" src="/support/form.js"></script>
|
||||
<script type="text/javascript" src="/support/hsbook.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="navheader"><h1 class="booktitle">Mercurial: The Definitive Guide<div class="authors">by Bryan O'Sullivan</div></h1></div>
|
||||
<div class="book"><ul class="booktoc">
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:preface/"><img src="/support/figs/rss.png"/></a></span>0. <a href="preface.html">Preface</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:intro/"><img src="/support/figs/rss.png"/></a></span>1. <a href="how-did-we-get-here.html">How did we get here?</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:tour-basic/"><img src="/support/figs/rss.png"/></a></span>2. <a href="a-tour-of-mercurial-the-basics.html">A tour of Mercurial: the basics</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:tour-merge/"><img src="/support/figs/rss.png"/></a></span>3. <a href="a-tour-of-mercurial-merging-work.html">A tour of Mercurial: merging work</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:concepts/"><img src="/support/figs/rss.png"/></a></span>4. <a href="behind-the-scenes.html">Behind the scenes</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:daily/"><img src="/support/figs/rss.png"/></a></span>5. <a href="mercurial-in-daily-use.html">Mercurial in daily use</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/cha:collab/"><img src="/support/figs/rss.png"/></a></span>6. <a href="collaborating-with-other-people.html">Collaborating with other people</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:names/"><img src="/support/figs/rss.png"/></a></span>7. <a href="file-names-and-pattern-matching.html">File names and pattern matching</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:branch/"><img src="/support/figs/rss.png"/></a></span>8. <a href="managing-releases-and-branchy-development.html">Managing releases and branchy development</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:undo/"><img src="/support/figs/rss.png"/></a></span>9. <a href="finding-and-fixing-mistakes.html">Finding and fixing mistakes</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:hook/"><img src="/support/figs/rss.png"/></a></span>10. <a href="handling-repository-events-with-hooks.html">Handling repository events with hooks</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:template/"><img src="/support/figs/rss.png"/></a></span>11. <a href="customizing-the-output-of-mercurial.html">Customizing the output of Mercurial</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:mq/"><img src="/support/figs/rss.png"/></a></span>12. <a href="managing-change-with-mercurial-queues.html">Managing change with Mercurial Queues</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:mq-collab/"><img src="/support/figs/rss.png"/></a></span>13. <a href="advanced-uses-of-mercurial-queues.html">Advanced uses of Mercurial Queues</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-07<a href="/feeds/comments/chap:hgext/"><img src="/support/figs/rss.png"/></a></span>14. <a href="adding-functionality-with-extensions.html">Adding functionality with extensions</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-04-28<a href="/feeds/comments/svn/"><img src="/support/figs/rss.png"/></a></span>A. <a href="migrating-to-mercurial.html">Migrating to Mercurial</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-05-04<a href="/feeds/comments/chap:mqref/"><img src="/support/figs/rss.png"/></a></span>B. <a href="mercurial-queues-reference.html">Mercurial Queues reference</a></li>
|
||||
<li class="zebra_a"><span class="chapinfo">2009-03-30<a href="/feeds/comments/chap:srcinstall/"><img src="/support/figs/rss.png"/></a></span>C. <a href="installing-mercurial-from-source.html">Installing Mercurial from source</a></li>
|
||||
<li class="zebra_b"><span class="chapinfo">2009-03-30<a href="/feeds/comments/cha:opl/"><img src="/support/figs/rss.png"/></a></span>D. <a href="open-publication-license.html">Open Publication License</a></li>
|
||||
</ul></div>
|
||||
|
||||
|
||||
<div class="hgbookfooter"> <p><img src="/support/figs/rss.png"> Want to stay
|
||||
up to date? Subscribe to comment feeds for any chapter, or
|
||||
the <a class="feed"
|
||||
href="/feeds/comments/">entire book</a>.</p> <p>Copyright
|
||||
2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by
|
||||
<a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a
|
||||
href="http://mattahan.deviantart.com/">Mattahan</a>.</p>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script>
|
||||
</body>
|
||||
</html>
|
33
read/installing-mercurial-from-source.html
Normal file
33
read/installing-mercurial-from-source.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Appendix C. Installing Mercurial from source</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="mercurial-queues-reference.html" title="Appendix B. Mercurial Queues reference"><link rel="next" href="open-publication-license.html" title="Appendix D. Open Publication License"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix C. Installing Mercurial from source</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="mercurial-queues-reference.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="open-publication-license.html">Next</a></td></tr></table></div><div class="appendix" lang="en" id="chap:srcinstall"><div class="titlepage"><div><div><h2 class="title">Appendix C. Installing Mercurial from source</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="installing-mercurial-from-source.html#sec:srcinstall:unixlike">On a Unix-like system</a></span></dt><dt><span class="sect1"><a href="installing-mercurial-from-source.html#id448555">On Windows</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:srcinstall:unixlike">On a Unix-like system</h2></div></div></div><p id="x_5e0"><a name="x_5e0"></a>If you are using a Unix-like system that has a sufficiently
|
||||
recent version of Python (2.3 or newer) available, it is easy to
|
||||
install Mercurial from source.</p><div class="orderedlist"><ol type="1"><li><p id="x_5e1"><a name="x_5e1"></a>Download a recent source tarball from <a class="ulink" href="http://www.selenic.com/mercurial/download" target="_top">http://www.selenic.com/mercurial/download</a>.</p></li><li><p id="x_5e2"><a name="x_5e2"></a>Unpack the tarball:</p><pre id="id448490" class="programlisting">gzip -dc mercurial-MYVERSION.tar.gz | tar xf -</pre></li><li><p id="x_5e3"><a name="x_5e3"></a>Go into the source directory and run the
|
||||
installer script. This will build Mercurial and install it
|
||||
in your home directory.</p><pre id="id448506" class="programlisting">cd mercurial-MYVERSION
|
||||
python setup.py install --force --home=$HOME</pre></li></ol></div><p id="x_5e4"><a name="x_5e4"></a>Once the install finishes, Mercurial will be in the
|
||||
<code class="literal">bin</code> subdirectory of your home directory.
|
||||
Don't forget to make sure that this directory is present in your
|
||||
shell's search path.</p><p id="x_5e5"><a name="x_5e5"></a>You will probably need to set the <code class="envar">PYTHONPATH</code>
|
||||
environment variable so that the Mercurial executable can find
|
||||
the rest of the Mercurial packages. For example, on my laptop,
|
||||
I have set it to <code class="literal">/home/bos/lib/python</code>. The
|
||||
exact path that you will need to use depends on how Python was
|
||||
built for your system, but should be easy to figure out. If
|
||||
you're uncertain, look through the output of the installer
|
||||
script above, and see where the contents of the
|
||||
<code class="literal">mercurial</code> directory were installed to.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id448555">On Windows</h2></div></div></div><p id="x_5e6"><a name="x_5e6"></a>Building and installing Mercurial on Windows requires a
|
||||
variety of tools, a fair amount of technical knowledge, and
|
||||
considerable patience. I very much <span class="emphasis"><em>do not
|
||||
recommend</em></span> this route if you are a “<span class="quote">casual
|
||||
user</span>”. Unless you intend to hack on Mercurial, I
|
||||
strongly suggest that you use a binary package instead.</p><p id="x_5e7"><a name="x_5e7"></a>If you are intent on building Mercurial from source on
|
||||
Windows, follow the “<span class="quote">hard way</span>” directions on the
|
||||
Mercurial wiki at <a class="ulink" href="http://www.selenic.com/mercurial/wiki/index.cgi/WindowsInstall" target="_top">http://www.selenic.com/mercurial/wiki/index.cgi/WindowsInstall</a>,
|
||||
and expect the process to involve a lot of fiddly work.</p></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="mercurial-queues-reference.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="open-publication-license.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Appendix B. Mercurial Queues reference </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Appendix D. Open Publication License</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
1041
read/managing-change-with-mercurial-queues.html
Normal file
1041
read/managing-change-with-mercurial-queues.html
Normal file
File diff suppressed because one or more lines are too long
517
read/managing-releases-and-branchy-development.html
Normal file
517
read/managing-releases-and-branchy-development.html
Normal file
|
@ -0,0 +1,517 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 8. Managing releases and branchy development</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="file-names-and-pattern-matching.html" title="Chapter 7. File names and pattern matching"><link rel="next" href="finding-and-fixing-mistakes.html" title="Chapter 9. Finding and fixing mistakes"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 8. Managing releases and branchy development</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="file-names-and-pattern-matching.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="finding-and-fixing-mistakes.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:branch"><div class="titlepage"><div><div><h2 class="title">Chapter 8. Managing releases and branchy development</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="managing-releases-and-branchy-development.html#id383990">Giving a persistent name to a revision</a></span></dt><dd><dl><dt><span class="sect2"><a href="managing-releases-and-branchy-development.html#id384894">Handling tag conflicts during a merge</a></span></dt><dt><span class="sect2"><a href="managing-releases-and-branchy-development.html#id385011">Tags and cloning</a></span></dt><dt><span class="sect2"><a href="managing-releases-and-branchy-development.html#id385111">When permanent tags are too much</a></span></dt></dl></dd><dt><span class="sect1"><a href="managing-releases-and-branchy-development.html#id385202">The flow of changes—big picture vs. little</a></span></dt><dt><span class="sect1"><a href="managing-releases-and-branchy-development.html#id385287">Managing big-picture branches in repositories</a></span></dt><dt><span class="sect1"><a href="managing-releases-and-branchy-development.html#id385475">Don't repeat yourself: merging across branches</a></span></dt><dt><span class="sect1"><a href="managing-releases-and-branchy-development.html#id386031">Naming branches within one repository</a></span></dt><dt><span class="sect1"><a href="managing-releases-and-branchy-development.html#id386726">Dealing with multiple named branches in a
|
||||
repository</a></span></dt><dt><span class="sect1"><a href="managing-releases-and-branchy-development.html#id387231">Branch names and merging</a></span></dt><dt><span class="sect1"><a href="managing-releases-and-branchy-development.html#id387616">Branch naming is generally useful</a></span></dt></dl></div><p id="x_369"><a name="x_369"></a>Mercurial provides several mechanisms for you to manage a
|
||||
project that is making progress on multiple fronts at once. To
|
||||
understand these mechanisms, let's first take a brief look at a
|
||||
fairly normal software project structure.</p><p id="x_36a"><a name="x_36a"></a>Many software projects issue periodic “<span class="quote">major</span>”
|
||||
releases that contain substantial new features. In parallel, they
|
||||
may issue “<span class="quote">minor</span>” releases. These are usually
|
||||
identical to the major releases off which they're based, but with
|
||||
a few bugs fixed.</p><p id="x_36b"><a name="x_36b"></a>In this chapter, we'll start by talking about how to keep
|
||||
records of project milestones such as releases. We'll then
|
||||
continue on to talk about the flow of work between different
|
||||
phases of a project, and how Mercurial can help you to isolate and
|
||||
manage this work.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id383990">Giving a persistent name to a revision</h2></div></div></div><p id="x_36c"><a name="x_36c"></a>Once you decide that you'd like to call a particular
|
||||
revision a “<span class="quote">release</span>”, it's a good idea to record
|
||||
the identity of that revision. This will let you reproduce that
|
||||
release at a later date, for whatever purpose you might need at
|
||||
the time (reproducing a bug, porting to a new platform, etc).
|
||||
|
||||
</p><pre id="id384355" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init mytag</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd mytag</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo hello > myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -A -m 'Initial commit'</code></strong>
|
||||
adding myfile
|
||||
</pre><p>
|
||||
|
||||
</p><p id="x_36d"><a name="x_36d"></a>Mercurial lets you give a permanent name to any revision
|
||||
using the <span class="command"><strong>hg tag</strong></span> command. Not
|
||||
surprisingly, these names are called “<span class="quote">tags</span>”.</p><pre id="id384242" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tag v1.0</code></strong>
|
||||
</pre><p id="x_36e"><a name="x_36e"></a>A tag is nothing more than a “<span class="quote">symbolic name</span>”
|
||||
for a revision. Tags exist purely for your convenience, so that
|
||||
you have a handy permanent way to refer to a revision; Mercurial
|
||||
doesn't interpret the tag names you use in any way. Neither
|
||||
does Mercurial place any restrictions on the name of a tag,
|
||||
beyond a few that are necessary to ensure that a tag can be
|
||||
parsed unambiguously. A tag name cannot contain any of the
|
||||
following characters:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_36f"><a name="x_36f"></a>Colon (ASCII 58,
|
||||
“<span class="quote"><code class="literal">:</code></span>”)</p></li><li><p id="x_370"><a name="x_370"></a>Carriage return (ASCII 13,
|
||||
“<span class="quote"><code class="literal">\r</code></span>”)</p></li><li><p id="x_371"><a name="x_371"></a>Newline (ASCII 10,
|
||||
“<span class="quote"><code class="literal">\n</code></span>”)</p></li></ul></div><p id="x_372"><a name="x_372"></a>You can use the <span class="command"><strong>hg tags</strong></span>
|
||||
command to display the tags present in your repository. In the
|
||||
output, each tagged revision is identified first by its name,
|
||||
then by revision number, and finally by the unique hash of the
|
||||
revision.</p><pre id="id384189" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tags</code></strong>
|
||||
tip 1:8046fdcc425d
|
||||
v1.0 0:a80eb2d666b7
|
||||
</pre><p id="x_373"><a name="x_373"></a>Notice that <code class="literal">tip</code> is listed in the output
|
||||
of <span class="command"><strong>hg tags</strong></span>. The
|
||||
<code class="literal">tip</code> tag is a special “<span class="quote">floating</span>”
|
||||
tag, which always identifies the newest revision in the
|
||||
repository.</p><p id="x_374"><a name="x_374"></a>In the output of the <span class="command"><strong>hg
|
||||
tags</strong></span> command, tags are listed in reverse order, by
|
||||
revision number. This usually means that recent tags are listed
|
||||
before older tags. It also means that <code class="literal">tip</code> is
|
||||
always going to be the first tag listed in the output of
|
||||
<span class="command"><strong>hg tags</strong></span>.</p><p id="x_375"><a name="x_375"></a>When you run <span class="command"><strong>hg log</strong></span>, if it
|
||||
displays a revision that has tags associated with it, it will
|
||||
print those tags.</p><pre id="id384742" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg log</code></strong>
|
||||
changeset: 1:8046fdcc425d
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:45 2009 +0000
|
||||
summary: Added tag v1.0 for changeset a80eb2d666b7
|
||||
|
||||
changeset: 0:a80eb2d666b7
|
||||
tag: v1.0
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:45 2009 +0000
|
||||
summary: Initial commit
|
||||
|
||||
</pre><p id="x_376"><a name="x_376"></a>Any time you need to provide a revision ID to a Mercurial
|
||||
command, the command will accept a tag name in its place.
|
||||
Internally, Mercurial will translate your tag name into the
|
||||
corresponding revision ID, then use that.</p><pre id="id384652" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo goodbye > myfile2</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -A -m 'Second commit'</code></strong>
|
||||
adding myfile2
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg log -r v1.0</code></strong>
|
||||
changeset: 0:a80eb2d666b7
|
||||
tag: v1.0
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:45 2009 +0000
|
||||
summary: Initial commit
|
||||
|
||||
</pre><p id="x_377"><a name="x_377"></a>There's no limit on the number of tags you can have in a
|
||||
repository, or on the number of tags that a single revision can
|
||||
have. As a practical matter, it's not a great idea to have
|
||||
“<span class="quote">too many</span>” (a number which will vary from project
|
||||
to project), simply because tags are supposed to help you to
|
||||
find revisions. If you have lots of tags, the ease of using
|
||||
them to identify revisions diminishes rapidly.</p><p id="x_378"><a name="x_378"></a>For example, if your project has milestones as frequent as
|
||||
every few days, it's perfectly reasonable to tag each one of
|
||||
those. But if you have a continuous build system that makes
|
||||
sure every revision can be built cleanly, you'd be introducing a
|
||||
lot of noise if you were to tag every clean build. Instead, you
|
||||
could tag failed builds (on the assumption that they're rare!),
|
||||
or simply not use tags to track buildability.</p><p id="x_379"><a name="x_379"></a>If you want to remove a tag that you no longer want, use
|
||||
<span class="command"><strong>hg tag --remove</strong></span>.</p><pre id="id384619" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tag --remove v1.0</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tags</code></strong>
|
||||
tip 3:788019dad621
|
||||
</pre><p id="x_37a"><a name="x_37a"></a>You can also modify a tag at any time, so that it identifies
|
||||
a different revision, by simply issuing a new <span class="command"><strong>hg tag</strong></span> command. You'll have to use the
|
||||
<code class="option">-f</code> option to tell Mercurial
|
||||
that you <span class="emphasis"><em>really</em></span> want to update the
|
||||
tag.</p><pre id="id385034" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tag -r 1 v1.1</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tags</code></strong>
|
||||
tip 4:7027bc5755bd
|
||||
v1.1 1:8046fdcc425d
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tag -r 2 v1.1</code></strong>
|
||||
abort: tag 'v1.1' already exists (use -f to force)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tag -f -r 2 v1.1</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tags</code></strong>
|
||||
tip 5:cdbd327f8987
|
||||
v1.1 2:97a73dafd9c0
|
||||
</pre><p id="x_37b"><a name="x_37b"></a>There will still be a permanent record of the previous
|
||||
identity of the tag, but Mercurial will no longer use it.
|
||||
There's thus no penalty to tagging the wrong revision; all you
|
||||
have to do is turn around and tag the correct revision once you
|
||||
discover your error.</p><p id="x_37c"><a name="x_37c"></a>Mercurial stores tags in a normal revision-controlled file
|
||||
in your repository. If you've created any tags, you'll find
|
||||
them in a file in the root of your repository named <code class="filename">.hgtags</code>. When you run the <span class="command"><strong>hg tag</strong></span> command, Mercurial modifies
|
||||
this file, then automatically commits the change to it. This
|
||||
means that every time you run <span class="command"><strong>hg
|
||||
tag</strong></span>, you'll see a corresponding changeset in the
|
||||
output of <span class="command"><strong>hg log</strong></span>.</p><pre id="id385228" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 5:cdbd327f8987
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:46 2009 +0000
|
||||
summary: Added tag v1.1 for changeset 97a73dafd9c0
|
||||
|
||||
</pre><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id384894">Handling tag conflicts during a merge</h3></div></div></div><p id="x_37d"><a name="x_37d"></a>You won't often need to care about the <code class="filename">.hgtags</code> file, but it sometimes
|
||||
makes its presence known during a merge. The format of the
|
||||
file is simple: it consists of a series of lines. Each line
|
||||
starts with a changeset hash, followed by a space, followed by
|
||||
the name of a tag.</p><p id="x_37e"><a name="x_37e"></a>If you're resolving a conflict in the <code class="filename">.hgtags</code> file during a merge,
|
||||
there's one twist to modifying the <code class="filename">.hgtags</code> file: when Mercurial is
|
||||
parsing the tags in a repository, it
|
||||
<span class="emphasis"><em>never</em></span> reads the working copy of the
|
||||
<code class="filename">.hgtags</code> file. Instead, it
|
||||
reads the <span class="emphasis"><em>most recently committed</em></span>
|
||||
revision of the file.</p><p id="x_37f"><a name="x_37f"></a>An unfortunate consequence of this design is that you
|
||||
can't actually verify that your merged <code class="filename">.hgtags</code> file is correct until
|
||||
<span class="emphasis"><em>after</em></span> you've committed a change. So if
|
||||
you find yourself resolving a conflict on <code class="filename">.hgtags</code> during a merge, be sure to
|
||||
run <span class="command"><strong>hg tags</strong></span> after you commit.
|
||||
If it finds an error in the <code class="filename">.hgtags</code> file, it will report the
|
||||
location of the error, which you can then fix and commit. You
|
||||
should then run <span class="command"><strong>hg tags</strong></span>
|
||||
again, just to be sure that your fix is correct.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id385011">Tags and cloning</h3></div></div></div><p id="x_380"><a name="x_380"></a>You may have noticed that the <span class="command"><strong>hg
|
||||
clone</strong></span> command has a <code class="option">-r</code> option that lets you clone
|
||||
an exact copy of the repository as of a particular changeset.
|
||||
The new clone will not contain any project history that comes
|
||||
after the revision you specified. This has an interaction
|
||||
with tags that can surprise the unwary.</p><p id="x_381"><a name="x_381"></a>Recall that a tag is stored as a revision to
|
||||
the <code class="filename">.hgtags</code> file. When you
|
||||
create a tag, the changeset in which its recorded refers to an
|
||||
older changeset. When you run <span class="command"><strong>hg clone
|
||||
-r foo</strong></span> to clone a repository as of tag
|
||||
<code class="literal">foo</code>, the new clone <span class="emphasis"><em>will not
|
||||
contain any revision newer than the one the tag refers to,
|
||||
including the revision where the tag was created</em></span>.
|
||||
The result is that you'll get exactly the right subset of the
|
||||
project's history in the new repository, but
|
||||
<span class="emphasis"><em>not</em></span> the tag you might have
|
||||
expected.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id385111">When permanent tags are too much</h3></div></div></div><p id="x_382"><a name="x_382"></a>Since Mercurial's tags are revision controlled and carried
|
||||
around with a project's history, everyone you work with will
|
||||
see the tags you create. But giving names to revisions has
|
||||
uses beyond simply noting that revision
|
||||
<code class="literal">4237e45506ee</code> is really
|
||||
<code class="literal">v2.0.2</code>. If you're trying to track down a
|
||||
subtle bug, you might want a tag to remind you of something
|
||||
like “<span class="quote">Anne saw the symptoms with this
|
||||
revision</span>”.</p><p id="x_383"><a name="x_383"></a>For cases like this, what you might want to use are
|
||||
<span class="emphasis"><em>local</em></span> tags. You can create a local tag
|
||||
with the <code class="option">-l</code> option to the
|
||||
<span class="command"><strong>hg tag</strong></span> command. This will
|
||||
store the tag in a file called <code class="filename">.hg/localtags</code>. Unlike <code class="filename">.hgtags</code>, <code class="filename">.hg/localtags</code> is not revision
|
||||
controlled. Any tags you create using <code class="option">-l</code> remain strictly local to the
|
||||
repository you're currently working in.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id385202">The flow of changes—big picture vs. little</h2></div></div></div><p id="x_384"><a name="x_384"></a>To return to the outline I sketched at the
|
||||
beginning of the chapter, let's think about a project that has
|
||||
multiple concurrent pieces of work under development at
|
||||
once.</p><p id="x_385"><a name="x_385"></a>There might be a push for a new “<span class="quote">main</span>” release;
|
||||
a new minor bugfix release to the last main release; and an
|
||||
unexpected “<span class="quote">hot fix</span>” to an old release that is now
|
||||
in maintenance mode.</p><p id="x_386"><a name="x_386"></a>The usual way people refer to these different concurrent
|
||||
directions of development is as “<span class="quote">branches</span>”.
|
||||
However, we've already seen numerous times that Mercurial treats
|
||||
<span class="emphasis"><em>all of history</em></span> as a series of branches and
|
||||
merges. Really, what we have here is two ideas that are
|
||||
peripherally related, but which happen to share a name.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_387"><a name="x_387"></a>“<span class="quote">Big picture</span>” branches represent
|
||||
the sweep of a project's evolution; people give them names,
|
||||
and talk about them in conversation.</p></li><li><p id="x_388"><a name="x_388"></a>“<span class="quote">Little picture</span>” branches are
|
||||
artefacts of the day-to-day activity of developing and
|
||||
merging changes. They expose the narrative of how the code
|
||||
was developed.</p></li></ul></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id385287">Managing big-picture branches in repositories</h2></div></div></div><p id="x_389"><a name="x_389"></a>The easiest way to isolate a “<span class="quote">big picture</span>”
|
||||
branch in Mercurial is in a dedicated repository. If you have
|
||||
an existing shared repository—let's call it
|
||||
<code class="literal">myproject</code>—that reaches a
|
||||
“<span class="quote">1.0</span>” milestone, you can start to prepare for
|
||||
future maintenance releases on top of version 1.0 by tagging the
|
||||
revision from which you prepared the 1.0 release.</p><pre id="id385665" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd myproject</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tag v1.0</code></strong>
|
||||
</pre><p id="x_38a"><a name="x_38a"></a>You can then clone a new shared
|
||||
<code class="literal">myproject-1.0.1</code> repository as of that
|
||||
tag.</p><pre id="id385745" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone myproject myproject-1.0.1</code></strong>
|
||||
updating working directory
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_38b"><a name="x_38b"></a>Afterwards, if someone needs to work on a bug fix that ought
|
||||
to go into an upcoming 1.0.1 minor release, they clone the
|
||||
<code class="literal">myproject-1.0.1</code> repository, make their
|
||||
changes, and push them back.</p><pre id="id385828" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg clone myproject-1.0.1 my-1.0.1-bugfix</code></strong>
|
||||
updating working directory
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd my-1.0.1-bugfix</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo 'I fixed a bug using only echo!' >> myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Important fix for 1.0.1'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg push</code></strong>
|
||||
pushing to /tmp/branch-repo1HDNuO/myproject-1.0.1
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files
|
||||
</pre><p id="x_38c"><a name="x_38c"></a>Meanwhile, development for
|
||||
the next major release can continue, isolated and unabated, in
|
||||
the <code class="literal">myproject</code> repository.</p><pre id="id385558" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone myproject my-feature</code></strong>
|
||||
updating working directory
|
||||
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd my-feature</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo 'This sure is an exciting new feature!' > mynewfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -A -m 'New feature'</code></strong>
|
||||
adding mynewfile
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg push</code></strong>
|
||||
pushing to /tmp/branch-repo1HDNuO/myproject
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id385475">Don't repeat yourself: merging across branches</h2></div></div></div><p id="x_38d"><a name="x_38d"></a>In many cases, if you have a bug to fix on a maintenance
|
||||
branch, the chances are good that the bug exists on your
|
||||
project's main branch (and possibly other maintenance branches,
|
||||
too). It's a rare developer who wants to fix the same bug
|
||||
multiple times, so let's look at a few ways that Mercurial can
|
||||
help you to manage these bugfixes without duplicating your
|
||||
work.</p><p id="x_38e"><a name="x_38e"></a>In the simplest instance, all you need to do is pull changes
|
||||
from your maintenance branch into your local clone of the target
|
||||
branch.</p><pre id="id385508" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone myproject myproject-merge</code></strong>
|
||||
updating working directory
|
||||
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd myproject-merge</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg pull ../myproject-1.0.1</code></strong>
|
||||
pulling from ../myproject-1.0.1
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files (+1 heads)
|
||||
(run 'hg heads' to see heads, 'hg merge' to merge)
|
||||
</pre><p id="x_38f"><a name="x_38f"></a>You'll then need to merge the heads of the two branches, and
|
||||
push back to the main branch.</p><pre id="id385922" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
(branch merge, don't forget to commit)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Merge bugfix from 1.0.1 branch'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg push</code></strong>
|
||||
pushing to /tmp/branch-repo1HDNuO/myproject
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 2 changesets with 1 changes to 1 files
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id386031">Naming branches within one repository</h2></div></div></div><p id="x_390"><a name="x_390"></a>In most instances, isolating branches in repositories is the
|
||||
right approach. Its simplicity makes it easy to understand; and
|
||||
so it's hard to make mistakes. There's a one-to-one
|
||||
relationship between branches you're working in and directories
|
||||
on your system. This lets you use normal (non-Mercurial-aware)
|
||||
tools to work on files within a branch/repository.</p><p id="x_391"><a name="x_391"></a>If you're more in the “<span class="quote">power user</span>” category
|
||||
(<span class="emphasis"><em>and</em></span> your collaborators are too), there is
|
||||
an alternative way of handling branches that you can consider.
|
||||
I've already mentioned the human-level distinction between
|
||||
“<span class="quote">small picture</span>” and “<span class="quote">big picture</span>”
|
||||
branches. While Mercurial works with multiple “<span class="quote">small
|
||||
picture</span>” branches in a repository all the time (for
|
||||
example after you pull changes in, but before you merge them),
|
||||
it can <span class="emphasis"><em>also</em></span> work with multiple “<span class="quote">big
|
||||
picture</span>” branches.</p><p id="x_392"><a name="x_392"></a>The key to working this way is that Mercurial lets you
|
||||
assign a persistent <span class="emphasis"><em>name</em></span> to a branch.
|
||||
There always exists a branch named <code class="literal">default</code>.
|
||||
Even before you start naming branches yourself, you can find
|
||||
traces of the <code class="literal">default</code> branch if you look for
|
||||
them.</p><p id="x_393"><a name="x_393"></a>As an example, when you run the <span class="command"><strong>hg
|
||||
commit</strong></span> command, and it pops up your editor so that
|
||||
you can enter a commit message, look for a line that contains
|
||||
the text “<span class="quote"><code class="literal">HG: branch default</code></span>” at
|
||||
the bottom. This is telling you that your commit will occur on
|
||||
the branch named <code class="literal">default</code>.</p><p id="x_394"><a name="x_394"></a>To start working with named branches, use the <span class="command"><strong>hg branches</strong></span> command. This command
|
||||
lists the named branches already present in your repository,
|
||||
telling you which changeset is the tip of each.</p><pre id="id386525" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 0:692c56a8362e
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:16 2009 +0000
|
||||
summary: Initial commit
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg branches</code></strong>
|
||||
default 0:692c56a8362e
|
||||
</pre><p id="x_395"><a name="x_395"></a>Since you haven't created any named branches yet, the only
|
||||
one that exists is <code class="literal">default</code>.</p><p id="x_396"><a name="x_396"></a>To find out what the “<span class="quote">current</span>” branch is, run
|
||||
the <span class="command"><strong>hg branch</strong></span> command, giving
|
||||
it no arguments. This tells you what branch the parent of the
|
||||
current changeset is on.</p><pre id="id386475" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg branch</code></strong>
|
||||
default
|
||||
</pre><p id="x_397"><a name="x_397"></a>To create a new branch, run the <span class="command"><strong>hg
|
||||
branch</strong></span> command again. This time, give it one
|
||||
argument: the name of the branch you want to create.</p><pre id="id386501" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg branch foo</code></strong>
|
||||
marked working directory as branch foo
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg branch</code></strong>
|
||||
foo
|
||||
</pre><p id="x_398"><a name="x_398"></a>After you've created a branch, you might wonder what effect
|
||||
the <span class="command"><strong>hg branch</strong></span> command has had.
|
||||
What do the <span class="command"><strong>hg status</strong></span> and
|
||||
<span class="command"><strong>hg tip</strong></span> commands report?</p><pre id="id386417" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 0:692c56a8362e
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:16 2009 +0000
|
||||
summary: Initial commit
|
||||
|
||||
</pre><p id="x_399"><a name="x_399"></a>Nothing has changed in the
|
||||
working directory, and there's been no new history created. As
|
||||
this suggests, running the <span class="command"><strong>hg
|
||||
branch</strong></span> command has no permanent effect; it only
|
||||
tells Mercurial what branch name to use the
|
||||
<span class="emphasis"><em>next</em></span> time you commit a changeset.</p><p id="x_39a"><a name="x_39a"></a>When you commit a change, Mercurial records the name of the
|
||||
branch on which you committed. Once you've switched from the
|
||||
<code class="literal">default</code> branch to another and committed,
|
||||
you'll see the name of the new branch show up in the output of
|
||||
<span class="command"><strong>hg log</strong></span>, <span class="command"><strong>hg tip</strong></span>, and other commands that
|
||||
display the same kind of output.</p><pre id="id386918" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo 'hello again' >> myfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Second commit'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 1:554c1c20014c
|
||||
branch: foo
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:17 2009 +0000
|
||||
summary: Second commit
|
||||
|
||||
</pre><p id="x_39b"><a name="x_39b"></a>The <span class="command"><strong>hg log</strong></span>-like commands
|
||||
will print the branch name of every changeset that's not on the
|
||||
<code class="literal">default</code> branch. As a result, if you never
|
||||
use named branches, you'll never see this information.</p><p id="x_39c"><a name="x_39c"></a>Once you've named a branch and committed a change with that
|
||||
name, every subsequent commit that descends from that change
|
||||
will inherit the same branch name. You can change the name of a
|
||||
branch at any time, using the <span class="command"><strong>hg
|
||||
branch</strong></span> command.</p><pre id="id386816" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg branch</code></strong>
|
||||
foo
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg branch bar</code></strong>
|
||||
marked working directory as branch bar
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo new file > newfile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -A -m 'Third commit'</code></strong>
|
||||
adding newfile
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 2:b9e802e02f12
|
||||
branch: bar
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:17 2009 +0000
|
||||
summary: Third commit
|
||||
|
||||
</pre><p id="x_39d"><a name="x_39d"></a>In practice, this is something you won't do very often, as
|
||||
branch names tend to have fairly long lifetimes. (This isn't a
|
||||
rule, just an observation.)</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id386726">Dealing with multiple named branches in a
|
||||
repository</h2></div></div></div><p id="x_39e"><a name="x_39e"></a>If you have more than one named branch in a repository,
|
||||
Mercurial will remember the branch that your working directory
|
||||
is on when you start a command like <span class="command"><strong>hg
|
||||
update</strong></span> or <span class="command"><strong>hg pull
|
||||
-u</strong></span>. It will update the working directory to the tip
|
||||
of this branch, no matter what the “<span class="quote">repo-wide</span>” tip
|
||||
is. To update to a revision that's on a different named branch,
|
||||
you may need to use the <code class="option">-C</code>
|
||||
option to <span class="command"><strong>hg update</strong></span>.</p><p id="x_39f"><a name="x_39f"></a>This behavior is a little subtle, so let's see it in
|
||||
action. First, let's remind ourselves what branch we're
|
||||
currently on, and what branches are in our repository.</p><pre id="id387049" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong>
|
||||
changeset: 2:b9e802e02f12
|
||||
branch: bar
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:17 2009 +0000
|
||||
summary: Third commit
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg branches</code></strong>
|
||||
bar 2:b9e802e02f12
|
||||
foo 1:554c1c20014c (inactive)
|
||||
default 0:692c56a8362e (inactive)
|
||||
</pre><p id="x_3a0"><a name="x_3a0"></a>We're on the <code class="literal">bar</code> branch, but there also
|
||||
exists an older <span class="command"><strong>hg foo</strong></span>
|
||||
branch.</p><p id="x_3a1"><a name="x_3a1"></a>We can <span class="command"><strong>hg update</strong></span> back and
|
||||
forth between the tips of the <code class="literal">foo</code> and
|
||||
<code class="literal">bar</code> branches without needing to use the
|
||||
<code class="option">-C</code> option, because this
|
||||
only involves going backwards and forwards linearly through our
|
||||
change history.</p><pre id="id387392" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg update foo</code></strong>
|
||||
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong>
|
||||
changeset: 1:554c1c20014c
|
||||
branch: foo
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:17 2009 +0000
|
||||
summary: Second commit
|
||||
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg update bar</code></strong>
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg parents</code></strong>
|
||||
changeset: 2:b9e802e02f12
|
||||
branch: bar
|
||||
tag: tip
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:17 2009 +0000
|
||||
summary: Third commit
|
||||
|
||||
</pre><p id="x_3a2"><a name="x_3a2"></a>If we go back to the <code class="literal">foo</code> branch and then
|
||||
run <span class="command"><strong>hg update</strong></span>, it will keep us
|
||||
on <code class="literal">foo</code>, not move us to the tip of
|
||||
<code class="literal">bar</code>.</p><pre id="id387295" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg update foo</code></strong>
|
||||
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg update</code></strong>
|
||||
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_3a3"><a name="x_3a3"></a>Committing a new change on the <code class="literal">foo</code> branch
|
||||
introduces a new head.</p><pre id="id387632" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo something > somefile</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -A -m 'New file'</code></strong>
|
||||
adding somefile
|
||||
created new head
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg heads</code></strong>
|
||||
changeset: 3:04da8e502cbb
|
||||
branch: foo
|
||||
tag: tip
|
||||
parent: 1:554c1c20014c
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:18 2009 +0000
|
||||
summary: New file
|
||||
|
||||
changeset: 2:b9e802e02f12
|
||||
branch: bar
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:17 2009 +0000
|
||||
summary: Third commit
|
||||
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id387231">Branch names and merging</h2></div></div></div><p id="x_3a4"><a name="x_3a4"></a>As you've probably noticed, merges in Mercurial are not
|
||||
symmetrical. Let's say our repository has two heads, 17 and 23.
|
||||
If I <span class="command"><strong>hg update</strong></span> to 17 and then
|
||||
<span class="command"><strong>hg merge</strong></span> with 23, Mercurial
|
||||
records 17 as the first parent of the merge, and 23 as the
|
||||
second. Whereas if I <span class="command"><strong>hg update</strong></span>
|
||||
to 23 and then <span class="command"><strong>hg merge</strong></span> with
|
||||
17, it records 23 as the first parent, and 17 as the
|
||||
second.</p><p id="x_3a5"><a name="x_3a5"></a>This affects Mercurial's choice of branch name when you
|
||||
merge. After a merge, Mercurial will retain the branch name of
|
||||
the first parent when you commit the result of the merge. If
|
||||
your first parent's branch name is <code class="literal">foo</code>, and
|
||||
you merge with <code class="literal">bar</code>, the branch name will
|
||||
still be <code class="literal">foo</code> after you merge.</p><p id="x_3a6"><a name="x_3a6"></a>It's not unusual for a repository to contain multiple heads,
|
||||
each with the same branch name. Let's say I'm working on the
|
||||
<code class="literal">foo</code> branch, and so are you. We commit
|
||||
different changes; I pull your changes; I now have two heads,
|
||||
each claiming to be on the <code class="literal">foo</code> branch. The
|
||||
result of a merge will be a single head on the
|
||||
<code class="literal">foo</code> branch, as you might hope.</p><p id="x_3a7"><a name="x_3a7"></a>But if I'm working on the <code class="literal">bar</code> branch, and
|
||||
I merge work from the <code class="literal">foo</code> branch, the result
|
||||
will remain on the <code class="literal">bar</code> branch.</p><pre id="id387860" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg branch</code></strong>
|
||||
bar
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg merge foo</code></strong>
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
(branch merge, don't forget to commit)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Merge'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg tip</code></strong>
|
||||
changeset: 4:c760b46b1a7b
|
||||
branch: bar
|
||||
tag: tip
|
||||
parent: 2:b9e802e02f12
|
||||
parent: 3:04da8e502cbb
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:18 2009 +0000
|
||||
summary: Merge
|
||||
|
||||
</pre><p id="x_3a8"><a name="x_3a8"></a>To give a more concrete example, if I'm working on the
|
||||
<code class="literal">bleeding-edge</code> branch, and I want to bring in
|
||||
the latest fixes from the <code class="literal">stable</code> branch,
|
||||
Mercurial will choose the “<span class="quote">right</span>”
|
||||
(<code class="literal">bleeding-edge</code>) branch name when I pull and
|
||||
merge from <code class="literal">stable</code>.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id387616">Branch naming is generally useful</h2></div></div></div><p id="x_3a9"><a name="x_3a9"></a>You shouldn't think of named branches as applicable only to
|
||||
situations where you have multiple long-lived branches
|
||||
cohabiting in a single repository. They're very useful even in
|
||||
the one-branch-per-repository case.</p><p id="x_3aa"><a name="x_3aa"></a>In the simplest case, giving a name to each branch gives you
|
||||
a permanent record of which branch a changeset originated on.
|
||||
This gives you more context when you're trying to follow the
|
||||
history of a long-lived branchy project.</p><p id="x_3ab"><a name="x_3ab"></a>If you're working with shared repositories, you can set up a
|
||||
<code class="literal">pretxnchangegroup</code> hook on each
|
||||
that will block incoming changes that have the
|
||||
“<span class="quote">wrong</span>” branch name. This provides a simple, but
|
||||
effective, defence against people accidentally pushing changes
|
||||
from a “<span class="quote">bleeding edge</span>” branch to a
|
||||
“<span class="quote">stable</span>” branch. Such a hook might look like this
|
||||
inside the shared repo's <code class="filename">
|
||||
/.hgrc</code>.</p><pre id="id387701" class="programlisting">[hooks]
|
||||
pretxnchangegroup.branch = hg heads --template '{branches} ' | grep mybranch</pre></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="file-names-and-pattern-matching.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="finding-and-fixing-mistakes.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 7. File names and pattern matching </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 9. Finding and fixing mistakes</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
671
read/mercurial-in-daily-use.html
Normal file
671
read/mercurial-in-daily-use.html
Normal file
|
@ -0,0 +1,671 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter 5. Mercurial in daily use</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="behind-the-scenes.html" title="Chapter 4. Behind the scenes"><link rel="next" href="collaborating-with-other-people.html" title="Chapter 6. Collaborating with other people"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 5. Mercurial in daily use</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="behind-the-scenes.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="collaborating-with-other-people.html">Next</a></td></tr></table></div><div class="chapter" lang="en" id="chap:daily"><div class="titlepage"><div><div><h2 class="title">Chapter 5. Mercurial in daily use</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="mercurial-in-daily-use.html#id360398">Telling Mercurial which files to track</a></span></dt><dd><dl><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id360891">Explicit versus implicit file naming</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id361216">Mercurial tracks files, not directories</a></span></dt></dl></dd><dt><span class="sect1"><a href="mercurial-in-daily-use.html#id361518">How to stop tracking a file</a></span></dt><dd><dl><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id361912">Removing a file does not affect its history</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id361971">Missing files</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id362350">Aside: why tell Mercurial explicitly to remove a
|
||||
file?</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id362374">Useful shorthand—adding and removing files in one
|
||||
step</a></span></dt></dl></dd><dt><span class="sect1"><a href="mercurial-in-daily-use.html#chap:daily.copy">Copying files</a></span></dt><dd><dl><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id362673">The results of copying during a merge</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#sec:daily:why-copy">Why should changes follow copies?</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id363437">How to make changes not follow a
|
||||
copy</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id363575">Behavior of the hg copy
|
||||
command</a></span></dt></dl></dd><dt><span class="sect1"><a href="mercurial-in-daily-use.html#id364064">Renaming files</a></span></dt><dd><dl><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id364249">Renaming files and merging changes</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id364290">Divergent renames and merging</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id364713">Convergent renames and merging</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id364870">Other name-related corner cases</a></span></dt></dl></dd><dt><span class="sect1"><a href="mercurial-in-daily-use.html#id365158">Recovering from mistakes</a></span></dt><dt><span class="sect1"><a href="mercurial-in-daily-use.html#id365252">Dealing with tricky merges</a></span></dt><dd><dl><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id366109">File resolution states</a></span></dt><dt><span class="sect2"><a href="mercurial-in-daily-use.html#id366263">Resolving a file merge</a></span></dt></dl></dd><dt><span class="sect1"><a href="mercurial-in-daily-use.html#id366325">More useful diffs</a></span></dt><dt><span class="sect1"><a href="mercurial-in-daily-use.html#id366788">Which files to manage, and which to avoid</a></span></dt><dt><span class="sect1"><a href="mercurial-in-daily-use.html#id360710">Backups and mirroring</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id360398">Telling Mercurial which files to track</h2></div></div></div><p id="x_1a3"><a name="x_1a3"></a>Mercurial does not work with files in your repository unless
|
||||
you tell it to manage them. The <span class="command"><strong>hg
|
||||
status</strong></span> command will tell you which files Mercurial
|
||||
doesn't know about; it uses a
|
||||
“<span class="quote"><code class="literal">?</code></span>” to display such
|
||||
files.</p><p id="x_1a4"><a name="x_1a4"></a>To tell Mercurial to track a file, use the <span class="command"><strong>hg add</strong></span> command. Once you have added a
|
||||
file, the entry in the output of <span class="command"><strong>hg
|
||||
status</strong></span> for that file changes from
|
||||
“<span class="quote"><code class="literal">?</code></span>” to
|
||||
“<span class="quote"><code class="literal">A</code></span>”.</p><pre id="id361125" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init add-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd add-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo a > myfile.txt</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
? myfile.txt
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add myfile.txt</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
A myfile.txt
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Added one file'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
</pre><p id="x_1a5"><a name="x_1a5"></a>After you run a <span class="command"><strong>hg commit</strong></span>,
|
||||
the files that you added before the commit will no longer be
|
||||
listed in the output of <span class="command"><strong>hg
|
||||
status</strong></span>. The reason for this is that by default, <span class="command"><strong>hg status</strong></span> only tells you about
|
||||
“<span class="quote">interesting</span>” files—those that you have (for
|
||||
example) modified, removed, or renamed. If you have a repository
|
||||
that contains thousands of files, you will rarely want to know
|
||||
about files that Mercurial is tracking, but that have not
|
||||
changed. (You can still get this information; we'll return to
|
||||
this later.)</p><p id="x_1a6"><a name="x_1a6"></a>Once you add a file, Mercurial doesn't do anything with it
|
||||
immediately. Instead, it will take a snapshot of the file's
|
||||
state the next time you perform a commit. It will then continue
|
||||
to track the changes you make to the file every time you commit,
|
||||
until you remove the file.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id360891">Explicit versus implicit file naming</h3></div></div></div><p id="x_1a7"><a name="x_1a7"></a>A useful behavior that Mercurial has is that if you pass
|
||||
the name of a directory to a command, every Mercurial command
|
||||
will treat this as “<span class="quote">I want to operate on every file in
|
||||
this directory and its subdirectories</span>”.</p><pre id="id361402" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mkdir b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo b > b/somefile.txt</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo c > b/source.cpp</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>mkdir b/d</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo d > b/d/test.h</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add b</code></strong>
|
||||
adding b/d/test.h
|
||||
adding b/somefile.txt
|
||||
adding b/source.cpp
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Added all files in subdirectory'</code></strong>
|
||||
</pre><p id="x_1a8"><a name="x_1a8"></a>Notice in this example that Mercurial printed
|
||||
the names of the files it added, whereas it didn't do so when
|
||||
we added the file named <code class="filename">myfile.txt</code> in the
|
||||
earlier example.</p><p id="x_1a9"><a name="x_1a9"></a>What's going on is that in the former case, we explicitly
|
||||
named the file to add on the command line. The assumption
|
||||
that Mercurial makes in such cases is that we know what we
|
||||
are doing, and it doesn't print any output.</p><p id="x_1aa"><a name="x_1aa"></a>However, when we <span class="emphasis"><em>imply</em></span> the names of
|
||||
files by giving the name of a directory, Mercurial takes the
|
||||
extra step of printing the name of each file that it does
|
||||
something with. This makes it more clear what is happening,
|
||||
and reduces the likelihood of a silent and nasty surprise.
|
||||
This behavior is common to most Mercurial commands.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id361216">Mercurial tracks files, not directories</h3></div></div></div><p id="x_1ab"><a name="x_1ab"></a>Mercurial does not track directory information. Instead,
|
||||
it tracks the path to a file. Before creating a file, it
|
||||
first creates any missing directory components of the path.
|
||||
After it deletes a file, it then deletes any empty directories
|
||||
that were in the deleted file's path. This sounds like a
|
||||
trivial distinction, but it has one minor practical
|
||||
consequence: it is not possible to represent a completely
|
||||
empty directory in Mercurial.</p><p id="x_1ac"><a name="x_1ac"></a>Empty directories are rarely useful, and there are
|
||||
unintrusive workarounds that you can use to achieve an
|
||||
appropriate effect. The developers of Mercurial thus felt
|
||||
that the complexity that would be required to manage empty
|
||||
directories was not worth the limited benefit this feature
|
||||
would bring.</p><p id="x_1ad"><a name="x_1ad"></a>If you need an empty directory in your repository, there
|
||||
are a few ways to achieve this. One is to create a directory,
|
||||
then <span class="command"><strong>hg add</strong></span> a
|
||||
“<span class="quote">hidden</span>” file to that directory. On Unix-like
|
||||
systems, any file name that begins with a period
|
||||
(“<span class="quote"><code class="literal">.</code></span>”) is treated as hidden by
|
||||
most commands and GUI tools. This approach is illustrated
|
||||
below.</p><pre id="id361678" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init hidden-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd hidden-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>mkdir empty</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>touch empty/.hidden</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add empty/.hidden</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Manage an empty-looking directory'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls empty</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone hidden-example tmp</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls tmp</code></strong>
|
||||
empty
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls tmp/empty</code></strong>
|
||||
</pre><p id="x_1ae"><a name="x_1ae"></a>Another way to tackle a need for an empty directory is to
|
||||
simply create one in your automated build scripts before they
|
||||
will need it.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id361518">How to stop tracking a file</h2></div></div></div><p id="x_1af"><a name="x_1af"></a>Once you decide that a file no longer belongs in
|
||||
your repository, use the <span class="command"><strong>hg
|
||||
remove</strong></span> command. This deletes the file, and tells
|
||||
Mercurial to stop tracking it (which will occur at the next
|
||||
commit). A removed file is represented in the output of
|
||||
<span class="command"><strong>hg status</strong></span> with a
|
||||
“<span class="quote"><code class="literal">R</code></span>”.</p><pre id="id361614" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init remove-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd remove-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo a > a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>mkdir b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo b > b/b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add a b</code></strong>
|
||||
adding b/b
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Small example for file removal'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg remove a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
R a
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg remove b</code></strong>
|
||||
removing b/b
|
||||
</pre><p id="x_1b0"><a name="x_1b0"></a>After you <span class="command"><strong>hg remove</strong></span> a file,
|
||||
Mercurial will no longer track changes to that file, even if you
|
||||
recreate a file with the same name in your working directory.
|
||||
If you do recreate a file with the same name and want Mercurial
|
||||
to track the new file, simply <span class="command"><strong>hg
|
||||
add</strong></span> it. Mercurial will know that the newly added
|
||||
file is not related to the old file of the same name.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id361912">Removing a file does not affect its history</h3></div></div></div><p id="x_1b1"><a name="x_1b1"></a>It is important to understand that removing a file has
|
||||
only two effects.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_1b2"><a name="x_1b2"></a>It removes the current version of the file
|
||||
from the working directory.</p></li><li><p id="x_1b3"><a name="x_1b3"></a>It stops Mercurial from tracking changes to
|
||||
the file, from the time of the next commit.</p></li></ul></div><p id="x_1b4"><a name="x_1b4"></a>Removing a file <span class="emphasis"><em>does not</em></span> in any way
|
||||
alter the <span class="emphasis"><em>history</em></span> of the file.</p><p id="x_1b5"><a name="x_1b5"></a>If you update the working directory to a
|
||||
changeset that was committed when it was still tracking a file
|
||||
that you later removed, the file will reappear in the working
|
||||
directory, with the contents it had when you committed that
|
||||
changeset. If you then update the working directory to a
|
||||
later changeset, in which the file had been removed, Mercurial
|
||||
will once again remove the file from the working
|
||||
directory.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id361971">Missing files</h3></div></div></div><p id="x_1b6"><a name="x_1b6"></a>Mercurial considers a file that you have deleted, but not
|
||||
used <span class="command"><strong>hg remove</strong></span> to delete, to
|
||||
be <span class="emphasis"><em>missing</em></span>. A missing file is
|
||||
represented with “<span class="quote"><code class="literal">!</code></span>” in the
|
||||
output of <span class="command"><strong>hg status</strong></span>.
|
||||
Mercurial commands will not generally do anything with missing
|
||||
files.</p><pre id="id362389" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init missing-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd missing-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo a > a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'File about to be missing'</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>rm a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
! a
|
||||
</pre><p id="x_1b7"><a name="x_1b7"></a>If your repository contains a file that <span class="command"><strong>hg status</strong></span> reports as missing, and
|
||||
you want the file to stay gone, you can run <span class="command"><strong>hg remove <code class="option">--after</code></strong></span> at any
|
||||
time later on, to tell Mercurial that you really did mean to
|
||||
remove the file.</p><pre id="id362602" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg remove --after a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
R a
|
||||
</pre><p id="x_1b8"><a name="x_1b8"></a>On the other hand, if you deleted the missing file by
|
||||
accident, give <span class="command"><strong>hg revert</strong></span> the
|
||||
name of the file to recover. It will reappear, in unmodified
|
||||
form.</p><pre id="id362278" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg revert a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat a</code></strong>
|
||||
a
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id362350">Aside: why tell Mercurial explicitly to remove a
|
||||
file?</h3></div></div></div><p id="x_1b9"><a name="x_1b9"></a>You might wonder why Mercurial requires you to explicitly
|
||||
tell it that you are deleting a file. Early during the
|
||||
development of Mercurial, it let you delete a file however you
|
||||
pleased; Mercurial would notice the absence of the file
|
||||
automatically when you next ran a <span class="command"><strong>hg
|
||||
commit</strong></span>, and stop tracking the file. In practice,
|
||||
this made it too easy to accidentally remove a file without
|
||||
noticing.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id362374">Useful shorthand—adding and removing files in one
|
||||
step</h3></div></div></div><p id="x_1ba"><a name="x_1ba"></a>Mercurial offers a combination command, <span class="command"><strong>hg addremove</strong></span>, that adds untracked
|
||||
files and marks missing files as removed.</p><pre id="id362827" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init addremove-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd addremove-example</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo a > a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo b > b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg addremove</code></strong>
|
||||
adding a
|
||||
adding b
|
||||
</pre><p id="x_1bb"><a name="x_1bb"></a>The <span class="command"><strong>hg commit</strong></span> command
|
||||
also provides a <code class="option">-A</code>
|
||||
option that performs this same add-and-remove, immediately
|
||||
followed by a commit.</p><pre id="id362800" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo c > c</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -A -m 'Commit with addremove'</code></strong>
|
||||
adding c
|
||||
</pre></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="chap:daily.copy">Copying files</h2></div></div></div><p id="x_1bc"><a name="x_1bc"></a>Mercurial provides a <span class="command"><strong>hg
|
||||
copy</strong></span> command that lets you make a new copy of a
|
||||
file. When you copy a file using this command, Mercurial makes
|
||||
a record of the fact that the new file is a copy of the original
|
||||
file. It treats these copied files specially when you merge
|
||||
your work with someone else's.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id362673">The results of copying during a merge</h3></div></div></div><p id="x_1bd"><a name="x_1bd"></a>What happens during a merge is that changes
|
||||
“<span class="quote">follow</span>” a copy. To best illustrate what this
|
||||
means, let's create an example. We'll start with the usual
|
||||
tiny repository that contains a single file.</p><pre id="id362752" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init my-copy</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd my-copy</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo line > file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg add file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Added a file'</code></strong>
|
||||
</pre><p id="x_1be"><a name="x_1be"></a>We need to do some work in
|
||||
parallel, so that we'll have something to merge. So let's
|
||||
clone our repository.</p><pre id="id363244" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone my-copy your-copy</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_1bf"><a name="x_1bf"></a>Back in our initial repository, let's use the <span class="command"><strong>hg copy</strong></span> command to make a copy of
|
||||
the first file we created.</p><pre id="id363206" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd my-copy</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg copy file new-file</code></strong>
|
||||
</pre><p id="x_1c0"><a name="x_1c0"></a>If we look at the output of the <span class="command"><strong>hg
|
||||
status</strong></span> command afterwards, the copied file looks
|
||||
just like a normal added file.</p><pre id="id363145" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
A new-file
|
||||
</pre><p id="x_1c1"><a name="x_1c1"></a>But if we pass the <code class="option">-C</code> option to <span class="command"><strong>hg status</strong></span>, it prints another line of
|
||||
output: this is the file that our newly-added file was copied
|
||||
<span class="emphasis"><em>from</em></span>.</p><pre id="id363483" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status -C</code></strong>
|
||||
A new-file
|
||||
file
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Copied file'</code></strong>
|
||||
</pre><p id="x_1c2"><a name="x_1c2"></a>Now, back in the repository we cloned, let's make a change
|
||||
in parallel. We'll add a line of content to the original file
|
||||
that we created.</p><pre id="id363089" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ../your-copy</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo 'new contents' >> file</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Changed file'</code></strong>
|
||||
</pre><p id="x_1c3"><a name="x_1c3"></a>Now we have a modified <code class="filename">file</code> in this
|
||||
repository. When we pull the changes from the first
|
||||
repository, and merge the two heads, Mercurial will propagate
|
||||
the changes that we made locally to <code class="filename">file</code>
|
||||
into its copy, <code class="filename">new-file</code>.</p><pre id="id363538" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg pull ../my-copy</code></strong>
|
||||
pulling from ../my-copy
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files (+1 heads)
|
||||
(run 'hg heads' to see heads, 'hg merge' to merge)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
|
||||
merging file and new-file to new-file
|
||||
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
|
||||
(branch merge, don't forget to commit)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cat new-file</code></strong>
|
||||
line
|
||||
new contents
|
||||
</pre></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:daily:why-copy">Why should changes follow copies?</h3></div></div></div><p id="x_1c4"><a name="x_1c4"></a>This behavior—of changes to a file
|
||||
propagating out to copies of the file—might seem
|
||||
esoteric, but in most cases it's highly desirable.</p><p id="x_1c5"><a name="x_1c5"></a>First of all, remember that this propagation
|
||||
<span class="emphasis"><em>only</em></span> happens when you merge. So if you
|
||||
<span class="command"><strong>hg copy</strong></span> a file, and
|
||||
subsequently modify the original file during the normal course
|
||||
of your work, nothing will happen.</p><p id="x_1c6"><a name="x_1c6"></a>The second thing to know is that modifications will only
|
||||
propagate across a copy as long as the changeset that you're
|
||||
merging changes from <span class="emphasis"><em>hasn't yet seen</em></span>
|
||||
the copy.</p><p id="x_1c7"><a name="x_1c7"></a>The reason that Mercurial does this is as follows. Let's
|
||||
say I make an important bug fix in a source file, and commit
|
||||
my changes. Meanwhile, you've decided to <span class="command"><strong>hg copy</strong></span> the file in your repository,
|
||||
without knowing about the bug or having seen the fix, and you
|
||||
have started hacking on your copy of the file.</p><p id="x_1c8"><a name="x_1c8"></a>If you pulled and merged my changes, and Mercurial
|
||||
<span class="emphasis"><em>didn't</em></span> propagate changes across copies,
|
||||
your new source file would now contain the bug, and unless you
|
||||
knew to propagate the bug fix by hand, the bug would
|
||||
<span class="emphasis"><em>remain</em></span> in your copy of the file.</p><p id="x_1c9"><a name="x_1c9"></a>By automatically propagating the change that fixed the bug
|
||||
from the original file to the copy, Mercurial prevents this
|
||||
class of problem. To my knowledge, Mercurial is the
|
||||
<span class="emphasis"><em>only</em></span> revision control system that
|
||||
propagates changes across copies like this.</p><p id="x_1ca"><a name="x_1ca"></a>Once your change history has a record that the copy and
|
||||
subsequent merge occurred, there's usually no further need to
|
||||
propagate changes from the original file to the copied file,
|
||||
and that's why Mercurial only propagates changes across copies
|
||||
at the first merge, and not afterwards.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id363437">How to make changes <span class="emphasis"><em>not</em></span> follow a
|
||||
copy</h3></div></div></div><p id="x_1cb"><a name="x_1cb"></a>If, for some reason, you decide that this business of
|
||||
automatically propagating changes across copies is not for
|
||||
you, simply use your system's normal file copy command (on
|
||||
Unix-like systems, that's <span class="command"><strong>cp</strong></span>) to make a
|
||||
copy of a file, then <span class="command"><strong>hg add</strong></span>
|
||||
the new copy by hand. Before you do so, though, please do
|
||||
reread <a class="xref" href="mercurial-in-daily-use.html#sec:daily:why-copy" title="Why should changes follow copies?">the section called “Why should changes follow copies?”</a>, and make
|
||||
an informed
|
||||
decision that this behavior is not appropriate to your
|
||||
specific case.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id363575">Behavior of the <span class="command"><strong>hg copy</strong></span>
|
||||
command</h3></div></div></div><p id="x_1cc"><a name="x_1cc"></a>When you use the <span class="command"><strong>hg copy</strong></span>
|
||||
command, Mercurial makes a copy of each source file as it
|
||||
currently stands in the working directory. This means that if
|
||||
you make some modifications to a file, then <span class="command"><strong>hg copy</strong></span> it without first having
|
||||
committed those changes, the new copy will also contain the
|
||||
modifications you have made up until that point. (I find this
|
||||
behavior a little counterintuitive, which is why I mention it
|
||||
here.)</p><p id="x_1cd"><a name="x_1cd"></a>The <span class="command"><strong>hg copy</strong></span>
|
||||
command acts similarly to the Unix <span class="command"><strong>cp</strong></span>
|
||||
command (you can use the <span class="command"><strong>hg
|
||||
cp</strong></span> alias if you prefer). We must supply two or
|
||||
more arguments, of which the last is treated as the
|
||||
<span class="emphasis"><em>destination</em></span>, and all others are
|
||||
<span class="emphasis"><em>sources</em></span>.</p><p id="x_685"><a name="x_685"></a>If you pass <span class="command"><strong>hg copy</strong></span> a
|
||||
single file as the source, and the destination does not exist,
|
||||
it creates a new file with that name.</p><pre id="id364014" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mkdir k</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg copy a k</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls k</code></strong>
|
||||
a
|
||||
</pre><p id="x_1ce"><a name="x_1ce"></a>If the destination is a directory, Mercurial copies its
|
||||
sources into that directory.</p><pre id="id363994" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>mkdir d</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg copy a b d</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls d</code></strong>
|
||||
a b
|
||||
</pre><p id="x_1cf"><a name="x_1cf"></a>Copying a directory is
|
||||
recursive, and preserves the directory structure of the
|
||||
source.</p><pre id="id363868" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg copy z e</code></strong>
|
||||
copying z/a/c to e/a/c
|
||||
</pre><p id="x_1d0"><a name="x_1d0"></a>If the source and destination are both directories, the
|
||||
source tree is recreated in the destination directory.</p><pre id="id363817" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg copy z d</code></strong>
|
||||
copying z/a/c to d/z/a/c
|
||||
</pre><p id="x_1d1"><a name="x_1d1"></a>As with the <span class="command"><strong>hg remove</strong></span>
|
||||
command, if you copy a file manually and then want Mercurial
|
||||
to know that you've copied the file, simply use the <code class="option">--after</code> option to <span class="command"><strong>hg copy</strong></span>.</p><pre id="id364027" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cp a n</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg copy --after a n</code></strong>
|
||||
</pre></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id364064">Renaming files</h2></div></div></div><p id="x_1d2"><a name="x_1d2"></a>It's rather more common to need to rename a file than to
|
||||
make a copy of it. The reason I discussed the <span class="command"><strong>hg copy</strong></span> command before talking about
|
||||
renaming files is that Mercurial treats a rename in essentially
|
||||
the same way as a copy. Therefore, knowing what Mercurial does
|
||||
when you copy a file tells you what to expect when you rename a
|
||||
file.</p><p id="x_1d3"><a name="x_1d3"></a>When you use the <span class="command"><strong>hg rename</strong></span>
|
||||
command, Mercurial makes a copy of each source file, then
|
||||
deletes it and marks the file as removed.</p><pre id="id364447" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg rename a b</code></strong>
|
||||
</pre><p id="x_1d4"><a name="x_1d4"></a>The <span class="command"><strong>hg status</strong></span> command shows
|
||||
the newly copied file as added, and the copied-from file as
|
||||
removed.</p><pre id="id364426" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status</code></strong>
|
||||
A b
|
||||
R a
|
||||
</pre><p id="x_1d5"><a name="x_1d5"></a>As with the results of a <span class="command"><strong>hg
|
||||
copy</strong></span>, we must use the <code class="option">-C</code> option to <span class="command"><strong>hg status</strong></span> to see that the added file
|
||||
is really being tracked by Mercurial as a copy of the original,
|
||||
now removed, file.</p><pre id="id364367" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status -C</code></strong>
|
||||
A b
|
||||
a
|
||||
R a
|
||||
</pre><p id="x_1d6"><a name="x_1d6"></a>As with <span class="command"><strong>hg remove</strong></span> and
|
||||
<span class="command"><strong>hg copy</strong></span>, you can tell Mercurial
|
||||
about a rename after the fact using the <code class="option">--after</code> option. In most other
|
||||
respects, the behavior of the <span class="command"><strong>hg
|
||||
rename</strong></span> command, and the options it accepts, are
|
||||
similar to the <span class="command"><strong>hg copy</strong></span>
|
||||
command.</p><p id="x_686"><a name="x_686"></a>If you're familiar with the Unix command line, you'll be
|
||||
glad to know that <span class="command"><strong>hg rename</strong></span>
|
||||
command can be invoked as <span class="command"><strong>hg
|
||||
mv</strong></span>.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id364249">Renaming files and merging changes</h3></div></div></div><p id="x_1d7"><a name="x_1d7"></a>Since Mercurial's rename is implemented as
|
||||
copy-and-remove, the same propagation of changes happens when
|
||||
you merge after a rename as after a copy.</p><p id="x_1d8"><a name="x_1d8"></a>If I modify a file, and you rename it to a new name, and
|
||||
then we merge our respective changes, my modifications to the
|
||||
file under its original name will be propagated into the file
|
||||
under its new name. (This is something you might expect to
|
||||
“<span class="quote">simply work,</span>” but not all revision control
|
||||
systems actually do this.)</p><p id="x_1d9"><a name="x_1d9"></a>Whereas having changes follow a copy is a feature where
|
||||
you can perhaps nod and say “<span class="quote">yes, that might be
|
||||
useful,</span>” it should be clear that having them follow a
|
||||
rename is definitely important. Without this facility, it
|
||||
would simply be too easy for changes to become orphaned when
|
||||
files are renamed.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id364290">Divergent renames and merging</h3></div></div></div><p id="x_1da"><a name="x_1da"></a>The case of diverging names occurs when two developers
|
||||
start with a file—let's call it
|
||||
<code class="filename">foo</code>—in their respective
|
||||
repositories.</p><pre id="id364337" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg clone orig anne</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone orig bob</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_1db"><a name="x_1db"></a>Anne renames the file to <code class="filename">bar</code>.</p><pre id="id364844" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd anne</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg rename foo bar</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg ci -m 'Rename foo to bar'</code></strong>
|
||||
</pre><p id="x_1dc"><a name="x_1dc"></a>Meanwhile, Bob renames it to
|
||||
<code class="filename">quux</code>. (Remember that <span class="command"><strong>hg mv</strong></span> is an alias for <span class="command"><strong>hg rename</strong></span>.)</p><pre id="id364729" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ../bob</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg mv foo quux</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg ci -m 'Rename foo to quux'</code></strong>
|
||||
</pre><p id="x_1dd"><a name="x_1dd"></a>I like to think of this as a conflict because each
|
||||
developer has expressed different intentions about what the
|
||||
file ought to be named.</p><p id="x_1de"><a name="x_1de"></a>What do you think should happen when they merge their
|
||||
work? Mercurial's actual behavior is that it always preserves
|
||||
<span class="emphasis"><em>both</em></span> names when it merges changesets that
|
||||
contain divergent renames.</p><pre id="id365077" class="screen"># See http://www.selenic.com/mercurial/bts/issue455
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd ../orig</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg pull -u ../anne</code></strong>
|
||||
pulling from ../anne
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files
|
||||
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg pull ../bob</code></strong>
|
||||
pulling from ../bob
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files (+1 heads)
|
||||
(run 'hg heads' to see heads, 'hg merge' to merge)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
|
||||
warning: detected divergent renames of foo to:
|
||||
bar
|
||||
quux
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
(branch merge, don't forget to commit)
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>ls</code></strong>
|
||||
bar quux
|
||||
</pre><p id="x_1df"><a name="x_1df"></a>Notice that while Mercurial warns about the divergent
|
||||
renames, it leaves it up to you to do something about the
|
||||
divergence after the merge.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id364713">Convergent renames and merging</h3></div></div></div><p id="x_1e0"><a name="x_1e0"></a>Another kind of rename conflict occurs when two people
|
||||
choose to rename different <span class="emphasis"><em>source</em></span> files
|
||||
to the same <span class="emphasis"><em>destination</em></span>. In this case,
|
||||
Mercurial runs its normal merge machinery, and lets you guide
|
||||
it to a suitable resolution.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id364870">Other name-related corner cases</h3></div></div></div><p id="x_1e1"><a name="x_1e1"></a>Mercurial has a longstanding bug in which it fails to
|
||||
handle a merge where one side has a file with a given name,
|
||||
while another has a directory with the same name. This is
|
||||
documented as <a class="ulink" href="http://www.selenic.com/mercurial/bts/issue29" target="_top">issue
|
||||
29</a>.</p><pre id="id365033" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init issue29</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd issue29</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo a > a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg ci -Ama</code></strong>
|
||||
adding a
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo b > b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg ci -Amb</code></strong>
|
||||
adding b
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg up 0</code></strong>
|
||||
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>mkdir b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo b > b/b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg ci -Amc</code></strong>
|
||||
adding b/b
|
||||
created new head
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
|
||||
abort: Is a directory: /tmp/issue29ozeAHx/issue29/b
|
||||
</pre></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id365158">Recovering from mistakes</h2></div></div></div><p id="x_1e2"><a name="x_1e2"></a>Mercurial has some useful commands that will help you to
|
||||
recover from some common mistakes.</p><p id="x_1e3"><a name="x_1e3"></a>The <span class="command"><strong>hg revert</strong></span> command lets
|
||||
you undo changes that you have made to your working directory.
|
||||
For example, if you <span class="command"><strong>hg add</strong></span> a
|
||||
file by accident, just run <span class="command"><strong>hg
|
||||
revert</strong></span> with the name of the file you added, and
|
||||
while the file won't be touched in any way, it won't be tracked
|
||||
for adding by Mercurial any longer, either. You can also use
|
||||
<span class="command"><strong>hg revert</strong></span> to get rid of
|
||||
erroneous changes to a file.</p><p id="x_1e4"><a name="x_1e4"></a>It is helpful to remember that the <span class="command"><strong>hg revert</strong></span> command is useful for
|
||||
changes that you have not yet committed. Once you've committed
|
||||
a change, if you decide it was a mistake, you can still do
|
||||
something about it, though your options may be more
|
||||
limited.</p><p id="x_1e5"><a name="x_1e5"></a>For more information about the <span class="command"><strong>hg revert</strong></span> command, and details about
|
||||
how to deal with changes you have already committed, see <a class="xref" href="finding-and-fixing-mistakes.html" title="Chapter 9. Finding and fixing mistakes">Chapter 9, <i>Finding and fixing mistakes</i></a>.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id365252">Dealing with tricky merges</h2></div></div></div><p id="x_687"><a name="x_687"></a>In a complicated or large project, it's not unusual for a
|
||||
merge of two changesets to result in some headaches. Suppose
|
||||
there's a big source file that's been extensively edited by each
|
||||
side of a merge: this is almost inevitably going to result in
|
||||
conflicts, some of which can take a few tries to sort
|
||||
out.</p><p id="x_688"><a name="x_688"></a>Let's develop a simple case of this and see how to deal with
|
||||
it. We'll start off with a repository containing one file, and
|
||||
clone it twice.</p><pre id="id365683" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg init conflict</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd conflict</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo first > myfile.txt</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg ci -A -m first</code></strong>
|
||||
adding myfile.txt
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>cd ..</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone conflict left</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg clone conflict right</code></strong>
|
||||
updating working directory
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
</pre><p id="x_689"><a name="x_689"></a>In one clone, we'll modify the file in one way.</p><pre id="id365663" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd left</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo left >> myfile.txt</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg ci -m left</code></strong>
|
||||
</pre><p id="x_68a"><a name="x_68a"></a>In another, we'll modify the file differently.</p><pre id="id365607" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ../right</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>echo right >> myfile.txt</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg ci -m right</code></strong>
|
||||
</pre><p id="x_68b"><a name="x_68b"></a>Next, we'll pull each set of changes into our original
|
||||
repo.</p><pre id="id366073" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>cd ../conflict</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg pull -u ../left</code></strong>
|
||||
pulling from ../left
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files
|
||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg pull -u ../right</code></strong>
|
||||
pulling from ../right
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files (+1 heads)
|
||||
not updating, since new heads added
|
||||
(run 'hg heads' to see heads, 'hg merge' to merge)
|
||||
</pre><p id="x_68c"><a name="x_68c"></a>We expect our repository to now contain two heads.</p><pre id="id366011" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg heads</code></strong>
|
||||
changeset: 2:adc157afe092
|
||||
tag: tip
|
||||
parent: 0:b704237e4749
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:25 2009 +0000
|
||||
summary: right
|
||||
|
||||
changeset: 1:64abc51bea49
|
||||
user: Bryan O'Sullivan <bos@serpentine.com>
|
||||
date: Tue May 05 06:55:25 2009 +0000
|
||||
summary: left
|
||||
|
||||
</pre><p id="x_68d"><a name="x_68d"></a>Normally, if we run <span class="command"><strong>hg
|
||||
merge</strong></span> at this point, it will drop us into a GUI that
|
||||
will let us manually resolve the conflicting edits to
|
||||
<code class="filename">myfile.txt</code>. However, to simplify things
|
||||
for presentation here, we'd like the merge to fail immediately
|
||||
instead. Here's one way we can do so.</p><pre id="id366060" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>export HGMERGE=merge</code></strong>
|
||||
</pre><p id="x_68e"><a name="x_68e"></a>We've told Mercurial's merge machinery to run the command
|
||||
<span class="command"><strong>false</strong></span> (which, as we desire, fails
|
||||
immediately) if it detects a merge that it can't sort out
|
||||
automatically.</p><p id="x_68f"><a name="x_68f"></a>If we now fire up <span class="command"><strong>hg
|
||||
merge</strong></span>, it should grind to a halt and report a
|
||||
failure.</p><pre id="id365931" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg merge</code></strong>
|
||||
merging myfile.txt
|
||||
merge: warning: conflicts during merge
|
||||
merging myfile.txt failed!
|
||||
0 files updated, 0 files merged, 0 files removed, 1 files unresolved
|
||||
use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
|
||||
</pre><p id="x_690"><a name="x_690"></a>Even if we don't notice that the merge failed, Mercurial
|
||||
will prevent us from accidentally committing the result of a
|
||||
failed merge.</p><pre id="id366386" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg commit -m 'Attempt to commit a failed merge'</code></strong>
|
||||
abort: unresolved merge conflicts (see hg resolve)
|
||||
</pre><p id="x_691"><a name="x_691"></a>When <span class="command"><strong>hg commit</strong></span> fails in
|
||||
this case, it suggests that we use the unfamiliar <span class="command"><strong>hg resolve</strong></span> command. As usual,
|
||||
<span class="command"><strong>hg help resolve</strong></span> will print a
|
||||
helpful synopsis.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id366109">File resolution states</h3></div></div></div><p id="x_692"><a name="x_692"></a>When a merge occurs, most files will usually remain
|
||||
unmodified. For each file where Mercurial has to do
|
||||
something, it tracks the state of the file.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_693"><a name="x_693"></a>A <span class="emphasis"><em>resolved</em></span> file has been
|
||||
successfully merged, either automatically by Mercurial or
|
||||
manually with human intervention.</p></li><li><p id="x_694"><a name="x_694"></a>An <span class="emphasis"><em>unresolved</em></span> file was not merged
|
||||
successfully, and needs more attention.</p></li></ul></div><p id="x_695"><a name="x_695"></a>If Mercurial sees <span class="emphasis"><em>any</em></span> file in the
|
||||
unresolved state after a merge, it considers the merge to have
|
||||
failed. Fortunately, we do not need to restart the entire
|
||||
merge from scratch.</p><p id="x_696"><a name="x_696"></a>The <code class="option">--list</code> or
|
||||
<code class="option">-l</code> option to <span class="command"><strong>hg resolve</strong></span> prints out the state of
|
||||
each merged file.</p><pre id="id366549" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg resolve -l</code></strong>
|
||||
U myfile.txt
|
||||
</pre><p id="x_697"><a name="x_697"></a>In the output from <span class="command"><strong>hg
|
||||
resolve</strong></span>, a resolved file is marked with
|
||||
<code class="literal">R</code>, while an unresolved file is marked with
|
||||
<code class="literal">U</code>. If any files are listed with
|
||||
<code class="literal">U</code>, we know that an attempt to commit the
|
||||
results of the merge will fail.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id366263">Resolving a file merge</h3></div></div></div><p id="x_698"><a name="x_698"></a>We have several options to move a file from the unresolved
|
||||
into the resolved state. By far the most common is to rerun
|
||||
<span class="command"><strong>hg resolve</strong></span>. If we pass the
|
||||
names of individual files or directories, it will retry the
|
||||
merges of any unresolved files present in those locations. We
|
||||
can also pass the <code class="option">--all</code>
|
||||
or <code class="option">-a</code> option, which
|
||||
will retry the merges of <span class="emphasis"><em>all</em></span> unresolved
|
||||
files.</p><p id="x_699"><a name="x_699"></a>Mercurial also lets us modify the resolution state of a
|
||||
file directly. We can manually mark a file as resolved using
|
||||
the <code class="option">--mark</code> option, or
|
||||
as unresolved using the <code class="option">--unmark</code> option. This allows
|
||||
us to clean up a particularly messy merge by hand, and to keep
|
||||
track of our progress with each file as we go.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id366325">More useful diffs</h2></div></div></div><p id="x_6c7"><a name="x_6c7"></a>The default output of the <span class="command"><strong>hg
|
||||
diff</strong></span> command is backwards compatible with the
|
||||
regular <span class="command"><strong>diff</strong></span> command, but this has some
|
||||
drawbacks.</p><p id="x_6c8"><a name="x_6c8"></a>Consider the case where we use <span class="command"><strong>hg
|
||||
rename</strong></span> to rename a file.</p><pre id="id366520" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg rename a b</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg diff</code></strong>
|
||||
diff -r 4b300eaa7199 a
|
||||
--- a/a Tue May 05 06:55:21 2009 +0000
|
||||
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
|
||||
@@ -1,1 +0,0 @@
|
||||
-a
|
||||
diff -r 4b300eaa7199 b
|
||||
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
|
||||
+++ b/b Tue May 05 06:55:21 2009 +0000
|
||||
@@ -0,0 +1,1 @@
|
||||
+a
|
||||
</pre><p id="x_6c9"><a name="x_6c9"></a>The output of <span class="command"><strong>hg diff</strong></span> above
|
||||
obscures the fact that we simply renamed a file. The <span class="command"><strong>hg diff</strong></span> command accepts an option,
|
||||
<code class="option">--git</code> or <code class="option">-g</code>, to use a newer
|
||||
diff format that displays such information in a more readable
|
||||
form.</p><pre id="id366842" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg diff -g</code></strong>
|
||||
diff --git a/a b/b
|
||||
rename from a
|
||||
rename to b
|
||||
</pre><p id="x_6ca"><a name="x_6ca"></a>This option also helps with a case that can otherwise be
|
||||
confusing: a file that appears to be modified according to
|
||||
<span class="command"><strong>hg status</strong></span>, but for which
|
||||
<span class="command"><strong>hg diff</strong></span> prints nothing. This
|
||||
situation can arise if we change the file's execute
|
||||
permissions.</p><pre id="id366568" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>chmod +x a</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg st</code></strong>
|
||||
M a
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>hg diff</code></strong>
|
||||
</pre><p id="x_6cb"><a name="x_6cb"></a>The normal <span class="command"><strong>diff</strong></span> command pays no attention
|
||||
to file permissions, which is why <span class="command"><strong>hg
|
||||
diff</strong></span> prints nothing by default. If we supply it
|
||||
with the <code class="option">-g</code> option, it tells us what really
|
||||
happened.</p><pre id="id366782" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg diff -g</code></strong>
|
||||
diff --git a/a b/a
|
||||
old mode 100644
|
||||
new mode 100755
|
||||
</pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id366788">Which files to manage, and which to avoid</h2></div></div></div><p id="x_6cc"><a name="x_6cc"></a>Revision control systems are generally best at managing text
|
||||
files that are written by humans, such as source code, where the
|
||||
files do not change much from one revision to the next. Some
|
||||
centralized revision control systems can also deal tolerably
|
||||
well with binary files, such as bitmap images.</p><p id="x_6cd"><a name="x_6cd"></a>For instance, a game development team will typically manage
|
||||
both its source code and all of its binary assets (e.g. geometry
|
||||
data, textures, map layouts) in a revision control
|
||||
system.</p><p id="x_6ce"><a name="x_6ce"></a>Because it is usually impossible to merge two conflicting
|
||||
modifications to a binary file, centralized systems often
|
||||
provide a file locking mechanism that allow a user to say
|
||||
“<span class="quote">I am the only person who can edit this
|
||||
file</span>”.</p><p id="x_6cf"><a name="x_6cf"></a>Compared to a centralized system, a distributed revision
|
||||
control system changes some of the factors that guide decisions
|
||||
over which files to manage and how.</p><p id="x_6d0"><a name="x_6d0"></a>For instance, a distributed revision control system cannot,
|
||||
by its nature, offer a file locking facility. There is thus no
|
||||
built-in mechanism to prevent two people from making conflicting
|
||||
changes to a binary file. If you have a team where several
|
||||
people may be editing binary files frequently, it may not be a
|
||||
good idea to use Mercurial—or any other distributed
|
||||
revision control system—to manage those files.</p><p id="x_6d1"><a name="x_6d1"></a>When storing modifications to a file, Mercurial usually
|
||||
saves only the differences between the previous and current
|
||||
versions of the file. For most text files, this is extremely
|
||||
efficient. However, some files (particularly binary files) are
|
||||
laid out in such a way that even a small change to a file's
|
||||
logical content results in many or most of the bytes inside the
|
||||
file changing. For instance, compressed files are particularly
|
||||
susceptible to this. If the differences between each successive
|
||||
version of a file are always large, Mercurial will not be able
|
||||
to store the file's revision history very efficiently. This can
|
||||
affect both local storage needs and the amount of time it takes
|
||||
to clone a repository.</p><p id="x_6d2"><a name="x_6d2"></a>To get an idea of how this could affect you in practice,
|
||||
suppose you want to use Mercurial to manage an OpenOffice
|
||||
document. OpenOffice stores documents on disk as compressed zip
|
||||
files. Edit even a single letter of your document in OpenOffice,
|
||||
and almost every byte in the entire file will change when you
|
||||
save it. Now suppose that file is 2MB in size. Because most of
|
||||
the file changes every time you save, Mercurial will have to
|
||||
store all 2MB of the file every time you commit, even though
|
||||
from your perspective, perhaps only a few words are changing
|
||||
each time. A single frequently-edited file that is not friendly
|
||||
to Mercurial's storage assumptions can easily have an outsized
|
||||
effect on the size of the repository.</p><p id="x_6d3"><a name="x_6d3"></a>Even worse, if both you and someone else edit the OpenOffice
|
||||
document you're working on, there is no useful way to merge your
|
||||
work. In fact, there isn't even a good way to tell what the
|
||||
differences are between your respective changes.</p><p id="x_6d4"><a name="x_6d4"></a>There are thus a few clear recommendations about specific
|
||||
kinds of files to be very careful with.</p><div class="itemizedlist"><ul type="disc"><li><p id="x_6d5"><a name="x_6d5"></a>Files that are very large and incompressible, e.g. ISO
|
||||
CD-ROM images, will by virtue of sheer size make clones over
|
||||
a network very slow.</p></li><li><p id="x_6d6"><a name="x_6d6"></a>Files that change a lot from one revision to the next
|
||||
may be expensive to store if you edit them frequently, and
|
||||
conflicts due to concurrent edits may be difficult to
|
||||
resolve.</p></li></ul></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id360710">Backups and mirroring</h2></div></div></div><p id="x_6d7"><a name="x_6d7"></a>Since Mercurial maintains a complete copy of history in each
|
||||
clone, everyone who uses Mercurial to collaborate on a project
|
||||
can potentially act as a source of backups in the event of a
|
||||
catastrophe. If a central repository becomes unavailable, you
|
||||
can construct a replacement simply by cloning a copy of the
|
||||
repository from one contributor, and pulling any changes they
|
||||
may not have seen from others.</p><p id="x_6d8"><a name="x_6d8"></a>It is simple to use Mercurial to perform off-site backups
|
||||
and remote mirrors. Set up a periodic job (e.g. via the
|
||||
<span class="command"><strong>cron</strong></span> command) on a remote server to pull
|
||||
changes from your master repositories every hour. This will
|
||||
only be tricky in the unlikely case that the number of master
|
||||
repositories you maintain changes frequently, in which case
|
||||
you'll need to do a little scripting to refresh the list of
|
||||
repositories to back up.</p><p id="x_6d9"><a name="x_6d9"></a>If you perform traditional backups of your master
|
||||
repositories to tape or disk, and you want to back up a
|
||||
repository named <code class="filename">myrepo</code>, use <span class="command"><strong>hg
|
||||
clone -U myrepo myrepo.bak</strong></span> to create a
|
||||
clone of <code class="filename">myrepo</code> before you start your
|
||||
backups. The <code class="option">-U</code> option doesn't check out a
|
||||
working directory after the clone completes, since that would be
|
||||
superfluous and make the backup take longer.</p><p id="x_6da"><a name="x_6da"></a>If you then back up <code class="filename">myrepo.bak</code> instead
|
||||
of <code class="filename">myrepo</code>, you will be guaranteed to have a
|
||||
consistent snapshot of your repository that won't be pushed to
|
||||
by an insomniac developer in mid-backup.</p></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="behind-the-scenes.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="collaborating-with-other-people.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 4. Behind the scenes </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 6. Collaborating with other people</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
263
read/mercurial-queues-reference.html
Normal file
263
read/mercurial-queues-reference.html
Normal file
|
@ -0,0 +1,263 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Appendix B. Mercurial Queues reference</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="migrating-to-mercurial.html" title="Appendix A. Migrating to Mercurial"><link rel="next" href="installing-mercurial-from-source.html" title="Appendix C. Installing Mercurial from source"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix B. Mercurial Queues reference</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="migrating-to-mercurial.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="installing-mercurial-from-source.html">Next</a></td></tr></table></div><div class="appendix" lang="en" id="chap:mqref"><div class="titlepage"><div><div><h2 class="title">Appendix B. Mercurial Queues reference</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="mercurial-queues-reference.html#sec:mqref:cmdref">MQ command reference</a></span></dt><dd><dl><dt><span class="sect2"><a href="mercurial-queues-reference.html#id444629">qapplied—print
|
||||
applied patches</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id444662">qcommit—commit
|
||||
changes in the queue repository</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id444757">qdelete—delete a patch
|
||||
from the series
|
||||
file</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id444842">qdiff—print a
|
||||
diff of the topmost applied patch</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id444880">qfold—move
|
||||
applied patches into repository history</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id444909">qfold—merge
|
||||
(fold) several patches into one</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id445054">qheader—display the
|
||||
header/description of a patch</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id445085">qimport—import
|
||||
a third-party patch into the queue</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id445169">qinit—prepare
|
||||
a repository to work with MQ</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id445302">qnew—create a
|
||||
new patch</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id445412">qnext—print
|
||||
the name of the next patch</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id445458">qpop—pop
|
||||
patches off the stack</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id445656">qprev—print
|
||||
the name of the previous patch</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#sec:mqref:cmd:qpush">qpush—push
|
||||
patches onto the stack</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id445928">qrefresh—update the
|
||||
topmost applied patch</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id446108">qrename—rename
|
||||
a patch</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id446162">qseries—print
|
||||
the entire patch series</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id446201">qtop—print the
|
||||
name of the current patch</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id446230">qunapplied—print patches
|
||||
not yet applied</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id446269">hg strip—remove a
|
||||
revision and descendants</a></span></dt></dl></dd><dt><span class="sect1"><a href="mercurial-queues-reference.html#id446370">MQ file reference</a></span></dt><dd><dl><dt><span class="sect2"><a href="mercurial-queues-reference.html#id446375">The series
|
||||
file</a></span></dt><dt><span class="sect2"><a href="mercurial-queues-reference.html#id446487">The status
|
||||
file</a></span></dt></dl></dd></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:mqref:cmdref">MQ command reference</h2></div></div></div><p id="x_5e8"><a name="x_5e8"></a>For an overview of the commands provided by MQ, use the
|
||||
command <span class="command"><strong>hg help mq</strong></span>.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id444629"><span class="command"><strong>qapplied</strong></span>—print
|
||||
applied patches</h3></div></div></div><p id="x_5e9"><a name="x_5e9"></a>The <span class="command"><strong>qapplied</strong></span> command
|
||||
prints the current stack of applied patches. Patches are
|
||||
printed in oldest-to-newest order, so the last patch in the
|
||||
list is the “<span class="quote">top</span>” patch.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id444662"><span class="command"><strong>qcommit</strong></span>—commit
|
||||
changes in the queue repository</h3></div></div></div><p id="x_5ea"><a name="x_5ea"></a>The <span class="command"><strong>qcommit</strong></span> command
|
||||
commits any outstanding changes in the <code class="filename">.hg/patches</code>
|
||||
repository. This command only works if the <code class="filename">.hg/patches</code>
|
||||
directory is a repository, i.e. you created the directory
|
||||
using <span class="command"><strong>hg qinit <code class="option">-c</code></strong></span> or
|
||||
ran <span class="command"><strong>hg init</strong></span> in the directory
|
||||
after running <span class="command"><strong>qinit</strong></span>.</p><p id="x_5eb"><a name="x_5eb"></a>This command is shorthand for <span class="command"><strong>hg
|
||||
commit --cwd .hg/patches</strong></span>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id444757"><span class="command"><strong>qdelete</strong></span>—delete a patch
|
||||
from the <code class="filename">series</code>
|
||||
file</h3></div></div></div><p id="x_5ec"><a name="x_5ec"></a>The <span class="command"><strong>qdelete</strong></span> command
|
||||
removes the entry for a patch from the <code class="filename">series</code> file in the <code class="filename">.hg/patches</code>
|
||||
directory. It does not pop the patch if the patch is already
|
||||
applied. By default, it does not delete the patch file; use
|
||||
the <code class="option">-f</code> option
|
||||
to do that.</p><p id="x_5ed"><a name="x_5ed"></a>Options:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_5ee"><a name="x_5ee"></a><code class="option">-f</code>: Delete the
|
||||
patch file.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id444842"><span class="command"><strong>qdiff</strong></span>—print a
|
||||
diff of the topmost applied patch</h3></div></div></div><p id="x_5ef"><a name="x_5ef"></a>The <span class="command"><strong>qdiff</strong></span> command
|
||||
prints a diff of the topmost applied patch. It is equivalent
|
||||
to <span class="command"><strong>hg diff -r-2:-1</strong></span>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id444880"><span class="command"><strong>qfold</strong></span>—move
|
||||
applied patches into repository history</h3></div></div></div><p id="x_72d"><a name="x_72d"></a>The <span class="command"><strong>hg qfinish</strong></span> command converts the
|
||||
specified applied patches into permanent changes by moving
|
||||
them out of MQ's control so that they will be treated as
|
||||
normal repository history.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id444909"><span class="command"><strong>qfold</strong></span>—merge
|
||||
(“<span class="quote">fold</span>”) several patches into one</h3></div></div></div><p id="x_5f0"><a name="x_5f0"></a>The <span class="command"><strong>qfold</strong></span> command
|
||||
merges multiple patches into the topmost applied patch, so
|
||||
that the topmost applied patch makes the union of all of the
|
||||
changes in the patches in question.</p><p id="x_5f1"><a name="x_5f1"></a>The patches to fold must not be applied; <span class="command"><strong>qfold</strong></span> will exit with an error if
|
||||
any is. The order in which patches are folded is significant;
|
||||
<span class="command"><strong>hg qfold a b</strong></span> means
|
||||
“<span class="quote">apply the current topmost patch, followed by
|
||||
<code class="literal">a</code>, followed by
|
||||
<code class="literal">b</code></span>”.</p><p id="x_5f2"><a name="x_5f2"></a>The comments from the folded patches are appended to the
|
||||
comments of the destination patch, with each block of comments
|
||||
separated by three asterisk
|
||||
(“<span class="quote"><code class="literal">*</code></span>”) characters. Use the
|
||||
<code class="option">-e</code> option to
|
||||
edit the commit message for the combined patch/changeset after
|
||||
the folding has completed.</p><p id="x_5f3"><a name="x_5f3"></a>Options:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_5f4"><a name="x_5f4"></a><code class="option">-e</code>: Edit the
|
||||
commit message and patch description for the newly folded
|
||||
patch.</p></li><li><p id="x_5f5"><a name="x_5f5"></a><code class="option">-l</code>: Use the
|
||||
contents of the given file as the new commit message and
|
||||
patch description for the folded patch.</p></li><li><p id="x_5f6"><a name="x_5f6"></a><code class="option">-m</code>: Use the
|
||||
given text as the new commit message and patch description
|
||||
for the folded patch.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id445054"><span class="command"><strong>qheader</strong></span>—display the
|
||||
header/description of a patch</h3></div></div></div><p id="x_5f7"><a name="x_5f7"></a>The <span class="command"><strong>qheader</strong></span> command
|
||||
prints the header, or description, of a patch. By default, it
|
||||
prints the header of the topmost applied patch. Given an
|
||||
argument, it prints the header of the named patch.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id445085"><span class="command"><strong>qimport</strong></span>—import
|
||||
a third-party patch into the queue</h3></div></div></div><p id="x_5f8"><a name="x_5f8"></a>The <span class="command"><strong>qimport</strong></span> command
|
||||
adds an entry for an external patch to the <code class="filename">series</code> file, and copies the patch
|
||||
into the <code class="filename">.hg/patches</code> directory. It adds
|
||||
the entry immediately after the topmost applied patch, but
|
||||
does not push the patch.</p><p id="x_5f9"><a name="x_5f9"></a>If the <code class="filename">.hg/patches</code> directory is a
|
||||
repository, <span class="command"><strong>qimport</strong></span>
|
||||
automatically does an <span class="command"><strong>hg add</strong></span>
|
||||
of the imported patch.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id445169"><span class="command"><strong>qinit</strong></span>—prepare
|
||||
a repository to work with MQ</h3></div></div></div><p id="x_5fa"><a name="x_5fa"></a>The <span class="command"><strong>qinit</strong></span> command
|
||||
prepares a repository to work with MQ. It creates a directory
|
||||
called <code class="filename">.hg/patches</code>.</p><p id="x_5fb"><a name="x_5fb"></a>Options:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_5fc"><a name="x_5fc"></a><code class="option">-c</code>: Create
|
||||
<code class="filename">.hg/patches</code> as a repository
|
||||
in its own right. Also creates a <code class="filename">.hgignore</code> file that will
|
||||
ignore the <code class="filename">status</code>
|
||||
file.</p></li></ul></div><p id="x_5fd"><a name="x_5fd"></a>When the <code class="filename">.hg/patches</code> directory is a
|
||||
repository, the <span class="command"><strong>qimport</strong></span>
|
||||
and <span class="command"><strong>qnew</strong></span> commands
|
||||
automatically <span class="command"><strong>hg add</strong></span> new
|
||||
patches.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id445302"><span class="command"><strong>qnew</strong></span>—create a
|
||||
new patch</h3></div></div></div><p id="x_5fe"><a name="x_5fe"></a>The <span class="command"><strong>qnew</strong></span> command
|
||||
creates a new patch. It takes one mandatory argument, the
|
||||
name to use for the patch file. The newly created patch is
|
||||
created empty by default. It is added to the <code class="filename">series</code> file after the current
|
||||
topmost applied patch, and is immediately pushed on top of
|
||||
that patch.</p><p id="x_5ff"><a name="x_5ff"></a>If <span class="command"><strong>qnew</strong></span> finds modified
|
||||
files in the working directory, it will refuse to create a new
|
||||
patch unless the <code class="option">-f</code> option is used
|
||||
(see below). This behavior allows you to <span class="command"><strong>qrefresh</strong></span> your topmost applied
|
||||
patch before you apply a new patch on top of it.</p><p id="x_600"><a name="x_600"></a>Options:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_601"><a name="x_601"></a><code class="option">-f</code>: Create a new
|
||||
patch if the contents of the working directory are
|
||||
modified. Any outstanding modifications are added to the
|
||||
newly created patch, so after this command completes, the
|
||||
working directory will no longer be modified.</p></li><li><p id="x_602"><a name="x_602"></a><code class="option">-m</code>: Use the given
|
||||
text as the commit message. This text will be stored at
|
||||
the beginning of the patch file, before the patch
|
||||
data.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id445412"><span class="command"><strong>qnext</strong></span>—print
|
||||
the name of the next patch</h3></div></div></div><p id="x_603"><a name="x_603"></a>The <span class="command"><strong>qnext</strong></span> command
|
||||
prints the name name of the next patch in the <code class="filename">series</code> file after the topmost
|
||||
applied patch. This patch will become the topmost applied
|
||||
patch if you run <span class="command"><strong>qpush</strong></span>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id445458"><span class="command"><strong>qpop</strong></span>—pop
|
||||
patches off the stack</h3></div></div></div><p id="x_604"><a name="x_604"></a>The <span class="command"><strong>qpop</strong></span> command
|
||||
removes applied patches from the top of the stack of applied
|
||||
patches. By default, it removes only one patch.</p><p id="x_605"><a name="x_605"></a>This command removes the changesets that represent the
|
||||
popped patches from the repository, and updates the working
|
||||
directory to undo the effects of the patches.</p><p id="x_606"><a name="x_606"></a>This command takes an optional argument, which it uses as
|
||||
the name or index of the patch to pop to. If given a name, it
|
||||
will pop patches until the named patch is the topmost applied
|
||||
patch. If given a number, <span class="command"><strong>qpop</strong></span> treats the number as an
|
||||
index into the entries in the series file, counting from zero
|
||||
(empty lines and lines containing only comments do not count).
|
||||
It pops patches until the patch identified by the given index
|
||||
is the topmost applied patch.</p><p id="x_607"><a name="x_607"></a>The <span class="command"><strong>qpop</strong></span> command does
|
||||
not read or write patches or the <code class="filename">series</code> file. It is thus safe to
|
||||
<span class="command"><strong>qpop</strong></span> a patch that you have
|
||||
removed from the <code class="filename">series</code>
|
||||
file, or a patch that you have renamed or deleted entirely.
|
||||
In the latter two cases, use the name of the patch as it was
|
||||
when you applied it.</p><p id="x_608"><a name="x_608"></a>By default, the <span class="command"><strong>qpop</strong></span>
|
||||
command will not pop any patches if the working directory has
|
||||
been modified. You can override this behavior using the
|
||||
<code class="option">-f</code> option,
|
||||
which reverts all modifications in the working
|
||||
directory.</p><p id="x_609"><a name="x_609"></a>Options:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_60a"><a name="x_60a"></a><code class="option">-a</code>: Pop all
|
||||
applied patches. This returns the repository to its state
|
||||
before you applied any patches.</p></li><li><p id="x_60b"><a name="x_60b"></a><code class="option">-f</code>: Forcibly
|
||||
revert any modifications to the working directory when
|
||||
popping.</p></li><li><p id="x_60c"><a name="x_60c"></a><code class="option">-n</code>: Pop a patch
|
||||
from the named queue.</p></li></ul></div><p id="x_60d"><a name="x_60d"></a>The <span class="command"><strong>qpop</strong></span> command
|
||||
removes one line from the end of the <code class="filename">status</code> file for each patch that it
|
||||
pops.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id445656"><span class="command"><strong>qprev</strong></span>—print
|
||||
the name of the previous patch</h3></div></div></div><p id="x_60e"><a name="x_60e"></a>The <span class="command"><strong>qprev</strong></span> command
|
||||
prints the name of the patch in the <code class="filename">series</code> file that comes before the
|
||||
topmost applied patch. This will become the topmost applied
|
||||
patch if you run <span class="command"><strong>qpop</strong></span>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="sec:mqref:cmd:qpush"><span class="command"><strong>qpush</strong></span>—push
|
||||
patches onto the stack</h3></div></div></div><p id="x_60f"><a name="x_60f"></a>The <span class="command"><strong>qpush</strong></span> command adds
|
||||
patches onto the applied stack. By default, it adds only one
|
||||
patch.</p><p id="x_610"><a name="x_610"></a>This command creates a new changeset to represent each
|
||||
applied patch, and updates the working directory to apply the
|
||||
effects of the patches.</p><p id="x_611"><a name="x_611"></a>The default data used when creating a changeset are as
|
||||
follows:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_612"><a name="x_612"></a>The commit date and time zone are the current
|
||||
date and time zone. Because these data are used to
|
||||
compute the identity of a changeset, this means that if
|
||||
you <span class="command"><strong>qpop</strong></span> a patch and
|
||||
<span class="command"><strong>qpush</strong></span> it again, the
|
||||
changeset that you push will have a different identity
|
||||
than the changeset you popped.</p></li><li><p id="x_613"><a name="x_613"></a>The author is the same as the default used by
|
||||
the <span class="command"><strong>hg commit</strong></span>
|
||||
command.</p></li><li><p id="x_614"><a name="x_614"></a>The commit message is any text from the patch
|
||||
file that comes before the first diff header. If there is
|
||||
no such text, a default commit message is used that
|
||||
identifies the name of the patch.</p></li></ul></div><p id="x_615"><a name="x_615"></a>If a patch contains a Mercurial patch header,
|
||||
the information in the patch header overrides these
|
||||
defaults.</p><p id="x_616"><a name="x_616"></a>Options:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_617"><a name="x_617"></a><code class="option">-a</code>: Push all
|
||||
unapplied patches from the <code class="filename">series</code> file until there are
|
||||
none left to push.</p></li><li><p id="x_618"><a name="x_618"></a><code class="option">-l</code>: Add the name
|
||||
of the patch to the end of the commit message.</p></li><li><p id="x_619"><a name="x_619"></a><code class="option">-m</code>: If a patch
|
||||
fails to apply cleanly, use the entry for the patch in
|
||||
another saved queue to compute the parameters for a
|
||||
three-way merge, and perform a three-way merge using the
|
||||
normal Mercurial merge machinery. Use the resolution of
|
||||
the merge as the new patch content.</p></li><li><p id="x_61a"><a name="x_61a"></a><code class="option">-n</code>: Use the
|
||||
named queue if merging while pushing.</p></li></ul></div><p id="x_61b"><a name="x_61b"></a>The <span class="command"><strong>qpush</strong></span> command
|
||||
reads, but does not modify, the <code class="filename">series</code> file. It appends one line
|
||||
to the <span class="command"><strong>hg status</strong></span> file for
|
||||
each patch that it pushes.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id445928"><span class="command"><strong>qrefresh</strong></span>—update the
|
||||
topmost applied patch</h3></div></div></div><p id="x_61c"><a name="x_61c"></a>The <span class="command"><strong>qrefresh</strong></span> command
|
||||
updates the topmost applied patch. It modifies the patch,
|
||||
removes the old changeset that represented the patch, and
|
||||
creates a new changeset to represent the modified
|
||||
patch.</p><p id="x_61d"><a name="x_61d"></a>The <span class="command"><strong>qrefresh</strong></span> command
|
||||
looks for the following modifications:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_61e"><a name="x_61e"></a>Changes to the commit message, i.e. the text
|
||||
before the first diff header in the patch file, are
|
||||
reflected in the new changeset that represents the
|
||||
patch.</p></li><li><p id="x_61f"><a name="x_61f"></a>Modifications to tracked files in the working
|
||||
directory are added to the patch.</p></li><li><p id="x_620"><a name="x_620"></a>Changes to the files tracked using <span class="command"><strong>hg add</strong></span>, <span class="command"><strong>hg copy</strong></span>, <span class="command"><strong>hg remove</strong></span>, or <span class="command"><strong>hg rename</strong></span>. Added files and copy
|
||||
and rename destinations are added to the patch, while
|
||||
removed files and rename sources are removed.</p></li></ul></div><p id="x_621"><a name="x_621"></a>Even if <span class="command"><strong>qrefresh</strong></span>
|
||||
detects no changes, it still recreates the changeset that
|
||||
represents the patch. This causes the identity of the
|
||||
changeset to differ from the previous changeset that
|
||||
identified the patch.</p><p id="x_622"><a name="x_622"></a>Options:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_623"><a name="x_623"></a><code class="option">-e</code>: Modify
|
||||
the commit and patch description, using the preferred text
|
||||
editor.</p></li><li><p id="x_624"><a name="x_624"></a><code class="option">-m</code>: Modify
|
||||
the commit message and patch description, using the given
|
||||
text.</p></li><li><p id="x_625"><a name="x_625"></a><code class="option">-l</code>: Modify
|
||||
the commit message and patch description, using text from
|
||||
the given file.</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id446108"><span class="command"><strong>qrename</strong></span>—rename
|
||||
a patch</h3></div></div></div><p id="x_626"><a name="x_626"></a>The <span class="command"><strong>qrename</strong></span> command
|
||||
renames a patch, and changes the entry for the patch in the
|
||||
<code class="filename">series</code> file.</p><p id="x_627"><a name="x_627"></a>With a single argument, <span class="command"><strong>qrename</strong></span> renames the topmost
|
||||
applied patch. With two arguments, it renames its first
|
||||
argument to its second.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id446162"><span class="command"><strong>qseries</strong></span>—print
|
||||
the entire patch series</h3></div></div></div><p id="x_62a"><a name="x_62a"></a>The <span class="command"><strong>qseries</strong></span> command
|
||||
prints the entire patch series from the <code class="filename">series</code> file. It prints only patch
|
||||
names, not empty lines or comments. It prints in order from
|
||||
first to be applied to last.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id446201"><span class="command"><strong>qtop</strong></span>—print the
|
||||
name of the current patch</h3></div></div></div><p id="x_62b"><a name="x_62b"></a>The <span class="command"><strong>qtop</strong></span> prints the
|
||||
name of the topmost currently applied patch.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id446230"><span class="command"><strong>qunapplied</strong></span>—print patches
|
||||
not yet applied</h3></div></div></div><p id="x_62c"><a name="x_62c"></a>The <span class="command"><strong>qunapplied</strong></span> command
|
||||
prints the names of patches from the <code class="filename">series</code> file that are not yet
|
||||
applied. It prints them in order from the next patch that
|
||||
will be pushed to the last.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id446269"><span class="command"><strong>hg strip</strong></span>—remove a
|
||||
revision and descendants</h3></div></div></div><p id="x_62d"><a name="x_62d"></a>The <span class="command"><strong>hg strip</strong></span> command
|
||||
removes a revision, and all of its descendants, from the
|
||||
repository. It undoes the effects of the removed revisions
|
||||
from the repository, and updates the working directory to the
|
||||
first parent of the removed revision.</p><p id="x_62e"><a name="x_62e"></a>The <span class="command"><strong>hg strip</strong></span> command
|
||||
saves a backup of the removed changesets in a bundle, so that
|
||||
they can be reapplied if removed in error.</p><p id="x_62f"><a name="x_62f"></a>Options:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_630"><a name="x_630"></a><code class="option">-b</code>: Save
|
||||
unrelated changesets that are intermixed with the stripped
|
||||
changesets in the backup bundle.</p></li><li><p id="x_631"><a name="x_631"></a><code class="option">-f</code>: If a
|
||||
branch has multiple heads, remove all heads.</p></li><li><p id="x_632"><a name="x_632"></a><code class="option">-n</code>: Do
|
||||
not save a backup bundle.</p></li></ul></div></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id446370">MQ file reference</h2></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id446375">The <code class="filename">series</code>
|
||||
file</h3></div></div></div><p id="x_633"><a name="x_633"></a>The <code class="filename">series</code> file
|
||||
contains a list of the names of all patches that MQ can apply.
|
||||
It is represented as a list of names, with one name saved per
|
||||
line. Leading and trailing white space in each line are
|
||||
ignored.</p><p id="x_634"><a name="x_634"></a>Lines may contain comments. A comment begins with the
|
||||
“<span class="quote"><code class="literal">#</code></span>” character, and extends to
|
||||
the end of the line. Empty lines, and lines that contain only
|
||||
comments, are ignored.</p><p id="x_635"><a name="x_635"></a>You will often need to edit the <code class="filename">series</code> file by hand, hence the
|
||||
support for comments and empty lines noted above. For
|
||||
example, you can comment out a patch temporarily, and <span class="command"><strong>qpush</strong></span> will skip over that patch
|
||||
when applying patches. You can also change the order in which
|
||||
patches are applied by reordering their entries in the
|
||||
<code class="filename">series</code> file.</p><p id="x_636"><a name="x_636"></a>Placing the <code class="filename">series</code>
|
||||
file under revision control is also supported; it is a good
|
||||
idea to place all of the patches that it refers to under
|
||||
revision control, as well. If you create a patch directory
|
||||
using the <code class="option">-c</code>
|
||||
option to <span class="command"><strong>qinit</strong></span>, this will
|
||||
be done for you automatically.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id446487">The <code class="filename">status</code>
|
||||
file</h3></div></div></div><p id="x_637"><a name="x_637"></a>The <code class="filename">status</code> file
|
||||
contains the names and changeset hashes of all patches that MQ
|
||||
currently has applied. Unlike the <code class="filename">series</code> file, this file is not
|
||||
intended for editing. You should not place this file under
|
||||
revision control, or modify it in any way. It is used by MQ
|
||||
strictly for internal book-keeping.</p></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="migrating-to-mercurial.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="installing-mercurial-from-source.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Appendix A. Migrating to Mercurial </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Appendix C. Installing Mercurial from source</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
221
read/migrating-to-mercurial.html
Normal file
221
read/migrating-to-mercurial.html
Normal file
|
@ -0,0 +1,221 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Appendix A. Migrating to Mercurial</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="adding-functionality-with-extensions.html" title="Chapter 14. Adding functionality with extensions"><link rel="next" href="mercurial-queues-reference.html" title="Appendix B. Mercurial Queues reference"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix A. Migrating to Mercurial</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="adding-functionality-with-extensions.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="mercurial-queues-reference.html">Next</a></td></tr></table></div><div class="appendix" lang="en" id="svn"><div class="titlepage"><div><div><h2 class="title">Appendix A. Migrating to Mercurial</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="migrating-to-mercurial.html#id441179">Importing history from another system</a></span></dt><dd><dl><dt><span class="sect2"><a href="migrating-to-mercurial.html#id441710">Converting multiple branches</a></span></dt><dt><span class="sect2"><a href="migrating-to-mercurial.html#id441801">Mapping user names</a></span></dt><dt><span class="sect2"><a href="migrating-to-mercurial.html#svn.filemap">Tidying up the tree</a></span></dt><dt><span class="sect2"><a href="migrating-to-mercurial.html#id441972">Improving Subversion conversion performance</a></span></dt></dl></dd><dt><span class="sect1"><a href="migrating-to-mercurial.html#id442205">Migrating from Subversion</a></span></dt><dd><dl><dt><span class="sect2"><a href="migrating-to-mercurial.html#id442221">Philosophical differences</a></span></dt><dd><dl><dt><span class="sect3"><a href="migrating-to-mercurial.html#id442247">Scope of commands</a></span></dt><dt><span class="sect3"><a href="migrating-to-mercurial.html#id442299">Multi-user operation and safety</a></span></dt><dt><span class="sect3"><a href="migrating-to-mercurial.html#id442339">Published vs local changes</a></span></dt></dl></dd><dt><span class="sect2"><a href="migrating-to-mercurial.html#id442397">Quick reference</a></span></dt></dl></dd><dt><span class="sect1"><a href="migrating-to-mercurial.html#id442924">Useful tips for newcomers</a></span></dt></dl></div><p id="x_6e1"><a name="x_6e1"></a>A common way to test the waters with a new revision control
|
||||
tool is to experiment with switching an existing project, rather
|
||||
than starting a new project from scratch.</p><p id="x_6e2"><a name="x_6e2"></a>In this appendix, we discuss how to import a project's history
|
||||
into Mercurial, and what to look out for if you are used to a
|
||||
different revision control system.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id441179">Importing history from another system</h2></div></div></div><p id="x_6e3"><a name="x_6e3"></a>Mercurial ships with an extension named
|
||||
<code class="literal">convert</code>, which can import project history
|
||||
from most popular revision control systems. At the time this
|
||||
book was written, it could import history from the following
|
||||
systems:</p><div class="itemizedlist"><ul type="disc"><li><p id="x_6e4"><a name="x_6e4"></a>Subversion</p></li><li><p id="x_6e5"><a name="x_6e5"></a>CVS</p></li><li><p id="x_6e6"><a name="x_6e6"></a>git</p></li><li><p id="x_6e7"><a name="x_6e7"></a>Darcs</p></li><li><p id="x_6e8"><a name="x_6e8"></a>Bazaar</p></li><li><p id="x_6e9"><a name="x_6e9"></a>Monotone</p></li><li><p id="x_6ea"><a name="x_6ea"></a>GNU Arch</p></li><li><p id="x_6eb"><a name="x_6eb"></a>Mercurial</p></li></ul></div><p id="x_6ec"><a name="x_6ec"></a>(To see why Mercurial itself is supported as a source, see
|
||||
<a class="xref" href="migrating-to-mercurial.html#svn.filemap" title="Tidying up the tree">the section called “Tidying up the tree”</a>.)</p><p id="x_6ed"><a name="x_6ed"></a>You can enable the extension in the usual way, by editing
|
||||
your <code class="filename">~/.hgrc</code> file.</p><pre id="id441625" class="programlisting">[extensions]
|
||||
convert =</pre><p id="x_6ee"><a name="x_6ee"></a>This will make a <span class="command"><strong>hg convert</strong></span> command
|
||||
available. The command is easy to use. For instance, this
|
||||
command will import the Subversion history for the Nose unit
|
||||
testing framework into Mercurial.</p><pre id="id441645" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg convert http://python-nose.googlecode.com/svn/trunk</code></strong></pre><p id="x_6ef"><a name="x_6ef"></a>The <code class="literal">convert</code> extension operates
|
||||
incrementally. In other words, after you have run <span class="command"><strong>hg
|
||||
convert</strong></span> once, running it again will import any new
|
||||
revisions committed after the first run began. Incremental
|
||||
conversion will only work if you run <span class="command"><strong>hg
|
||||
convert</strong></span> in the same Mercurial repository that you
|
||||
originally used, because the <code class="literal">convert</code>
|
||||
extension saves some private metadata in a
|
||||
non-revision-controlled file named
|
||||
<code class="filename">.hg/shamap</code> inside the target
|
||||
repository.</p><p id="x_707"><a name="x_707"></a>When you want to start making changes using Mercurial, it's
|
||||
best to clone the tree in which you are doing your conversions,
|
||||
and leave the original tree for future incremental conversions.
|
||||
This is the safest way to let you pull and merge future commits
|
||||
from the source revision control system into your newly active
|
||||
Mercurial project.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id441710">Converting multiple branches</h3></div></div></div><p id="x_708"><a name="x_708"></a>The <span class="command"><strong>hg convert</strong></span> command given above
|
||||
converts only the history of the <code class="literal">trunk</code>
|
||||
branch of the Subversion repository. If we instead use the
|
||||
URL <code class="literal">http://python-nose.googlecode.com/svn</code>,
|
||||
Mercurial will automatically detect the
|
||||
<code class="literal">trunk</code>, <code class="literal">tags</code> and
|
||||
<code class="literal">branches</code> layout that Subversion projects
|
||||
usually use, and it will import each as a separate Mercurial
|
||||
branch.</p><p id="x_709"><a name="x_709"></a>By default, each Subversion branch imported into Mercurial
|
||||
is given a branch name. After the conversion completes, you
|
||||
can get a list of the active branch names in the Mercurial
|
||||
repository using <span class="command"><strong>hg branches -a</strong></span>. If you
|
||||
would prefer to import the Subversion branches without names,
|
||||
pass the <code class="option">--config
|
||||
convert.hg.usebranchnames=false</code> option to
|
||||
<span class="command"><strong>hg convert</strong></span>.</p><p id="x_70a"><a name="x_70a"></a>Once you have converted your tree, if you want to follow
|
||||
the usual Mercurial practice of working in a tree that
|
||||
contains a single branch, you can clone that single branch
|
||||
using <span class="command"><strong>hg clone -r mybranchname</strong></span>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id441801">Mapping user names</h3></div></div></div><p id="x_6f0"><a name="x_6f0"></a>Some revision control tools save only short usernames with
|
||||
commits, and these can be difficult to interpret. The norm
|
||||
with Mercurial is to save a committer's name and email
|
||||
address, which is much more useful for talking to them after
|
||||
the fact.</p><p id="x_6f1"><a name="x_6f1"></a>If you are converting a tree from a revision control
|
||||
system that uses short names, you can map those names to
|
||||
longer equivalents by passing a <code class="option">--authors</code>
|
||||
option to <span class="command"><strong>hg convert</strong></span>. This option accepts
|
||||
a file name that should contain entries of the following
|
||||
form.</p><pre id="id441835" class="programlisting">arist = Aristotle <aristotle@phil.example.gr>
|
||||
soc = Socrates <socrates@phil.example.gr></pre><p id="x_6f2"><a name="x_6f2"></a>Whenever <code class="literal">convert</code> encounters a commit
|
||||
with the username <code class="literal">arist</code> in the source
|
||||
repository, it will use the name <code class="literal">Aristotle
|
||||
<aristotle@phil.example.gr></code> in the converted
|
||||
Mercurial revision. If no match is found for a name, it is
|
||||
used verbatim.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="svn.filemap">Tidying up the tree</h3></div></div></div><p id="x_6f3"><a name="x_6f3"></a>Not all projects have pristine history. There may be a
|
||||
directory that should never have been checked in, a file that
|
||||
is too big, or a whole hierarchy that needs to be
|
||||
refactored.</p><p id="x_6f4"><a name="x_6f4"></a>The <code class="literal">convert</code> extension supports the idea
|
||||
of a “<span class="quote">file map</span>” that can reorganize the files and
|
||||
directories in a project as it imports the project's history.
|
||||
This is useful not only when importing history from other
|
||||
revision control systems, but also to prune or refactor a
|
||||
Mercurial tree.</p><p id="x_6f5"><a name="x_6f5"></a>To specify a file map, use the <code class="option">--filemap</code>
|
||||
option and supply a file name. A file map contains lines of the
|
||||
following forms.</p><pre id="id441918" class="programlisting"># This is a comment.
|
||||
# Empty lines are ignored.
|
||||
|
||||
include path/to/file
|
||||
|
||||
exclude path/to/file
|
||||
|
||||
rename from/some/path to/some/other/place
|
||||
</pre><p id="x_6f6"><a name="x_6f6"></a>The <code class="literal">include</code> directive causes a file, or
|
||||
all files under a directory, to be included in the destination
|
||||
repository. This also excludes all other files and dirs not
|
||||
explicitely included. The <code class="literal">exclude</code>
|
||||
directive causes files or directories to be omitted, and
|
||||
others not explicitly mentioned to be included.</p><p id="x_6f7"><a name="x_6f7"></a>To move a file or directory from one location to another,
|
||||
use the <code class="literal">rename</code> directive. If you need to
|
||||
move a file or directory from a subdirectory into the root of
|
||||
the repository, use <code class="literal">.</code> as the second
|
||||
argument to the <code class="literal">rename</code> directive.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id441972">Improving Subversion conversion performance</h3></div></div></div><p id="x_70b"><a name="x_70b"></a>You will often need several attempts before you hit the
|
||||
perfect combination of user map, file map, and other
|
||||
conversion parameters. Converting a Subversion repository
|
||||
over an access protocol like <code class="literal">ssh</code> or
|
||||
<code class="literal">http</code> can proceed thousands of times more
|
||||
slowly than Mercurial is capable of actually operating, due to
|
||||
network delays. This can make tuning that perfect conversion
|
||||
recipe very painful.</p><p id="x_70c"><a name="x_70c"></a>The <a class="ulink" href="http://svn.collab.net/repos/svn/trunk/notes/svnsync.txt" target="_top"><span class="command"><strong>svnsync</strong></span></a>
|
||||
command can greatly speed up the conversion of a Subversion
|
||||
repository. It is a read-only mirroring program for
|
||||
Subversion repositories. The idea is that you create a local
|
||||
mirror of your Subversion tree, then convert the mirror into a
|
||||
Mercurial repository.</p><p id="x_70d"><a name="x_70d"></a>Suppose we want to convert the Subversion repository for
|
||||
the popular Memcached project into a Mercurial tree. First,
|
||||
we create a local Subversion repository.</p><pre id="id442028" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>svnadmin create memcached-mirror</code></strong></pre><p id="x_70e"><a name="x_70e"></a>Next, we set up a Subversion hook that
|
||||
<span class="command"><strong>svnsync</strong></span> needs.</p><pre id="id442056" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>echo '#!/bin/sh' > memcached-mirror/hooks/pre-revprop-change</code></strong>
|
||||
<code class="prompt">$</code> <strong class="userinput"><code>chmod +x memcached-mirror/hooks/pre-revprop-change</code></strong></pre><p id="x_70f"><a name="x_70f"></a>We then initialize <span class="command"><strong>svnsync</strong></span> in this
|
||||
repository.</p><pre id="id442096" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>svnsync --init file://`pwd`/memcached-mirror \
|
||||
http://code.sixapart.com/svn/memcached</code></strong></pre><p id="x_710"><a name="x_710"></a>Our next step is to begin the <span class="command"><strong>svnsync</strong></span>
|
||||
mirroring process.</p><pre id="id442124" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>svnsync sync file://`pwd`/memcached-mirror</code></strong></pre><p id="x_711"><a name="x_711"></a>Finally, we import the history of our local Subversion
|
||||
mirror into Mercurial.</p><pre id="id442146" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg convert memcached-mirror</code></strong></pre><p id="x_712"><a name="x_712"></a>We can use this process incrementally if the Subversion
|
||||
repository is still in use. We run <span class="command"><strong>svnsync</strong></span>
|
||||
to pull new changes into our mirror, then <span class="command"><strong>hg
|
||||
convert</strong></span> to import them into our Mercurial
|
||||
tree.</p><p id="x_713"><a name="x_713"></a>There are two advantages to doing a two-stage import with
|
||||
<span class="command"><strong>svnsync</strong></span>. The first is that it uses more
|
||||
efficient Subversion network syncing code than <span class="command"><strong>hg
|
||||
convert</strong></span>, so it transfers less data over the
|
||||
network. The second is that the import from a local
|
||||
Subversion tree is so fast that you can tweak your conversion
|
||||
setup repeatedly without having to sit through a painfully
|
||||
slow network-based conversion process each time.</p></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id442205">Migrating from Subversion</h2></div></div></div><p id="x_6f8"><a name="x_6f8"></a>Subversion is currently the most popular open source
|
||||
revision control system. Although there are many differences
|
||||
between Mercurial and Subversion, making the transition from
|
||||
Subversion to Mercurial is not particularly difficult. The two
|
||||
have similar command sets and generally uniform
|
||||
interfaces.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id442221">Philosophical differences</h3></div></div></div><p id="x_6f9"><a name="x_6f9"></a>The fundamental difference between Subversion and
|
||||
Mercurial is of course that Subversion is centralized, while
|
||||
Mercurial is distributed. Since Mercurial stores all of a
|
||||
project's history on your local drive, it only needs to
|
||||
perform a network access when you want to explicitly
|
||||
communicate with another repository. In contrast, Subversion
|
||||
stores very little information locally, and the client must
|
||||
thus contact its server for many common operations.</p><p id="x_6fa"><a name="x_6fa"></a>Subversion more or less gets away without a well-defined
|
||||
notion of a branch: which portion of a server's namespace
|
||||
qualifies as a branch is a matter of convention, with the
|
||||
software providing no enforcement. Mercurial treats a
|
||||
repository as the unit of branch management.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id442247">Scope of commands</h4></div></div></div><p id="x_6fb"><a name="x_6fb"></a>Since Subversion doesn't know what parts of its
|
||||
namespace are really branches, it treats most commands as
|
||||
requests to operate at and below whatever directory you are
|
||||
currently visiting. For instance, if you run <span class="command"><strong>svn
|
||||
log</strong></span>, you'll get the history of whatever part of
|
||||
the tree you're looking at, not the tree as a whole.</p><p id="x_6fc"><a name="x_6fc"></a>Mercurial's commands behave differently, by defaulting
|
||||
to operating over an entire repository. Run <span class="command"><strong>hg
|
||||
log</strong></span> and it will tell you the history of the
|
||||
entire tree, no matter what part of the working directory
|
||||
you're visiting at the time. If you want the history of
|
||||
just a particular file or directory, simply supply it by
|
||||
name, e.g. <span class="command"><strong>hg log src</strong></span>.</p><p id="x_6fd"><a name="x_6fd"></a>From my own experience, this difference in default
|
||||
behaviors is probably the most likely to trip you up if you
|
||||
have to switch back and forth frequently between the two
|
||||
tools.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id442299">Multi-user operation and safety</h4></div></div></div><p id="x_6fe"><a name="x_6fe"></a>With Subversion, it is normal (though slightly frowned
|
||||
upon) for multiple people to collaborate in a single branch.
|
||||
If Alice and Bob are working together, and Alice commits
|
||||
some changes to their shared branch, Bob must update his
|
||||
client's view of the branch before he can commit. Since at
|
||||
this time he has no permanent record of the changes he has
|
||||
made, he can corrupt or lose his modifications during and
|
||||
after his update.</p><p id="x_6ff"><a name="x_6ff"></a>Mercurial encourages a commit-then-merge model instead.
|
||||
Bob commits his changes locally before pulling changes from,
|
||||
or pushing them to, the server that he shares with Alice.
|
||||
If Alice pushed her changes before Bob tries to push his, he
|
||||
will not be able to push his changes until he pulls hers,
|
||||
merges with them, and commits the result of the merge. If
|
||||
he makes a mistake during the merge, he still has the option
|
||||
of reverting to the commit that recorded his changes.</p><p id="x_700"><a name="x_700"></a>It is worth emphasizing that these are the common ways
|
||||
of working with these tools. Subversion supports a safer
|
||||
work-in-your-own-branch model, but it is cumbersome enough
|
||||
in practice to not be widely used. Mercurial can support
|
||||
the less safe mode of allowing changes to be pulled in and
|
||||
merged on top of uncommitted edits, but this is considered
|
||||
highly unusual.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title" id="id442339">Published vs local changes</h4></div></div></div><p id="x_701"><a name="x_701"></a>A Subversion <span class="command"><strong>svn commit</strong></span> command
|
||||
immediately publishes changes to a server, where they can be
|
||||
seen by everyone who has read access.</p><p id="x_702"><a name="x_702"></a>With Mercurial, commits are always local, and must be
|
||||
published via a <span class="command"><strong>hg push</strong></span> command
|
||||
afterwards.</p><p id="x_703"><a name="x_703"></a>Each approach has its advantages and disadvantages. The
|
||||
Subversion model means that changes are published, and hence
|
||||
reviewable and usable, immediately. On the other hand, this
|
||||
means that a user must have commit access to a repository in
|
||||
order to use the software in a normal way, and commit access
|
||||
is not lightly given out by most open source
|
||||
projects.</p><p id="x_704"><a name="x_704"></a>The Mercurial approach allows anyone who can clone a
|
||||
repository to commit changes without the need for someone
|
||||
else's permission, and they can then publish their changes
|
||||
and continue to participate however they see fit. The
|
||||
distinction between committing and pushing does open up the
|
||||
possibility of someone committing changes to their laptop
|
||||
and walking away for a few days having forgotten to push
|
||||
them, which in rare cases might leave collaborators
|
||||
temporarily stuck.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title" id="id442397">Quick reference</h3></div></div></div><div class="table"><a name="id442402"></a><p class="title"><b>Table A.1. Subversion commands and Mercurial equivalents</b></p><div class="table-contents"><table summary="Subversion commands and Mercurial equivalents" border="1"><colgroup><col><col><col></colgroup><thead><tr><th>Subversion</th><th>Mercurial</th><th>Notes</th></tr></thead><tbody><tr><td><span class="command"><strong>svn add</strong></span></td><td><span class="command"><strong>hg add</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn blame</strong></span></td><td><span class="command"><strong>hg annotate</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn cat</strong></span></td><td><span class="command"><strong>hg cat</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn checkout</strong></span></td><td><span class="command"><strong>hg clone</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn cleanup</strong></span></td><td>n/a</td><td>No cleanup needed</td></tr><tr><td><span class="command"><strong>svn commit</strong></span></td><td><span class="command"><strong>hg commit</strong></span>; <span class="command"><strong>hg
|
||||
push</strong></span></td><td><span class="command"><strong>hg push</strong></span> publishes after
|
||||
commit</td></tr><tr><td><span class="command"><strong>svn copy</strong></span></td><td><span class="command"><strong>hg clone</strong></span></td><td>To create a new branch</td></tr><tr><td><span class="command"><strong>svn copy</strong></span></td><td><span class="command"><strong>hg copy</strong></span></td><td>To copy files or directories</td></tr><tr><td><span class="command"><strong>svn delete</strong></span> (<span class="command"><strong>svn
|
||||
remove</strong></span>)</td><td><span class="command"><strong>hg remove</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn diff</strong></span></td><td><span class="command"><strong>hg diff</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn export</strong></span></td><td><span class="command"><strong>hg archive</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn help</strong></span></td><td><span class="command"><strong>hg help</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn import</strong></span></td><td><span class="command"><strong>hg addremove</strong></span>; <span class="command"><strong>hg
|
||||
commit</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn info</strong></span></td><td><span class="command"><strong>hg parents</strong></span></td><td>Shows what revision is checked out</td></tr><tr><td><span class="command"><strong>svn info</strong></span></td><td><span class="command"><strong>hg showconfig
|
||||
paths.parent</strong></span></td><td>Shows what URL is checked out</td></tr><tr><td><span class="command"><strong>svn list</strong></span></td><td><span class="command"><strong>hg manifest</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn log</strong></span></td><td><span class="command"><strong>hg log</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn merge</strong></span></td><td><span class="command"><strong>hg merge</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn mkdir</strong></span></td><td>n/a</td><td>Mercurial does not track directories</td></tr><tr><td><span class="command"><strong>svn move</strong></span> (<span class="command"><strong>svn
|
||||
rename</strong></span>)</td><td><span class="command"><strong>hg rename</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn resolved</strong></span></td><td><span class="command"><strong>hg resolve -m</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn revert</strong></span></td><td><span class="command"><strong>hg revert</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn status</strong></span></td><td><span class="command"><strong>hg status</strong></span></td><td> </td></tr><tr><td><span class="command"><strong>svn update</strong></span></td><td><span class="command"><strong>hg pull -u</strong></span></td><td> </td></tr></tbody></table></div></div><br class="table-break"></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id442924">Useful tips for newcomers</h2></div></div></div><p id="x_705"><a name="x_705"></a>Under some revision control systems, printing a diff for a
|
||||
single committed revision can be painful. For instance, with
|
||||
Subversion, to see what changed in revision 104654, you must
|
||||
type <span class="command"><strong>svn diff -r104653:104654</strong></span>. Mercurial
|
||||
eliminates the need to type the revision ID twice in this common
|
||||
case. For a plain diff, <span class="command"><strong>hg export 104654</strong></span>. For
|
||||
a log message followed by a diff, <span class="command"><strong>hg log -r104654
|
||||
-p</strong></span>.</p><p id="x_706"><a name="x_706"></a>When you run <span class="command"><strong>hg status</strong></span> without any
|
||||
arguments, it prints the status of the entire tree, with paths
|
||||
relative to the root of the repository. This makes it tricky to
|
||||
copy a file name from the output of <span class="command"><strong>hg status</strong></span>
|
||||
into the command line. If you supply a file or directory name
|
||||
to <span class="command"><strong>hg status</strong></span>, it will print paths relative to
|
||||
your current location instead. So to get tree-wide status from
|
||||
<span class="command"><strong>hg status</strong></span>, with paths that are relative to
|
||||
your current directory and not the root of the repository, feed
|
||||
the output of <span class="command"><strong>hg root</strong></span> into <span class="command"><strong>hg
|
||||
status</strong></span>. You can easily do this as follows on a
|
||||
Unix-like system:</p><pre id="id443005" class="screen"><code class="prompt">$</code> <strong class="userinput"><code>hg status `hg root`</code></strong></pre></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="adding-functionality-with-extensions.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="mercurial-queues-reference.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 14. Adding functionality with extensions </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Appendix B. Mercurial Queues reference</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
89
read/open-publication-license.html
Normal file
89
read/open-publication-license.html
Normal file
|
@ -0,0 +1,89 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Appendix D. Open Publication License</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="installing-mercurial-from-source.html" title="Appendix C. Installing Mercurial from source"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix D. Open Publication License</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="installing-mercurial-from-source.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> </td></tr></table></div><div class="appendix" lang="en" id="cha:opl"><div class="titlepage"><div><div><h2 class="title">Appendix D. Open Publication License</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="open-publication-license.html#id448273">Requirements on both unmodified and modified
|
||||
versions</a></span></dt><dt><span class="sect1"><a href="open-publication-license.html#id448880">Copyright</a></span></dt><dt><span class="sect1"><a href="open-publication-license.html#id448894">Scope of license</a></span></dt><dt><span class="sect1"><a href="open-publication-license.html#id448948">Requirements on modified works</a></span></dt><dt><span class="sect1"><a href="open-publication-license.html#id449019">Good-practice recommendations</a></span></dt><dt><span class="sect1"><a href="open-publication-license.html#sec:opl:options">License options</a></span></dt></dl></div><p id="x_638"><a name="x_638"></a>Version 1.0, 8 June 1999</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id448273">Requirements on both unmodified and modified
|
||||
versions</h2></div></div></div><p id="x_639"><a name="x_639"></a>The Open Publication works may be reproduced and distributed
|
||||
in whole or in part, in any medium physical or electronic,
|
||||
provided that the terms of this license are adhered to, and that
|
||||
this license or an incorporation of it by reference (with any
|
||||
options elected by the author(s) and/or publisher) is displayed
|
||||
in the reproduction.</p><p id="x_63a"><a name="x_63a"></a>Proper form for an incorporation by reference is as
|
||||
follows:</p><div class="blockquote"><blockquote class="blockquote"><p id="x_63b"><a name="x_63b"></a> Copyright (c) <span class="emphasis"><em>year</em></span> by
|
||||
<span class="emphasis"><em>author's name or designee</em></span>. This material
|
||||
may be distributed only subject to the terms and conditions
|
||||
set forth in the Open Publication License,
|
||||
v<span class="emphasis"><em>x.y</em></span> or later (the latest version is
|
||||
presently available at <a class="ulink" href="http://www.opencontent.org/openpub/" target="_top">http://www.opencontent.org/openpub/</a>).</p></blockquote></div><p id="x_63c"><a name="x_63c"></a>The reference must be immediately followed with any options
|
||||
elected by the author(s) and/or publisher of the document (see
|
||||
<a class="xref" href="open-publication-license.html#sec:opl:options" title="License options">the section called “License options”</a>).</p><p id="x_63d"><a name="x_63d"></a>Commercial redistribution of Open Publication-licensed
|
||||
material is permitted.</p><p id="x_63e"><a name="x_63e"></a>Any publication in standard (paper) book form shall require
|
||||
the citation of the original publisher and author. The publisher
|
||||
and author's names shall appear on all outer surfaces of the
|
||||
book. On all outer surfaces of the book the original publisher's
|
||||
name shall be as large as the title of the work and cited as
|
||||
possessive with respect to the title.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id448880">Copyright</h2></div></div></div><p id="x_63f"><a name="x_63f"></a>The copyright to each Open Publication is owned by its
|
||||
author(s) or designee.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id448894">Scope of license</h2></div></div></div><p id="x_640"><a name="x_640"></a>The following license terms apply to all Open Publication
|
||||
works, unless otherwise explicitly stated in the
|
||||
document.</p><p id="x_641"><a name="x_641"></a>Mere aggregation of Open Publication works or a portion of
|
||||
an Open Publication work with other works or programs on the
|
||||
same media shall not cause this license to apply to those other
|
||||
works. The aggregate work shall contain a notice specifying the
|
||||
inclusion of the Open Publication material and appropriate
|
||||
copyright notice.</p><p id="x_642"><a name="x_642"></a><span class="bold"><strong>Severability</strong></span>. If any part
|
||||
of this license is found to be unenforceable in any
|
||||
jurisdiction, the remaining portions of the license remain in
|
||||
force.</p><p id="x_643"><a name="x_643"></a><span class="bold"><strong>No warranty</strong></span>. Open
|
||||
Publication works are licensed and provided “<span class="quote">as is</span>”
|
||||
without warranty of any kind, express or implied, including, but
|
||||
not limited to, the implied warranties of merchantability and
|
||||
fitness for a particular purpose or a warranty of
|
||||
non-infringement.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id448948">Requirements on modified works</h2></div></div></div><p id="x_644"><a name="x_644"></a>All modified versions of documents covered by this license,
|
||||
including translations, anthologies, compilations and partial
|
||||
documents, must meet the following requirements:</p><div class="orderedlist"><ol type="1"><li><p id="x_645"><a name="x_645"></a>The modified version must be labeled as
|
||||
such.</p></li><li><p id="x_646"><a name="x_646"></a>The person making the modifications must be
|
||||
identified and the modifications dated.</p></li><li><p id="x_647"><a name="x_647"></a>Acknowledgement of the original author and
|
||||
publisher if applicable must be retained according to normal
|
||||
academic citation practices.</p></li><li><p id="x_648"><a name="x_648"></a>The location of the original unmodified document
|
||||
must be identified.</p></li><li><p id="x_649"><a name="x_649"></a>The original author's (or authors') name(s) may
|
||||
not be used to assert or imply endorsement of the resulting
|
||||
document without the original author's (or authors')
|
||||
permission.</p></li></ol></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id449019">Good-practice recommendations</h2></div></div></div><p id="x_64a"><a name="x_64a"></a>In addition to the requirements of this license, it is
|
||||
requested from and strongly recommended of redistributors
|
||||
that:</p><div class="orderedlist"><ol type="1"><li><p id="x_64b"><a name="x_64b"></a>If you are distributing Open Publication works
|
||||
on hardcopy or CD-ROM, you provide email notification to the
|
||||
authors of your intent to redistribute at least thirty days
|
||||
before your manuscript or media freeze, to give the authors
|
||||
time to provide updated documents. This notification should
|
||||
describe modifications, if any, made to the document.</p></li><li><p id="x_64c"><a name="x_64c"></a>All substantive modifications (including
|
||||
deletions) be either clearly marked up in the document or
|
||||
else described in an attachment to the document.</p></li><li><p id="x_64d"><a name="x_64d"></a>Finally, while it is not mandatory under this
|
||||
license, it is considered good form to offer a free copy of
|
||||
any hardcopy and CD-ROM expression of an Open
|
||||
Publication-licensed work to its author(s).</p></li></ol></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="sec:opl:options">License options</h2></div></div></div><p id="x_64e"><a name="x_64e"></a>The author(s) and/or publisher of an Open
|
||||
Publication-licensed document may elect certain options by
|
||||
appending language to the reference to or copy of the license.
|
||||
These options are considered part of the license instance and
|
||||
must be included with the license (or its incorporation by
|
||||
reference) in derived works.</p><div class="orderedlist"><ol type="1"><li><p id="x_64f"><a name="x_64f"></a>To prohibit distribution of substantively
|
||||
modified versions without the explicit permission of the
|
||||
author(s). “<span class="quote">Substantive modification</span>” is
|
||||
defined as a change to the semantic content of the document,
|
||||
and excludes mere changes in format or typographical
|
||||
corrections.</p></li><li><p id="x_650"><a name="x_650"></a> To accomplish this, add the phrase
|
||||
“<span class="quote">Distribution of substantively modified versions of
|
||||
this document is prohibited without the explicit
|
||||
permission of the copyright holder.</span>” to the license
|
||||
reference or copy.</p></li><li><p id="x_651"><a name="x_651"></a>To prohibit any publication of this work or
|
||||
derivative works in whole or in part in standard (paper)
|
||||
book form for commercial purposes is prohibited unless prior
|
||||
permission is obtained from the copyright holder.</p></li><li><p id="x_652"><a name="x_652"></a>To accomplish this, add the phrase
|
||||
“<span class="quote">Distribution of the work or derivative of the work in
|
||||
any standard (paper) book form is prohibited unless prior
|
||||
permission is obtained from the copyright holder.</span>”
|
||||
to the license reference or copy.</p></li></ol></div></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="installing-mercurial-from-source.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">Appendix C. Installing Mercurial from source </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
112
read/preface.html
Normal file
112
read/preface.html
Normal file
|
@ -0,0 +1,112 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Preface</title><link rel="stylesheet" href="/support/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.3"><link rel="home" href="index.html" title="Mercurial: The Definitive Guide"><link rel="up" href="index.html" title="Mercurial: The Definitive Guide"><link rel="prev" href="index.html" title="Mercurial: The Definitive Guide"><link rel="next" href="how-did-we-get-here.html" title="Chapter 1. How did we get here?"><link rel="alternate" type="application/atom+xml" title="Comments" href="/feeds/comments/"><link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"><script type="text/javascript" src="/support/jquery-min.js"></script><script type="text/javascript" src="/support/form.js"></script><script type="text/javascript" src="/support/hsbook.js"></script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a><span class="authors">by Bryan O'Sullivan</span></h2></div><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Preface</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="how-did-we-get-here.html">Next</a></td></tr></table></div><div class="preface" lang="en" id="chap:preface"><div class="titlepage"><div><div><h2 class="title">Preface</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="preface.html#id321829">Technical storytelling</a></span></dt><dt><span class="sect1"><a href="preface.html#id330285">Thank you for supporting Mercurial</a></span></dt><dt><span class="sect1"><a href="preface.html#id296114">Acknowledgments</a></span></dt><dt><span class="sect1"><a href="preface.html#id298254">Conventions Used in This Book</a></span></dt><dt><span class="sect1"><a href="preface.html#id341884">Using Code Examples</a></span></dt><dt><span class="sect1"><a href="preface.html#id297605">Safari® Books Online</a></span></dt><dt><span class="sect1"><a href="preface.html#id297646">How to Contact Us</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id321829">Technical storytelling</h2></div></div></div><p id="x_72e"><a name="x_72e"></a>A few years ago, when I wanted to explain why I believed
|
||||
that distributed revision control is important, the field was
|
||||
then so new that there was almost no published literature to
|
||||
refer people to.</p><p id="x_72f"><a name="x_72f"></a>Although at that time I spent some time working on the
|
||||
internals of Mercurial itself, I switched to writing this book
|
||||
because that seemed like the most effective way to help the
|
||||
software to reach a wide audience, along with the idea that
|
||||
revision control ought to be distributed in nature. I publish
|
||||
the book online under a liberal license for the same
|
||||
reason: to get the word out.</p><p id="x_730"><a name="x_730"></a>There's a familiar rhythm to a good software book that
|
||||
closely resembles telling a story: What is this thing? Why does
|
||||
it matter? How will it help me? How do I use it? In this
|
||||
book, I try to answer those questions for distributed revision
|
||||
control in general, and for Mercurial in particular.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id330285">Thank you for supporting Mercurial</h2></div></div></div><p id="x_731"><a name="x_731"></a>By purchasing a copy of this book, you are supporting the
|
||||
continued development and freedom of Mercurial in particular,
|
||||
and of open source and free software in general. O'Reilly Media
|
||||
and I are donating my royalties on the sales of this book to the
|
||||
Software Freedom Conservancy (<a class="ulink" href="http://www.softwarefreedom.org/" target="_top">http://www.softwarefreedom.org/</a>)
|
||||
which provides clerical and legal support to Mercurial and a
|
||||
number of other prominent and worthy open source software
|
||||
projects.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id296114">Acknowledgments</h2></div></div></div><p id="x_732"><a name="x_732"></a>This book would not exist were it not for the efforts of
|
||||
Matt Mackall, the author and project lead of Mercurial. He is
|
||||
ably assisted by hundreds of volunteer contributors across the
|
||||
world.</p><p id="x_733"><a name="x_733"></a>My children, Cian and Ruairi, always stood ready to help me
|
||||
to unwind with wonderful, madcap little-boy games. I'd also
|
||||
like to thank my ex-wife, Shannon, for her support.</p><p id="x_734"><a name="x_734"></a>My colleagues and friends provided help and support in
|
||||
innumerable ways. This list of people is necessarily very
|
||||
incomplete: Stephen Hahn, Karyn Ritter, Bonnie Corwin, James
|
||||
Vasile, Matt Norwood, Eben Moglen, Bradley Kuhn, Robert Walsh,
|
||||
Jeremy Fitzhardinge, Rachel Chalmers.</p><p id="x_735"><a name="x_735"></a>I developed this book in the open, posting drafts of
|
||||
chapters to the book web site as I completed them. Readers then
|
||||
submitted feedback using a web application that I developed. By
|
||||
the time I finished writing the book, more than 100 people had
|
||||
submitted comments, an amazing number considering that the
|
||||
comment system was live for only about two months towards the
|
||||
end of the writing process.</p><p id="x_736"><a name="x_736"></a>I would particularly like to recognize the following people,
|
||||
who between them contributed over a third of the total number of
|
||||
comments. I would like to thank them for their care and effort
|
||||
in providing so much detailed feedback.</p><p id="x_737"><a name="x_737"></a>Martin Geisler, Damien Cassou, Alexey Bakhirkin, Till Plewe,
|
||||
Dan Himes, Paul Sargent, Gokberk Hamurcu, Matthijs van der
|
||||
Vleuten, Michael Chermside, John Mulligan, Jordi Fita, Jon
|
||||
Parise.</p><p id="x_738"><a name="x_738"></a>I also want to acknowledge the help of the many people who
|
||||
caught errors and provided helpful suggestions throughout the
|
||||
book.</p><p id="x_739"><a name="x_739"></a>Jeremy W. Sherman, Brian Mearns, Vincent Furia, Iwan
|
||||
Luijks, Billy Edwards, Andreas Sliwka, Paweł Sołyga, Eric
|
||||
Hanchrow, Steve Nicolai, Michał Masłowski, Kevin Fitch, Johan
|
||||
Holmberg, Hal Wine, Volker Simonis, Thomas P Jakobsen, Ted
|
||||
Stresen-Reuter, Stephen Rasku, Raphael Das Gupta, Ned
|
||||
Batchelder, Lou Keeble, Li Linxiao, Kao Cardoso Félix, Joseph
|
||||
Wecker, Jon Prescot, Jon Maken, John Yeary, Jason Harris,
|
||||
Geoffrey Zheng, Fredrik Jonson, Ed Davies, David Zumbrunnen,
|
||||
David Mercer, David Cabana, Ben Karel, Alan Franzoni, Yousry
|
||||
Abdallah, Whitney Young, Vinay Sajip, Tom Towle, Tim Ottinger,
|
||||
Thomas Schraitle, Tero Saarni, Ted Mielczarek, Svetoslav
|
||||
Agafonkin, Shaun Rowland, Rocco Rutte, Polo-Francois Poli,
|
||||
Philip Jenvey, Petr Tesałék, Peter R. Annema, Paul Bonser,
|
||||
Olivier Scherler, Olivier Fournier, Nick Parker, Nick Fabry,
|
||||
Nicholas Guarracino, Mike Driscoll, Mike Coleman, Mietek Bák,
|
||||
Michael Maloney, László Nagy, Kent Johnson, Julio Nobrega, Jord
|
||||
Fita, Jonathan March, Jonas Nockert, Jim Tittsler, Jeduan
|
||||
Cornejo Legorreta, Jan Larres, James Murphy, Henri Wiechers,
|
||||
Hagen Möbius, Gábor Farkas, Fabien Engels, Evert Rol, Evan
|
||||
Willms, Eduardo Felipe Castegnaro, Dennis Decker Jensen, Deniz
|
||||
Dogan, David Smith, Daed Lee, Christine Slotty, Charles Merriam,
|
||||
Guillaume Catto, Brian Dorsey, Bob Nystrom, Benoit Boissinot,
|
||||
Avi Rosenschein, Andrew Watts, Andrew Donkin, Alexey Rodriguez,
|
||||
Ahmed Chaudhary.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id298254">Conventions Used in This Book</h2></div></div></div><p id="x_73a"><a name="x_73a"></a>The following typographical conventions are used in this
|
||||
book:</p><div class="variablelist"><dl><dt><span class="term">Italic</span></dt><dd><p id="x_73b"><a name="x_73b"></a>Indicates new terms, URLs, email addresses, filenames,
|
||||
and file extensions.</p></dd><dt><span class="term"><code class="literal">Constant width</code></span></dt><dd><p id="x_73c"><a name="x_73c"></a>Used for program listings, as well as within
|
||||
paragraphs to refer to program elements such as variable
|
||||
or function names, databases, data types, environment
|
||||
variables, statements, and keywords.</p></dd><dt><span class="term"><strong class="userinput"><code>Constant width bold</code></strong></span></dt><dd><p id="x_73d"><a name="x_73d"></a>Shows commands or other text that should be typed
|
||||
literally by the user.</p></dd><dt><span class="term"><em class="replaceable"><code>Constant width italic</code></em></span></dt><dd><p id="x_73e"><a name="x_73e"></a>Shows text that should be replaced with user-supplied
|
||||
values or by values determined by context.</p></dd></dl></div><div class="tip"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="/support/figs/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p id="x_73f"><a name="x_73f"></a>This icon signifies a tip, suggestion, or general
|
||||
note.</p></td></tr></table></div><div class="caution"><table border="0" summary="Caution"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="/support/figs/caution.png"></td><th align="left">Caution</th></tr><tr><td align="left" valign="top"><p id="x_740"><a name="x_740"></a>This icon indicates a warning or caution.</p></td></tr></table></div></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id341884">Using Code Examples</h2></div></div></div><p id="x_741"><a name="x_741"></a>This book is here to help you get your job done. In general,
|
||||
you may use the code in this book in your programs and
|
||||
documentation. You do not need to contact us for permission
|
||||
unless you’re reproducing a significant portion of the code. For
|
||||
example, writing a program that uses several chunks of code from
|
||||
this book does not require permission. Selling or distributing a
|
||||
CD-ROM of examples from O’Reilly books does require permission.
|
||||
Answering a question by citing this book and quoting example
|
||||
code does not require permission. Incorporating a significant
|
||||
amount of example code from this book into your product’s
|
||||
documentation does require permission.</p><p id="x_742"><a name="x_742"></a>We appreciate, but do not require, attribution. An
|
||||
attribution usually includes the title, author, publisher, and
|
||||
ISBN. For example: “<span class="emphasis"><em>Book Title</em></span> by Some
|
||||
Author. Copyright 2008 O’Reilly Media, Inc.,
|
||||
978-0-596-xxxx-x.”</p><p id="x_743"><a name="x_743"></a>If you feel your use of code examples falls outside fair use
|
||||
or the permission given above, feel free to contact us at
|
||||
<code class="email"><<a class="email" href="mailto:permissions@oreilly.com">permissions@oreilly.com</a>></code>.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id297605">Safari® Books Online</h2></div></div></div><div class="note"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="/support/figs/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p id="x_744"><a name="x_744"></a>When you see a Safari® Books Online icon on the cover of
|
||||
your favorite technology book, that means the book is
|
||||
available online through the O’Reilly Network Safari
|
||||
Bookshelf.</p></td></tr></table></div><p id="x_745"><a name="x_745"></a>Safari offers a solution that’s better than e-books. It’s a
|
||||
virtual library that lets you easily search thousands of top
|
||||
tech books, cut and paste code samples, download chapters, and
|
||||
find quick answers when you need the most accurate, current
|
||||
information. Try it for free at <a class="ulink" href="http://my.safaribooksonline.com/?portal=oreilly" target="_top">http://my.safaribooksonline.com</a>.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="id297646">How to Contact Us</h2></div></div></div><p id="x_746"><a name="x_746"></a>Please address comments and questions concerning this book
|
||||
to the publisher:</p><table class="simplelist" border="0" summary="Simple list"><tr><td>O’Reilly Media, Inc.</td></tr><tr><td>1005 Gravenstein Highway North</td></tr><tr><td>Sebastopol, CA 95472</td></tr><tr><td>800-998-9938 (in the United States or Canada)</td></tr><tr><td>707-829-0515 (international or local)</td></tr><tr><td>707 829-0104 (fax)</td></tr></table><p id="x_747"><a name="x_747"></a>We have a web page for this book, where we list errata,
|
||||
examples, and any additional information. You can access this
|
||||
page at:</p><table class="simplelist" border="0" summary="Simple list"><tr><td><a class="ulink" href="http://www.oreilly.com/catalog/<catalog%20%20%20%20page>" target="_top">http://www.oreilly.com/catalog/<catalog page></a></td></tr></table><p class="remark"><i><span class="remark">Don’t forget to update the <url> attribute,
|
||||
too.</span></i></p><p id="x_748"><a name="x_748"></a>To comment or ask technical questions about this book, send
|
||||
email to:</p><table class="simplelist" border="0" summary="Simple list"><tr><td><code class="email"><<a class="email" href="mailto:bookquestions@oreilly.com">bookquestions@oreilly.com</a>></code></td></tr></table><p id="x_749"><a name="x_749"></a>For more information about our books, conferences, Resource
|
||||
Centers, and the O’Reilly Network, see our web site at:</p><table class="simplelist" border="0" summary="Simple list"><tr><td><a class="ulink" href="http://www.oreilly.com" target="_top">http://www.oreilly.com</a></td></tr></table></div></div><div class="hgfooter"><p><img src="/support/figs/rss.png"> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p><p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan.
|
||||
Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p></div><div class="navfooter"><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="how-did-we-get-here.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Mercurial: The Definitive Guide </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 1. How did we get here?</td></tr></table></div><script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-1805907-5");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}</script></body></html>
|
Loading…
Reference in a new issue