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