hgbook

annotate en/ch03-tour-merge.xml @ 560:dbe91bb622d8

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