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