hgbook

view en/ch14-hgext.xml @ 704:acf9dc5f088d

Add a skeletal preface.
author Bryan O'Sullivan <bos@serpentine.com>
date Thu May 07 21:07:35 2009 -0700 (2009-05-07)
parents en/ch13-hgext.xml@b338f5490029
children 527b86d55d4a
line source
1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
3 <chapter id="chap:hgext">
4 <?dbhtml filename="adding-functionality-with-extensions.html"?>
5 <title>Adding functionality with extensions</title>
7 <para id="x_4fe">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>
12 <para id="x_4ff">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 id="x_500"><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 id="x_501">In <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 id="x_502">The Mercurial Queues patch management extension is
34 so invaluable that it merits two chapters and an appendix all
35 to itself. <xref linkend="chap:mq"/> covers the
36 basics; <xref
37 linkend="chap:mq-collab"/> discusses advanced topics;
38 and <xref linkend="chap:mqref"/> goes into detail on
39 each
40 command.</para>
41 </listitem></itemizedlist>
43 <para id="x_503">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 id="x_504">In <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>
54 <sect1 id="sec:hgext:inotify">
55 <title>Improve performance with the <literal
56 role="hg-ext">inotify</literal> extension</title>
58 <para id="x_505">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>
62 <para id="x_506">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>
72 <para id="x_507">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>
82 <para id="x_508">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>
88 <para id="x_509">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>
95 <para id="x_50a">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 behavior 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>
108 <para id="x_50b">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>
115 <para id="x_50c">Before we continue, please pay attention to some
116 caveats.</para>
117 <itemizedlist>
118 <listitem><para id="x_50d">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 id="x_50e">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 id="x_50f">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>
141 <para id="x_510">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>
146 <para id="x_511">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 id="x_512"> 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 id="x_513">To get going, it's best to already have a functioning copy
158 of Mercurial installed.</para>
159 <note>
160 <para id="x_514"> 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 id="x_515">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 id="x_516">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 id="x_517">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 <xref
187 linkend="sec:mq:start"/> to get started
188 quickly.</para>
189 </listitem>
190 <listitem><para id="x_518">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 id="x_519"> 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 id="x_51a">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 id="x_51b">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 id="x_51c">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>
220 <para id="x_51d">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>
228 <para id="x_51e">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>
242 <para id="x_51f">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>
249 <para id="x_520">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 behavior, 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>
258 </sect1>
259 <sect1 id="sec:hgext:extdiff">
260 <title>Flexible diff support with the <literal
261 role="hg-ext">extdiff</literal> extension</title>
263 <para id="x_521">Mercurial's built-in <command role="hg-cmd">hg
264 diff</command> command outputs plaintext unified diffs.</para>
266 &interaction.extdiff.diff;
268 <para id="x_522">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>
273 <para id="x_523">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 id="x_524">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>
286 &interaction.extdiff.extdiff;
288 <para id="x_525">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>
293 <para id="x_526">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>
306 <para id="x_527">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>
322 <para id="x_528">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>
339 <para id="x_529">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>
346 &interaction.extdiff.extdiff-ctx;
348 <para id="x_52a">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>
352 <para id="x_52b">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 <xref
357 linkend="mq-collab:tips:interdiff"/>.</para>
359 <sect2>
360 <title>Defining command aliases</title>
362 <para id="x_52c">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>
369 <para id="x_52d">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 id="x_52e">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>
389 <para id="x_52f">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>
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>
406 <para id="x_530">Need to have a long chat with Brendan about this.</para>
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>
413 <para id="x_531">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>
421 <para id="x_532">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>
429 <para id="x_533">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 id="x_534">Once you've enabled the extension, you will have a new
436 command available, named <command
437 role="hg-ext-patchbomb">email</command>.</para>
439 <para id="x_535">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>
450 <para id="x_536">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 id="x_537">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>
464 <para id="x_538">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>
472 <para id="x_539">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>
477 <para id="x_53a">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>
483 <sect2>
484 <title>Changing the behavior of patchbombs</title>
486 <para id="x_53b">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 id="x_53c">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 id="x_53d">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 id="x_53e">The default behavior is to send unified diffs
505 (see <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 id="x_53f">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 id="x_540">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 id="x_541">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 id="x_542">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>
546 </sect2>
547 </sect1>
548 </chapter>
550 <!--
551 local variables:
552 sgml-parent-document: ("00book.xml" "book" "chapter")
553 end:
554 -->