Mercurial > hgbook
diff en/ch13-hgext.xml @ 682:28b5a5befb08
Fold preface and intro into one
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Thu, 19 Mar 2009 20:54:12 -0700 |
parents | en/ch14-hgext.xml@8366882f67f2 |
children | c838b3975bc6 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/en/ch13-hgext.xml Thu Mar 19 20:54:12 2009 -0700 @@ -0,0 +1,554 @@ +<!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : --> + +<chapter id="chap:hgext"> + <?dbhtml filename="adding-functionality-with-extensions.html"?> + <title>Adding functionality with extensions</title> + + <para>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.</para> + + <para>However, Mercurial doesn't box you in with an inflexible + command set: you can add features to it as + <emphasis>extensions</emphasis> (sometimes known as + <emphasis>plugins</emphasis>). We've already discussed a few of + these extensions in earlier chapters.</para> + <itemizedlist> + <listitem><para>Section <xref linkend="sec:tour-merge:fetch"/> + covers the <literal role="hg-ext">fetch</literal> extension; + this combines pulling new changes and merging them with local + changes into a single command, <command + role="hg-ext-fetch">fetch</command>.</para> + </listitem> + <listitem><para>In chapter <xref linkend="chap:hook"/>, we covered + several extensions that are useful for hook-related + functionality: <literal role="hg-ext">acl</literal> adds + access control lists; <literal + role="hg-ext">bugzilla</literal> adds integration with the + Bugzilla bug tracking system; and <literal + role="hg-ext">notify</literal> sends notification emails on + new changes.</para> + </listitem> + <listitem><para>The Mercurial Queues patch management extension is + so invaluable that it merits two chapters and an appendix all + to itself. Chapter <xref linkend="chap:mq"/> covers the + basics; chapter <xref + linkend="chap:mq-collab"/> discusses advanced topics; + and appendix <xref linkend="chap:mqref"/> goes into detail on + each + command.</para> + </listitem></itemizedlist> + + <para>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.</para> + <itemizedlist> + <listitem><para>In section <xref linkend="sec:hgext:inotify"/>, + we'll discuss the possibility of <emphasis>huge</emphasis> + performance improvements using the <literal + role="hg-ext">inotify</literal> extension.</para> + </listitem></itemizedlist> + + <sect1 id="sec:hgext:inotify"> + <title>Improve performance with the <literal + role="hg-ext">inotify</literal> extension</title> + + <para>Are you interested in having some of the most common + Mercurial operations run as much as a hundred times faster? + Read on!</para> + + <para>Mercurial has great performance under normal circumstances. + For example, when you run the <command role="hg-cmd">hg + status</command> 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 <command + role="hg-cmd">hg diff</command> command uses the status + machinery to avoid doing an expensive comparison operation on + files that obviously haven't changed.</para> + + <para>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 <command role="hg-cmd">hg + status</command>, 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.</para> + + <para>To put a number on the magnitude of this effect, I created a + repository containing 150,000 managed files. I timed <command + role="hg-cmd">hg status</command> as taking ten seconds to + run, even when <emphasis>none</emphasis> of those files had been + modified.</para> + + <para>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 + <literal>inotify</literal>.</para> + + <para>Mercurial's <literal role="hg-ext">inotify</literal> + extension talks to the kernel's <literal>inotify</literal> + component to optimise <command role="hg-cmd">hg status</command> + commands. The extension has two components. A daemon sits in + the background and receives notifications from the + <literal>inotify</literal> subsystem. It also listens for + connections from a regular Mercurial command. The extension + modifies Mercurial's behaviour 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.</para> + + <para>Recall the ten seconds that I measured plain Mercurial as + taking to run <command role="hg-cmd">hg status</command> on a + 150,000 file repository. With the <literal + role="hg-ext">inotify</literal> extension enabled, the time + dropped to 0.1 seconds, a factor of <emphasis>one + hundred</emphasis> faster.</para> + + <para>Before we continue, please pay attention to some + caveats.</para> + <itemizedlist> + <listitem><para>The <literal role="hg-ext">inotify</literal> + extension is Linux-specific. Because it interfaces directly + to the Linux kernel's <literal>inotify</literal> subsystem, + it does not work on other operating systems.</para> + </listitem> + <listitem><para>It should work on any Linux distribution that + was released after early 2005. Older distributions are + likely to have a kernel that lacks + <literal>inotify</literal>, or a version of + <literal>glibc</literal> that does not have the necessary + interfacing support.</para> + </listitem> + <listitem><para>Not all filesystems are suitable for use with + the <literal role="hg-ext">inotify</literal> 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 <literal>inotify</literal> system has no way of + knowing about changes made on another system. Most local + filesystems (e.g. ext3, XFS, ReiserFS) should work + fine.</para> + </listitem></itemizedlist> + + <para>The <literal role="hg-ext">inotify</literal> 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!</para> + + <para>The extension currently comes in two parts: a set of patches + to the Mercurial source code, and a library of Python bindings + to the <literal>inotify</literal> subsystem.</para> + <note> + <para> There are <emphasis>two</emphasis> Python + <literal>inotify</literal> binding libraries. One of them is + called <literal>pyinotify</literal>, and is packaged by some + Linux distributions as <literal>python-inotify</literal>. + This is <emphasis>not</emphasis> the one you'll need, as it is + too buggy and inefficient to be practical.</para> + </note> + <para>To get going, it's best to already have a functioning copy + of Mercurial installed.</para> + <note> + <para> If you follow the instructions below, you'll be + <emphasis>replacing</emphasis> and overwriting any existing + installation of Mercurial that you might already have, using + the latest <quote>bleeding edge</quote> Mercurial code. Don't + say you weren't warned!</para> + </note> + <orderedlist> + <listitem><para>Clone the Python <literal>inotify</literal> + binding repository. Build and install it.</para> + <programlisting>hg clone http://hg.kublai.com/python/inotify +cd inotify +python setup.py build --force +sudo python setup.py install --skip-build</programlisting> + </listitem> + <listitem><para>Clone the <filename + class="directory">crew</filename> Mercurial repository. + Clone the <literal role="hg-ext">inotify</literal> patch + repository so that Mercurial Queues will be able to apply + patches to your cope of the <filename + class="directory">crew</filename> repository.</para> + <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</programlisting> + </listitem> + <listitem><para>Make sure that you have the Mercurial Queues + extension, <literal role="hg-ext">mq</literal>, enabled. If + you've never used MQ, read section <xref + linkend="sec:mq:start"/> to get started + quickly.</para> + </listitem> + <listitem><para>Go into the <filename + class="directory">inotify</filename> repo, and apply all + of the <literal role="hg-ext">inotify</literal> patches + using the <option role="hg-ext-mq-cmd-qpush-opt">hg + -a</option> option to the <command + role="hg-ext-mq">qpush</command> command.</para> + <programlisting>cd inotify +hg qpush -a</programlisting> + </listitem> + <listitem><para> If you get an error message from <command + role="hg-ext-mq">qpush</command>, you should not continue. + Instead, ask for help.</para> + </listitem> + <listitem><para>Build and install the patched version of + Mercurial.</para> + <programlisting>python setup.py build --force +sudo python setup.py install --skip-build</programlisting> + </listitem> + </orderedlist> + <para>Once you've build a suitably patched version of Mercurial, + all you need to do to enable the <literal + role="hg-ext">inotify</literal> extension is add an entry to + your <filename role="special">~/.hgrc</filename>.</para> + <programlisting>[extensions] inotify =</programlisting> + <para>When the <literal role="hg-ext">inotify</literal> 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.</para> + + <para>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 <literal role="hg-ext">inotify</literal> + extension and run a few commands in different repositories, + you'll thus see a few <literal>hg</literal> processes sitting + around, waiting for updates from the kernel and queries from + Mercurial.</para> + + <para>The first time you run a Mercurial command in a repository + when you have the <literal role="hg-ext">inotify</literal> + 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, <emphasis>every</emphasis> 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 <literal role="hg-ext">inotify</literal> daemon makes + status operations almost instantaneous on repositories of all + sizes!</para> + + <para>If you like, you can manually start a status daemon using + the <command role="hg-ext-inotify">inserve</command> command. + This gives you slightly finer control over how the daemon ought + to run. This command will of course only be available when the + <literal role="hg-ext">inotify</literal> extension is + enabled.</para> + + <para>When you're using the <literal + role="hg-ext">inotify</literal> extension, you should notice + <emphasis>no difference at all</emphasis> in Mercurial's + behaviour, 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.</para> + + </sect1> + <sect1 id="sec:hgext:extdiff"> + <title>Flexible diff support with the <literal + role="hg-ext">extdiff</literal> extension</title> + + <para>Mercurial's built-in <command role="hg-cmd">hg + diff</command> command outputs plaintext unified diffs.</para> + + &interaction.extdiff.diff; + + <para>If you would like to use an external tool to display + modifications, you'll want to use the <literal + role="hg-ext">extdiff</literal> extension. This will let you + use, for example, a graphical diff tool.</para> + + <para>The <literal role="hg-ext">extdiff</literal> extension is + bundled with Mercurial, so it's easy to set up. In the <literal + role="rc-extensions">extensions</literal> section of your + <filename role="special">~/.hgrc</filename>, simply add a + one-line entry to enable the extension.</para> + <programlisting>[extensions] +extdiff =</programlisting> + <para>This introduces a command named <command + role="hg-ext-extdiff">extdiff</command>, which by default uses + your system's <command>diff</command> command to generate a + unified diff in the same form as the built-in <command + role="hg-cmd">hg diff</command> command.</para> + + &interaction.extdiff.extdiff; + + <para>The result won't be exactly the same as with the built-in + <command role="hg-cmd">hg diff</command> variations, because the + output of <command>diff</command> varies from one system to + another, even when passed the same options.</para> + + <para>As the <quote><literal>making snapshot</literal></quote> + lines of output above imply, the <command + role="hg-ext-extdiff">extdiff</command> 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 <command + role="hg-ext-extdiff">extdiff</command> 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.</para> + + <para>Snapshot directory names have the same base name as your + repository. If your repository path is <filename + class="directory">/quux/bar/foo</filename>, then <filename + class="directory">foo</filename> 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 <literal>a631aca1083f</literal>, the directory will be + named <filename class="directory">foo.a631aca1083f</filename>. + A snapshot of the working directory won't have a changeset ID + appended, so it would just be <filename + class="directory">foo</filename> in this example. To see what + this looks like in practice, look again at the <command + role="hg-ext-extdiff">extdiff</command> example above. Notice + that the diff has the snapshot directory names embedded in its + header.</para> + + <para>The <command role="hg-ext-extdiff">extdiff</command> command + accepts two important options. The <option + role="hg-ext-extdiff-cmd-extdiff-opt">hg -p</option> option + lets you choose a program to view differences with, instead of + <command>diff</command>. With the <option + role="hg-ext-extdiff-cmd-extdiff-opt">hg -o</option> option, + you can change the options that <command + role="hg-ext-extdiff">extdiff</command> passes to the program + (by default, these options are + <quote><literal>-Npru</literal></quote>, which only make sense + if you're running <command>diff</command>). In other respects, + the <command role="hg-ext-extdiff">extdiff</command> command + acts similarly to the built-in <command role="hg-cmd">hg + diff</command> command: you use the same option names, syntax, + and arguments to specify the revisions you want, the files you + want, and so on.</para> + + <para>As an example, here's how to run the normal system + <command>diff</command> command, getting it to generate context + diffs (using the <option role="cmd-opt-diff">-c</option> option) + instead of unified diffs, and five lines of context instead of + the default three (passing <literal>5</literal> as the argument + to the <option role="cmd-opt-diff">-C</option> option).</para> + + &interaction.extdiff.extdiff-ctx; + + <para>Launching a visual diff tool is just as easy. Here's how to + launch the <command>kdiff3</command> viewer.</para> + <programlisting>hg extdiff -p kdiff3 -o</programlisting> + + <para>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 <literal + role="hg-ext">mq</literal> extension and the + <command>interdiff</command> command, see section <xref + linkend="mq-collab:tips:interdiff"/>.</para> + + <sect2> + <title>Defining command aliases</title> + + <para>It can be cumbersome to remember the options to both the + <command role="hg-ext-extdiff">extdiff</command> command and + the diff viewer you want to use, so the <literal + role="hg-ext">extdiff</literal> extension lets you define + <emphasis>new</emphasis> commands that will invoke your diff + viewer with exactly the right options.</para> + + <para>All you need to do is edit your <filename + role="special">~/.hgrc</filename>, and add a section named + <literal role="rc-extdiff">extdiff</literal>. Inside this + section, you can define multiple commands. Here's how to add + a <literal>kdiff3</literal> command. Once you've defined + this, you can type <quote><literal>hg kdiff3</literal></quote> + and the <literal role="hg-ext">extdiff</literal> extension + will run <command>kdiff3</command> for you.</para> + <programlisting>[extdiff] +cmd.kdiff3 =</programlisting> + <para>If you leave the right hand side of the definition empty, + as above, the <literal role="hg-ext">extdiff</literal> + 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 + <quote><literal>hg wibble</literal></quote>, which runs + <command>kdiff3</command>.</para> + <programlisting>[extdiff] + cmd.wibble = kdiff3</programlisting> + + <para>You can also specify the default options that you want to + invoke your diff viewing program with. The prefix to use is + <quote><literal>opts.</literal></quote>, followed by the name + of the command to which the options apply. This example + defines a <quote><literal>hg vimdiff</literal></quote> command + that runs the <command>vim</command> editor's + <literal>DirDiff</literal> extension.</para> + <programlisting>[extdiff] + cmd.vimdiff = vim +opts.vimdiff = -f '+next' '+execute "DirDiff" argv(0) argv(1)'</programlisting> + + </sect2> + </sect1> + <sect1 id="sec:hgext:transplant"> + <title>Cherrypicking changes with the <literal + role="hg-ext">transplant</literal> extension</title> + + <para>Need to have a long chat with Brendan about this.</para> + + </sect1> + <sect1 id="sec:hgext:patchbomb"> + <title>Send changes via email with the <literal + role="hg-ext">patchbomb</literal> extension</title> + + <para>Many projects have a culture of <quote>change + review</quote>, 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.</para> + + <para>Mercurial makes it easy to send changes over email for + review or application, via its <literal + role="hg-ext">patchbomb</literal> 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 <quote>bombing</quote> the + recipient's inbox, hence <quote>patchbomb</quote>.</para> + + <para>As usual, the basic configuration of the <literal + role="hg-ext">patchbomb</literal> extension takes just one or + two lines in your <filename role="special"> + /.hgrc</filename>.</para> + <programlisting>[extensions] +patchbomb =</programlisting> + <para>Once you've enabled the extension, you will have a new + command available, named <command + role="hg-ext-patchbomb">email</command>.</para> + + <para>The safest and best way to invoke the <command + role="hg-ext-patchbomb">email</command> command is to + <emphasis>always</emphasis> run it first with the <option + role="hg-ext-patchbomb-cmd-email-opt">hg -n</option> option. + This will show you what the command <emphasis>would</emphasis> + 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 <option + role="hg-ext-patchbomb-cmd-email-opt">hg -n</option> option + removed.</para> + + <para>The <command role="hg-ext-patchbomb">email</command> command + accepts the same kind of revision syntax as every other + Mercurial command. For example, this command will send every + revision between 7 and <literal>tip</literal>, inclusive.</para> + <programlisting>hg email -n 7:tip</programlisting> + <para>You can also specify a <emphasis>repository</emphasis> to + compare with. If you provide a repository but no revisions, the + <command role="hg-ext-patchbomb">email</command> 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 <option + role="hg-ext-patchbomb-cmd-email-opt">hg -b</option> option), + this will constrain the revisions sent.</para> + + <para>It's perfectly safe to run the <command + role="hg-ext-patchbomb">email</command> 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 + <literal>readline</literal>-style editing capabilities when + entering those headers, too, which is useful.)</para> + + <para>When you are sending just one revision, the <command + role="hg-ext-patchbomb">email</command> command will by + default use the first line of the changeset description as the + subject of the single email message it sends.</para> + + <para>If you send multiple revisions, the <command + role="hg-ext-patchbomb">email</command> 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.</para> + + <sect2> + <title>Changing the behaviour of patchbombs</title> + + <para>Not every project has exactly the same conventions for + sending changes in email; the <literal + role="hg-ext">patchbomb</literal> extension tries to + accommodate a number of variations through command line + options.</para> + <itemizedlist> + <listitem><para>You can write a subject for the introductory + message on the command line using the <option + role="hg-ext-patchbomb-cmd-email-opt">hg -s</option> + option. This takes one argument, the text of the subject + to use.</para> + </listitem> + <listitem><para>To change the email address from which the + messages originate, use the <option + role="hg-ext-patchbomb-cmd-email-opt">hg -f</option> + option. This takes one argument, the email address to + use.</para> + </listitem> + <listitem><para>The default behaviour is to send unified diffs + (see section <xref linkend="sec:mq:patch"/> for a + description of the + format), one per message. You can send a binary bundle + instead with the <option + role="hg-ext-patchbomb-cmd-email-opt">hg -b</option> + option.</para> + </listitem> + <listitem><para>Unified diffs are normally prefaced with a + metadata header. You can omit this, and send unadorned + diffs, with the <option + role="hg-ext-patchbomb-cmd-email-opt">hg + --plain</option> option.</para> + </listitem> + <listitem><para>Diffs are normally sent <quote>inline</quote>, + 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 <option + role="hg-ext-patchbomb-cmd-email-opt">hg -a</option> + option.</para> + </listitem> + <listitem><para>Instead of sending mail messages, you can + write them to an <literal>mbox</literal>-format mail + folder using the <option + role="hg-ext-patchbomb-cmd-email-opt">hg -m</option> + option. That option takes one argument, the name of the + file to write to.</para> + </listitem> + <listitem><para>If you would like to add a + <command>diffstat</command>-format summary to each patch, + and one to the introductory message, use the <option + role="hg-ext-patchbomb-cmd-email-opt">hg -d</option> + option. The <command>diffstat</command> 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.</para> + </listitem></itemizedlist> + + </sect2> + </sect1> +</chapter> + +<!-- +local variables: +sgml-parent-document: ("00book.xml" "book" "chapter") +end: +-->