hgbook

annotate en/ch03-tour-merge.xml @ 647:d0160b0b1a9e

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