comparison en/ch13-hgext.xml @ 749:7e7c47481e4f

Oops, this is the real merge for my hg's oddity
author Dongsheng Song <dongsheng.song@gmail.com>
date Fri, 20 Mar 2009 16:43:35 +0800
parents en/ch14-hgext.xml@d0160b0b1a9e
children 1c13ed2130a7
comparison
equal deleted inserted replaced
748:d13c7c706a58 749:7e7c47481e4f
1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
2
3 <chapter id="chap.hgext">
4 <?dbhtml filename="adding-functionality-with-extensions.html"?>
5 <title>Adding functionality with extensions</title>
6
7 <para>While the core of Mercurial is quite complete from a
8 functionality standpoint, it's deliberately shorn of fancy
9 features. This approach of preserving simplicity keeps the
10 software easy to deal with for both maintainers and users.</para>
11
12 <para>However, Mercurial doesn't box you in with an inflexible
13 command set: you can add features to it as
14 <emphasis>extensions</emphasis> (sometimes known as
15 <emphasis>plugins</emphasis>). We've already discussed a few of
16 these extensions in earlier chapters.</para>
17 <itemizedlist>
18 <listitem><para>Section <xref linkend="sec.tour-merge.fetch"/>
19 covers the <literal role="hg-ext">fetch</literal> extension;
20 this combines pulling new changes and merging them with local
21 changes into a single command, <command
22 role="hg-ext-fetch">fetch</command>.</para>
23 </listitem>
24 <listitem><para>In chapter <xref linkend="chap.hook"/>, we covered
25 several extensions that are useful for hook-related
26 functionality: <literal role="hg-ext">acl</literal> adds
27 access control lists; <literal
28 role="hg-ext">bugzilla</literal> adds integration with the
29 Bugzilla bug tracking system; and <literal
30 role="hg-ext">notify</literal> sends notification emails on
31 new changes.</para>
32 </listitem>
33 <listitem><para>The Mercurial Queues patch management extension is
34 so invaluable that it merits two chapters and an appendix all
35 to itself. Chapter <xref linkend="chap.mq"/> covers the
36 basics; chapter <xref
37 linkend="chap.mq-collab"/> discusses advanced topics;
38 and appendix <xref linkend="chap.mqref"/> goes into detail on
39 each
40 command.</para>
41 </listitem></itemizedlist>
42
43 <para>In this chapter, we'll cover some of the other extensions that
44 are available for Mercurial, and briefly touch on some of the
45 machinery you'll need to know about if you want to write an
46 extension of your own.</para>
47 <itemizedlist>
48 <listitem><para>In section <xref linkend="sec.hgext.inotify"/>,
49 we'll discuss the possibility of <emphasis>huge</emphasis>
50 performance improvements using the <literal
51 role="hg-ext">inotify</literal> extension.</para>
52 </listitem></itemizedlist>
53
54 <sect1 id="sec.hgext.inotify">
55 <title>Improve performance with the <literal
56 role="hg-ext">inotify</literal> extension</title>
57
58 <para>Are you interested in having some of the most common
59 Mercurial operations run as much as a hundred times faster?
60 Read on!</para>
61
62 <para>Mercurial has great performance under normal circumstances.
63 For example, when you run the <command role="hg-cmd">hg
64 status</command> command, Mercurial has to scan almost every
65 directory and file in your repository so that it can display
66 file status. Many other Mercurial commands need to do the same
67 work behind the scenes; for example, the <command
68 role="hg-cmd">hg diff</command> command uses the status
69 machinery to avoid doing an expensive comparison operation on
70 files that obviously haven't changed.</para>
71
72 <para>Because obtaining file status is crucial to good
73 performance, the authors of Mercurial have optimised this code
74 to within an inch of its life. However, there's no avoiding the
75 fact that when you run <command role="hg-cmd">hg
76 status</command>, Mercurial is going to have to perform at
77 least one expensive system call for each managed file to
78 determine whether it's changed since the last time Mercurial
79 checked. For a sufficiently large repository, this can take a
80 long time.</para>
81
82 <para>To put a number on the magnitude of this effect, I created a
83 repository containing 150,000 managed files. I timed <command
84 role="hg-cmd">hg status</command> as taking ten seconds to
85 run, even when <emphasis>none</emphasis> of those files had been
86 modified.</para>
87
88 <para>Many modern operating systems contain a file notification
89 facility. If a program signs up to an appropriate service, the
90 operating system will notify it every time a file of interest is
91 created, modified, or deleted. On Linux systems, the kernel
92 component that does this is called
93 <literal>inotify</literal>.</para>
94
95 <para>Mercurial's <literal role="hg-ext">inotify</literal>
96 extension talks to the kernel's <literal>inotify</literal>
97 component to optimise <command role="hg-cmd">hg status</command>
98 commands. The extension has two components. A daemon sits in
99 the background and receives notifications from the
100 <literal>inotify</literal> subsystem. It also listens for
101 connections from a regular Mercurial command. The extension
102 modifies Mercurial's behaviour so that instead of scanning the
103 filesystem, it queries the daemon. Since the daemon has perfect
104 information about the state of the repository, it can respond
105 with a result instantaneously, avoiding the need to scan every
106 directory and file in the repository.</para>
107
108 <para>Recall the ten seconds that I measured plain Mercurial as
109 taking to run <command role="hg-cmd">hg status</command> on a
110 150,000 file repository. With the <literal
111 role="hg-ext">inotify</literal> extension enabled, the time
112 dropped to 0.1 seconds, a factor of <emphasis>one
113 hundred</emphasis> faster.</para>
114
115 <para>Before we continue, please pay attention to some
116 caveats.</para>
117 <itemizedlist>
118 <listitem><para>The <literal role="hg-ext">inotify</literal>
119 extension is Linux-specific. Because it interfaces directly
120 to the Linux kernel's <literal>inotify</literal> subsystem,
121 it does not work on other operating systems.</para>
122 </listitem>
123 <listitem><para>It should work on any Linux distribution that
124 was released after early 2005. Older distributions are
125 likely to have a kernel that lacks
126 <literal>inotify</literal>, or a version of
127 <literal>glibc</literal> that does not have the necessary
128 interfacing support.</para>
129 </listitem>
130 <listitem><para>Not all filesystems are suitable for use with
131 the <literal role="hg-ext">inotify</literal> extension.
132 Network filesystems such as NFS are a non-starter, for
133 example, particularly if you're running Mercurial on several
134 systems, all mounting the same network filesystem. The
135 kernel's <literal>inotify</literal> system has no way of
136 knowing about changes made on another system. Most local
137 filesystems (e.g. ext3, XFS, ReiserFS) should work
138 fine.</para>
139 </listitem></itemizedlist>
140
141 <para>The <literal role="hg-ext">inotify</literal> extension is
142 not yet shipped with Mercurial as of May 2007, so it's a little
143 more involved to set up than other extensions. But the
144 performance improvement is worth it!</para>
145
146 <para>The extension currently comes in two parts: a set of patches
147 to the Mercurial source code, and a library of Python bindings
148 to the <literal>inotify</literal> subsystem.</para>
149 <note>
150 <para> There are <emphasis>two</emphasis> Python
151 <literal>inotify</literal> binding libraries. One of them is
152 called <literal>pyinotify</literal>, and is packaged by some
153 Linux distributions as <literal>python-inotify</literal>.
154 This is <emphasis>not</emphasis> the one you'll need, as it is
155 too buggy and inefficient to be practical.</para>
156 </note>
157 <para>To get going, it's best to already have a functioning copy
158 of Mercurial installed.</para>
159 <note>
160 <para> If you follow the instructions below, you'll be
161 <emphasis>replacing</emphasis> and overwriting any existing
162 installation of Mercurial that you might already have, using
163 the latest <quote>bleeding edge</quote> Mercurial code. Don't
164 say you weren't warned!</para>
165 </note>
166 <orderedlist>
167 <listitem><para>Clone the Python <literal>inotify</literal>
168 binding repository. Build and install it.</para>
169 <programlisting>hg clone http://hg.kublai.com/python/inotify
170 cd inotify
171 python setup.py build --force
172 sudo python setup.py install --skip-build</programlisting>
173 </listitem>
174 <listitem><para>Clone the <filename
175 class="directory">crew</filename> Mercurial repository.
176 Clone the <literal role="hg-ext">inotify</literal> patch
177 repository so that Mercurial Queues will be able to apply
178 patches to your cope of the <filename
179 class="directory">crew</filename> repository.</para>
180 <programlisting>hg clone http://hg.intevation.org/mercurial/crew
181 hg clone crew inotify
182 hg clone http://hg.kublai.com/mercurial/patches/inotify inotify/.hg/patches</programlisting>
183 </listitem>
184 <listitem><para>Make sure that you have the Mercurial Queues
185 extension, <literal role="hg-ext">mq</literal>, enabled. If
186 you've never used MQ, read section <xref
187 linkend="sec.mq.start"/> to get started
188 quickly.</para>
189 </listitem>
190 <listitem><para>Go into the <filename
191 class="directory">inotify</filename> repo, and apply all
192 of the <literal role="hg-ext">inotify</literal> patches
193 using the <option role="hg-ext-mq-cmd-qpush-opt">hg
194 -a</option> option to the <command
195 role="hg-ext-mq">qpush</command> command.</para>
196 <programlisting>cd inotify
197 hg qpush -a</programlisting>
198 </listitem>
199 <listitem><para> If you get an error message from <command
200 role="hg-ext-mq">qpush</command>, you should not continue.
201 Instead, ask for help.</para>
202 </listitem>
203 <listitem><para>Build and install the patched version of
204 Mercurial.</para>
205 <programlisting>python setup.py build --force
206 sudo python setup.py install --skip-build</programlisting>
207 </listitem>
208 </orderedlist>
209 <para>Once you've build a suitably patched version of Mercurial,
210 all you need to do to enable the <literal
211 role="hg-ext">inotify</literal> extension is add an entry to
212 your <filename role="special">~/.hgrc</filename>.</para>
213 <programlisting>[extensions] inotify =</programlisting>
214 <para>When the <literal role="hg-ext">inotify</literal> extension
215 is enabled, Mercurial will automatically and transparently start
216 the status daemon the first time you run a command that needs
217 status in a repository. It runs one status daemon per
218 repository.</para>
219
220 <para>The status daemon is started silently, and runs in the
221 background. If you look at a list of running processes after
222 you've enabled the <literal role="hg-ext">inotify</literal>
223 extension and run a few commands in different repositories,
224 you'll thus see a few <literal>hg</literal> processes sitting
225 around, waiting for updates from the kernel and queries from
226 Mercurial.</para>
227
228 <para>The first time you run a Mercurial command in a repository
229 when you have the <literal role="hg-ext">inotify</literal>
230 extension enabled, it will run with about the same performance
231 as a normal Mercurial command. This is because the status
232 daemon needs to perform a normal status scan so that it has a
233 baseline against which to apply later updates from the kernel.
234 However, <emphasis>every</emphasis> subsequent command that does
235 any kind of status check should be noticeably faster on
236 repositories of even fairly modest size. Better yet, the bigger
237 your repository is, the greater a performance advantage you'll
238 see. The <literal role="hg-ext">inotify</literal> daemon makes
239 status operations almost instantaneous on repositories of all
240 sizes!</para>
241
242 <para>If you like, you can manually start a status daemon using
243 the <command role="hg-ext-inotify">inserve</command> command.
244 This gives you slightly finer control over how the daemon ought
245 to run. This command will of course only be available when the
246 <literal role="hg-ext">inotify</literal> extension is
247 enabled.</para>
248
249 <para>When you're using the <literal
250 role="hg-ext">inotify</literal> extension, you should notice
251 <emphasis>no difference at all</emphasis> in Mercurial's
252 behaviour, with the sole exception of status-related commands
253 running a whole lot faster than they used to. You should
254 specifically expect that commands will not print different
255 output; neither should they give different results. If either of
256 these situations occurs, please report a bug.</para>
257
258 </sect1>
259 <sect1 id="sec.hgext.extdiff">
260 <title>Flexible diff support with the <literal
261 role="hg-ext">extdiff</literal> extension</title>
262
263 <para>Mercurial's built-in <command role="hg-cmd">hg
264 diff</command> command outputs plaintext unified diffs.</para>
265
266 &interaction.extdiff.diff;
267
268 <para>If you would like to use an external tool to display
269 modifications, you'll want to use the <literal
270 role="hg-ext">extdiff</literal> extension. This will let you
271 use, for example, a graphical diff tool.</para>
272
273 <para>The <literal role="hg-ext">extdiff</literal> extension is
274 bundled with Mercurial, so it's easy to set up. In the <literal
275 role="rc-extensions">extensions</literal> section of your
276 <filename role="special">~/.hgrc</filename>, simply add a
277 one-line entry to enable the extension.</para>
278 <programlisting>[extensions]
279 extdiff =</programlisting>
280 <para>This introduces a command named <command
281 role="hg-ext-extdiff">extdiff</command>, which by default uses
282 your system's <command>diff</command> command to generate a
283 unified diff in the same form as the built-in <command
284 role="hg-cmd">hg diff</command> command.</para>
285
286 &interaction.extdiff.extdiff;
287
288 <para>The result won't be exactly the same as with the built-in
289 <command role="hg-cmd">hg diff</command> variations, because the
290 output of <command>diff</command> varies from one system to
291 another, even when passed the same options.</para>
292
293 <para>As the <quote><literal>making snapshot</literal></quote>
294 lines of output above imply, the <command
295 role="hg-ext-extdiff">extdiff</command> command works by
296 creating two snapshots of your source tree. The first snapshot
297 is of the source revision; the second, of the target revision or
298 working directory. The <command
299 role="hg-ext-extdiff">extdiff</command> command generates
300 these snapshots in a temporary directory, passes the name of
301 each directory to an external diff viewer, then deletes the
302 temporary directory. For efficiency, it only snapshots the
303 directories and files that have changed between the two
304 revisions.</para>
305
306 <para>Snapshot directory names have the same base name as your
307 repository. If your repository path is <filename
308 class="directory">/quux/bar/foo</filename>, then <filename
309 class="directory">foo</filename> will be the name of each
310 snapshot directory. Each snapshot directory name has its
311 changeset ID appended, if appropriate. If a snapshot is of
312 revision <literal>a631aca1083f</literal>, the directory will be
313 named <filename class="directory">foo.a631aca1083f</filename>.
314 A snapshot of the working directory won't have a changeset ID
315 appended, so it would just be <filename
316 class="directory">foo</filename> in this example. To see what
317 this looks like in practice, look again at the <command
318 role="hg-ext-extdiff">extdiff</command> example above. Notice
319 that the diff has the snapshot directory names embedded in its
320 header.</para>
321
322 <para>The <command role="hg-ext-extdiff">extdiff</command> command
323 accepts two important options. The <option
324 role="hg-ext-extdiff-cmd-extdiff-opt">hg -p</option> option
325 lets you choose a program to view differences with, instead of
326 <command>diff</command>. With the <option
327 role="hg-ext-extdiff-cmd-extdiff-opt">hg -o</option> option,
328 you can change the options that <command
329 role="hg-ext-extdiff">extdiff</command> passes to the program
330 (by default, these options are
331 <quote><literal>-Npru</literal></quote>, which only make sense
332 if you're running <command>diff</command>). In other respects,
333 the <command role="hg-ext-extdiff">extdiff</command> command
334 acts similarly to the built-in <command role="hg-cmd">hg
335 diff</command> command: you use the same option names, syntax,
336 and arguments to specify the revisions you want, the files you
337 want, and so on.</para>
338
339 <para>As an example, here's how to run the normal system
340 <command>diff</command> command, getting it to generate context
341 diffs (using the <option role="cmd-opt-diff">-c</option> option)
342 instead of unified diffs, and five lines of context instead of
343 the default three (passing <literal>5</literal> as the argument
344 to the <option role="cmd-opt-diff">-C</option> option).</para>
345
346 &interaction.extdiff.extdiff-ctx;
347
348 <para>Launching a visual diff tool is just as easy. Here's how to
349 launch the <command>kdiff3</command> viewer.</para>
350 <programlisting>hg extdiff -p kdiff3 -o</programlisting>
351
352 <para>If your diff viewing command can't deal with directories,
353 you can easily work around this with a little scripting. For an
354 example of such scripting in action with the <literal
355 role="hg-ext">mq</literal> extension and the
356 <command>interdiff</command> command, see section <xref
357 linkend="mq-collab.tips.interdiff"/>.</para>
358
359 <sect2>
360 <title>Defining command aliases</title>
361
362 <para>It can be cumbersome to remember the options to both the
363 <command role="hg-ext-extdiff">extdiff</command> command and
364 the diff viewer you want to use, so the <literal
365 role="hg-ext">extdiff</literal> extension lets you define
366 <emphasis>new</emphasis> commands that will invoke your diff
367 viewer with exactly the right options.</para>
368
369 <para>All you need to do is edit your <filename
370 role="special">~/.hgrc</filename>, and add a section named
371 <literal role="rc-extdiff">extdiff</literal>. Inside this
372 section, you can define multiple commands. Here's how to add
373 a <literal>kdiff3</literal> command. Once you've defined
374 this, you can type <quote><literal>hg kdiff3</literal></quote>
375 and the <literal role="hg-ext">extdiff</literal> extension
376 will run <command>kdiff3</command> for you.</para>
377 <programlisting>[extdiff]
378 cmd.kdiff3 =</programlisting>
379 <para>If you leave the right hand side of the definition empty,
380 as above, the <literal role="hg-ext">extdiff</literal>
381 extension uses the name of the command you defined as the name
382 of the external program to run. But these names don't have to
383 be the same. Here, we define a command named
384 <quote><literal>hg wibble</literal></quote>, which runs
385 <command>kdiff3</command>.</para>
386 <programlisting>[extdiff]
387 cmd.wibble = kdiff3</programlisting>
388
389 <para>You can also specify the default options that you want to
390 invoke your diff viewing program with. The prefix to use is
391 <quote><literal>opts.</literal></quote>, followed by the name
392 of the command to which the options apply. This example
393 defines a <quote><literal>hg vimdiff</literal></quote> command
394 that runs the <command>vim</command> editor's
395 <literal>DirDiff</literal> extension.</para>
396 <programlisting>[extdiff]
397 cmd.vimdiff = vim
398 opts.vimdiff = -f '+next' '+execute "DirDiff" argv(0) argv(1)'</programlisting>
399
400 </sect2>
401 </sect1>
402 <sect1 id="sec.hgext.transplant">
403 <title>Cherrypicking changes with the <literal
404 role="hg-ext">transplant</literal> extension</title>
405
406 <para>Need to have a long chat with Brendan about this.</para>
407
408 </sect1>
409 <sect1 id="sec.hgext.patchbomb">
410 <title>Send changes via email with the <literal
411 role="hg-ext">patchbomb</literal> extension</title>
412
413 <para>Many projects have a culture of <quote>change
414 review</quote>, in which people send their modifications to a
415 mailing list for others to read and comment on before they
416 commit the final version to a shared repository. Some projects
417 have people who act as gatekeepers; they apply changes from
418 other people to a repository to which those others don't have
419 access.</para>
420
421 <para>Mercurial makes it easy to send changes over email for
422 review or application, via its <literal
423 role="hg-ext">patchbomb</literal> extension. The extension is
424 so named because changes are formatted as patches, and it's usual
425 to send one changeset per email message. Sending a long series
426 of changes by email is thus much like <quote>bombing</quote> the
427 recipient's inbox, hence <quote>patchbomb</quote>.</para>
428
429 <para>As usual, the basic configuration of the <literal
430 role="hg-ext">patchbomb</literal> extension takes just one or
431 two lines in your <filename role="special">
432 /.hgrc</filename>.</para>
433 <programlisting>[extensions]
434 patchbomb =</programlisting>
435 <para>Once you've enabled the extension, you will have a new
436 command available, named <command
437 role="hg-ext-patchbomb">email</command>.</para>
438
439 <para>The safest and best way to invoke the <command
440 role="hg-ext-patchbomb">email</command> command is to
441 <emphasis>always</emphasis> run it first with the <option
442 role="hg-ext-patchbomb-cmd-email-opt">hg -n</option> option.
443 This will show you what the command <emphasis>would</emphasis>
444 send, without actually sending anything. Once you've had a
445 quick glance over the changes and verified that you are sending
446 the right ones, you can rerun the same command, with the <option
447 role="hg-ext-patchbomb-cmd-email-opt">hg -n</option> option
448 removed.</para>
449
450 <para>The <command role="hg-ext-patchbomb">email</command> command
451 accepts the same kind of revision syntax as every other
452 Mercurial command. For example, this command will send every
453 revision between 7 and <literal>tip</literal>, inclusive.</para>
454 <programlisting>hg email -n 7:tip</programlisting>
455 <para>You can also specify a <emphasis>repository</emphasis> to
456 compare with. If you provide a repository but no revisions, the
457 <command role="hg-ext-patchbomb">email</command> command will
458 send all revisions in the local repository that are not present
459 in the remote repository. If you additionally specify revisions
460 or a branch name (the latter using the <option
461 role="hg-ext-patchbomb-cmd-email-opt">hg -b</option> option),
462 this will constrain the revisions sent.</para>
463
464 <para>It's perfectly safe to run the <command
465 role="hg-ext-patchbomb">email</command> command without the
466 names of the people you want to send to: if you do this, it will
467 just prompt you for those values interactively. (If you're
468 using a Linux or Unix-like system, you should have enhanced
469 <literal>readline</literal>-style editing capabilities when
470 entering those headers, too, which is useful.)</para>
471
472 <para>When you are sending just one revision, the <command
473 role="hg-ext-patchbomb">email</command> command will by
474 default use the first line of the changeset description as the
475 subject of the single email message it sends.</para>
476
477 <para>If you send multiple revisions, the <command
478 role="hg-ext-patchbomb">email</command> command will usually
479 send one message per changeset. It will preface the series with
480 an introductory message, in which you should describe the
481 purpose of the series of changes you're sending.</para>
482
483 <sect2>
484 <title>Changing the behaviour of patchbombs</title>
485
486 <para>Not every project has exactly the same conventions for
487 sending changes in email; the <literal
488 role="hg-ext">patchbomb</literal> extension tries to
489 accommodate a number of variations through command line
490 options.</para>
491 <itemizedlist>
492 <listitem><para>You can write a subject for the introductory
493 message on the command line using the <option
494 role="hg-ext-patchbomb-cmd-email-opt">hg -s</option>
495 option. This takes one argument, the text of the subject
496 to use.</para>
497 </listitem>
498 <listitem><para>To change the email address from which the
499 messages originate, use the <option
500 role="hg-ext-patchbomb-cmd-email-opt">hg -f</option>
501 option. This takes one argument, the email address to
502 use.</para>
503 </listitem>
504 <listitem><para>The default behaviour is to send unified diffs
505 (see section <xref linkend="sec.mq.patch"/> for a
506 description of the
507 format), one per message. You can send a binary bundle
508 instead with the <option
509 role="hg-ext-patchbomb-cmd-email-opt">hg -b</option>
510 option.</para>
511 </listitem>
512 <listitem><para>Unified diffs are normally prefaced with a
513 metadata header. You can omit this, and send unadorned
514 diffs, with the <option
515 role="hg-ext-patchbomb-cmd-email-opt">hg
516 --plain</option> option.</para>
517 </listitem>
518 <listitem><para>Diffs are normally sent <quote>inline</quote>,
519 in the same body part as the description of a patch. This
520 makes it easiest for the largest number of readers to
521 quote and respond to parts of a diff, as some mail clients
522 will only quote the first MIME body part in a message. If
523 you'd prefer to send the description and the diff in
524 separate body parts, use the <option
525 role="hg-ext-patchbomb-cmd-email-opt">hg -a</option>
526 option.</para>
527 </listitem>
528 <listitem><para>Instead of sending mail messages, you can
529 write them to an <literal>mbox</literal>-format mail
530 folder using the <option
531 role="hg-ext-patchbomb-cmd-email-opt">hg -m</option>
532 option. That option takes one argument, the name of the
533 file to write to.</para>
534 </listitem>
535 <listitem><para>If you would like to add a
536 <command>diffstat</command>-format summary to each patch,
537 and one to the introductory message, use the <option
538 role="hg-ext-patchbomb-cmd-email-opt">hg -d</option>
539 option. The <command>diffstat</command> command displays
540 a table containing the name of each file patched, the
541 number of lines affected, and a histogram showing how much
542 each file is modified. This gives readers a qualitative
543 glance at how complex a patch is.</para>
544 </listitem></itemizedlist>
545
546 </sect2>
547 </sect1>
548 </chapter>
549
550 <!--
551 local variables:
552 sgml-parent-document: ("00book.xml" "book" "chapter")
553 end:
554 -->