diff en/ch03-tour-merge.xml @ 831:acf9dc5f088d

Add a skeletal preface.
author Bryan O'Sullivan <bos@serpentine.com>
date Thu, 07 May 2009 21:07:35 -0700
parents en/ch02-tour-merge.xml@18131160f7ee
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/en/ch03-tour-merge.xml	Thu May 07 21:07:35 2009 -0700
@@ -0,0 +1,454 @@
+<!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
+
+<chapter id="chap:tour-merge">
+  <?dbhtml filename="a-tour-of-mercurial-merging-work.html"?>
+  <title>A tour of Mercurial: merging work</title>
+
+  <para id="x_338">We've now covered cloning a repository, making changes in a
+    repository, and pulling or pushing changes from one repository
+    into another.  Our next step is <emphasis>merging</emphasis>
+    changes from separate repositories.</para>
+
+  <sect1>
+    <title>Merging streams of work</title>
+
+    <para id="x_339">Merging is a fundamental part of working with a distributed
+      revision control tool.  Here are a few cases in which the need
+      to merge work arises.</para>
+    <itemizedlist>
+      <listitem>
+	<para id="x_33a">Alice and Bob each have a personal copy of a
+	  repository for a project they're collaborating on.  Alice
+	  fixes a bug in her repository; Bob adds a new feature in
+	  his.  They want the shared repository to contain both the
+	  bug fix and the new feature.</para>
+      </listitem>
+      <listitem>
+	<para id="x_33b">Cynthia frequently works on several different
+	  tasks for a single project at once, each safely isolated in
+	  its own repository. Working this way means that she often
+	  needs to merge one piece of her own work with
+	  another.</para>
+      </listitem>
+    </itemizedlist>
+
+    <para id="x_33c">Because we need to merge often, Mercurial makes
+      the process easy.  Let's walk through a merge.  We'll begin by
+      cloning yet another repository (see how often they spring up?)
+      and making a change in it.</para>
+
+    &interaction.tour.merge.clone;
+
+    <para id="x_33d">We should now have two copies of
+      <filename>hello.c</filename> with different contents.  The
+      histories of the two repositories have also diverged, as
+      illustrated in <xref
+	linkend="fig:tour-merge:sep-repos"/>.  Here is a copy of our
+      file from one repository.</para>
+
+    &interaction.tour.merge.cat1;
+
+    <para id="x_722">And here is our slightly different version from the other
+      repository.</para>
+
+    &interaction.tour.merge.cat2;
+
+    <figure id="fig:tour-merge:sep-repos">
+      <title>Divergent recent histories of the <filename
+	  class="directory">my-hello</filename> and <filename
+	  class="directory">my-new-hello</filename>
+	repositories</title>
+      <mediaobject>
+	<imageobject><imagedata fileref="figs/tour-merge-sep-repos.png"/></imageobject>
+	<textobject><phrase>XXX add text</phrase></textobject>
+      </mediaobject>
+    </figure>
+
+    <para id="x_33f">We already know that pulling changes from our <filename
+	class="directory">my-hello</filename> repository will have no
+      effect on the working directory.</para>
+
+    &interaction.tour.merge.pull;
+
+    <para id="x_340">However, the <command role="hg-cmd">hg pull</command>
+      command says something about <quote>heads</quote>.</para>
+
+    <sect2>
+      <title>Head changesets</title>
+
+      <para id="x_341">Remember that Mercurial records what the parent
+	of each change is.  If a change has a parent, we call it a
+	child or descendant of the parent.  A head is a change that
+	has no children.  The tip revision is thus a head, because the
+	newest revision in a repository doesn't have any children.
+	There are times when a repository can contain more than one
+	head.</para>
+
+      <figure id="fig:tour-merge:pull">
+	<title>Repository contents after pulling from <filename
+	    class="directory">my-hello</filename> into <filename
+	    class="directory">my-new-hello</filename></title>
+	<mediaobject>
+	  <imageobject>
+	    <imagedata fileref="figs/tour-merge-pull.png"/>
+	  </imageobject>
+	  <textobject><phrase>XXX add text</phrase></textobject>
+	</mediaobject>
+      </figure>
+
+      <para id="x_343">In <xref linkend="fig:tour-merge:pull"/>, you can
+	see the effect of the pull from <filename
+	  class="directory">my-hello</filename> into <filename
+	  class="directory">my-new-hello</filename>.  The history that
+	was already present in <filename
+	  class="directory">my-new-hello</filename> is untouched, but
+	a new revision has been added.  By referring to <xref
+	  linkend="fig:tour-merge:sep-repos"/>, we can see that the
+	<emphasis>changeset ID</emphasis> remains the same in the new
+	repository, but the <emphasis>revision number</emphasis> has
+	changed.  (This, incidentally, is a fine example of why it's
+	not safe to use revision numbers when discussing changesets.)
+	We can view the heads in a repository using the <command
+	  role="hg-cmd">hg heads</command> command.</para>
+
+      &interaction.tour.merge.heads;
+    </sect2>
+
+    <sect2>
+      <title>Performing the merge</title>
+
+      <para id="x_344">What happens if we try to use the normal <command
+	  role="hg-cmd">hg update</command> command to update to the
+	new tip?</para>
+
+      &interaction.tour.merge.update;
+
+      <para id="x_345">Mercurial is telling us that the <command
+	  role="hg-cmd">hg update</command> command won't do a merge;
+	it won't update the working directory when it thinks we might
+	want to do a merge, unless we force it to do so.
+	(Incidentally, forcing the update with <command>hg update
+	  -C</command> would revert any uncommitted changes in the
+	working directory.)</para>
+
+      <para id="x_723">To start a merge between the two heads, we use the
+	<command role="hg-cmd">hg merge</command> command.</para>
+
+      &interaction.tour.merge.merge;
+
+      <para id="x_347">We resolve the contents of <filename>hello.c</filename>
+
+This updates the working directory so that it
+	contains changes from <emphasis>both</emphasis> heads, which
+	is reflected in both the output of <command role="hg-cmd">hg
+	  parents</command> and the contents of
+	<filename>hello.c</filename>.</para>
+
+      &interaction.tour.merge.parents;
+    </sect2>
+
+    <sect2>
+      <title>Committing the results of the merge</title>
+
+      <para id="x_348">Whenever we've done a merge, <command role="hg-cmd">hg
+	  parents</command> will display two parents until we <command
+	  role="hg-cmd">hg commit</command> the results of the
+	  merge.</para>
+
+	&interaction.tour.merge.commit;
+
+      <para id="x_349">We now have a new tip revision; notice that it has
+	<emphasis>both</emphasis> of our former heads as its parents.
+	These are the same revisions that were previously displayed by
+	<command role="hg-cmd">hg parents</command>.</para>
+
+      &interaction.tour.merge.tip;
+
+      <para id="x_34a">In <xref
+	  linkend="fig:tour-merge:merge"/>, you can see a
+	representation of what happens to the working directory during
+	the merge, and how this affects the repository when the commit
+	happens.  During the merge, the working directory has two
+	parent changesets, and these become the parents of the new
+	changeset.</para>
+
+      <figure id="fig:tour-merge:merge">
+	<title>Working directory and repository during merge, and
+	  following commit</title>
+	<mediaobject>
+	  <imageobject>
+	    <imagedata fileref="figs/tour-merge-merge.png"/>
+	  </imageobject>
+	  <textobject><phrase>XXX add text</phrase></textobject>
+	</mediaobject>
+      </figure>
+
+      <para id="x_69c">We sometimes talk about a merge having
+	<emphasis>sides</emphasis>: the left side is the first parent
+	in the output of <command role="hg-cmd">hg parents</command>,
+	and the right side is the second.  If the working directory
+	was at e.g. revision 5 before we began a merge, that revision
+	will become the left side of the merge.</para>
+    </sect2>
+  </sect1>
+
+  <sect1>
+    <title>Merging conflicting changes</title>
+
+    <para id="x_34b">Most merges are simple affairs, but sometimes you'll find
+      yourself merging changes where each side modifies the same portions
+      of the same files.  Unless both modifications are identical,
+      this results in a <emphasis>conflict</emphasis>, where you have
+      to decide how to reconcile the different changes into something
+      coherent.</para>
+
+    <figure id="fig:tour-merge:conflict">
+      <title>Conflicting changes to a document</title>
+      <mediaobject>
+	<imageobject><imagedata fileref="figs/tour-merge-conflict.png"/></imageobject>
+	<textobject><phrase>XXX add text</phrase></textobject>
+      </mediaobject>
+    </figure>
+
+    <para id="x_34d"><xref linkend="fig:tour-merge:conflict"/> illustrates
+      an instance of two conflicting changes to a document.  We
+      started with a single version of the file; then we made some
+      changes; while someone else made different changes to the same
+      text.  Our task in resolving the conflicting changes is to
+      decide what the file should look like.</para>
+
+    <para id="x_34e">Mercurial doesn't have a built-in facility for handling
+      conflicts. Instead, it runs an external program, usually one
+      that displays some kind of graphical conflict resolution
+      interface.  By default, Mercurial tries to find one of several
+      different merging tools that are likely to be installed on your
+      system.  It first tries a few fully automatic merging tools; if
+      these don't succeed (because the resolution process requires
+      human guidance) or aren't present, it tries a few
+      different graphical merging tools.</para>
+
+    <para id="x_34f">It's also possible to get Mercurial to run a
+      specific program or script, by setting the
+      <envar>HGMERGE</envar> environment variable to the name of your
+      preferred program.</para>
+
+    <sect2>
+      <title>Using a graphical merge tool</title>
+
+      <para id="x_350">My preferred graphical merge tool is
+	<command>kdiff3</command>, which I'll use to describe the
+	features that are common to graphical file merging tools.  You
+	can see a screenshot of <command>kdiff3</command> in action in
+	<xref linkend="fig:tour-merge:kdiff3"/>.  The kind of
+	merge it is performing is called a <emphasis>three-way
+	  merge</emphasis>, because there are three different versions
+	of the file of interest to us.  The tool thus splits the upper
+	portion of the window into three panes:</para>
+      <itemizedlist>
+	<listitem><para id="x_351">At the left is the <emphasis>base</emphasis>
+	    version of the file, i.e. the most recent version from
+	    which the two versions we're trying to merge are
+	    descended.</para>
+	</listitem>
+	<listitem><para id="x_352">In the middle is <quote>our</quote> version of
+	    the file, with the contents that we modified.</para>
+	</listitem>
+	<listitem><para id="x_353">On the right is <quote>their</quote> version
+	    of the file, the one that from the changeset that we're
+	    trying to merge with.</para>
+	</listitem></itemizedlist>
+      <para id="x_354">In the pane below these is the current
+	<emphasis>result</emphasis> of the merge. Our task is to
+	replace all of the red text, which indicates unresolved
+	conflicts, with some sensible merger of the
+	<quote>ours</quote> and <quote>theirs</quote> versions of the
+	file.</para>
+
+      <para id="x_355">All four of these panes are <emphasis>locked
+	  together</emphasis>; if we scroll vertically or horizontally
+	in any of them, the others are updated to display the
+	corresponding sections of their respective files.</para>
+
+      <figure id="fig:tour-merge:kdiff3">
+	<title>Using <command>kdiff3</command> to merge versions of a
+	  file</title>
+	<mediaobject>
+	  <imageobject>
+	    <imagedata width="100%" fileref="figs/kdiff3.png"/></imageobject>
+	  <textobject>
+	    <phrase>XXX add text</phrase>
+	  </textobject>
+	</mediaobject>
+      </figure>
+
+      <para id="x_357">For each conflicting portion of the file, we can choose to
+	resolve the conflict using some combination of text from the
+	base version, ours, or theirs.  We can also manually edit the
+	merged file at any time, in case we need to make further
+	modifications.</para>
+
+      <para id="x_358">There are <emphasis>many</emphasis> file merging tools
+	available, too many to cover here.  They vary in which
+	platforms they are available for, and in their particular
+	strengths and weaknesses.  Most are tuned for merging files
+	containing plain text, while a few are aimed at specialised
+	file formats (generally XML).</para>
+    </sect2>
+
+    <sect2>
+      <title>A worked example</title>
+
+      <para id="x_359">In this example, we will reproduce the file modification
+	history of <xref linkend="fig:tour-merge:conflict"/>
+	above.  Let's begin by creating a repository with a base
+	version of our document.</para>
+
+      &interaction.tour-merge-conflict.wife;
+
+      <para id="x_35a">We'll clone the repository and make a change to the
+	file.</para>
+
+      &interaction.tour-merge-conflict.cousin;
+
+      <para id="x_35b">And another clone, to simulate someone else making a
+	change to the file. (This hints at the idea that it's not all
+	that unusual to merge with yourself when you isolate tasks in
+	separate repositories, and indeed to find and resolve
+	conflicts while doing so.)</para>
+
+      &interaction.tour-merge-conflict.son;
+
+      <para id="x_35c">Having created two
+	different versions of the file, we'll set up an environment
+	suitable for running our merge.</para>
+
+      &interaction.tour-merge-conflict.pull;
+
+      <para id="x_35d">In this example, I'll set
+	<envar>HGMERGE</envar> to tell Mercurial to use the
+	non-interactive <command>merge</command> command.  This is
+	bundled with many Unix-like systems. (If you're following this
+	example on your computer, don't bother setting
+	<envar>HGMERGE</envar>.  You'll get dropped into a GUI file
+	merge tool instead, which is much preferable.)</para>
+
+      &interaction.tour-merge-conflict.merge;
+
+      <para id="x_35f">Because <command>merge</command> can't resolve the
+	conflicting changes, it leaves <emphasis>merge
+	  markers</emphasis> inside the file that has conflicts,
+	indicating which lines have conflicts, and whether they came
+	from our version of the file or theirs.</para>
+
+      <para id="x_360">Mercurial can tell from the way <command>merge</command>
+	exits that it wasn't able to merge successfully, so it tells
+	us what commands we'll need to run if we want to redo the
+	merging operation.  This could be useful if, for example, we
+	were running a graphical merge tool and quit because we were
+	confused or realised we had made a mistake.</para>
+
+      <para id="x_361">If automatic or manual merges fail, there's nothing to
+	prevent us from <quote>fixing up</quote> the affected files
+	ourselves, and committing the results of our merge:</para>
+
+      &interaction.tour-merge-conflict.commit;
+
+      <note>
+	<title>Where is the <command>hg resolve</command> command?</title>
+
+	<para id="x_724">The <command>hg resolve</command> command was introduced
+	  in Mercurial 1.1, which was released in December 2008. If
+	  you are using an older version of Mercurial (run <command>hg
+	    version</command> to see), this command will not be
+	  present.  If your version of Mercurial is older than 1.1,
+	  you should strongly consider upgrading to a newer version
+	  before trying to tackle complicated merges.</para>
+      </note>
+    </sect2>
+  </sect1>
+
+  <sect1 id="sec:tour-merge:fetch">
+    <title>Simplifying the pull-merge-commit sequence</title>
+
+    <para id="x_362">The process of merging changes as outlined above is
+      straightforward, but requires running three commands in
+      sequence.</para>
+    <programlisting>hg pull -u
+hg merge
+hg commit -m 'Merged remote changes'</programlisting>
+    <para id="x_363">In the case of the final commit, you also need to enter a
+      commit message, which is almost always going to be a piece of
+      uninteresting <quote>boilerplate</quote> text.</para>
+
+    <para id="x_364">It would be nice to reduce the number of steps needed, if
+      this were possible.  Indeed, Mercurial is distributed with an
+      extension called <literal role="hg-ext">fetch</literal> that
+      does just this.</para>
+
+    <para id="x_365">Mercurial provides a flexible extension mechanism that lets
+      people extend its functionality, while keeping the core of
+      Mercurial small and easy to deal with.  Some extensions add new
+      commands that you can use from the command line, while others
+      work <quote>behind the scenes,</quote> for example adding
+      capabilities to Mercurial's built-in server mode.</para>
+
+    <para id="x_366">The <literal role="hg-ext">fetch</literal>
+      extension adds a new command called, not surprisingly, <command
+	role="hg-cmd">hg fetch</command>.  This extension acts as a
+      combination of <command role="hg-cmd">hg pull -u</command>,
+      <command role="hg-cmd">hg merge</command> and <command
+	role="hg-cmd">hg commit</command>.  It begins by pulling
+      changes from another repository into the current repository.  If
+      it finds that the changes added a new head to the repository, it
+      updates to the new head, begins a merge, then (if the merge
+      succeeded) commits the result of the merge with an
+      automatically-generated commit message.  If no new heads were
+      added, it updates the working directory to the new tip
+      changeset.</para>
+
+    <para id="x_367">Enabling the <literal
+	role="hg-ext">fetch</literal> extension is easy.  Edit the
+      <filename role="special">.hgrc</filename> file in your home
+      directory, and either go to the <literal
+	role="rc-extensions">extensions</literal> section or create an
+      <literal role="rc-extensions">extensions</literal> section. Then
+      add a line that simply reads
+      <quote><literal>fetch=</literal></quote>.</para>
+
+    <programlisting>[extensions]
+fetch =</programlisting>
+
+    <para id="x_368">(Normally, the right-hand side of the
+      <quote><literal>=</literal></quote> would indicate where to find
+      the extension, but since the <literal
+	role="hg-ext">fetch</literal> extension is in the standard
+      distribution, Mercurial knows where to search for it.)</para>
+  </sect1>
+
+  <sect1>
+    <title>Renaming, copying, and merging</title>
+
+    <para id="x_729">During the life of a project, we will often want to change
+      the layout of its files and directories. This can be as simple
+      as renaming a single file, or as complex as restructuring the
+      entire hierarchy of files within the project.</para>
+
+    <para id="x_72a">Mercurial supports these kinds of complex changes fluently,
+      provided we tell it what we're doing.  If we want to rename a
+      file, we should use the <command>hg rename</command><footnote>
+	<para id="x_72b">If you're a Unix user, you'll be glad to know that the
+	  <command>hg rename</command> command can be abbreviated as
+	  <command>hg mv</command>.</para>
+      </footnote> command to rename it, so that Mercurial can do the
+      right thing later when we merge.</para>
+
+    <para id="x_72c">We will cover the use of these commands in more detail in
+      <xref linkend="chap:daily.copy"/>.</para>
+  </sect1>
+</chapter>
+
+<!--
+local variables: 
+sgml-parent-document: ("00book.xml" "book" "chapter")
+end:
+-->