hgbook

changeset 103:5b80c922ebdd

More merge content.
author Bryan O'Sullivan <bos@serpentine.com>
date Thu Oct 19 15:18:07 2006 -0700 (2006-10-19)
parents ff9dc8bc2a8b
children 32bf9a5f22c0
files en/99defs.tex en/Makefile en/examples/run-example en/examples/tour-merge-conflict en/kdiff3.png en/tour-merge-conflict.svg en/tour-merge.tex
line diff
     1.1 --- a/en/99defs.tex	Wed Oct 18 15:47:04 2006 -0700
     1.2 +++ b/en/99defs.tex	Thu Oct 19 15:18:07 2006 -0700
     1.3 @@ -108,7 +108,7 @@
     1.4  
     1.5  % Graphics inclusion.
     1.6  \ifpdf
     1.7 -  \newcommand{\grafix}[1]{\includegraphics{#1.pdf}}
     1.8 +  \newcommand{\grafix}[1]{\includegraphics{#1}}
     1.9  \else
    1.10    \newcommand{\grafix}[1]{\includegraphics{#1.png}}
    1.11  \fi
     2.1 --- a/en/Makefile	Wed Oct 18 15:47:04 2006 -0700
     2.2 +++ b/en/Makefile	Thu Oct 19 15:18:07 2006 -0700
     2.3 @@ -19,11 +19,15 @@
     2.4  	tour-merge.tex
     2.5  
     2.6  image-sources := \
     2.7 +	kdiff3.png \
     2.8  	mq-stack.svg \
     2.9  	tour-history.svg \
    2.10 -	tour-merge-sep-repos.svg \
    2.11 +	tour-merge-conflict.svg \
    2.12 +	tour-merge-merge.svg \
    2.13  	tour-merge-pull.svg \
    2.14 -	tour-merge-merge.svg
    2.15 +	tour-merge-sep-repos.svg
    2.16 +
    2.17 +image-svg := $(filter %.svg,$(image-sources))
    2.18  
    2.19  example-sources := \
    2.20  	daily.files \
    2.21 @@ -38,7 +42,8 @@
    2.22  	mq.tutorial \
    2.23  	template.simple \
    2.24  	template.svnstyle \
    2.25 -	tour
    2.26 +	tour \
    2.27 +	tour-merge-conflict
    2.28  
    2.29  latex-options = \
    2.30  	-interaction batchmode \
    2.31 @@ -134,5 +139,7 @@
    2.32  	echo -n $(hg_id) > build_id.tex
    2.33  
    2.34  clean:
    2.35 -	rm -rf beta html pdf *.eps *.pdf *.png *.aux *.dvi *.log *.out \
    2.36 +	rm -rf beta html pdf \
    2.37 +		$(image-svg:%.svg=%.pdf) \
    2.38 +		$(image-svg:%.svg=%.png) \
    2.39  		examples/*.{out,run} examples/.run build_id.tex
     3.1 --- a/en/examples/run-example	Wed Oct 18 15:47:04 2006 -0700
     3.2 +++ b/en/examples/run-example	Thu Oct 19 15:18:07 2006 -0700
     3.3 @@ -39,7 +39,8 @@
     3.4          
     3.5  class example:
     3.6      shell = '/usr/bin/env bash'
     3.7 -    prompt = '__run_example_prompt__ '
     3.8 +    ps1 = '__run_example_ps1__ '
     3.9 +    ps2 = '__run_example_ps2__ '
    3.10      pi_re = re.compile(r'#\$\s*(name):\s*(.*)$')
    3.11      
    3.12      timeout = 5
    3.13 @@ -99,21 +100,23 @@
    3.14                  s = self.read()
    3.15              except OSError, err:
    3.16                  if err.errno == errno.EIO:
    3.17 -                    return ''
    3.18 +                    return '', ''
    3.19                  raise
    3.20              if self.verbose:
    3.21                  print >> sys.stderr, self.debugrepr(s)
    3.22              out.write(s)
    3.23              s = out.getvalue()
    3.24 -            if s.endswith(self.prompt):
    3.25 -                return s.replace('\r\n', '\n')[:-len(self.prompt)]
    3.26 +            if s.endswith(self.ps1):
    3.27 +                return self.ps1, s.replace('\r\n', '\n')[:-len(self.ps1)]
    3.28 +            if s.endswith(self.ps2):
    3.29 +                return self.ps2, s.replace('\r\n', '\n')[:-len(self.ps2)]
    3.30          
    3.31      def sendreceive(self, s):
    3.32          self.send(s)
    3.33 -        r = self.receive()
    3.34 +        ps, r = self.receive()
    3.35          if r.startswith(s):
    3.36              r = r[len(s):]
    3.37 -        return r
    3.38 +        return ps, r
    3.39      
    3.40      def run(self):
    3.41          ofp = None
    3.42 @@ -128,8 +131,8 @@
    3.43          
    3.44          rcfile = os.path.join(tmpdir, '.bashrc')
    3.45          rcfp = open(rcfile, 'w')
    3.46 -        print >> rcfp, 'PS1="%s"' % self.prompt
    3.47 -        print >> rcfp, 'PS2="%s"' % self.prompt
    3.48 +        print >> rcfp, 'PS1="%s"' % self.ps1
    3.49 +        print >> rcfp, 'PS2="%s"' % self.ps2
    3.50          print >> rcfp, 'unset HISTFILE'
    3.51          print >> rcfp, 'export EXAMPLE_DIR="%s"' % os.getcwd()
    3.52          print >> rcfp, 'export LANG=C'
    3.53 @@ -153,12 +156,19 @@
    3.54                  os._exit(0)
    3.55          self.poll.register(self.cfd, select.POLLIN | select.POLLERR |
    3.56                             select.POLLHUP)
    3.57 +
    3.58 +        prompts = {
    3.59 +            '': '',
    3.60 +            self.ps1: '$',
    3.61 +            self.ps2: '>',
    3.62 +            }
    3.63 +
    3.64          try:
    3.65              try:
    3.66                  # eat first prompt string from shell
    3.67                  self.read()
    3.68                  # setup env and prompt
    3.69 -                self.sendreceive('source %s\n' % rcfile)
    3.70 +                ps, output = self.sendreceive('source %s\n' % rcfile)
    3.71                  for hunk in self.parse():
    3.72                      # is this line a processing instruction?
    3.73                      m = self.pi_re.match(hunk)
    3.74 @@ -174,18 +184,20 @@
    3.75                                  ofp = None
    3.76                      elif hunk.strip():
    3.77                          # it's something we should execute
    3.78 -                        output = self.sendreceive(hunk)
    3.79 +                        newps, output = self.sendreceive(hunk)
    3.80                          if not ofp:
    3.81                              continue
    3.82                          # first, print the command we ran
    3.83                          if not hunk.startswith('#'):
    3.84                              nl = hunk.endswith('\n')
    3.85 -                            hunk = ('$ \\textbf{%s}' %
    3.86 -                                    tex_escape(hunk.rstrip('\n')))
    3.87 +                            hunk = ('%s \\textbf{%s}' %
    3.88 +                                    (prompts[ps],
    3.89 +                                     tex_escape(hunk.rstrip('\n'))))
    3.90                              if nl: hunk += '\n'
    3.91                          ofp.write(hunk)
    3.92                          # then its output
    3.93                          ofp.write(tex_escape(output))
    3.94 +                    ps = newps
    3.95                  self.status('\n')
    3.96                  open(self.name + '.run', 'w')
    3.97              except:
    3.98 @@ -195,7 +207,7 @@
    3.99                  raise
   3.100              else:
   3.101                  try:
   3.102 -                    output = self.sendreceive('exit\n')
   3.103 +                    ps, output = self.sendreceive('exit\n')
   3.104                      if ofp:
   3.105                          ofp.write(output)
   3.106                      os.close(self.cfd)
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/en/examples/tour-merge-conflict	Thu Oct 19 15:18:07 2006 -0700
     4.3 @@ -0,0 +1,71 @@
     4.4 +#!/bin/bash
     4.5 +
     4.6 +hg init scam
     4.7 +cd scam
     4.8 +
     4.9 +#$ name: wife
    4.10 +
    4.11 +cat > letter.txt <<EOF
    4.12 +Greetings!
    4.13 +
    4.14 +I am Mariam Abacha, the wife of former
    4.15 +Nigerian dictator Sani Abacha.
    4.16 +EOF
    4.17 +
    4.18 +hg add letter.txt
    4.19 +hg commit -m '419 scam, first draft'
    4.20 +
    4.21 +#$ name: cousin
    4.22 +
    4.23 +cd ..
    4.24 +hg clone scam scam-cousin
    4.25 +cd scam-cousin
    4.26 +
    4.27 +cat > letter.txt <<EOF
    4.28 +Greetings!
    4.29 +
    4.30 +I am Shehu Musa Abacha, cousin to the former
    4.31 +Nigerian dictator Sani Abacha.
    4.32 +EOF
    4.33 +
    4.34 +hg commit -m '419 scam, with cousin'
    4.35 +
    4.36 +#$ name: son
    4.37 +
    4.38 +cd ..
    4.39 +hg clone scam scam-son
    4.40 +cd scam-son
    4.41 +
    4.42 +cat > letter.txt <<EOF
    4.43 +Greetings!
    4.44 +
    4.45 +I am Alhaji Abba Abacha, son of the former
    4.46 +Nigerian dictator Sani Abacha.
    4.47 +EOF
    4.48 +
    4.49 +hg commit -m '419 scam, with son'
    4.50 +
    4.51 +#$ name: pull
    4.52 +
    4.53 +cd ..
    4.54 +hg clone scam-cousin scam-merge
    4.55 +cd scam-merge
    4.56 +hg pull -u ../scam-son
    4.57 +
    4.58 +#$ name: merge
    4.59 +
    4.60 +export HGMERGE=merge
    4.61 +hg merge
    4.62 +cat letter.txt
    4.63 +
    4.64 +#$ name: commit
    4.65 +
    4.66 +cat > letter.txt <<EOF
    4.67 +Greetings!
    4.68 +
    4.69 +I am Bryan O'Sullivan, no relation of the former
    4.70 +Nigerian dictator Sani Abacha.
    4.71 +EOF
    4.72 +
    4.73 +hg commit -m 'Send me your money'
    4.74 +hg tip
     5.1 Binary file en/kdiff3.png has changed
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/en/tour-merge-conflict.svg	Thu Oct 19 15:18:07 2006 -0700
     6.3 @@ -0,0 +1,210 @@
     6.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
     6.5 +<!-- Created with Inkscape (http://www.inkscape.org/) -->
     6.6 +<svg
     6.7 +   xmlns:dc="http://purl.org/dc/elements/1.1/"
     6.8 +   xmlns:cc="http://web.resource.org/cc/"
     6.9 +   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    6.10 +   xmlns:svg="http://www.w3.org/2000/svg"
    6.11 +   xmlns="http://www.w3.org/2000/svg"
    6.12 +   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
    6.13 +   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
    6.14 +   width="744.09448819"
    6.15 +   height="1052.3622047"
    6.16 +   id="svg2"
    6.17 +   sodipodi:version="0.32"
    6.18 +   inkscape:version="0.44.1"
    6.19 +   sodipodi:docname="tour-merge-conflict.svg">
    6.20 +  <defs
    6.21 +     id="defs4">
    6.22 +    <marker
    6.23 +       inkscape:stockid="Arrow1Mend"
    6.24 +       orient="auto"
    6.25 +       refY="0.0"
    6.26 +       refX="0.0"
    6.27 +       id="Arrow1Mend"
    6.28 +       style="overflow:visible;">
    6.29 +      <path
    6.30 +         id="path3053"
    6.31 +         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
    6.32 +         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
    6.33 +         transform="scale(0.4) rotate(180) translate(10,0)" />
    6.34 +    </marker>
    6.35 +  </defs>
    6.36 +  <sodipodi:namedview
    6.37 +     id="base"
    6.38 +     pagecolor="#ffffff"
    6.39 +     bordercolor="#666666"
    6.40 +     borderopacity="1.0"
    6.41 +     gridtolerance="10000"
    6.42 +     guidetolerance="10"
    6.43 +     objecttolerance="10"
    6.44 +     inkscape:pageopacity="0.0"
    6.45 +     inkscape:pageshadow="2"
    6.46 +     inkscape:zoom="1.4"
    6.47 +     inkscape:cx="164.78349"
    6.48 +     inkscape:cy="590.07679"
    6.49 +     inkscape:document-units="px"
    6.50 +     inkscape:current-layer="layer1"
    6.51 +     inkscape:window-width="906"
    6.52 +     inkscape:window-height="620"
    6.53 +     inkscape:window-x="5"
    6.54 +     inkscape:window-y="49" />
    6.55 +  <metadata
    6.56 +     id="metadata7">
    6.57 +    <rdf:RDF>
    6.58 +      <cc:Work
    6.59 +         rdf:about="">
    6.60 +        <dc:format>image/svg+xml</dc:format>
    6.61 +        <dc:type
    6.62 +           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
    6.63 +      </cc:Work>
    6.64 +    </rdf:RDF>
    6.65 +  </metadata>
    6.66 +  <g
    6.67 +     inkscape:label="Layer 1"
    6.68 +     inkscape:groupmode="layer"
    6.69 +     id="layer1">
    6.70 +    <g
    6.71 +       id="g1988"
    6.72 +       transform="translate(84.85711,0)">
    6.73 +      <g
    6.74 +         id="g1876">
    6.75 +        <path
    6.76 +           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
    6.77 +           d="M 118.57143,458.21933 L 118.57143,563.79075 L 191.42857,563.79075 L 204.28571,550.93361 L 203.57142,459.6479 L 118.57143,458.21933 z "
    6.78 +           id="path1872"
    6.79 +           sodipodi:nodetypes="cccccc" />
    6.80 +        <path
    6.81 +           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
    6.82 +           d="M 191.55484,563.36862 L 191.6923,560.98794 L 192.69126,552.44884 L 203.80416,551.31242"
    6.83 +           id="path1874"
    6.84 +           sodipodi:nodetypes="cccc" />
    6.85 +      </g>
    6.86 +      <flowRoot
    6.87 +         style="font-size:8px;font-family:Times New Roman"
    6.88 +         id="flowRoot1898"
    6.89 +         xml:space="preserve"><flowRegion
    6.90 +           id="flowRegion1900"><rect
    6.91 +             style="font-size:8px;font-family:Times New Roman"
    6.92 +             y="464.50504"
    6.93 +             x="122.85714"
    6.94 +             height="93.571426"
    6.95 +             width="76.428574"
    6.96 +             id="rect1902" /></flowRegion><flowPara
    6.97 +           id="flowPara1904">Greetings!</flowPara><flowPara
    6.98 +           id="flowPara1906" /><flowPara
    6.99 +           id="flowPara1908">I am Mariam Abacha, the wife of former Nigerian dictator Sani Abacha. I am contacting you in confidence, and as a means of developing</flowPara></flowRoot>    </g>
   6.100 +    <g
   6.101 +       id="g1966"
   6.102 +       transform="translate(82,0.35715)">
   6.103 +      <g
   6.104 +         transform="translate(-77.85718,-140.0714)"
   6.105 +         id="g1910">
   6.106 +        <path
   6.107 +           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
   6.108 +           d="M 118.57143,458.21933 L 118.57143,563.79075 L 191.42857,563.79075 L 204.28571,550.93361 L 203.57142,459.6479 L 118.57143,458.21933 z "
   6.109 +           id="path1912"
   6.110 +           sodipodi:nodetypes="cccccc" />
   6.111 +        <path
   6.112 +           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
   6.113 +           d="M 191.55484,563.36862 L 191.6923,560.98794 L 192.69126,552.44884 L 203.80416,551.31242"
   6.114 +           id="path1914"
   6.115 +           sodipodi:nodetypes="cccc" />
   6.116 +      </g>
   6.117 +      <flowRoot
   6.118 +         transform="translate(-77.85718,-140.0714)"
   6.119 +         style="font-size:8px;font-family:Times New Roman"
   6.120 +         id="flowRoot1916"
   6.121 +         xml:space="preserve"><flowRegion
   6.122 +           id="flowRegion1918"><rect
   6.123 +             style="font-size:8px;font-family:Times New Roman"
   6.124 +             y="464.50504"
   6.125 +             x="122.85714"
   6.126 +             height="93.571426"
   6.127 +             width="76.428574"
   6.128 +             id="rect1920" /></flowRegion><flowPara
   6.129 +           id="flowPara1922">Greetings!</flowPara><flowPara
   6.130 +           id="flowPara1924" /><flowPara
   6.131 +           id="flowPara1926">I am <flowSpan
   6.132 +   style="font-style:italic;fill:red"
   6.133 +   id="flowSpan3094">Shehu Musa Abacha, cousin to</flowSpan> the former Nigerian dictator Sani Abacha. I am contacting you in confidence, and as a means of developing</flowPara></flowRoot>    </g>
   6.134 +    <g
   6.135 +       id="g1977"
   6.136 +       transform="translate(81.99999,-0.35715)">
   6.137 +      <g
   6.138 +         transform="translate(83.57141,-139.3571)"
   6.139 +         id="g1932">
   6.140 +        <path
   6.141 +           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
   6.142 +           d="M 118.57143,458.21933 L 118.57143,563.79075 L 191.42857,563.79075 L 204.28571,550.93361 L 203.57142,459.6479 L 118.57143,458.21933 z "
   6.143 +           id="path1934"
   6.144 +           sodipodi:nodetypes="cccccc" />
   6.145 +        <path
   6.146 +           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
   6.147 +           d="M 191.55484,563.36862 L 191.6923,560.98794 L 192.69126,552.44884 L 203.80416,551.31242"
   6.148 +           id="path1936"
   6.149 +           sodipodi:nodetypes="cccc" />
   6.150 +      </g>
   6.151 +      <flowRoot
   6.152 +         transform="translate(83.57141,-139.3571)"
   6.153 +         style="font-size:8px;font-family:Times New Roman"
   6.154 +         id="flowRoot1938"
   6.155 +         xml:space="preserve"><flowRegion
   6.156 +           id="flowRegion1940"><rect
   6.157 +             style="font-size:8px;font-family:Times New Roman"
   6.158 +             y="464.50504"
   6.159 +             x="122.85714"
   6.160 +             height="93.571426"
   6.161 +             width="76.428574"
   6.162 +             id="rect1942" /></flowRegion><flowPara
   6.163 +           id="flowPara1944">Greetings!</flowPara><flowPara
   6.164 +           id="flowPara1946" /><flowPara
   6.165 +           id="flowPara1948">I am <flowSpan
   6.166 +   style="font-style:italic;fill:red"
   6.167 +   id="flowSpan3096">Alhaji Abba Abacha, son of</flowSpan> the former Nigerian dictator Sani Abacha. I am contacting you in confidence, and as a means of developing</flowPara></flowRoot>    </g>
   6.168 +    <path
   6.169 +       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1"
   6.170 +       d="M 215.502,457.71933 L 196.35507,424.5765"
   6.171 +       id="path1999"
   6.172 +       inkscape:connector-type="polyline"
   6.173 +       inkscape:connection-start="#g1988"
   6.174 +       inkscape:connection-end="#g1966" />
   6.175 +    <path
   6.176 +       style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1"
   6.177 +       d="M 277.06936,457.71933 L 296.21629,424.5765"
   6.178 +       id="path2001"
   6.179 +       inkscape:connector-type="polyline"
   6.180 +       inkscape:connection-start="#g1988"
   6.181 +       inkscape:connection-end="#g1977" />
   6.182 +    <text
   6.183 +       xml:space="preserve"
   6.184 +       style="font-size:12px;font-style:normal;font-weight:normal;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman"
   6.185 +       x="302.42859"
   6.186 +       y="515.08905"
   6.187 +       id="text1905"><tspan
   6.188 +         sodipodi:role="line"
   6.189 +         id="tspan1907"
   6.190 +         x="302.42859"
   6.191 +         y="515.08905">Base version</tspan></text>
   6.192 +    <text
   6.193 +       xml:space="preserve"
   6.194 +       style="font-size:12px;font-style:normal;font-weight:normal;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman"
   6.195 +       x="45.57143"
   6.196 +       y="374.1619"
   6.197 +       id="text1917"><tspan
   6.198 +         sodipodi:role="line"
   6.199 +         id="tspan1919"
   6.200 +         x="45.57143"
   6.201 +         y="374.1619">Our changes</tspan></text>
   6.202 +    <text
   6.203 +       xml:space="preserve"
   6.204 +       style="font-size:12px;font-style:normal;font-weight:normal;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman"
   6.205 +       x="385.71429"
   6.206 +       y="374.1619"
   6.207 +       id="text1921"><tspan
   6.208 +         sodipodi:role="line"
   6.209 +         id="tspan1923"
   6.210 +         x="385.71429"
   6.211 +         y="374.1619">Their changes</tspan></text>
   6.212 +  </g>
   6.213 +</svg>
     7.1 --- a/en/tour-merge.tex	Wed Oct 18 15:47:04 2006 -0700
     7.2 +++ b/en/tour-merge.tex	Thu Oct 19 15:18:07 2006 -0700
     7.3 @@ -113,12 +113,126 @@
     7.4  \section{Merging conflicting changes}
     7.5  
     7.6  Most merges are simple affairs, but sometimes you'll find yourself
     7.7 -merging a change that you made with another, where both modify the
     7.8 -same portions of the same files.  Unless both modifications are
     7.9 -identical, this results in a \emph{conflict}, where you have to decide
    7.10 -how to reconcile the different changes into something coherent.
    7.11 -
    7.12 -\section{Using an extension to simplify merging}
    7.13 +merging changes where each modifies the same portions of the same
    7.14 +files.  Unless both modifications are identical, this results in a
    7.15 +\emph{conflict}, where you have to decide how to reconcile the
    7.16 +different changes into something coherent.
    7.17 +
    7.18 +\begin{figure}[ht]
    7.19 +  \centering
    7.20 +  \grafix{tour-merge-conflict}
    7.21 +  \caption{Conflicting changes to a document}
    7.22 +  \label{fig:tour-merge:conflict}
    7.23 +\end{figure}
    7.24 +
    7.25 +Figure~\ref{fig:tour-merge:conflict} illustrates an instance of two
    7.26 +conflicting changes to a document.  We started with a single version
    7.27 +of the file; then we made some changes; while someone else made
    7.28 +different changes to the same text.  Our task in resolving the
    7.29 +conflicting changes is to decide what the file should look like.
    7.30 +
    7.31 +Mercurial doesn't have a built-in facility for handling conflicts.
    7.32 +Instead, it runs an external program called \command{hgmerge}.  This
    7.33 +is a shell script that is bundled with Mercurial; you can change it to
    7.34 +behave however you please.  What it does by default is try to find one
    7.35 +of several different merging tools that are likely to be installed on
    7.36 +your system.  It first tries a few fully automatic merging tools; if
    7.37 +these don't succeed (because the resolution process requires human
    7.38 +guidance) or aren't present, the script tries a few different
    7.39 +graphical merging tools.
    7.40 +
    7.41 +It's also possible to get Mercurial to run another program or script
    7.42 +instead of \command{hgmerge}, by setting the \envar{HGMERGE}
    7.43 +environment variable to the name of your preferred program.
    7.44 +
    7.45 +\subsection{Using a graphical merge tool}
    7.46 +
    7.47 +My preferred graphical merge tool is \command{kdiff3}, which I'll use
    7.48 +to describe the features that are common to graphical file merging
    7.49 +tools.  You can see a screenshot of \command{kdiff3} in action in
    7.50 +figure~\ref{fig:tour-merge:kdiff3}.  The kind of merge it is
    7.51 +performing is called a \emph{three-way merge}, because there are three
    7.52 +different versions of the file of interest to us.  The tool thus
    7.53 +splits the upper portion of the window into three panes:
    7.54 +\begin{itemize}
    7.55 +\item At the left is the \emph{base} version of the file, i.e.~the
    7.56 +  most recent version from which the two versions we're trying to
    7.57 +  merge are descended.
    7.58 +\item In the middle is ``our'' version of the file, with the contents
    7.59 +  that we modified.
    7.60 +\item On the right is ``their'' version of the file, the one that
    7.61 +  from the changeset that we're trying to merge with.
    7.62 +\end{itemize}
    7.63 +In the pane below these is the current \emph{result} of the merge.
    7.64 +Our task is to replace all of the red text, which indicates unresolved
    7.65 +conflicts, with some sensible merger of the ``ours'' and ``theirs''
    7.66 +versions of the file.
    7.67 +
    7.68 +All four of these panes are \emph{locked together}; if we scroll
    7.69 +vertically or horizontally in any of them, the others are updated to
    7.70 +display the corresponding sections of their respective files.
    7.71 +
    7.72 +\begin{figure}[ht]
    7.73 +  \centering
    7.74 +  \grafix{kdiff3}
    7.75 +  \caption{Using \command{kdiff3} to merge versions of a file}
    7.76 +  \label{fig:tour-merge:kdiff3}
    7.77 +\end{figure}
    7.78 +
    7.79 +For each conflicting portion of the file, we can choose to resolve
    7.80 +thhe conflict using some combination of text from the base version,
    7.81 +ours, or theirs.  We can also manually edit the merged file at any
    7.82 +time, in case we need to make further modifications.
    7.83 +
    7.84 +There are \emph{many} file merging tools available, too many to cover
    7.85 +here.  They vary in which platforms they are available for, and in
    7.86 +their particular strengths and weaknesses.  Most are tuned for merging
    7.87 +files containing plain text, while a few are aimed at specialised file
    7.88 +formats (generally XML).
    7.89 +
    7.90 +\subsection{A worked example}
    7.91 +
    7.92 +In this example, we will reproduce the file modification history of
    7.93 +figure~\ref{fig:tour-merge:conflict} above.  Let's begin by creating a
    7.94 +repository with a base version of our document.
    7.95 +\interaction{tour-merge-conflict.wife}
    7.96 +We'll clone the repository and make a change to the file.
    7.97 +\interaction{tour-merge-conflict.cousin}
    7.98 +And another clone, to simulate someone else making a change to the
    7.99 +file.  (This hints at the idea that it's not all that unusual to merge
   7.100 +with yourself when you isolate tasks in separate repositories, and
   7.101 +indeed to find and resolve conflicts while doing so.)
   7.102 +\interaction{tour-merge-conflict.son}
   7.103 +Having created two different versions of the file, we'll set up an
   7.104 +environment suitable for running our merge.
   7.105 +\interaction{tour-merge-conflict.pull}
   7.106 +
   7.107 +In this example, I won't use Mercurial's normal \command{hgmerge}
   7.108 +program to do the merge, because it would drop my nice automated
   7.109 +example-running tool into a graphical user interface.  Instead, I'll
   7.110 +set \envar{HGMERGE} to tell Mercurial to use the non-interactive
   7.111 +\command{merge} command.  This is bundled with many Unix-like systems.
   7.112 +If you're following this example on your computer, don't bother
   7.113 +setting \envar{HGMERGE}.
   7.114 +\interaction{tour-merge-conflict.merge}
   7.115 +Because \command{merge} can't resolve the conflicting changes, it
   7.116 +leaves \emph{merge markers} inside the file that has conflicts,
   7.117 +indicating which lines have conflicts, and whether they came from our
   7.118 +version of the file or theirs.
   7.119 +
   7.120 +Mercurial can tell from the way \command{merge} exits that it wasn't
   7.121 +able to merge successfully, so it tells us what commands we'll need to
   7.122 +run if we want to redo the merging operation.  This could be useful
   7.123 +if, for example, we were running a graphical merge tool and quit
   7.124 +because we were confused or realised we had made a mistake.
   7.125 +
   7.126 +If automatic or manual merges fail, there's nothing to prevent us from
   7.127 +``fixing up'' the affected files ourselves, and committing the results
   7.128 +of our merge:
   7.129 +\interaction{tour-merge-conflict.commit}
   7.130 +
   7.131 +\section{Simplifying the pull-merge-commit 
   7.132 +  sequence}
   7.133  
   7.134  The process of merging changes as outlined above is straightforward,
   7.135  but requires running three commands in sequence.
   7.136 @@ -127,9 +241,9 @@
   7.137    hg merge
   7.138    hg commit -m 'Merged remote changes'
   7.139  \end{codesample2}
   7.140 -In the case of the final commit, you also need to come up with a
   7.141 -commit message, which is almost always going to be a piece of
   7.142 -uninteresting ``boilerplate'' text.
   7.143 +In the case of the final commit, you also need to enter a commit
   7.144 +message, which is almost always going to be a piece of uninteresting
   7.145 +``boilerplate'' text.
   7.146  
   7.147  It would be nice to reduce the number of steps needed, if this were
   7.148  possible.  Indeed, Mercurial is distributed with an extension called