hgbook
diff en/ch03-tour-merge.xml @ 559:b90b024729f1
WIP DocBook snapshot that all compiles. Mirabile dictu!
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Wed Feb 18 00:22:09 2009 -0800 (2009-02-18) |
parents | en/ch03-tour-merge.tex@f72b7e6cbe90 |
children | 8fcd44708f41 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/en/ch03-tour-merge.xml Wed Feb 18 00:22:09 2009 -0800 1.3 @@ -0,0 +1,394 @@ 1.4 +<!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : --> 1.5 + 1.6 +<chapter id="chap:tour-merge"> 1.7 + <title>A tour of Mercurial: merging work</title> 1.8 + 1.9 + <para>We've now covered cloning a repository, making changes in a 1.10 + repository, and pulling or pushing changes from one repository 1.11 + into another. Our next step is <emphasis>merging</emphasis> 1.12 + changes from separate repositories.</para> 1.13 + 1.14 + <sect1> 1.15 + <title>Merging streams of work</title> 1.16 + 1.17 + <para>Merging is a fundamental part of working with a distributed 1.18 + revision control tool.</para> 1.19 + <itemizedlist> 1.20 + <listitem><para>Alice and Bob each have a personal copy of a 1.21 + repository for a project they're collaborating on. Alice 1.22 + fixes a bug in her repository; Bob adds a new feature in 1.23 + his. They want the shared repository to contain both the 1.24 + bug fix and the new feature.</para> 1.25 + </listitem> 1.26 + <listitem><para>I frequently work on several different tasks for 1.27 + a single project at once, each safely isolated in its own 1.28 + repository. Working this way means that I often need to 1.29 + merge one piece of my own work with another.</para> 1.30 + </listitem></itemizedlist> 1.31 + 1.32 + <para>Because merging is such a common thing to need to do, 1.33 + Mercurial makes it easy. Let's walk through the process. We'll 1.34 + begin by cloning yet another repository (see how often they 1.35 + spring up?) and making a change in it.</para> 1.36 + 1.37 + <!-- &interaction.tour.merge.clone; --> 1.38 + 1.39 + <para>We should now have two copies of 1.40 + <filename>hello.c</filename> with different contents. The 1.41 + histories of the two repositories have also diverged, as 1.42 + illustrated in figure <xref 1.43 + linkend="fig:tour-merge:sep-repos"/>.</para> 1.44 + 1.45 + <!-- &interaction.tour.merge.cat; --> 1.46 + 1.47 + <informalfigure id="fig:tour-merge:sep-repos"> 1.48 + <mediaobject> 1.49 + <imageobject><imagedata fileref="tour-merge-sep-repos"/></imageobject> 1.50 + <textobject><phrase>XXX add text</phrase></textobject> 1.51 + <caption><para>Divergent recent histories of the <filename 1.52 + class="directory">my-hello</filename> and <filename 1.53 + class="directory">my-new-hello</filename> 1.54 + repositories</para></caption> 1.55 + </mediaobject> 1.56 + </informalfigure> 1.57 + 1.58 + <para>We already know that pulling changes from our <filename 1.59 + class="directory">my-hello</filename> repository will have no 1.60 + effect on the working directory.</para> 1.61 + 1.62 + <!-- &interaction.tour.merge.pull; --> 1.63 + 1.64 + <para>However, the <command role="hg-cmd">hg pull</command> 1.65 + command says something about <quote>heads</quote>.</para> 1.66 + 1.67 + <sect2> 1.68 + <title>Head changesets</title> 1.69 + 1.70 + <para>A head is a change that has no descendants, or children, 1.71 + as they're also known. The tip revision is thus a head, 1.72 + because the newest revision in a repository doesn't have any 1.73 + children, but a repository can contain more than one 1.74 + head.</para> 1.75 + 1.76 + <informalfigure id="fig:tour-merge:pull"> 1.77 + <mediaobject><imageobject><imagedata 1.78 + fileref="tour-merge-pull"/></imageobject><textobject><phrase>XXX 1.79 + add text</phrase></textobject> 1.80 + <caption><para>Repository contents after pulling from 1.81 + <filename class="directory">my-hello</filename> into 1.82 + <filename 1.83 + class="directory">my-new-hello</filename></para></caption> 1.84 + </mediaobject> 1.85 + </informalfigure> 1.86 + 1.87 + <para>In figure <xref linkend="fig:tour-merge:pull"/>, you can 1.88 + see the effect of the pull from <filename 1.89 + class="directory">my-hello</filename> into <filename 1.90 + class="directory">my-new-hello</filename>. The history that 1.91 + was already present in <filename 1.92 + class="directory">my-new-hello</filename> is untouched, but 1.93 + a new revision has been added. By referring to figure <xref 1.94 + linkend="fig:tour-merge:sep-repos"/>, we can see that the 1.95 + <emphasis>changeset ID</emphasis> remains the same in the new 1.96 + repository, but the <emphasis>revision number</emphasis> has 1.97 + changed. (This, incidentally, is a fine example of why it's 1.98 + not safe to use revision numbers when discussing changesets.) 1.99 + We can view the heads in a repository using the <command 1.100 + role="hg-cmd">hg heads</command> command.</para> 1.101 + 1.102 + <!-- &interaction.tour.merge.heads; --> 1.103 + 1.104 + </sect2> 1.105 + <sect2> 1.106 + <title>Performing the merge</title> 1.107 + 1.108 + <para>What happens if we try to use the normal <command 1.109 + role="hg-cmd">hg update</command> command to update to the 1.110 + new tip?</para> 1.111 + 1.112 + <!-- &interaction.tour.merge.update; --> 1.113 + 1.114 + <para>Mercurial is telling us that the <command role="hg-cmd">hg 1.115 + update</command> command won't do a merge; it won't update 1.116 + the working directory when it thinks we might be wanting to do 1.117 + a merge, unless we force it to do so. Instead, we use the 1.118 + <command role="hg-cmd">hg merge</command> command to merge the 1.119 + two heads.</para> 1.120 + 1.121 + <!-- &interaction.tour.merge.merge; --> 1.122 + 1.123 + <informalfigure id="fig:tour-merge:merge"> 1.124 + 1.125 + <mediaobject><imageobject><imagedata 1.126 + fileref="tour-merge-merge"/></imageobject><textobject><phrase>XXX 1.127 + add text</phrase></textobject> 1.128 + <caption><para>Working directory and repository during 1.129 + merge, and following commit</para></caption> 1.130 + </mediaobject> 1.131 + </informalfigure> 1.132 + 1.133 + <para>This updates the working directory so that it contains 1.134 + changes from <emphasis>both</emphasis> heads, which is 1.135 + reflected in both the output of <command role="hg-cmd">hg 1.136 + parents</command> and the contents of 1.137 + <filename>hello.c</filename>.</para> 1.138 + 1.139 + <!-- &interaction.tour.merge.parents; --> 1.140 + 1.141 + </sect2> 1.142 + <sect2> 1.143 + <title>Committing the results of the merge</title> 1.144 + 1.145 + <para>Whenever we've done a merge, <command role="hg-cmd">hg 1.146 + parents</command> will display two parents until we <command 1.147 + role="hg-cmd">hg commit</command> the results of the 1.148 + merge.</para> 1.149 + 1.150 + <!-- &interaction.tour.merge.commit; --> 1.151 + 1.152 + <para>We now have a new tip revision; notice that it has 1.153 + <emphasis>both</emphasis> of our former heads as its parents. 1.154 + These are the same revisions that were previously displayed by 1.155 + <command role="hg-cmd">hg parents</command>.</para> 1.156 + 1.157 + <!-- &interaction.tour.merge.tip; --> 1.158 + 1.159 + <para>In figure <xref 1.160 + linkend="fig:tour-merge:merge"/>, you can see a 1.161 + representation of what happens to the working directory during 1.162 + the merge, and how this affects the repository when the commit 1.163 + happens. During the merge, the working directory has two 1.164 + parent changesets, and these become the parents of the new 1.165 + changeset.</para> 1.166 + 1.167 + </sect2> 1.168 + </sect1> 1.169 + <sect1> 1.170 + <title>Merging conflicting changes</title> 1.171 + 1.172 + <para>Most merges are simple affairs, but sometimes you'll find 1.173 + yourself merging changes where each modifies the same portions 1.174 + of the same files. Unless both modifications are identical, 1.175 + this results in a <emphasis>conflict</emphasis>, where you have 1.176 + to decide how to reconcile the different changes into something 1.177 + coherent.</para> 1.178 + 1.179 + <informalfigure> 1.180 + 1.181 + <mediaobject id="fig:tour-merge:conflict"> 1.182 + <imageobject><imagedata fileref="tour-merge-conflict"/></imageobject> 1.183 + <textobject><phrase>XXX add text</phrase></textobject> 1.184 + <caption><para>Conflicting changes to a 1.185 + document</para></caption> </mediaobject> 1.186 + </informalfigure> 1.187 + 1.188 + <para>Figure <xref linkend="fig:tour-merge:conflict"/> illustrates 1.189 + an instance of two conflicting changes to a document. We 1.190 + started with a single version of the file; then we made some 1.191 + changes; while someone else made different changes to the same 1.192 + text. Our task in resolving the conflicting changes is to 1.193 + decide what the file should look like.</para> 1.194 + 1.195 + <para>Mercurial doesn't have a built-in facility for handling 1.196 + conflicts. Instead, it runs an external program called 1.197 + <command>hgmerge</command>. This is a shell script that is 1.198 + bundled with Mercurial; you can change it to behave however you 1.199 + please. What it does by default is try to find one of several 1.200 + different merging tools that are likely to be installed on your 1.201 + system. It first tries a few fully automatic merging tools; if 1.202 + these don't succeed (because the resolution process requires 1.203 + human guidance) or aren't present, the script tries a few 1.204 + different graphical merging tools.</para> 1.205 + 1.206 + <para>It's also possible to get Mercurial to run another program 1.207 + or script instead of <command>hgmerge</command>, by setting the 1.208 + <envar>HGMERGE</envar> environment variable to the name of your 1.209 + preferred program.</para> 1.210 + 1.211 + <sect2> 1.212 + <title>Using a graphical merge tool</title> 1.213 + 1.214 + <para>My preferred graphical merge tool is 1.215 + <command>kdiff3</command>, which I'll use to describe the 1.216 + features that are common to graphical file merging tools. You 1.217 + can see a screenshot of <command>kdiff3</command> in action in 1.218 + figure <xref linkend="fig:tour-merge:kdiff3"/>. The kind of 1.219 + merge it is performing is called a <emphasis>three-way 1.220 + merge</emphasis>, because there are three different versions 1.221 + of the file of interest to us. The tool thus splits the upper 1.222 + portion of the window into three panes:</para> 1.223 + <itemizedlist> 1.224 + <listitem><para>At the left is the <emphasis>base</emphasis> 1.225 + version of the file, i.e. the most recent version from 1.226 + which the two versions we're trying to merge are 1.227 + descended.</para> 1.228 + </listitem> 1.229 + <listitem><para>In the middle is <quote>our</quote> version of 1.230 + the file, with the contents that we modified.</para> 1.231 + </listitem> 1.232 + <listitem><para>On the right is <quote>their</quote> version 1.233 + of the file, the one that from the changeset that we're 1.234 + trying to merge with.</para> 1.235 + </listitem></itemizedlist> 1.236 + <para>In the pane below these is the current 1.237 + <emphasis>result</emphasis> of the merge. Our task is to 1.238 + replace all of the red text, which indicates unresolved 1.239 + conflicts, with some sensible merger of the 1.240 + <quote>ours</quote> and <quote>theirs</quote> versions of the 1.241 + file.</para> 1.242 + 1.243 + <para>All four of these panes are <emphasis>locked 1.244 + together</emphasis>; if we scroll vertically or horizontally 1.245 + in any of them, the others are updated to display the 1.246 + corresponding sections of their respective files.</para> 1.247 + 1.248 + <informalfigure id="fig:tour-merge:kdiff3"> 1.249 + <mediaobject><imageobject><imagedata 1.250 + fileref="kdiff3"/></imageobject><textobject><phrase>XXX 1.251 + add text</phrase></textobject> 1.252 + <caption><para>Using <command>kdiff3</command> to merge 1.253 + versions of a file</para></caption> 1.254 + </mediaobject> 1.255 + </informalfigure> 1.256 + 1.257 + <para>For each conflicting portion of the file, we can choose to 1.258 + resolve the conflict using some combination of text from the 1.259 + base version, ours, or theirs. We can also manually edit the 1.260 + merged file at any time, in case we need to make further 1.261 + modifications.</para> 1.262 + 1.263 + <para>There are <emphasis>many</emphasis> file merging tools 1.264 + available, too many to cover here. They vary in which 1.265 + platforms they are available for, and in their particular 1.266 + strengths and weaknesses. Most are tuned for merging files 1.267 + containing plain text, while a few are aimed at specialised 1.268 + file formats (generally XML).</para> 1.269 + 1.270 + </sect2> 1.271 + <sect2> 1.272 + <title>A worked example</title> 1.273 + 1.274 + <para>In this example, we will reproduce the file modification 1.275 + history of figure <xref linkend="fig:tour-merge:conflict"/> 1.276 + above. Let's begin by creating a repository with a base 1.277 + version of our document.</para> 1.278 + 1.279 + <!-- &interaction.tour-merge-conflict.wife; --> 1.280 + 1.281 + <para>We'll clone the repository and make a change to the 1.282 + file.</para> 1.283 + 1.284 + <!-- &interaction.tour-merge-conflict.cousin; --> 1.285 + 1.286 + <para>And another clone, to simulate someone else making a 1.287 + change to the file. (This hints at the idea that it's not all 1.288 + that unusual to merge with yourself when you isolate tasks in 1.289 + separate repositories, and indeed to find and resolve 1.290 + conflicts while doing so.)</para> 1.291 + 1.292 + <!-- &interaction.tour-merge-conflict.son; --> 1.293 + 1.294 + <para>Having created two 1.295 + different versions of the file, we'll set up an environment 1.296 + suitable for running our merge.</para> 1.297 + 1.298 + <!-- &interaction.tour-merge-conflict.pull; --> 1.299 + 1.300 + <para>In this example, I won't use Mercurial's normal 1.301 + <command>hgmerge</command> program to do the merge, because it 1.302 + would drop my nice automated example-running tool into a 1.303 + graphical user interface. Instead, I'll set 1.304 + <envar>HGMERGE</envar> to tell Mercurial to use the 1.305 + non-interactive <command>merge</command> command. This is 1.306 + bundled with many Unix-like systems. If you're following this 1.307 + example on your computer, don't bother setting 1.308 + <envar>HGMERGE</envar>.</para> 1.309 + 1.310 + <para><emphasis role="bold">XXX FIX THIS 1.311 + EXAMPLE.</emphasis></para> 1.312 + 1.313 + <!-- &interaction.tour-merge-conflict.merge; --> 1.314 + 1.315 + <para>Because <command>merge</command> can't resolve the 1.316 + conflicting changes, it leaves <emphasis>merge 1.317 + markers</emphasis> inside the file that has conflicts, 1.318 + indicating which lines have conflicts, and whether they came 1.319 + from our version of the file or theirs.</para> 1.320 + 1.321 + <para>Mercurial can tell from the way <command>merge</command> 1.322 + exits that it wasn't able to merge successfully, so it tells 1.323 + us what commands we'll need to run if we want to redo the 1.324 + merging operation. This could be useful if, for example, we 1.325 + were running a graphical merge tool and quit because we were 1.326 + confused or realised we had made a mistake.</para> 1.327 + 1.328 + <para>If automatic or manual merges fail, there's nothing to 1.329 + prevent us from <quote>fixing up</quote> the affected files 1.330 + ourselves, and committing the results of our merge:</para> 1.331 + 1.332 + <!-- &interaction.tour-merge-conflict.commit; --> 1.333 + 1.334 + </sect2> 1.335 + </sect1> 1.336 + <sect1 id="sec:tour-merge:fetch"> 1.337 + <title>Simplifying the pull-merge-commit sequence</title> 1.338 + 1.339 + <para>The process of merging changes as outlined above is 1.340 + straightforward, but requires running three commands in 1.341 + sequence.</para> 1.342 + <programlisting> 1.343 + hg pull hg merge hg commit -m 'Merged remote changes' 1.344 + </programlisting> 1.345 + <para>In the case of the final commit, you also need to enter a 1.346 + commit message, which is almost always going to be a piece of 1.347 + uninteresting <quote>boilerplate</quote> text.</para> 1.348 + 1.349 + <para>It would be nice to reduce the number of steps needed, if 1.350 + this were possible. Indeed, Mercurial is distributed with an 1.351 + extension called <literal role="hg-ext">fetch</literal> that 1.352 + does just this.</para> 1.353 + 1.354 + <para>Mercurial provides a flexible extension mechanism that lets 1.355 + people extend its functionality, while keeping the core of 1.356 + Mercurial small and easy to deal with. Some extensions add new 1.357 + commands that you can use from the command line, while others 1.358 + work <quote>behind the scenes,</quote> for example adding 1.359 + capabilities to the server.</para> 1.360 + 1.361 + <para>The <literal role="hg-ext">fetch</literal> extension adds a 1.362 + new command called, not surprisingly, <command role="hg-cmd">hg 1.363 + fetch</command>. This extension acts as a combination of 1.364 + <command role="hg-cmd">hg pull</command>, <command 1.365 + role="hg-cmd">hg update</command> and <command 1.366 + role="hg-cmd">hg merge</command>. It begins by pulling 1.367 + changes from another repository into the current repository. If 1.368 + it finds that the changes added a new head to the repository, it 1.369 + begins a merge, then commits the result of the merge with an 1.370 + automatically-generated commit message. If no new heads were 1.371 + added, it updates the working directory to the new tip 1.372 + changeset.</para> 1.373 + 1.374 + <para>Enabling the <literal role="hg-ext">fetch</literal> 1.375 + extension is easy. Edit your <filename 1.376 + role="special">.hgrc</filename>, and either go to the <literal 1.377 + role="rc-extensions">extensions</literal> section or create an 1.378 + <literal role="rc-extensions">extensions</literal> section. Then 1.379 + add a line that simply reads <quote><literal>fetch 1.380 + </literal></quote>.</para> 1.381 + <programlisting> 1.382 + [extensions] fetch = 1.383 + </programlisting> 1.384 + <para>(Normally, on the right-hand side of the 1.385 + <quote><literal>=</literal></quote> would appear the location of 1.386 + the extension, but since the <literal 1.387 + role="hg-ext">fetch</literal> extension is in the standard 1.388 + distribution, Mercurial knows where to search for it.)</para> 1.389 + 1.390 + </sect1> 1.391 +</chapter> 1.392 + 1.393 +<!-- 1.394 +local variables: 1.395 +sgml-parent-document: ("00book.xml" "book" "chapter") 1.396 +end: 1.397 +-->