hgbook

view en/ch03-tour-merge.xml @ 567:8fcd44708f41

Uncomment all the mangled interaction examples.
author Bryan O'Sullivan <bos@serpentine.com>
date Mon Mar 09 23:22:09 2009 -0700 (2009-03-09)
parents b90b024729f1
children 13513d2a128d
line source
1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
3 <chapter id="chap:tour-merge">
4 <title>A tour of Mercurial: merging work</title>
6 <para>We've now covered cloning a repository, making changes in a
7 repository, and pulling or pushing changes from one repository
8 into another. Our next step is <emphasis>merging</emphasis>
9 changes from separate repositories.</para>
11 <sect1>
12 <title>Merging streams of work</title>
14 <para>Merging is a fundamental part of working with a distributed
15 revision control tool.</para>
16 <itemizedlist>
17 <listitem><para>Alice and Bob each have a personal copy of a
18 repository for a project they're collaborating on. Alice
19 fixes a bug in her repository; Bob adds a new feature in
20 his. They want the shared repository to contain both the
21 bug fix and the new feature.</para>
22 </listitem>
23 <listitem><para>I frequently work on several different tasks for
24 a single project at once, each safely isolated in its own
25 repository. Working this way means that I often need to
26 merge one piece of my own work with another.</para>
27 </listitem></itemizedlist>
29 <para>Because merging is such a common thing to need to do,
30 Mercurial makes it easy. Let's walk through the process. We'll
31 begin by cloning yet another repository (see how often they
32 spring up?) and making a change in it.</para>
34 &interaction.tour.merge.clone;
36 <para>We should now have two copies of
37 <filename>hello.c</filename> with different contents. The
38 histories of the two repositories have also diverged, as
39 illustrated in figure <xref
40 linkend="fig:tour-merge:sep-repos"/>.</para>
42 &interaction.tour.merge.cat;
44 <informalfigure id="fig:tour-merge:sep-repos">
45 <mediaobject>
46 <imageobject><imagedata fileref="tour-merge-sep-repos"/></imageobject>
47 <textobject><phrase>XXX add text</phrase></textobject>
48 <caption><para>Divergent recent histories of the <filename
49 class="directory">my-hello</filename> and <filename
50 class="directory">my-new-hello</filename>
51 repositories</para></caption>
52 </mediaobject>
53 </informalfigure>
55 <para>We already know that pulling changes from our <filename
56 class="directory">my-hello</filename> repository will have no
57 effect on the working directory.</para>
59 &interaction.tour.merge.pull;
61 <para>However, the <command role="hg-cmd">hg pull</command>
62 command says something about <quote>heads</quote>.</para>
64 <sect2>
65 <title>Head changesets</title>
67 <para>A head is a change that has no descendants, or children,
68 as they're also known. The tip revision is thus a head,
69 because the newest revision in a repository doesn't have any
70 children, but a repository can contain more than one
71 head.</para>
73 <informalfigure id="fig:tour-merge:pull">
74 <mediaobject><imageobject><imagedata
75 fileref="tour-merge-pull"/></imageobject><textobject><phrase>XXX
76 add text</phrase></textobject>
77 <caption><para>Repository contents after pulling from
78 <filename class="directory">my-hello</filename> into
79 <filename
80 class="directory">my-new-hello</filename></para></caption>
81 </mediaobject>
82 </informalfigure>
84 <para>In figure <xref linkend="fig:tour-merge:pull"/>, you can
85 see the effect of the pull from <filename
86 class="directory">my-hello</filename> into <filename
87 class="directory">my-new-hello</filename>. The history that
88 was already present in <filename
89 class="directory">my-new-hello</filename> is untouched, but
90 a new revision has been added. By referring to figure <xref
91 linkend="fig:tour-merge:sep-repos"/>, we can see that the
92 <emphasis>changeset ID</emphasis> remains the same in the new
93 repository, but the <emphasis>revision number</emphasis> has
94 changed. (This, incidentally, is a fine example of why it's
95 not safe to use revision numbers when discussing changesets.)
96 We can view the heads in a repository using the <command
97 role="hg-cmd">hg heads</command> command.</para>
99 &interaction.tour.merge.heads;
101 </sect2>
102 <sect2>
103 <title>Performing the merge</title>
105 <para>What happens if we try to use the normal <command
106 role="hg-cmd">hg update</command> command to update to the
107 new tip?</para>
109 &interaction.tour.merge.update;
111 <para>Mercurial is telling us that the <command role="hg-cmd">hg
112 update</command> command won't do a merge; it won't update
113 the working directory when it thinks we might be wanting to do
114 a merge, unless we force it to do so. Instead, we use the
115 <command role="hg-cmd">hg merge</command> command to merge the
116 two heads.</para>
118 &interaction.tour.merge.merge;
120 <informalfigure id="fig:tour-merge:merge">
122 <mediaobject><imageobject><imagedata
123 fileref="tour-merge-merge"/></imageobject><textobject><phrase>XXX
124 add text</phrase></textobject>
125 <caption><para>Working directory and repository during
126 merge, and following commit</para></caption>
127 </mediaobject>
128 </informalfigure>
130 <para>This updates the working directory so that it contains
131 changes from <emphasis>both</emphasis> heads, which is
132 reflected in both the output of <command role="hg-cmd">hg
133 parents</command> and the contents of
134 <filename>hello.c</filename>.</para>
136 &interaction.tour.merge.parents;
138 </sect2>
139 <sect2>
140 <title>Committing the results of the merge</title>
142 <para>Whenever we've done a merge, <command role="hg-cmd">hg
143 parents</command> will display two parents until we <command
144 role="hg-cmd">hg commit</command> the results of the
145 merge.</para>
147 &interaction.tour.merge.commit;
149 <para>We now have a new tip revision; notice that it has
150 <emphasis>both</emphasis> of our former heads as its parents.
151 These are the same revisions that were previously displayed by
152 <command role="hg-cmd">hg parents</command>.</para>
154 &interaction.tour.merge.tip;
156 <para>In figure <xref
157 linkend="fig:tour-merge:merge"/>, you can see a
158 representation of what happens to the working directory during
159 the merge, and how this affects the repository when the commit
160 happens. During the merge, the working directory has two
161 parent changesets, and these become the parents of the new
162 changeset.</para>
164 </sect2>
165 </sect1>
166 <sect1>
167 <title>Merging conflicting changes</title>
169 <para>Most merges are simple affairs, but sometimes you'll find
170 yourself merging changes where each modifies the same portions
171 of the same files. Unless both modifications are identical,
172 this results in a <emphasis>conflict</emphasis>, where you have
173 to decide how to reconcile the different changes into something
174 coherent.</para>
176 <informalfigure>
178 <mediaobject id="fig:tour-merge:conflict">
179 <imageobject><imagedata fileref="tour-merge-conflict"/></imageobject>
180 <textobject><phrase>XXX add text</phrase></textobject>
181 <caption><para>Conflicting changes to a
182 document</para></caption> </mediaobject>
183 </informalfigure>
185 <para>Figure <xref linkend="fig:tour-merge:conflict"/> illustrates
186 an instance of two conflicting changes to a document. We
187 started with a single version of the file; then we made some
188 changes; while someone else made different changes to the same
189 text. Our task in resolving the conflicting changes is to
190 decide what the file should look like.</para>
192 <para>Mercurial doesn't have a built-in facility for handling
193 conflicts. Instead, it runs an external program called
194 <command>hgmerge</command>. This is a shell script that is
195 bundled with Mercurial; you can change it to behave however you
196 please. What it does by default is try to find one of several
197 different merging tools that are likely to be installed on your
198 system. It first tries a few fully automatic merging tools; if
199 these don't succeed (because the resolution process requires
200 human guidance) or aren't present, the script tries a few
201 different graphical merging tools.</para>
203 <para>It's also possible to get Mercurial to run another program
204 or script instead of <command>hgmerge</command>, by setting the
205 <envar>HGMERGE</envar> environment variable to the name of your
206 preferred program.</para>
208 <sect2>
209 <title>Using a graphical merge tool</title>
211 <para>My preferred graphical merge tool is
212 <command>kdiff3</command>, which I'll use to describe the
213 features that are common to graphical file merging tools. You
214 can see a screenshot of <command>kdiff3</command> in action in
215 figure <xref linkend="fig:tour-merge:kdiff3"/>. The kind of
216 merge it is performing is called a <emphasis>three-way
217 merge</emphasis>, because there are three different versions
218 of the file of interest to us. The tool thus splits the upper
219 portion of the window into three panes:</para>
220 <itemizedlist>
221 <listitem><para>At the left is the <emphasis>base</emphasis>
222 version of the file, i.e. the most recent version from
223 which the two versions we're trying to merge are
224 descended.</para>
225 </listitem>
226 <listitem><para>In the middle is <quote>our</quote> version of
227 the file, with the contents that we modified.</para>
228 </listitem>
229 <listitem><para>On the right is <quote>their</quote> version
230 of the file, the one that from the changeset that we're
231 trying to merge with.</para>
232 </listitem></itemizedlist>
233 <para>In the pane below these is the current
234 <emphasis>result</emphasis> of the merge. Our task is to
235 replace all of the red text, which indicates unresolved
236 conflicts, with some sensible merger of the
237 <quote>ours</quote> and <quote>theirs</quote> versions of the
238 file.</para>
240 <para>All four of these panes are <emphasis>locked
241 together</emphasis>; if we scroll vertically or horizontally
242 in any of them, the others are updated to display the
243 corresponding sections of their respective files.</para>
245 <informalfigure id="fig:tour-merge:kdiff3">
246 <mediaobject><imageobject><imagedata
247 fileref="kdiff3"/></imageobject><textobject><phrase>XXX
248 add text</phrase></textobject>
249 <caption><para>Using <command>kdiff3</command> to merge
250 versions of a file</para></caption>
251 </mediaobject>
252 </informalfigure>
254 <para>For each conflicting portion of the file, we can choose to
255 resolve the conflict using some combination of text from the
256 base version, ours, or theirs. We can also manually edit the
257 merged file at any time, in case we need to make further
258 modifications.</para>
260 <para>There are <emphasis>many</emphasis> file merging tools
261 available, too many to cover here. They vary in which
262 platforms they are available for, and in their particular
263 strengths and weaknesses. Most are tuned for merging files
264 containing plain text, while a few are aimed at specialised
265 file formats (generally XML).</para>
267 </sect2>
268 <sect2>
269 <title>A worked example</title>
271 <para>In this example, we will reproduce the file modification
272 history of figure <xref linkend="fig:tour-merge:conflict"/>
273 above. Let's begin by creating a repository with a base
274 version of our document.</para>
276 &interaction.tour-merge-conflict.wife;
278 <para>We'll clone the repository and make a change to the
279 file.</para>
281 &interaction.tour-merge-conflict.cousin;
283 <para>And another clone, to simulate someone else making a
284 change to the file. (This hints at the idea that it's not all
285 that unusual to merge with yourself when you isolate tasks in
286 separate repositories, and indeed to find and resolve
287 conflicts while doing so.)</para>
289 &interaction.tour-merge-conflict.son;
291 <para>Having created two
292 different versions of the file, we'll set up an environment
293 suitable for running our merge.</para>
295 &interaction.tour-merge-conflict.pull;
297 <para>In this example, I won't use Mercurial's normal
298 <command>hgmerge</command> program to do the merge, because it
299 would drop my nice automated example-running tool into a
300 graphical user interface. Instead, I'll set
301 <envar>HGMERGE</envar> to tell Mercurial to use the
302 non-interactive <command>merge</command> command. This is
303 bundled with many Unix-like systems. If you're following this
304 example on your computer, don't bother setting
305 <envar>HGMERGE</envar>.</para>
307 <para><emphasis role="bold">XXX FIX THIS
308 EXAMPLE.</emphasis></para>
310 &interaction.tour-merge-conflict.merge;
312 <para>Because <command>merge</command> can't resolve the
313 conflicting changes, it leaves <emphasis>merge
314 markers</emphasis> inside the file that has conflicts,
315 indicating which lines have conflicts, and whether they came
316 from our version of the file or theirs.</para>
318 <para>Mercurial can tell from the way <command>merge</command>
319 exits that it wasn't able to merge successfully, so it tells
320 us what commands we'll need to run if we want to redo the
321 merging operation. This could be useful if, for example, we
322 were running a graphical merge tool and quit because we were
323 confused or realised we had made a mistake.</para>
325 <para>If automatic or manual merges fail, there's nothing to
326 prevent us from <quote>fixing up</quote> the affected files
327 ourselves, and committing the results of our merge:</para>
329 &interaction.tour-merge-conflict.commit;
331 </sect2>
332 </sect1>
333 <sect1 id="sec:tour-merge:fetch">
334 <title>Simplifying the pull-merge-commit sequence</title>
336 <para>The process of merging changes as outlined above is
337 straightforward, but requires running three commands in
338 sequence.</para>
339 <programlisting>
340 hg pull hg merge hg commit -m 'Merged remote changes'
341 </programlisting>
342 <para>In the case of the final commit, you also need to enter a
343 commit message, which is almost always going to be a piece of
344 uninteresting <quote>boilerplate</quote> text.</para>
346 <para>It would be nice to reduce the number of steps needed, if
347 this were possible. Indeed, Mercurial is distributed with an
348 extension called <literal role="hg-ext">fetch</literal> that
349 does just this.</para>
351 <para>Mercurial provides a flexible extension mechanism that lets
352 people extend its functionality, while keeping the core of
353 Mercurial small and easy to deal with. Some extensions add new
354 commands that you can use from the command line, while others
355 work <quote>behind the scenes,</quote> for example adding
356 capabilities to the server.</para>
358 <para>The <literal role="hg-ext">fetch</literal> extension adds a
359 new command called, not surprisingly, <command role="hg-cmd">hg
360 fetch</command>. This extension acts as a combination of
361 <command role="hg-cmd">hg pull</command>, <command
362 role="hg-cmd">hg update</command> and <command
363 role="hg-cmd">hg merge</command>. It begins by pulling
364 changes from another repository into the current repository. If
365 it finds that the changes added a new head to the repository, it
366 begins a merge, then commits the result of the merge with an
367 automatically-generated commit message. If no new heads were
368 added, it updates the working directory to the new tip
369 changeset.</para>
371 <para>Enabling the <literal role="hg-ext">fetch</literal>
372 extension is easy. Edit your <filename
373 role="special">.hgrc</filename>, and either go to the <literal
374 role="rc-extensions">extensions</literal> section or create an
375 <literal role="rc-extensions">extensions</literal> section. Then
376 add a line that simply reads <quote><literal>fetch
377 </literal></quote>.</para>
378 <programlisting>
379 [extensions] fetch =
380 </programlisting>
381 <para>(Normally, on the right-hand side of the
382 <quote><literal>=</literal></quote> would appear the location of
383 the extension, but since the <literal
384 role="hg-ext">fetch</literal> extension is in the standard
385 distribution, Mercurial knows where to search for it.)</para>
387 </sect1>
388 </chapter>
390 <!--
391 local variables:
392 sgml-parent-document: ("00book.xml" "book" "chapter")
393 end:
394 -->