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