hgbook

annotate en/ch03-tour-merge.xml @ 579:80928ea6e7ae

Add the ability to include text files and have them XML-mangled.
author Bryan O'Sullivan <bos@serpentine.com>
date Tue Mar 17 21:47:12 2009 -0700 (2009-03-17)
parents 13513d2a128d
children d0160b0b1a9e
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 -->