Source

hgbook / en / ch14-hgext.xml

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
<!-- 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 id="x_4fe">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 id="x_4ff">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 id="x_500"><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 id="x_501">In <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 id="x_502">The Mercurial Queues patch management extension is
	so invaluable that it merits two chapters and an appendix all
	to itself. <xref linkend="chap:mq"/> covers the
	basics; <xref
	  linkend="chap:mq-collab"/> discusses advanced topics;
	and <xref linkend="chap:mqref"/> goes into detail on
	each
	command.</para>
    </listitem></itemizedlist>

  <para id="x_503">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 id="x_504">In <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 id="x_505">Are you interested in having some of the most common
      Mercurial operations run as much as a hundred times faster?
      Read on!</para>

    <para id="x_506">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 id="x_507">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 id="x_508">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 id="x_509">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 id="x_50a">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 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.</para>

    <para id="x_50b">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 id="x_50c">Before we continue, please pay attention to some
      caveats.</para>
    <itemizedlist>
      <listitem><para id="x_50d">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 id="x_50e">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 id="x_50f">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 id="x_510">The <literal role="hg-ext">inotify</literal> extension is
      shipped with Mercurial since 1.0.
      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 id="x_51c">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 id="x_51d">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 id="x_51e">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 id="x_51f">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 id="x_520">When you're using the <literal
	role="hg-ext">inotify</literal> extension, you should notice
      <emphasis>no difference at all</emphasis> 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.</para>

  </sect1>
  <sect1 id="sec:hgext:extdiff">
    <title>Flexible diff support with the <literal
	role="hg-ext">extdiff</literal> extension</title>

    <para id="x_521">Mercurial's built-in <command role="hg-cmd">hg
	diff</command> command outputs plaintext unified diffs.</para>

    &interaction.extdiff.diff;

    <para id="x_522">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 id="x_523">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 id="x_524">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 id="x_525">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 id="x_526">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 id="x_527">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 id="x_528">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 id="x_529">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 id="x_52a">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 id="x_52b">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 <xref
	linkend="mq-collab:tips:interdiff"/>.</para>

    <sect2>
      <title>Defining command aliases</title>

      <para id="x_52c">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 id="x_52d">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 id="x_52e">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 id="x_52f">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 id="x_530">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 id="x_531">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 id="x_532">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 id="x_533">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 id="x_534">Once you've enabled the extension, you will have a new
      command available, named <command
	role="hg-ext-patchbomb">email</command>.</para>

    <para id="x_535">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 id="x_536">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 id="x_537">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 id="x_538">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 id="x_539">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 id="x_53a">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 behavior of patchbombs</title>

      <para id="x_53b">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 id="x_53c">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 id="x_53d">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 id="x_53e">The default behavior is to send unified diffs
	    (see <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 id="x_53f">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 id="x_540">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 id="x_541">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 id="x_542">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:
-->
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.