hgbook
changeset 921:547d3aa25ef0
Initial copy from the english version, added package for french input.
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/fr/00book.tex Thu Feb 05 12:37:03 2009 +0100 1.3 @@ -0,0 +1,80 @@ 1.4 +% The use of oneside here is a temporary hack; \marginpar entries 1.5 +% don't show up on odd pages of PDF output without it. Sigh. 1.6 +\documentclass[oneside]{book} 1.7 +\usepackage{enumerate} 1.8 +\usepackage{fullpage} 1.9 +\usepackage{makeidx} 1.10 +\usepackage{ifpdf} 1.11 +\usepackage{graphicx} 1.12 +\usepackage{pslatex} 1.13 +\usepackage{fancyvrb} 1.14 +% adding package specific to the french version 1.15 +\usepackage[french]{babel} 1.16 +\usepackage[utf8]{inputenc} 1.17 +% leave hyperref until last 1.18 +\usepackage[colorlinks=true,bookmarks=true,pdftitle={Distributed 1.19 + revision control with Mercurial},pdfsubject={Revision 1.20 + control},pdfkeywords={Mercurial, Revision control, Distributed 1.21 + revision control},pdfauthor={Bryan O'Sullivan}]{hyperref} 1.22 + 1.23 +\include{99defs} 1.24 + 1.25 +\title{Gestion de source distribué avec Mercurial} \author{Bryan 1.26 + O'Sullivan} 1.27 +\date{Copyright \copyright\ 2006, 2007 Bryan O'Sullivan.\\ 1.28 + Ce document peut être librement distribué selon les termes et 1.29 + les conditions décrites dans la version 1.0 de la licence Open Publication. 1.30 + La licence est en annexe~\ref{chap:opl} de ce document.\\ 1.31 + 1.32 + Cette traduction a été généré depuis 1.33 + \href{http://hg.serpentine.com/mercurial/book/}{rev~\input{build_id}} 1.34 + avec \href{http://www.selenic.com/hg/}{rev~\input{hg_id}} of Mercurial.} 1.35 + 1.36 +\makeindex 1.37 + 1.38 +\begin{document} 1.39 + 1.40 +\maketitle 1.41 + 1.42 +\addcontentsline{toc}{chapter}{Contents} 1.43 +\pagenumbering{roman} 1.44 +\tableofcontents 1.45 +\listoffigures 1.46 +%\listoftables 1.47 + 1.48 +\pagenumbering{arabic} 1.49 + 1.50 +\include{preface} 1.51 +\include{intro} 1.52 +\include{tour-basic} 1.53 +\include{tour-merge} 1.54 +\include{concepts} 1.55 +\include{daily} 1.56 +\include{collab} 1.57 +\include{filenames} 1.58 +\include{branch} 1.59 +\include{undo} 1.60 +\include{hook} 1.61 +\include{template} 1.62 +\include{mq} 1.63 +\include{mq-collab} 1.64 +\include{hgext} 1.65 + 1.66 +\appendix 1.67 +\include{cmdref} 1.68 +\include{mq-ref} 1.69 +\include{srcinstall} 1.70 +\include{license} 1.71 +\addcontentsline{toc}{chapter}{Bibliography} 1.72 +\bibliographystyle{alpha} 1.73 +\bibliography{99book} 1.74 + 1.75 +\addcontentsline{toc}{chapter}{Index} 1.76 +\printindex 1.77 + 1.78 +\end{document} 1.79 + 1.80 +%%% Local Variables: 1.81 +%%% mode: latex 1.82 +%%% TeX-master: t 1.83 +%%% End:
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/fr/99book.bib Thu Feb 05 12:37:03 2009 +0100 2.3 @@ -0,0 +1,76 @@ 2.4 +@Unpublished{gruenbacher:2005, 2.5 + author = {Andreas Gruenbacher}, 2.6 + title = {How To Survive With Many Patches (Introduction to \texttt{quilt})}, 2.7 + year = {2005}, 2.8 + month = {June}, 2.9 + note = {\url{http://www.suse.de/~agruen/quilt.pdf}}, 2.10 +} 2.11 + 2.12 +@InProceedings{web:europython, 2.13 + author = {Bryan O'Sullivan}, 2.14 + title = {Achieving High Performance in Mercurial}, 2.15 + booktitle = {EuroPython Conference}, 2.16 + year = {2006}, 2.17 + month = {July}, 2.18 + note = {\url{XXX}}, 2.19 +} 2.20 + 2.21 +@Misc{web:diffstat, 2.22 + author = {Thomas Dickey}, 2.23 + title = {\texttt{diffstat}--make a histogram of \texttt{diff} output}, 2.24 + note = {\url{http://dickey.his.com/diffstat/diffstat.html}}, 2.25 +} 2.26 + 2.27 +@Misc{web:quilt, 2.28 + author = {Andreas Gruenbacher, Martin Quinson, Jean Delvare}, 2.29 + title = {Patchwork Quilt}, 2.30 + note = {\url{http://savannah.nongnu.org/projects/quilt}}, 2.31 +} 2.32 + 2.33 +@Misc{web:patchutils, 2.34 + author = {Tim Waugh}, 2.35 + title = {\texttt{patchutils}--programs that operate on patch files}, 2.36 + note = {\url{http://cyberelk.net/tim/patchutils/}}, 2.37 +} 2.38 + 2.39 +@Misc{web:mpatch, 2.40 + author = {Chris Mason}, 2.41 + title = {\texttt{mpatch}--help solve patch rejects}, 2.42 + note = {\url{http://oss.oracle.com/~mason/mpatch/}}, 2.43 +} 2.44 + 2.45 +@Misc{web:wiggle, 2.46 + author = {Neil Brown}, 2.47 + title = {\texttt{wiggle}--apply conflicting patches}, 2.48 + note = {\url{http://cgi.cse.unsw.edu.au/~neilb/source/wiggle/}}, 2.49 +} 2.50 + 2.51 +@Misc{web:mysql-python, 2.52 + author = {Andy Dustman}, 2.53 + title = {MySQL for Python}, 2.54 + note = {\url{http://sourceforge.net/projects/mysql-python}}, 2.55 +} 2.56 + 2.57 +@Misc{web:changelog, 2.58 + author = {Richard Stallman, GNU Project volunteers}, 2.59 + title = {GNU Coding Standards---Change Logs}, 2.60 + note = {\url{http://www.gnu.org/prep/standards/html_node/Change-Logs.html}}, 2.61 +} 2.62 + 2.63 +@Misc{web:macpython, 2.64 + author = {Bob Ippolito, Ronald Oussoren}, 2.65 + title = {Universal MacPython}, 2.66 + note = {\url{http://bob.pythonmac.org/archives/2006/04/10/python-and-universal-binaries-on-mac-os-x/}}, 2.67 +} 2.68 + 2.69 +@Misc{web:putty, 2.70 + author = {Simon Tatham}, 2.71 + title = {PuTTY---open source ssh client for Windows}, 2.72 + note = {\url{http://www.chiark.greenend.org.uk/~sgtatham/putty/}}, 2.73 +} 2.74 + 2.75 +@Misc{web:configparser, 2.76 + author = {Python.org}, 2.77 + title = {\texttt{ConfigParser}---Configuration file parser}, 2.78 + note = {\url{http://docs.python.org/lib/module-ConfigParser.html}}, 2.79 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/fr/99defs.tex Thu Feb 05 12:37:03 2009 +0100 3.3 @@ -0,0 +1,146 @@ 3.4 +% Bug ID. 3.5 +\newcommand{\bug}[1]{\index{Mercurial bug 3.6 + database!\href{http://www.selenic.com/mercurial/bts/issue#1}{bug 3.7 + ~#1}}\href{http://www.selenic.com/mercurial/bts/issue#1}{Mercurial 3.8 + bug no.~#1}} 3.9 + 3.10 +% File name in the user's home directory. 3.11 +\newcommand{\tildefile}[1]{\texttt{\~{}/#1}} 3.12 + 3.13 +% File name. 3.14 +\newcommand{\filename}[1]{\texttt{#1}} 3.15 + 3.16 +% Directory name. 3.17 +\newcommand{\dirname}[1]{\texttt{#1}} 3.18 + 3.19 +% File name, with index entry. 3.20 +% The ``s'' prefix comes from ``special''. 3.21 +\newcommand{\sfilename}[1]{\index{\texttt{#1} file}\texttt{#1}} 3.22 + 3.23 +% Directory name, with index entry. 3.24 +\newcommand{\sdirname}[1]{\index{\texttt{#1} directory}\texttt{#1}} 3.25 + 3.26 +% Mercurial extension. 3.27 +\newcommand{\hgext}[1]{\index{\texttt{#1} extension}\texttt{#1}} 3.28 + 3.29 +% Command provided by a Mercurial extension. 3.30 +\newcommand{\hgxcmd}[2]{\index{\texttt{#2} command (\texttt{#1} 3.31 + extension)}\index{\texttt{#1} extension!\texttt{#2} command}``\texttt{hg #2}''} 3.32 + 3.33 +% Mercurial command. 3.34 +\newcommand{\hgcmd}[1]{\index{\texttt{#1} command}``\texttt{hg #1}''} 3.35 + 3.36 +% Mercurial command, with arguments. 3.37 +\newcommand{\hgcmdargs}[2]{\index{\texttt{#1} command}``\texttt{hg #1 #2}''} 3.38 + 3.39 +\newcommand{\tplkword}[1]{\index{\texttt{#1} template keyword}\index{template keywords!\texttt{#1}}\texttt{#1}} 3.40 + 3.41 +\newcommand{\tplkwfilt}[2]{\index{\texttt{#1} template keyword!\texttt{#2} 3.42 + filter}\index{template filters!\texttt{#2}}\index{\texttt{#2} 3.43 + template filter}\texttt{#2}} 3.44 + 3.45 +\newcommand{\tplfilter}[1]{\index{template 3.46 + filters!\texttt{#1}}\index{\texttt{#1} template 3.47 + filter}\texttt{#1}} 3.48 + 3.49 +% Shell/system command. 3.50 +\newcommand{\command}[1]{\index{\texttt{#1} system command}\texttt{#1}} 3.51 + 3.52 +% Shell/system command, with arguments. 3.53 +\newcommand{\cmdargs}[2]{\index{\texttt{#1} system command}``\texttt{#1 #2}''} 3.54 + 3.55 +% Mercurial command option. 3.56 +\newcommand{\hgopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}} 3.57 + 3.58 +% Mercurial command option, provided by an extension command. 3.59 +\newcommand{\hgxopt}[3]{\index{\texttt{#2} command (\texttt{#1} extension)!\texttt{#3} option}\index{\texttt{#1} extension!\texttt{#2} command!\texttt{#3} option}\texttt{#3}} 3.60 + 3.61 +% Mercurial global option. 3.62 +\newcommand{\hggopt}[1]{\index{global options!\texttt{#1} option}\texttt{#1}} 3.63 + 3.64 +% Shell/system command option. 3.65 +\newcommand{\cmdopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}} 3.66 + 3.67 +% Command option. 3.68 +\newcommand{\option}[1]{\texttt{#1}} 3.69 + 3.70 +% Software package. 3.71 +\newcommand{\package}[1]{\index{\texttt{#1} package}\texttt{#1}} 3.72 + 3.73 +% Section name from a hgrc file. 3.74 +\newcommand{\rcsection}[1]{\index{\texttt{hgrc} file!\texttt{#1} section}\texttt{[#1]}} 3.75 + 3.76 +% Named item in a hgrc file section. 3.77 +\newcommand{\rcitem}[2]{\index{\texttt{hgrc} file!\texttt{#1} 3.78 + section!\texttt{#2} entry}\texttt{#2}} 3.79 + 3.80 +% hgrc file. 3.81 +\newcommand{\hgrc}{\index{configuration file!\texttt{hgrc} 3.82 + (Linux/Unix)}\index{\texttt{hgrc} configuration file}\texttt{hgrc}} 3.83 + 3.84 +% Mercurial.ini file. 3.85 +\newcommand{\hgini}{\index{configuration file!\texttt{Mercurial.ini} 3.86 + (Windows)}\index{\texttt{Mercurial.ini} configuration file}\texttt{Mercurial.ini}} 3.87 + 3.88 +% Hook name. 3.89 +\newcommand{\hook}[1]{\index{\texttt{#1} hook}\index{hooks!\texttt{#1}}\texttt{#1}} 3.90 + 3.91 +% Environment variable. 3.92 +\newcommand{\envar}[1]{\index{\texttt{#1} environment 3.93 + variable}\index{environment variables!\texttt{#1}}\texttt{#1}} 3.94 + 3.95 +% Python module. 3.96 +\newcommand{\pymod}[1]{\index{\texttt{#1} module}\texttt{#1}} 3.97 + 3.98 +% Python class in a module. 3.99 +\newcommand{\pymodclass}[2]{\index{\texttt{#1} module!\texttt{#2} 3.100 + class}\texttt{#1.#2}} 3.101 + 3.102 +% Python function in a module. 3.103 +\newcommand{\pymodfunc}[2]{\index{\texttt{#1} module!\texttt{#2} 3.104 + function}\texttt{#1.#2}} 3.105 + 3.106 +% Note: blah blah. 3.107 +\newsavebox{\notebox} 3.108 +\newenvironment{note}% 3.109 + {\begin{lrbox}{\notebox}\begin{minipage}{0.7\textwidth}\textbf{Note:}\space}% 3.110 + {\end{minipage}\end{lrbox}\fbox{\usebox{\notebox}}} 3.111 +\newenvironment{caution}% 3.112 + {\begin{lrbox}{\notebox}\begin{minipage}{0.7\textwidth}\textbf{Caution:}\space}% 3.113 + {\end{minipage}\end{lrbox}\fbox{\usebox{\notebox}}} 3.114 + 3.115 +% Code sample, eating 4 characters of leading space. 3.116 +\DefineVerbatimEnvironment{codesample4}{Verbatim}{frame=single,gobble=4,numbers=left,commandchars=\\\{\}} 3.117 + 3.118 +% Code sample, eating 2 characters of leading space. 3.119 +\DefineVerbatimEnvironment{codesample2}{Verbatim}{frame=single,gobble=2,numbers=left,commandchars=\\\{\}} 3.120 + 3.121 +% Interaction from the examples directory. 3.122 +\newcommand{\interaction}[1]{\VerbatimInput[frame=single,numbers=left,commandchars=\\\{\}]{examples/#1.lxo}} 3.123 +% Example code from the examples directory. 3.124 +\newcommand{\excode}[1]{\VerbatimInput[frame=single,numbers=left,commandchars=\\\{\}]{../examples/#1}} 3.125 + 3.126 +% Graphics inclusion. 3.127 +\ifpdf 3.128 + \newcommand{\grafix}[1]{\includegraphics{#1}} 3.129 +\else 3.130 + \newcommand{\grafix}[1]{\includegraphics{#1.png}} 3.131 +\fi 3.132 + 3.133 +% Reference entry for a command. 3.134 +\newcommand{\cmdref}[2]{\section{\hgcmd{#1}---#2}\label{cmdref:#1}\index{\texttt{#1} command}} 3.135 + 3.136 +% Reference entry for a command option with long and short forms. 3.137 +\newcommand{\optref}[3]{\subsubsection{\hgopt{#1}{--#3}, also \hgopt{#1}{-#2}}} 3.138 + 3.139 +% Reference entry for a command option with only long form. 3.140 +\newcommand{\loptref}[2]{\subsubsection{\hgopt{#1}{--#2} option}} 3.141 + 3.142 +% command to generate a footnote to be used as a translator's note 3.143 +\newcommand{\ndt}[1]{\footnote{\textbf{N. del T.} #1}} 3.144 + 3.145 + 3.146 +%%% Local Variables: 3.147 +%%% mode: latex 3.148 +%%% TeX-master: "00book" 3.149 +%%% End:
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/fr/Makefile Thu Feb 05 12:37:03 2009 +0100 4.3 @@ -0,0 +1,220 @@ 4.4 +# This makefile requires GNU make. 4.5 + 4.6 +sources := \ 4.7 + 00book.tex \ 4.8 + 99book.bib \ 4.9 + 99defs.tex \ 4.10 + build_id.tex \ 4.11 + branch.tex \ 4.12 + cmdref.tex \ 4.13 + collab.tex \ 4.14 + concepts.tex \ 4.15 + daily.tex \ 4.16 + filenames.tex \ 4.17 + hg_id.tex \ 4.18 + hgext.tex \ 4.19 + hook.tex \ 4.20 + intro.tex \ 4.21 + mq.tex \ 4.22 + mq-collab.tex \ 4.23 + mq-ref.tex \ 4.24 + preface.tex \ 4.25 + srcinstall.tex \ 4.26 + template.tex \ 4.27 + tour-basic.tex \ 4.28 + tour-merge.tex \ 4.29 + undo.tex 4.30 + 4.31 +image-sources := \ 4.32 + feature-branches.dot \ 4.33 + filelog.svg \ 4.34 + kdiff3.png \ 4.35 + metadata.svg \ 4.36 + mq-stack.svg \ 4.37 + note.png \ 4.38 + revlog.svg \ 4.39 + snapshot.svg \ 4.40 + tour-history.svg \ 4.41 + tour-merge-conflict.svg \ 4.42 + tour-merge-merge.svg \ 4.43 + tour-merge-pull.svg \ 4.44 + tour-merge-sep-repos.svg \ 4.45 + undo-manual.dot \ 4.46 + undo-manual-merge.dot \ 4.47 + undo-non-tip.dot \ 4.48 + undo-simple.dot \ 4.49 + wdir.svg \ 4.50 + wdir-after-commit.svg \ 4.51 + wdir-branch.svg \ 4.52 + wdir-merge.svg \ 4.53 + wdir-pre-branch.svg 4.54 + 4.55 +image-dot := $(filter %.dot,$(image-sources)) 4.56 +image-svg := $(filter %.svg,$(image-sources)) 4.57 +image-png := $(filter %.png,$(image-sources)) 4.58 + 4.59 +image-pdf := $(image-dot:%.dot=%.pdf) $(image-svg:%.svg=%.pdf) $(image-png) 4.60 +image-html := $(image-dot:%.dot=%.png) $(image-svg:%.svg=%.png) $(image-png) 4.61 + 4.62 +example-sources := \ 4.63 + backout \ 4.64 + bisect \ 4.65 + branching \ 4.66 + branch-named \ 4.67 + branch-repo \ 4.68 + cmdref \ 4.69 + daily.copy \ 4.70 + daily.files \ 4.71 + daily.rename \ 4.72 + daily.revert \ 4.73 + extdiff \ 4.74 + filenames \ 4.75 + hook.msglen \ 4.76 + hook.simple \ 4.77 + hook.ws \ 4.78 + issue29 \ 4.79 + mq.guards \ 4.80 + mq.qinit-help \ 4.81 + mq.dodiff \ 4.82 + mq.id \ 4.83 + mq.tarball \ 4.84 + mq.tools \ 4.85 + mq.tutorial \ 4.86 + rename.divergent \ 4.87 + rollback \ 4.88 + tag \ 4.89 + template.simple \ 4.90 + template.svnstyle \ 4.91 + tour \ 4.92 + tour-merge-conflict 4.93 + 4.94 +example-prereqs := \ 4.95 + /usr/bin/merge 4.96 + 4.97 +dist-sources := \ 4.98 + ../html/hgicon.png \ 4.99 + ../html/index.html.var \ 4.100 + ../html/index.en.html 4.101 + 4.102 +latex-options = \ 4.103 + -interaction batchmode \ 4.104 + -output-directory $(dir $(1)) \ 4.105 + -jobname $(basename $(notdir $(1))) 4.106 + 4.107 +hg = $(shell which hg) 4.108 + 4.109 +hg-id = $(shell hg parents --template '{node|short}, dated {date|isodate},\n') 4.110 + 4.111 +hg-version = $(shell hg version -q | \ 4.112 + sed 's,.*(version \(unknown\|[a-f0-9+]*\)),\1,') 4.113 + 4.114 +all: pdf html 4.115 + 4.116 +pdf: pdf/hgbook.pdf 4.117 + 4.118 +define pdf 4.119 + mkdir -p $(dir $@) 4.120 + TEXINPUTS=$(dir $<): pdflatex $(call latex-options,$@) $< || (rm -f $@; exit 1) 4.121 + cp 99book.bib $(dir $@) 4.122 + cd $(dir $@) && bibtex $(basename $(notdir $@)) 4.123 + cd $(dir $@) && makeindex $(basename $(notdir $@)) 4.124 + TEXINPUTS=$(dir $<): pdflatex $(call latex-options,$@) $< || (rm -f $@; exit 1) 4.125 + TEXINPUTS=$(dir $<): pdflatex $(call latex-options,$@) $< || (rm -f $@; exit 1) 4.126 + if grep 'Reference.*undefined' $(@:.pdf=.log); then exit 1; fi 4.127 +endef 4.128 + 4.129 +pdf/hgbook.pdf: $(sources) examples $(image-pdf) 4.130 + $(call pdf) 4.131 + 4.132 +html: onepage split 4.133 + 4.134 +onepage: $(htlatex) html/onepage/hgbook.html html/onepage/hgbook.css $(image-html:%=html/onepage/%) 4.135 + 4.136 +html/onepage/%: % 4.137 + cp $< $@ 4.138 + 4.139 +split: $(htlatex) html/split/hgbook.html html/split/hgbook.css $(image-html:%=html/split/%) 4.140 + 4.141 +html/split/%: % 4.142 + cp $< $@ 4.143 + 4.144 +# This is a horrible hack to work around the fact that the htlatex 4.145 +# command in tex4ht is itself a horrible hack. I really don't want to 4.146 +# include verbatim the big wad of TeX that is repeated in that script, 4.147 +# but I've given up and run a hacked copy as htlatex.book here. 4.148 + 4.149 +define htlatex 4.150 + mkdir -p $(dir $(1)) 4.151 + cp 99book.bib $(dir $(1)) 4.152 + TEXINPUTS=$(dir $(2)): ./htlatex.book $(2) "bookhtml,html4-uni,$(3)" " -cunihtf -utf8" "$(dir $(1))" "$(call latex-options,$(1))" || (rm -f $(1); exit 1) 4.153 + cd $(dir $(1)) && tex4ht -f/$(basename $(notdir $(1))) -cvalidate -cunihtf 4.154 + cd $(dir $(1)) && t4ht -f/$(basename $(notdir $(1))) 4.155 + ./fixhtml.py $(dir $(1))/*.html 4.156 + rm $(dir $(1))/hgbook.css 4.157 +endef 4.158 + 4.159 +html/onepage/hgbook.html: $(sources) examples $(image-html) bookhtml.cfg 4.160 + $(call htlatex,$@,$<) 4.161 + 4.162 +html/split/hgbook.html: $(sources) examples bookhtml.cfg 4.163 + $(call htlatex,$@,$<,2) 4.164 + 4.165 +# Produce 90dpi PNGs for the web. 4.166 + 4.167 +%.png: %.svg fixsvg 4.168 + ./fixsvg $< 4.169 + inkscape -D -e $@ $<-tmp.svg 4.170 + rm $<-tmp.svg 4.171 + 4.172 +%.svg: %.dot 4.173 + dot -Tsvg -o $@ $< 4.174 + 4.175 +# Produce eps & pdf for the pdf 4.176 + 4.177 +%.pdf: %.eps 4.178 + epstopdf $< 4.179 + 4.180 +%.eps: %.svg 4.181 + ./fixsvg $< 4.182 + inkscape -E $@ $<-tmp.svg 4.183 + rm $<-tmp.svg 4.184 + 4.185 +%.eps: %.dot 4.186 + dot -Tps -o $@ $< 4.187 + 4.188 +examples: $(example-prereqs) examples/.run 4.189 + 4.190 +examples/.run: $(example-sources:%=examples/%.run) 4.191 + touch examples/.run 4.192 + 4.193 +examples/%.run: examples/% examples/run-example 4.194 + cd examples && ./run-example $(notdir $<) 4.195 + 4.196 +changelog := $(wildcard ../.hg/store/00changelog.[id]) 4.197 +ifeq ($(changelog),) 4.198 +changelog := $(wildcard ../.hg/00changelog.[id]) 4.199 +endif 4.200 + 4.201 +build_id.tex: $(changelog) 4.202 + echo -n '$(hg-id)' > build_id.tex 4.203 + 4.204 +hg_id.tex: $(hg) 4.205 + echo -n '$(hg-version)' > hg_id.tex 4.206 + 4.207 +clean: 4.208 + rm -rf dist html pdf \ 4.209 + $(image-dot:%.dot=%.pdf) \ 4.210 + $(image-dot:%.dot=%.png) \ 4.211 + $(image-svg:%.svg=%.pdf) \ 4.212 + $(image-svg:%.svg=%.png) \ 4.213 + examples/*.{lxo,run} examples/.run build_id.tex hg_id.tex 4.214 + 4.215 +install: pdf split $(dist-sources) 4.216 + rm -rf dist 4.217 + mkdir -p dist 4.218 + cp pdf/hgbook.pdf dist 4.219 + cp html/split/*.{css,html,png} dist 4.220 + cp $(dist-sources) dist 4.221 + 4.222 +rsync: install 4.223 + rsync -avz --delete dist sp.red-bean.com:public_html/hgbook
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/fr/bookhtml.cfg Thu Feb 05 12:37:03 2009 +0100 5.3 @@ -0,0 +1,18 @@ 5.4 +% -*- latex -*- 5.5 + 5.6 +\Preamble{xhtml} 5.7 + 5.8 +% Tex4ht's default definition of lists is complete crap. 5.9 +% Unfortunately, it can't distinguish between "ul" and "dl" lists. 5.10 + 5.11 +\ConfigureList{itemize}% 5.12 + {\EndP\HCode{<ul>}\let\endItem=\empty} 5.13 + {\ifvmode \IgnorePar\fi 5.14 + \EndP\HCode{</li></ul>}\ShowPar} 5.15 + {\endItem \def\endItem{\EndP\Tg</span>}\HCode{<li><span class="dt">}} 5.16 + {\HCode{</span><span class="dd">}} 5.17 +\def\textbullet{} 5.18 + 5.19 +\begin{document} 5.20 + 5.21 +\EndPreamble
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/fr/branch.tex Thu Feb 05 12:37:03 2009 +0100 6.3 @@ -0,0 +1,392 @@ 6.4 +\chapter{Managing releases and branchy development} 6.5 +\label{chap:branch} 6.6 + 6.7 +Mercurial provides several mechanisms for you to manage a project that 6.8 +is making progress on multiple fronts at once. To understand these 6.9 +mechanisms, let's first take a brief look at a fairly normal software 6.10 +project structure. 6.11 + 6.12 +Many software projects issue periodic ``major'' releases that contain 6.13 +substantial new features. In parallel, they may issue ``minor'' 6.14 +releases. These are usually identical to the major releases off which 6.15 +they're based, but with a few bugs fixed. 6.16 + 6.17 +In this chapter, we'll start by talking about how to keep records of 6.18 +project milestones such as releases. We'll then continue on to talk 6.19 +about the flow of work between different phases of a project, and how 6.20 +Mercurial can help you to isolate and manage this work. 6.21 + 6.22 +\section{Giving a persistent name to a revision} 6.23 + 6.24 +Once you decide that you'd like to call a particular revision a 6.25 +``release'', it's a good idea to record the identity of that revision. 6.26 +This will let you reproduce that release at a later date, for whatever 6.27 +purpose you might need at the time (reproducing a bug, porting to a 6.28 +new platform, etc). 6.29 +\interaction{tag.init} 6.30 + 6.31 +Mercurial lets you give a permanent name to any revision using the 6.32 +\hgcmd{tag} command. Not surprisingly, these names are called 6.33 +``tags''. 6.34 +\interaction{tag.tag} 6.35 + 6.36 +A tag is nothing more than a ``symbolic name'' for a revision. Tags 6.37 +exist purely for your convenience, so that you have a handy permanent 6.38 +way to refer to a revision; Mercurial doesn't interpret the tag names 6.39 +you use in any way. Neither does Mercurial place any restrictions on 6.40 +the name of a tag, beyond a few that are necessary to ensure that a 6.41 +tag can be parsed unambiguously. A tag name cannot contain any of the 6.42 +following characters: 6.43 +\begin{itemize} 6.44 +\item Colon (ASCII 58, ``\texttt{:}'') 6.45 +\item Carriage return (ASCII 13, ``\Verb+\r+'') 6.46 +\item Newline (ASCII 10, ``\Verb+\n+'') 6.47 +\end{itemize} 6.48 + 6.49 +You can use the \hgcmd{tags} command to display the tags present in 6.50 +your repository. In the output, each tagged revision is identified 6.51 +first by its name, then by revision number, and finally by the unique 6.52 +hash of the revision. 6.53 +\interaction{tag.tags} 6.54 +Notice that \texttt{tip} is listed in the output of \hgcmd{tags}. The 6.55 +\texttt{tip} tag is a special ``floating'' tag, which always 6.56 +identifies the newest revision in the repository. 6.57 + 6.58 +In the output of the \hgcmd{tags} command, tags are listed in reverse 6.59 +order, by revision number. This usually means that recent tags are 6.60 +listed before older tags. It also means that \texttt{tip} is always 6.61 +going to be the first tag listed in the output of \hgcmd{tags}. 6.62 + 6.63 +When you run \hgcmd{log}, if it displays a revision that has tags 6.64 +associated with it, it will print those tags. 6.65 +\interaction{tag.log} 6.66 + 6.67 +Any time you need to provide a revision~ID to a Mercurial command, the 6.68 +command will accept a tag name in its place. Internally, Mercurial 6.69 +will translate your tag name into the corresponding revision~ID, then 6.70 +use that. 6.71 +\interaction{tag.log.v1.0} 6.72 + 6.73 +There's no limit on the number of tags you can have in a repository, 6.74 +or on the number of tags that a single revision can have. As a 6.75 +practical matter, it's not a great idea to have ``too many'' (a number 6.76 +which will vary from project to project), simply because tags are 6.77 +supposed to help you to find revisions. If you have lots of tags, the 6.78 +ease of using them to identify revisions diminishes rapidly. 6.79 + 6.80 +For example, if your project has milestones as frequent as every few 6.81 +days, it's perfectly reasonable to tag each one of those. But if you 6.82 +have a continuous build system that makes sure every revision can be 6.83 +built cleanly, you'd be introducing a lot of noise if you were to tag 6.84 +every clean build. Instead, you could tag failed builds (on the 6.85 +assumption that they're rare!), or simply not use tags to track 6.86 +buildability. 6.87 + 6.88 +If you want to remove a tag that you no longer want, use 6.89 +\hgcmdargs{tag}{--remove}. 6.90 +\interaction{tag.remove} 6.91 +You can also modify a tag at any time, so that it identifies a 6.92 +different revision, by simply issuing a new \hgcmd{tag} command. 6.93 +You'll have to use the \hgopt{tag}{-f} option to tell Mercurial that 6.94 +you \emph{really} want to update the tag. 6.95 +\interaction{tag.replace} 6.96 +There will still be a permanent record of the previous identity of the 6.97 +tag, but Mercurial will no longer use it. There's thus no penalty to 6.98 +tagging the wrong revision; all you have to do is turn around and tag 6.99 +the correct revision once you discover your error. 6.100 + 6.101 +Mercurial stores tags in a normal revision-controlled file in your 6.102 +repository. If you've created any tags, you'll find them in a file 6.103 +named \sfilename{.hgtags}. When you run the \hgcmd{tag} command, 6.104 +Mercurial modifies this file, then automatically commits the change to 6.105 +it. This means that every time you run \hgcmd{tag}, you'll see a 6.106 +corresponding changeset in the output of \hgcmd{log}. 6.107 +\interaction{tag.tip} 6.108 + 6.109 +\subsection{Handling tag conflicts during a merge} 6.110 + 6.111 +You won't often need to care about the \sfilename{.hgtags} file, but 6.112 +it sometimes makes its presence known during a merge. The format of 6.113 +the file is simple: it consists of a series of lines. Each line 6.114 +starts with a changeset hash, followed by a space, followed by the 6.115 +name of a tag. 6.116 + 6.117 +If you're resolving a conflict in the \sfilename{.hgtags} file during 6.118 +a merge, there's one twist to modifying the \sfilename{.hgtags} file: 6.119 +when Mercurial is parsing the tags in a repository, it \emph{never} 6.120 +reads the working copy of the \sfilename{.hgtags} file. Instead, it 6.121 +reads the \emph{most recently committed} revision of the file. 6.122 + 6.123 +An unfortunate consequence of this design is that you can't actually 6.124 +verify that your merged \sfilename{.hgtags} file is correct until 6.125 +\emph{after} you've committed a change. So if you find yourself 6.126 +resolving a conflict on \sfilename{.hgtags} during a merge, be sure to 6.127 +run \hgcmd{tags} after you commit. If it finds an error in the 6.128 +\sfilename{.hgtags} file, it will report the location of the error, 6.129 +which you can then fix and commit. You should then run \hgcmd{tags} 6.130 +again, just to be sure that your fix is correct. 6.131 + 6.132 +\subsection{Tags and cloning} 6.133 + 6.134 +You may have noticed that the \hgcmd{clone} command has a 6.135 +\hgopt{clone}{-r} option that lets you clone an exact copy of the 6.136 +repository as of a particular changeset. The new clone will not 6.137 +contain any project history that comes after the revision you 6.138 +specified. This has an interaction with tags that can surprise the 6.139 +unwary. 6.140 + 6.141 +Recall that a tag is stored as a revision to the \sfilename{.hgtags} 6.142 +file, so that when you create a tag, the changeset in which it's 6.143 +recorded necessarily refers to an older changeset. When you run 6.144 +\hgcmdargs{clone}{-r foo} to clone a repository as of tag 6.145 +\texttt{foo}, the new clone \emph{will not contain the history that 6.146 + created the tag} that you used to clone the repository. The result 6.147 +is that you'll get exactly the right subset of the project's history 6.148 +in the new repository, but \emph{not} the tag you might have expected. 6.149 + 6.150 +\subsection{When permanent tags are too much} 6.151 + 6.152 +Since Mercurial's tags are revision controlled and carried around with 6.153 +a project's history, everyone you work with will see the tags you 6.154 +create. But giving names to revisions has uses beyond simply noting 6.155 +that revision \texttt{4237e45506ee} is really \texttt{v2.0.2}. If 6.156 +you're trying to track down a subtle bug, you might want a tag to 6.157 +remind you of something like ``Anne saw the symptoms with this 6.158 +revision''. 6.159 + 6.160 +For cases like this, what you might want to use are \emph{local} tags. 6.161 +You can create a local tag with the \hgopt{tag}{-l} option to the 6.162 +\hgcmd{tag} command. This will store the tag in a file called 6.163 +\sfilename{.hg/localtags}. Unlike \sfilename{.hgtags}, 6.164 +\sfilename{.hg/localtags} is not revision controlled. Any tags you 6.165 +create using \hgopt{tag}{-l} remain strictly local to the repository 6.166 +you're currently working in. 6.167 + 6.168 +\section{The flow of changes---big picture vs. little} 6.169 + 6.170 +To return to the outline I sketched at the beginning of a chapter, 6.171 +let's think about a project that has multiple concurrent pieces of 6.172 +work under development at once. 6.173 + 6.174 +There might be a push for a new ``main'' release; a new minor bugfix 6.175 +release to the last main release; and an unexpected ``hot fix'' to an 6.176 +old release that is now in maintenance mode. 6.177 + 6.178 +The usual way people refer to these different concurrent directions of 6.179 +development is as ``branches''. However, we've already seen numerous 6.180 +times that Mercurial treats \emph{all of history} as a series of 6.181 +branches and merges. Really, what we have here is two ideas that are 6.182 +peripherally related, but which happen to share a name. 6.183 +\begin{itemize} 6.184 +\item ``Big picture'' branches represent the sweep of a project's 6.185 + evolution; people give them names, and talk about them in 6.186 + conversation. 6.187 +\item ``Little picture'' branches are artefacts of the day-to-day 6.188 + activity of developing and merging changes. They expose the 6.189 + narrative of how the code was developed. 6.190 +\end{itemize} 6.191 + 6.192 +\section{Managing big-picture branches in repositories} 6.193 + 6.194 +The easiest way to isolate a ``big picture'' branch in Mercurial is in 6.195 +a dedicated repository. If you have an existing shared 6.196 +repository---let's call it \texttt{myproject}---that reaches a ``1.0'' 6.197 +milestone, you can start to prepare for future maintenance releases on 6.198 +top of version~1.0 by tagging the revision from which you prepared 6.199 +the~1.0 release. 6.200 +\interaction{branch-repo.tag} 6.201 +You can then clone a new shared \texttt{myproject-1.0.1} repository as 6.202 +of that tag. 6.203 +\interaction{branch-repo.clone} 6.204 + 6.205 +Afterwards, if someone needs to work on a bug fix that ought to go 6.206 +into an upcoming~1.0.1 minor release, they clone the 6.207 +\texttt{myproject-1.0.1} repository, make their changes, and push them 6.208 +back. 6.209 +\interaction{branch-repo.bugfix} 6.210 +Meanwhile, development for the next major release can continue, 6.211 +isolated and unabated, in the \texttt{myproject} repository. 6.212 +\interaction{branch-repo.new} 6.213 + 6.214 +\section{Don't repeat yourself: merging across branches} 6.215 + 6.216 +In many cases, if you have a bug to fix on a maintenance branch, the 6.217 +chances are good that the bug exists on your project's main branch 6.218 +(and possibly other maintenance branches, too). It's a rare developer 6.219 +who wants to fix the same bug multiple times, so let's look at a few 6.220 +ways that Mercurial can help you to manage these bugfixes without 6.221 +duplicating your work. 6.222 + 6.223 +In the simplest instance, all you need to do is pull changes from your 6.224 +maintenance branch into your local clone of the target branch. 6.225 +\interaction{branch-repo.pull} 6.226 +You'll then need to merge the heads of the two branches, and push back 6.227 +to the main branch. 6.228 +\interaction{branch-repo.merge} 6.229 + 6.230 +\section{Naming branches within one repository} 6.231 + 6.232 +In most instances, isolating branches in repositories is the right 6.233 +approach. Its simplicity makes it easy to understand; and so it's 6.234 +hard to make mistakes. There's a one-to-one relationship between 6.235 +branches you're working in and directories on your system. This lets 6.236 +you use normal (non-Mercurial-aware) tools to work on files within a 6.237 +branch/repository. 6.238 + 6.239 +If you're more in the ``power user'' category (\emph{and} your 6.240 +collaborators are too), there is an alternative way of handling 6.241 +branches that you can consider. I've already mentioned the 6.242 +human-level distinction between ``small picture'' and ``big picture'' 6.243 +branches. While Mercurial works with multiple ``small picture'' 6.244 +branches in a repository all the time (for example after you pull 6.245 +changes in, but before you merge them), it can \emph{also} work with 6.246 +multiple ``big picture'' branches. 6.247 + 6.248 +The key to working this way is that Mercurial lets you assign a 6.249 +persistent \emph{name} to a branch. There always exists a branch 6.250 +named \texttt{default}. Even before you start naming branches 6.251 +yourself, you can find traces of the \texttt{default} branch if you 6.252 +look for them. 6.253 + 6.254 +As an example, when you run the \hgcmd{commit} command, and it pops up 6.255 +your editor so that you can enter a commit message, look for a line 6.256 +that contains the text ``\texttt{HG: branch default}'' at the bottom. 6.257 +This is telling you that your commit will occur on the branch named 6.258 +\texttt{default}. 6.259 + 6.260 +To start working with named branches, use the \hgcmd{branches} 6.261 +command. This command lists the named branches already present in 6.262 +your repository, telling you which changeset is the tip of each. 6.263 +\interaction{branch-named.branches} 6.264 +Since you haven't created any named branches yet, the only one that 6.265 +exists is \texttt{default}. 6.266 + 6.267 +To find out what the ``current'' branch is, run the \hgcmd{branch} 6.268 +command, giving it no arguments. This tells you what branch the 6.269 +parent of the current changeset is on. 6.270 +\interaction{branch-named.branch} 6.271 + 6.272 +To create a new branch, run the \hgcmd{branch} command again. This 6.273 +time, give it one argument: the name of the branch you want to create. 6.274 +\interaction{branch-named.create} 6.275 + 6.276 +After you've created a branch, you might wonder what effect the 6.277 +\hgcmd{branch} command has had. What do the \hgcmd{status} and 6.278 +\hgcmd{tip} commands report? 6.279 +\interaction{branch-named.status} 6.280 +Nothing has changed in the working directory, and there's been no new 6.281 +history created. As this suggests, running the \hgcmd{branch} command 6.282 +has no permanent effect; it only tells Mercurial what branch name to 6.283 +use the \emph{next} time you commit a changeset. 6.284 + 6.285 +When you commit a change, Mercurial records the name of the branch on 6.286 +which you committed. Once you've switched from the \texttt{default} 6.287 +branch to another and committed, you'll see the name of the new branch 6.288 +show up in the output of \hgcmd{log}, \hgcmd{tip}, and other commands 6.289 +that display the same kind of output. 6.290 +\interaction{branch-named.commit} 6.291 +The \hgcmd{log}-like commands will print the branch name of every 6.292 +changeset that's not on the \texttt{default} branch. As a result, if 6.293 +you never use named branches, you'll never see this information. 6.294 + 6.295 +Once you've named a branch and committed a change with that name, 6.296 +every subsequent commit that descends from that change will inherit 6.297 +the same branch name. You can change the name of a branch at any 6.298 +time, using the \hgcmd{branch} command. 6.299 +\interaction{branch-named.rebranch} 6.300 +In practice, this is something you won't do very often, as branch 6.301 +names tend to have fairly long lifetimes. (This isn't a rule, just an 6.302 +observation.) 6.303 + 6.304 +\section{Dealing with multiple named branches in a repository} 6.305 + 6.306 +If you have more than one named branch in a repository, Mercurial will 6.307 +remember the branch that your working directory on when you start a 6.308 +command like \hgcmd{update} or \hgcmdargs{pull}{-u}. It will update 6.309 +the working directory to the tip of this branch, no matter what the 6.310 +``repo-wide'' tip is. To update to a revision that's on a different 6.311 +named branch, you may need to use the \hgopt{update}{-C} option to 6.312 +\hgcmd{update}. 6.313 + 6.314 +This behaviour is a little subtle, so let's see it in action. First, 6.315 +let's remind ourselves what branch we're currently on, and what 6.316 +branches are in our repository. 6.317 +\interaction{branch-named.parents} 6.318 +We're on the \texttt{bar} branch, but there also exists an older 6.319 +\hgcmd{foo} branch. 6.320 + 6.321 +We can \hgcmd{update} back and forth between the tips of the 6.322 +\texttt{foo} and \texttt{bar} branches without needing to use the 6.323 +\hgopt{update}{-C} option, because this only involves going backwards 6.324 +and forwards linearly through our change history. 6.325 +\interaction{branch-named.update-switchy} 6.326 + 6.327 +If we go back to the \texttt{foo} branch and then run \hgcmd{update}, 6.328 +it will keep us on \texttt{foo}, not move us to the tip of 6.329 +\texttt{bar}. 6.330 +\interaction{branch-named.update-nothing} 6.331 + 6.332 +Committing a new change on the \texttt{foo} branch introduces a new 6.333 +head. 6.334 +\interaction{branch-named.foo-commit} 6.335 + 6.336 +\section{Branch names and merging} 6.337 + 6.338 +As you've probably noticed, merges in Mercurial are not symmetrical. 6.339 +Let's say our repository has two heads, 17 and 23. If I 6.340 +\hgcmd{update} to 17 and then \hgcmd{merge} with 23, Mercurial records 6.341 +17 as the first parent of the merge, and 23 as the second. Whereas if 6.342 +I \hgcmd{update} to 23 and then \hgcmd{merge} with 17, it records 23 6.343 +as the first parent, and 17 as the second. 6.344 + 6.345 +This affects Mercurial's choice of branch name when you merge. After 6.346 +a merge, Mercurial will retain the branch name of the first parent 6.347 +when you commit the result of the merge. If your first parent's 6.348 +branch name is \texttt{foo}, and you merge with \texttt{bar}, the 6.349 +branch name will still be \texttt{foo} after you merge. 6.350 + 6.351 +It's not unusual for a repository to contain multiple heads, each with 6.352 +the same branch name. Let's say I'm working on the \texttt{foo} 6.353 +branch, and so are you. We commit different changes; I pull your 6.354 +changes; I now have two heads, each claiming to be on the \texttt{foo} 6.355 +branch. The result of a merge will be a single head on the 6.356 +\texttt{foo} branch, as you might hope. 6.357 + 6.358 +But if I'm working on the \texttt{bar} branch, and I merge work from 6.359 +the \texttt{foo} branch, the result will remain on the \texttt{bar} 6.360 +branch. 6.361 +\interaction{branch-named.merge} 6.362 + 6.363 +To give a more concrete example, if I'm working on the 6.364 +\texttt{bleeding-edge} branch, and I want to bring in the latest fixes 6.365 +from the \texttt{stable} branch, Mercurial will choose the ``right'' 6.366 +(\texttt{bleeding-edge}) branch name when I pull and merge from 6.367 +\texttt{stable}. 6.368 + 6.369 +\section{Branch naming is generally useful} 6.370 + 6.371 +You shouldn't think of named branches as applicable only to situations 6.372 +where you have multiple long-lived branches cohabiting in a single 6.373 +repository. They're very useful even in the one-branch-per-repository 6.374 +case. 6.375 + 6.376 +In the simplest case, giving a name to each branch gives you a 6.377 +permanent record of which branch a changeset originated on. This 6.378 +gives you more context when you're trying to follow the history of a 6.379 +long-lived branchy project. 6.380 + 6.381 +If you're working with shared repositories, you can set up a 6.382 +\hook{pretxnchangegroup} hook on each that will block incoming changes 6.383 +that have the ``wrong'' branch name. This provides a simple, but 6.384 +effective, defence against people accidentally pushing changes from a 6.385 +``bleeding edge'' branch to a ``stable'' branch. Such a hook might 6.386 +look like this inside the shared repo's \hgrc. 6.387 +\begin{codesample2} 6.388 + [hooks] 6.389 + pretxnchangegroup.branch = hg heads --template '{branches} ' | grep mybranch 6.390 +\end{codesample2} 6.391 + 6.392 +%%% Local Variables: 6.393 +%%% mode: latex 6.394 +%%% TeX-master: "00book" 6.395 +%%% End:
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/fr/cmdref.py Thu Feb 05 12:37:03 2009 +0100 7.3 @@ -0,0 +1,156 @@ 7.4 +#!/usr/bin/env python 7.5 + 7.6 +import getopt 7.7 +import itertools 7.8 +import os 7.9 +import re 7.10 +import sys 7.11 + 7.12 +def usage(exitcode): 7.13 + print >> sys.stderr, ('usage: %s [-H|--hidden] hg_repo' % 7.14 + os.path.basename(sys.argv[0])) 7.15 + sys.exit(exitcode) 7.16 + 7.17 +try: 7.18 + opts, args = getopt.getopt(sys.argv[1:], 'AHh?', ['all', 'help', 'hidden']) 7.19 + opt_all = False 7.20 + opt_hidden = False 7.21 + for o, a in opts: 7.22 + if o in ('-h', '-?', '--help'): 7.23 + usage(0) 7.24 + if o in ('-A', '--all'): 7.25 + opt_all = True 7.26 + if o in ('-H', '--hidden'): 7.27 + opt_hidden = True 7.28 +except getopt.GetoptError, err: 7.29 + print >> sys.stderr, 'error:', err 7.30 + usage(1) 7.31 + 7.32 +try: 7.33 + hg_repo, ltx_file = args 7.34 +except ValueError: 7.35 + usage(1) 7.36 + 7.37 +if not os.path.isfile(os.path.join(hg_repo, 'mercurial', 'commands.py')): 7.38 + print >> sys.stderr, ('error: %r does not contain mercurial code' % 7.39 + hg_repo) 7.40 + sys.exit(1) 7.41 + 7.42 +sys.path.insert(0, hg_repo) 7.43 + 7.44 +from mercurial import commands 7.45 + 7.46 +def get_commands(): 7.47 + seen = {} 7.48 + for name, info in sorted(commands.table.iteritems()): 7.49 + aliases = name.split('|', 1) 7.50 + name = aliases.pop(0).lstrip('^') 7.51 + function, options, synopsis = info 7.52 + seen[name] = {} 7.53 + for shortopt, longopt, arg, desc in options: 7.54 + seen[name][longopt] = shortopt 7.55 + return seen 7.56 + 7.57 +def cmd_filter((name, aliases, options)): 7.58 + if opt_all: 7.59 + return True 7.60 + if opt_hidden: 7.61 + return name.startswith('debug') 7.62 + return not name.startswith('debug') 7.63 + 7.64 +def scan(ltx_file): 7.65 + cmdref_re = re.compile(r'^\\cmdref{(?P<cmd>\w+)}') 7.66 + optref_re = re.compile(r'^\\l?optref{(?P<cmd>\w+)}' 7.67 + r'(?:{(?P<short>[^}])})?' 7.68 + r'{(?P<long>[^}]+)}') 7.69 + 7.70 + seen = {} 7.71 + locs = {} 7.72 + for lnum, line in enumerate(open(ltx_file)): 7.73 + m = cmdref_re.match(line) 7.74 + if m: 7.75 + d = m.groupdict() 7.76 + cmd = d['cmd'] 7.77 + seen[cmd] = {} 7.78 + locs[cmd] = lnum + 1 7.79 + continue 7.80 + m = optref_re.match(line) 7.81 + if m: 7.82 + d = m.groupdict() 7.83 + seen[d['cmd']][d['long']] = d['short'] 7.84 + continue 7.85 + return seen, locs 7.86 + 7.87 +documented, locs = scan(ltx_file) 7.88 +known = get_commands() 7.89 + 7.90 +doc_set = set(documented) 7.91 +known_set = set(known) 7.92 + 7.93 +errors = 0 7.94 + 7.95 +for nonexistent in sorted(doc_set.difference(known_set)): 7.96 + print >> sys.stderr, ('%s:%d: %r command does not exist' % 7.97 + (ltx_file, locs[nonexistent], nonexistent)) 7.98 + errors += 1 7.99 + 7.100 +def optcmp(a, b): 7.101 + la, sa = a 7.102 + lb, sb = b 7.103 + sc = cmp(sa, sb) 7.104 + if sc: 7.105 + return sc 7.106 + return cmp(la, lb) 7.107 + 7.108 +for cmd in doc_set.intersection(known_set): 7.109 + doc_opts = documented[cmd] 7.110 + known_opts = known[cmd] 7.111 + 7.112 + do_set = set(doc_opts) 7.113 + ko_set = set(known_opts) 7.114 + 7.115 + for nonexistent in sorted(do_set.difference(ko_set)): 7.116 + print >> sys.stderr, ('%s:%d: %r option to %r command does not exist' % 7.117 + (ltx_file, locs[cmd], nonexistent, cmd)) 7.118 + errors += 1 7.119 + 7.120 + def mycmp(la, lb): 7.121 + sa = known_opts[la] 7.122 + sb = known_opts[lb] 7.123 + return optcmp((la, sa), (lb, sb)) 7.124 + 7.125 + for undocumented in sorted(ko_set.difference(do_set), cmp=mycmp): 7.126 + print >> sys.stderr, ('%s:%d: %r option to %r command not documented' % 7.127 + (ltx_file, locs[cmd], undocumented, cmd)) 7.128 + shortopt = known_opts[undocumented] 7.129 + if shortopt: 7.130 + print '\optref{%s}{%s}{%s}' % (cmd, shortopt, undocumented) 7.131 + else: 7.132 + print '\loptref{%s}{%s}' % (cmd, undocumented) 7.133 + errors += 1 7.134 + sys.stdout.flush() 7.135 + 7.136 +if errors: 7.137 + sys.exit(1) 7.138 + 7.139 +sorted_locs = sorted(locs.iteritems(), key=lambda x:x[1]) 7.140 + 7.141 +def next_loc(cmd): 7.142 + for i, (name, loc) in enumerate(sorted_locs): 7.143 + if name >= cmd: 7.144 + return sorted_locs[i-1][1] + 1 7.145 + return loc 7.146 + 7.147 +for undocumented in sorted(known_set.difference(doc_set)): 7.148 + print >> sys.stderr, ('%s:%d: %r command not documented' % 7.149 + (ltx_file, next_loc(undocumented), undocumented)) 7.150 + print '\cmdref{%s}' % undocumented 7.151 + for longopt, shortopt in sorted(known[undocumented].items(), cmp=optcmp): 7.152 + if shortopt: 7.153 + print '\optref{%s}{%s}{%s}' % (undocumented, shortopt, longopt) 7.154 + else: 7.155 + print '\loptref{%s}{%s}' % (undocumented, longopt) 7.156 + sys.stdout.flush() 7.157 + errors += 1 7.158 + 7.159 +sys.exit(errors and 1 or 0)
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/fr/cmdref.tex Thu Feb 05 12:37:03 2009 +0100 8.3 @@ -0,0 +1,176 @@ 8.4 +\chapter{Command reference} 8.5 +\label{cmdref} 8.6 + 8.7 +\cmdref{add}{add files at the next commit} 8.8 +\optref{add}{I}{include} 8.9 +\optref{add}{X}{exclude} 8.10 +\optref{add}{n}{dry-run} 8.11 + 8.12 +\cmdref{diff}{print changes in history or working directory} 8.13 + 8.14 +Show differences between revisions for the specified files or 8.15 +directories, using the unified diff format. For a description of the 8.16 +unified diff format, see section~\ref{sec:mq:patch}. 8.17 + 8.18 +By default, this command does not print diffs for files that Mercurial 8.19 +considers to contain binary data. To control this behaviour, see the 8.20 +\hgopt{diff}{-a} and \hgopt{diff}{--git} options. 8.21 + 8.22 +\subsection{Options} 8.23 + 8.24 +\loptref{diff}{nodates} 8.25 + 8.26 +Omit date and time information when printing diff headers. 8.27 + 8.28 +\optref{diff}{B}{ignore-blank-lines} 8.29 + 8.30 +Do not print changes that only insert or delete blank lines. A line 8.31 +that contains only whitespace is not considered blank. 8.32 + 8.33 +\optref{diff}{I}{include} 8.34 + 8.35 +Include files and directories whose names match the given patterns. 8.36 + 8.37 +\optref{diff}{X}{exclude} 8.38 + 8.39 +Exclude files and directories whose names match the given patterns. 8.40 + 8.41 +\optref{diff}{a}{text} 8.42 + 8.43 +If this option is not specified, \hgcmd{diff} will refuse to print 8.44 +diffs for files that it detects as binary. Specifying \hgopt{diff}{-a} 8.45 +forces \hgcmd{diff} to treat all files as text, and generate diffs for 8.46 +all of them. 8.47 + 8.48 +This option is useful for files that are ``mostly text'' but have a 8.49 +few embedded NUL characters. If you use it on files that contain a 8.50 +lot of binary data, its output will be incomprehensible. 8.51 + 8.52 +\optref{diff}{b}{ignore-space-change} 8.53 + 8.54 +Do not print a line if the only change to that line is in the amount 8.55 +of white space it contains. 8.56 + 8.57 +\optref{diff}{g}{git} 8.58 + 8.59 +Print \command{git}-compatible diffs. XXX reference a format 8.60 +description. 8.61 + 8.62 +\optref{diff}{p}{show-function} 8.63 + 8.64 +Display the name of the enclosing function in a hunk header, using a 8.65 +simple heuristic. This functionality is enabled by default, so the 8.66 +\hgopt{diff}{-p} option has no effect unless you change the value of 8.67 +the \rcitem{diff}{showfunc} config item, as in the following example. 8.68 +\interaction{cmdref.diff-p} 8.69 + 8.70 +\optref{diff}{r}{rev} 8.71 + 8.72 +Specify one or more revisions to compare. The \hgcmd{diff} command 8.73 +accepts up to two \hgopt{diff}{-r} options to specify the revisions to 8.74 +compare. 8.75 + 8.76 +\begin{enumerate} 8.77 +\setcounter{enumi}{0} 8.78 +\item Display the differences between the parent revision of the 8.79 + working directory and the working directory. 8.80 +\item Display the differences between the specified changeset and the 8.81 + working directory. 8.82 +\item Display the differences between the two specified changesets. 8.83 +\end{enumerate} 8.84 + 8.85 +You can specify two revisions using either two \hgopt{diff}{-r} 8.86 +options or revision range notation. For example, the two revision 8.87 +specifications below are equivalent. 8.88 +\begin{codesample2} 8.89 + hg diff -r 10 -r 20 8.90 + hg diff -r10:20 8.91 +\end{codesample2} 8.92 + 8.93 +When you provide two revisions, Mercurial treats the order of those 8.94 +revisions as significant. Thus, \hgcmdargs{diff}{-r10:20} will 8.95 +produce a diff that will transform files from their contents as of 8.96 +revision~10 to their contents as of revision~20, while 8.97 +\hgcmdargs{diff}{-r20:10} means the opposite: the diff that will 8.98 +transform files from their revision~20 contents to their revision~10 8.99 +contents. You cannot reverse the ordering in this way if you are 8.100 +diffing against the working directory. 8.101 + 8.102 +\optref{diff}{w}{ignore-all-space} 8.103 + 8.104 +\cmdref{version}{print version and copyright information} 8.105 + 8.106 +This command displays the version of Mercurial you are running, and 8.107 +its copyright license. There are four kinds of version string that 8.108 +you may see. 8.109 +\begin{itemize} 8.110 +\item The string ``\texttt{unknown}''. This version of Mercurial was 8.111 + not built in a Mercurial repository, and cannot determine its own 8.112 + version. 8.113 +\item A short numeric string, such as ``\texttt{1.1}''. This is a 8.114 + build of a revision of Mercurial that was identified by a specific 8.115 + tag in the repository where it was built. (This doesn't necessarily 8.116 + mean that you're running an official release; someone else could 8.117 + have added that tag to any revision in the repository where they 8.118 + built Mercurial.) 8.119 +\item A hexadecimal string, such as ``\texttt{875489e31abe}''. This 8.120 + is a build of the given revision of Mercurial. 8.121 +\item A hexadecimal string followed by a date, such as 8.122 + ``\texttt{875489e31abe+20070205}''. This is a build of the given 8.123 + revision of Mercurial, where the build repository contained some 8.124 + local changes that had not been committed. 8.125 +\end{itemize} 8.126 + 8.127 +\subsection{Tips and tricks} 8.128 + 8.129 +\subsubsection{Why do the results of \hgcmd{diff} and \hgcmd{status} 8.130 + differ?} 8.131 +\label{cmdref:diff-vs-status} 8.132 + 8.133 +When you run the \hgcmd{status} command, you'll see a list of files 8.134 +that Mercurial will record changes for the next time you perform a 8.135 +commit. If you run the \hgcmd{diff} command, you may notice that it 8.136 +prints diffs for only a \emph{subset} of the files that \hgcmd{status} 8.137 +listed. There are two possible reasons for this. 8.138 + 8.139 +The first is that \hgcmd{status} prints some kinds of modifications 8.140 +that \hgcmd{diff} doesn't normally display. The \hgcmd{diff} command 8.141 +normally outputs unified diffs, which don't have the ability to 8.142 +represent some changes that Mercurial can track. Most notably, 8.143 +traditional diffs can't represent a change in whether or not a file is 8.144 +executable, but Mercurial records this information. 8.145 + 8.146 +If you use the \hgopt{diff}{--git} option to \hgcmd{diff}, it will 8.147 +display \command{git}-compatible diffs that \emph{can} display this 8.148 +extra information. 8.149 + 8.150 +The second possible reason that \hgcmd{diff} might be printing diffs 8.151 +for a subset of the files displayed by \hgcmd{status} is that if you 8.152 +invoke it without any arguments, \hgcmd{diff} prints diffs against the 8.153 +first parent of the working directory. If you have run \hgcmd{merge} 8.154 +to merge two changesets, but you haven't yet committed the results of 8.155 +the merge, your working directory has two parents (use \hgcmd{parents} 8.156 +to see them). While \hgcmd{status} prints modifications relative to 8.157 +\emph{both} parents after an uncommitted merge, \hgcmd{diff} still 8.158 +operates relative only to the first parent. You can get it to print 8.159 +diffs relative to the second parent by specifying that parent with the 8.160 +\hgopt{diff}{-r} option. There is no way to print diffs relative to 8.161 +both parents. 8.162 + 8.163 +\subsubsection{Generating safe binary diffs} 8.164 + 8.165 +If you use the \hgopt{diff}{-a} option to force Mercurial to print 8.166 +diffs of files that are either ``mostly text'' or contain lots of 8.167 +binary data, those diffs cannot subsequently be applied by either 8.168 +Mercurial's \hgcmd{import} command or the system's \command{patch} 8.169 +command. 8.170 + 8.171 +If you want to generate a diff of a binary file that is safe to use as 8.172 +input for \hgcmd{import}, use the \hgcmd{diff}{--git} option when you 8.173 +generate the patch. The system \command{patch} command cannot handle 8.174 +binary patches at all. 8.175 + 8.176 +%%% Local Variables: 8.177 +%%% mode: latex 8.178 +%%% TeX-master: "00book" 8.179 +%%% End:
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/fr/collab.tex Thu Feb 05 12:37:03 2009 +0100 9.3 @@ -0,0 +1,1118 @@ 9.4 +\chapter{Collaborating with other people} 9.5 +\label{cha:collab} 9.6 + 9.7 +As a completely decentralised tool, Mercurial doesn't impose any 9.8 +policy on how people ought to work with each other. However, if 9.9 +you're new to distributed revision control, it helps to have some 9.10 +tools and examples in mind when you're thinking about possible 9.11 +workflow models. 9.12 + 9.13 +\section{Mercurial's web interface} 9.14 + 9.15 +Mercurial has a powerful web interface that provides several 9.16 +useful capabilities. 9.17 + 9.18 +For interactive use, the web interface lets you browse a single 9.19 +repository or a collection of repositories. You can view the history 9.20 +of a repository, examine each change (comments and diffs), and view 9.21 +the contents of each directory and file. 9.22 + 9.23 +Also for human consumption, the web interface provides an RSS feed of 9.24 +the changes in a repository. This lets you ``subscribe'' to a 9.25 +repository using your favourite feed reader, and be automatically 9.26 +notified of activity in that repository as soon as it happens. I find 9.27 +this capability much more convenient than the model of subscribing to 9.28 +a mailing list to which notifications are sent, as it requires no 9.29 +additional configuration on the part of whoever is serving the 9.30 +repository. 9.31 + 9.32 +The web interface also lets remote users clone a repository, pull 9.33 +changes from it, and (when the server is configured to permit it) push 9.34 +changes back to it. Mercurial's HTTP tunneling protocol aggressively 9.35 +compresses data, so that it works efficiently even over low-bandwidth 9.36 +network connections. 9.37 + 9.38 +The easiest way to get started with the web interface is to use your 9.39 +web browser to visit an existing repository, such as the master 9.40 +Mercurial repository at 9.41 +\url{http://www.selenic.com/repo/hg?style=gitweb}. 9.42 + 9.43 +If you're interested in providing a web interface to your own 9.44 +repositories, Mercurial provides two ways to do this. The first is 9.45 +using the \hgcmd{serve} command, which is best suited to short-term 9.46 +``lightweight'' serving. See section~\ref{sec:collab:serve} below for 9.47 +details of how to use this command. If you have a long-lived 9.48 +repository that you'd like to make permanently available, Mercurial 9.49 +has built-in support for the CGI (Common Gateway Interface) standard, 9.50 +which all common web servers support. See 9.51 +section~\ref{sec:collab:cgi} for details of CGI configuration. 9.52 + 9.53 +\section{Collaboration models} 9.54 + 9.55 +With a suitably flexible tool, making decisions about workflow is much 9.56 +more of a social engineering challenge than a technical one. 9.57 +Mercurial imposes few limitations on how you can structure the flow of 9.58 +work in a project, so it's up to you and your group to set up and live 9.59 +with a model that matches your own particular needs. 9.60 + 9.61 +\subsection{Factors to keep in mind} 9.62 + 9.63 +The most important aspect of any model that you must keep in mind is 9.64 +how well it matches the needs and capabilities of the people who will 9.65 +be using it. This might seem self-evident; even so, you still can't 9.66 +afford to forget it for a moment. 9.67 + 9.68 +I once put together a workflow model that seemed to make perfect sense 9.69 +to me, but that caused a considerable amount of consternation and 9.70 +strife within my development team. In spite of my attempts to explain 9.71 +why we needed a complex set of branches, and how changes ought to flow 9.72 +between them, a few team members revolted. Even though they were 9.73 +smart people, they didn't want to pay attention to the constraints we 9.74 +were operating under, or face the consequences of those constraints in 9.75 +the details of the model that I was advocating. 9.76 + 9.77 +Don't sweep foreseeable social or technical problems under the rug. 9.78 +Whatever scheme you put into effect, you should plan for mistakes and 9.79 +problem scenarios. Consider adding automated machinery to prevent, or 9.80 +quickly recover from, trouble that you can anticipate. As an example, 9.81 +if you intend to have a branch with not-for-release changes in it, 9.82 +you'd do well to think early about the possibility that someone might 9.83 +accidentally merge those changes into a release branch. You could 9.84 +avoid this particular problem by writing a hook that prevents changes 9.85 +from being merged from an inappropriate branch. 9.86 + 9.87 +\subsection{Informal anarchy} 9.88 + 9.89 +I wouldn't suggest an ``anything goes'' approach as something 9.90 +sustainable, but it's a model that's easy to grasp, and it works 9.91 +perfectly well in a few unusual situations. 9.92 + 9.93 +As one example, many projects have a loose-knit group of collaborators 9.94 +who rarely physically meet each other. Some groups like to overcome 9.95 +the isolation of working at a distance by organising occasional 9.96 +``sprints''. In a sprint, a number of people get together in a single 9.97 +location (a company's conference room, a hotel meeting room, that kind 9.98 +of place) and spend several days more or less locked in there, hacking 9.99 +intensely on a handful of projects. 9.100 + 9.101 +A sprint is the perfect place to use the \hgcmd{serve} command, since 9.102 +\hgcmd{serve} does not requires any fancy server infrastructure. You 9.103 +can get started with \hgcmd{serve} in moments, by reading 9.104 +section~\ref{sec:collab:serve} below. Then simply tell the person 9.105 +next to you that you're running a server, send the URL to them in an 9.106 +instant message, and you immediately have a quick-turnaround way to 9.107 +work together. They can type your URL into their web browser and 9.108 +quickly review your changes; or they can pull a bugfix from you and 9.109 +verify it; or they can clone a branch containing a new feature and try 9.110 +it out. 9.111 + 9.112 +The charm, and the problem, with doing things in an ad hoc fashion 9.113 +like this is that only people who know about your changes, and where 9.114 +they are, can see them. Such an informal approach simply doesn't 9.115 +scale beyond a handful people, because each individual needs to know 9.116 +about $n$ different repositories to pull from. 9.117 + 9.118 +\subsection{A single central repository} 9.119 + 9.120 +For smaller projects migrating from a centralised revision control 9.121 +tool, perhaps the easiest way to get started is to have changes flow 9.122 +through a single shared central repository. This is also the 9.123 +most common ``building block'' for more ambitious workflow schemes. 9.124 + 9.125 +Contributors start by cloning a copy of this repository. They can 9.126 +pull changes from it whenever they need to, and some (perhaps all) 9.127 +developers have permission to push a change back when they're ready 9.128 +for other people to see it. 9.129 + 9.130 +Under this model, it can still often make sense for people to pull 9.131 +changes directly from each other, without going through the central 9.132 +repository. Consider a case in which I have a tentative bug fix, but 9.133 +I am worried that if I were to publish it to the central repository, 9.134 +it might subsequently break everyone else's trees as they pull it. To 9.135 +reduce the potential for damage, I can ask you to clone my repository 9.136 +into a temporary repository of your own and test it. This lets us put 9.137 +off publishing the potentially unsafe change until it has had a little 9.138 +testing. 9.139 + 9.140 +In this kind of scenario, people usually use the \command{ssh} 9.141 +protocol to securely push changes to the central repository, as 9.142 +documented in section~\ref{sec:collab:ssh}. It's also usual to 9.143 +publish a read-only copy of the repository over HTTP using CGI, as in 9.144 +section~\ref{sec:collab:cgi}. Publishing over HTTP satisfies the 9.145 +needs of people who don't have push access, and those who want to use 9.146 +web browsers to browse the repository's history. 9.147 + 9.148 +\subsection{Working with multiple branches} 9.149 + 9.150 +Projects of any significant size naturally tend to make progress on 9.151 +several fronts simultaneously. In the case of software, it's common 9.152 +for a project to go through periodic official releases. A release 9.153 +might then go into ``maintenance mode'' for a while after its first 9.154 +publication; maintenance releases tend to contain only bug fixes, not 9.155 +new features. In parallel with these maintenance releases, one or 9.156 +more future releases may be under development. People normally use 9.157 +the word ``branch'' to refer to one of these many slightly different 9.158 +directions in which development is proceeding. 9.159 + 9.160 +Mercurial is particularly well suited to managing a number of 9.161 +simultaneous, but not identical, branches. Each ``development 9.162 +direction'' can live in its own central repository, and you can merge 9.163 +changes from one to another as the need arises. Because repositories 9.164 +are independent of each other, unstable changes in a development 9.165 +branch will never affect a stable branch unless someone explicitly 9.166 +merges those changes in. 9.167 + 9.168 +Here's an example of how this can work in practice. Let's say you 9.169 +have one ``main branch'' on a central server. 9.170 +\interaction{branching.init} 9.171 +People clone it, make changes locally, test them, and push them back. 9.172 + 9.173 +Once the main branch reaches a release milestone, you can use the 9.174 +\hgcmd{tag} command to give a permanent name to the milestone 9.175 +revision. 9.176 +\interaction{branching.tag} 9.177 +Let's say some ongoing development occurs on the main branch. 9.178 +\interaction{branching.main} 9.179 +Using the tag that was recorded at the milestone, people who clone 9.180 +that repository at any time in the future can use \hgcmd{update} to 9.181 +get a copy of the working directory exactly as it was when that tagged 9.182 +revision was committed. 9.183 +\interaction{branching.update} 9.184 + 9.185 +In addition, immediately after the main branch is tagged, someone can 9.186 +then clone the main branch on the server to a new ``stable'' branch, 9.187 +also on the server. 9.188 +\interaction{branching.clone} 9.189 + 9.190 +Someone who needs to make a change to the stable branch can then clone 9.191 +\emph{that} repository, make their changes, commit, and push their 9.192 +changes back there. 9.193 +\interaction{branching.stable} 9.194 +Because Mercurial repositories are independent, and Mercurial doesn't 9.195 +move changes around automatically, the stable and main branches are 9.196 +\emph{isolated} from each other. The changes that you made on the 9.197 +main branch don't ``leak'' to the stable branch, and vice versa. 9.198 + 9.199 +You'll often want all of your bugfixes on the stable branch to show up 9.200 +on the main branch, too. Rather than rewrite a bugfix on the main 9.201 +branch, you can simply pull and merge changes from the stable to the 9.202 +main branch, and Mercurial will bring those bugfixes in for you. 9.203 +\interaction{branching.merge} 9.204 +The main branch will still contain changes that are not on the stable 9.205 +branch, but it will also contain all of the bugfixes from the stable 9.206 +branch. The stable branch remains unaffected by these changes. 9.207 + 9.208 +\subsection{Feature branches} 9.209 + 9.210 +For larger projects, an effective way to manage change is to break up 9.211 +a team into smaller groups. Each group has a shared branch of its 9.212 +own, cloned from a single ``master'' branch used by the entire 9.213 +project. People working on an individual branch are typically quite 9.214 +isolated from developments on other branches. 9.215 + 9.216 +\begin{figure}[ht] 9.217 + \centering 9.218 + \grafix{feature-branches} 9.219 + \caption{Feature branches} 9.220 + \label{fig:collab:feature-branches} 9.221 +\end{figure} 9.222 + 9.223 +When a particular feature is deemed to be in suitable shape, someone 9.224 +on that feature team pulls and merges from the master branch into the 9.225 +feature branch, then pushes back up to the master branch. 9.226 + 9.227 +\subsection{The release train} 9.228 + 9.229 +Some projects are organised on a ``train'' basis: a release is 9.230 +scheduled to happen every few months, and whatever features are ready 9.231 +when the ``train'' is ready to leave are allowed in. 9.232 + 9.233 +This model resembles working with feature branches. The difference is 9.234 +that when a feature branch misses a train, someone on the feature team 9.235 +pulls and merges the changes that went out on that train release into 9.236 +the feature branch, and the team continues its work on top of that 9.237 +release so that their feature can make the next release. 9.238 + 9.239 +\subsection{The Linux kernel model} 9.240 + 9.241 +The development of the Linux kernel has a shallow hierarchical 9.242 +structure, surrounded by a cloud of apparent chaos. Because most 9.243 +Linux developers use \command{git}, a distributed revision control 9.244 +tool with capabilities similar to Mercurial, it's useful to describe 9.245 +the way work flows in that environment; if you like the ideas, the 9.246 +approach translates well across tools. 9.247 + 9.248 +At the center of the community sits Linus Torvalds, the creator of 9.249 +Linux. He publishes a single source repository that is considered the 9.250 +``authoritative'' current tree by the entire developer community. 9.251 +Anyone can clone Linus's tree, but he is very choosy about whose trees 9.252 +he pulls from. 9.253 + 9.254 +Linus has a number of ``trusted lieutenants''. As a general rule, he 9.255 +pulls whatever changes they publish, in most cases without even 9.256 +reviewing those changes. Some of those lieutenants are generally 9.257 +agreed to be ``maintainers'', responsible for specific subsystems 9.258 +within the kernel. If a random kernel hacker wants to make a change 9.259 +to a subsystem that they want to end up in Linus's tree, they must 9.260 +find out who the subsystem's maintainer is, and ask that maintainer to 9.261 +take their change. If the maintainer reviews their changes and agrees 9.262 +to take them, they'll pass them along to Linus in due course. 9.263 + 9.264 +Individual lieutenants have their own approaches to reviewing, 9.265 +accepting, and publishing changes; and for deciding when to feed them 9.266 +to Linus. In addition, there are several well known branches that 9.267 +people use for different purposes. For example, a few people maintain 9.268 +``stable'' repositories of older versions of the kernel, to which they 9.269 +apply critical fixes as needed. Some maintainers publish multiple 9.270 +trees: one for experimental changes; one for changes that they are 9.271 +about to feed upstream; and so on. Others just publish a single 9.272 +tree. 9.273 + 9.274 +This model has two notable features. The first is that it's ``pull 9.275 +only''. You have to ask, convince, or beg another developer to take a 9.276 +change from you, because there are almost no trees to which more than 9.277 +one person can push, and there's no way to push changes into a tree 9.278 +that someone else controls. 9.279 + 9.280 +The second is that it's based on reputation and acclaim. If you're an 9.281 +unknown, Linus will probably ignore changes from you without even 9.282 +responding. But a subsystem maintainer will probably review them, and 9.283 +will likely take them if they pass their criteria for suitability. 9.284 +The more ``good'' changes you contribute to a maintainer, the more 9.285 +likely they are to trust your judgment and accept your changes. If 9.286 +you're well-known and maintain a long-lived branch for something Linus 9.287 +hasn't yet accepted, people with similar interests may pull your 9.288 +changes regularly to keep up with your work. 9.289 + 9.290 +Reputation and acclaim don't necessarily cross subsystem or ``people'' 9.291 +boundaries. If you're a respected but specialised storage hacker, and 9.292 +you try to fix a networking bug, that change will receive a level of 9.293 +scrutiny from a network maintainer comparable to a change from a 9.294 +complete stranger. 9.295 + 9.296 +To people who come from more orderly project backgrounds, the 9.297 +comparatively chaotic Linux kernel development process often seems 9.298 +completely insane. It's subject to the whims of individuals; people 9.299 +make sweeping changes whenever they deem it appropriate; and the pace 9.300 +of development is astounding. And yet Linux is a highly successful, 9.301 +well-regarded piece of software. 9.302 + 9.303 +\subsection{Pull-only versus shared-push collaboration} 9.304 + 9.305 +A perpetual source of heat in the open source community is whether a 9.306 +development model in which people only ever pull changes from others 9.307 +is ``better than'' one in which multiple people can push changes to a 9.308 +shared repository. 9.309 + 9.310 +Typically, the backers of the shared-push model use tools that 9.311 +actively enforce this approach. If you're using a centralised 9.312 +revision control tool such as Subversion, there's no way to make a 9.313 +choice over which model you'll use: the tool gives you shared-push, 9.314 +and if you want to do anything else, you'll have to roll your own 9.315 +approach on top (such as applying a patch by hand). 9.316 + 9.317 +A good distributed revision control tool, such as Mercurial, will 9.318 +support both models. You and your collaborators can then structure 9.319 +how you work together based on your own needs and preferences, not on 9.320 +what contortions your tools force you into. 9.321 + 9.322 +\subsection{Where collaboration meets branch management} 9.323 + 9.324 +Once you and your team set up some shared repositories and start 9.325 +propagating changes back and forth between local and shared repos, you 9.326 +begin to face a related, but slightly different challenge: that of 9.327 +managing the multiple directions in which your team may be moving at 9.328 +once. Even though this subject is intimately related to how your team 9.329 +collaborates, it's dense enough to merit treatment of its own, in 9.330 +chapter~\ref{chap:branch}. 9.331 + 9.332 +\section{The technical side of sharing} 9.333 + 9.334 +The remainder of this chapter is devoted to the question of serving 9.335 +data to your collaborators. 9.336 + 9.337 +\section{Informal sharing with \hgcmd{serve}} 9.338 +\label{sec:collab:serve} 9.339 + 9.340 +Mercurial's \hgcmd{serve} command is wonderfully suited to small, 9.341 +tight-knit, and fast-paced group environments. It also provides a 9.342 +great way to get a feel for using Mercurial commands over a network. 9.343 + 9.344 +Run \hgcmd{serve} inside a repository, and in under a second it will 9.345 +bring up a specialised HTTP server; this will accept connections from 9.346 +any client, and serve up data for that repository until you terminate 9.347 +it. Anyone who knows the URL of the server you just started, and can 9.348 +talk to your computer over the network, can then use a web browser or 9.349 +Mercurial to read data from that repository. A URL for a 9.350 +\hgcmd{serve} instance running on a laptop is likely to look something 9.351 +like \Verb|http://my-laptop.local:8000/|. 9.352 + 9.353 +The \hgcmd{serve} command is \emph{not} a general-purpose web server. 9.354 +It can do only two things: 9.355 +\begin{itemize} 9.356 +\item Allow people to browse the history of the repository it's 9.357 + serving, from their normal web browsers. 9.358 +\item Speak Mercurial's wire protocol, so that people can 9.359 + \hgcmd{clone} or \hgcmd{pull} changes from that repository. 9.360 +\end{itemize} 9.361 +In particular, \hgcmd{serve} won't allow remote users to \emph{modify} 9.362 +your repository. It's intended for read-only use. 9.363 + 9.364 +If you're getting started with Mercurial, there's nothing to prevent 9.365 +you from using \hgcmd{serve} to serve up a repository on your own 9.366 +computer, then use commands like \hgcmd{clone}, \hgcmd{incoming}, and 9.367 +so on to talk to that server as if the repository was hosted remotely. 9.368 +This can help you to quickly get acquainted with using commands on 9.369 +network-hosted repositories. 9.370 + 9.371 +\subsection{A few things to keep in mind} 9.372 + 9.373 +Because it provides unauthenticated read access to all clients, you 9.374 +should only use \hgcmd{serve} in an environment where you either don't 9.375 +care, or have complete control over, who can access your network and 9.376 +pull data from your repository. 9.377 + 9.378 +The \hgcmd{serve} command knows nothing about any firewall software 9.379 +you might have installed on your system or network. It cannot detect 9.380 +or control your firewall software. If other people are unable to talk 9.381 +to a running \hgcmd{serve} instance, the second thing you should do 9.382 +(\emph{after} you make sure that they're using the correct URL) is 9.383 +check your firewall configuration. 9.384 + 9.385 +By default, \hgcmd{serve} listens for incoming connections on 9.386 +port~8000. If another process is already listening on the port you 9.387 +want to use, you can specify a different port to listen on using the 9.388 +\hgopt{serve}{-p} option. 9.389 + 9.390 +Normally, when \hgcmd{serve} starts, it prints no output, which can be 9.391 +a bit unnerving. If you'd like to confirm that it is indeed running 9.392 +correctly, and find out what URL you should send to your 9.393 +collaborators, start it with the \hggopt{-v} option. 9.394 + 9.395 +\section{Using the Secure Shell (ssh) protocol} 9.396 +\label{sec:collab:ssh} 9.397 + 9.398 +You can pull and push changes securely over a network connection using 9.399 +the Secure Shell (\texttt{ssh}) protocol. To use this successfully, 9.400 +you may have to do a little bit of configuration on the client or 9.401 +server sides. 9.402 + 9.403 +If you're not familiar with ssh, it's a network protocol that lets you 9.404 +securely communicate with another computer. To use it with Mercurial, 9.405 +you'll be setting up one or more user accounts on a server so that 9.406 +remote users can log in and execute commands. 9.407 + 9.408 +(If you \emph{are} familiar with ssh, you'll probably find some of the 9.409 +material that follows to be elementary in nature.) 9.410 + 9.411 +\subsection{How to read and write ssh URLs} 9.412 + 9.413 +An ssh URL tends to look like this: 9.414 +\begin{codesample2} 9.415 + ssh://bos@hg.serpentine.com:22/hg/hgbook 9.416 +\end{codesample2} 9.417 +\begin{enumerate} 9.418 +\item The ``\texttt{ssh://}'' part tells Mercurial to use the ssh 9.419 + protocol. 9.420 +\item The ``\texttt{bos@}'' component indicates what username to log 9.421 + into the server as. You can leave this out if the remote username 9.422 + is the same as your local username. 9.423 +\item The ``\texttt{hg.serpentine.com}'' gives the hostname of the 9.424 + server to log into. 9.425 +\item The ``:22'' identifies the port number to connect to the server 9.426 + on. The default port is~22, so you only need to specify this part 9.427 + if you're \emph{not} using port~22. 9.428 +\item The remainder of the URL is the local path to the repository on 9.429 + the server. 9.430 +\end{enumerate} 9.431 + 9.432 +There's plenty of scope for confusion with the path component of ssh 9.433 +URLs, as there is no standard way for tools to interpret it. Some 9.434 +programs behave differently than others when dealing with these paths. 9.435 +This isn't an ideal situation, but it's unlikely to change. Please 9.436 +read the following paragraphs carefully. 9.437 + 9.438 +Mercurial treats the path to a repository on the server as relative to 9.439 +the remote user's home directory. For example, if user \texttt{foo} 9.440 +on the server has a home directory of \dirname{/home/foo}, then an ssh 9.441 +URL that contains a path component of \dirname{bar} 9.442 +\emph{really} refers to the directory \dirname{/home/foo/bar}. 9.443 + 9.444 +If you want to specify a path relative to another user's home 9.445 +directory, you can use a path that starts with a tilde character 9.446 +followed by the user's name (let's call them \texttt{otheruser}), like 9.447 +this. 9.448 +\begin{codesample2} 9.449 + ssh://server/~otheruser/hg/repo 9.450 +\end{codesample2} 9.451 + 9.452 +And if you really want to specify an \emph{absolute} path on the 9.453 +server, begin the path component with two slashes, as in this example. 9.454 +\begin{codesample2} 9.455 + ssh://server//absolute/path 9.456 +\end{codesample2} 9.457 + 9.458 +\subsection{Finding an ssh client for your system} 9.459 + 9.460 +Almost every Unix-like system comes with OpenSSH preinstalled. If 9.461 +you're using such a system, run \Verb|which ssh| to find out if 9.462 +the \command{ssh} command is installed (it's usually in 9.463 +\dirname{/usr/bin}). In the unlikely event that it isn't present, 9.464 +take a look at your system documentation to figure out how to install 9.465 +it. 9.466 + 9.467 +On Windows, you'll first need to download a suitable ssh 9.468 +client. There are two alternatives. 9.469 +\begin{itemize} 9.470 +\item Simon Tatham's excellent PuTTY package~\cite{web:putty} provides 9.471 + a complete suite of ssh client commands. 9.472 +\item If you have a high tolerance for pain, you can use the Cygwin 9.473 + port of OpenSSH. 9.474 +\end{itemize} 9.475 +In either case, you'll need to edit your \hgini\ file to tell 9.476 +Mercurial where to find the actual client command. For example, if 9.477 +you're using PuTTY, you'll need to use the \command{plink} command as 9.478 +a command-line ssh client. 9.479 +\begin{codesample2} 9.480 + [ui] 9.481 + ssh = C:/path/to/plink.exe -ssh -i "C:/path/to/my/private/key" 9.482 +\end{codesample2} 9.483 + 9.484 +\begin{note} 9.485 + The path to \command{plink} shouldn't contain any whitespace 9.486 + characters, or Mercurial may not be able to run it correctly (so 9.487 + putting it in \dirname{C:\\Program Files} is probably not a good 9.488 + idea). 9.489 +\end{note} 9.490 + 9.491 +\subsection{Generating a key pair} 9.492 + 9.493 +To avoid the need to repetitively type a password every time you need 9.494 +to use your ssh client, I recommend generating a key pair. On a 9.495 +Unix-like system, the \command{ssh-keygen} command will do the trick. 9.496 +On Windows, if you're using PuTTY, the \command{puttygen} command is 9.497 +what you'll need. 9.498 + 9.499 +When you generate a key pair, it's usually \emph{highly} advisable to 9.500 +protect it with a passphrase. (The only time that you might not want 9.501 +to do this is when you're using the ssh protocol for automated tasks 9.502 +on a secure network.) 9.503 + 9.504 +Simply generating a key pair isn't enough, however. You'll need to 9.505 +add the public key to the set of authorised keys for whatever user 9.506 +you're logging in remotely as. For servers using OpenSSH (the vast 9.507 +majority), this will mean adding the public key to a list in a file 9.508 +called \sfilename{authorized\_keys} in their \sdirname{.ssh} 9.509 +directory. 9.510 + 9.511 +On a Unix-like system, your public key will have a \filename{.pub} 9.512 +extension. If you're using \command{puttygen} on Windows, you can 9.513 +save the public key to a file of your choosing, or paste it from the 9.514 +window it's displayed in straight into the 9.515 +\sfilename{authorized\_keys} file. 9.516 + 9.517 +\subsection{Using an authentication agent} 9.518 + 9.519 +An authentication agent is a daemon that stores passphrases in memory 9.520 +(so it will forget passphrases if you log out and log back in again). 9.521 +An ssh client will notice if it's running, and query it for a 9.522 +passphrase. If there's no authentication agent running, or the agent 9.523 +doesn't store the necessary passphrase, you'll have to type your 9.524 +passphrase every time Mercurial tries to communicate with a server on 9.525 +your behalf (e.g.~whenever you pull or push changes). 9.526 + 9.527 +The downside of storing passphrases in an agent is that it's possible 9.528 +for a well-prepared attacker to recover the plain text of your 9.529 +passphrases, in some cases even if your system has been power-cycled. 9.530 +You should make your own judgment as to whether this is an acceptable 9.531 +risk. It certainly saves a lot of repeated typing. 9.532 + 9.533 +On Unix-like systems, the agent is called \command{ssh-agent}, and 9.534 +it's often run automatically for you when you log in. You'll need to 9.535 +use the \command{ssh-add} command to add passphrases to the agent's 9.536 +store. On Windows, if you're using PuTTY, the \command{pageant} 9.537 +command acts as the agent. It adds an icon to your system tray that 9.538 +will let you manage stored passphrases. 9.539 + 9.540 +\subsection{Configuring the server side properly} 9.541 + 9.542 +Because ssh can be fiddly to set up if you're new to it, there's a 9.543 +variety of things that can go wrong. Add Mercurial on top, and 9.544 +there's plenty more scope for head-scratching. Most of these 9.545 +potential problems occur on the server side, not the client side. The 9.546 +good news is that once you've gotten a configuration working, it will 9.547 +usually continue to work indefinitely. 9.548 + 9.549 +Before you try using Mercurial to talk to an ssh server, it's best to 9.550 +make sure that you can use the normal \command{ssh} or \command{putty} 9.551 +command to talk to the server first. If you run into problems with 9.552 +using these commands directly, Mercurial surely won't work. Worse, it 9.553 +will obscure the underlying problem. Any time you want to debug 9.554 +ssh-related Mercurial problems, you should drop back to making sure 9.555 +that plain ssh client commands work first, \emph{before} you worry 9.556 +about whether there's a problem with Mercurial. 9.557 + 9.558 +The first thing to be sure of on the server side is that you can 9.559 +actually log in from another machine at all. If you can't use 9.560 +\command{ssh} or \command{putty} to log in, the error message you get 9.561 +may give you a few hints as to what's wrong. The most common problems 9.562 +are as follows. 9.563 +\begin{itemize} 9.564 +\item If you get a ``connection refused'' error, either there isn't an 9.565 + SSH daemon running on the server at all, or it's inaccessible due to 9.566 + firewall configuration. 9.567 +\item If you get a ``no route to host'' error, you either have an 9.568 + incorrect address for the server or a seriously locked down firewall 9.569 + that won't admit its existence at all. 9.570 +\item If you get a ``permission denied'' error, you may have mistyped 9.571 + the username on the server, or you could have mistyped your key's 9.572 + passphrase or the remote user's password. 9.573 +\end{itemize} 9.574 +In summary, if you're having trouble talking to the server's ssh 9.575 +daemon, first make sure that one is running at all. On many systems 9.576 +it will be installed, but disabled, by default. Once you're done with 9.577 +this step, you should then check that the server's firewall is 9.578 +configured to allow incoming connections on the port the ssh daemon is 9.579 +listening on (usually~22). Don't worry about more exotic 9.580 +possibilities for misconfiguration until you've checked these two 9.581 +first. 9.582 + 9.583 +If you're using an authentication agent on the client side to store 9.584 +passphrases for your keys, you ought to be able to log into the server 9.585 +without being prompted for a passphrase or a password. If you're 9.586 +prompted for a passphrase, there are a few possible culprits. 9.587 +\begin{itemize} 9.588 +\item You might have forgotten to use \command{ssh-add} or 9.589 + \command{pageant} to store the passphrase. 9.590 +\item You might have stored the passphrase for the wrong key. 9.591 +\end{itemize} 9.592 +If you're being prompted for the remote user's password, there are 9.593 +another few possible problems to check. 9.594 +\begin{itemize} 9.595 +\item Either the user's home directory or their \sdirname{.ssh} 9.596 + directory might have excessively liberal permissions. As a result, 9.597 + the ssh daemon will not trust or read their 9.598 + \sfilename{authorized\_keys} file. For example, a group-writable 9.599 + home or \sdirname{.ssh} directory will often cause this symptom. 9.600 +\item The user's \sfilename{authorized\_keys} file may have a problem. 9.601 + If anyone other than the user owns or can write to that file, the 9.602 + ssh daemon will not trust or read it. 9.603 +\end{itemize} 9.604 + 9.605 +In the ideal world, you should be able to run the following command 9.606 +successfully, and it should print exactly one line of output, the 9.607 +current date and time. 9.608 +\begin{codesample2} 9.609 + ssh myserver date 9.610 +\end{codesample2} 9.611 + 9.612 +If, on your server, you have login scripts that print banners or other 9.613 +junk even when running non-interactive commands like this, you should 9.614 +fix them before you continue, so that they only print output if 9.615 +they're run interactively. Otherwise these banners will at least 9.616 +clutter up Mercurial's output. Worse, they could potentially cause 9.617 +problems with running Mercurial commands remotely. Mercurial makes 9.618 +tries to detect and ignore banners in non-interactive \command{ssh} 9.619 +sessions, but it is not foolproof. (If you're editing your login 9.620 +scripts on your server, the usual way to see if a login script is 9.621 +running in an interactive shell is to check the return code from the 9.622 +command \Verb|tty -s|.) 9.623 + 9.624 +Once you've verified that plain old ssh is working with your server, 9.625 +the next step is to ensure that Mercurial runs on the server. The 9.626 +following command should run successfully: 9.627 +\begin{codesample2} 9.628 + ssh myserver hg version 9.629 +\end{codesample2} 9.630 +If you see an error message instead of normal \hgcmd{version} output, 9.631 +this is usually because you haven't installed Mercurial to 9.632 +\dirname{/usr/bin}. Don't worry if this is the case; you don't need 9.633 +to do that. But you should check for a few possible problems. 9.634 +\begin{itemize} 9.635 +\item Is Mercurial really installed on the server at all? I know this 9.636 + sounds trivial, but it's worth checking! 9.637 +\item Maybe your shell's search path (usually set via the \envar{PATH} 9.638 + environment variable) is simply misconfigured. 9.639 +\item Perhaps your \envar{PATH} environment variable is only being set 9.640 + to point to the location of the \command{hg} executable if the login 9.641 + session is interactive. This can happen if you're setting the path 9.642 + in the wrong shell login script. See your shell's documentation for 9.643 + details. 9.644 +\item The \envar{PYTHONPATH} environment variable may need to contain 9.645 + the path to the Mercurial Python modules. It might not be set at 9.646 + all; it could be incorrect; or it may be set only if the login is 9.647 + interactive. 9.648 +\end{itemize} 9.649 + 9.650 +If you can run \hgcmd{version} over an ssh connection, well done! 9.651 +You've got the server and client sorted out. You should now be able 9.652 +to use Mercurial to access repositories hosted by that username on 9.653 +that server. If you run into problems with Mercurial and ssh at this 9.654 +point, try using the \hggopt{--debug} option to get a clearer picture 9.655 +of what's going on. 9.656 + 9.657 +\subsection{Using compression with ssh} 9.658 + 9.659 +Mercurial does not compress data when it uses the ssh protocol, 9.660 +because the ssh protocol can transparently compress data. However, 9.661 +the default behaviour of ssh clients is \emph{not} to request 9.662 +compression. 9.663 + 9.664 +Over any network other than a fast LAN (even a wireless network), 9.665 +using compression is likely to significantly speed up Mercurial's 9.666 +network operations. For example, over a WAN, someone measured 9.667 +compression as reducing the amount of time required to clone a 9.668 +particularly large repository from~51 minutes to~17 minutes. 9.669 + 9.670 +Both \command{ssh} and \command{plink} accept a \cmdopt{ssh}{-C} 9.671 +option which turns on compression. You can easily edit your \hgrc\ to 9.672 +enable compression for all of Mercurial's uses of the ssh protocol. 9.673 +\begin{codesample2} 9.674 + [ui] 9.675 + ssh = ssh -C 9.676 +\end{codesample2} 9.677 + 9.678 +If you use \command{ssh}, you can configure it to always use 9.679 +compression when talking to your server. To do this, edit your 9.680 +\sfilename{.ssh/config} file (which may not yet exist), as follows. 9.681 +\begin{codesample2} 9.682 + Host hg 9.683 + Compression yes 9.684 + HostName hg.example.com 9.685 +\end{codesample2} 9.686 +This defines an alias, \texttt{hg}. When you use it on the 9.687 +\command{ssh} command line or in a Mercurial \texttt{ssh}-protocol 9.688 +URL, it will cause \command{ssh} to connect to \texttt{hg.example.com} 9.689 +and use compression. This gives you both a shorter name to type and 9.690 +compression, each of which is a good thing in its own right. 9.691 + 9.692 +\section{Serving over HTTP using CGI} 9.693 +\label{sec:collab:cgi} 9.694 + 9.695 +Depending on how ambitious you are, configuring Mercurial's CGI 9.696 +interface can take anything from a few moments to several hours. 9.697 + 9.698 +We'll begin with the simplest of examples, and work our way towards a 9.699 +more complex configuration. Even for the most basic case, you're 9.700 +almost certainly going to need to read and modify your web server's 9.701 +configuration. 9.702 + 9.703 +\begin{note} 9.704 + Configuring a web server is a complex, fiddly, and highly 9.705 + system-dependent activity. I can't possibly give you instructions 9.706 + that will cover anything like all of the cases you will encounter. 9.707 + Please use your discretion and judgment in following the sections 9.708 + below. Be prepared to make plenty of mistakes, and to spend a lot 9.709 + of time reading your server's error logs. 9.710 +\end{note} 9.711 + 9.712 +\subsection{Web server configuration checklist} 9.713 + 9.714 +Before you continue, do take a few moments to check a few aspects of 9.715 +your system's setup. 9.716 + 9.717 +\begin{enumerate} 9.718 +\item Do you have a web server installed at all? Mac OS X ships with 9.719 + Apache, but many other systems may not have a web server installed. 9.720 +\item If you have a web server installed, is it actually running? On 9.721 + most systems, even if one is present, it will be disabled by 9.722 + default. 9.723 +\item Is your server configured to allow you to run CGI programs in 9.724 + the directory where you plan to do so? Most servers default to 9.725 + explicitly disabling the ability to run CGI programs. 9.726 +\end{enumerate} 9.727 + 9.728 +If you don't have a web server installed, and don't have substantial 9.729 +experience configuring Apache, you should consider using the 9.730 +\texttt{lighttpd} web server instead of Apache. Apache has a 9.731 +well-deserved reputation for baroque and confusing configuration. 9.732 +While \texttt{lighttpd} is less capable in some ways than Apache, most 9.733 +of these capabilities are not relevant to serving Mercurial 9.734 +repositories. And \texttt{lighttpd} is undeniably \emph{much} easier 9.735 +to get started with than Apache. 9.736 + 9.737 +\subsection{Basic CGI configuration} 9.738 + 9.739 +On Unix-like systems, it's common for users to have a subdirectory 9.740 +named something like \dirname{public\_html} in their home directory, 9.741 +from which they can serve up web pages. A file named \filename{foo} 9.742 +in this directory will be accessible at a URL of the form 9.743 +\texttt{http://www.example.com/\~{}username/foo}. 9.744 + 9.745 +To get started, find the \sfilename{hgweb.cgi} script that should be 9.746 +present in your Mercurial installation. If you can't quickly find a 9.747 +local copy on your system, simply download one from the master 9.748 +Mercurial repository at 9.749 +\url{http://www.selenic.com/repo/hg/raw-file/tip/hgweb.cgi}. 9.750 + 9.751 +You'll need to copy this script into your \dirname{public\_html} 9.752 +directory, and ensure that it's executable. 9.753 +\begin{codesample2} 9.754 + cp .../hgweb.cgi ~/public_html 9.755 + chmod 755 ~/public_html/hgweb.cgi 9.756 +\end{codesample2} 9.757 +The \texttt{755} argument to \command{chmod} is a little more general 9.758 +than just making the script executable: it ensures that the script is 9.759 +executable by anyone, and that ``group'' and ``other'' write 9.760 +permissions are \emph{not} set. If you were to leave those write 9.761 +permissions enabled, Apache's \texttt{suexec} subsystem would likely 9.762 +refuse to execute the script. In fact, \texttt{suexec} also insists 9.763 +that the \emph{directory} in which the script resides must not be 9.764 +writable by others. 9.765 +\begin{codesample2} 9.766 + chmod 755 ~/public_html 9.767 +\end{codesample2} 9.768 + 9.769 +\subsubsection{What could \emph{possibly} go wrong?} 9.770 +\label{sec:collab:wtf} 9.771 + 9.772 +Once you've copied the CGI script into place, go into a web browser, 9.773 +and try to open the URL \url{http://myhostname/~myuser/hgweb.cgi}, 9.774 +\emph{but} brace yourself for instant failure. There's a high 9.775 +probability that trying to visit this URL will fail, and there are 9.776 +many possible reasons for this. In fact, you're likely to stumble 9.777 +over almost every one of the possible errors below, so please read 9.778 +carefully. The following are all of the problems I ran into on a 9.779 +system running Fedora~7, with a fresh installation of Apache, and a 9.780 +user account that I created specially to perform this exercise. 9.781 + 9.782 +Your web server may have per-user directories disabled. If you're 9.783 +using Apache, search your config file for a \texttt{UserDir} 9.784 +directive. If there's none present, per-user directories will be 9.785 +disabled. If one exists, but its value is \texttt{disabled}, then 9.786 +per-user directories will be disabled. Otherwise, the string after 9.787 +\texttt{UserDir} gives the name of the subdirectory that Apache will 9.788 +look in under your home directory, for example \dirname{public\_html}. 9.789 + 9.790 +Your file access permissions may be too restrictive. The web server 9.791 +must be able to traverse your home directory and directories under 9.792 +your \dirname{public\_html} directory, and read files under the latter 9.793 +too. Here's a quick recipe to help you to make your permissions more 9.794 +appropriate. 9.795 +\begin{codesample2} 9.796 + chmod 755 ~ 9.797 + find ~/public_html -type d -print0 | xargs -0r chmod 755 9.798 + find ~/public_html -type f -print0 | xargs -0r chmod 644 9.799 +\end{codesample2} 9.800 + 9.801 +The other possibility with permissions is that you might get a 9.802 +completely empty window when you try to load the script. In this 9.803 +case, it's likely that your access permissions are \emph{too 9.804 + permissive}. Apache's \texttt{suexec} subsystem won't execute a 9.805 +script that's group-~or world-writable, for example. 9.806 + 9.807 +Your web server may be configured to disallow execution of CGI 9.808 +programs in your per-user web directory. Here's Apache's 9.809 +default per-user configuration from my Fedora system. 9.810 +\begin{codesample2} 9.811 + <Directory /home/*/public_html> 9.812 + AllowOverride FileInfo AuthConfig Limit 9.813 + Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec 9.814 + <Limit GET POST OPTIONS> 9.815 + Order allow,deny 9.816 + Allow from all 9.817 + </Limit> 9.818 + <LimitExcept GET POST OPTIONS> 9.819 + Order deny,allow 9.820 + Deny from all 9.821 + </LimitExcept> 9.822 + </Directory> 9.823 +\end{codesample2} 9.824 +If you find a similar-looking \texttt{Directory} group in your Apache 9.825 +configuration, the directive to look at inside it is \texttt{Options}. 9.826 +Add \texttt{ExecCGI} to the end of this list if it's missing, and 9.827 +restart the web server. 9.828 + 9.829 +If you find that Apache serves you the text of the CGI script instead 9.830 +of executing it, you may need to either uncomment (if already present) 9.831 +or add a directive like this. 9.832 +\begin{codesample2} 9.833 + AddHandler cgi-script .cgi 9.834 +\end{codesample2} 9.835 + 9.836 +The next possibility is that you might be served with a colourful 9.837 +Python backtrace claiming that it can't import a 9.838 +\texttt{mercurial}-related module. This is actually progress! The 9.839 +server is now capable of executing your CGI script. This error is 9.840 +only likely to occur if you're running a private installation of 9.841 +Mercurial, instead of a system-wide version. Remember that the web 9.842 +server runs the CGI program without any of the environment variables 9.843 +that you take for granted in an interactive session. If this error 9.844 +happens to you, edit your copy of \sfilename{hgweb.cgi} and follow the 9.845 +directions inside it to correctly set your \envar{PYTHONPATH} 9.846 +environment variable. 9.847 + 9.848 +Finally, you are \emph{certain} to by served with another colourful 9.849 +Python backtrace: this one will complain that it can't find 9.850 +\dirname{/path/to/repository}. Edit your \sfilename{hgweb.cgi} script 9.851 +and replace the \dirname{/path/to/repository} string with the complete 9.852 +path to the repository you want to serve up. 9.853 + 9.854 +At this point, when you try to reload the page, you should be 9.855 +presented with a nice HTML view of your repository's history. Whew! 9.856 + 9.857 +\subsubsection{Configuring lighttpd} 9.858 + 9.859 +To be exhaustive in my experiments, I tried configuring the 9.860 +increasingly popular \texttt{lighttpd} web server to serve the same 9.861 +repository as I described with Apache above. I had already overcome 9.862 +all of the problems I outlined with Apache, many of which are not 9.863 +server-specific. As a result, I was fairly sure that my file and 9.864 +directory permissions were good, and that my \sfilename{hgweb.cgi} 9.865 +script was properly edited. 9.866 + 9.867 +Once I had Apache running, getting \texttt{lighttpd} to serve the 9.868 +repository was a snap (in other words, even if you're trying to use 9.869 +\texttt{lighttpd}, you should read the Apache section). I first had 9.870 +to edit the \texttt{mod\_access} section of its config file to enable 9.871 +\texttt{mod\_cgi} and \texttt{mod\_userdir}, both of which were 9.872 +disabled by default on my system. I then added a few lines to the end 9.873 +of the config file, to configure these modules. 9.874 +\begin{codesample2} 9.875 + userdir.path = "public_html" 9.876 + cgi.assign = ( ".cgi" => "" ) 9.877 +\end{codesample2} 9.878 +With this done, \texttt{lighttpd} ran immediately for me. If I had 9.879 +configured \texttt{lighttpd} before Apache, I'd almost certainly have 9.880 +run into many of the same system-level configuration problems as I did 9.881 +with Apache. However, I found \texttt{lighttpd} to be noticeably 9.882 +easier to configure than Apache, even though I've used Apache for over 9.883 +a decade, and this was my first exposure to \texttt{lighttpd}. 9.884 + 9.885 +\subsection{Sharing multiple repositories with one CGI script} 9.886 + 9.887 +The \sfilename{hgweb.cgi} script only lets you publish a single 9.888 +repository, which is an annoying restriction. If you want to publish 9.889 +more than one without wracking yourself with multiple copies of the 9.890 +same script, each with different names, a better choice is to use the 9.891 +\sfilename{hgwebdir.cgi} script. 9.892 + 9.893 +The procedure to configure \sfilename{hgwebdir.cgi} is only a little 9.894 +more involved than for \sfilename{hgweb.cgi}. First, you must obtain 9.895 +a copy of the script. If you don't have one handy, you can download a 9.896 +copy from the master Mercurial repository at 9.897 +\url{http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi}. 9.898 + 9.899 +You'll need to copy this script into your \dirname{public\_html} 9.900 +directory, and ensure that it's executable. 9.901 +\begin{codesample2} 9.902 + cp .../hgwebdir.cgi ~/public_html 9.903 + chmod 755 ~/public_html ~/public_html/hgwebdir.cgi 9.904 +\end{codesample2} 9.905 +With basic configuration out of the way, try to visit 9.906 +\url{http://myhostname/~myuser/hgwebdir.cgi} in your browser. It 9.907 +should display an empty list of repositories. If you get a blank 9.908 +window or error message, try walking through the list of potential 9.909 +problems in section~\ref{sec:collab:wtf}. 9.910 + 9.911 +The \sfilename{hgwebdir.cgi} script relies on an external 9.912 +configuration file. By default, it searches for a file named 9.913 +\sfilename{hgweb.config} in the same directory as itself. You'll need 9.914 +to create this file, and make it world-readable. The format of the 9.915 +file is similar to a Windows ``ini'' file, as understood by Python's 9.916 +\texttt{ConfigParser}~\cite{web:configparser} module. 9.917 + 9.918 +The easiest way to configure \sfilename{hgwebdir.cgi} is with a 9.919 +section named \texttt{collections}. This will automatically publish 9.920 +\emph{every} repository under the directories you name. The section 9.921 +should look like this: 9.922 +\begin{codesample2} 9.923 + [collections] 9.924 + /my/root = /my/root 9.925 +\end{codesample2} 9.926 +Mercurial interprets this by looking at the directory name on the 9.927 +\emph{right} hand side of the ``\texttt{=}'' sign; finding 9.928 +repositories in that directory hierarchy; and using the text on the 9.929 +\emph{left} to strip off matching text from the names it will actually 9.930 +list in the web interface. The remaining component of a path after 9.931 +this stripping has occurred is called a ``virtual path''. 9.932 + 9.933 +Given the example above, if we have a repository whose local path is 9.934 +\dirname{/my/root/this/repo}, the CGI script will strip the leading 9.935 +\dirname{/my/root} from the name, and publish the repository with a 9.936 +virtual path of \dirname{this/repo}. If the base URL for our CGI 9.937 +script is \url{http://myhostname/~myuser/hgwebdir.cgi}, the complete 9.938 +URL for that repository will be 9.939 +\url{http://myhostname/~myuser/hgwebdir.cgi/this/repo}. 9.940 + 9.941 +If we replace \dirname{/my/root} on the left hand side of this example 9.942 +with \dirname{/my}, then \sfilename{hgwebdir.cgi} will only strip off 9.943 +\dirname{/my} from the repository name, and will give us a virtual 9.944 +path of \dirname{root/this/repo} instead of \dirname{this/repo}. 9.945 + 9.946 +The \sfilename{hgwebdir.cgi} script will recursively search each 9.947 +directory listed in the \texttt{collections} section of its 9.948 +configuration file, but it will \texttt{not} recurse into the 9.949 +repositories it finds. 9.950 + 9.951 +The \texttt{collections} mechanism makes it easy to publish many 9.952 +repositories in a ``fire and forget'' manner. You only need to set up 9.953 +the CGI script and configuration file one time. Afterwards, you can 9.954 +publish or unpublish a repository at any time by simply moving it 9.955 +into, or out of, the directory hierarchy in which you've configured 9.956 +\sfilename{hgwebdir.cgi} to look. 9.957 + 9.958 +\subsubsection{Explicitly specifying which repositories to publish} 9.959 + 9.960 +In addition to the \texttt{collections} mechanism, the 9.961 +\sfilename{hgwebdir.cgi} script allows you to publish a specific list 9.962 +of repositories. To do so, create a \texttt{paths} section, with 9.963 +contents of the following form. 9.964 +\begin{codesample2} 9.965 + [paths] 9.966 + repo1 = /my/path/to/some/repo 9.967 + repo2 = /some/path/to/another 9.968 +\end{codesample2} 9.969 +In this case, the virtual path (the component that will appear in a 9.970 +URL) is on the left hand side of each definition, while the path to 9.971 +the repository is on the right. Notice that there does not need to be 9.972 +any relationship between the virtual path you choose and the location 9.973 +of a repository in your filesystem. 9.974 + 9.975 +If you wish, you can use both the \texttt{collections} and 9.976 +\texttt{paths} mechanisms simultaneously in a single configuration 9.977 +file. 9.978 + 9.979 +\begin{note} 9.980 + If multiple repositories have the same virtual path, 9.981 + \sfilename{hgwebdir.cgi} will not report an error. Instead, it will 9.982 + behave unpredictably. 9.983 +\end{note} 9.984 + 9.985 +\subsection{Downloading source archives} 9.986 + 9.987 +Mercurial's web interface lets users download an archive of any 9.988 +revision. This archive will contain a snapshot of the working 9.989 +directory as of that revision, but it will not contain a copy of the 9.990 +repository data. 9.991 + 9.992 +By default, this feature is not enabled. To enable it, you'll need to 9.993 +add an \rcitem{web}{allow\_archive} item to the \rcsection{web} 9.994 +section of your \hgrc. 9.995 + 9.996 +\subsection{Web configuration options} 9.997 + 9.998 +Mercurial's web interfaces (the \hgcmd{serve} command, and the 9.999 +\sfilename{hgweb.cgi} and \sfilename{hgwebdir.cgi} scripts) have a 9.1000 +number of configuration options that you can set. These belong in a 9.1001 +section named \rcsection{web}. 9.1002 +\begin{itemize} 9.1003 +\item[\rcitem{web}{allow\_archive}] Determines which (if any) archive 9.1004 + download mechanisms Mercurial supports. If you enable this 9.1005 + feature, users of the web interface will be able to download an 9.1006 + archive of whatever revision of a repository they are viewing. 9.1007 + To enable the archive feature, this item must take the form of a 9.1008 + sequence of words drawn from the list below. 9.1009 + \begin{itemize} 9.1010 + \item[\texttt{bz2}] A \command{tar} archive, compressed using 9.1011 + \texttt{bzip2} compression. This has the best compression ratio, 9.1012 + but uses the most CPU time on the server. 9.1013 + \item[\texttt{gz}] A \command{tar} archive, compressed using 9.1014 + \texttt{gzip} compression. 9.1015 + \item[\texttt{zip}] A \command{zip} archive, compressed using LZW 9.1016 + compression. This format has the worst compression ratio, but is 9.1017 + widely used in the Windows world. 9.1018 + \end{itemize} 9.1019 + If you provide an empty list, or don't have an 9.1020 + \rcitem{web}{allow\_archive} entry at all, this feature will be 9.1021 + disabled. Here is an example of how to enable all three supported 9.1022 + formats. 9.1023 + \begin{codesample4} 9.1024 + [web] 9.1025 + allow_archive = bz2 gz zip 9.1026 + \end{codesample4} 9.1027 +\item[\rcitem{web}{allowpull}] Boolean. Determines whether the web 9.1028 + interface allows remote users to \hgcmd{pull} and \hgcmd{clone} this 9.1029 + repository over~HTTP. If set to \texttt{no} or \texttt{false}, only 9.1030 + the ``human-oriented'' portion of the web interface is available. 9.1031 +\item[\rcitem{web}{contact}] String. A free-form (but preferably 9.1032 + brief) string identifying the person or group in charge of the 9.1033 + repository. This often contains the name and email address of a 9.1034 + person or mailing list. It often makes sense to place this entry in 9.1035 + a repository's own \sfilename{.hg/hgrc} file, but it can make sense 9.1036 + to use in a global \hgrc\ if every repository has a single 9.1037 + maintainer. 9.1038 +\item[\rcitem{web}{maxchanges}] Integer. The default maximum number 9.1039 + of changesets to display in a single page of output. 9.1040 +\item[\rcitem{web}{maxfiles}] Integer. The default maximum number 9.1041 + of modified files to display in a single page of output. 9.1042 +\item[\rcitem{web}{stripes}] Integer. If the web interface displays 9.1043 + alternating ``stripes'' to make it easier to visually align rows 9.1044 + when you are looking at a table, this number controls the number of 9.1045 + rows in each stripe. 9.1046 +\item[\rcitem{web}{style}] Controls the template Mercurial uses to 9.1047 + display the web interface. Mercurial ships with two web templates, 9.1048 + named \texttt{default} and \texttt{gitweb} (the latter is much more 9.1049 + visually attractive). You can also specify a custom template of 9.1050 + your own; see chapter~\ref{chap:template} for details. Here, you 9.1051 + can see how to enable the \texttt{gitweb} style. 9.1052 + \begin{codesample4} 9.1053 + [web] 9.1054 + style = gitweb 9.1055 + \end{codesample4} 9.1056 +\item[\rcitem{web}{templates}] Path. The directory in which to search 9.1057 + for template files. By default, Mercurial searches in the directory 9.1058 + in which it was installed. 9.1059 +\end{itemize} 9.1060 +If you are using \sfilename{hgwebdir.cgi}, you can place a few 9.1061 +configuration items in a \rcsection{web} section of the 9.1062 +\sfilename{hgweb.config} file instead of a \hgrc\ file, for 9.1063 +convenience. These items are \rcitem{web}{motd} and 9.1064 +\rcitem{web}{style}. 9.1065 + 9.1066 +\subsubsection{Options specific to an individual repository} 9.1067 + 9.1068 +A few \rcsection{web} configuration items ought to be placed in a 9.1069 +repository's local \sfilename{.hg/hgrc}, rather than a user's or 9.1070 +global \hgrc. 9.1071 +\begin{itemize} 9.1072 +\item[\rcitem{web}{description}] String. A free-form (but preferably 9.1073 + brief) string that describes the contents or purpose of the 9.1074 + repository. 9.1075 +\item[\rcitem{web}{name}] String. The name to use for the repository 9.1076 + in the web interface. This overrides the default name, which is the 9.1077 + last component of the repository's path. 9.1078 +\end{itemize} 9.1079 + 9.1080 +\subsubsection{Options specific to the \hgcmd{serve} command} 9.1081 + 9.1082 +Some of the items in the \rcsection{web} section of a \hgrc\ file are 9.1083 +only for use with the \hgcmd{serve} command. 9.1084 +\begin{itemize} 9.1085 +\item[\rcitem{web}{accesslog}] Path. The name of a file into which to 9.1086 + write an access log. By default, the \hgcmd{serve} command writes 9.1087 + this information to standard output, not to a file. Log entries are 9.1088 + written in the standard ``combined'' file format used by almost all 9.1089 + web servers. 9.1090 +\item[\rcitem{web}{address}] String. The local address on which the 9.1091 + server should listen for incoming connections. By default, the 9.1092 + server listens on all addresses. 9.1093 +\item[\rcitem{web}{errorlog}] Path. The name of a file into which to 9.1094 + write an error log. By default, the \hgcmd{serve} command writes this 9.1095 + information to standard error, not to a file. 9.1096 +\item[\rcitem{web}{ipv6}] Boolean. Whether to use the IPv6 protocol. 9.1097 + By default, IPv6 is not used. 9.1098 +\item[\rcitem{web}{port}] Integer. The TCP~port number on which the 9.1099 + server should listen. The default port number used is~8000. 9.1100 +\end{itemize} 9.1101 + 9.1102 +\subsubsection{Choosing the right \hgrc\ file to add \rcsection{web} 9.1103 + items to} 9.1104 + 9.1105 +It is important to remember that a web server like Apache or 9.1106 +\texttt{lighttpd} will run under a user~ID that is different to yours. 9.1107 +CGI scripts run by your server, such as \sfilename{hgweb.cgi}, will 9.1108 +usually also run under that user~ID. 9.1109 + 9.1110 +If you add \rcsection{web} items to your own personal \hgrc\ file, CGI 9.1111 +scripts won't read that \hgrc\ file. Those settings will thus only 9.1112 +affect the behaviour of the \hgcmd{serve} command when you run it. To 9.1113 +cause CGI scripts to see your settings, either create a \hgrc\ file in 9.1114 +the home directory of the user ID that runs your web server, or add 9.1115 +those settings to a system-wide \hgrc\ file. 9.1116 + 9.1117 + 9.1118 +%%% Local Variables: 9.1119 +%%% mode: latex 9.1120 +%%% TeX-master: "00book" 9.1121 +%%% End:
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/fr/concepts.tex Thu Feb 05 12:37:03 2009 +0100 10.3 @@ -0,0 +1,577 @@ 10.4 +\chapter{Behind the scenes} 10.5 +\label{chap:concepts} 10.6 + 10.7 +Unlike many revision control systems, the concepts upon which 10.8 +Mercurial is built are simple enough that it's easy to understand how 10.9 +the software really works. Knowing this certainly isn't necessary, 10.10 +but I find it useful to have a ``mental model'' of what's going on. 10.11 + 10.12 +This understanding gives me confidence that Mercurial has been 10.13 +carefully designed to be both \emph{safe} and \emph{efficient}. And 10.14 +just as importantly, if it's easy for me to retain a good idea of what 10.15 +the software is doing when I perform a revision control task, I'm less 10.16 +likely to be surprised by its behaviour. 10.17 + 10.18 +In this chapter, we'll initially cover the core concepts behind 10.19 +Mercurial's design, then continue to discuss some of the interesting 10.20 +details of its implementation. 10.21 + 10.22 +\section{Mercurial's historical record} 10.23 + 10.24 +\subsection{Tracking the history of a single file} 10.25 + 10.26 +When Mercurial tracks modifications to a file, it stores the history 10.27 +of that file in a metadata object called a \emph{filelog}. Each entry 10.28 +in the filelog contains enough information to reconstruct one revision 10.29 +of the file that is being tracked. Filelogs are stored as files in 10.30 +the \sdirname{.hg/store/data} directory. A filelog contains two kinds 10.31 +of information: revision data, and an index to help Mercurial to find 10.32 +a revision efficiently. 10.33 + 10.34 +A file that is large, or has a lot of history, has its filelog stored 10.35 +in separate data (``\texttt{.d}'' suffix) and index (``\texttt{.i}'' 10.36 +suffix) files. For small files without much history, the revision 10.37 +data and index are combined in a single ``\texttt{.i}'' file. The 10.38 +correspondence between a file in the working directory and the filelog 10.39 +that tracks its history in the repository is illustrated in 10.40 +figure~\ref{fig:concepts:filelog}. 10.41 + 10.42 +\begin{figure}[ht] 10.43 + \centering 10.44 + \grafix{filelog} 10.45 + \caption{Relationships between files in working directory and 10.46 + filelogs in repository} 10.47 + \label{fig:concepts:filelog} 10.48 +\end{figure} 10.49 + 10.50 +\subsection{Managing tracked files} 10.51 + 10.52 +Mercurial uses a structure called a \emph{manifest} to collect 10.53 +together information about the files that it tracks. Each entry in 10.54 +the manifest contains information about the files present in a single 10.55 +changeset. An entry records which files are present in the changeset, 10.56 +the revision of each file, and a few other pieces of file metadata. 10.57 + 10.58 +\subsection{Recording changeset information} 10.59 + 10.60 +The \emph{changelog} contains information about each changeset. Each 10.61 +revision records who committed a change, the changeset comment, other 10.62 +pieces of changeset-related information, and the revision of the 10.63 +manifest to use. 10.64 + 10.65 +\subsection{Relationships between revisions} 10.66 + 10.67 +Within a changelog, a manifest, or a filelog, each revision stores a 10.68 +pointer to its immediate parent (or to its two parents, if it's a 10.69 +merge revision). As I mentioned above, there are also relationships 10.70 +between revisions \emph{across} these structures, and they are 10.71 +hierarchical in nature. 10.72 + 10.73 +For every changeset in a repository, there is exactly one revision 10.74 +stored in the changelog. Each revision of the changelog contains a 10.75 +pointer to a single revision of the manifest. A revision of the 10.76 +manifest stores a pointer to a single revision of each filelog tracked 10.77 +when that changeset was created. These relationships are illustrated 10.78 +in figure~\ref{fig:concepts:metadata}. 10.79 + 10.80 +\begin{figure}[ht] 10.81 + \centering 10.82 + \grafix{metadata} 10.83 + \caption{Metadata relationships} 10.84 + \label{fig:concepts:metadata} 10.85 +\end{figure} 10.86 + 10.87 +As the illustration shows, there is \emph{not} a ``one to one'' 10.88 +relationship between revisions in the changelog, manifest, or filelog. 10.89 +If the manifest hasn't changed between two changesets, the changelog 10.90 +entries for those changesets will point to the same revision of the 10.91 +manifest. If a file that Mercurial tracks hasn't changed between two 10.92 +changesets, the entry for that file in the two revisions of the 10.93 +manifest will point to the same revision of its filelog. 10.94 + 10.95 +\section{Safe, efficient storage} 10.96 + 10.97 +The underpinnings of changelogs, manifests, and filelogs are provided 10.98 +by a single structure called the \emph{revlog}. 10.99 + 10.100 +\subsection{Efficient storage} 10.101 + 10.102 +The revlog provides efficient storage of revisions using a 10.103 +\emph{delta} mechanism. Instead of storing a complete copy of a file 10.104 +for each revision, it stores the changes needed to transform an older 10.105 +revision into the new revision. For many kinds of file data, these 10.106 +deltas are typically a fraction of a percent of the size of a full 10.107 +copy of a file. 10.108 + 10.109 +Some obsolete revision control systems can only work with deltas of 10.110 +text files. They must either store binary files as complete snapshots 10.111 +or encoded into a text representation, both of which are wasteful 10.112 +approaches. Mercurial can efficiently handle deltas of files with 10.113 +arbitrary binary contents; it doesn't need to treat text as special. 10.114 + 10.115 +\subsection{Safe operation} 10.116 +\label{sec:concepts:txn} 10.117 + 10.118 +Mercurial only ever \emph{appends} data to the end of a revlog file. 10.119 +It never modifies a section of a file after it has written it. This 10.120 +is both more robust and efficient than schemes that need to modify or 10.121 +rewrite data. 10.122 + 10.123 +In addition, Mercurial treats every write as part of a 10.124 +\emph{transaction} that can span a number of files. A transaction is 10.125 +\emph{atomic}: either the entire transaction succeeds and its effects 10.126 +are all visible to readers in one go, or the whole thing is undone. 10.127 +This guarantee of atomicity means that if you're running two copies of 10.128 +Mercurial, where one is reading data and one is writing it, the reader 10.129 +will never see a partially written result that might confuse it. 10.130 + 10.131 +The fact that Mercurial only appends to files makes it easier to 10.132 +provide this transactional guarantee. The easier it is to do stuff 10.133 +like this, the more confident you should be that it's done correctly. 10.134 + 10.135 +\subsection{Fast retrieval} 10.136 + 10.137 +Mercurial cleverly avoids a pitfall common to all earlier 10.138 +revision control systems: the problem of \emph{inefficient retrieval}. 10.139 +Most revision control systems store the contents of a revision as an 10.140 +incremental series of modifications against a ``snapshot''. To 10.141 +reconstruct a specific revision, you must first read the snapshot, and 10.142 +then every one of the revisions between the snapshot and your target 10.143 +revision. The more history that a file accumulates, the more 10.144 +revisions you must read, hence the longer it takes to reconstruct a 10.145 +particular revision. 10.146 + 10.147 +\begin{figure}[ht] 10.148 + \centering 10.149 + \grafix{snapshot} 10.150 + \caption{Snapshot of a revlog, with incremental deltas} 10.151 + \label{fig:concepts:snapshot} 10.152 +\end{figure} 10.153 + 10.154 +The innovation that Mercurial applies to this problem is simple but 10.155 +effective. Once the cumulative amount of delta information stored 10.156 +since the last snapshot exceeds a fixed threshold, it stores a new 10.157 +snapshot (compressed, of course), instead of another delta. This 10.158 +makes it possible to reconstruct \emph{any} revision of a file 10.159 +quickly. This approach works so well that it has since been copied by 10.160 +several other revision control systems. 10.161 + 10.162 +Figure~\ref{fig:concepts:snapshot} illustrates the idea. In an entry 10.163 +in a revlog's index file, Mercurial stores the range of entries from 10.164 +the data file that it must read to reconstruct a particular revision. 10.165 + 10.166 +\subsubsection{Aside: the influence of video compression} 10.167 + 10.168 +If you're familiar with video compression or have ever watched a TV 10.169 +feed through a digital cable or satellite service, you may know that 10.170 +most video compression schemes store each frame of video as a delta 10.171 +against its predecessor frame. In addition, these schemes use 10.172 +``lossy'' compression techniques to increase the compression ratio, so 10.173 +visual errors accumulate over the course of a number of inter-frame 10.174 +deltas. 10.175 + 10.176 +Because it's possible for a video stream to ``drop out'' occasionally 10.177 +due to signal glitches, and to limit the accumulation of artefacts 10.178 +introduced by the lossy compression process, video encoders 10.179 +periodically insert a complete frame (called a ``key frame'') into the 10.180 +video stream; the next delta is generated against that frame. This 10.181 +means that if the video signal gets interrupted, it will resume once 10.182 +the next key frame is received. Also, the accumulation of encoding 10.183 +errors restarts anew with each key frame. 10.184 + 10.185 +\subsection{Identification and strong integrity} 10.186 + 10.187 +Along with delta or snapshot information, a revlog entry contains a 10.188 +cryptographic hash of the data that it represents. This makes it 10.189 +difficult to forge the contents of a revision, and easy to detect 10.190 +accidental corruption. 10.191 + 10.192 +Hashes provide more than a mere check against corruption; they are 10.193 +used as the identifiers for revisions. The changeset identification 10.194 +hashes that you see as an end user are from revisions of the 10.195 +changelog. Although filelogs and the manifest also use hashes, 10.196 +Mercurial only uses these behind the scenes. 10.197 + 10.198 +Mercurial verifies that hashes are correct when it retrieves file 10.199 +revisions and when it pulls changes from another repository. If it 10.200 +encounters an integrity problem, it will complain and stop whatever 10.201 +it's doing. 10.202 + 10.203 +In addition to the effect it has on retrieval efficiency, Mercurial's 10.204 +use of periodic snapshots makes it more robust against partial data 10.205 +corruption. If a revlog becomes partly corrupted due to a hardware 10.206 +error or system bug, it's often possible to reconstruct some or most 10.207 +revisions from the uncorrupted sections of the revlog, both before and 10.208 +after the corrupted section. This would not be possible with a 10.209 +delta-only storage model. 10.210 + 10.211 +\section{Revision history, branching, 10.212 + and merging} 10.213 + 10.214 +Every entry in a Mercurial revlog knows the identity of its immediate 10.215 +ancestor revision, usually referred to as its \emph{parent}. In fact, 10.216 +a revision contains room for not one parent, but two. Mercurial uses 10.217 +a special hash, called the ``null ID'', to represent the idea ``there 10.218 +is no parent here''. This hash is simply a string of zeroes. 10.219 + 10.220 +In figure~\ref{fig:concepts:revlog}, you can see an example of the 10.221 +conceptual structure of a revlog. Filelogs, manifests, and changelogs 10.222 +all have this same structure; they differ only in the kind of data 10.223 +stored in each delta or snapshot. 10.224 + 10.225 +The first revision in a revlog (at the bottom of the image) has the 10.226 +null ID in both of its parent slots. For a ``normal'' revision, its 10.227 +first parent slot contains the ID of its parent revision, and its 10.228 +second contains the null ID, indicating that the revision has only one 10.229 +real parent. Any two revisions that have the same parent ID are 10.230 +branches. A revision that represents a merge between branches has two 10.231 +normal revision IDs in its parent slots. 10.232 + 10.233 +\begin{figure}[ht] 10.234 + \centering 10.235 + \grafix{revlog} 10.236 + \caption{} 10.237 + \label{fig:concepts:revlog} 10.238 +\end{figure} 10.239 + 10.240 +\section{The working directory} 10.241 + 10.242 +In the working directory, Mercurial stores a snapshot of the files 10.243 +from the repository as of a particular changeset. 10.244 + 10.245 +The working directory ``knows'' which changeset it contains. When you 10.246 +update the working directory to contain a particular changeset, 10.247 +Mercurial looks up the appropriate revision of the manifest to find 10.248 +out which files it was tracking at the time that changeset was 10.249 +committed, and which revision of each file was then current. It then 10.250 +recreates a copy of each of those files, with the same contents it had 10.251 +when the changeset was committed. 10.252 + 10.253 +The \emph{dirstate} contains Mercurial's knowledge of the working 10.254 +directory. This details which changeset the working directory is 10.255 +updated to, and all of the files that Mercurial is tracking in the 10.256 +working directory. 10.257 + 10.258 +Just as a revision of a revlog has room for two parents, so that it 10.259 +can represent either a normal revision (with one parent) or a merge of 10.260 +two earlier revisions, the dirstate has slots for two parents. When 10.261 +you use the \hgcmd{update} command, the changeset that you update to 10.262 +is stored in the ``first parent'' slot, and the null ID in the second. 10.263 +When you \hgcmd{merge} with another changeset, the first parent 10.264 +remains unchanged, and the second parent is filled in with the 10.265 +changeset you're merging with. The \hgcmd{parents} command tells you 10.266 +what the parents of the dirstate are. 10.267 + 10.268 +\subsection{What happens when you commit} 10.269 + 10.270 +The dirstate stores parent information for more than just book-keeping 10.271 +purposes. Mercurial uses the parents of the dirstate as \emph{the 10.272 + parents of a new changeset} when you perform a commit. 10.273 + 10.274 +\begin{figure}[ht] 10.275 + \centering 10.276 + \grafix{wdir} 10.277 + \caption{The working directory can have two parents} 10.278 + \label{fig:concepts:wdir} 10.279 +\end{figure} 10.280 + 10.281 +Figure~\ref{fig:concepts:wdir} shows the normal state of the working 10.282 +directory, where it has a single changeset as parent. That changeset 10.283 +is the \emph{tip}, the newest changeset in the repository that has no 10.284 +children. 10.285 + 10.286 +\begin{figure}[ht] 10.287 + \centering 10.288 + \grafix{wdir-after-commit} 10.289 + \caption{The working directory gains new parents after a commit} 10.290 + \label{fig:concepts:wdir-after-commit} 10.291 +\end{figure} 10.292 + 10.293 +It's useful to think of the working directory as ``the changeset I'm 10.294 +about to commit''. Any files that you tell Mercurial that you've 10.295 +added, removed, renamed, or copied will be reflected in that 10.296 +changeset, as will modifications to any files that Mercurial is 10.297 +already tracking; the new changeset will have the parents of the 10.298 +working directory as its parents. 10.299 + 10.300 +After a commit, Mercurial will update the parents of the working 10.301 +directory, so that the first parent is the ID of the new changeset, 10.302 +and the second is the null ID. This is shown in 10.303 +figure~\ref{fig:concepts:wdir-after-commit}. Mercurial doesn't touch 10.304 +any of the files in the working directory when you commit; it just 10.305 +modifies the dirstate to note its new parents. 10.306 + 10.307 +\subsection{Creating a new head} 10.308 + 10.309 +It's perfectly normal to update the working directory to a changeset 10.310 +other than the current tip. For example, you might want to know what 10.311 +your project looked like last Tuesday, or you could be looking through 10.312 +changesets to see which one introduced a bug. In cases like this, the 10.313 +natural thing to do is update the working directory to the changeset 10.314 +you're interested in, and then examine the files in the working 10.315 +directory directly to see their contents as they were when you 10.316 +committed that changeset. The effect of this is shown in 10.317 +figure~\ref{fig:concepts:wdir-pre-branch}. 10.318 + 10.319 +\begin{figure}[ht] 10.320 + \centering 10.321 + \grafix{wdir-pre-branch} 10.322 + \caption{The working directory, updated to an older changeset} 10.323 + \label{fig:concepts:wdir-pre-branch} 10.324 +\end{figure} 10.325 + 10.326 +Having updated the working directory to an older changeset, what 10.327 +happens if you make some changes, and then commit? Mercurial behaves 10.328 +in the same way as I outlined above. The parents of the working 10.329 +directory become the parents of the new changeset. This new changeset 10.330 +has no children, so it becomes the new tip. And the repository now 10.331 +contains two changesets that have no children; we call these 10.332 +\emph{heads}. You can see the structure that this creates in 10.333 +figure~\ref{fig:concepts:wdir-branch}. 10.334 + 10.335 +\begin{figure}[ht] 10.336 + \centering 10.337 + \grafix{wdir-branch} 10.338 + \caption{After a commit made while synced to an older changeset} 10.339 + \label{fig:concepts:wdir-branch} 10.340 +\end{figure} 10.341 + 10.342 +\begin{note} 10.343 + If you're new to Mercurial, you should keep in mind a common 10.344 + ``error'', which is to use the \hgcmd{pull} command without any 10.345 + options. By default, the \hgcmd{pull} command \emph{does not} 10.346 + update the working directory, so you'll bring new changesets into 10.347 + your repository, but the working directory will stay synced at the 10.348 + same changeset as before the pull. If you make some changes and 10.349 + commit afterwards, you'll thus create a new head, because your 10.350 + working directory isn't synced to whatever the current tip is. 10.351 + 10.352 + I put the word ``error'' in quotes because all that you need to do 10.353 + to rectify this situation is \hgcmd{merge}, then \hgcmd{commit}. In 10.354 + other words, this almost never has negative consequences; it just 10.355 + surprises people. I'll discuss other ways to avoid this behaviour, 10.356 + and why Mercurial behaves in this initially surprising way, later 10.357 + on. 10.358 +\end{note} 10.359 + 10.360 +\subsection{Merging heads} 10.361 + 10.362 +When you run the \hgcmd{merge} command, Mercurial leaves the first 10.363 +parent of the working directory unchanged, and sets the second parent 10.364 +to the changeset you're merging with, as shown in 10.365 +figure~\ref{fig:concepts:wdir-merge}. 10.366 + 10.367 +\begin{figure}[ht] 10.368 + \centering 10.369 + \grafix{wdir-merge} 10.370 + \caption{Merging two heads} 10.371 + \label{fig:concepts:wdir-merge} 10.372 +\end{figure} 10.373 + 10.374 +Mercurial also has to modify the working directory, to merge the files 10.375 +managed in the two changesets. Simplified a little, the merging 10.376 +process goes like this, for every file in the manifests of both 10.377 +changesets. 10.378 +\begin{itemize} 10.379 +\item If neither changeset has modified a file, do nothing with that 10.380 + file. 10.381 +\item If one changeset has modified a file, and the other hasn't, 10.382 + create the modified copy of the file in the working directory. 10.383 +\item If one changeset has removed a file, and the other hasn't (or 10.384 + has also deleted it), delete the file from the working directory. 10.385 +\item If one changeset has removed a file, but the other has modified 10.386 + the file, ask the user what to do: keep the modified file, or remove 10.387 + it? 10.388 +\item If both changesets have modified a file, invoke an external 10.389 + merge program to choose the new contents for the merged file. This 10.390 + may require input from the user. 10.391 +\item If one changeset has modified a file, and the other has renamed 10.392 + or copied the file, make sure that the changes follow the new name 10.393 + of the file. 10.394 +\end{itemize} 10.395 +There are more details---merging has plenty of corner cases---but 10.396 +these are the most common choices that are involved in a merge. As 10.397 +you can see, most cases are completely automatic, and indeed most 10.398 +merges finish automatically, without requiring your input to resolve 10.399 +any conflicts. 10.400 + 10.401 +When you're thinking about what happens when you commit after a merge, 10.402 +once again the working directory is ``the changeset I'm about to 10.403 +commit''. After the \hgcmd{merge} command completes, the working 10.404 +directory has two parents; these will become the parents of the new 10.405 +changeset. 10.406 + 10.407 +Mercurial lets you perform multiple merges, but you must commit the 10.408 +results of each individual merge as you go. This is necessary because 10.409 +Mercurial only tracks two parents for both revisions and the working 10.410 +directory. While it would be technically possible to merge multiple 10.411 +changesets at once, the prospect of user confusion and making a 10.412 +terrible mess of a merge immediately becomes overwhelming. 10.413 + 10.414 +\section{Other interesting design features} 10.415 + 10.416 +In the sections above, I've tried to highlight some of the most 10.417 +important aspects of Mercurial's design, to illustrate that it pays 10.418 +careful attention to reliability and performance. However, the 10.419 +attention to detail doesn't stop there. There are a number of other 10.420 +aspects of Mercurial's construction that I personally find 10.421 +interesting. I'll detail a few of them here, separate from the ``big 10.422 +ticket'' items above, so that if you're interested, you can gain a 10.423 +better idea of the amount of thinking that goes into a well-designed 10.424 +system. 10.425 + 10.426 +\subsection{Clever compression} 10.427 + 10.428 +When appropriate, Mercurial will store both snapshots and deltas in 10.429 +compressed form. It does this by always \emph{trying to} compress a 10.430 +snapshot or delta, but only storing the compressed version if it's 10.431 +smaller than the uncompressed version. 10.432 + 10.433 +This means that Mercurial does ``the right thing'' when storing a file 10.434 +whose native form is compressed, such as a \texttt{zip} archive or a 10.435 +JPEG image. When these types of files are compressed a second time, 10.436 +the resulting file is usually bigger than the once-compressed form, 10.437 +and so Mercurial will store the plain \texttt{zip} or JPEG. 10.438 + 10.439 +Deltas between revisions of a compressed file are usually larger than 10.440 +snapshots of the file, and Mercurial again does ``the right thing'' in 10.441 +these cases. It finds that such a delta exceeds the threshold at 10.442 +which it should store a complete snapshot of the file, so it stores 10.443 +the snapshot, again saving space compared to a naive delta-only 10.444 +approach. 10.445 + 10.446 +\subsubsection{Network recompression} 10.447 + 10.448 +When storing revisions on disk, Mercurial uses the ``deflate'' 10.449 +compression algorithm (the same one used by the popular \texttt{zip} 10.450 +archive format), which balances good speed with a respectable 10.451 +compression ratio. However, when transmitting revision data over a 10.452 +network connection, Mercurial uncompresses the compressed revision 10.453 +data. 10.454 + 10.455 +If the connection is over HTTP, Mercurial recompresses the entire 10.456 +stream of data using a compression algorithm that gives a better 10.457 +compression ratio (the Burrows-Wheeler algorithm from the widely used 10.458 +\texttt{bzip2} compression package). This combination of algorithm 10.459 +and compression of the entire stream (instead of a revision at a time) 10.460 +substantially reduces the number of bytes to be transferred, yielding 10.461 +better network performance over almost all kinds of network. 10.462 + 10.463 +(If the connection is over \command{ssh}, Mercurial \emph{doesn't} 10.464 +recompress the stream, because \command{ssh} can already do this 10.465 +itself.) 10.466 + 10.467 +\subsection{Read/write ordering and atomicity} 10.468 + 10.469 +Appending to files isn't the whole story when it comes to guaranteeing 10.470 +that a reader won't see a partial write. If you recall 10.471 +figure~\ref{fig:concepts:metadata}, revisions in the changelog point to 10.472 +revisions in the manifest, and revisions in the manifest point to 10.473 +revisions in filelogs. This hierarchy is deliberate. 10.474 + 10.475 +A writer starts a transaction by writing filelog and manifest data, 10.476 +and doesn't write any changelog data until those are finished. A 10.477 +reader starts by reading changelog data, then manifest data, followed 10.478 +by filelog data. 10.479 + 10.480 +Since the writer has always finished writing filelog and manifest data 10.481 +before it writes to the changelog, a reader will never read a pointer 10.482 +to a partially written manifest revision from the changelog, and it will 10.483 +never read a pointer to a partially written filelog revision from the 10.484 +manifest. 10.485 + 10.486 +\subsection{Concurrent access} 10.487 + 10.488 +The read/write ordering and atomicity guarantees mean that Mercurial 10.489 +never needs to \emph{lock} a repository when it's reading data, even 10.490 +if the repository is being written to while the read is occurring. 10.491 +This has a big effect on scalability; you can have an arbitrary number 10.492 +of Mercurial processes safely reading data from a repository safely 10.493 +all at once, no matter whether it's being written to or not. 10.494 + 10.495 +The lockless nature of reading means that if you're sharing a 10.496 +repository on a multi-user system, you don't need to grant other local 10.497 +users permission to \emph{write} to your repository in order for them 10.498 +to be able to clone it or pull changes from it; they only need 10.499 +\emph{read} permission. (This is \emph{not} a common feature among 10.500 +revision control systems, so don't take it for granted! Most require 10.501 +readers to be able to lock a repository to access it safely, and this 10.502 +requires write permission on at least one directory, which of course 10.503 +makes for all kinds of nasty and annoying security and administrative 10.504 +problems.) 10.505 + 10.506 +Mercurial uses locks to ensure that only one process can write to a 10.507 +repository at a time (the locking mechanism is safe even over 10.508 +filesystems that are notoriously hostile to locking, such as NFS). If 10.509 +a repository is locked, a writer will wait for a while to retry if the 10.510 +repository becomes unlocked, but if the repository remains locked for 10.511 +too long, the process attempting to write will time out after a while. 10.512 +This means that your daily automated scripts won't get stuck forever 10.513 +and pile up if a system crashes unnoticed, for example. (Yes, the 10.514 +timeout is configurable, from zero to infinity.) 10.515 + 10.516 +\subsubsection{Safe dirstate access} 10.517 + 10.518 +As with revision data, Mercurial doesn't take a lock to read the 10.519 +dirstate file; it does acquire a lock to write it. To avoid the 10.520 +possibility of reading a partially written copy of the dirstate file, 10.521 +Mercurial writes to a file with a unique name in the same directory as 10.522 +the dirstate file, then renames the temporary file atomically to 10.523 +\filename{dirstate}. The file named \filename{dirstate} is thus 10.524 +guaranteed to be complete, not partially written. 10.525 + 10.526 +\subsection{Avoiding seeks} 10.527 + 10.528 +Critical to Mercurial's performance is the avoidance of seeks of the 10.529 +disk head, since any seek is far more expensive than even a 10.530 +comparatively large read operation. 10.531 + 10.532 +This is why, for example, the dirstate is stored in a single file. If 10.533 +there were a dirstate file per directory that Mercurial tracked, the 10.534 +disk would seek once per directory. Instead, Mercurial reads the 10.535 +entire single dirstate file in one step. 10.536 + 10.537 +Mercurial also uses a ``copy on write'' scheme when cloning a 10.538 +repository on local storage. Instead of copying every revlog file 10.539 +from the old repository into the new repository, it makes a ``hard 10.540 +link'', which is a shorthand way to say ``these two names point to the 10.541 +same file''. When Mercurial is about to write to one of a revlog's 10.542 +files, it checks to see if the number of names pointing at the file is 10.543 +greater than one. If it is, more than one repository is using the 10.544 +file, so Mercurial makes a new copy of the file that is private to 10.545 +this repository. 10.546 + 10.547 +A few revision control developers have pointed out that this idea of 10.548 +making a complete private copy of a file is not very efficient in its 10.549 +use of storage. While this is true, storage is cheap, and this method 10.550 +gives the highest performance while deferring most book-keeping to the 10.551 +operating system. An alternative scheme would most likely reduce 10.552 +performance and increase the complexity of the software, each of which 10.553 +is much more important to the ``feel'' of day-to-day use. 10.554 + 10.555 +\subsection{Other contents of the dirstate} 10.556 + 10.557 +Because Mercurial doesn't force you to tell it when you're modifying a 10.558 +file, it uses the dirstate to store some extra information so it can 10.559 +determine efficiently whether you have modified a file. For each file 10.560 +in the working directory, it stores the time that it last modified the 10.561 +file itself, and the size of the file at that time. 10.562 + 10.563 +When you explicitly \hgcmd{add}, \hgcmd{remove}, \hgcmd{rename} or 10.564 +\hgcmd{copy} files, Mercurial updates the dirstate so that it knows 10.565 +what to do with those files when you commit. 10.566 + 10.567 +When Mercurial is checking the states of files in the working 10.568 +directory, it first checks a file's modification time. If that has 10.569 +not changed, the file must not have been modified. If the file's size 10.570 +has changed, the file must have been modified. If the modification 10.571 +time has changed, but the size has not, only then does Mercurial need 10.572 +to read the actual contents of the file to see if they've changed. 10.573 +Storing these few extra pieces of information dramatically reduces the 10.574 +amount of data that Mercurial needs to read, which yields large 10.575 +performance improvements compared to other revision control systems. 10.576 + 10.577 +%%% Local Variables: 10.578 +%%% mode: latex 10.579 +%%% TeX-master: "00book" 10.580 +%%% End:
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/fr/daily.tex Thu Feb 05 12:37:03 2009 +0100 11.3 @@ -0,0 +1,381 @@ 11.4 +\chapter{Mercurial in daily use} 11.5 +\label{chap:daily} 11.6 + 11.7 +\section{Telling Mercurial which files to track} 11.8 + 11.9 +Mercurial does not work with files in your repository unless you tell 11.10 +it to manage them. The \hgcmd{status} command will tell you which 11.11 +files Mercurial doesn't know about; it uses a ``\texttt{?}'' to 11.12 +display such files. 11.13 + 11.14 +To tell Mercurial to track a file, use the \hgcmd{add} command. Once 11.15 +you have added a file, the entry in the output of \hgcmd{status} for 11.16 +that file changes from ``\texttt{?}'' to ``\texttt{A}''. 11.17 +\interaction{daily.files.add} 11.18 + 11.19 +After you run a \hgcmd{commit}, the files that you added before the 11.20 +commit will no longer be listed in the output of \hgcmd{status}. The 11.21 +reason for this is that \hgcmd{status} only tells you about 11.22 +``interesting'' files---those that you have modified or told Mercurial 11.23 +to do something with---by default. If you have a repository that 11.24 +contains thousands of files, you will rarely want to know about files 11.25 +that Mercurial is tracking, but that have not changed. (You can still 11.26 +get this information; we'll return to this later.) 11.27 + 11.28 +Once you add a file, Mercurial doesn't do anything with it 11.29 +immediately. Instead, it will take a snapshot of the file's state the 11.30 +next time you perform a commit. It will then continue to track the 11.31 +changes you make to the file every time you commit, until you remove 11.32 +the file. 11.33 + 11.34 +\subsection{Explicit versus implicit file naming} 11.35 + 11.36 +A useful behaviour that Mercurial has is that if you pass the name of 11.37 +a directory to a command, every Mercurial command will treat this as 11.38 +``I want to operate on every file in this directory and its 11.39 +subdirectories''. 11.40 +\interaction{daily.files.add-dir} 11.41 +Notice in this example that Mercurial printed the names of the files 11.42 +it added, whereas it didn't do so when we added the file named 11.43 +\filename{a} in the earlier example. 11.44 + 11.45 +What's going on is that in the former case, we explicitly named the 11.46 +file to add on the command line, so the assumption that Mercurial 11.47 +makes in such cases is that you know what you were doing, and it 11.48 +doesn't print any output. 11.49 + 11.50 +However, when we \emph{imply} the names of files by giving the name of 11.51 +a directory, Mercurial takes the extra step of printing the name of 11.52 +each file that it does something with. This makes it more clear what 11.53 +is happening, and reduces the likelihood of a silent and nasty 11.54 +surprise. This behaviour is common to most Mercurial commands. 11.55 + 11.56 +\subsection{Aside: Mercurial tracks files, not directories} 11.57 + 11.58 +Mercurial does not track directory information. Instead, it tracks 11.59 +the path to a file. Before creating a file, it first creates any 11.60 +missing directory components of the path. After it deletes a file, it 11.61 +then deletes any empty directories that were in the deleted file's 11.62 +path. This sounds like a trivial distinction, but it has one minor 11.63 +practical consequence: it is not possible to represent a completely 11.64 +empty directory in Mercurial. 11.65 + 11.66 +Empty directories are rarely useful, and there are unintrusive 11.67 +workarounds that you can use to achieve an appropriate effect. The 11.68 +developers of Mercurial thus felt that the complexity that would be 11.69 +required to manage empty directories was not worth the limited benefit 11.70 +this feature would bring. 11.71 + 11.72 +If you need an empty directory in your repository, there are a few 11.73 +ways to achieve this. One is to create a directory, then \hgcmd{add} a 11.74 +``hidden'' file to that directory. On Unix-like systems, any file 11.75 +name that begins with a period (``\texttt{.}'') is treated as hidden 11.76 +by most commands and GUI tools. This approach is illustrated in 11.77 +figure~\ref{ex:daily:hidden}. 11.78 + 11.79 +\begin{figure}[ht] 11.80 + \interaction{daily.files.hidden} 11.81 + \caption{Simulating an empty directory using a hidden file} 11.82 + \label{ex:daily:hidden} 11.83 +\end{figure} 11.84 + 11.85 +Another way to tackle a need for an empty directory is to simply 11.86 +create one in your automated build scripts before they will need it. 11.87 + 11.88 +\section{How to stop tracking a file} 11.89 + 11.90 +Once you decide that a file no longer belongs in your repository, use 11.91 +the \hgcmd{remove} command; this deletes the file, and tells Mercurial 11.92 +to stop tracking it. A removed file is represented in the output of 11.93 +\hgcmd{status} with a ``\texttt{R}''. 11.94 +\interaction{daily.files.remove} 11.95 + 11.96 +After you \hgcmd{remove} a file, Mercurial will no longer track 11.97 +changes to that file, even if you recreate a file with the same name 11.98 +in your working directory. If you do recreate a file with the same 11.99 +name and want Mercurial to track the new file, simply \hgcmd{add} it. 11.100 +Mercurial will know that the newly added file is not related to the 11.101 +old file of the same name. 11.102 + 11.103 +\subsection{Removing a file does not affect its history} 11.104 + 11.105 +It is important to understand that removing a file has only two 11.106 +effects. 11.107 +\begin{itemize} 11.108 +\item It removes the current version of the file from the working 11.109 + directory. 11.110 +\item It stops Mercurial from tracking changes to the file, from the 11.111 + time of the next commit. 11.112 +\end{itemize} 11.113 +Removing a file \emph{does not} in any way alter the \emph{history} of 11.114 +the file. 11.115 + 11.116 +If you update the working directory to a changeset in which a file 11.117 +that you have removed was still tracked, it will reappear in the 11.118 +working directory, with the contents it had when you committed that 11.119 +changeset. If you then update the working directory to a later 11.120 +changeset, in which the file had been removed, Mercurial will once 11.121 +again remove the file from the working directory. 11.122 + 11.123 +\subsection{Missing files} 11.124 + 11.125 +Mercurial considers a file that you have deleted, but not used 11.126 +\hgcmd{remove} to delete, to be \emph{missing}. A missing file is 11.127 +represented with ``\texttt{!}'' in the output of \hgcmd{status}. 11.128 +Mercurial commands will not generally do anything with missing files. 11.129 +\interaction{daily.files.missing} 11.130 + 11.131 +If your repository contains a file that \hgcmd{status} reports as 11.132 +missing, and you want the file to stay gone, you can run 11.133 +\hgcmdargs{remove}{\hgopt{remove}{--after}} at any time later on, to 11.134 +tell Mercurial that you really did mean to remove the file. 11.135 +\interaction{daily.files.remove-after} 11.136 + 11.137 +On the other hand, if you deleted the missing file by accident, use 11.138 +\hgcmdargs{revert}{\emph{filename}} to recover the file. It will 11.139 +reappear, in unmodified form. 11.140 +\interaction{daily.files.recover-missing} 11.141 + 11.142 +\subsection{Aside: why tell Mercurial explicitly to 11.143 + remove a file?} 11.144 + 11.145 +You might wonder why Mercurial requires you to explicitly tell it that 11.146 +you are deleting a file. Early during the development of Mercurial, 11.147 +it let you delete a file however you pleased; Mercurial would notice 11.148 +the absence of the file automatically when you next ran a 11.149 +\hgcmd{commit}, and stop tracking the file. In practice, this made it 11.150 +too easy to accidentally remove a file without noticing. 11.151 + 11.152 +\subsection{Useful shorthand---adding and removing files 11.153 + in one step} 11.154 + 11.155 +Mercurial offers a combination command, \hgcmd{addremove}, that adds 11.156 +untracked files and marks missing files as removed. 11.157 +\interaction{daily.files.addremove} 11.158 +The \hgcmd{commit} command also provides a \hgopt{commit}{-A} option 11.159 +that performs this same add-and-remove, immediately followed by a 11.160 +commit. 11.161 +\interaction{daily.files.commit-addremove} 11.162 + 11.163 +\section{Copying files} 11.164 + 11.165 +Mercurial provides a \hgcmd{copy} command that lets you make a new 11.166 +copy of a file. When you copy a file using this command, Mercurial 11.167 +makes a record of the fact that the new file is a copy of the original 11.168 +file. It treats these copied files specially when you merge your work 11.169 +with someone else's. 11.170 + 11.171 +\subsection{The results of copying during a merge} 11.172 + 11.173 +What happens during a merge is that changes ``follow'' a copy. To 11.174 +best illustrate what this means, let's create an example. We'll start 11.175 +with the usual tiny repository that contains a single file. 11.176 +\interaction{daily.copy.init} 11.177 +We need to do some work in parallel, so that we'll have something to 11.178 +merge. So let's clone our repository. 11.179 +\interaction{daily.copy.clone} 11.180 +Back in our initial repository, let's use the \hgcmd{copy} command to 11.181 +make a copy of the first file we created. 11.182 +\interaction{daily.copy.copy} 11.183 + 11.184 +If we look at the output of the \hgcmd{status} command afterwards, the 11.185 +copied file looks just like a normal added file. 11.186 +\interaction{daily.copy.status} 11.187 +But if we pass the \hgopt{status}{-C} option to \hgcmd{status}, it 11.188 +prints another line of output: this is the file that our newly-added 11.189 +file was copied \emph{from}. 11.190 +\interaction{daily.copy.status-copy} 11.191 + 11.192 +Now, back in the repository we cloned, let's make a change in 11.193 +parallel. We'll add a line of content to the original file that we 11.194 +created. 11.195 +\interaction{daily.copy.other} 11.196 +Now we have a modified \filename{file} in this repository. When we 11.197 +pull the changes from the first repository, and merge the two heads, 11.198 +Mercurial will propagate the changes that we made locally to 11.199 +\filename{file} into its copy, \filename{new-file}. 11.200 +\interaction{daily.copy.merge} 11.201 + 11.202 +\subsection{Why should changes follow copies?} 11.203 +\label{sec:daily:why-copy} 11.204 + 11.205 +This behaviour, of changes to a file propagating out to copies of the 11.206 +file, might seem esoteric, but in most cases it's highly desirable. 11.207 + 11.208 +First of all, remember that this propagation \emph{only} happens when 11.209 +you merge. So if you \hgcmd{copy} a file, and subsequently modify the 11.210 +original file during the normal course of your work, nothing will 11.211 +happen. 11.212 + 11.213 +The second thing to know is that modifications will only propagate 11.214 +across a copy as long as the repository that you're pulling changes 11.215 +from \emph{doesn't know} about the copy. 11.216 + 11.217 +The reason that Mercurial does this is as follows. Let's say I make 11.218 +an important bug fix in a source file, and commit my changes. 11.219 +Meanwhile, you've decided to \hgcmd{copy} the file in your repository, 11.220 +without knowing about the bug or having seen the fix, and you have 11.221 +started hacking on your copy of the file. 11.222 + 11.223 +If you pulled and merged my changes, and Mercurial \emph{didn't} 11.224 +propagate changes across copies, your source file would now contain 11.225 +the bug, and unless you remembered to propagate the bug fix by hand, 11.226 +the bug would \emph{remain} in your copy of the file. 11.227 + 11.228 +By automatically propagating the change that fixed the bug from the 11.229 +original file to the copy, Mercurial prevents this class of problem. 11.230 +To my knowledge, Mercurial is the \emph{only} revision control system 11.231 +that propagates changes across copies like this. 11.232 + 11.233 +Once your change history has a record that the copy and subsequent 11.234 +merge occurred, there's usually no further need to propagate changes 11.235 +from the original file to the copied file, and that's why Mercurial 11.236 +only propagates changes across copies until this point, and no 11.237 +further. 11.238 + 11.239 +\subsection{How to make changes \emph{not} follow a copy} 11.240 + 11.241 +If, for some reason, you decide that this business of automatically 11.242 +propagating changes across copies is not for you, simply use your 11.243 +system's normal file copy command (on Unix-like systems, that's 11.244 +\command{cp}) to make a copy of a file, then \hgcmd{add} the new copy 11.245 +by hand. Before you do so, though, please do reread 11.246 +section~\ref{sec:daily:why-copy}, and make an informed decision that 11.247 +this behaviour is not appropriate to your specific case. 11.248 + 11.249 +\subsection{Behaviour of the \hgcmd{copy} command} 11.250 + 11.251 +When you use the \hgcmd{copy} command, Mercurial makes a copy of each 11.252 +source file as it currently stands in the working directory. This 11.253 +means that if you make some modifications to a file, then \hgcmd{copy} 11.254 +it without first having committed those changes, the new copy will 11.255 +also contain the modifications you have made up until that point. (I 11.256 +find this behaviour a little counterintuitive, which is why I mention 11.257 +it here.) 11.258 + 11.259 +The \hgcmd{copy} command acts similarly to the Unix \command{cp} 11.260 +command (you can use the \hgcmd{cp} alias if you prefer). The last 11.261 +argument is the \emph{destination}, and all prior arguments are 11.262 +\emph{sources}. If you pass it a single file as the source, and the 11.263 +destination does not exist, it creates a new file with that name. 11.264 +\interaction{daily.copy.simple} 11.265 +If the destination is a directory, Mercurial copies its sources into 11.266 +that directory. 11.267 +\interaction{daily.copy.dir-dest} 11.268 +Copying a directory is recursive, and preserves the directory 11.269 +structure of the source. 11.270 +\interaction{daily.copy.dir-src} 11.271 +If the source and destination are both directories, the source tree is 11.272 +recreated in the destination directory. 11.273 +\interaction{daily.copy.dir-src-dest} 11.274 + 11.275 +As with the \hgcmd{rename} command, if you copy a file manually and 11.276 +then want Mercurial to know that you've copied the file, simply use 11.277 +the \hgopt{copy}{--after} option to \hgcmd{copy}. 11.278 +\interaction{daily.copy.after} 11.279 + 11.280 +\section{Renaming files} 11.281 + 11.282 +It's rather more common to need to rename a file than to make a copy 11.283 +of it. The reason I discussed the \hgcmd{copy} command before talking 11.284 +about renaming files is that Mercurial treats a rename in essentially 11.285 +the same way as a copy. Therefore, knowing what Mercurial does when 11.286 +you copy a file tells you what to expect when you rename a file. 11.287 + 11.288 +When you use the \hgcmd{rename} command, Mercurial makes a copy of 11.289 +each source file, then deletes it and marks the file as removed. 11.290 +\interaction{daily.rename.rename} 11.291 +The \hgcmd{status} command shows the newly copied file as added, and 11.292 +the copied-from file as removed. 11.293 +\interaction{daily.rename.status} 11.294 +As with the results of a \hgcmd{copy}, we must use the 11.295 +\hgopt{status}{-C} option to \hgcmd{status} to see that the added file 11.296 +is really being tracked by Mercurial as a copy of the original, now 11.297 +removed, file. 11.298 +\interaction{daily.rename.status-copy} 11.299 + 11.300 +As with \hgcmd{remove} and \hgcmd{copy}, you can tell Mercurial about 11.301 +a rename after the fact using the \hgopt{rename}{--after} option. In 11.302 +most other respects, the behaviour of the \hgcmd{rename} command, and 11.303 +the options it accepts, are similar to the \hgcmd{copy} command. 11.304 + 11.305 +\subsection{Renaming files and merging changes} 11.306 + 11.307 +Since Mercurial's rename is implemented as copy-and-remove, the same 11.308 +propagation of changes happens when you merge after a rename as after 11.309 +a copy. 11.310 + 11.311 +If I modify a file, and you rename it to a new name, and then we merge 11.312 +our respective changes, my modifications to the file under its 11.313 +original name will be propagated into the file under its new name. 11.314 +(This is something you might expect to ``simply work,'' but not all 11.315 +revision control systems actually do this.) 11.316 + 11.317 +Whereas having changes follow a copy is a feature where you can 11.318 +perhaps nod and say ``yes, that might be useful,'' it should be clear 11.319 +that having them follow a rename is definitely important. Without 11.320 +this facility, it would simply be too easy for changes to become 11.321 +orphaned when files are renamed. 11.322 + 11.323 +\subsection{Divergent renames and merging} 11.324 + 11.325 +The case of diverging names occurs when two developers start with a 11.326 +file---let's call it \filename{foo}---in their respective 11.327 +repositories. 11.328 + 11.329 +\interaction{rename.divergent.clone} 11.330 +Anne renames the file to \filename{bar}. 11.331 +\interaction{rename.divergent.rename.anne} 11.332 +Meanwhile, Bob renames it to \filename{quux}. 11.333 +\interaction{rename.divergent.rename.bob} 11.334 + 11.335 +I like to think of this as a conflict because each developer has 11.336 +expressed different intentions about what the file ought to be named. 11.337 + 11.338 +What do you think should happen when they merge their work? 11.339 +Mercurial's actual behaviour is that it always preserves \emph{both} 11.340 +names when it merges changesets that contain divergent renames. 11.341 +\interaction{rename.divergent.merge} 11.342 + 11.343 +Notice that Mercurial does warn about the divergent renames, but it 11.344 +leaves it up to you to do something about the divergence after the merge. 11.345 + 11.346 +\subsection{Convergent renames and merging} 11.347 + 11.348 +Another kind of rename conflict occurs when two people choose to 11.349 +rename different \emph{source} files to the same \emph{destination}. 11.350 +In this case, Mercurial runs its normal merge machinery, and lets you 11.351 +guide it to a suitable resolution. 11.352 + 11.353 +\subsection{Other name-related corner cases} 11.354 + 11.355 +Mercurial has a longstanding bug in which it fails to handle a merge 11.356 +where one side has a file with a given name, while another has a 11.357 +directory with the same name. This is documented as~\bug{29}. 11.358 +\interaction{issue29.go} 11.359 + 11.360 +\section{Recovering from mistakes} 11.361 + 11.362 +Mercurial has some useful commands that will help you to recover from 11.363 +some common mistakes. 11.364 + 11.365 +The \hgcmd{revert} command lets you undo changes that you have made to 11.366 +your working directory. For example, if you \hgcmd{add} a file by 11.367 +accident, just run \hgcmd{revert} with the name of the file you added, 11.368 +and while the file won't be touched in any way, it won't be tracked 11.369 +for adding by Mercurial any longer, either. You can also use 11.370 +\hgcmd{revert} to get rid of erroneous changes to a file. 11.371 + 11.372 +It's useful to remember that the \hgcmd{revert} command is useful for 11.373 +changes that you have not yet committed. Once you've committed a 11.374 +change, if you decide it was a mistake, you can still do something 11.375 +about it, though your options may be more limited. 11.376 + 11.377 +For more information about the \hgcmd{revert} command, and details 11.378 +about how to deal with changes you have already committed, see 11.379 +chapter~\ref{chap:undo}. 11.380 + 11.381 +%%% Local Variables: 11.382 +%%% mode: latex 11.383 +%%% TeX-master: "00book" 11.384 +%%% End:
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/fr/examples/backout Thu Feb 05 12:37:03 2009 +0100 12.3 @@ -0,0 +1,83 @@ 12.4 +#!/bin/bash 12.5 + 12.6 +# We have to fake the merges here, because they cause conflicts with 12.7 +# three-way command-line merge, and kdiff3 may not be available. 12.8 + 12.9 +export HGMERGE=$(mktemp) 12.10 +echo '#!/bin/sh' >> $HGMERGE 12.11 +echo 'echo first change > "$1"' >> $HGMERGE 12.12 +echo 'echo third change >> "$1"' >> $HGMERGE 12.13 +chmod 700 $HGMERGE 12.14 + 12.15 +#$ name: init 12.16 + 12.17 +hg init myrepo 12.18 +cd myrepo 12.19 +echo first change >> myfile 12.20 +hg add myfile 12.21 +hg commit -m 'first change' 12.22 +echo second change >> myfile 12.23 +hg commit -m 'second change' 12.24 + 12.25 +#$ name: simple 12.26 + 12.27 +hg backout -m 'back out second change' tip 12.28 +cat myfile 12.29 + 12.30 +#$ name: simple.log 12.31 +#$ ignore: \s+200[78]-.* 12.32 + 12.33 +hg log --style compact 12.34 + 12.35 +#$ name: non-tip.clone 12.36 + 12.37 +cd .. 12.38 +hg clone -r1 myrepo non-tip-repo 12.39 +cd non-tip-repo 12.40 + 12.41 +#$ name: non-tip.backout 12.42 + 12.43 +echo third change >> myfile 12.44 +hg commit -m 'third change' 12.45 +hg backout --merge -m 'back out second change' 1 12.46 + 12.47 +#$ name: non-tip.cat 12.48 +cat myfile 12.49 + 12.50 +#$ name: manual.clone 12.51 + 12.52 +cd .. 12.53 +hg clone -r1 myrepo newrepo 12.54 +cd newrepo 12.55 + 12.56 +#$ name: manual.backout 12.57 + 12.58 +echo third change >> myfile 12.59 +hg commit -m 'third change' 12.60 +hg backout -m 'back out second change' 1 12.61 + 12.62 +#$ name: manual.log 12.63 + 12.64 +hg log --style compact 12.65 + 12.66 +#$ name: manual.parents 12.67 + 12.68 +hg parents 12.69 + 12.70 +#$ name: manual.heads 12.71 + 12.72 +hg heads 12.73 + 12.74 +#$ name: manual.cat 12.75 + 12.76 +cat myfile 12.77 + 12.78 +#$ name: manual.merge 12.79 + 12.80 +hg merge 12.81 +hg commit -m 'merged backout with previous tip' 12.82 +cat myfile 12.83 + 12.84 +#$ name: 12.85 + 12.86 +rm $HGMERGE
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/fr/examples/bisect Thu Feb 05 12:37:03 2009 +0100 13.3 @@ -0,0 +1,92 @@ 13.4 +#!/bin/bash 13.5 + 13.6 +if hg -v | head -1 | grep -e "version 0.*" 13.7 +then 13.8 +#On mercurial 1.0 and later bisect is a builtin 13.9 +echo '[extensions]' >> $HGRC 13.10 +echo 'hbisect =' >> $HGRC 13.11 +fi 13.12 + 13.13 +# XXX There's some kind of horrible nondeterminism in the execution of 13.14 +# bisect at the moment. Ugh. 13.15 + 13.16 +#$ ignore: .* 13.17 + 13.18 +#$ name: init 13.19 + 13.20 +hg init mybug 13.21 +cd mybug 13.22 + 13.23 +#$ name: commits 13.24 + 13.25 +buggy_change=22 13.26 + 13.27 +for (( i = 0; i < 35; i++ )); do 13.28 + if [[ $i = $buggy_change ]]; then 13.29 + echo 'i have a gub' > myfile$i 13.30 + hg commit -q -A -m 'buggy changeset' 13.31 + else 13.32 + echo 'nothing to see here, move along' > myfile$i 13.33 + hg commit -q -A -m 'normal changeset' 13.34 + fi 13.35 +done 13.36 + 13.37 +#$ name: help 13.38 + 13.39 +hg help bisect 13.40 + 13.41 +#$ name: search.init 13.42 + 13.43 +hg bisect init 13.44 + 13.45 +#$ name: search.bad-init 13.46 + 13.47 +hg bisect bad 13.48 + 13.49 +#$ name: search.good-init 13.50 + 13.51 +hg bisect good 10 13.52 + 13.53 +#$ name: search.step1 13.54 + 13.55 +if grep -q 'i have a gub' * 13.56 +then 13.57 + result=bad 13.58 +else 13.59 + result=good 13.60 +fi 13.61 + 13.62 +echo this revision is $result 13.63 +hg bisect --$result 13.64 + 13.65 +#$ name: search.mytest 13.66 + 13.67 +mytest() { 13.68 + if grep -q 'i have a gub' * 13.69 + then 13.70 + result=bad 13.71 + else 13.72 + result=good 13.73 + fi 13.74 + 13.75 + echo this revision is $result 13.76 + hg bisect $result 13.77 +} 13.78 + 13.79 +#$ name: search.step2 13.80 + 13.81 +mytest 13.82 + 13.83 +#$ name: search.rest 13.84 + 13.85 +mytest 13.86 +mytest 13.87 +mytest 13.88 + 13.89 +#$ name: search.reset 13.90 + 13.91 +hg bisect reset 13.92 + 13.93 +#$ name: 13.94 + 13.95 +exit 0
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/fr/examples/branch-named Thu Feb 05 12:37:03 2009 +0100 14.3 @@ -0,0 +1,73 @@ 14.4 +#!/bin/bash 14.5 + 14.6 +hg init a 14.7 +cd a 14.8 +echo hello > myfile 14.9 +hg commit -A -m 'Initial commit' 14.10 + 14.11 +#$ name: branches 14.12 + 14.13 +hg tip 14.14 +hg branches 14.15 + 14.16 +#$ name: branch 14.17 + 14.18 +hg branch 14.19 + 14.20 +#$ name: create 14.21 + 14.22 +hg branch foo 14.23 +hg branch 14.24 + 14.25 +#$ name: status 14.26 + 14.27 +hg status 14.28 +hg tip 14.29 + 14.30 +#$ name: commit 14.31 + 14.32 +echo 'hello again' >> myfile 14.33 +hg commit -m 'Second commit' 14.34 +hg tip 14.35 + 14.36 +#$ name: rebranch 14.37 + 14.38 +hg branch 14.39 +hg branch bar 14.40 +echo new file > newfile 14.41 +hg commit -A -m 'Third commit' 14.42 +hg tip 14.43 + 14.44 +#$ name: parents 14.45 + 14.46 +hg parents 14.47 +hg branches 14.48 + 14.49 +#$ name: update-switchy 14.50 + 14.51 +hg update foo 14.52 +hg parents 14.53 +hg update bar 14.54 +hg parents 14.55 + 14.56 +#$ name: update-nothing 14.57 + 14.58 +hg update foo 14.59 +hg update 14.60 + 14.61 +#$ name: foo-commit 14.62 + 14.63 +echo something > somefile 14.64 +hg commit -A -m 'New file' 14.65 +hg heads 14.66 + 14.67 +#$ name: update-bar 14.68 + 14.69 +hg update bar 14.70 + 14.71 +#$ name: merge 14.72 + 14.73 +hg branch 14.74 +hg merge foo 14.75 +hg commit -m 'Merge' 14.76 +hg tip
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/fr/examples/branch-repo Thu Feb 05 12:37:03 2009 +0100 15.3 @@ -0,0 +1,48 @@ 15.4 +#!/bin/bash 15.5 + 15.6 +hg init myproject 15.7 +cd myproject 15.8 +echo hello > myfile 15.9 +hg commit -A -m 'Initial commit' 15.10 +cd .. 15.11 + 15.12 +#$ name: tag 15.13 + 15.14 +cd myproject 15.15 +hg tag v1.0 15.16 + 15.17 +#$ name: clone 15.18 + 15.19 +cd .. 15.20 +hg clone myproject myproject-1.0.1 15.21 + 15.22 +#$ name: bugfix 15.23 + 15.24 +hg clone myproject-1.0.1 my-1.0.1-bugfix 15.25 +cd my-1.0.1-bugfix 15.26 +echo 'I fixed a bug using only echo!' >> myfile 15.27 +hg commit -m 'Important fix for 1.0.1' 15.28 +#$ ignore: /tmp/branch-repo.* 15.29 +hg push 15.30 + 15.31 +#$ name: new 15.32 + 15.33 +cd .. 15.34 +hg clone myproject my-feature 15.35 +cd my-feature 15.36 +echo 'This sure is an exciting new feature!' > mynewfile 15.37 +hg commit -A -m 'New feature' 15.38 +hg push 15.39 + 15.40 +#$ name: pull 15.41 + 15.42 +cd .. 15.43 +hg clone myproject myproject-merge 15.44 +cd myproject-merge 15.45 +hg pull ../myproject-1.0.1 15.46 + 15.47 +#$ name: merge 15.48 + 15.49 +hg merge 15.50 +hg commit -m 'Merge bugfix from 1.0.1 branch' 15.51 +hg push
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/fr/examples/branching Thu Feb 05 12:37:03 2009 +0100 16.3 @@ -0,0 +1,63 @@ 16.4 +#!/bin/bash 16.5 + 16.6 +#$ name: init 16.7 + 16.8 +hg init main 16.9 +cd main 16.10 +echo 'This is a boring feature.' > myfile 16.11 +hg commit -A -m 'We have reached an important milestone!' 16.12 + 16.13 +#$ name: tag 16.14 + 16.15 +hg tag v1.0 16.16 +hg tip 16.17 +hg tags 16.18 + 16.19 +#$ name: main 16.20 + 16.21 +cd ../main 16.22 +echo 'This is exciting and new!' >> myfile 16.23 +hg commit -m 'Add a new feature' 16.24 +cat myfile 16.25 + 16.26 +#$ name: update 16.27 + 16.28 +cd .. 16.29 +hg clone -U main main-old 16.30 +cd main-old 16.31 +hg update v1.0 16.32 +cat myfile 16.33 + 16.34 +#$ name: clone 16.35 + 16.36 +cd .. 16.37 +hg clone -rv1.0 main stable 16.38 + 16.39 +#$ name: stable 16.40 + 16.41 +hg clone stable stable-fix 16.42 +cd stable-fix 16.43 +echo 'This is a fix to a boring feature.' > myfile 16.44 +hg commit -m 'Fix a bug' 16.45 +#$ ignore: /tmp/branching.* 16.46 +hg push 16.47 + 16.48 +#$ name: 16.49 + 16.50 +export HGMERGE=$(mktemp) 16.51 +echo '#!/bin/sh' > $HGMERGE 16.52 +echo 'echo "This is a fix to a boring feature." > "$1"' >> $HGMERGE 16.53 +echo 'echo "This is exciting and new!" >> "$1"' >> $HGMERGE 16.54 +chmod 700 $HGMERGE 16.55 + 16.56 +#$ name: merge 16.57 + 16.58 +cd ../main 16.59 +hg pull ../stable 16.60 +hg merge 16.61 +hg commit -m 'Bring in bugfix from stable branch' 16.62 +cat myfile 16.63 + 16.64 +#$ name: 16.65 + 16.66 +rm $HGMERGE
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/fr/examples/cmdref Thu Feb 05 12:37:03 2009 +0100 17.3 @@ -0,0 +1,22 @@ 17.4 +#!/bin/bash 17.5 + 17.6 +hg init diff 17.7 +cd diff 17.8 +cat > myfile.c <<EOF 17.9 +int myfunc() 17.10 +{ 17.11 + return 1; 17.12 +} 17.13 +EOF 17.14 +hg ci -Ama 17.15 + 17.16 +sed -ie 's/return 1/return 10/' myfile.c 17.17 + 17.18 +#$ name: diff-p 17.19 + 17.20 +echo '[diff]' >> $HGRC 17.21 +echo 'showfunc = False' >> $HGRC 17.22 + 17.23 +hg diff 17.24 + 17.25 +hg diff -p
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/fr/examples/daily.copy Thu Feb 05 12:37:03 2009 +0100 18.3 @@ -0,0 +1,82 @@ 18.4 +#!/bin/bash 18.5 + 18.6 +#$ name: init 18.7 + 18.8 +hg init my-copy 18.9 +cd my-copy 18.10 +echo line > file 18.11 +hg add file 18.12 +hg commit -m 'Added a file' 18.13 + 18.14 +#$ name: clone 18.15 + 18.16 +cd .. 18.17 +hg clone my-copy your-copy 18.18 + 18.19 +#$ name: copy 18.20 + 18.21 +cd my-copy 18.22 +hg copy file new-file 18.23 + 18.24 +#$ name: status 18.25 + 18.26 +hg status 18.27 + 18.28 +#$ name: status-copy 18.29 + 18.30 +hg status -C 18.31 +hg commit -m 'Copied file' 18.32 + 18.33 +#$ name: other 18.34 + 18.35 +cd ../your-copy 18.36 +echo 'new contents' >> file 18.37 +hg commit -m 'Changed file' 18.38 + 18.39 +#$ name: cat 18.40 + 18.41 +cat file 18.42 +cat ../my-copy/new-file 18.43 + 18.44 +#$ name: merge 18.45 + 18.46 +hg pull ../my-copy 18.47 +hg merge 18.48 +cat new-file 18.49 + 18.50 +#$ name: 18.51 + 18.52 +cd .. 18.53 +hg init copy-example 18.54 +cd copy-example 18.55 +echo a > a 18.56 +echo b > b 18.57 +mkdir c 18.58 +mkdir c/a 18.59 +echo c > c/a/c 18.60 +hg ci -Ama 18.61 + 18.62 +#$ name: simple 18.63 + 18.64 +mkdir k 18.65 +hg copy a k 18.66 +ls k 18.67 + 18.68 +#$ name: dir-dest 18.69 + 18.70 +mkdir d 18.71 +hg copy a b d 18.72 +ls d 18.73 + 18.74 +#$ name: dir-src 18.75 + 18.76 +hg copy c e 18.77 + 18.78 +#$ name: dir-src-dest 18.79 + 18.80 +hg copy c d 18.81 + 18.82 +#$ name: after 18.83 + 18.84 +cp a z 18.85 +hg copy --after a z
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/fr/examples/daily.files Thu Feb 05 12:37:03 2009 +0100 19.3 @@ -0,0 +1,93 @@ 19.4 +#!/bin/bash 19.5 + 19.6 +#$ name: add 19.7 + 19.8 +hg init add-example 19.9 +cd add-example 19.10 +echo a > a 19.11 +hg status 19.12 +hg add a 19.13 +hg status 19.14 +hg commit -m 'Added one file' 19.15 +hg status 19.16 + 19.17 +#$ name: add-dir 19.18 + 19.19 +mkdir b 19.20 +echo b > b/b 19.21 +echo c > b/c 19.22 +mkdir b/d 19.23 +echo d > b/d/d 19.24 +hg add b 19.25 +hg commit -m 'Added all files in subdirectory' 19.26 + 19.27 +#$ name: 19.28 + 19.29 +cd .. 19.30 + 19.31 +#$ name: hidden 19.32 + 19.33 +hg init hidden-example 19.34 +cd hidden-example 19.35 +mkdir empty 19.36 +touch empty/.hidden 19.37 +hg add empty/.hidden 19.38 +hg commit -m 'Manage an empty-looking directory' 19.39 +ls empty 19.40 +cd .. 19.41 +hg clone hidden-example tmp 19.42 +ls tmp 19.43 +ls tmp/empty 19.44 + 19.45 +#$ name: remove 19.46 + 19.47 +hg init remove-example 19.48 +cd remove-example 19.49 +echo a > a 19.50 +mkdir b 19.51 +echo b > b/b 19.52 +hg add a b 19.53 +hg commit -m 'Small example for file removal' 19.54 +hg remove a 19.55 +hg status 19.56 +hg remove b 19.57 + 19.58 +#$ name: 19.59 + 19.60 +cd .. 19.61 + 19.62 +#$ name: missing 19.63 +hg init missing-example 19.64 +cd missing-example 19.65 +echo a > a 19.66 +hg add a 19.67 +hg commit -m 'File about to be missing' 19.68 +rm a 19.69 +hg status 19.70 + 19.71 +#$ name: remove-after 19.72 + 19.73 +hg remove --after a 19.74 +hg status 19.75 + 19.76 +#$ name: recover-missing 19.77 +hg revert a 19.78 +cat a 19.79 +hg status 19.80 + 19.81 +#$ name: 19.82 + 19.83 +cd .. 19.84 + 19.85 +#$ name: addremove 19.86 + 19.87 +hg init addremove-example 19.88 +cd addremove-example 19.89 +echo a > a 19.90 +echo b > b 19.91 +hg addremove 19.92 + 19.93 +#$ name: commit-addremove 19.94 + 19.95 +echo c > c 19.96 +hg commit -A -m 'Commit with addremove'
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/fr/examples/daily.rename Thu Feb 05 12:37:03 2009 +0100 20.3 @@ -0,0 +1,18 @@ 20.4 +#!/bin/bash 20.5 + 20.6 +hg init a 20.7 +cd a 20.8 +echo a > a 20.9 +hg ci -Ama 20.10 + 20.11 +#$ name: rename 20.12 + 20.13 +hg rename a b 20.14 + 20.15 +#$ name: status 20.16 + 20.17 +hg status 20.18 + 20.19 +#$ name: status-copy 20.20 + 20.21 +hg status -C
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/fr/examples/daily.revert Thu Feb 05 12:37:03 2009 +0100 21.3 @@ -0,0 +1,74 @@ 21.4 +#!/bin/bash 21.5 + 21.6 +hg init a 21.7 +cd a 21.8 +echo 'original content' > file 21.9 +hg ci -Ama 21.10 + 21.11 +#$ name: modify 21.12 + 21.13 +cat file 21.14 +echo unwanted change >> file 21.15 +hg diff file 21.16 + 21.17 +#$ name: unmodify 21.18 + 21.19 +hg status 21.20 +hg revert file 21.21 +cat file 21.22 + 21.23 +#$ name: status 21.24 + 21.25 +hg status 21.26 +cat file.orig 21.27 + 21.28 +#$ name: 21.29 + 21.30 +rm file.orig 21.31 + 21.32 +#$ name: add 21.33 + 21.34 +echo oops > oops 21.35 +hg add oops 21.36 +hg status oops 21.37 +hg revert oops 21.38 +hg status 21.39 + 21.40 +#$ name: 21.41 + 21.42 +rm oops 21.43 + 21.44 +#$ name: remove 21.45 + 21.46 +hg remove file 21.47 +hg status 21.48 +hg revert file 21.49 +hg status 21.50 +ls file 21.51 + 21.52 +#$ name: missing 21.53 + 21.54 +rm file 21.55 +hg status 21.56 +hg revert file 21.57 +ls file 21.58 + 21.59 +#$ name: copy 21.60 + 21.61 +hg copy file new-file 21.62 +hg revert new-file 21.63 +hg status 21.64 + 21.65 +#$ name: 21.66 + 21.67 +rm new-file 21.68 + 21.69 +#$ name: rename 21.70 + 21.71 +hg rename file new-file 21.72 +hg revert new-file 21.73 +hg status 21.74 + 21.75 +#$ name: rename-orig 21.76 +hg revert file 21.77 +hg status
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/fr/examples/data/check_whitespace.py Thu Feb 05 12:37:03 2009 +0100 22.3 @@ -0,0 +1,44 @@ 22.4 +#!/usr/bin/python 22.5 + 22.6 +import re 22.7 + 22.8 +def trailing_whitespace(difflines): 22.9 + added, linenum, header = [], 0, False 22.10 + 22.11 + for line in difflines: 22.12 + if header: 22.13 + # remember the name of the file that this diff affects 22.14 + m = re.match(r'(?:---|\+\+\+) ([^\t]+)', line) 22.15 + if m and m.group(1) != '/dev/null': 22.16 + filename = m.group(1).split('/', 1)[-1] 22.17 + if line.startswith('+++ '): 22.18 + header = False 22.19 + continue 22.20 + if line.startswith('diff '): 22.21 + header = True 22.22 + continue 22.23 + # hunk header - save the line number 22.24 + m = re.match(r'@@ -\d+,\d+ \+(\d+),', line) 22.25 + if m: 22.26 + linenum = int(m.group(1)) 22.27 + continue 22.28 + # hunk body - check for an added line with trailing whitespace 22.29 + m = re.match(r'\+.*\s$', line) 22.30 + if m: 22.31 + added.append((filename, linenum)) 22.32 + if line and line[0] in ' +': 22.33 + linenum += 1 22.34 + return added 22.35 + 22.36 +if __name__ == '__main__': 22.37 + import os, sys 22.38 + 22.39 + added = trailing_whitespace(os.popen('hg export tip')) 22.40 + if added: 22.41 + for filename, linenum in added: 22.42 + print >> sys.stderr, ('%s, line %d: trailing whitespace added' % 22.43 + (filename, linenum)) 22.44 + # save the commit message so we don't need to retype it 22.45 + os.system('hg tip --template "{desc}" > .hg/commit.save') 22.46 + print >> sys.stderr, 'commit message saved to .hg/commit.save' 22.47 + sys.exit(1)
23.1 Binary file fr/examples/data/netplug-1.2.5.tar.bz2 has changed
24.1 Binary file fr/examples/data/netplug-1.2.8.tar.bz2 has changed
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/fr/examples/data/remove-redundant-null-checks.patch Thu Feb 05 12:37:03 2009 +0100 25.3 @@ -0,0 +1,190 @@ 25.4 + 25.5 +From: Jesper Juhl <jesper.juhl@gmail.com> 25.6 + 25.7 +Remove redundant NULL chck before kfree + tiny CodingStyle cleanup for 25.8 +drivers/ 25.9 + 25.10 +Signed-off-by: Jesper Juhl <jesper.juhl@gmail.com> 25.11 +Signed-off-by: Andrew Morton <akpm@osdl.org> 25.12 +--- 25.13 + 25.14 + drivers/char/agp/sgi-agp.c | 5 ++--- 25.15 + drivers/char/hvcs.c | 11 +++++------ 25.16 + drivers/message/fusion/mptfc.c | 6 ++---- 25.17 + drivers/message/fusion/mptsas.c | 3 +-- 25.18 + drivers/net/fs_enet/fs_enet-mii.c | 3 +-- 25.19 + drivers/net/wireless/ipw2200.c | 22 ++++++---------------- 25.20 + drivers/scsi/libata-scsi.c | 4 +--- 25.21 + drivers/video/au1100fb.c | 3 +-- 25.22 + 8 files changed, 19 insertions(+), 38 deletions(-) 25.23 + 25.24 +diff -puN drivers/char/agp/sgi-agp.c~remove-redundant-null-checks-before-free-in-drivers drivers/char/agp/sgi-agp.c 25.25 +--- a/drivers/char/agp/sgi-agp.c~remove-redundant-null-checks-before-free-in-drivers 25.26 ++++ a/drivers/char/agp/sgi-agp.c 25.27 +@@ -329,9 +329,8 @@ static int __devinit agp_sgi_init(void) 25.28 + 25.29 + static void __devexit agp_sgi_cleanup(void) 25.30 + { 25.31 +- if (sgi_tioca_agp_bridges) 25.32 +- kfree(sgi_tioca_agp_bridges); 25.33 +- sgi_tioca_agp_bridges=NULL; 25.34 ++ kfree(sgi_tioca_agp_bridges); 25.35 ++ sgi_tioca_agp_bridges = NULL; 25.36 + } 25.37 + 25.38 + module_init(agp_sgi_init); 25.39 +diff -puN drivers/char/hvcs.c~remove-redundant-null-checks-before-free-in-drivers drivers/char/hvcs.c 25.40 +--- a/drivers/char/hvcs.c~remove-redundant-null-checks-before-free-in-drivers 25.41 ++++ a/drivers/char/hvcs.c 25.42 +@@ -1320,11 +1320,12 @@ static struct tty_operations hvcs_ops = 25.43 + static int hvcs_alloc_index_list(int n) 25.44 + { 25.45 + int i; 25.46 ++ 25.47 + hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); 25.48 + if (!hvcs_index_list) 25.49 + return -ENOMEM; 25.50 + hvcs_index_count = n; 25.51 +- for(i = 0; i < hvcs_index_count; i++) 25.52 ++ for (i = 0; i < hvcs_index_count; i++) 25.53 + hvcs_index_list[i] = -1; 25.54 + return 0; 25.55 + } 25.56 +@@ -1332,11 +1333,9 @@ static int hvcs_alloc_index_list(int n) 25.57 + static void hvcs_free_index_list(void) 25.58 + { 25.59 + /* Paranoia check to be thorough. */ 25.60 +- if (hvcs_index_list) { 25.61 +- kfree(hvcs_index_list); 25.62 +- hvcs_index_list = NULL; 25.63 +- hvcs_index_count = 0; 25.64 +- } 25.65 ++ kfree(hvcs_index_list); 25.66 ++ hvcs_index_list = NULL; 25.67 ++ hvcs_index_count = 0; 25.68 + } 25.69 + 25.70 + static int __init hvcs_module_init(void) 25.71 +diff -puN drivers/message/fusion/mptfc.c~remove-redundant-null-checks-before-free-in-drivers drivers/message/fusion/mptfc.c 25.72 +--- a/drivers/message/fusion/mptfc.c~remove-redundant-null-checks-before-free-in-drivers 25.73 ++++ a/drivers/message/fusion/mptfc.c 25.74 +@@ -305,10 +305,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, in 25.75 + } 25.76 + 25.77 + out: 25.78 +- if (pp0_array) 25.79 +- kfree(pp0_array); 25.80 +- if (p0_array) 25.81 +- kfree(p0_array); 25.82 ++ kfree(pp0_array); 25.83 ++ kfree(p0_array); 25.84 + return rc; 25.85 + } 25.86 + 25.87 +diff -puN drivers/message/fusion/mptsas.c~remove-redundant-null-checks-before-free-in-drivers drivers/message/fusion/mptsas.c 25.88 +--- a/drivers/message/fusion/mptsas.c~remove-redundant-null-checks-before-free-in-drivers 25.89 ++++ a/drivers/message/fusion/mptsas.c 25.90 +@@ -1378,8 +1378,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) 25.91 + return 0; 25.92 + 25.93 + out_free_port_info: 25.94 +- if (hba) 25.95 +- kfree(hba); 25.96 ++ kfree(hba); 25.97 + out: 25.98 + return error; 25.99 + } 25.100 +diff -puN drivers/net/fs_enet/fs_enet-mii.c~remove-redundant-null-checks-before-free-in-drivers drivers/net/fs_enet/fs_enet-mii.c 25.101 +--- a/drivers/net/fs_enet/fs_enet-mii.c~remove-redundant-null-checks-before-free-in-drivers 25.102 ++++ a/drivers/net/fs_enet/fs_enet-mii.c 25.103 +@@ -431,8 +431,7 @@ static struct fs_enet_mii_bus *create_bu 25.104 + return bus; 25.105 + 25.106 + err: 25.107 +- if (bus) 25.108 +- kfree(bus); 25.109 ++ kfree(bus); 25.110 + return ERR_PTR(ret); 25.111 + } 25.112 + 25.113 +diff -puN drivers/net/wireless/ipw2200.c~remove-redundant-null-checks-before-free-in-drivers drivers/net/wireless/ipw2200.c 25.114 +--- a/drivers/net/wireless/ipw2200.c~remove-redundant-null-checks-before-free-in-drivers 25.115 ++++ a/drivers/net/wireless/ipw2200.c 25.116 +@@ -1229,12 +1229,6 @@ static struct ipw_fw_error *ipw_alloc_er 25.117 + return error; 25.118 + } 25.119 + 25.120 +-static void ipw_free_error_log(struct ipw_fw_error *error) 25.121 +-{ 25.122 +- if (error) 25.123 +- kfree(error); 25.124 +-} 25.125 +- 25.126 + static ssize_t show_event_log(struct device *d, 25.127 + struct device_attribute *attr, char *buf) 25.128 + { 25.129 +@@ -1296,10 +1290,9 @@ static ssize_t clear_error(struct device 25.130 + const char *buf, size_t count) 25.131 + { 25.132 + struct ipw_priv *priv = dev_get_drvdata(d); 25.133 +- if (priv->error) { 25.134 +- ipw_free_error_log(priv->error); 25.135 +- priv->error = NULL; 25.136 +- } 25.137 ++ 25.138 ++ kfree(priv->error); 25.139 ++ priv->error = NULL; 25.140 + return count; 25.141 + } 25.142 + 25.143 +@@ -1970,8 +1963,7 @@ static void ipw_irq_tasklet(struct ipw_p 25.144 + struct ipw_fw_error *error = 25.145 + ipw_alloc_error_log(priv); 25.146 + ipw_dump_error_log(priv, error); 25.147 +- if (error) 25.148 +- ipw_free_error_log(error); 25.149 ++ kfree(error); 25.150 + } 25.151 + #endif 25.152 + } else { 25.153 +@@ -11693,10 +11685,8 @@ static void ipw_pci_remove(struct pci_de 25.154 + } 25.155 + } 25.156 + 25.157 +- if (priv->error) { 25.158 +- ipw_free_error_log(priv->error); 25.159 +- priv->error = NULL; 25.160 +- } 25.161 ++ kfree(priv->error); 25.162 ++ priv->error = NULL; 25.163 + 25.164 + #ifdef CONFIG_IPW2200_PROMISCUOUS 25.165 + ipw_prom_free(priv); 25.166 +diff -puN drivers/scsi/libata-scsi.c~remove-redundant-null-checks-before-free-in-drivers drivers/scsi/libata-scsi.c 25.167 +--- a/drivers/scsi/libata-scsi.c~remove-redundant-null-checks-before-free-in-drivers 25.168 ++++ a/drivers/scsi/libata-scsi.c 25.169 +@@ -222,9 +222,7 @@ int ata_cmd_ioctl(struct scsi_device *sc 25.170 + && copy_to_user(arg + sizeof(args), argbuf, argsize)) 25.171 + rc = -EFAULT; 25.172 + error: 25.173 +- if (argbuf) 25.174 +- kfree(argbuf); 25.175 +- 25.176 ++ kfree(argbuf); 25.177 + return rc; 25.178 + } 25.179 + 25.180 +diff -puN drivers/video/au1100fb.c~remove-redundant-null-checks-before-free-in-drivers drivers/video/au1100fb.c 25.181 +--- a/drivers/video/au1100fb.c~remove-redundant-null-checks-before-free-in-drivers 25.182 ++++ a/drivers/video/au1100fb.c 25.183 +@@ -743,8 +743,7 @@ void __exit au1100fb_cleanup(void) 25.184 + { 25.185 + driver_unregister(&au1100fb_driver); 25.186 + 25.187 +- if (drv_info.opt_mode) 25.188 +- kfree(drv_info.opt_mode); 25.189 ++ kfree(drv_info.opt_mode); 25.190 + } 25.191 + 25.192 + module_init(au1100fb_init); 25.193 +_
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 26.2 +++ b/fr/examples/extdiff Thu Feb 05 12:37:03 2009 +0100 26.3 @@ -0,0 +1,28 @@ 26.4 +#!/bin/bash 26.5 + 26.6 +echo '[extensions]' >> $HGRC 26.7 +echo 'extdiff =' >> $HGRC 26.8 + 26.9 +hg init a 26.10 +cd a 26.11 +echo 'The first line.' > myfile 26.12 +hg ci -Ama 26.13 +echo 'The second line.' >> myfile 26.14 + 26.15 +#$ name: diff 26.16 + 26.17 +hg diff 26.18 + 26.19 +#$ name: extdiff 26.20 + 26.21 +hg extdiff 26.22 + 26.23 +#$ name: extdiff-ctx 26.24 + 26.25 +#$ ignore: ^\*\*\* a.* 26.26 + 26.27 +hg extdiff -o -NprcC5 26.28 + 26.29 +#$ name: 26.30 + 26.31 +exit 0
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/fr/examples/filenames Thu Feb 05 12:37:03 2009 +0100 27.3 @@ -0,0 +1,61 @@ 27.4 +#!/bin/bash 27.5 + 27.6 +hg init a 27.7 +cd a 27.8 +mkdir -p examples src/watcher 27.9 +touch COPYING MANIFEST.in README setup.py 27.10 +touch examples/performant.py examples/simple.py 27.11 +touch src/main.py src/watcher/_watcher.c src/watcher/watcher.py src/xyzzy.txt 27.12 + 27.13 +#$ name: files 27.14 + 27.15 +hg add COPYING README examples/simple.py 27.16 + 27.17 +#$ name: dirs 27.18 + 27.19 +hg status src 27.20 + 27.21 +#$ name: wdir-subdir 27.22 + 27.23 +cd src 27.24 +hg add -n 27.25 +hg add -n . 27.26 + 27.27 +#$ name: wdir-relname 27.28 + 27.29 +hg status 27.30 +hg status `hg root` 27.31 + 27.32 +#$ name: glob.star 27.33 + 27.34 +hg add 'glob:*.py' 27.35 + 27.36 +#$ name: glob.starstar 27.37 + 27.38 +cd .. 27.39 +hg status 'glob:**.py' 27.40 + 27.41 +#$ name: glob.star-starstar 27.42 + 27.43 +hg status 'glob:*.py' 27.44 +hg status 'glob:**.py' 27.45 + 27.46 +#$ name: glob.question 27.47 + 27.48 +hg status 'glob:**.?' 27.49 + 27.50 +#$ name: glob.range 27.51 + 27.52 +hg status 'glob:**[nr-t]' 27.53 + 27.54 +#$ name: glob.group 27.55 + 27.56 +hg status 'glob:*.{in,py}' 27.57 + 27.58 +#$ name: filter.include 27.59 + 27.60 +hg status -I '*.in' 27.61 + 27.62 +#$ name: filter.exclude 27.63 + 27.64 +hg status -X '**.py' src
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/fr/examples/hook.msglen Thu Feb 05 12:37:03 2009 +0100 28.3 @@ -0,0 +1,14 @@ 28.4 +#!/bin/sh 28.5 + 28.6 +hg init a 28.7 +cd a 28.8 +echo '[hooks]' > .hg/hgrc 28.9 +echo 'pretxncommit.msglen = test `hg tip --template {desc} | wc -c` -ge 10' >> .hg/hgrc 28.10 + 28.11 +#$ name: go 28.12 + 28.13 +cat .hg/hgrc 28.14 +echo a > a 28.15 +hg add a 28.16 +hg commit -A -m 'too short' 28.17 +hg commit -A -m 'long enough'
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/fr/examples/hook.simple Thu Feb 05 12:37:03 2009 +0100 29.3 @@ -0,0 +1,37 @@ 29.4 +#!/bin/bash 29.5 + 29.6 +#$ name: init 29.7 + 29.8 +hg init hook-test 29.9 +cd hook-test 29.10 +echo '[hooks]' >> .hg/hgrc 29.11 +echo 'commit = echo committed $HG_NODE' >> .hg/hgrc 29.12 +cat .hg/hgrc 29.13 +echo a > a 29.14 +hg add a 29.15 +hg commit -m 'testing commit hook' 29.16 + 29.17 +#$ name: ext 29.18 +#$ ignore: ^date of commit.* 29.19 + 29.20 +echo 'commit.when = echo -n "date of commit: "; date' >> .hg/hgrc 29.21 +echo a >> a 29.22 +hg commit -m 'i have two hooks' 29.23 + 29.24 +#$ name: 29.25 + 29.26 +echo '#!/bin/sh' >> check_bug_id 29.27 +echo '# check that a commit comment mentions a numeric bug id' >> check_bug_id 29.28 +echo 'hg log -r $1 --template {desc} | grep -q "\<bug *[0-9]"' >> check_bug_id 29.29 +chmod +x check_bug_id 29.30 + 29.31 +#$ name: pretxncommit 29.32 + 29.33 +cat check_bug_id 29.34 + 29.35 +echo 'pretxncommit.bug_id_required = ./check_bug_id $HG_NODE' >> .hg/hgrc 29.36 + 29.37 +echo a >> a 29.38 +hg commit -m 'i am not mentioning a bug id' 29.39 + 29.40 +hg commit -m 'i refer you to bug 666'
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/fr/examples/hook.ws Thu Feb 05 12:37:03 2009 +0100 30.3 @@ -0,0 +1,31 @@ 30.4 +#!/bin/bash 30.5 + 30.6 +hg init a 30.7 +cd a 30.8 +echo '[hooks]' > .hg/hgrc 30.9 +echo "pretxncommit.whitespace = hg export tip | (! egrep -q '^\\+.*[ \\t]$')" >> .hg/hgrc 30.10 + 30.11 +#$ name: simple 30.12 + 30.13 +cat .hg/hgrc 30.14 +echo 'a ' > a 30.15 +hg commit -A -m 'test with trailing whitespace' 30.16 +echo 'a' > a 30.17 +hg commit -A -m 'drop trailing whitespace and try again' 30.18 + 30.19 +#$ name: 30.20 + 30.21 +echo '[hooks]' > .hg/hgrc 30.22 +echo "pretxncommit.whitespace = .hg/check_whitespace.py" >> .hg/hgrc 30.23 +cp $EXAMPLE_DIR/data/check_whitespace.py .hg 30.24 + 30.25 +#$ name: better 30.26 + 30.27 +cat .hg/hgrc 30.28 +echo 'a ' >> a 30.29 +hg commit -A -m 'add new line with trailing whitespace' 30.30 +sed -i 's, *$,,' a 30.31 +hg commit -A -m 'trimmed trailing whitespace' 30.32 + 30.33 +#$ name: 30.34 +exit 0
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/fr/examples/issue29 Thu Feb 05 12:37:03 2009 +0100 31.3 @@ -0,0 +1,22 @@ 31.4 +#!/bin/bash 31.5 + 31.6 +#$ name: go 31.7 + 31.8 +hg init issue29 31.9 +cd issue29 31.10 +echo a > a 31.11 +hg ci -Ama 31.12 +echo b > b 31.13 +hg ci -Amb 31.14 +hg up 0 31.15 +mkdir b 31.16 +echo b > b/b 31.17 +hg ci -Amc 31.18 + 31.19 +#$ ignore: abort: Is a directory: .* 31.20 +hg merge 31.21 + 31.22 +#$ name: 31.23 +# This error is expected from the failed merge. 31.24 + 31.25 +exit 0
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 32.2 +++ b/fr/examples/mq.dodiff Thu Feb 05 12:37:03 2009 +0100 32.3 @@ -0,0 +1,14 @@ 32.4 +#!/bin/bash 32.5 + 32.6 +#$ name: diff 32.7 + 32.8 +echo 'this is my original thought' > oldfile 32.9 +echo 'i have changed my mind' > newfile 32.10 + 32.11 +diff -u oldfile newfile > tiny.patch 32.12 + 32.13 +cat tiny.patch 32.14 + 32.15 +patch < tiny.patch 32.16 + 32.17 +cat oldfile
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/fr/examples/mq.guards Thu Feb 05 12:37:03 2009 +0100 33.3 @@ -0,0 +1,67 @@ 33.4 +#!/bin/bash 33.5 + 33.6 +echo '[extensions]' >> $HGRC 33.7 +echo 'hgext.mq =' >> $HGRC 33.8 + 33.9 +hg init a 33.10 +cd a 33.11 + 33.12 +#$ name: init 33.13 + 33.14 +hg qinit 33.15 +hg qnew hello.patch 33.16 +echo hello > hello 33.17 +hg add hello 33.18 +hg qrefresh 33.19 +hg qnew goodbye.patch 33.20 +echo goodbye > goodbye 33.21 +hg add goodbye 33.22 +hg qrefresh 33.23 + 33.24 +#$ name: qguard 33.25 + 33.26 +hg qguard 33.27 + 33.28 +#$ name: qguard.pos 33.29 + 33.30 +hg qguard +foo 33.31 +hg qguard 33.32 + 33.33 +#$ name: qguard.neg 33.34 + 33.35 +hg qguard hello.patch -quux 33.36 +hg qguard hello.patch 33.37 + 33.38 +#$ name: series 33.39 + 33.40 +cat .hg/patches/series 33.41 + 33.42 +#$ name: qselect.foo 33.43 + 33.44 +hg qpop -a 33.45 +hg qselect 33.46 +hg qselect foo 33.47 +hg qselect 33.48 + 33.49 +#$ name: qselect.cat 33.50 + 33.51 +cat .hg/patches/guards 33.52 + 33.53 +#$ name: qselect.qpush 33.54 +hg qpush -a 33.55 + 33.56 +#$ name: qselect.error 33.57 + 33.58 +hg qselect +foo 33.59 + 33.60 +#$ name: qselect.quux 33.61 + 33.62 +hg qselect quux 33.63 +hg qpop -a 33.64 +hg qpush -a 33.65 + 33.66 +#$ name: qselect.foobar 33.67 + 33.68 +hg qselect foo bar 33.69 +hg qpop -a 33.70 +hg qpush -a
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/fr/examples/mq.id Thu Feb 05 12:37:03 2009 +0100 34.3 @@ -0,0 +1,28 @@ 34.4 +#!/bin/sh 34.5 + 34.6 +echo '[extensions]' >> $HGRC 34.7 +echo 'hgext.mq =' >> $HGRC 34.8 + 34.9 +hg init a 34.10 +cd a 34.11 +hg qinit 34.12 +echo 'int x;' > test.c 34.13 +hg ci -Ama 34.14 + 34.15 +hg qnew first.patch 34.16 +echo 'float c;' >> test.c 34.17 +hg qrefresh 34.18 + 34.19 +hg qnew second.patch 34.20 +echo 'double u;' > other.c 34.21 +hg add other.c 34.22 +hg qrefresh 34.23 + 34.24 +#$ name: output 34.25 + 34.26 +hg qapplied 34.27 +hg log -r qbase:qtip 34.28 +hg export second.patch 34.29 + 34.30 +#$ name: 34.31 +exit 0
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 35.2 +++ b/fr/examples/mq.qinit-help Thu Feb 05 12:37:03 2009 +0100 35.3 @@ -0,0 +1,7 @@ 35.4 +#!/bin/bash 35.5 + 35.6 +echo '[extensions]' >> $HGRC 35.7 +echo 'hgext.mq =' >> $HGRC 35.8 + 35.9 +#$ name: help 35.10 +hg help qinit
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 36.2 +++ b/fr/examples/mq.tarball Thu Feb 05 12:37:03 2009 +0100 36.3 @@ -0,0 +1,51 @@ 36.4 +#!/bin/bash 36.5 + 36.6 +cp $EXAMPLE_DIR/data/netplug-*.tar.bz2 . 36.7 +ln -s /bin/true download 36.8 +export PATH=`pwd`:$PATH 36.9 + 36.10 +#$ name: download 36.11 + 36.12 +download netplug-1.2.5.tar.bz2 36.13 +tar jxf netplug-1.2.5.tar.bz2 36.14 +cd netplug-1.2.5 36.15 +hg init 36.16 +hg commit -q --addremove --message netplug-1.2.5 36.17 +cd .. 36.18 +hg clone netplug-1.2.5 netplug 36.19 + 36.20 +#$ name: 36.21 + 36.22 +cd netplug 36.23 +echo '[extensions]' >> $HGRC 36.24 +echo 'hgext.mq =' >> $HGRC 36.25 +cd .. 36.26 + 36.27 +#$ name: qinit 36.28 + 36.29 +cd netplug 36.30 +hg qinit 36.31 +hg qnew -m 'fix build problem with gcc 4' build-fix.patch 36.32 +perl -pi -e 's/int addr_len/socklen_t addr_len/' netlink.c 36.33 +hg qrefresh 36.34 +hg tip -p 36.35 + 36.36 +#$ name: newsource 36.37 + 36.38 +hg qpop -a 36.39 +cd .. 36.40 +download netplug-1.2.8.tar.bz2 36.41 +hg clone netplug-1.2.5 netplug-1.2.8 36.42 +cd netplug-1.2.8 36.43 +hg locate -0 | xargs -0 rm 36.44 +cd .. 36.45 +tar jxf netplug-1.2.8.tar.bz2 36.46 +cd netplug-1.2.8 36.47 +hg commit --addremove --message netplug-1.2.8 36.48 + 36.49 +#$ name: repush 36.50 + 36.51 +cd ../netplug 36.52 +hg pull ../netplug-1.2.8 36.53 +hg qpush -a 36.54 +
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 37.2 +++ b/fr/examples/mq.tools Thu Feb 05 12:37:03 2009 +0100 37.3 @@ -0,0 +1,11 @@ 37.4 +#!/bin/bash 37.5 + 37.6 +cp $EXAMPLE_DIR/data/remove-redundant-null-checks.patch . 37.7 + 37.8 +#$ name: tools 37.9 +diffstat -p1 remove-redundant-null-checks.patch 37.10 + 37.11 +filterdiff -i '*/video/*' remove-redundant-null-checks.patch 37.12 + 37.13 +#$ name: lsdiff 37.14 +lsdiff -nvv remove-redundant-null-checks.patch
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 38.2 +++ b/fr/examples/mq.tutorial Thu Feb 05 12:37:03 2009 +0100 38.3 @@ -0,0 +1,74 @@ 38.4 +#!/bin/bash 38.5 + 38.6 +echo '[extensions]' >> $HGRC 38.7 +echo 'hgext.mq =' >> $HGRC 38.8 + 38.9 +#$ name: qinit 38.10 + 38.11 +hg init mq-sandbox 38.12 +cd mq-sandbox 38.13 +echo 'line 1' > file1 38.14 +echo 'another line 1' > file2 38.15 +hg add file1 file2 38.16 +hg commit -m'first change' 38.17 + 38.18 +hg qinit 38.19 + 38.20 +#$ name: qnew 38.21 + 38.22 +hg tip 38.23 +hg qnew first.patch 38.24 +hg tip 38.25 +ls .hg/patches 38.26 + 38.27 +#$ name: qrefresh 38.28 +#$ ignore: \s+200[78]-.* 38.29 + 38.30 +echo 'line 2' >> file1 38.31 +hg diff 38.32 +hg qrefresh 38.33 +hg diff 38.34 +hg tip --style=compact --patch 38.35 + 38.36 +#$ name: qrefresh2 38.37 + 38.38 +echo 'line 3' >> file1 38.39 +hg status 38.40 +hg qrefresh 38.41 +hg tip --style=compact --patch 38.42 + 38.43 +#$ name: qnew2 38.44 + 38.45 +hg qnew second.patch 38.46 +hg log --style=compact --limit=2 38.47 +echo 'line 4' >> file1 38.48 +hg qrefresh 38.49 +hg tip --style=compact --patch 38.50 +hg annotate file1 38.51 + 38.52 +#$ name: qseries 38.53 + 38.54 +hg qseries 38.55 +hg qapplied 38.56 + 38.57 +#$ name: qpop 38.58 + 38.59 +hg qapplied 38.60 +hg qpop 38.61 +hg qseries 38.62 +hg qapplied 38.63 +cat file1 38.64 + 38.65 +#$ name: qpush-a 38.66 + 38.67 +hg qpush -a 38.68 +cat file1 38.69 + 38.70 +#$ name: add 38.71 + 38.72 +echo 'file 3, line 1' >> file3 38.73 +hg qnew add-file3.patch 38.74 +hg qnew -f add-file3.patch 38.75 + 38.76 +#$ name: 38.77 +exit 0
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 39.2 +++ b/fr/examples/rename.divergent Thu Feb 05 12:37:03 2009 +0100 39.3 @@ -0,0 +1,33 @@ 39.4 +#!/bin/bash 39.5 + 39.6 +hg init orig 39.7 +cd orig 39.8 +echo foo > foo 39.9 +hg ci -A -m 'First commit' 39.10 +cd .. 39.11 + 39.12 +#$ name: clone 39.13 + 39.14 +hg clone orig anne 39.15 +hg clone orig bob 39.16 + 39.17 +#$ name: rename.anne 39.18 + 39.19 +cd anne 39.20 +hg mv foo bar 39.21 +hg ci -m 'Rename foo to bar' 39.22 + 39.23 +#$ name: rename.bob 39.24 + 39.25 +cd ../bob 39.26 +hg mv foo quux 39.27 +hg ci -m 'Rename foo to quux' 39.28 + 39.29 +#$ name: merge 39.30 +# See http://www.selenic.com/mercurial/bts/issue455 39.31 + 39.32 +cd ../orig 39.33 +hg pull -u ../anne 39.34 +hg pull ../bob 39.35 +hg merge 39.36 +ls
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 40.2 +++ b/fr/examples/rollback Thu Feb 05 12:37:03 2009 +0100 40.3 @@ -0,0 +1,37 @@ 40.4 +#!/bin/bash 40.5 + 40.6 +hg init a 40.7 +cd a 40.8 +echo a > a 40.9 +hg ci -A -m 'First commit' 40.10 + 40.11 +echo a >> a 40.12 + 40.13 +#$ name: tip 40.14 + 40.15 +#$ name: commit 40.16 + 40.17 +hg status 40.18 +echo b > b 40.19 +hg commit -m 'Add file b' 40.20 + 40.21 +#$ name: status 40.22 + 40.23 +hg status 40.24 +hg tip 40.25 + 40.26 +#$ name: rollback 40.27 + 40.28 +hg rollback 40.29 +hg tip 40.30 +hg status 40.31 + 40.32 +#$ name: add 40.33 + 40.34 +hg add b 40.35 +hg commit -m 'Add file b, this time for real' 40.36 + 40.37 +#$ name: twice 40.38 + 40.39 +hg rollback 40.40 +hg rollback
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 41.2 +++ b/fr/examples/run-example Thu Feb 05 12:37:03 2009 +0100 41.3 @@ -0,0 +1,391 @@ 41.4 +#!/usr/bin/env python 41.5 +# 41.6 +# This program takes something that resembles a shell script and runs 41.7 +# it, spitting input (commands from the script) and output into text 41.8 +# files, for use in examples. 41.9 + 41.10 +import cStringIO 41.11 +import errno 41.12 +import getopt 41.13 +import os 41.14 +import pty 41.15 +import re 41.16 +import select 41.17 +import shutil 41.18 +import signal 41.19 +import stat 41.20 +import sys 41.21 +import tempfile 41.22 +import time 41.23 + 41.24 +tex_subs = { 41.25 + '\\': '\\textbackslash{}', 41.26 + '{': '\\{', 41.27 + '}': '\\}', 41.28 + } 41.29 + 41.30 +def gensubs(s): 41.31 + start = 0 41.32 + for i, c in enumerate(s): 41.33 + sub = tex_subs.get(c) 41.34 + if sub: 41.35 + yield s[start:i] 41.36 + start = i + 1 41.37 + yield sub 41.38 + yield s[start:] 41.39 + 41.40 +def tex_escape(s): 41.41 + return ''.join(gensubs(s)) 41.42 + 41.43 +def maybe_unlink(name): 41.44 + try: 41.45 + os.unlink(name) 41.46 + return True 41.47 + except OSError, err: 41.48 + if err.errno != errno.ENOENT: 41.49 + raise 41.50 + return False 41.51 + 41.52 +def find_path_to(program): 41.53 + for p in os.environ.get('PATH', os.defpath).split(os.pathsep): 41.54 + name = os.path.join(p, program) 41.55 + if os.access(name, os.X_OK): 41.56 + return p 41.57 + return None 41.58 + 41.59 +class example: 41.60 + shell = '/usr/bin/env bash' 41.61 + ps1 = '__run_example_ps1__ ' 41.62 + ps2 = '__run_example_ps2__ ' 41.63 + pi_re = re.compile(r'#\$\s*(name|ignore):\s*(.*)$') 41.64 + 41.65 + timeout = 10 41.66 + 41.67 + def __init__(self, name, verbose): 41.68 + self.name = name 41.69 + self.verbose = verbose 41.70 + self.poll = select.poll() 41.71 + 41.72 + def parse(self): 41.73 + '''yield each hunk of input from the file.''' 41.74 + fp = open(self.name) 41.75 + cfp = cStringIO.StringIO() 41.76 + for line in fp: 41.77 + cfp.write(line) 41.78 + if not line.rstrip().endswith('\\'): 41.79 + yield cfp.getvalue() 41.80 + cfp.seek(0) 41.81 + cfp.truncate() 41.82 + 41.83 + def status(self, s): 41.84 + sys.stdout.write(s) 41.85 + if not s.endswith('\n'): 41.86 + sys.stdout.flush() 41.87 + 41.88 + def send(self, s): 41.89 + if self.verbose: 41.90 + print >> sys.stderr, '>', self.debugrepr(s) 41.91 + while s: 41.92 + count = os.write(self.cfd, s) 41.93 + s = s[count:] 41.94 + 41.95 + def debugrepr(self, s): 41.96 + rs = repr(s) 41.97 + limit = 60 41.98 + if len(rs) > limit: 41.99 + return ('%s%s ... [%d bytes]' % (rs[:limit], rs[0], len(s))) 41.100 + else: 41.101 + return rs 41.102 + 41.103 + timeout = 5 41.104 + 41.105 + def read(self, hint): 41.106 + events = self.poll.poll(self.timeout * 1000) 41.107 + if not events: 41.108 + print >> sys.stderr, ('[%stimed out after %d seconds]' % 41.109 + (hint, self.timeout)) 41.110 + os.kill(self.pid, signal.SIGHUP) 41.111 + return '' 41.112 + return os.read(self.cfd, 1024) 41.113 + 41.114 + def receive(self, hint): 41.115 + out = cStringIO.StringIO() 41.116 + while True: 41.117 + try: 41.118 + if self.verbose: 41.119 + sys.stderr.write('< ') 41.120 + s = self.read(hint) 41.121 + except OSError, err: 41.122 + if err.errno == errno.EIO: 41.123 + return '', '' 41.124 + raise 41.125 + if self.verbose: 41.126 + print >> sys.stderr, self.debugrepr(s) 41.127 + out.write(s) 41.128 + s = out.getvalue() 41.129 + if s.endswith(self.ps1): 41.130 + return self.ps1, s.replace('\r\n', '\n')[:-len(self.ps1)] 41.131 + if s.endswith(self.ps2): 41.132 + return self.ps2, s.replace('\r\n', '\n')[:-len(self.ps2)] 41.133 + 41.134 + def sendreceive(self, s, hint): 41.135 + self.send(s) 41.136 + ps, r = self.receive(hint) 41.137 + if r.startswith(s): 41.138 + r = r[len(s):] 41.139 + return ps, r 41.140 + 41.141 + def run(self): 41.142 + ofp = None 41.143 + basename = os.path.basename(self.name) 41.144 + self.status('running %s ' % basename) 41.145 + tmpdir = tempfile.mkdtemp(prefix=basename) 41.146 + 41.147 + # remove the marker file that we tell make to use to see if 41.148 + # this run succeeded 41.149 + maybe_unlink(self.name + '.run') 41.150 + 41.151 + rcfile = os.path.join(tmpdir, '.hgrc') 41.152 + rcfp = open(rcfile, 'w') 41.153 + print >> rcfp, '[ui]' 41.154 + print >> rcfp, "username = Bryan O'Sullivan <bos@serpentine.com>" 41.155 + 41.156 + rcfile = os.path.join(tmpdir, '.bashrc') 41.157 + rcfp = open(rcfile, 'w') 41.158 + print >> rcfp, 'PS1="%s"' % self.ps1 41.159 + print >> rcfp, 'PS2="%s"' % self.ps2 41.160 + print >> rcfp, 'unset HISTFILE' 41.161 + path = ['/usr/bin', '/bin'] 41.162 + hg = find_path_to('hg') 41.163 + if hg and hg not in path: 41.164 + path.append(hg) 41.165 + def re_export(envar): 41.166 + v = os.getenv(envar) 41.167 + if v is not None: 41.168 + print >> rcfp, 'export ' + envar + '=' + v 41.169 + print >> rcfp, 'export PATH=' + ':'.join(path) 41.170 + re_export('PYTHONPATH') 41.171 + print >> rcfp, 'export EXAMPLE_DIR="%s"' % os.getcwd() 41.172 + print >> rcfp, 'export HGMERGE=merge' 41.173 + print >> rcfp, 'export LANG=C' 41.174 + print >> rcfp, 'export LC_ALL=C' 41.175 + print >> rcfp, 'export TZ=GMT' 41.176 + print >> rcfp, 'export HGRC="%s/.hgrc"' % tmpdir 41.177 + print >> rcfp, 'export HGRCPATH=$HGRC' 41.178 + print >> rcfp, 'cd %s' % tmpdir 41.179 + rcfp.close() 41.180 + sys.stdout.flush() 41.181 + sys.stderr.flush() 41.182 + self.pid, self.cfd = pty.fork() 41.183 + if self.pid == 0: 41.184 + cmdline = ['/usr/bin/env', '-i', 'bash', '--noediting', 41.185 + '--noprofile', '--norc'] 41.186 + try: 41.187 + os.execv(cmdline[0], cmdline) 41.188 + except OSError, err: 41.189 + print >> sys.stderr, '%s: %s' % (cmdline[0], err.strerror) 41.190 + sys.stderr.flush() 41.191 + os._exit(0) 41.192 + self.poll.register(self.cfd, select.POLLIN | select.POLLERR | 41.193 + select.POLLHUP) 41.194 + 41.195 + prompts = { 41.196 + '': '', 41.197 + self.ps1: '$', 41.198 + self.ps2: '>', 41.199 + } 41.200 + 41.201 + ignore = [ 41.202 + r'\d+:[0-9a-f]{12}', # changeset number:hash 41.203 + r'[0-9a-f]{40}', # long changeset hash 41.204 + r'[0-9a-f]{12}', # short changeset hash 41.205 + r'^(?:---|\+\+\+) .*', # diff header with dates 41.206 + r'^date:.*', # date 41.207 + #r'^diff -r.*', # "diff -r" is followed by hash 41.208 + r'^# Date \d+ \d+', # hg patch header 41.209 + ] 41.210 + 41.211 + err = False 41.212 + read_hint = '' 41.213 + 41.214 + try: 41.215 + try: 41.216 + # eat first prompt string from shell 41.217 + self.read(read_hint) 41.218 + # setup env and prompt 41.219 + ps, output = self.sendreceive('source %s\n' % rcfile, 41.220 + read_hint) 41.221 + for hunk in self.parse(): 41.222 + # is this line a processing instruction? 41.223 + m = self.pi_re.match(hunk) 41.224 + if m: 41.225 + pi, rest = m.groups() 41.226 + if pi == 'name': 41.227 + self.status('.') 41.228 + out = rest 41.229 + if out in ('err', 'lxo', 'out', 'run', 'tmp'): 41.230 + print >> sys.stderr, ('%s: illegal section ' 41.231 + 'name %r' % 41.232 + (self.name, out)) 41.233 + return 1 41.234 + assert os.sep not in out 41.235 + if ofp is not None: 41.236 + ofp.close() 41.237 + err |= self.rename_output(ofp_basename, ignore) 41.238 + if out: 41.239 + ofp_basename = '%s.%s' % (self.name, out) 41.240 + read_hint = ofp_basename + ' ' 41.241 + ofp = open(ofp_basename + '.tmp', 'w') 41.242 + else: 41.243 + ofp = None 41.244 + elif pi == 'ignore': 41.245 + ignore.append(rest) 41.246 + elif hunk.strip(): 41.247 + # it's something we should execute 41.248 + newps, output = self.sendreceive(hunk, read_hint) 41.249 + if not ofp: 41.250 + continue 41.251 + # first, print the command we ran 41.252 + if not hunk.startswith('#'): 41.253 + nl = hunk.endswith('\n') 41.254 + hunk = ('%s \\textbf{%s}' % 41.255 + (prompts[ps], 41.256 + tex_escape(hunk.rstrip('\n')))) 41.257 + if nl: hunk += '\n' 41.258 + ofp.write(hunk) 41.259 + # then its output 41.260 + ofp.write(tex_escape(output)) 41.261 + ps = newps 41.262 + self.status('\n') 41.263 + except: 41.264 + print >> sys.stderr, '(killed)' 41.265 + os.kill(self.pid, signal.SIGKILL) 41.266 + pid, rc = os.wait() 41.267 + raise 41.268 + else: 41.269 + try: 41.270 + ps, output = self.sendreceive('exit\n', read_hint) 41.271 + if ofp is not None: 41.272 + ofp.write(output) 41.273 + ofp.close() 41.274 + err |= self.rename_output(ofp_basename, ignore) 41.275 + os.close(self.cfd) 41.276 + except IOError: 41.277 + pass 41.278 + os.kill(self.pid, signal.SIGTERM) 41.279 + pid, rc = os.wait() 41.280 + err = err or rc 41.281 + if err: 41.282 + if os.WIFEXITED(rc): 41.283 + print >> sys.stderr, '(exit %s)' % os.WEXITSTATUS(rc) 41.284 + elif os.WIFSIGNALED(rc): 41.285 + print >> sys.stderr, '(signal %s)' % os.WTERMSIG(rc) 41.286 + else: 41.287 + open(self.name + '.run', 'w') 41.288 + return err 41.289 + finally: 41.290 + shutil.rmtree(tmpdir) 41.291 + 41.292 + def rename_output(self, base, ignore): 41.293 + mangle_re = re.compile('(?:' + '|'.join(ignore) + ')') 41.294 + def mangle(s): 41.295 + return mangle_re.sub('', s) 41.296 + def matchfp(fp1, fp2): 41.297 + while True: 41.298 + s1 = mangle(fp1.readline()) 41.299 + s2 = mangle(fp2.readline()) 41.300 + if cmp(s1, s2): 41.301 + break 41.302 + if not s1: 41.303 + return True 41.304 + return False 41.305 + 41.306 + oldname = base + '.out' 41.307 + tmpname = base + '.tmp' 41.308 + errname = base + '.err' 41.309 + errfp = open(errname, 'w+') 41.310 + for line in open(tmpname): 41.311 + errfp.write(mangle_re.sub('', line)) 41.312 + os.rename(tmpname, base + '.lxo') 41.313 + errfp.seek(0) 41.314 + try: 41.315 + oldfp = open(oldname) 41.316 + except IOError, err: 41.317 + if err.errno != errno.ENOENT: 41.318 + raise 41.319 + os.rename(errname, oldname) 41.320 + return False 41.321 + if matchfp(oldfp, errfp): 41.322 + os.unlink(errname) 41.323 + return False 41.324 + else: 41.325 + print >> sys.stderr, '\nOutput of %s has changed!' % base 41.326 + os.system('diff -u %s %s 1>&2' % (oldname, errname)) 41.327 + return True 41.328 + 41.329 +def print_help(exit, msg=None): 41.330 + if msg: 41.331 + print >> sys.stderr, 'Error:', msg 41.332 + print >> sys.stderr, 'Usage: run-example [options] [test...]' 41.333 + print >> sys.stderr, 'Options:' 41.334 + print >> sys.stderr, ' -a --all run all tests in this directory' 41.335 + print >> sys.stderr, ' -h --help print this help message' 41.336 + print >> sys.stderr, ' -v --verbose display extra debug output' 41.337 + sys.exit(exit) 41.338 + 41.339 +def main(path='.'): 41.340 + opts, args = getopt.getopt(sys.argv[1:], '?ahv', 41.341 + ['all', 'help', 'verbose']) 41.342 + verbose = False 41.343 + run_all = False 41.344 + for o, a in opts: 41.345 + if o in ('-h', '-?', '--help'): 41.346 + print_help(0) 41.347 + if o in ('-a', '--all'): 41.348 + run_all = True 41.349 + if o in ('-v', '--verbose'): 41.350 + verbose = True 41.351 + errs = 0 41.352 + if args: 41.353 + for a in args: 41.354 + try: 41.355 + st = os.lstat(a) 41.356 + except OSError, err: 41.357 + print >> sys.stderr, '%s: %s' % (a, err.strerror) 41.358 + errs += 1 41.359 + continue 41.360 + if stat.S_ISREG(st.st_mode) and st.st_mode & 0111: 41.361 + if example(a, verbose).run(): 41.362 + errs += 1 41.363 + else: 41.364 + print >> sys.stderr, '%s: not a file, or not executable' % a 41.365 + errs += 1 41.366 + elif run_all: 41.367 + names = os.listdir(path) 41.368 + names.sort() 41.369 + for name in names: 41.370 + if name == 'run-example' or name.startswith('.'): continue 41.371 + if name.endswith('.out') or name.endswith('~'): continue 41.372 + if name.endswith('.run'): continue 41.373 + pathname = os.path.join(path, name) 41.374 + try: 41.375 + st = os.lstat(pathname) 41.376 + except OSError, err: 41.377 + # could be an output file that was removed while we ran 41.378 + if err.errno != errno.ENOENT: 41.379 + raise 41.380 + continue 41.381 + if stat.S_ISREG(st.st_mode) and st.st_mode & 0111: 41.382 + if example(pathname, verbose).run(): 41.383 + errs += 1 41.384 + print >> open(os.path.join(path, '.run'), 'w'), time.asctime() 41.385 + else: 41.386 + print_help(1, msg='no test names given, and --all not provided') 41.387 + return errs 41.388 + 41.389 +if __name__ == '__main__': 41.390 + try: 41.391 + sys.exit(main()) 41.392 + except KeyboardInterrupt: 41.393 + print >> sys.stderr, 'interrupted!' 41.394 + sys.exit(1)
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 42.2 +++ b/fr/examples/svn-long.txt Thu Feb 05 12:37:03 2009 +0100 42.3 @@ -0,0 +1,11 @@ 42.4 +------------------------------------------------------------------------ 42.5 +r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines 42.6 +Changed paths: 42.7 + M /gen2/trunk/src/linux-kernel/infiniband/core/cma.c 42.8 + 42.9 +On reporting a route error, also include the status for the error, 42.10 +rather than indicating a status of 0 when an error has occurred. 42.11 + 42.12 +Signed-off-by: Sean Hefty <sean.hefty@intel.com> 42.13 + 42.14 +------------------------------------------------------------------------
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 43.2 +++ b/fr/examples/svn-short.txt Thu Feb 05 12:37:03 2009 +0100 43.3 @@ -0,0 +1,9 @@ 43.4 +------------------------------------------------------------------------ 43.5 +r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines 43.6 + 43.7 +On reporting a route error, also include the status for the error, 43.8 +rather than indicating a status of 0 when an error has occurred. 43.9 + 43.10 +Signed-off-by: Sean Hefty <sean.hefty@intel.com> 43.11 + 43.12 +------------------------------------------------------------------------
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 44.2 +++ b/fr/examples/svn.style Thu Feb 05 12:37:03 2009 +0100 44.3 @@ -0,0 +1,2 @@ 44.4 +header = '------------------------------------------------------------------------\n\n' 44.5 +changeset = svn.template
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 45.2 +++ b/fr/examples/svn.template Thu Feb 05 12:37:03 2009 +0100 45.3 @@ -0,0 +1,5 @@ 45.4 +r{rev} | {author|user} | {date|isodate} ({date|rfc822date}) 45.5 + 45.6 +{desc|strip|fill76} 45.7 + 45.8 +------------------------------------------------------------------------
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 46.2 +++ b/fr/examples/tag Thu Feb 05 12:37:03 2009 +0100 46.3 @@ -0,0 +1,44 @@ 46.4 +#!/bin/bash 46.5 + 46.6 +#$ name: init 46.7 + 46.8 +hg init mytag 46.9 +cd mytag 46.10 + 46.11 +echo hello > myfile 46.12 +hg commit -A -m 'Initial commit' 46.13 + 46.14 +#$ name: tag 46.15 + 46.16 +hg tag v1.0 46.17 + 46.18 +#$ name: tags 46.19 + 46.20 +hg tags 46.21 + 46.22 +#$ name: log 46.23 + 46.24 +hg log 46.25 + 46.26 +#$ name: log.v1.0 46.27 + 46.28 +echo goodbye > myfile2 46.29 +hg commit -A -m 'Second commit' 46.30 +hg log -r v1.0 46.31 + 46.32 +#$ name: remove 46.33 + 46.34 +hg tag --remove v1.0 46.35 +hg tags 46.36 + 46.37 +#$ name: replace 46.38 + 46.39 +hg tag -r 1 v1.1 46.40 +hg tags 46.41 +hg tag -r 2 v1.1 46.42 +hg tag -f -r 2 v1.1 46.43 +hg tags 46.44 + 46.45 +#$ name: tip 46.46 + 46.47 +hg tip
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 47.2 +++ b/fr/examples/template.simple Thu Feb 05 12:37:03 2009 +0100 47.3 @@ -0,0 +1,96 @@ 47.4 +#!/bin/bash 47.5 + 47.6 +# So many different bits of random output, it would be a nightmare to 47.7 +# ignore each individually. 47.8 +#$ ignore: .* 47.9 + 47.10 +hg init myrepo 47.11 +cd myrepo 47.12 +echo hello > hello 47.13 +hg commit -Am'added hello' 47.14 + 47.15 +echo hello >> hello 47.16 +echo goodbye > goodbye 47.17 +echo ' added line to end of <<hello>> file.' > ../msg 47.18 +echo '' >> ../msg 47.19 +echo 'in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.' >> ../msg 47.20 + 47.21 +hg commit -Al../msg 47.22 + 47.23 +hg tag mytag 47.24 +hg tag v0.1 47.25 + 47.26 +#$ name: normal 47.27 + 47.28 +hg log -r1 47.29 + 47.30 +#$ name: compact 47.31 + 47.32 +hg log --style compact 47.33 + 47.34 +#$ name: changelog 47.35 + 47.36 +hg log --style changelog 47.37 + 47.38 +#$ name: simplest 47.39 + 47.40 +hg log -r1 --template 'i saw a changeset\n' 47.41 + 47.42 +#$ name: simplesub 47.43 + 47.44 +hg log --template 'i saw a changeset: {desc}\n' 47.45 + 47.46 +#$ name: keywords 47.47 + 47.48 +hg log -r1 --template 'author: {author}\n' 47.49 +hg log -r1 --template 'desc:\n{desc}\n' 47.50 +hg log -r1 --template 'files: {files}\n' 47.51 +hg log -r1 --template 'file_adds: {file_adds}\n' 47.52 +hg log -r1 --template 'file_dels: {file_dels}\n' 47.53 +hg log -r1 --template 'node: {node}\n' 47.54 +hg log -r1 --template 'parents: {parents}\n' 47.55 +hg log -r1 --template 'rev: {rev}\n' 47.56 +hg log -r1 --template 'tags: {tags}\n' 47.57 + 47.58 +#$ name: datekeyword 47.59 + 47.60 +hg log -r1 --template 'date: {date}\n' 47.61 +hg log -r1 --template 'date: {date|isodate}\n' 47.62 + 47.63 +#$ name: manyfilters 47.64 + 47.65 +hg log -r1 --template '{author}\n' 47.66 +hg log -r1 --template '{author|domain}\n' 47.67 +hg log -r1 --template '{author|email}\n' 47.68 +hg log -r1 --template '{author|obfuscate}\n' | cut -c-76 47.69 +hg log -r1 --template '{author|person}\n' 47.70 +hg log -r1 --template '{author|user}\n' 47.71 + 47.72 +hg log -r1 --template 'looks almost right, but actually garbage: {date}\n' 47.73 +hg log -r1 --template '{date|age}\n' 47.74 +hg log -r1 --template '{date|date}\n' 47.75 +hg log -r1 --template '{date|hgdate}\n' 47.76 +hg log -r1 --template '{date|isodate}\n' 47.77 +hg log -r1 --template '{date|rfc822date}\n' 47.78 +hg log -r1 --template '{date|shortdate}\n' 47.79 + 47.80 +hg log -r1 --template '{desc}\n' | cut -c-76 47.81 +hg log -r1 --template '{desc|addbreaks}\n' | cut -c-76 47.82 +hg log -r1 --template '{desc|escape}\n' | cut -c-76 47.83 +hg log -r1 --template '{desc|fill68}\n' 47.84 +hg log -r1 --template '{desc|fill76}\n' 47.85 +hg log -r1 --template '{desc|firstline}\n' 47.86 +hg log -r1 --template '{desc|strip}\n' | cut -c-76 47.87 +hg log -r1 --template '{desc|tabindent}\n' | expand | cut -c-76 47.88 + 47.89 +hg log -r1 --template '{node}\n' 47.90 +hg log -r1 --template '{node|short}\n' 47.91 + 47.92 +#$ name: combine 47.93 + 47.94 +hg log -r1 --template 'description:\n\t{desc|strip|fill68|tabindent}\n' 47.95 + 47.96 +#$ name: rev 47.97 + 47.98 +echo 'changeset = "rev: {rev}\n"' > rev 47.99 +hg log -l1 --style ./rev
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 48.2 +++ b/fr/examples/template.svnstyle Thu Feb 05 12:37:03 2009 +0100 48.3 @@ -0,0 +1,70 @@ 48.4 +#!/bin/bash 48.5 + 48.6 +svn() { 48.7 + cat $EXAMPLE_DIR/svn-short.txt 48.8 +} 48.9 + 48.10 +#$ name: short 48.11 + 48.12 +svn log -r9653 48.13 + 48.14 +#$ name: 48.15 + 48.16 +hg init myrepo 48.17 +cd myrepo 48.18 + 48.19 +echo hello > hello 48.20 +hg commit -Am'added hello' 48.21 + 48.22 +echo hello >> hello 48.23 +echo goodbye > goodbye 48.24 +echo ' added line to end of <<hello>> file.' > ../msg 48.25 +echo '' >> ../msg 48.26 +echo 'in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.' >> ../msg 48.27 + 48.28 +hg commit -Al../msg 48.29 + 48.30 +hg tag mytag 48.31 +hg tag v0.1 48.32 + 48.33 +echo 'changeset = "{node|short}\n"' > svn.style 48.34 + 48.35 +#$ name: id 48.36 + 48.37 +hg log -r0 --template '{node}' 48.38 + 48.39 +#$ name: simplest 48.40 + 48.41 +cat svn.style 48.42 +hg log -r1 --style svn.style 48.43 + 48.44 +#$ name: 48.45 + 48.46 +echo 'changeset =' > broken.style 48.47 + 48.48 +#$ name: syntax.input 48.49 + 48.50 +cat broken.style 48.51 + 48.52 +#$ name: syntax.error 48.53 + 48.54 +hg log -r1 --style broken.style 48.55 + 48.56 +#$ name: 48.57 + 48.58 +cp $EXAMPLE_DIR/svn.style . 48.59 +cp $EXAMPLE_DIR/svn.template . 48.60 + 48.61 +#$ name: template 48.62 + 48.63 +cat svn.template 48.64 + 48.65 +#$ name: style 48.66 + 48.67 +cat svn.style 48.68 + 48.69 +#$ name: result 48.70 +#$ ignore: \| 200[78].* 48.71 + 48.72 +hg log -r1 --style svn.style 48.73 +
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 49.2 +++ b/fr/examples/tour Thu Feb 05 12:37:03 2009 +0100 49.3 @@ -0,0 +1,194 @@ 49.4 +#!/bin/bash 49.5 + 49.6 +#$ name: version 49.7 + 49.8 +hg version 49.9 + 49.10 +#$ name: help 49.11 + 49.12 +hg help init 49.13 + 49.14 +#$ name: clone 49.15 + 49.16 +hg clone http://hg.serpentine.com/tutorial/hello 49.17 + 49.18 +#$ name: ls 49.19 +#$ ignore: ^drwx.* 49.20 +#$ ignore: ^total \d+ 49.21 + 49.22 +ls -l 49.23 +ls hello 49.24 + 49.25 +#$ name: ls-a 49.26 + 49.27 +cd hello 49.28 +ls -a 49.29 + 49.30 +#$ name: log 49.31 + 49.32 +hg log 49.33 + 49.34 +#$ name: log-r 49.35 + 49.36 +hg log -r 3 49.37 +hg log -r 0272e0d5a517 49.38 +hg log -r 1 -r 4 49.39 + 49.40 +#$ name: log.range 49.41 + 49.42 +hg log -r 2:4 49.43 + 49.44 +#$ name: log-v 49.45 + 49.46 +hg log -v -r 3 49.47 + 49.48 +#$ name: log-vp 49.49 + 49.50 +hg log -v -p -r 2 49.51 + 49.52 +#$ name: reclone 49.53 + 49.54 +cd .. 49.55 +hg clone hello my-hello 49.56 +cd my-hello 49.57 + 49.58 +#$ name: sed 49.59 + 49.60 +sed -i '/printf/a\\tprintf("hello again!\\n");' hello.c 49.61 + 49.62 +#$ name: status 49.63 + 49.64 +ls 49.65 +hg status 49.66 + 49.67 +#$ name: diff 49.68 + 49.69 +hg diff 49.70 + 49.71 +#$ name: 49.72 + 49.73 +export HGEDITOR='echo Added an extra line of output >' 49.74 + 49.75 +#$ name: commit 49.76 + 49.77 +hg commit 49.78 + 49.79 +#$ name: merge.dummy1 49.80 + 49.81 +hg log -r 5 | grep changeset | cut -c 16-19 2>/dev/null > /tmp/REV5.my-hello 49.82 + 49.83 +#$ name: tip 49.84 + 49.85 +hg tip -vp 49.86 + 49.87 +#$ name: clone-pull 49.88 + 49.89 +cd .. 49.90 +hg clone hello hello-pull 49.91 + 49.92 +#$ name: incoming 49.93 + 49.94 +cd hello-pull 49.95 +hg incoming ../my-hello 49.96 + 49.97 +#$ name: pull 49.98 + 49.99 +hg tip 49.100 +hg pull ../my-hello 49.101 +hg tip 49.102 + 49.103 +#$ name: update 49.104 + 49.105 +grep printf hello.c 49.106 +hg update tip 49.107 +grep printf hello.c 49.108 + 49.109 +#$ name: parents 49.110 + 49.111 +hg parents 49.112 + 49.113 +#$ name: older 49.114 + 49.115 +hg update 2 49.116 +hg parents 49.117 +hg update 49.118 + 49.119 +#$ name: clone-push 49.120 + 49.121 +cd .. 49.122 +hg clone hello hello-push 49.123 + 49.124 +#$ name: outgoing 49.125 + 49.126 +cd my-hello 49.127 +hg outgoing ../hello-push 49.128 + 49.129 +#$ name: push 49.130 + 49.131 +hg push ../hello-push 49.132 + 49.133 +#$ name: push.nothing 49.134 + 49.135 +hg push ../hello-push 49.136 + 49.137 +#$ name: outgoing.net 49.138 + 49.139 +hg outgoing http://hg.serpentine.com/tutorial/hello 49.140 + 49.141 +#$ name: push.net 49.142 + 49.143 +hg push http://hg.serpentine.com/tutorial/hello 49.144 + 49.145 +#$ name: merge.clone 49.146 + 49.147 +cd .. 49.148 +hg clone hello my-new-hello 49.149 +cd my-new-hello 49.150 +sed -i '/printf/i\\tprintf("once more, hello.\\n");' hello.c 49.151 +hg commit -m 'A new hello for a new day.' 49.152 + 49.153 +#$ name: merge.dummy2 49.154 + 49.155 +hg log -r 5 | grep changeset | cut -c 16-19 2>/dev/null > /tmp/REV5.my-new-hello 49.156 + 49.157 +#$ name: merge.cat 49.158 + 49.159 +cat hello.c 49.160 +cat ../my-hello/hello.c 49.161 + 49.162 +#$ name: merge.pull 49.163 + 49.164 +hg pull ../my-hello 49.165 + 49.166 +#$ name: merge.dummy3 49.167 + 49.168 +hg log -r 6 | grep changeset | cut -c 16-19 2>/dev/null > /tmp/REV6.my-new-hello 49.169 + 49.170 +#$ name: merge.heads 49.171 + 49.172 +hg heads 49.173 + 49.174 +#$ name: merge.update 49.175 + 49.176 +hg update 49.177 + 49.178 +#$ name: merge.merge 49.179 + 49.180 +hg merge 49.181 + 49.182 +#$ name: merge.parents 49.183 + 49.184 +hg parents 49.185 +cat hello.c 49.186 + 49.187 +#$ name: merge.commit 49.188 + 49.189 +hg commit -m 'Merged changes' 49.190 + 49.191 +#$ name: merge.dummy4 49.192 + 49.193 +hg log -r 7 | grep changeset | cut -c 16-19 2>/dev/null > /tmp/REV7.my-new-hello 49.194 + 49.195 +#$ name: merge.tip 49.196 + 49.197 +hg tip
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 50.2 +++ b/fr/examples/tour-merge-conflict Thu Feb 05 12:37:03 2009 +0100 50.3 @@ -0,0 +1,73 @@ 50.4 +#!/bin/bash 50.5 + 50.6 +hg init scam 50.7 +cd scam 50.8 + 50.9 +#$ name: wife 50.10 + 50.11 +cat > letter.txt <<EOF 50.12 +Greetings! 50.13 + 50.14 +I am Mariam Abacha, the wife of former 50.15 +Nigerian dictator Sani Abacha. 50.16 +EOF 50.17 + 50.18 +hg add letter.txt 50.19 +hg commit -m '419 scam, first draft' 50.20 + 50.21 +#$ name: cousin 50.22 + 50.23 +cd .. 50.24 +hg clone scam scam-cousin 50.25 +cd scam-cousin 50.26 + 50.27 +cat > letter.txt <<EOF 50.28 +Greetings! 50.29 + 50.30 +I am Shehu Musa Abacha, cousin to the former 50.31 +Nigerian dictator Sani Abacha. 50.32 +EOF 50.33 + 50.34 +hg commit -m '419 scam, with cousin' 50.35 + 50.36 +#$ name: son 50.37 + 50.38 +cd .. 50.39 +hg clone scam scam-son 50.40 +cd scam-son 50.41 + 50.42 +cat > letter.txt <<EOF 50.43 +Greetings! 50.44 + 50.45 +I am Alhaji Abba Abacha, son of the former 50.46 +Nigerian dictator Sani Abacha. 50.47 +EOF 50.48 + 50.49 +hg commit -m '419 scam, with son' 50.50 + 50.51 +#$ name: pull 50.52 + 50.53 +cd .. 50.54 +hg clone scam-cousin scam-merge 50.55 +cd scam-merge 50.56 +hg pull -u ../scam-son 50.57 + 50.58 +#$ name: merge 50.59 +#$ ignore: [<>]{7} /tmp/.* 50.60 + 50.61 +export HGMERGE=merge 50.62 +hg merge 50.63 +cat letter.txt 50.64 + 50.65 +#$ name: commit 50.66 + 50.67 +cat > letter.txt <<EOF 50.68 +Greetings! 50.69 + 50.70 +I am Bryan O'Sullivan, no relation of the former 50.71 +Nigerian dictator Sani Abacha. 50.72 +EOF 50.73 + 50.74 +hg resolve -m letter.txt 50.75 +hg commit -m 'Send me your money' 50.76 +hg tip
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 51.2 +++ b/fr/fblinks Thu Feb 05 12:37:03 2009 +0100 51.3 @@ -0,0 +1,67 @@ 51.4 +#!/usr/bin/python 51.5 + 51.6 +import errno 51.7 +import os 51.8 +import re 51.9 +import sys 51.10 + 51.11 +hg_id = sys.argv[1] 51.12 + 51.13 +dest_dir = sys.argv[2] 51.14 + 51.15 +empty_re = re.compile(r'^\s*$') 51.16 +line_re = re.compile(r'^(\w+)(.*)') 51.17 + 51.18 +try: 51.19 + os.makedirs(dest_dir) 51.20 +except OSError, err: 51.21 + if err.errno != errno.EEXIST: 51.22 + raise 51.23 + 51.24 +def feedback(name, text, ctx_id): 51.25 + return r'\marginpar{\scriptsize \href{http://demesne:8000/book/feedback/submit/%s/%s/%d/}{Feedback}}' % (hg_id, name, ctx_id) 51.26 + 51.27 +ctxs = {} 51.28 +try: 51.29 + cfp = open(os.path.join(dest_dir, 'rev-' + hg_id + '.ctx'), 'r+') 51.30 + for line in cfp: 51.31 + f, l, c = line.split(':', 2) 51.32 + ctxs[(f, int(l))] = c.strip() 51.33 +except IOError, err: 51.34 + if err.errno != errno.ENOENT: raise 51.35 + cfp = open(os.path.join(dest_dir, 'rev-' + hg_id + '.ctx'), 'w+') 51.36 + 51.37 +changes = 0 51.38 + 51.39 +for name in sys.argv[3:]: 51.40 + if not name.endswith('.tex'): 51.41 + continue 51.42 + dest_name = os.path.join(dest_dir, name) 51.43 + ifp = open(name) 51.44 + ofp = open(dest_name, 'w') 51.45 + new_par = True 51.46 + line_num = 0 51.47 + par_num = 0 51.48 + for line in ifp: 51.49 + line_num += 1 51.50 + if new_par: 51.51 + m = line_re.match(line) 51.52 + if m: 51.53 + par_num += 1 51.54 + ls = line.strip() 51.55 + if ctxs.get((name, par_num)) != ls: 51.56 + ctxs[(name, par_num)] = ls 51.57 + changes += 1 51.58 + line = m.group(1) + feedback(name, line, par_num) + m.group(2) 51.59 + new_par = False 51.60 + elif not line.strip(): 51.61 + new_par = True 51.62 + ofp.write(line) 51.63 + 51.64 +if changes: 51.65 + cfp.seek(0) 51.66 + print '%s: %d changes' % (cfp.name, changes) 51.67 + ctxs = ctxs.items() 51.68 + ctxs.sort() 51.69 + for ((file, line), content) in ctxs: 51.70 + cfp.write('%s:%d: %s\n' % (file, line, content))
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 52.2 +++ b/fr/feature-branches.dot Thu Feb 05 12:37:03 2009 +0100 52.3 @@ -0,0 +1,8 @@ 52.4 +digraph feature_branches { 52.5 + master -> crypto; 52.6 + master -> filesystems; 52.7 + master -> ipc; 52.8 + master -> memory; 52.9 + master -> network; 52.10 + master -> security; 52.11 +}
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 53.2 +++ b/fr/filelog.svg Thu Feb 05 12:37:03 2009 +0100 53.3 @@ -0,0 +1,373 @@ 53.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 53.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 53.6 +<svg 53.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 53.8 + xmlns:cc="http://web.resource.org/cc/" 53.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 53.10 + xmlns:svg="http://www.w3.org/2000/svg" 53.11 + xmlns="http://www.w3.org/2000/svg" 53.12 + xmlns:xlink="http://www.w3.org/1999/xlink" 53.13 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 53.14 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 53.15 + width="744.09448819" 53.16 + height="1052.3622047" 53.17 + id="svg2" 53.18 + sodipodi:version="0.32" 53.19 + inkscape:version="0.45.1" 53.20 + sodipodi:docname="filelog.svg" 53.21 + sodipodi:docbase="/home/arun/hgbook/en" 53.22 + inkscape:output_extension="org.inkscape.output.svg.inkscape"> 53.23 + <defs 53.24 + id="defs4"> 53.25 + <marker 53.26 + inkscape:stockid="Arrow1Mend" 53.27 + orient="auto" 53.28 + refY="0.0" 53.29 + refX="0.0" 53.30 + id="Arrow1Mend" 53.31 + style="overflow:visible;"> 53.32 + <path 53.33 + id="path3128" 53.34 + 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 " 53.35 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 53.36 + transform="scale(0.4) rotate(180) translate(10,0)" /> 53.37 + </marker> 53.38 + <linearGradient 53.39 + id="linearGradient2887"> 53.40 + <stop 53.41 + style="stop-color:#91cfcf;stop-opacity:1;" 53.42 + offset="0" 53.43 + id="stop2889" /> 53.44 + <stop 53.45 + style="stop-color:aqua;stop-opacity:0;" 53.46 + offset="1" 53.47 + id="stop2891" /> 53.48 + </linearGradient> 53.49 + <linearGradient 53.50 + id="linearGradient2795"> 53.51 + <stop 53.52 + style="stop-color:#ccc;stop-opacity:1;" 53.53 + offset="0" 53.54 + id="stop2797" /> 53.55 + <stop 53.56 + style="stop-color:#ccc;stop-opacity:0;" 53.57 + offset="1" 53.58 + id="stop2799" /> 53.59 + </linearGradient> 53.60 + <linearGradient 53.61 + inkscape:collect="always" 53.62 + xlink:href="#linearGradient2795" 53.63 + id="linearGradient3170" 53.64 + gradientUnits="userSpaceOnUse" 53.65 + gradientTransform="translate(121.2183,94.95434)" 53.66 + x1="81.322357" 53.67 + y1="404.34424" 53.68 + x2="201.52036" 53.69 + y2="373.03967" /> 53.70 + <linearGradient 53.71 + inkscape:collect="always" 53.72 + xlink:href="#linearGradient2887" 53.73 + id="linearGradient3172" 53.74 + gradientUnits="userSpaceOnUse" 53.75 + gradientTransform="translate(0,12)" 53.76 + x1="62.634491" 53.77 + y1="503.3392" 53.78 + x2="248.49242" 53.79 + y2="462.94327" /> 53.80 + <linearGradient 53.81 + inkscape:collect="always" 53.82 + xlink:href="#linearGradient2795" 53.83 + id="linearGradient3174" 53.84 + gradientUnits="userSpaceOnUse" 53.85 + gradientTransform="matrix(1.001035,0,0,0.653159,236.7075,153.0415)" 53.86 + x1="81.322357" 53.87 + y1="404.34424" 53.88 + x2="201.52036" 53.89 + y2="373.03967" /> 53.90 + <linearGradient 53.91 + inkscape:collect="always" 53.92 + xlink:href="#linearGradient2887" 53.93 + id="linearGradient3176" 53.94 + gradientUnits="userSpaceOnUse" 53.95 + gradientTransform="translate(0,12)" 53.96 + x1="62.634491" 53.97 + y1="503.3392" 53.98 + x2="248.49242" 53.99 + y2="462.94327" /> 53.100 + <linearGradient 53.101 + inkscape:collect="always" 53.102 + xlink:href="#linearGradient2795" 53.103 + id="linearGradient3208" 53.104 + gradientUnits="userSpaceOnUse" 53.105 + gradientTransform="matrix(1.001035,0,0,0.653159,236.7075,153.0415)" 53.106 + x1="81.322357" 53.107 + y1="404.34424" 53.108 + x2="201.52036" 53.109 + y2="373.03967" /> 53.110 + <linearGradient 53.111 + inkscape:collect="always" 53.112 + xlink:href="#linearGradient2887" 53.113 + id="linearGradient3210" 53.114 + gradientUnits="userSpaceOnUse" 53.115 + gradientTransform="translate(0,12)" 53.116 + x1="62.634491" 53.117 + y1="503.3392" 53.118 + x2="248.49242" 53.119 + y2="462.94327" /> 53.120 + <linearGradient 53.121 + inkscape:collect="always" 53.122 + xlink:href="#linearGradient2795" 53.123 + id="linearGradient3212" 53.124 + gradientUnits="userSpaceOnUse" 53.125 + gradientTransform="translate(121.2183,94.95434)" 53.126 + x1="81.322357" 53.127 + y1="404.34424" 53.128 + x2="201.52036" 53.129 + y2="373.03967" /> 53.130 + <linearGradient 53.131 + inkscape:collect="always" 53.132 + xlink:href="#linearGradient2887" 53.133 + id="linearGradient3214" 53.134 + gradientUnits="userSpaceOnUse" 53.135 + gradientTransform="translate(0,12)" 53.136 + x1="62.634491" 53.137 + y1="503.3392" 53.138 + x2="248.49242" 53.139 + y2="462.94327" /> 53.140 + <linearGradient 53.141 + inkscape:collect="always" 53.142 + xlink:href="#linearGradient2795" 53.143 + id="linearGradient3256" 53.144 + gradientUnits="userSpaceOnUse" 53.145 + gradientTransform="matrix(1.2343775,0,0,0.9981848,103.25588,95.681888)" 53.146 + x1="74.301666" 53.147 + y1="431.67441" 53.148 + x2="260.05884" 53.149 + y2="369.95322" /> 53.150 + <linearGradient 53.151 + inkscape:collect="always" 53.152 + xlink:href="#linearGradient2887" 53.153 + id="linearGradient3258" 53.154 + gradientUnits="userSpaceOnUse" 53.155 + gradientTransform="matrix(1.228929,0,0,0.9972824,-62.037003,13.312997)" 53.156 + x1="62.634491" 53.157 + y1="503.3392" 53.158 + x2="248.49242" 53.159 + y2="462.94327" /> 53.160 + <linearGradient 53.161 + inkscape:collect="always" 53.162 + xlink:href="#linearGradient2795" 53.163 + id="linearGradient3260" 53.164 + gradientUnits="userSpaceOnUse" 53.165 + gradientTransform="matrix(1.2300738,0,0,0.6517275,219.97511,153.61527)" 53.166 + x1="74.387527" 53.167 + y1="431.80576" 53.168 + x2="259.97339" 53.169 + y2="369.82224" /> 53.170 + <linearGradient 53.171 + inkscape:collect="always" 53.172 + xlink:href="#linearGradient2887" 53.173 + id="linearGradient3262" 53.174 + gradientUnits="userSpaceOnUse" 53.175 + gradientTransform="matrix(1.2289272,0,0,0.9972824,-62.036756,13.312985)" 53.176 + x1="62.634491" 53.177 + y1="503.3392" 53.178 + x2="248.49242" 53.179 + y2="462.94327" /> 53.180 + </defs> 53.181 + <sodipodi:namedview 53.182 + id="base" 53.183 + pagecolor="#ffffff" 53.184 + bordercolor="#666666" 53.185 + borderopacity="1.0" 53.186 + gridtolerance="10000" 53.187 + guidetolerance="10" 53.188 + objecttolerance="10" 53.189 + inkscape:pageopacity="0.0" 53.190 + inkscape:pageshadow="2" 53.191 + inkscape:zoom="1.4" 53.192 + inkscape:cx="455.8122" 53.193 + inkscape:cy="520" 53.194 + inkscape:document-units="px" 53.195 + inkscape:current-layer="layer1" 53.196 + inkscape:window-width="1680" 53.197 + inkscape:window-height="970" 53.198 + inkscape:window-x="0" 53.199 + inkscape:window-y="54" /> 53.200 + <metadata 53.201 + id="metadata7"> 53.202 + <rdf:RDF> 53.203 + <cc:Work 53.204 + rdf:about=""> 53.205 + <dc:format>image/svg+xml</dc:format> 53.206 + <dc:type 53.207 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 53.208 + </cc:Work> 53.209 + </rdf:RDF> 53.210 + </metadata> 53.211 + <g 53.212 + inkscape:label="Layer 1" 53.213 + inkscape:groupmode="layer" 53.214 + id="layer1"> 53.215 + <rect 53.216 + style="opacity:1;fill:#abadf8;fill-opacity:1;stroke:#595959;stroke-width:0.93760371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 53.217 + id="rect3180" 53.218 + width="273.81375" 53.219 + height="199.06245" 53.220 + x="369.1796" 53.221 + y="351.79019" /> 53.222 + <rect 53.223 + style="opacity:1;fill:#a2f69c;fill-opacity:1;stroke:#595959;stroke-width:0.93760341;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 53.224 + id="rect3178" 53.225 + width="273.81339" 53.226 + height="199.06233" 53.227 + x="72.699799" 53.228 + y="351.78983" /> 53.229 + <g 53.230 + id="g3144" 53.231 + transform="translate(80.467048,0.71578)"> 53.232 + <g 53.233 + id="g2940"> 53.234 + <rect 53.235 + style="fill:url(#linearGradient3260);fill-opacity:1;stroke:#000000;stroke-width:0.89536202;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 53.236 + id="rect2914" 53.237 + width="227.38896" 53.238 + height="39.500999" 53.239 + x="311.92496" 53.240 + y="395.08627" /> 53.241 + <text 53.242 + xml:space="preserve" 53.243 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 53.244 + x="323.72824" 53.245 + y="416.7626" 53.246 + id="text2918"><tspan 53.247 + sodipodi:role="line" 53.248 + id="tspan2920" 53.249 + x="323.72824" 53.250 + y="416.7626" 53.251 + style="font-family:Courier">.hg/store/data/README.i</tspan></text> 53.252 + </g> 53.253 + <g 53.254 + transform="translate(3.79093e-5,-80.1853)" 53.255 + id="g2945"> 53.256 + <g 53.257 + id="g2955"> 53.258 + <rect 53.259 + y="475.4968" 53.260 + x="15.550935" 53.261 + height="39.500999" 53.262 + width="227.17694" 53.263 + id="rect2947" 53.264 + style="fill:url(#linearGradient3262);fill-opacity:1;stroke:#000000;stroke-width:1.10706258;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 53.265 + <text 53.266 + id="text2949" 53.267 + y="498.35123" 53.268 + x="31.230644" 53.269 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 53.270 + xml:space="preserve"><tspan 53.271 + style="font-family:Courier" 53.272 + y="498.35123" 53.273 + x="31.230644" 53.274 + id="tspan2951" 53.275 + sodipodi:role="line">README</tspan></text> 53.276 + </g> 53.277 + </g> 53.278 + <path 53.279 + inkscape:connector-type="polyline" 53.280 + id="path2960" 53.281 + d="M 242.94685,414.91115 C 242.94685,414.91115 293.61127,415.26754 310.16269,415.38633" 53.282 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.02046943px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 53.283 + sodipodi:nodetypes="cz" /> 53.284 + </g> 53.285 + <g 53.286 + id="g3156" 53.287 + transform="translate(80.467048,0.71578)"> 53.288 + <g 53.289 + transform="translate(116,0)" 53.290 + id="g2831"> 53.291 + <rect 53.292 + style="fill:url(#linearGradient3256);fill-opacity:1;stroke:#000000;stroke-width:1.11001658;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 53.293 + id="rect1906" 53.294 + width="228.18446" 53.295 + height="60.499123" 53.296 + x="195.52719" 53.297 + y="465.51859" /> 53.298 + <g 53.299 + id="g2803" 53.300 + transform="translate(-0.893671,1.833581)"> 53.301 + <text 53.302 + id="text1884" 53.303 + y="483.92801" 53.304 + x="208.95944" 53.305 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 53.306 + xml:space="preserve"><tspan 53.307 + style="font-family:Courier" 53.308 + y="483.92801" 53.309 + x="208.95944" 53.310 + id="tspan1886" 53.311 + sodipodi:role="line">.hg/store/data/src/hello.c.d</tspan></text> 53.312 + <text 53.313 + id="text1888" 53.314 + y="507.79309" 53.315 + x="208.95944" 53.316 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 53.317 + xml:space="preserve"><tspan 53.318 + style="font-family:Courier" 53.319 + y="507.79309" 53.320 + x="208.95944" 53.321 + id="tspan1890" 53.322 + sodipodi:role="line">.hg/store/data/src/hello.c.i</tspan></text> 53.323 + </g> 53.324 + </g> 53.325 + <g 53.326 + id="g2907"> 53.327 + <rect 53.328 + style="fill:url(#linearGradient3258);fill-opacity:1;stroke:#000000;stroke-width:1.10706329;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 53.329 + id="rect2843" 53.330 + width="227.17728" 53.331 + height="39.500999" 53.332 + x="15.550805" 53.333 + y="475.4968" /> 53.334 + <text 53.335 + xml:space="preserve" 53.336 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 53.337 + x="31.230644" 53.338 + y="498.35123" 53.339 + id="text2847"><tspan 53.340 + sodipodi:role="line" 53.341 + id="tspan2849" 53.342 + x="31.230644" 53.343 + y="498.35123" 53.344 + style="font-family:Courier">src/hello.c</tspan></text> 53.345 + </g> 53.346 + <path 53.347 + inkscape:connection-end="#g2831" 53.348 + inkscape:connection-start="#g2907" 53.349 + inkscape:connector-type="polyline" 53.350 + id="path2962" 53.351 + d="M 242.4315,495.88043 C 242.4315,495.88043 292.8861,495.99942 310.04102,496.03909" 53.352 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 53.353 + sodipodi:nodetypes="cs" /> 53.354 + </g> 53.355 + <text 53.356 + xml:space="preserve" 53.357 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 53.358 + x="98.496666" 53.359 + y="373.96353" 53.360 + id="text3216"><tspan 53.361 + sodipodi:role="line" 53.362 + id="tspan3218" 53.363 + x="98.496666" 53.364 + y="373.96353">Working directory</tspan></text> 53.365 + <text 53.366 + xml:space="preserve" 53.367 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 53.368 + x="391.39197" 53.369 + y="373.96353" 53.370 + id="text3228"><tspan 53.371 + sodipodi:role="line" 53.372 + id="tspan3230" 53.373 + x="391.39197" 53.374 + y="373.96353">Repository</tspan></text> 53.375 + </g> 53.376 +</svg>
54.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 54.2 +++ b/fr/filenames.tex Thu Feb 05 12:37:03 2009 +0100 54.3 @@ -0,0 +1,306 @@ 54.4 +\chapter{File names and pattern matching} 54.5 +\label{chap:names} 54.6 + 54.7 +Mercurial provides mechanisms that let you work with file names in a 54.8 +consistent and expressive way. 54.9 + 54.10 +\section{Simple file naming} 54.11 + 54.12 +Mercurial uses a unified piece of machinery ``under the hood'' to 54.13 +handle file names. Every command behaves uniformly with respect to 54.14 +file names. The way in which commands work with file names is as 54.15 +follows. 54.16 + 54.17 +If you explicitly name real files on the command line, Mercurial works 54.18 +with exactly those files, as you would expect. 54.19 +\interaction{filenames.files} 54.20 + 54.21 +When you provide a directory name, Mercurial will interpret this as 54.22 +``operate on every file in this directory and its subdirectories''. 54.23 +Mercurial traverses the files and subdirectories in a directory in 54.24 +alphabetical order. When it encounters a subdirectory, it will 54.25 +traverse that subdirectory before continuing with the current 54.26 +directory. 54.27 +\interaction{filenames.dirs} 54.28 + 54.29 +\section{Running commands without any file names} 54.30 + 54.31 +Mercurial's commands that work with file names have useful default 54.32 +behaviours when you invoke them without providing any file names or 54.33 +patterns. What kind of behaviour you should expect depends on what 54.34 +the command does. Here are a few rules of thumb you can use to 54.35 +predict what a command is likely to do if you don't give it any names 54.36 +to work with. 54.37 +\begin{itemize} 54.38 +\item Most commands will operate on the entire working directory. 54.39 + This is what the \hgcmd{add} command does, for example. 54.40 +\item If the command has effects that are difficult or impossible to 54.41 + reverse, it will force you to explicitly provide at least one name 54.42 + or pattern (see below). This protects you from accidentally 54.43 + deleting files by running \hgcmd{remove} with no arguments, for 54.44 + example. 54.45 +\end{itemize} 54.46 + 54.47 +It's easy to work around these default behaviours if they don't suit 54.48 +you. If a command normally operates on the whole working directory, 54.49 +you can invoke it on just the current directory and its subdirectories 54.50 +by giving it the name ``\dirname{.}''. 54.51 +\interaction{filenames.wdir-subdir} 54.52 + 54.53 +Along the same lines, some commands normally print file names relative 54.54 +to the root of the repository, even if you're invoking them from a 54.55 +subdirectory. Such a command will print file names relative to your 54.56 +subdirectory if you give it explicit names. Here, we're going to run 54.57 +\hgcmd{status} from a subdirectory, and get it to operate on the 54.58 +entire working directory while printing file names relative to our 54.59 +subdirectory, by passing it the output of the \hgcmd{root} command. 54.60 +\interaction{filenames.wdir-relname} 54.61 + 54.62 +\section{Telling you what's going on} 54.63 + 54.64 +The \hgcmd{add} example in the preceding section illustrates something 54.65 +else that's helpful about Mercurial commands. If a command operates 54.66 +on a file that you didn't name explicitly on the command line, it will 54.67 +usually print the name of the file, so that you will not be surprised 54.68 +what's going on. 54.69 + 54.70 +The principle here is of \emph{least surprise}. If you've exactly 54.71 +named a file on the command line, there's no point in repeating it 54.72 +back at you. If Mercurial is acting on a file \emph{implicitly}, 54.73 +because you provided no names, or a directory, or a pattern (see 54.74 +below), it's safest to tell you what it's doing. 54.75 + 54.76 +For commands that behave this way, you can silence them using the 54.77 +\hggopt{-q} option. You can also get them to print the name of every 54.78 +file, even those you've named explicitly, using the \hggopt{-v} 54.79 +option. 54.80 + 54.81 +\section{Using patterns to identify files} 54.82 + 54.83 +In addition to working with file and directory names, Mercurial lets 54.84 +you use \emph{patterns} to identify files. Mercurial's pattern 54.85 +handling is expressive. 54.86 + 54.87 +On Unix-like systems (Linux, MacOS, etc.), the job of matching file 54.88 +names to patterns normally falls to the shell. On these systems, you 54.89 +must explicitly tell Mercurial that a name is a pattern. On Windows, 54.90 +the shell does not expand patterns, so Mercurial will automatically 54.91 +identify names that are patterns, and expand them for you. 54.92 + 54.93 +To provide a pattern in place of a regular name on the command line, 54.94 +the mechanism is simple: 54.95 +\begin{codesample2} 54.96 + syntax:patternbody 54.97 +\end{codesample2} 54.98 +That is, a pattern is identified by a short text string that says what 54.99 +kind of pattern this is, followed by a colon, followed by the actual 54.100 +pattern. 54.101 + 54.102 +Mercurial supports two kinds of pattern syntax. The most frequently 54.103 +used is called \texttt{glob}; this is the same kind of pattern 54.104 +matching used by the Unix shell, and should be familiar to Windows 54.105 +command prompt users, too. 54.106 + 54.107 +When Mercurial does automatic pattern matching on Windows, it uses 54.108 +\texttt{glob} syntax. You can thus omit the ``\texttt{glob:}'' prefix 54.109 +on Windows, but it's safe to use it, too. 54.110 + 54.111 +The \texttt{re} syntax is more powerful; it lets you specify patterns 54.112 +using regular expressions, also known as regexps. 54.113 + 54.114 +By the way, in the examples that follow, notice that I'm careful to 54.115 +wrap all of my patterns in quote characters, so that they won't get 54.116 +expanded by the shell before Mercurial sees them. 54.117 + 54.118 +\subsection{Shell-style \texttt{glob} patterns} 54.119 + 54.120 +This is an overview of the kinds of patterns you can use when you're 54.121 +matching on glob patterns. 54.122 + 54.123 +The ``\texttt{*}'' character matches any string, within a single 54.124 +directory. 54.125 +\interaction{filenames.glob.star} 54.126 + 54.127 +The ``\texttt{**}'' pattern matches any string, and crosses directory 54.128 +boundaries. It's not a standard Unix glob token, but it's accepted by 54.129 +several popular Unix shells, and is very useful. 54.130 +\interaction{filenames.glob.starstar} 54.131 + 54.132 +The ``\texttt{?}'' pattern matches any single character. 54.133 +\interaction{filenames.glob.question} 54.134 + 54.135 +The ``\texttt{[}'' character begins a \emph{character class}. This 54.136 +matches any single character within the class. The class ends with a 54.137 +``\texttt{]}'' character. A class may contain multiple \emph{range}s 54.138 +of the form ``\texttt{a-f}'', which is shorthand for 54.139 +``\texttt{abcdef}''. 54.140 +\interaction{filenames.glob.range} 54.141 +If the first character after the ``\texttt{[}'' in a character class 54.142 +is a ``\texttt{!}'', it \emph{negates} the class, making it match any 54.143 +single character not in the class. 54.144 + 54.145 +A ``\texttt{\{}'' begins a group of subpatterns, where the whole group 54.146 +matches if any subpattern in the group matches. The ``\texttt{,}'' 54.147 +character separates subpatterns, and ``\texttt{\}}'' ends the group. 54.148 +\interaction{filenames.glob.group} 54.149 + 54.150 +\subsubsection{Watch out!} 54.151 + 54.152 +Don't forget that if you want to match a pattern in any directory, you 54.153 +should not be using the ``\texttt{*}'' match-any token, as this will 54.154 +only match within one directory. Instead, use the ``\texttt{**}'' 54.155 +token. This small example illustrates the difference between the two. 54.156 +\interaction{filenames.glob.star-starstar} 54.157 + 54.158 +\subsection{Regular expression matching with \texttt{re} patterns} 54.159 + 54.160 +Mercurial accepts the same regular expression syntax as the Python 54.161 +programming language (it uses Python's regexp engine internally). 54.162 +This is based on the Perl language's regexp syntax, which is the most 54.163 +popular dialect in use (it's also used in Java, for example). 54.164 + 54.165 +I won't discuss Mercurial's regexp dialect in any detail here, as 54.166 +regexps are not often used. Perl-style regexps are in any case 54.167 +already exhaustively documented on a multitude of web sites, and in 54.168 +many books. Instead, I will focus here on a few things you should 54.169 +know if you find yourself needing to use regexps with Mercurial. 54.170 + 54.171 +A regexp is matched against an entire file name, relative to the root 54.172 +of the repository. In other words, even if you're already in 54.173 +subbdirectory \dirname{foo}, if you want to match files under this 54.174 +directory, your pattern must start with ``\texttt{foo/}''. 54.175 + 54.176 +One thing to note, if you're familiar with Perl-style regexps, is that 54.177 +Mercurial's are \emph{rooted}. That is, a regexp starts matching 54.178 +against the beginning of a string; it doesn't look for a match 54.179 +anywhere within the string. To match anywhere in a string, start 54.180 +your pattern with ``\texttt{.*}''. 54.181 + 54.182 +\section{Filtering files} 54.183 + 54.184 +Not only does Mercurial give you a variety of ways to specify files; 54.185 +it lets you further winnow those files using \emph{filters}. Commands 54.186 +that work with file names accept two filtering options. 54.187 +\begin{itemize} 54.188 +\item \hggopt{-I}, or \hggopt{--include}, lets you specify a pattern 54.189 + that file names must match in order to be processed. 54.190 +\item \hggopt{-X}, or \hggopt{--exclude}, gives you a way to 54.191 + \emph{avoid} processing files, if they match this pattern. 54.192 +\end{itemize} 54.193 +You can provide multiple \hggopt{-I} and \hggopt{-X} options on the 54.194 +command line, and intermix them as you please. Mercurial interprets 54.195 +the patterns you provide using glob syntax by default (but you can use 54.196 +regexps if you need to). 54.197 + 54.198 +You can read a \hggopt{-I} filter as ``process only the files that 54.199 +match this filter''. 54.200 +\interaction{filenames.filter.include} 54.201 +The \hggopt{-X} filter is best read as ``process only the files that 54.202 +don't match this pattern''. 54.203 +\interaction{filenames.filter.exclude} 54.204 + 54.205 +\section{Ignoring unwanted files and directories} 54.206 + 54.207 +XXX. 54.208 + 54.209 +\section{Case sensitivity} 54.210 +\label{sec:names:case} 54.211 + 54.212 +If you're working in a mixed development environment that contains 54.213 +both Linux (or other Unix) systems and Macs or Windows systems, you 54.214 +should keep in the back of your mind the knowledge that they treat the 54.215 +case (``N'' versus ``n'') of file names in incompatible ways. This is 54.216 +not very likely to affect you, and it's easy to deal with if it does, 54.217 +but it could surprise you if you don't know about it. 54.218 + 54.219 +Operating systems and filesystems differ in the way they handle the 54.220 +\emph{case} of characters in file and directory names. There are 54.221 +three common ways to handle case in names. 54.222 +\begin{itemize} 54.223 +\item Completely case insensitive. Uppercase and lowercase versions 54.224 + of a letter are treated as identical, both when creating a file and 54.225 + during subsequent accesses. This is common on older DOS-based 54.226 + systems. 54.227 +\item Case preserving, but insensitive. When a file or directory is 54.228 + created, the case of its name is stored, and can be retrieved and 54.229 + displayed by the operating system. When an existing file is being 54.230 + looked up, its case is ignored. This is the standard arrangement on 54.231 + Windows and MacOS. The names \filename{foo} and \filename{FoO} 54.232 + identify the same file. This treatment of uppercase and lowercase 54.233 + letters as interchangeable is also referred to as \emph{case 54.234 + folding}. 54.235 +\item Case sensitive. The case of a name is significant at all times. 54.236 + The names \filename{foo} and {FoO} identify different files. This 54.237 + is the way Linux and Unix systems normally work. 54.238 +\end{itemize} 54.239 + 54.240 +On Unix-like systems, it is possible to have any or all of the above 54.241 +ways of handling case in action at once. For example, if you use a 54.242 +USB thumb drive formatted with a FAT32 filesystem on a Linux system, 54.243 +Linux will handle names on that filesystem in a case preserving, but 54.244 +insensitive, way. 54.245 + 54.246 +\subsection{Safe, portable repository storage} 54.247 + 54.248 +Mercurial's repository storage mechanism is \emph{case safe}. It 54.249 +translates file names so that they can be safely stored on both case 54.250 +sensitive and case insensitive filesystems. This means that you can 54.251 +use normal file copying tools to transfer a Mercurial repository onto, 54.252 +for example, a USB thumb drive, and safely move that drive and 54.253 +repository back and forth between a Mac, a PC running Windows, and a 54.254 +Linux box. 54.255 + 54.256 +\subsection{Detecting case conflicts} 54.257 + 54.258 +When operating in the working directory, Mercurial honours the naming 54.259 +policy of the filesystem where the working directory is located. If 54.260 +the filesystem is case preserving, but insensitive, Mercurial will 54.261 +treat names that differ only in case as the same. 54.262 + 54.263 +An important aspect of this approach is that it is possible to commit 54.264 +a changeset on a case sensitive (typically Linux or Unix) filesystem 54.265 +that will cause trouble for users on case insensitive (usually Windows 54.266 +and MacOS) users. If a Linux user commits changes to two files, one 54.267 +named \filename{myfile.c} and the other named \filename{MyFile.C}, 54.268 +they will be stored correctly in the repository. And in the working 54.269 +directories of other Linux users, they will be correctly represented 54.270 +as separate files. 54.271 + 54.272 +If a Windows or Mac user pulls this change, they will not initially 54.273 +have a problem, because Mercurial's repository storage mechanism is 54.274 +case safe. However, once they try to \hgcmd{update} the working 54.275 +directory to that changeset, or \hgcmd{merge} with that changeset, 54.276 +Mercurial will spot the conflict between the two file names that the 54.277 +filesystem would treat as the same, and forbid the update or merge 54.278 +from occurring. 54.279 + 54.280 +\subsection{Fixing a case conflict} 54.281 + 54.282 +If you are using Windows or a Mac in a mixed environment where some of 54.283 +your collaborators are using Linux or Unix, and Mercurial reports a 54.284 +case folding conflict when you try to \hgcmd{update} or \hgcmd{merge}, 54.285 +the procedure to fix the problem is simple. 54.286 + 54.287 +Just find a nearby Linux or Unix box, clone the problem repository 54.288 +onto it, and use Mercurial's \hgcmd{rename} command to change the 54.289 +names of any offending files or directories so that they will no 54.290 +longer cause case folding conflicts. Commit this change, \hgcmd{pull} 54.291 +or \hgcmd{push} it across to your Windows or MacOS system, and 54.292 +\hgcmd{update} to the revision with the non-conflicting names. 54.293 + 54.294 +The changeset with case-conflicting names will remain in your 54.295 +project's history, and you still won't be able to \hgcmd{update} your 54.296 +working directory to that changeset on a Windows or MacOS system, but 54.297 +you can continue development unimpeded. 54.298 + 54.299 +\begin{note} 54.300 + Prior to version~0.9.3, Mercurial did not use a case safe repository 54.301 + storage mechanism, and did not detect case folding conflicts. If 54.302 + you are using an older version of Mercurial on Windows or MacOS, I 54.303 + strongly recommend that you upgrade. 54.304 +\end{note} 54.305 + 54.306 +%%% Local Variables: 54.307 +%%% mode: latex 54.308 +%%% TeX-master: "00book" 54.309 +%%% End:
55.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 55.2 +++ b/fr/fixhtml.py Thu Feb 05 12:37:03 2009 +0100 55.3 @@ -0,0 +1,50 @@ 55.4 +#!/usr/bin/env python 55.5 +# 55.6 +# This script attempts to work around some of the more bizarre and 55.7 +# quirky behaviours of htlatex. 55.8 +# 55.9 +# - We've persuaded htlatex to produce UTF-8, which unfortunately 55.10 +# causes it to use huge character sequences to represent even the 55.11 +# safe 7-bit ASCII subset of UTF-8. We fix that up. 55.12 +# 55.13 +# - BUT we have to treat angle brackets (for example, redirections in 55.14 +# shell script snippets) specially, otherwise they'll break the 55.15 +# generated HTML. (Reported by Johannes Hoff.) 55.16 +# 55.17 +# - For some reason, htlatex gives a unique ID to each fancyvrb 55.18 +# environment, which makes writing a sane, small CSS stylesheet 55.19 +# impossible. We squish all those IDs down to nothing. 55.20 + 55.21 +import os 55.22 +import sys 55.23 +import re 55.24 + 55.25 +angle_re = re.compile(r'([CE];)') 55.26 +unicode_re = re.compile(r'�([0-7][0-9A-F]);') 55.27 +fancyvrb_re = re.compile(r'id="fancyvrb\d+"', re.I) 55.28 +ligature_re = re.compile(r'ྰ([0-4]);') 55.29 + 55.30 +tmpsuffix = '.tmp.' + str(os.getpid()) 55.31 + 55.32 +def hide_angle(m): 55.33 + return m.group(1).lower() 55.34 + 55.35 +def fix_ascii(m): 55.36 + return chr(int(m.group(1), 16)) 55.37 + 55.38 +ligatures = ['ff', 'fi', 'fl', 'ffi', 'ffl'] 55.39 + 55.40 +def expand_ligature(m): 55.41 + return ligatures[int(m.group(1))] 55.42 + 55.43 +for name in sys.argv[1:]: 55.44 + tmpname = name + tmpsuffix 55.45 + ofp = file(tmpname, 'w') 55.46 + for line in file(name): 55.47 + line = angle_re.sub(hide_angle, line) 55.48 + line = unicode_re.sub(fix_ascii, line) 55.49 + line = ligature_re.sub(expand_ligature, line) 55.50 + line = fancyvrb_re.sub('id="fancyvrb"', line) 55.51 + ofp.write(line) 55.52 + ofp.close() 55.53 + os.rename(tmpname, name)
56.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 56.2 +++ b/fr/fixsvg Thu Feb 05 12:37:03 2009 +0100 56.3 @@ -0,0 +1,29 @@ 56.4 +#!/bin/bash 56.5 + 56.6 +test -d hello || hg clone http://hg.serpentine.com/tutorial/hello 56.7 + 56.8 +set -e 56.9 + 56.10 +for i in 0 1 2 3 4 56.11 +do 56.12 + export REV$i=$(hg --cwd hello log -r $i --template '{node|short}' | cut -c1-4) 56.13 +done 56.14 +export REV_my_hello=$(cat /tmp/REV5.my-hello) 56.15 +export REV_my_new_hello=$(cat /tmp/REV5.my-new-hello) 56.16 +export REV6_my_new_hello=$(cat /tmp/REV6.my-new-hello) 56.17 +export REV7_my_new_hello=$(cat /tmp/REV7.my-new-hello) 56.18 + 56.19 +FILE=$1 56.20 +OUTFILE=$FILE-tmp.svg 56.21 +rm -f $OUTFILE 56.22 +echo "Fixing $FILE" 56.23 +cp $FILE $OUTFILE 56.24 +perl -p -i -e "s#REV0#$REV0#" $OUTFILE 56.25 +perl -p -i -e "s#REV1#$REV1#" $OUTFILE 56.26 +perl -p -i -e "s#REV2#$REV2#" $OUTFILE 56.27 +perl -p -i -e "s#REV3#$REV3#" $OUTFILE 56.28 +perl -p -i -e "s#REV4#$REV4#" $OUTFILE 56.29 +perl -p -i -e "s#REV_my_hello#$REV_my_hello#" $OUTFILE 56.30 +perl -p -i -e "s#REV_my_new_hello#$REV_my_new_hello#" $OUTFILE 56.31 +perl -p -i -e "s#REV6_my_new_hello#$REV6_my_new_hello#" $OUTFILE 56.32 +perl -p -i -e "s#REV7_my_new_hello#$REV7_my_new_hello#" $OUTFILE
57.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 57.2 +++ b/fr/hgbook.css Thu Feb 05 12:37:03 2009 +0100 57.3 @@ -0,0 +1,441 @@ 57.4 +body { 57.5 + font: 12px/1.5 Verdana, sans-serif; 57.6 + padding-top: 50px; 57.7 + padding-left: 80px; 57.8 + padding-right: 80px; 57.9 + padding-bottom: 90px; 57.10 +} 57.11 +.ptmr7t- { 57.12 + font-family: monospace; 57.13 +} 57.14 +.ptmr7t-x-x-172 { 57.15 + font-size: 172%; 57.16 + font-family: monospace; 57.17 +} 57.18 +.ptmr7t-x-x-120 { 57.19 + font-size: 120%; 57.20 +} 57.21 +.zpzccmry-x-x-120 { 57.22 + font-size: 120%; 57.23 + font-weight: bold; 57.24 + font-style: italic; 57.25 +} 57.26 +.zpzccmry-x-x-120 { 57.27 + font-weight: bold; 57.28 + font-style: italic; 57.29 +} 57.30 +.pcrr7tn- { 57.31 + font-family: monospace; 57.32 +} 57.33 +.ptmri7t- { 57.34 + font-style: italic; 57.35 +} 57.36 +.ptmr7t-x-x-50 { 57.37 + font-size: 50%; 57.38 + font-family: monospace; 57.39 +} 57.40 +.ptmb7t- { 57.41 + font-weight: bold; 57.42 +} 57.43 +.zptmcmr- { 57.44 + font-style: italic; 57.45 +} 57.46 +.zptmcmrm- { 57.47 + font-style: italic; 57.48 +} 57.49 +.zpzccmry- { 57.50 + font-weight: bold; 57.51 + font-style: italic; 57.52 +} 57.53 +.pcrb7t- { 57.54 + font-family: monospace; 57.55 + font-weight: bold; 57.56 +} 57.57 +.pcrro7t- { 57.58 + font-family: monospace; 57.59 + font-style: oblique; 57.60 +} 57.61 +p.noindent { 57.62 + text-indent: 0em; 57.63 + margin: 0em; 57.64 +} 57.65 +p.nopar { 57.66 + text-indent: 0em; 57.67 +} 57.68 +p.indent { 57.69 + text-indent: 1.5em; 57.70 + margin: 0em; 57.71 +} 57.72 +a img { 57.73 + border-top: 0; 57.74 + border-left: 0; 57.75 + border-right: 0; 57.76 +} 57.77 +center { 57.78 + margin-top: 1em; 57.79 + margin-bottom: 1em; 57.80 +} 57.81 +td center { 57.82 + margin-top: 0em; 57.83 + margin-bottom: 0em; 57.84 +} 57.85 +.Canvas { 57.86 + position: relative; 57.87 +} 57.88 +img.math { 57.89 + vertical-align: middle; 57.90 +} 57.91 +li p.indent { 57.92 + text-indent: 0em; 57.93 +} 57.94 +.enumerate1 { 57.95 + list-style-type: decimal; 57.96 +} 57.97 +.enumerate2 { 57.98 + list-style-type: lower-alpha; 57.99 +} 57.100 +.enumerate3 { 57.101 + list-style-type: lower-roman; 57.102 +} 57.103 +.enumerate4 { 57.104 + list-style-type: upper-alpha; 57.105 +} 57.106 +div.newtheorem { 57.107 + margin-bottom: 2em; 57.108 + margin-top: 2em; 57.109 +} 57.110 +.obeylines-h,.obeylines-v { 57.111 + white-space: nowrap; 57.112 +} 57.113 +div.obeylines-v p { 57.114 + margin-top: 0; 57.115 + margin-bottom: 0; 57.116 +} 57.117 +.overline { 57.118 + text-decoration: overline; 57.119 +} 57.120 +.overline img { 57.121 + border-top: 1px solid black; 57.122 +} 57.123 +td.displaylines { 57.124 + text-align: center; 57.125 + white-space: nowrap; 57.126 +} 57.127 +.centerline { 57.128 + text-align: center; 57.129 +} 57.130 +.rightline { 57.131 + text-align: right; 57.132 +} 57.133 +div.verbatim { 57.134 + font-family: monospace; 57.135 + white-space: nowrap; 57.136 +} 57.137 +table.verbatim { 57.138 + width: 100%; 57.139 +} 57.140 +.fbox { 57.141 + background: url(note.png) no-repeat #cec; 57.142 + padding-left: 65px; 57.143 + padding-top: 1em; 57.144 + padding-bottom: 1em; 57.145 + padding-right: 1em; 57.146 + text-indent: 0pt; 57.147 + border: dotted black 1px; 57.148 +} 57.149 +div.center div.fbox { 57.150 + text-align: center; 57.151 + clear: both; 57.152 + padding-left: 3.0pt; 57.153 + padding-right: 3.0pt; 57.154 + text-indent: 0pt; 57.155 + border: solid black 0.4pt; 57.156 +} 57.157 +table.minipage { 57.158 + width: 100%; 57.159 +} 57.160 +div.center, div.center div.center { 57.161 + text-align: center; 57.162 + margin-left: 1em; 57.163 + margin-right: 1em; 57.164 +} 57.165 +div.center div { 57.166 + text-align: left; 57.167 +} 57.168 +div.flushright, div.flushright div.flushright { 57.169 + text-align: right; 57.170 +} 57.171 +div.flushright div { 57.172 + text-align: left; 57.173 +} 57.174 +div.flushleft { 57.175 + text-align: left; 57.176 +} 57.177 +.underline { 57.178 + text-decoration: underline; 57.179 +} 57.180 +.underline img { 57.181 + border-bottom: 1px solid black; 57.182 + margin-bottom: 1pt; 57.183 +} 57.184 +.framebox-c, .framebox-l, .framebox-r { 57.185 + padding-left: 3.0pt; 57.186 + padding-right: 3.0pt; 57.187 + text-indent: 0pt; 57.188 + border: solid black 0.4pt; 57.189 +} 57.190 +.framebox-c { 57.191 + text-align: center; 57.192 +} 57.193 +.framebox-l { 57.194 + text-align: left; 57.195 +} 57.196 +.framebox-r { 57.197 + text-align: right; 57.198 +} 57.199 +span.thank-mark { 57.200 + vertical-align: super 57.201 +} 57.202 +span.footnote-mark sup.textsuperscript, span.footnote-mark a sup.textsuperscript { 57.203 + font-size: 80%; 57.204 +} 57.205 +div.tabular, div.center div.tabular { 57.206 + text-align: center; 57.207 + margin-top: 0.5em; 57.208 + margin-bottom: 0.5em; 57.209 +} 57.210 +table.tabular td p { 57.211 + margin-top: 0em; 57.212 +} 57.213 +table.tabular { 57.214 + margin-left: auto; 57.215 + margin-right: auto; 57.216 +} 57.217 +div.td00 { 57.218 + margin-left: 0pt; 57.219 + margin-right: 0pt; 57.220 +} 57.221 +div.td01 { 57.222 + margin-left: 0pt; 57.223 + margin-right: 5pt; 57.224 +} 57.225 +div.td10 { 57.226 + margin-left: 5pt; 57.227 + margin-right: 0pt; 57.228 +} 57.229 +div.td11 { 57.230 + margin-left: 5pt; 57.231 + margin-right: 5pt; 57.232 +} 57.233 +table[rules] { 57.234 + border-left: solid black 0.4pt; 57.235 + border-right: solid black 0.4pt; 57.236 +} 57.237 +td.td00 { 57.238 + padding-left: 0pt; 57.239 + padding-right: 0pt; 57.240 +} 57.241 +td.td01 { 57.242 + padding-left: 0pt; 57.243 + padding-right: 5pt; 57.244 +} 57.245 +td.td10 { 57.246 + padding-left: 5pt; 57.247 + padding-right: 0pt; 57.248 +} 57.249 +td.td11 { 57.250 + padding-left: 5pt; 57.251 + padding-right: 5pt; 57.252 +} 57.253 +table[rules] { 57.254 + border-left: solid black 0.4pt; 57.255 + border-right: solid black 0.4pt; 57.256 +} 57.257 +.hline hr, .cline hr { 57.258 + height : 1px; 57.259 + margin: 0px; 57.260 +} 57.261 +.tabbing-right { 57.262 + text-align: right; 57.263 +} 57.264 +span.TEX { 57.265 + letter-spacing: -0.125em; 57.266 +} 57.267 +span.TEX span.E { 57.268 + position: relative;top: 0.5ex;left: -0.0417em; 57.269 +} 57.270 +a span.TEX span.E { 57.271 + text-decoration: none; 57.272 +} 57.273 +span.LATEX span.A { 57.274 + position: relative; 57.275 + top: -0.5ex; 57.276 + left: -0.4em; 57.277 + font-size: 85%; 57.278 +} 57.279 +span.LATEX span.TEX { 57.280 + position: relative; 57.281 + left: -0.4em; 57.282 +} 57.283 +div.float img, div.float .caption { 57.284 + text-align: center; 57.285 +} 57.286 +div.figure img, div.figure .caption { 57.287 + text-align: center; 57.288 +} 57.289 +.marginpar { 57.290 + width: 20%; 57.291 + float: right; 57.292 + text-align: left; 57.293 + margin-left: auto; 57.294 + margin-top: 0.5em; 57.295 + font-size: 85%; 57.296 + text-decoration: underline; 57.297 +} 57.298 +.marginpar p { 57.299 + margin-top: 0.4em; 57.300 + margin-bottom: 0.4em; 57.301 +} 57.302 +table.equation { 57.303 + width: 100%; 57.304 +} 57.305 +.equation td { 57.306 + text-align: center; 57.307 +} 57.308 +td.equation { 57.309 + margin-top: 1em; 57.310 + margin-bottom: 1em; 57.311 +} 57.312 +td.equation-label { 57.313 + width: 5%; 57.314 + text-align: center; 57.315 +} 57.316 +td.eqnarray4 { 57.317 + width: 5%; 57.318 + white-space: normal; 57.319 +} 57.320 +td.eqnarray2 { 57.321 + width: 5%; 57.322 +} 57.323 +table.eqnarray-star, table.eqnarray { 57.324 + width: 100%; 57.325 +} 57.326 +div.eqnarray { 57.327 + text-align: center; 57.328 +} 57.329 +div.array { 57.330 + text-align: center; 57.331 +} 57.332 +div.pmatrix { 57.333 + text-align: center; 57.334 +} 57.335 +table.pmatrix { 57.336 + width: 100%; 57.337 +} 57.338 +span.pmatrix img { 57.339 + vertical-align: middle; 57.340 +} 57.341 +div.pmatrix { 57.342 + text-align: center; 57.343 +} 57.344 +table.pmatrix { 57.345 + width: 100%; 57.346 +} 57.347 +img.cdots { 57.348 + vertical-align: middle; 57.349 +} 57.350 +.partToc a, .partToc, .likepartToc a, .likepartToc { 57.351 + line-height: 200%; 57.352 + font-weight: bold; 57.353 + font-size: 110%; 57.354 +} 57.355 +.chapterToc a, .chapterToc, .likechapterToc a, .likechapterToc, .appendixToc a, .appendixToc { 57.356 + line-height: 200%; 57.357 + font-weight: bold; 57.358 +} 57.359 +.caption td.id { 57.360 + font-weight: bold; 57.361 + white-space: nowrap; 57.362 +} 57.363 +table.caption { 57.364 + text-align: center; 57.365 +} 57.366 +h1.partHead { 57.367 + text-align: center; 57.368 +} 57.369 +p.bibitem { 57.370 + text-indent: -2em; 57.371 + margin-left: 2em; 57.372 + margin-top: 0.6em; 57.373 + margin-bottom: 0.6em; 57.374 +} 57.375 +p.bibitem-p { 57.376 + text-indent: 0em; 57.377 + margin-left: 2em; 57.378 + margin-top: 0.6em; 57.379 + margin-bottom: 0.6em; 57.380 +} 57.381 +.paragraphHead, .likeparagraphHead { 57.382 + margin-top: 2em; 57.383 + font-weight: bold; 57.384 +} 57.385 +.subparagraphHead, .likesubparagraphHead { 57.386 + font-weight: bold; 57.387 +} 57.388 +.quote { 57.389 + margin-bottom: 0.25em; 57.390 + margin-top: 0.25em; 57.391 + margin-left: 1em; 57.392 + margin-right: 1em; 57.393 + text-align: justify; 57.394 +} 57.395 +.verse { 57.396 + white-space: nowrap; 57.397 + margin-left: 2em} 57.398 +div.maketitle { 57.399 + text-align: center; 57.400 +} 57.401 +h2.titleHead { 57.402 + text-align: center; 57.403 +} 57.404 +div.maketitle { 57.405 + margin-bottom: 2em; 57.406 +} 57.407 +div.author, div.date { 57.408 + text-align: center; 57.409 +} 57.410 +div.thanks { 57.411 + text-align: left; 57.412 + margin-left: 10%; 57.413 + font-size: 85%; 57.414 + font-style: italic; 57.415 +} 57.416 +div.author { 57.417 + white-space: nowrap; 57.418 +} 57.419 +.quotation { 57.420 + margin-bottom: 0.25em; 57.421 + margin-top: 0.25em; 57.422 + margin-left: 1em; 57.423 +} 57.424 +h1.partHead { 57.425 + text-align: center; 57.426 +} 57.427 +img.graphics { 57.428 + margin-left: 10%; 57.429 +} 57.430 +.figure { 57.431 + width: 100%; 57.432 +} 57.433 +P.fancyvrb { 57.434 + white-space: nowrap; 57.435 +} 57.436 +hr { 57.437 + border: 0; 57.438 + height: 1px; 57.439 +} 57.440 +div#fancyvrb { 57.441 + white-space: nowrap; 57.442 + background: #eee; 57.443 + padding: 1em; 57.444 +}
58.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 58.2 +++ b/fr/hgext.tex Thu Feb 05 12:37:03 2009 +0100 58.3 @@ -0,0 +1,429 @@ 58.4 +\chapter{Adding functionality with extensions} 58.5 +\label{chap:hgext} 58.6 + 58.7 +While the core of Mercurial is quite complete from a functionality 58.8 +standpoint, it's deliberately shorn of fancy features. This approach 58.9 +of preserving simplicity keeps the software easy to deal with for both 58.10 +maintainers and users. 58.11 + 58.12 +However, Mercurial doesn't box you in with an inflexible command set: 58.13 +you can add features to it as \emph{extensions} (sometimes known as 58.14 +\emph{plugins}). We've already discussed a few of these extensions in 58.15 +earlier chapters. 58.16 +\begin{itemize} 58.17 +\item Section~\ref{sec:tour-merge:fetch} covers the \hgext{fetch} 58.18 + extension; this combines pulling new changes and merging them with 58.19 + local changes into a single command, \hgxcmd{fetch}{fetch}. 58.20 +\item In chapter~\ref{chap:hook}, we covered several extensions that 58.21 + are useful for hook-related functionality: \hgext{acl} adds access 58.22 + control lists; \hgext{bugzilla} adds integration with the Bugzilla 58.23 + bug tracking system; and \hgext{notify} sends notification emails on 58.24 + new changes. 58.25 +\item The Mercurial Queues patch management extension is so invaluable 58.26 + that it merits two chapters and an appendix all to itself. 58.27 + Chapter~\ref{chap:mq} covers the basics; 58.28 + chapter~\ref{chap:mq-collab} discusses advanced topics; and 58.29 + appendix~\ref{chap:mqref} goes into detail on each command. 58.30 +\end{itemize} 58.31 + 58.32 +In this chapter, we'll cover some of the other extensions that are 58.33 +available for Mercurial, and briefly touch on some of the machinery 58.34 +you'll need to know about if you want to write an extension of your 58.35 +own. 58.36 +\begin{itemize} 58.37 +\item In section~\ref{sec:hgext:inotify}, we'll discuss the 58.38 + possibility of \emph{huge} performance improvements using the 58.39 + \hgext{inotify} extension. 58.40 +\end{itemize} 58.41 + 58.42 +\section{Improve performance with the \hgext{inotify} extension} 58.43 +\label{sec:hgext:inotify} 58.44 + 58.45 +Are you interested in having some of the most common Mercurial 58.46 +operations run as much as a hundred times faster? Read on! 58.47 + 58.48 +Mercurial has great performance under normal circumstances. For 58.49 +example, when you run the \hgcmd{status} command, Mercurial has to 58.50 +scan almost every directory and file in your repository so that it can 58.51 +display file status. Many other Mercurial commands need to do the 58.52 +same work behind the scenes; for example, the \hgcmd{diff} command 58.53 +uses the status machinery to avoid doing an expensive comparison 58.54 +operation on files that obviously haven't changed. 58.55 + 58.56 +Because obtaining file status is crucial to good performance, the 58.57 +authors of Mercurial have optimised this code to within an inch of its 58.58 +life. However, there's no avoiding the fact that when you run 58.59 +\hgcmd{status}, Mercurial is going to have to perform at least one 58.60 +expensive system call for each managed file to determine whether it's 58.61 +changed since the last time Mercurial checked. For a sufficiently 58.62 +large repository, this can take a long time. 58.63 + 58.64 +To put a number on the magnitude of this effect, I created a 58.65 +repository containing 150,000 managed files. I timed \hgcmd{status} 58.66 +as taking ten seconds to run, even when \emph{none} of those files had 58.67 +been modified. 58.68 + 58.69 +Many modern operating systems contain a file notification facility. 58.70 +If a program signs up to an appropriate service, the operating system 58.71 +will notify it every time a file of interest is created, modified, or 58.72 +deleted. On Linux systems, the kernel component that does this is 58.73 +called \texttt{inotify}. 58.74 + 58.75 +Mercurial's \hgext{inotify} extension talks to the kernel's 58.76 +\texttt{inotify} component to optimise \hgcmd{status} commands. The 58.77 +extension has two components. A daemon sits in the background and 58.78 +receives notifications from the \texttt{inotify} subsystem. It also 58.79 +listens for connections from a regular Mercurial command. The 58.80 +extension modifies Mercurial's behaviour so that instead of scanning 58.81 +the filesystem, it queries the daemon. Since the daemon has perfect 58.82 +information about the state of the repository, it can respond with a 58.83 +result instantaneously, avoiding the need to scan every directory and 58.84 +file in the repository. 58.85 + 58.86 +Recall the ten seconds that I measured plain Mercurial as taking to 58.87 +run \hgcmd{status} on a 150,000 file repository. With the 58.88 +\hgext{inotify} extension enabled, the time dropped to 0.1~seconds, a 58.89 +factor of \emph{one hundred} faster. 58.90 + 58.91 +Before we continue, please pay attention to some caveats. 58.92 +\begin{itemize} 58.93 +\item The \hgext{inotify} extension is Linux-specific. Because it 58.94 + interfaces directly to the Linux kernel's \texttt{inotify} 58.95 + subsystem, it does not work on other operating systems. 58.96 +\item It should work on any Linux distribution that was released after 58.97 + early~2005. Older distributions are likely to have a kernel that 58.98 + lacks \texttt{inotify}, or a version of \texttt{glibc} that does not 58.99 + have the necessary interfacing support. 58.100 +\item Not all filesystems are suitable for use with the 58.101 + \hgext{inotify} extension. Network filesystems such as NFS are a 58.102 + non-starter, for example, particularly if you're running Mercurial 58.103 + on several systems, all mounting the same network filesystem. The 58.104 + kernel's \texttt{inotify} system has no way of knowing about changes 58.105 + made on another system. Most local filesystems (e.g.~ext3, XFS, 58.106 + ReiserFS) should work fine. 58.107 +\end{itemize} 58.108 + 58.109 +The \hgext{inotify} extension is not yet shipped with Mercurial as of 58.110 +May~2007, so it's a little more involved to set up than other 58.111 +extensions. But the performance improvement is worth it! 58.112 + 58.113 +The extension currently comes in two parts: a set of patches to the 58.114 +Mercurial source code, and a library of Python bindings to the 58.115 +\texttt{inotify} subsystem. 58.116 +\begin{note} 58.117 + There are \emph{two} Python \texttt{inotify} binding libraries. One 58.118 + of them is called \texttt{pyinotify}, and is packaged by some Linux 58.119 + distributions as \texttt{python-inotify}. This is \emph{not} the 58.120 + one you'll need, as it is too buggy and inefficient to be practical. 58.121 +\end{note} 58.122 +To get going, it's best to already have a functioning copy of 58.123 +Mercurial installed. 58.124 +\begin{note} 58.125 + If you follow the instructions below, you'll be \emph{replacing} and 58.126 + overwriting any existing installation of Mercurial that you might 58.127 + already have, using the latest ``bleeding edge'' Mercurial code. 58.128 + Don't say you weren't warned! 58.129 +\end{note} 58.130 +\begin{enumerate} 58.131 +\item Clone the Python \texttt{inotify} binding repository. Build and 58.132 + install it. 58.133 + \begin{codesample4} 58.134 + hg clone http://hg.kublai.com/python/inotify 58.135 + cd inotify 58.136 + python setup.py build --force 58.137 + sudo python setup.py install --skip-build 58.138 + \end{codesample4} 58.139 +\item Clone the \dirname{crew} Mercurial repository. Clone the 58.140 + \hgext{inotify} patch repository so that Mercurial Queues will be 58.141 + able to apply patches to your cope of the \dirname{crew} repository. 58.142 + \begin{codesample4} 58.143 + hg clone http://hg.intevation.org/mercurial/crew 58.144 + hg clone crew inotify 58.145 + hg clone http://hg.kublai.com/mercurial/patches/inotify inotify/.hg/patches 58.146 + \end{codesample4} 58.147 +\item Make sure that you have the Mercurial Queues extension, 58.148 + \hgext{mq}, enabled. If you've never used MQ, read 58.149 + section~\ref{sec:mq:start} to get started quickly. 58.150 +\item Go into the \dirname{inotify} repo, and apply all of the 58.151 + \hgext{inotify} patches using the \hgxopt{mq}{qpush}{-a} option to 58.152 + the \hgxcmd{mq}{qpush} command. 58.153 + \begin{codesample4} 58.154 + cd inotify 58.155 + hg qpush -a 58.156 + \end{codesample4} 58.157 + If you get an error message from \hgxcmd{mq}{qpush}, you should not 58.158 + continue. Instead, ask for help. 58.159 +\item Build and install the patched version of Mercurial. 58.160 + \begin{codesample4} 58.161 + python setup.py build --force 58.162 + sudo python setup.py install --skip-build 58.163 + \end{codesample4} 58.164 +\end{enumerate} 58.165 +Once you've build a suitably patched version of Mercurial, all you 58.166 +need to do to enable the \hgext{inotify} extension is add an entry to 58.167 +your \hgrc. 58.168 +\begin{codesample2} 58.169 + [extensions] 58.170 + inotify = 58.171 +\end{codesample2} 58.172 +When the \hgext{inotify} extension is enabled, Mercurial will 58.173 +automatically and transparently start the status daemon the first time 58.174 +you run a command that needs status in a repository. It runs one 58.175 +status daemon per repository. 58.176 + 58.177 +The status daemon is started silently, and runs in the background. If 58.178 +you look at a list of running processes after you've enabled the 58.179 +\hgext{inotify} extension and run a few commands in different 58.180 +repositories, you'll thus see a few \texttt{hg} processes sitting 58.181 +around, waiting for updates from the kernel and queries from 58.182 +Mercurial. 58.183 + 58.184 +The first time you run a Mercurial command in a repository when you 58.185 +have the \hgext{inotify} extension enabled, it will run with about the 58.186 +same performance as a normal Mercurial command. This is because the 58.187 +status daemon needs to perform a normal status scan so that it has a 58.188 +baseline against which to apply later updates from the kernel. 58.189 +However, \emph{every} subsequent command that does any kind of status 58.190 +check should be noticeably faster on repositories of even fairly 58.191 +modest size. Better yet, the bigger your repository is, the greater a 58.192 +performance advantage you'll see. The \hgext{inotify} daemon makes 58.193 +status operations almost instantaneous on repositories of all sizes! 58.194 + 58.195 +If you like, you can manually start a status daemon using the 58.196 +\hgxcmd{inotify}{inserve} command. This gives you slightly finer 58.197 +control over how the daemon ought to run. This command will of course 58.198 +only be available when the \hgext{inotify} extension is enabled. 58.199 + 58.200 +When you're using the \hgext{inotify} extension, you should notice 58.201 +\emph{no difference at all} in Mercurial's behaviour, with the sole 58.202 +exception of status-related commands running a whole lot faster than 58.203 +they used to. You should specifically expect that commands will not 58.204 +print different output; neither should they give different results. 58.205 +If either of these situations occurs, please report a bug. 58.206 + 58.207 +\section{Flexible diff support with the \hgext{extdiff} extension} 58.208 +\label{sec:hgext:extdiff} 58.209 + 58.210 +Mercurial's built-in \hgcmd{diff} command outputs plaintext unified 58.211 +diffs. 58.212 +\interaction{extdiff.diff} 58.213 +If you would like to use an external tool to display modifications, 58.214 +you'll want to use the \hgext{extdiff} extension. This will let you 58.215 +use, for example, a graphical diff tool. 58.216 + 58.217 +The \hgext{extdiff} extension is bundled with Mercurial, so it's easy 58.218 +to set up. In the \rcsection{extensions} section of your \hgrc, 58.219 +simply add a one-line entry to enable the extension. 58.220 +\begin{codesample2} 58.221 + [extensions] 58.222 + extdiff = 58.223 +\end{codesample2} 58.224 +This introduces a command named \hgxcmd{extdiff}{extdiff}, which by 58.225 +default uses your system's \command{diff} command to generate a 58.226 +unified diff in the same form as the built-in \hgcmd{diff} command. 58.227 +\interaction{extdiff.extdiff} 58.228 +The result won't be exactly the same as with the built-in \hgcmd{diff} 58.229 +variations, because the output of \command{diff} varies from one 58.230 +system to another, even when passed the same options. 58.231 + 58.232 +As the ``\texttt{making snapshot}'' lines of output above imply, the 58.233 +\hgxcmd{extdiff}{extdiff} command works by creating two snapshots of 58.234 +your source tree. The first snapshot is of the source revision; the 58.235 +second, of the target revision or working directory. The 58.236 +\hgxcmd{extdiff}{extdiff} command generates these snapshots in a 58.237 +temporary directory, passes the name of each directory to an external 58.238 +diff viewer, then deletes the temporary directory. For efficiency, it 58.239 +only snapshots the directories and files that have changed between the 58.240 +two revisions. 58.241 + 58.242 +Snapshot directory names have the same base name as your repository. 58.243 +If your repository path is \dirname{/quux/bar/foo}, then \dirname{foo} 58.244 +will be the name of each snapshot directory. Each snapshot directory 58.245 +name has its changeset ID appended, if appropriate. If a snapshot is 58.246 +of revision \texttt{a631aca1083f}, the directory will be named 58.247 +\dirname{foo.a631aca1083f}. A snapshot of the working directory won't 58.248 +have a changeset ID appended, so it would just be \dirname{foo} in 58.249 +this example. To see what this looks like in practice, look again at 58.250 +the \hgxcmd{extdiff}{extdiff} example above. Notice that the diff has 58.251 +the snapshot directory names embedded in its header. 58.252 + 58.253 +The \hgxcmd{extdiff}{extdiff} command accepts two important options. 58.254 +The \hgxopt{extdiff}{extdiff}{-p} option lets you choose a program to 58.255 +view differences with, instead of \command{diff}. With the 58.256 +\hgxopt{extdiff}{extdiff}{-o} option, you can change the options that 58.257 +\hgxcmd{extdiff}{extdiff} passes to the program (by default, these 58.258 +options are ``\texttt{-Npru}'', which only make sense if you're 58.259 +running \command{diff}). In other respects, the 58.260 +\hgxcmd{extdiff}{extdiff} command acts similarly to the built-in 58.261 +\hgcmd{diff} command: you use the same option names, syntax, and 58.262 +arguments to specify the revisions you want, the files you want, and 58.263 +so on. 58.264 + 58.265 +As an example, here's how to run the normal system \command{diff} 58.266 +command, getting it to generate context diffs (using the 58.267 +\cmdopt{diff}{-c} option) instead of unified diffs, and five lines of 58.268 +context instead of the default three (passing \texttt{5} as the 58.269 +argument to the \cmdopt{diff}{-C} option). 58.270 +\interaction{extdiff.extdiff-ctx} 58.271 + 58.272 +Launching a visual diff tool is just as easy. Here's how to launch 58.273 +the \command{kdiff3} viewer. 58.274 +\begin{codesample2} 58.275 + hg extdiff -p kdiff3 -o '' 58.276 +\end{codesample2} 58.277 + 58.278 +If your diff viewing command can't deal with directories, you can 58.279 +easily work around this with a little scripting. For an example of 58.280 +such scripting in action with the \hgext{mq} extension and the 58.281 +\command{interdiff} command, see 58.282 +section~\ref{mq-collab:tips:interdiff}. 58.283 + 58.284 +\subsection{Defining command aliases} 58.285 + 58.286 +It can be cumbersome to remember the options to both the 58.287 +\hgxcmd{extdiff}{extdiff} command and the diff viewer you want to use, 58.288 +so the \hgext{extdiff} extension lets you define \emph{new} commands 58.289 +that will invoke your diff viewer with exactly the right options. 58.290 + 58.291 +All you need to do is edit your \hgrc, and add a section named 58.292 +\rcsection{extdiff}. Inside this section, you can define multiple 58.293 +commands. Here's how to add a \texttt{kdiff3} command. Once you've 58.294 +defined this, you can type ``\texttt{hg kdiff3}'' and the 58.295 +\hgext{extdiff} extension will run \command{kdiff3} for you. 58.296 +\begin{codesample2} 58.297 + [extdiff] 58.298 + cmd.kdiff3 = 58.299 +\end{codesample2} 58.300 +If you leave the right hand side of the definition empty, as above, 58.301 +the \hgext{extdiff} extension uses the name of the command you defined 58.302 +as the name of the external program to run. But these names don't 58.303 +have to be the same. Here, we define a command named ``\texttt{hg 58.304 + wibble}'', which runs \command{kdiff3}. 58.305 +\begin{codesample2} 58.306 + [extdiff] 58.307 + cmd.wibble = kdiff3 58.308 +\end{codesample2} 58.309 + 58.310 +You can also specify the default options that you want to invoke your 58.311 +diff viewing program with. The prefix to use is ``\texttt{opts.}'', 58.312 +followed by the name of the command to which the options apply. This 58.313 +example defines a ``\texttt{hg vimdiff}'' command that runs the 58.314 +\command{vim} editor's \texttt{DirDiff} extension. 58.315 +\begin{codesample2} 58.316 + [extdiff] 58.317 + cmd.vimdiff = vim 58.318 + opts.vimdiff = -f '+next' '+execute "DirDiff" argv(0) argv(1)' 58.319 +\end{codesample2} 58.320 + 58.321 +\section{Cherrypicking changes with the \hgext{transplant} extension} 58.322 +\label{sec:hgext:transplant} 58.323 + 58.324 +Need to have a long chat with Brendan about this. 58.325 + 58.326 +\section{Send changes via email with the \hgext{patchbomb} extension} 58.327 +\label{sec:hgext:patchbomb} 58.328 + 58.329 +Many projects have a culture of ``change review'', in which people 58.330 +send their modifications to a mailing list for others to read and 58.331 +comment on before they commit the final version to a shared 58.332 +repository. Some projects have people who act as gatekeepers; they 58.333 +apply changes from other people to a repository to which those others 58.334 +don't have access. 58.335 + 58.336 +Mercurial makes it easy to send changes over email for review or 58.337 +application, via its \hgext{patchbomb} extension. The extension is so 58.338 +namd because changes are formatted as patches, and it's usual to send 58.339 +one changeset per email message. Sending a long series of changes by 58.340 +email is thus much like ``bombing'' the recipient's inbox, hence 58.341 +``patchbomb''. 58.342 + 58.343 +As usual, the basic configuration of the \hgext{patchbomb} extension 58.344 +takes just one or two lines in your \hgrc. 58.345 +\begin{codesample2} 58.346 + [extensions] 58.347 + patchbomb = 58.348 +\end{codesample2} 58.349 +Once you've enabled the extension, you will have a new command 58.350 +available, named \hgxcmd{patchbomb}{email}. 58.351 + 58.352 +The safest and best way to invoke the \hgxcmd{patchbomb}{email} 58.353 +command is to \emph{always} run it first with the 58.354 +\hgxopt{patchbomb}{email}{-n} option. This will show you what the 58.355 +command \emph{would} send, without actually sending anything. Once 58.356 +you've had a quick glance over the changes and verified that you are 58.357 +sending the right ones, you can rerun the same command, with the 58.358 +\hgxopt{patchbomb}{email}{-n} option removed. 58.359 + 58.360 +The \hgxcmd{patchbomb}{email} command accepts the same kind of 58.361 +revision syntax as every other Mercurial command. For example, this 58.362 +command will send every revision between 7 and \texttt{tip}, 58.363 +inclusive. 58.364 +\begin{codesample2} 58.365 + hg email -n 7:tip 58.366 +\end{codesample2} 58.367 +You can also specify a \emph{repository} to compare with. If you 58.368 +provide a repository but no revisions, the \hgxcmd{patchbomb}{email} 58.369 +command will send all revisions in the local repository that are not 58.370 +present in the remote repository. If you additionally specify 58.371 +revisions or a branch name (the latter using the 58.372 +\hgxopt{patchbomb}{email}{-b} option), this will constrain the 58.373 +revisions sent. 58.374 + 58.375 +It's perfectly safe to run the \hgxcmd{patchbomb}{email} command 58.376 +without the names of the people you want to send to: if you do this, 58.377 +it will just prompt you for those values interactively. (If you're 58.378 +using a Linux or Unix-like system, you should have enhanced 58.379 +\texttt{readline}-style editing capabilities when entering those 58.380 +headers, too, which is useful.) 58.381 + 58.382 +When you are sending just one revision, the \hgxcmd{patchbomb}{email} 58.383 +command will by default use the first line of the changeset 58.384 +description as the subject of the single email message it sends. 58.385 + 58.386 +If you send multiple revisions, the \hgxcmd{patchbomb}{email} command 58.387 +will usually send one message per changeset. It will preface the 58.388 +series with an introductory message, in which you should describe the 58.389 +purpose of the series of changes you're sending. 58.390 + 58.391 +\subsection{Changing the behaviour of patchbombs} 58.392 + 58.393 +Not every project has exactly the same conventions for sending changes 58.394 +in email; the \hgext{patchbomb} extension tries to accommodate a 58.395 +number of variations through command line options. 58.396 +\begin{itemize} 58.397 +\item You can write a subject for the introductory message on the 58.398 + command line using the \hgxopt{patchbomb}{email}{-s} option. This 58.399 + takes one argument, the text of the subject to use. 58.400 +\item To change the email address from which the messages originate, 58.401 + use the \hgxopt{patchbomb}{email}{-f} option. This takes one 58.402 + argument, the email address to use. 58.403 +\item The default behaviour is to send unified diffs (see 58.404 + section~\ref{sec:mq:patch} for a description of the format), one per 58.405 + message. You can send a binary bundle instead with the 58.406 + \hgxopt{patchbomb}{email}{-b} option. 58.407 +\item Unified diffs are normally prefaced with a metadata header. You 58.408 + can omit this, and send unadorned diffs, with the 58.409 + \hgxopt{patchbomb}{email}{--plain} option. 58.410 +\item Diffs are normally sent ``inline'', in the same body part as the 58.411 + description of a patch. This makes it easiest for the largest 58.412 + number of readers to quote and respond to parts of a diff, as some 58.413 + mail clients will only quote the first MIME body part in a message. 58.414 + If you'd prefer to send the description and the diff in separate 58.415 + body parts, use the \hgxopt{patchbomb}{email}{-a} option. 58.416 +\item Instead of sending mail messages, you can write them to an 58.417 + \texttt{mbox}-format mail folder using the 58.418 + \hgxopt{patchbomb}{email}{-m} option. That option takes one 58.419 + argument, the name of the file to write to. 58.420 +\item If you would like to add a \command{diffstat}-format summary to 58.421 + each patch, and one to the introductory message, use the 58.422 + \hgxopt{patchbomb}{email}{-d} option. The \command{diffstat} 58.423 + command displays a table containing the name of each file patched, 58.424 + the number of lines affected, and a histogram showing how much each 58.425 + file is modified. This gives readers a qualitative glance at how 58.426 + complex a patch is. 58.427 +\end{itemize} 58.428 + 58.429 +%%% Local Variables: 58.430 +%%% mode: latex 58.431 +%%% TeX-master: "00book" 58.432 +%%% End:
59.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 59.2 +++ b/fr/hook.tex Thu Feb 05 12:37:03 2009 +0100 59.3 @@ -0,0 +1,1413 @@ 59.4 +\chapter{Handling repository events with hooks} 59.5 +\label{chap:hook} 59.6 + 59.7 +Mercurial offers a powerful mechanism to let you perform automated 59.8 +actions in response to events that occur in a repository. In some 59.9 +cases, you can even control Mercurial's response to those events. 59.10 + 59.11 +The name Mercurial uses for one of these actions is a \emph{hook}. 59.12 +Hooks are called ``triggers'' in some revision control systems, but 59.13 +the two names refer to the same idea. 59.14 + 59.15 +\section{An overview of hooks in Mercurial} 59.16 + 59.17 +Here is a brief list of the hooks that Mercurial supports. We will 59.18 +revisit each of these hooks in more detail later, in 59.19 +section~\ref{sec:hook:ref}. 59.20 + 59.21 +\begin{itemize} 59.22 +\item[\small\hook{changegroup}] This is run after a group of 59.23 + changesets has been brought into the repository from elsewhere. 59.24 +\item[\small\hook{commit}] This is run after a new changeset has been 59.25 + created in the local repository. 59.26 +\item[\small\hook{incoming}] This is run once for each new changeset 59.27 + that is brought into the repository from elsewhere. Notice the 59.28 + difference from \hook{changegroup}, which is run once per 59.29 + \emph{group} of changesets brought in. 59.30 +\item[\small\hook{outgoing}] This is run after a group of changesets 59.31 + has been transmitted from this repository. 59.32 +\item[\small\hook{prechangegroup}] This is run before starting to 59.33 + bring a group of changesets into the repository. 59.34 +\item[\small\hook{precommit}] Controlling. This is run before starting 59.35 + a commit. 59.36 +\item[\small\hook{preoutgoing}] Controlling. This is run before 59.37 + starting to transmit a group of changesets from this repository. 59.38 +\item[\small\hook{pretag}] Controlling. This is run before creating a tag. 59.39 +\item[\small\hook{pretxnchangegroup}] Controlling. This is run after a 59.40 + group of changesets has been brought into the local repository from 59.41 + another, but before the transaction completes that will make the 59.42 + changes permanent in the repository. 59.43 +\item[\small\hook{pretxncommit}] Controlling. This is run after a new 59.44 + changeset has been created in the local repository, but before the 59.45 + transaction completes that will make it permanent. 59.46 +\item[\small\hook{preupdate}] Controlling. This is run before starting 59.47 + an update or merge of the working directory. 59.48 +\item[\small\hook{tag}] This is run after a tag is created. 59.49 +\item[\small\hook{update}] This is run after an update or merge of the 59.50 + working directory has finished. 59.51 +\end{itemize} 59.52 +Each of the hooks whose description begins with the word 59.53 +``Controlling'' has the ability to determine whether an activity can 59.54 +proceed. If the hook succeeds, the activity may proceed; if it fails, 59.55 +the activity is either not permitted or undone, depending on the hook. 59.56 + 59.57 +\section{Hooks and security} 59.58 + 59.59 +\subsection{Hooks are run with your privileges} 59.60 + 59.61 +When you run a Mercurial command in a repository, and the command 59.62 +causes a hook to run, that hook runs on \emph{your} system, under 59.63 +\emph{your} user account, with \emph{your} privilege level. Since 59.64 +hooks are arbitrary pieces of executable code, you should treat them 59.65 +with an appropriate level of suspicion. Do not install a hook unless 59.66 +you are confident that you know who created it and what it does. 59.67 + 59.68 +In some cases, you may be exposed to hooks that you did not install 59.69 +yourself. If you work with Mercurial on an unfamiliar system, 59.70 +Mercurial will run hooks defined in that system's global \hgrc\ file. 59.71 + 59.72 +If you are working with a repository owned by another user, Mercurial 59.73 +can run hooks defined in that user's repository, but it will still run 59.74 +them as ``you''. For example, if you \hgcmd{pull} from that 59.75 +repository, and its \sfilename{.hg/hgrc} defines a local 59.76 +\hook{outgoing} hook, that hook will run under your user account, even 59.77 +though you don't own that repository. 59.78 + 59.79 +\begin{note} 59.80 + This only applies if you are pulling from a repository on a local or 59.81 + network filesystem. If you're pulling over http or ssh, any 59.82 + \hook{outgoing} hook will run under whatever account is executing 59.83 + the server process, on the server. 59.84 +\end{note} 59.85 + 59.86 +XXX To see what hooks are defined in a repository, use the 59.87 +\hgcmdargs{config}{hooks} command. If you are working in one 59.88 +repository, but talking to another that you do not own (e.g.~using 59.89 +\hgcmd{pull} or \hgcmd{incoming}), remember that it is the other 59.90 +repository's hooks you should be checking, not your own. 59.91 + 59.92 +\subsection{Hooks do not propagate} 59.93 + 59.94 +In Mercurial, hooks are not revision controlled, and do not propagate 59.95 +when you clone, or pull from, a repository. The reason for this is 59.96 +simple: a hook is a completely arbitrary piece of executable code. It 59.97 +runs under your user identity, with your privilege level, on your 59.98 +machine. 59.99 + 59.100 +It would be extremely reckless for any distributed revision control 59.101 +system to implement revision-controlled hooks, as this would offer an 59.102 +easily exploitable way to subvert the accounts of users of the 59.103 +revision control system. 59.104 + 59.105 +Since Mercurial does not propagate hooks, if you are collaborating 59.106 +with other people on a common project, you should not assume that they 59.107 +are using the same Mercurial hooks as you are, or that theirs are 59.108 +correctly configured. You should document the hooks you expect people 59.109 +to use. 59.110 + 59.111 +In a corporate intranet, this is somewhat easier to control, as you 59.112 +can for example provide a ``standard'' installation of Mercurial on an 59.113 +NFS filesystem, and use a site-wide \hgrc\ file to define hooks that 59.114 +all users will see. However, this too has its limits; see below. 59.115 + 59.116 +\subsection{Hooks can be overridden} 59.117 + 59.118 +Mercurial allows you to override a hook definition by redefining the 59.119 +hook. You can disable it by setting its value to the empty string, or 59.120 +change its behaviour as you wish. 59.121 + 59.122 +If you deploy a system-~or site-wide \hgrc\ file that defines some 59.123 +hooks, you should thus understand that your users can disable or 59.124 +override those hooks. 59.125 + 59.126 +\subsection{Ensuring that critical hooks are run} 59.127 + 59.128 +Sometimes you may want to enforce a policy that you do not want others 59.129 +to be able to work around. For example, you may have a requirement 59.130 +that every changeset must pass a rigorous set of tests. Defining this 59.131 +requirement via a hook in a site-wide \hgrc\ won't work for remote 59.132 +users on laptops, and of course local users can subvert it at will by 59.133 +overriding the hook. 59.134 + 59.135 +Instead, you can set up your policies for use of Mercurial so that 59.136 +people are expected to propagate changes through a well-known 59.137 +``canonical'' server that you have locked down and configured 59.138 +appropriately. 59.139 + 59.140 +One way to do this is via a combination of social engineering and 59.141 +technology. Set up a restricted-access account; users can push 59.142 +changes over the network to repositories managed by this account, but 59.143 +they cannot log into the account and run normal shell commands. In 59.144 +this scenario, a user can commit a changeset that contains any old 59.145 +garbage they want. 59.146 + 59.147 +When someone pushes a changeset to the server that everyone pulls 59.148 +from, the server will test the changeset before it accepts it as 59.149 +permanent, and reject it if it fails to pass the test suite. If 59.150 +people only pull changes from this filtering server, it will serve to 59.151 +ensure that all changes that people pull have been automatically 59.152 +vetted. 59.153 + 59.154 +\section{Care with \texttt{pretxn} hooks in a shared-access repository} 59.155 + 59.156 +If you want to use hooks to do some automated work in a repository 59.157 +that a number of people have shared access to, you need to be careful 59.158 +in how you do this. 59.159 + 59.160 +Mercurial only locks a repository when it is writing to the 59.161 +repository, and only the parts of Mercurial that write to the 59.162 +repository pay attention to locks. Write locks are necessary to 59.163 +prevent multiple simultaneous writers from scribbling on each other's 59.164 +work, corrupting the repository. 59.165 + 59.166 +Because Mercurial is careful with the order in which it reads and 59.167 +writes data, it does not need to acquire a lock when it wants to read 59.168 +data from the repository. The parts of Mercurial that read from the 59.169 +repository never pay attention to locks. This lockless reading scheme 59.170 +greatly increases performance and concurrency. 59.171 + 59.172 +With great performance comes a trade-off, though, one which has the 59.173 +potential to cause you trouble unless you're aware of it. To describe 59.174 +this requires a little detail about how Mercurial adds changesets to a 59.175 +repository and reads those changes. 59.176 + 59.177 +When Mercurial \emph{writes} metadata, it writes it straight into the 59.178 +destination file. It writes file data first, then manifest data 59.179 +(which contains pointers to the new file data), then changelog data 59.180 +(which contains pointers to the new manifest data). Before the first 59.181 +write to each file, it stores a record of where the end of the file 59.182 +was in its transaction log. If the transaction must be rolled back, 59.183 +Mercurial simply truncates each file back to the size it was before the 59.184 +transaction began. 59.185 + 59.186 +When Mercurial \emph{reads} metadata, it reads the changelog first, 59.187 +then everything else. Since a reader will only access parts of the 59.188 +manifest or file metadata that it can see in the changelog, it can 59.189 +never see partially written data. 59.190 + 59.191 +Some controlling hooks (\hook{pretxncommit} and 59.192 +\hook{pretxnchangegroup}) run when a transaction is almost complete. 59.193 +All of the metadata has been written, but Mercurial can still roll the 59.194 +transaction back and cause the newly-written data to disappear. 59.195 + 59.196 +If one of these hooks runs for long, it opens a window of time during 59.197 +which a reader can see the metadata for changesets that are not yet 59.198 +permanent, and should not be thought of as ``really there''. The 59.199 +longer the hook runs, the longer that window is open. 59.200 + 59.201 +\subsection{The problem illustrated} 59.202 + 59.203 +In principle, a good use for the \hook{pretxnchangegroup} hook would 59.204 +be to automatically build and test incoming changes before they are 59.205 +accepted into a central repository. This could let you guarantee that 59.206 +nobody can push changes to this repository that ``break the build''. 59.207 +But if a client can pull changes while they're being tested, the 59.208 +usefulness of the test is zero; an unsuspecting someone can pull 59.209 +untested changes, potentially breaking their build. 59.210 + 59.211 +The safest technological answer to this challenge is to set up such a 59.212 +``gatekeeper'' repository as \emph{unidirectional}. Let it take 59.213 +changes pushed in from the outside, but do not allow anyone to pull 59.214 +changes from it (use the \hook{preoutgoing} hook to lock it down). 59.215 +Configure a \hook{changegroup} hook so that if a build or test 59.216 +succeeds, the hook will push the new changes out to another repository 59.217 +that people \emph{can} pull from. 59.218 + 59.219 +In practice, putting a centralised bottleneck like this in place is 59.220 +not often a good idea, and transaction visibility has nothing to do 59.221 +with the problem. As the size of a project---and the time it takes to 59.222 +build and test---grows, you rapidly run into a wall with this ``try 59.223 +before you buy'' approach, where you have more changesets to test than 59.224 +time in which to deal with them. The inevitable result is frustration 59.225 +on the part of all involved. 59.226 + 59.227 +An approach that scales better is to get people to build and test 59.228 +before they push, then run automated builds and tests centrally 59.229 +\emph{after} a push, to be sure all is well. The advantage of this 59.230 +approach is that it does not impose a limit on the rate at which the 59.231 +repository can accept changes. 59.232 + 59.233 +\section{A short tutorial on using hooks} 59.234 +\label{sec:hook:simple} 59.235 + 59.236 +It is easy to write a Mercurial hook. Let's start with a hook that 59.237 +runs when you finish a \hgcmd{commit}, and simply prints the hash of 59.238 +the changeset you just created. The hook is called \hook{commit}. 59.239 + 59.240 +\begin{figure}[ht] 59.241 + \interaction{hook.simple.init} 59.242 + \caption{A simple hook that runs when a changeset is committed} 59.243 + \label{ex:hook:init} 59.244 +\end{figure} 59.245 + 59.246 +All hooks follow the pattern in example~\ref{ex:hook:init}. You add 59.247 +an entry to the \rcsection{hooks} section of your \hgrc. On the left 59.248 +is the name of the event to trigger on; on the right is the action to 59.249 +take. As you can see, you can run an arbitrary shell command in a 59.250 +hook. Mercurial passes extra information to the hook using 59.251 +environment variables (look for \envar{HG\_NODE} in the example). 59.252 + 59.253 +\subsection{Performing multiple actions per event} 59.254 + 59.255 +Quite often, you will want to define more than one hook for a 59.256 +particular kind of event, as shown in example~\ref{ex:hook:ext}. 59.257 +Mercurial lets you do this by adding an \emph{extension} to the end of 59.258 +a hook's name. You extend a hook's name by giving the name of the 59.259 +hook, followed by a full stop (the ``\texttt{.}'' character), followed 59.260 +by some more text of your choosing. For example, Mercurial will run 59.261 +both \texttt{commit.foo} and \texttt{commit.bar} when the 59.262 +\texttt{commit} event occurs. 59.263 + 59.264 +\begin{figure}[ht] 59.265 + \interaction{hook.simple.ext} 59.266 + \caption{Defining a second \hook{commit} hook} 59.267 + \label{ex:hook:ext} 59.268 +\end{figure} 59.269 + 59.270 +To give a well-defined order of execution when there are multiple 59.271 +hooks defined for an event, Mercurial sorts hooks by extension, and 59.272 +executes the hook commands in this sorted order. In the above 59.273 +example, it will execute \texttt{commit.bar} before 59.274 +\texttt{commit.foo}, and \texttt{commit} before both. 59.275 + 59.276 +It is a good idea to use a somewhat descriptive extension when you 59.277 +define a new hook. This will help you to remember what the hook was 59.278 +for. If the hook fails, you'll get an error message that contains the 59.279 +hook name and extension, so using a descriptive extension could give 59.280 +you an immediate hint as to why the hook failed (see 59.281 +section~\ref{sec:hook:perm} for an example). 59.282 + 59.283 +\subsection{Controlling whether an activity can proceed} 59.284 +\label{sec:hook:perm} 59.285 + 59.286 +In our earlier examples, we used the \hook{commit} hook, which is 59.287 +run after a commit has completed. This is one of several Mercurial 59.288 +hooks that run after an activity finishes. Such hooks have no way of 59.289 +influencing the activity itself. 59.290 + 59.291 +Mercurial defines a number of events that occur before an activity 59.292 +starts; or after it starts, but before it finishes. Hooks that 59.293 +trigger on these events have the added ability to choose whether the 59.294 +activity can continue, or will abort. 59.295 + 59.296 +The \hook{pretxncommit} hook runs after a commit has all but 59.297 +completed. In other words, the metadata representing the changeset 59.298 +has been written out to disk, but the transaction has not yet been 59.299 +allowed to complete. The \hook{pretxncommit} hook has the ability to 59.300 +decide whether the transaction can complete, or must be rolled back. 59.301 + 59.302 +If the \hook{pretxncommit} hook exits with a status code of zero, the 59.303 +transaction is allowed to complete; the commit finishes; and the 59.304 +\hook{commit} hook is run. If the \hook{pretxncommit} hook exits with 59.305 +a non-zero status code, the transaction is rolled back; the metadata 59.306 +representing the changeset is erased; and the \hook{commit} hook is 59.307 +not run. 59.308 + 59.309 +\begin{figure}[ht] 59.310 + \interaction{hook.simple.pretxncommit} 59.311 + \caption{Using the \hook{pretxncommit} hook to control commits} 59.312 + \label{ex:hook:pretxncommit} 59.313 +\end{figure} 59.314 + 59.315 +The hook in example~\ref{ex:hook:pretxncommit} checks that a commit 59.316 +comment contains a bug ID. If it does, the commit can complete. If 59.317 +not, the commit is rolled back. 59.318 + 59.319 +\section{Writing your own hooks} 59.320 + 59.321 +When you are writing a hook, you might find it useful to run Mercurial 59.322 +either with the \hggopt{-v} option, or the \rcitem{ui}{verbose} config 59.323 +item set to ``true''. When you do so, Mercurial will print a message 59.324 +before it calls each hook. 59.325 + 59.326 +\subsection{Choosing how your hook should run} 59.327 +\label{sec:hook:lang} 59.328 + 59.329 +You can write a hook either as a normal program---typically a shell 59.330 +script---or as a Python function that is executed within the Mercurial 59.331 +process. 59.332 + 59.333 +Writing a hook as an external program has the advantage that it 59.334 +requires no knowledge of Mercurial's internals. You can call normal 59.335 +Mercurial commands to get any added information you need. The 59.336 +trade-off is that external hooks are slower than in-process hooks. 59.337 + 59.338 +An in-process Python hook has complete access to the Mercurial API, 59.339 +and does not ``shell out'' to another process, so it is inherently 59.340 +faster than an external hook. It is also easier to obtain much of the 59.341 +information that a hook requires by using the Mercurial API than by 59.342 +running Mercurial commands. 59.343 + 59.344 +If you are comfortable with Python, or require high performance, 59.345 +writing your hooks in Python may be a good choice. However, when you 59.346 +have a straightforward hook to write and you don't need to care about 59.347 +performance (probably the majority of hooks), a shell script is 59.348 +perfectly fine. 59.349 + 59.350 +\subsection{Hook parameters} 59.351 +\label{sec:hook:param} 59.352 + 59.353 +Mercurial calls each hook with a set of well-defined parameters. In 59.354 +Python, a parameter is passed as a keyword argument to your hook 59.355 +function. For an external program, a parameter is passed as an 59.356 +environment variable. 59.357 + 59.358 +Whether your hook is written in Python or as a shell script, the 59.359 +hook-specific parameter names and values will be the same. A boolean 59.360 +parameter will be represented as a boolean value in Python, but as the 59.361 +number 1 (for ``true'') or 0 (for ``false'') as an environment 59.362 +variable for an external hook. If a hook parameter is named 59.363 +\texttt{foo}, the keyword argument for a Python hook will also be 59.364 +named \texttt{foo}, while the environment variable for an external 59.365 +hook will be named \texttt{HG\_FOO}. 59.366 + 59.367 +\subsection{Hook return values and activity control} 59.368 + 59.369 +A hook that executes successfully must exit with a status of zero if 59.370 +external, or return boolean ``false'' if in-process. Failure is 59.371 +indicated with a non-zero exit status from an external hook, or an 59.372 +in-process hook returning boolean ``true''. If an in-process hook 59.373 +raises an exception, the hook is considered to have failed. 59.374 + 59.375 +For a hook that controls whether an activity can proceed, zero/false 59.376 +means ``allow'', while non-zero/true/exception means ``deny''. 59.377 + 59.378 +\subsection{Writing an external hook} 59.379 + 59.380 +When you define an external hook in your \hgrc\ and the hook is run, 59.381 +its value is passed to your shell, which interprets it. This means 59.382 +that you can use normal shell constructs in the body of the hook. 59.383 + 59.384 +An executable hook is always run with its current directory set to a 59.385 +repository's root directory. 59.386 + 59.387 +Each hook parameter is passed in as an environment variable; the name 59.388 +is upper-cased, and prefixed with the string ``\texttt{HG\_}''. 59.389 + 59.390 +With the exception of hook parameters, Mercurial does not set or 59.391 +modify any environment variables when running a hook. This is useful 59.392 +to remember if you are writing a site-wide hook that may be run by a 59.393 +number of different users with differing environment variables set. 59.394 +In multi-user situations, you should not rely on environment variables 59.395 +being set to the values you have in your environment when testing the 59.396 +hook. 59.397 + 59.398 +\subsection{Telling Mercurial to use an in-process hook} 59.399 + 59.400 +The \hgrc\ syntax for defining an in-process hook is slightly 59.401 +different than for an executable hook. The value of the hook must 59.402 +start with the text ``\texttt{python:}'', and continue with the 59.403 +fully-qualified name of a callable object to use as the hook's value. 59.404 + 59.405 +The module in which a hook lives is automatically imported when a hook 59.406 +is run. So long as you have the module name and \envar{PYTHONPATH} 59.407 +right, it should ``just work''. 59.408 + 59.409 +The following \hgrc\ example snippet illustrates the syntax and 59.410 +meaning of the notions we just described. 59.411 +\begin{codesample2} 59.412 + [hooks] 59.413 + commit.example = python:mymodule.submodule.myhook 59.414 +\end{codesample2} 59.415 +When Mercurial runs the \texttt{commit.example} hook, it imports 59.416 +\texttt{mymodule.submodule}, looks for the callable object named 59.417 +\texttt{myhook}, and calls it. 59.418 + 59.419 +\subsection{Writing an in-process hook} 59.420 + 59.421 +The simplest in-process hook does nothing, but illustrates the basic 59.422 +shape of the hook API: 59.423 +\begin{codesample2} 59.424 + def myhook(ui, repo, **kwargs): 59.425 + pass 59.426 +\end{codesample2} 59.427 +The first argument to a Python hook is always a 59.428 +\pymodclass{mercurial.ui}{ui} object. The second is a repository object; 59.429 +at the moment, it is always an instance of 59.430 +\pymodclass{mercurial.localrepo}{localrepository}. Following these two 59.431 +arguments are other keyword arguments. Which ones are passed in 59.432 +depends on the hook being called, but a hook can ignore arguments it 59.433 +doesn't care about by dropping them into a keyword argument dict, as 59.434 +with \texttt{**kwargs} above. 59.435 + 59.436 +\section{Some hook examples} 59.437 + 59.438 +\subsection{Writing meaningful commit messages} 59.439 + 59.440 +It's hard to imagine a useful commit message being very short. The 59.441 +simple \hook{pretxncommit} hook of figure~\ref{ex:hook:msglen.go} 59.442 +will prevent you from committing a changeset with a message that is 59.443 +less than ten bytes long. 59.444 + 59.445 +\begin{figure}[ht] 59.446 + \interaction{hook.msglen.go} 59.447 + \caption{A hook that forbids overly short commit messages} 59.448 + \label{ex:hook:msglen.go} 59.449 +\end{figure} 59.450 + 59.451 +\subsection{Checking for trailing whitespace} 59.452 + 59.453 +An interesting use of a commit-related hook is to help you to write 59.454 +cleaner code. A simple example of ``cleaner code'' is the dictum that 59.455 +a change should not add any new lines of text that contain ``trailing 59.456 +whitespace''. Trailing whitespace is a series of space and tab 59.457 +characters at the end of a line of text. In most cases, trailing 59.458 +whitespace is unnecessary, invisible noise, but it is occasionally 59.459 +problematic, and people often prefer to get rid of it. 59.460 + 59.461 +You can use either the \hook{precommit} or \hook{pretxncommit} hook to 59.462 +tell whether you have a trailing whitespace problem. If you use the 59.463 +\hook{precommit} hook, the hook will not know which files you are 59.464 +committing, so it will have to check every modified file in the 59.465 +repository for trailing white space. If you want to commit a change 59.466 +to just the file \filename{foo}, but the file \filename{bar} contains 59.467 +trailing whitespace, doing a check in the \hook{precommit} hook will 59.468 +prevent you from committing \filename{foo} due to the problem with 59.469 +\filename{bar}. This doesn't seem right. 59.470 + 59.471 +Should you choose the \hook{pretxncommit} hook, the check won't occur 59.472 +until just before the transaction for the commit completes. This will 59.473 +allow you to check for problems only the exact files that are being 59.474 +committed. However, if you entered the commit message interactively 59.475 +and the hook fails, the transaction will roll back; you'll have to 59.476 +re-enter the commit message after you fix the trailing whitespace and 59.477 +run \hgcmd{commit} again. 59.478 + 59.479 +\begin{figure}[ht] 59.480 + \interaction{hook.ws.simple} 59.481 + \caption{A simple hook that checks for trailing whitespace} 59.482 + \label{ex:hook:ws.simple} 59.483 +\end{figure} 59.484 + 59.485 +Figure~\ref{ex:hook:ws.simple} introduces a simple \hook{pretxncommit} 59.486 +hook that checks for trailing whitespace. This hook is short, but not 59.487 +very helpful. It exits with an error status if a change adds a line 59.488 +with trailing whitespace to any file, but does not print any 59.489 +information that might help us to identify the offending file or 59.490 +line. It also has the nice property of not paying attention to 59.491 +unmodified lines; only lines that introduce new trailing whitespace 59.492 +cause problems. 59.493 + 59.494 +\begin{figure}[ht] 59.495 + \interaction{hook.ws.better} 59.496 + \caption{A better trailing whitespace hook} 59.497 + \label{ex:hook:ws.better} 59.498 +\end{figure} 59.499 + 59.500 +The example of figure~\ref{ex:hook:ws.better} is much more complex, 59.501 +but also more useful. It parses a unified diff to see if any lines 59.502 +add trailing whitespace, and prints the name of the file and the line 59.503 +number of each such occurrence. Even better, if the change adds 59.504 +trailing whitespace, this hook saves the commit comment and prints the 59.505 +name of the save file before exiting and telling Mercurial to roll the 59.506 +transaction back, so you can use 59.507 +\hgcmdargs{commit}{\hgopt{commit}{-l}~\emph{filename}} to reuse the 59.508 +saved commit message once you've corrected the problem. 59.509 + 59.510 +As a final aside, note in figure~\ref{ex:hook:ws.better} the use of 59.511 +\command{perl}'s in-place editing feature to get rid of trailing 59.512 +whitespace from a file. This is concise and useful enough that I will 59.513 +reproduce it here. 59.514 +\begin{codesample2} 59.515 + perl -pi -e 's,\textbackslash{}s+\$,,' filename 59.516 +\end{codesample2} 59.517 + 59.518 +\section{Bundled hooks} 59.519 + 59.520 +Mercurial ships with several bundled hooks. You can find them in the 59.521 +\dirname{hgext} directory of a Mercurial source tree. If you are 59.522 +using a Mercurial binary package, the hooks will be located in the 59.523 +\dirname{hgext} directory of wherever your package installer put 59.524 +Mercurial. 59.525 + 59.526 +\subsection{\hgext{acl}---access control for parts of a repository} 59.527 + 59.528 +The \hgext{acl} extension lets you control which remote users are 59.529 +allowed to push changesets to a networked server. You can protect any 59.530 +portion of a repository (including the entire repo), so that a 59.531 +specific remote user can push changes that do not affect the protected 59.532 +portion. 59.533 + 59.534 +This extension implements access control based on the identity of the 59.535 +user performing a push, \emph{not} on who committed the changesets 59.536 +they're pushing. It makes sense to use this hook only if you have a 59.537 +locked-down server environment that authenticates remote users, and 59.538 +you want to be sure that only specific users are allowed to push 59.539 +changes to that server. 59.540 + 59.541 +\subsubsection{Configuring the \hook{acl} hook} 59.542 + 59.543 +In order to manage incoming changesets, the \hgext{acl} hook must be 59.544 +used as a \hook{pretxnchangegroup} hook. This lets it see which files 59.545 +are modified by each incoming changeset, and roll back a group of 59.546 +changesets if they modify ``forbidden'' files. Example: 59.547 +\begin{codesample2} 59.548 + [hooks] 59.549 + pretxnchangegroup.acl = python:hgext.acl.hook 59.550 +\end{codesample2} 59.551 + 59.552 +The \hgext{acl} extension is configured using three sections. 59.553 + 59.554 +The \rcsection{acl} section has only one entry, \rcitem{acl}{sources}, 59.555 +which lists the sources of incoming changesets that the hook should 59.556 +pay attention to. You don't normally need to configure this section. 59.557 +\begin{itemize} 59.558 +\item[\rcitem{acl}{serve}] Control incoming changesets that are arriving 59.559 + from a remote repository over http or ssh. This is the default 59.560 + value of \rcitem{acl}{sources}, and usually the only setting you'll 59.561 + need for this configuration item. 59.562 +\item[\rcitem{acl}{pull}] Control incoming changesets that are 59.563 + arriving via a pull from a local repository. 59.564 +\item[\rcitem{acl}{push}] Control incoming changesets that are 59.565 + arriving via a push from a local repository. 59.566 +\item[\rcitem{acl}{bundle}] Control incoming changesets that are 59.567 + arriving from another repository via a bundle. 59.568 +\end{itemize} 59.569 + 59.570 +The \rcsection{acl.allow} section controls the users that are allowed to 59.571 +add changesets to the repository. If this section is not present, all 59.572 +users that are not explicitly denied are allowed. If this section is 59.573 +present, all users that are not explicitly allowed are denied (so an 59.574 +empty section means that all users are denied). 59.575 + 59.576 +The \rcsection{acl.deny} section determines which users are denied 59.577 +from adding changesets to the repository. If this section is not 59.578 +present or is empty, no users are denied. 59.579 + 59.580 +The syntaxes for the \rcsection{acl.allow} and \rcsection{acl.deny} 59.581 +sections are identical. On the left of each entry is a glob pattern 59.582 +that matches files or directories, relative to the root of the 59.583 +repository; on the right, a user name. 59.584 + 59.585 +In the following example, the user \texttt{docwriter} can only push 59.586 +changes to the \dirname{docs} subtree of the repository, while 59.587 +\texttt{intern} can push changes to any file or directory except 59.588 +\dirname{source/sensitive}. 59.589 +\begin{codesample2} 59.590 + [acl.allow] 59.591 + docs/** = docwriter 59.592 + 59.593 + [acl.deny] 59.594 + source/sensitive/** = intern 59.595 +\end{codesample2} 59.596 + 59.597 +\subsubsection{Testing and troubleshooting} 59.598 + 59.599 +If you want to test the \hgext{acl} hook, run it with Mercurial's 59.600 +debugging output enabled. Since you'll probably be running it on a 59.601 +server where it's not convenient (or sometimes possible) to pass in 59.602 +the \hggopt{--debug} option, don't forget that you can enable 59.603 +debugging output in your \hgrc: 59.604 +\begin{codesample2} 59.605 + [ui] 59.606 + debug = true 59.607 +\end{codesample2} 59.608 +With this enabled, the \hgext{acl} hook will print enough information 59.609 +to let you figure out why it is allowing or forbidding pushes from 59.610 +specific users. 59.611 + 59.612 +\subsection{\hgext{bugzilla}---integration with Bugzilla} 59.613 + 59.614 +The \hgext{bugzilla} extension adds a comment to a Bugzilla bug 59.615 +whenever it finds a reference to that bug ID in a commit comment. You 59.616 +can install this hook on a shared server, so that any time a remote 59.617 +user pushes changes to this server, the hook gets run. 59.618 + 59.619 +It adds a comment to the bug that looks like this (you can configure 59.620 +the contents of the comment---see below): 59.621 +\begin{codesample2} 59.622 + Changeset aad8b264143a, made by Joe User <joe.user@domain.com> in 59.623 + the frobnitz repository, refers to this bug. 59.624 + 59.625 + For complete details, see 59.626 + http://hg.domain.com/frobnitz?cmd=changeset;node=aad8b264143a 59.627 + 59.628 + Changeset description: 59.629 + Fix bug 10483 by guarding against some NULL pointers 59.630 +\end{codesample2} 59.631 +The value of this hook is that it automates the process of updating a 59.632 +bug any time a changeset refers to it. If you configure the hook 59.633 +properly, it makes it easy for people to browse straight from a 59.634 +Bugzilla bug to a changeset that refers to that bug. 59.635 + 59.636 +You can use the code in this hook as a starting point for some more 59.637 +exotic Bugzilla integration recipes. Here are a few possibilities: 59.638 +\begin{itemize} 59.639 +\item Require that every changeset pushed to the server have a valid 59.640 + bug~ID in its commit comment. In this case, you'd want to configure 59.641 + the hook as a \hook{pretxncommit} hook. This would allow the hook 59.642 + to reject changes that didn't contain bug IDs. 59.643 +\item Allow incoming changesets to automatically modify the 59.644 + \emph{state} of a bug, as well as simply adding a comment. For 59.645 + example, the hook could recognise the string ``fixed bug 31337'' as 59.646 + indicating that it should update the state of bug 31337 to 59.647 + ``requires testing''. 59.648 +\end{itemize} 59.649 + 59.650 +\subsubsection{Configuring the \hook{bugzilla} hook} 59.651 +\label{sec:hook:bugzilla:config} 59.652 + 59.653 +You should configure this hook in your server's \hgrc\ as an 59.654 +\hook{incoming} hook, for example as follows: 59.655 +\begin{codesample2} 59.656 + [hooks] 59.657 + incoming.bugzilla = python:hgext.bugzilla.hook 59.658 +\end{codesample2} 59.659 + 59.660 +Because of the specialised nature of this hook, and because Bugzilla 59.661 +was not written with this kind of integration in mind, configuring 59.662 +this hook is a somewhat involved process. 59.663 + 59.664 +Before you begin, you must install the MySQL bindings for Python on 59.665 +the host(s) where you'll be running the hook. If this is not 59.666 +available as a binary package for your system, you can download it 59.667 +from~\cite{web:mysql-python}. 59.668 + 59.669 +Configuration information for this hook lives in the 59.670 +\rcsection{bugzilla} section of your \hgrc. 59.671 +\begin{itemize} 59.672 +\item[\rcitem{bugzilla}{version}] The version of Bugzilla installed on 59.673 + the server. The database schema that Bugzilla uses changes 59.674 + occasionally, so this hook has to know exactly which schema to use. 59.675 + At the moment, the only version supported is \texttt{2.16}. 59.676 +\item[\rcitem{bugzilla}{host}] The hostname of the MySQL server that 59.677 + stores your Bugzilla data. The database must be configured to allow 59.678 + connections from whatever host you are running the \hook{bugzilla} 59.679 + hook on. 59.680 +\item[\rcitem{bugzilla}{user}] The username with which to connect to 59.681 + the MySQL server. The database must be configured to allow this 59.682 + user to connect from whatever host you are running the 59.683 + \hook{bugzilla} hook on. This user must be able to access and 59.684 + modify Bugzilla tables. The default value of this item is 59.685 + \texttt{bugs}, which is the standard name of the Bugzilla user in a 59.686 + MySQL database. 59.687 +\item[\rcitem{bugzilla}{password}] The MySQL password for the user you 59.688 + configured above. This is stored as plain text, so you should make 59.689 + sure that unauthorised users cannot read the \hgrc\ file where you 59.690 + store this information. 59.691 +\item[\rcitem{bugzilla}{db}] The name of the Bugzilla database on the 59.692 + MySQL server. The default value of this item is \texttt{bugs}, 59.693 + which is the standard name of the MySQL database where Bugzilla 59.694 + stores its data. 59.695 +\item[\rcitem{bugzilla}{notify}] If you want Bugzilla to send out a 59.696 + notification email to subscribers after this hook has added a 59.697 + comment to a bug, you will need this hook to run a command whenever 59.698 + it updates the database. The command to run depends on where you 59.699 + have installed Bugzilla, but it will typically look something like 59.700 + this, if you have Bugzilla installed in 59.701 + \dirname{/var/www/html/bugzilla}: 59.702 + \begin{codesample4} 59.703 + cd /var/www/html/bugzilla && ./processmail %s nobody@nowhere.com 59.704 + \end{codesample4} 59.705 + The Bugzilla \texttt{processmail} program expects to be given a 59.706 + bug~ID (the hook replaces ``\texttt{\%s}'' with the bug~ID) and an 59.707 + email address. It also expects to be able to write to some files in 59.708 + the directory that it runs in. If Bugzilla and this hook are not 59.709 + installed on the same machine, you will need to find a way to run 59.710 + \texttt{processmail} on the server where Bugzilla is installed. 59.711 +\end{itemize} 59.712 + 59.713 +\subsubsection{Mapping committer names to Bugzilla user names} 59.714 + 59.715 +By default, the \hgext{bugzilla} hook tries to use the email address 59.716 +of a changeset's committer as the Bugzilla user name with which to 59.717 +update a bug. If this does not suit your needs, you can map committer 59.718 +email addresses to Bugzilla user names using a \rcsection{usermap} 59.719 +section. 59.720 + 59.721 +Each item in the \rcsection{usermap} section contains an email address 59.722 +on the left, and a Bugzilla user name on the right. 59.723 +\begin{codesample2} 59.724 + [usermap] 59.725 + jane.user@example.com = jane 59.726 +\end{codesample2} 59.727 +You can either keep the \rcsection{usermap} data in a normal \hgrc, or 59.728 +tell the \hgext{bugzilla} hook to read the information from an 59.729 +external \filename{usermap} file. In the latter case, you can store 59.730 +\filename{usermap} data by itself in (for example) a user-modifiable 59.731 +repository. This makes it possible to let your users maintain their 59.732 +own \rcitem{bugzilla}{usermap} entries. The main \hgrc\ file might 59.733 +look like this: 59.734 +\begin{codesample2} 59.735 + # regular hgrc file refers to external usermap file 59.736 + [bugzilla] 59.737 + usermap = /home/hg/repos/userdata/bugzilla-usermap.conf 59.738 +\end{codesample2} 59.739 +While the \filename{usermap} file that it refers to might look like 59.740 +this: 59.741 +\begin{codesample2} 59.742 + # bugzilla-usermap.conf - inside a hg repository 59.743 + [usermap] 59.744 + stephanie@example.com = steph 59.745 +\end{codesample2} 59.746 + 59.747 +\subsubsection{Configuring the text that gets added to a bug} 59.748 + 59.749 +You can configure the text that this hook adds as a comment; you 59.750 +specify it in the form of a Mercurial template. Several \hgrc\ 59.751 +entries (still in the \rcsection{bugzilla} section) control this 59.752 +behaviour. 59.753 +\begin{itemize} 59.754 +\item[\texttt{strip}] The number of leading path elements to strip 59.755 + from a repository's path name to construct a partial path for a URL. 59.756 + For example, if the repositories on your server live under 59.757 + \dirname{/home/hg/repos}, and you have a repository whose path is 59.758 + \dirname{/home/hg/repos/app/tests}, then setting \texttt{strip} to 59.759 + \texttt{4} will give a partial path of \dirname{app/tests}. The 59.760 + hook will make this partial path available when expanding a 59.761 + template, as \texttt{webroot}. 59.762 +\item[\texttt{template}] The text of the template to use. In addition 59.763 + to the usual changeset-related variables, this template can use 59.764 + \texttt{hgweb} (the value of the \texttt{hgweb} configuration item 59.765 + above) and \texttt{webroot} (the path constructed using 59.766 + \texttt{strip} above). 59.767 +\end{itemize} 59.768 + 59.769 +In addition, you can add a \rcitem{web}{baseurl} item to the 59.770 +\rcsection{web} section of your \hgrc. The \hgext{bugzilla} hook will 59.771 +make this available when expanding a template, as the base string to 59.772 +use when constructing a URL that will let users browse from a Bugzilla 59.773 +comment to view a changeset. Example: 59.774 +\begin{codesample2} 59.775 + [web] 59.776 + baseurl = http://hg.domain.com/ 59.777 +\end{codesample2} 59.778 + 59.779 +Here is an example set of \hgext{bugzilla} hook config information. 59.780 +\begin{codesample2} 59.781 + [bugzilla] 59.782 + host = bugzilla.example.com 59.783 + password = mypassword 59.784 + version = 2.16 59.785 + # server-side repos live in /home/hg/repos, so strip 4 leading 59.786 + # separators 59.787 + strip = 4 59.788 + hgweb = http://hg.example.com/ 59.789 + usermap = /home/hg/repos/notify/bugzilla.conf 59.790 + template = Changeset \{node|short\}, made by \{author\} in the \{webroot\} 59.791 + repo, refers to this bug.\\nFor complete details, see 59.792 + \{hgweb\}\{webroot\}?cmd=changeset;node=\{node|short\}\\nChangeset 59.793 + description:\\n\\t\{desc|tabindent\} 59.794 +\end{codesample2} 59.795 + 59.796 +\subsubsection{Testing and troubleshooting} 59.797 + 59.798 +The most common problems with configuring the \hgext{bugzilla} hook 59.799 +relate to running Bugzilla's \filename{processmail} script and mapping 59.800 +committer names to user names. 59.801 + 59.802 +Recall from section~\ref{sec:hook:bugzilla:config} above that the user 59.803 +that runs the Mercurial process on the server is also the one that 59.804 +will run the \filename{processmail} script. The 59.805 +\filename{processmail} script sometimes causes Bugzilla to write to 59.806 +files in its configuration directory, and Bugzilla's configuration 59.807 +files are usually owned by the user that your web server runs under. 59.808 + 59.809 +You can cause \filename{processmail} to be run with the suitable 59.810 +user's identity using the \command{sudo} command. Here is an example 59.811 +entry for a \filename{sudoers} file. 59.812 +\begin{codesample2} 59.813 + hg_user = (httpd_user) NOPASSWD: /var/www/html/bugzilla/processmail-wrapper %s 59.814 +\end{codesample2} 59.815 +This allows the \texttt{hg\_user} user to run a 59.816 +\filename{processmail-wrapper} program under the identity of 59.817 +\texttt{httpd\_user}. 59.818 + 59.819 +This indirection through a wrapper script is necessary, because 59.820 +\filename{processmail} expects to be run with its current directory 59.821 +set to wherever you installed Bugzilla; you can't specify that kind of 59.822 +constraint in a \filename{sudoers} file. The contents of the wrapper 59.823 +script are simple: 59.824 +\begin{codesample2} 59.825 + #!/bin/sh 59.826 + cd `dirname $0` && ./processmail "$1" nobody@example.com 59.827 +\end{codesample2} 59.828 +It doesn't seem to matter what email address you pass to 59.829 +\filename{processmail}. 59.830 + 59.831 +If your \rcsection{usermap} is not set up correctly, users will see an 59.832 +error message from the \hgext{bugzilla} hook when they push changes 59.833 +to the server. The error message will look like this: 59.834 +\begin{codesample2} 59.835 + cannot find bugzilla user id for john.q.public@example.com 59.836 +\end{codesample2} 59.837 +What this means is that the committer's address, 59.838 +\texttt{john.q.public@example.com}, is not a valid Bugzilla user name, 59.839 +nor does it have an entry in your \rcsection{usermap} that maps it to 59.840 +a valid Bugzilla user name. 59.841 + 59.842 +\subsection{\hgext{notify}---send email notifications} 59.843 + 59.844 +Although Mercurial's built-in web server provides RSS feeds of changes 59.845 +in every repository, many people prefer to receive change 59.846 +notifications via email. The \hgext{notify} hook lets you send out 59.847 +notifications to a set of email addresses whenever changesets arrive 59.848 +that those subscribers are interested in. 59.849 + 59.850 +As with the \hgext{bugzilla} hook, the \hgext{notify} hook is 59.851 +template-driven, so you can customise the contents of the notification 59.852 +messages that it sends. 59.853 + 59.854 +By default, the \hgext{notify} hook includes a diff of every changeset 59.855 +that it sends out; you can limit the size of the diff, or turn this 59.856 +feature off entirely. It is useful for letting subscribers review 59.857 +changes immediately, rather than clicking to follow a URL. 59.858 + 59.859 +\subsubsection{Configuring the \hgext{notify} hook} 59.860 + 59.861 +You can set up the \hgext{notify} hook to send one email message per 59.862 +incoming changeset, or one per incoming group of changesets (all those 59.863 +that arrived in a single pull or push). 59.864 +\begin{codesample2} 59.865 + [hooks] 59.866 + # send one email per group of changes 59.867 + changegroup.notify = python:hgext.notify.hook 59.868 + # send one email per change 59.869 + incoming.notify = python:hgext.notify.hook 59.870 +\end{codesample2} 59.871 + 59.872 +Configuration information for this hook lives in the 59.873 +\rcsection{notify} section of a \hgrc\ file. 59.874 +\begin{itemize} 59.875 +\item[\rcitem{notify}{test}] By default, this hook does not send out 59.876 + email at all; instead, it prints the message that it \emph{would} 59.877 + send. Set this item to \texttt{false} to allow email to be sent. 59.878 + The reason that sending of email is turned off by default is that it 59.879 + takes several tries to configure this extension exactly as you would 59.880 + like, and it would be bad form to spam subscribers with a number of 59.881 + ``broken'' notifications while you debug your configuration. 59.882 +\item[\rcitem{notify}{config}] The path to a configuration file that 59.883 + contains subscription information. This is kept separate from the 59.884 + main \hgrc\ so that you can maintain it in a repository of its own. 59.885 + People can then clone that repository, update their subscriptions, 59.886 + and push the changes back to your server. 59.887 +\item[\rcitem{notify}{strip}] The number of leading path separator 59.888 + characters to strip from a repository's path, when deciding whether 59.889 + a repository has subscribers. For example, if the repositories on 59.890 + your server live in \dirname{/home/hg/repos}, and \hgext{notify} is 59.891 + considering a repository named \dirname{/home/hg/repos/shared/test}, 59.892 + setting \rcitem{notify}{strip} to \texttt{4} will cause 59.893 + \hgext{notify} to trim the path it considers down to 59.894 + \dirname{shared/test}, and it will match subscribers against that. 59.895 +\item[\rcitem{notify}{template}] The template text to use when sending 59.896 + messages. This specifies both the contents of the message header 59.897 + and its body. 59.898 +\item[\rcitem{notify}{maxdiff}] The maximum number of lines of diff 59.899 + data to append to the end of a message. If a diff is longer than 59.900 + this, it is truncated. By default, this is set to 300. Set this to 59.901 + \texttt{0} to omit diffs from notification emails. 59.902 +\item[\rcitem{notify}{sources}] A list of sources of changesets to 59.903 + consider. This lets you limit \hgext{notify} to only sending out 59.904 + email about changes that remote users pushed into this repository 59.905 + via a server, for example. See section~\ref{sec:hook:sources} for 59.906 + the sources you can specify here. 59.907 +\end{itemize} 59.908 + 59.909 +If you set the \rcitem{web}{baseurl} item in the \rcsection{web} 59.910 +section, you can use it in a template; it will be available as 59.911 +\texttt{webroot}. 59.912 + 59.913 +Here is an example set of \hgext{notify} configuration information. 59.914 +\begin{codesample2} 59.915 + [notify] 59.916 + # really send email 59.917 + test = false 59.918 + # subscriber data lives in the notify repo 59.919 + config = /home/hg/repos/notify/notify.conf 59.920 + # repos live in /home/hg/repos on server, so strip 4 "/" chars 59.921 + strip = 4 59.922 + template = X-Hg-Repo: \{webroot\} 59.923 + Subject: \{webroot\}: \{desc|firstline|strip\} 59.924 + From: \{author\} 59.925 + 59.926 + changeset \{node|short\} in \{root\} 59.927 + details: \{baseurl\}\{webroot\}?cmd=changeset;node=\{node|short\} 59.928 + description: 59.929 + \{desc|tabindent|strip\} 59.930 + 59.931 + [web] 59.932 + baseurl = http://hg.example.com/ 59.933 +\end{codesample2} 59.934 + 59.935 +This will produce a message that looks like the following: 59.936 +\begin{codesample2} 59.937 + X-Hg-Repo: tests/slave 59.938 + Subject: tests/slave: Handle error case when slave has no buffers 59.939 + Date: Wed, 2 Aug 2006 15:25:46 -0700 (PDT) 59.940 + 59.941 + changeset 3cba9bfe74b5 in /home/hg/repos/tests/slave 59.942 + details: http://hg.example.com/tests/slave?cmd=changeset;node=3cba9bfe74b5 59.943 + description: 59.944 + Handle error case when slave has no buffers 59.945 + diffs (54 lines): 59.946 + 59.947 + diff -r 9d95df7cf2ad -r 3cba9bfe74b5 include/tests.h 59.948 + --- a/include/tests.h Wed Aug 02 15:19:52 2006 -0700 59.949 + +++ b/include/tests.h Wed Aug 02 15:25:26 2006 -0700 59.950 + @@ -212,6 +212,15 @@ static __inline__ void test_headers(void *h) 59.951 + [...snip...] 59.952 +\end{codesample2} 59.953 + 59.954 +\subsubsection{Testing and troubleshooting} 59.955 + 59.956 +Do not forget that by default, the \hgext{notify} extension \emph{will 59.957 + not send any mail} until you explicitly configure it to do so, by 59.958 +setting \rcitem{notify}{test} to \texttt{false}. Until you do that, 59.959 +it simply prints the message it \emph{would} send. 59.960 + 59.961 +\section{Information for writers of hooks} 59.962 +\label{sec:hook:ref} 59.963 + 59.964 +\subsection{In-process hook execution} 59.965 + 59.966 +An in-process hook is called with arguments of the following form: 59.967 +\begin{codesample2} 59.968 + def myhook(ui, repo, **kwargs): 59.969 + pass 59.970 +\end{codesample2} 59.971 +The \texttt{ui} parameter is a \pymodclass{mercurial.ui}{ui} object. 59.972 +The \texttt{repo} parameter is a 59.973 +\pymodclass{mercurial.localrepo}{localrepository} object. The 59.974 +names and values of the \texttt{**kwargs} parameters depend on the 59.975 +hook being invoked, with the following common features: 59.976 +\begin{itemize} 59.977 +\item If a parameter is named \texttt{node} or 59.978 + \texttt{parent\emph{N}}, it will contain a hexadecimal changeset ID. 59.979 + The empty string is used to represent ``null changeset ID'' instead 59.980 + of a string of zeroes. 59.981 +\item If a parameter is named \texttt{url}, it will contain the URL of 59.982 + a remote repository, if that can be determined. 59.983 +\item Boolean-valued parameters are represented as Python 59.984 + \texttt{bool} objects. 59.985 +\end{itemize} 59.986 + 59.987 +An in-process hook is called without a change to the process's working 59.988 +directory (unlike external hooks, which are run in the root of the 59.989 +repository). It must not change the process's working directory, or 59.990 +it will cause any calls it makes into the Mercurial API to fail. 59.991 + 59.992 +If a hook returns a boolean ``false'' value, it is considered to have 59.993 +succeeded. If it returns a boolean ``true'' value or raises an 59.994 +exception, it is considered to have failed. A useful way to think of 59.995 +the calling convention is ``tell me if you fail''. 59.996 + 59.997 +Note that changeset IDs are passed into Python hooks as hexadecimal 59.998 +strings, not the binary hashes that Mercurial's APIs normally use. To 59.999 +convert a hash from hex to binary, use the 59.1000 +\pymodfunc{mercurial.node}{bin} function. 59.1001 + 59.1002 +\subsection{External hook execution} 59.1003 + 59.1004 +An external hook is passed to the shell of the user running Mercurial. 59.1005 +Features of that shell, such as variable substitution and command 59.1006 +redirection, are available. The hook is run in the root directory of 59.1007 +the repository (unlike in-process hooks, which are run in the same 59.1008 +directory that Mercurial was run in). 59.1009 + 59.1010 +Hook parameters are passed to the hook as environment variables. Each 59.1011 +environment variable's name is converted in upper case and prefixed 59.1012 +with the string ``\texttt{HG\_}''. For example, if the name of a 59.1013 +parameter is ``\texttt{node}'', the name of the environment variable 59.1014 +representing that parameter will be ``\texttt{HG\_NODE}''. 59.1015 + 59.1016 +A boolean parameter is represented as the string ``\texttt{1}'' for 59.1017 +``true'', ``\texttt{0}'' for ``false''. If an environment variable is 59.1018 +named \envar{HG\_NODE}, \envar{HG\_PARENT1} or \envar{HG\_PARENT2}, it 59.1019 +contains a changeset ID represented as a hexadecimal string. The 59.1020 +empty string is used to represent ``null changeset ID'' instead of a 59.1021 +string of zeroes. If an environment variable is named 59.1022 +\envar{HG\_URL}, it will contain the URL of a remote repository, if 59.1023 +that can be determined. 59.1024 + 59.1025 +If a hook exits with a status of zero, it is considered to have 59.1026 +succeeded. If it exits with a non-zero status, it is considered to 59.1027 +have failed. 59.1028 + 59.1029 +\subsection{Finding out where changesets come from} 59.1030 + 59.1031 +A hook that involves the transfer of changesets between a local 59.1032 +repository and another may be able to find out information about the 59.1033 +``far side''. Mercurial knows \emph{how} changes are being 59.1034 +transferred, and in many cases \emph{where} they are being transferred 59.1035 +to or from. 59.1036 + 59.1037 +\subsubsection{Sources of changesets} 59.1038 +\label{sec:hook:sources} 59.1039 + 59.1040 +Mercurial will tell a hook what means are, or were, used to transfer 59.1041 +changesets between repositories. This is provided by Mercurial in a 59.1042 +Python parameter named \texttt{source}, or an environment variable named 59.1043 +\envar{HG\_SOURCE}. 59.1044 + 59.1045 +\begin{itemize} 59.1046 +\item[\texttt{serve}] Changesets are transferred to or from a remote 59.1047 + repository over http or ssh. 59.1048 +\item[\texttt{pull}] Changesets are being transferred via a pull from 59.1049 + one repository into another. 59.1050 +\item[\texttt{push}] Changesets are being transferred via a push from 59.1051 + one repository into another. 59.1052 +\item[\texttt{bundle}] Changesets are being transferred to or from a 59.1053 + bundle. 59.1054 +\end{itemize} 59.1055 + 59.1056 +\subsubsection{Where changes are going---remote repository URLs} 59.1057 +\label{sec:hook:url} 59.1058 + 59.1059 +When possible, Mercurial will tell a hook the location of the ``far 59.1060 +side'' of an activity that transfers changeset data between 59.1061 +repositories. This is provided by Mercurial in a Python parameter 59.1062 +named \texttt{url}, or an environment variable named \envar{HG\_URL}. 59.1063 + 59.1064 +This information is not always known. If a hook is invoked in a 59.1065 +repository that is being served via http or ssh, Mercurial cannot tell 59.1066 +where the remote repository is, but it may know where the client is 59.1067 +connecting from. In such cases, the URL will take one of the 59.1068 +following forms: 59.1069 +\begin{itemize} 59.1070 +\item \texttt{remote:ssh:\emph{ip-address}}---remote ssh client, at 59.1071 + the given IP address. 59.1072 +\item \texttt{remote:http:\emph{ip-address}}---remote http client, at 59.1073 + the given IP address. If the client is using SSL, this will be of 59.1074 + the form \texttt{remote:https:\emph{ip-address}}. 59.1075 +\item Empty---no information could be discovered about the remote 59.1076 + client. 59.1077 +\end{itemize} 59.1078 + 59.1079 +\section{Hook reference} 59.1080 + 59.1081 +\subsection{\hook{changegroup}---after remote changesets added} 59.1082 +\label{sec:hook:changegroup} 59.1083 + 59.1084 +This hook is run after a group of pre-existing changesets has been 59.1085 +added to the repository, for example via a \hgcmd{pull} or 59.1086 +\hgcmd{unbundle}. This hook is run once per operation that added one 59.1087 +or more changesets. This is in contrast to the \hook{incoming} hook, 59.1088 +which is run once per changeset, regardless of whether the changesets 59.1089 +arrive in a group. 59.1090 + 59.1091 +Some possible uses for this hook include kicking off an automated 59.1092 +build or test of the added changesets, updating a bug database, or 59.1093 +notifying subscribers that a repository contains new changes. 59.1094 + 59.1095 +Parameters to this hook: 59.1096 +\begin{itemize} 59.1097 +\item[\texttt{node}] A changeset ID. The changeset ID of the first 59.1098 + changeset in the group that was added. All changesets between this 59.1099 + and \index{tags!\texttt{tip}}\texttt{tip}, inclusive, were added by 59.1100 + a single \hgcmd{pull}, \hgcmd{push} or \hgcmd{unbundle}. 59.1101 +\item[\texttt{source}] A string. The source of these changes. See 59.1102 + section~\ref{sec:hook:sources} for details. 59.1103 +\item[\texttt{url}] A URL. The location of the remote repository, if 59.1104 + known. See section~\ref{sec:hook:url} for more information. 59.1105 +\end{itemize} 59.1106 + 59.1107 +See also: \hook{incoming} (section~\ref{sec:hook:incoming}), 59.1108 +\hook{prechangegroup} (section~\ref{sec:hook:prechangegroup}), 59.1109 +\hook{pretxnchangegroup} (section~\ref{sec:hook:pretxnchangegroup}) 59.1110 + 59.1111 +\subsection{\hook{commit}---after a new changeset is created} 59.1112 +\label{sec:hook:commit} 59.1113 + 59.1114 +This hook is run after a new changeset has been created. 59.1115 + 59.1116 +Parameters to this hook: 59.1117 +\begin{itemize} 59.1118 +\item[\texttt{node}] A changeset ID. The changeset ID of the newly 59.1119 + committed changeset. 59.1120 +\item[\texttt{parent1}] A changeset ID. The changeset ID of the first 59.1121 + parent of the newly committed changeset. 59.1122 +\item[\texttt{parent2}] A changeset ID. The changeset ID of the second 59.1123 + parent of the newly committed changeset. 59.1124 +\end{itemize} 59.1125 + 59.1126 +See also: \hook{precommit} (section~\ref{sec:hook:precommit}), 59.1127 +\hook{pretxncommit} (section~\ref{sec:hook:pretxncommit}) 59.1128 + 59.1129 +\subsection{\hook{incoming}---after one remote changeset is added} 59.1130 +\label{sec:hook:incoming} 59.1131 + 59.1132 +This hook is run after a pre-existing changeset has been added to the 59.1133 +repository, for example via a \hgcmd{push}. If a group of changesets 59.1134 +was added in a single operation, this hook is called once for each 59.1135 +added changeset. 59.1136 + 59.1137 +You can use this hook for the same purposes as the \hook{changegroup} 59.1138 +hook (section~\ref{sec:hook:changegroup}); it's simply more convenient 59.1139 +sometimes to run a hook once per group of changesets, while other 59.1140 +times it's handier once per changeset. 59.1141 + 59.1142 +Parameters to this hook: 59.1143 +\begin{itemize} 59.1144 +\item[\texttt{node}] A changeset ID. The ID of the newly added 59.1145 + changeset. 59.1146 +\item[\texttt{source}] A string. The source of these changes. See 59.1147 + section~\ref{sec:hook:sources} for details. 59.1148 +\item[\texttt{url}] A URL. The location of the remote repository, if 59.1149 + known. See section~\ref{sec:hook:url} for more information. 59.1150 +\end{itemize} 59.1151 + 59.1152 +See also: \hook{changegroup} (section~\ref{sec:hook:changegroup}) \hook{prechangegroup} (section~\ref{sec:hook:prechangegroup}), \hook{pretxnchangegroup} (section~\ref{sec:hook:pretxnchangegroup}) 59.1153 + 59.1154 +\subsection{\hook{outgoing}---after changesets are propagated} 59.1155 +\label{sec:hook:outgoing} 59.1156 + 59.1157 +This hook is run after a group of changesets has been propagated out 59.1158 +of this repository, for example by a \hgcmd{push} or \hgcmd{bundle} 59.1159 +command. 59.1160 + 59.1161 +One possible use for this hook is to notify administrators that 59.1162 +changes have been pulled. 59.1163 + 59.1164 +Parameters to this hook: 59.1165 +\begin{itemize} 59.1166 +\item[\texttt{node}] A changeset ID. The changeset ID of the first 59.1167 + changeset of the group that was sent. 59.1168 +\item[\texttt{source}] A string. The source of the of the operation 59.1169 + (see section~\ref{sec:hook:sources}). If a remote client pulled 59.1170 + changes from this repository, \texttt{source} will be 59.1171 + \texttt{serve}. If the client that obtained changes from this 59.1172 + repository was local, \texttt{source} will be \texttt{bundle}, 59.1173 + \texttt{pull}, or \texttt{push}, depending on the operation the 59.1174 + client performed. 59.1175 +\item[\texttt{url}] A URL. The location of the remote repository, if 59.1176 + known. See section~\ref{sec:hook:url} for more information. 59.1177 +\end{itemize} 59.1178 + 59.1179 +See also: \hook{preoutgoing} (section~\ref{sec:hook:preoutgoing}) 59.1180 + 59.1181 +\subsection{\hook{prechangegroup}---before starting to add remote changesets} 59.1182 +\label{sec:hook:prechangegroup} 59.1183 + 59.1184 +This controlling hook is run before Mercurial begins to add a group of 59.1185 +changesets from another repository. 59.1186 + 59.1187 +This hook does not have any information about the changesets to be 59.1188 +added, because it is run before transmission of those changesets is 59.1189 +allowed to begin. If this hook fails, the changesets will not be 59.1190 +transmitted. 59.1191 + 59.1192 +One use for this hook is to prevent external changes from being added 59.1193 +to a repository. For example, you could use this to ``freeze'' a 59.1194 +server-hosted branch temporarily or permanently so that users cannot 59.1195 +push to it, while still allowing a local administrator to modify the 59.1196 +repository. 59.1197 + 59.1198 +Parameters to this hook: 59.1199 +\begin{itemize} 59.1200 +\item[\texttt{source}] A string. The source of these changes. See 59.1201 + section~\ref{sec:hook:sources} for details. 59.1202 +\item[\texttt{url}] A URL. The location of the remote repository, if 59.1203 + known. See section~\ref{sec:hook:url} for more information. 59.1204 +\end{itemize} 59.1205 + 59.1206 +See also: \hook{changegroup} (section~\ref{sec:hook:changegroup}), 59.1207 +\hook{incoming} (section~\ref{sec:hook:incoming}), , 59.1208 +\hook{pretxnchangegroup} (section~\ref{sec:hook:pretxnchangegroup}) 59.1209 + 59.1210 +\subsection{\hook{precommit}---before starting to commit a changeset} 59.1211 +\label{sec:hook:precommit} 59.1212 + 59.1213 +This hook is run before Mercurial begins to commit a new changeset. 59.1214 +It is run before Mercurial has any of the metadata for the commit, 59.1215 +such as the files to be committed, the commit message, or the commit 59.1216 +date. 59.1217 + 59.1218 +One use for this hook is to disable the ability to commit new 59.1219 +changesets, while still allowing incoming changesets. Another is to 59.1220 +run a build or test, and only allow the commit to begin if the build 59.1221 +or test succeeds. 59.1222 + 59.1223 +Parameters to this hook: 59.1224 +\begin{itemize} 59.1225 +\item[\texttt{parent1}] A changeset ID. The changeset ID of the first 59.1226 + parent of the working directory. 59.1227 +\item[\texttt{parent2}] A changeset ID. The changeset ID of the second 59.1228 + parent of the working directory. 59.1229 +\end{itemize} 59.1230 +If the commit proceeds, the parents of the working directory will 59.1231 +become the parents of the new changeset. 59.1232 + 59.1233 +See also: \hook{commit} (section~\ref{sec:hook:commit}), 59.1234 +\hook{pretxncommit} (section~\ref{sec:hook:pretxncommit}) 59.1235 + 59.1236 +\subsection{\hook{preoutgoing}---before starting to propagate changesets} 59.1237 +\label{sec:hook:preoutgoing} 59.1238 + 59.1239 +This hook is invoked before Mercurial knows the identities of the 59.1240 +changesets to be transmitted. 59.1241 + 59.1242 +One use for this hook is to prevent changes from being transmitted to 59.1243 +another repository. 59.1244 + 59.1245 +Parameters to this hook: 59.1246 +\begin{itemize} 59.1247 +\item[\texttt{source}] A string. The source of the operation that is 59.1248 + attempting to obtain changes from this repository (see 59.1249 + section~\ref{sec:hook:sources}). See the documentation for the 59.1250 + \texttt{source} parameter to the \hook{outgoing} hook, in 59.1251 + section~\ref{sec:hook:outgoing}, for possible values of this 59.1252 + parameter. 59.1253 +\item[\texttt{url}] A URL. The location of the remote repository, if 59.1254 + known. See section~\ref{sec:hook:url} for more information. 59.1255 +\end{itemize} 59.1256 + 59.1257 +See also: \hook{outgoing} (section~\ref{sec:hook:outgoing}) 59.1258 + 59.1259 +\subsection{\hook{pretag}---before tagging a changeset} 59.1260 +\label{sec:hook:pretag} 59.1261 + 59.1262 +This controlling hook is run before a tag is created. If the hook 59.1263 +succeeds, creation of the tag proceeds. If the hook fails, the tag is 59.1264 +not created. 59.1265 + 59.1266 +Parameters to this hook: 59.1267 +\begin{itemize} 59.1268 +\item[\texttt{local}] A boolean. Whether the tag is local to this 59.1269 + repository instance (i.e.~stored in \sfilename{.hg/localtags}) or 59.1270 + managed by Mercurial (stored in \sfilename{.hgtags}). 59.1271 +\item[\texttt{node}] A changeset ID. The ID of the changeset to be tagged. 59.1272 +\item[\texttt{tag}] A string. The name of the tag to be created. 59.1273 +\end{itemize} 59.1274 + 59.1275 +If the tag to be created is revision-controlled, the \hook{precommit} 59.1276 +and \hook{pretxncommit} hooks (sections~\ref{sec:hook:commit} 59.1277 +and~\ref{sec:hook:pretxncommit}) will also be run. 59.1278 + 59.1279 +See also: \hook{tag} (section~\ref{sec:hook:tag}) 59.1280 + 59.1281 +\subsection{\hook{pretxnchangegroup}---before completing addition of 59.1282 + remote changesets} 59.1283 +\label{sec:hook:pretxnchangegroup} 59.1284 + 59.1285 +This controlling hook is run before a transaction---that manages the 59.1286 +addition of a group of new changesets from outside the 59.1287 +repository---completes. If the hook succeeds, the transaction 59.1288 +completes, and all of the changesets become permanent within this 59.1289 +repository. If the hook fails, the transaction is rolled back, and 59.1290 +the data for the changesets is erased. 59.1291 + 59.1292 +This hook can access the metadata associated with the almost-added 59.1293 +changesets, but it should not do anything permanent with this data. 59.1294 +It must also not modify the working directory. 59.1295 + 59.1296 +While this hook is running, if other Mercurial processes access this 59.1297 +repository, they will be able to see the almost-added changesets as if 59.1298 +they are permanent. This may lead to race conditions if you do not 59.1299 +take steps to avoid them. 59.1300 + 59.1301 +This hook can be used to automatically vet a group of changesets. If 59.1302 +the hook fails, all of the changesets are ``rejected'' when the 59.1303 +transaction rolls back. 59.1304 + 59.1305 +Parameters to this hook: 59.1306 +\begin{itemize} 59.1307 +\item[\texttt{node}] A changeset ID. The changeset ID of the first 59.1308 + changeset in the group that was added. All changesets between this 59.1309 + and \index{tags!\texttt{tip}}\texttt{tip}, inclusive, were added by 59.1310 + a single \hgcmd{pull}, \hgcmd{push} or \hgcmd{unbundle}. 59.1311 +\item[\texttt{source}] A string. The source of these changes. See 59.1312 + section~\ref{sec:hook:sources} for details. 59.1313 +\item[\texttt{url}] A URL. The location of the remote repository, if 59.1314 + known. See section~\ref{sec:hook:url} for more information. 59.1315 +\end{itemize} 59.1316 + 59.1317 +See also: \hook{changegroup} (section~\ref{sec:hook:changegroup}), 59.1318 +\hook{incoming} (section~\ref{sec:hook:incoming}), 59.1319 +\hook{prechangegroup} (section~\ref{sec:hook:prechangegroup}) 59.1320 + 59.1321 +\subsection{\hook{pretxncommit}---before completing commit of new changeset} 59.1322 +\label{sec:hook:pretxncommit} 59.1323 + 59.1324 +This controlling hook is run before a transaction---that manages a new 59.1325 +commit---completes. If the hook succeeds, the transaction completes 59.1326 +and the changeset becomes permanent within this repository. If the 59.1327 +hook fails, the transaction is rolled back, and the commit data is 59.1328 +erased. 59.1329 + 59.1330 +This hook can access the metadata associated with the almost-new 59.1331 +changeset, but it should not do anything permanent with this data. It 59.1332 +must also not modify the working directory. 59.1333 + 59.1334 +While this hook is running, if other Mercurial processes access this 59.1335 +repository, they will be able to see the almost-new changeset as if it 59.1336 +is permanent. This may lead to race conditions if you do not take 59.1337 +steps to avoid them. 59.1338 + 59.1339 +Parameters to this hook: 59.1340 +\begin{itemize} 59.1341 +\item[\texttt{node}] A changeset ID. The changeset ID of the newly 59.1342 + committed changeset. 59.1343 +\item[\texttt{parent1}] A changeset ID. The changeset ID of the first 59.1344 + parent of the newly committed changeset. 59.1345 +\item[\texttt{parent2}] A changeset ID. The changeset ID of the second 59.1346 + parent of the newly committed changeset. 59.1347 +\end{itemize} 59.1348 + 59.1349 +See also: \hook{precommit} (section~\ref{sec:hook:precommit}) 59.1350 + 59.1351 +\subsection{\hook{preupdate}---before updating or merging working directory} 59.1352 +\label{sec:hook:preupdate} 59.1353 + 59.1354 +This controlling hook is run before an update or merge of the working 59.1355 +directory begins. It is run only if Mercurial's normal pre-update 59.1356 +checks determine that the update or merge can proceed. If the hook 59.1357 +succeeds, the update or merge may proceed; if it fails, the update or 59.1358 +merge does not start. 59.1359 + 59.1360 +Parameters to this hook: 59.1361 +\begin{itemize} 59.1362 +\item[\texttt{parent1}] A changeset ID. The ID of the parent that the 59.1363 + working directory is to be updated to. If the working directory is 59.1364 + being merged, it will not change this parent. 59.1365 +\item[\texttt{parent2}] A changeset ID. Only set if the working 59.1366 + directory is being merged. The ID of the revision that the working 59.1367 + directory is being merged with. 59.1368 +\end{itemize} 59.1369 + 59.1370 +See also: \hook{update} (section~\ref{sec:hook:update}) 59.1371 + 59.1372 +\subsection{\hook{tag}---after tagging a changeset} 59.1373 +\label{sec:hook:tag} 59.1374 + 59.1375 +This hook is run after a tag has been created. 59.1376 + 59.1377 +Parameters to this hook: 59.1378 +\begin{itemize} 59.1379 +\item[\texttt{local}] A boolean. Whether the new tag is local to this 59.1380 + repository instance (i.e.~stored in \sfilename{.hg/localtags}) or 59.1381 + managed by Mercurial (stored in \sfilename{.hgtags}). 59.1382 +\item[\texttt{node}] A changeset ID. The ID of the changeset that was 59.1383 + tagged. 59.1384 +\item[\texttt{tag}] A string. The name of the tag that was created. 59.1385 +\end{itemize} 59.1386 + 59.1387 +If the created tag is revision-controlled, the \hook{commit} hook 59.1388 +(section~\ref{sec:hook:commit}) is run before this hook. 59.1389 + 59.1390 +See also: \hook{pretag} (section~\ref{sec:hook:pretag}) 59.1391 + 59.1392 +\subsection{\hook{update}---after updating or merging working directory} 59.1393 +\label{sec:hook:update} 59.1394 + 59.1395 +This hook is run after an update or merge of the working directory 59.1396 +completes. Since a merge can fail (if the external \command{hgmerge} 59.1397 +command fails to resolve conflicts in a file), this hook communicates 59.1398 +whether the update or merge completed cleanly. 59.1399 + 59.1400 +\begin{itemize} 59.1401 +\item[\texttt{error}] A boolean. Indicates whether the update or 59.1402 + merge completed successfully. 59.1403 +\item[\texttt{parent1}] A changeset ID. The ID of the parent that the 59.1404 + working directory was updated to. If the working directory was 59.1405 + merged, it will not have changed this parent. 59.1406 +\item[\texttt{parent2}] A changeset ID. Only set if the working 59.1407 + directory was merged. The ID of the revision that the working 59.1408 + directory was merged with. 59.1409 +\end{itemize} 59.1410 + 59.1411 +See also: \hook{preupdate} (section~\ref{sec:hook:preupdate}) 59.1412 + 59.1413 +%%% Local Variables: 59.1414 +%%% mode: latex 59.1415 +%%% TeX-master: "00book" 59.1416 +%%% End:
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 60.2 +++ b/fr/htlatex.book Thu Feb 05 12:37:03 2009 +0100 60.3 @@ -0,0 +1,12 @@ 60.4 +#!/bin/bash 60.5 +# 60.6 +# This script is horrible. It's essentially a hacked copy of 60.7 +# /usr/bin/htlatex from Fedora Core 6. I apologise for any lasting 60.8 +# pain reading it causes. 60.9 + 60.10 +latex $5 '\makeatletter\def\HCode{\futurelet\HCode\HChar}\def\HChar{\ifx"\HCode\def\HCode"##1"{\Link##1}\expandafter\HCode\else\expandafter\Link\fi}\def\Link#1.a.b.c.{\g@addto@macro\@documentclasshook{\RequirePackage[#1,html]{tex4ht}}\let\HCode\documentstyle\def\documentstyle{\let\documentstyle\HCode\expandafter\def\csname tex4ht\endcsname{#1,html}\def\HCode####1{\documentstyle[tex4ht,}\@ifnextchar[{\HCode}{\documentstyle[tex4ht]}}}\makeatother\HCode '$2'.a.b.c.\input ' $1 60.11 +(cd $4 && bibtex hgbook) 60.12 +(cd $4 && makeindex hgbook) 60.13 +latex $5 '\makeatletter\def\HCode{\futurelet\HCode\HChar}\def\HChar{\ifx"\HCode\def\HCode"##1"{\Link##1}\expandafter\HCode\else\expandafter\Link\fi}\def\Link#1.a.b.c.{\g@addto@macro\@documentclasshook{\RequirePackage[#1,html]{tex4ht}}\let\HCode\documentstyle\def\documentstyle{\let\documentstyle\HCode\expandafter\def\csname tex4ht\endcsname{#1,html}\def\HCode####1{\documentstyle[tex4ht,}\@ifnextchar[{\HCode}{\documentstyle[tex4ht]}}}\makeatother\HCode '$2'.a.b.c.\input ' $1 60.14 +latex $5 '\makeatletter\def\HCode{\futurelet\HCode\HChar}\def\HChar{\ifx"\HCode\def\HCode"##1"{\Link##1}\expandafter\HCode\else\expandafter\Link\fi}\def\Link#1.a.b.c.{\g@addto@macro\@documentclasshook{\RequirePackage[#1,html]{tex4ht}}\let\HCode\documentstyle\def\documentstyle{\let\documentstyle\HCode\expandafter\def\csname tex4ht\endcsname{#1,html}\def\HCode####1{\documentstyle[tex4ht,}\@ifnextchar[{\HCode}{\documentstyle[tex4ht]}}}\makeatother\HCode '$2'.a.b.c.\input ' $1 60.15 +echo status $$
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 61.2 +++ b/fr/intro.tex Thu Feb 05 12:37:03 2009 +0100 61.3 @@ -0,0 +1,561 @@ 61.4 +\chapter{Introduction} 61.5 +\label{chap:intro} 61.6 + 61.7 +\section{About revision control} 61.8 + 61.9 +Revision control is the process of managing multiple versions of a 61.10 +piece of information. In its simplest form, this is something that 61.11 +many people do by hand: every time you modify a file, save it under a 61.12 +new name that contains a number, each one higher than the number of 61.13 +the preceding version. 61.14 + 61.15 +Manually managing multiple versions of even a single file is an 61.16 +error-prone task, though, so software tools to help automate this 61.17 +process have long been available. The earliest automated revision 61.18 +control tools were intended to help a single user to manage revisions 61.19 +of a single file. Over the past few decades, the scope of revision 61.20 +control tools has expanded greatly; they now manage multiple files, 61.21 +and help multiple people to work together. The best modern revision 61.22 +control tools have no problem coping with thousands of people working 61.23 +together on projects that consist of hundreds of thousands of files. 61.24 + 61.25 +\subsection{Why use revision control?} 61.26 + 61.27 +There are a number of reasons why you or your team might want to use 61.28 +an automated revision control tool for a project. 61.29 +\begin{itemize} 61.30 +\item It will track the history and evolution of your project, so you 61.31 + don't have to. For every change, you'll have a log of \emph{who} 61.32 + made it; \emph{why} they made it; \emph{when} they made it; and 61.33 + \emph{what} the change was. 61.34 +\item When you're working with other people, revision control software 61.35 + makes it easier for you to collaborate. For example, when people 61.36 + more or less simultaneously make potentially incompatible changes, 61.37 + the software will help you to identify and resolve those conflicts. 61.38 +\item It can help you to recover from mistakes. If you make a change 61.39 + that later turns out to be in error, you can revert to an earlier 61.40 + version of one or more files. In fact, a \emph{really} good 61.41 + revision control tool will even help you to efficiently figure out 61.42 + exactly when a problem was introduced (see 61.43 + section~\ref{sec:undo:bisect} for details). 61.44 +\item It will help you to work simultaneously on, and manage the drift 61.45 + between, multiple versions of your project. 61.46 +\end{itemize} 61.47 +Most of these reasons are equally valid---at least in theory---whether 61.48 +you're working on a project by yourself, or with a hundred other 61.49 +people. 61.50 + 61.51 +A key question about the practicality of revision control at these two 61.52 +different scales (``lone hacker'' and ``huge team'') is how its 61.53 +\emph{benefits} compare to its \emph{costs}. A revision control tool 61.54 +that's difficult to understand or use is going to impose a high cost. 61.55 + 61.56 +A five-hundred-person project is likely to collapse under its own 61.57 +weight almost immediately without a revision control tool and process. 61.58 +In this case, the cost of using revision control might hardly seem 61.59 +worth considering, since \emph{without} it, failure is almost 61.60 +guaranteed. 61.61 + 61.62 +On the other hand, a one-person ``quick hack'' might seem like a poor 61.63 +place to use a revision control tool, because surely the cost of using 61.64 +one must be close to the overall cost of the project. Right? 61.65 + 61.66 +Mercurial uniquely supports \emph{both} of these scales of 61.67 +development. You can learn the basics in just a few minutes, and due 61.68 +to its low overhead, you can apply revision control to the smallest of 61.69 +projects with ease. Its simplicity means you won't have a lot of 61.70 +abstruse concepts or command sequences competing for mental space with 61.71 +whatever you're \emph{really} trying to do. At the same time, 61.72 +Mercurial's high performance and peer-to-peer nature let you scale 61.73 +painlessly to handle large projects. 61.74 + 61.75 +No revision control tool can rescue a poorly run project, but a good 61.76 +choice of tools can make a huge difference to the fluidity with which 61.77 +you can work on a project. 61.78 + 61.79 +\subsection{The many names of revision control} 61.80 + 61.81 +Revision control is a diverse field, so much so that it doesn't 61.82 +actually have a single name or acronym. Here are a few of the more 61.83 +common names and acronyms you'll encounter: 61.84 +\begin{itemize} 61.85 +\item Revision control (RCS) 61.86 +\item Software configuration management (SCM), or configuration management 61.87 +\item Source code management 61.88 +\item Source code control, or source control 61.89 +\item Version control (VCS) 61.90 +\end{itemize} 61.91 +Some people claim that these terms actually have different meanings, 61.92 +but in practice they overlap so much that there's no agreed or even 61.93 +useful way to tease them apart. 61.94 + 61.95 +\section{A short history of revision control} 61.96 + 61.97 +The best known of the old-time revision control tools is SCCS (Source 61.98 +Code Control System), which Marc Rochkind wrote at Bell Labs, in the 61.99 +early 1970s. SCCS operated on individual files, and required every 61.100 +person working on a project to have access to a shared workspace on a 61.101 +single system. Only one person could modify a file at any time; 61.102 +arbitration for access to files was via locks. It was common for 61.103 +people to lock files, and later forget to unlock them, preventing 61.104 +anyone else from modifying those files without the help of an 61.105 +administrator. 61.106 + 61.107 +Walter Tichy developed a free alternative to SCCS in the early 1980s; 61.108 +he called his program RCS (Revison Control System). Like SCCS, RCS 61.109 +required developers to work in a single shared workspace, and to lock 61.110 +files to prevent multiple people from modifying them simultaneously. 61.111 + 61.112 +Later in the 1980s, Dick Grune used RCS as a building block for a set 61.113 +of shell scripts he initially called cmt, but then renamed to CVS 61.114 +(Concurrent Versions System). The big innovation of CVS was that it 61.115 +let developers work simultaneously and somewhat independently in their 61.116 +own personal workspaces. The personal workspaces prevented developers 61.117 +from stepping on each other's toes all the time, as was common with 61.118 +SCCS and RCS. Each developer had a copy of every project file, and 61.119 +could modify their copies independently. They had to merge their 61.120 +edits prior to committing changes to the central repository. 61.121 + 61.122 +Brian Berliner took Grune's original scripts and rewrote them in~C, 61.123 +releasing in 1989 the code that has since developed into the modern 61.124 +version of CVS. CVS subsequently acquired the ability to operate over 61.125 +a network connection, giving it a client/server architecture. CVS's 61.126 +architecture is centralised; only the server has a copy of the history 61.127 +of the project. Client workspaces just contain copies of recent 61.128 +versions of the project's files, and a little metadata to tell them 61.129 +where the server is. CVS has been enormously successful; it is 61.130 +probably the world's most widely used revision control system. 61.131 + 61.132 +In the early 1990s, Sun Microsystems developed an early distributed 61.133 +revision control system, called TeamWare. A TeamWare workspace 61.134 +contains a complete copy of the project's history. TeamWare has no 61.135 +notion of a central repository. (CVS relied upon RCS for its history 61.136 +storage; TeamWare used SCCS.) 61.137 + 61.138 +As the 1990s progressed, awareness grew of a number of problems with 61.139 +CVS. It records simultaneous changes to multiple files individually, 61.140 +instead of grouping them together as a single logically atomic 61.141 +operation. It does not manage its file hierarchy well; it is easy to 61.142 +make a mess of a repository by renaming files and directories. Worse, 61.143 +its source code is difficult to read and maintain, which made the 61.144 +``pain level'' of fixing these architectural problems prohibitive. 61.145 + 61.146 +In 2001, Jim Blandy and Karl Fogel, two developers who had worked on 61.147 +CVS, started a project to replace it with a tool that would have a 61.148 +better architecture and cleaner code. The result, Subversion, does 61.149 +not stray from CVS's centralised client/server model, but it adds 61.150 +multi-file atomic commits, better namespace management, and a number 61.151 +of other features that make it a generally better tool than CVS. 61.152 +Since its initial release, it has rapidly grown in popularity. 61.153 + 61.154 +More or less simultaneously, Graydon Hoare began working on an 61.155 +ambitious distributed revision control system that he named Monotone. 61.156 +While Monotone addresses many of CVS's design flaws and has a 61.157 +peer-to-peer architecture, it goes beyond earlier (and subsequent) 61.158 +revision control tools in a number of innovative ways. It uses 61.159 +cryptographic hashes as identifiers, and has an integral notion of 61.160 +``trust'' for code from different sources. 61.161 + 61.162 +Mercurial began life in 2005. While a few aspects of its design are 61.163 +influenced by Monotone, Mercurial focuses on ease of use, high 61.164 +performance, and scalability to very large projects. 61.165 + 61.166 +\section{Trends in revision control} 61.167 + 61.168 +There has been an unmistakable trend in the development and use of 61.169 +revision control tools over the past four decades, as people have 61.170 +become familiar with the capabilities of their tools and constrained 61.171 +by their limitations. 61.172 + 61.173 +The first generation began by managing single files on individual 61.174 +computers. Although these tools represented a huge advance over 61.175 +ad-hoc manual revision control, their locking model and reliance on a 61.176 +single computer limited them to small, tightly-knit teams. 61.177 + 61.178 +The second generation loosened these constraints by moving to 61.179 +network-centered architectures, and managing entire projects at a 61.180 +time. As projects grew larger, they ran into new problems. With 61.181 +clients needing to talk to servers very frequently, server scaling 61.182 +became an issue for large projects. An unreliable network connection 61.183 +could prevent remote users from being able to talk to the server at 61.184 +all. As open source projects started making read-only access 61.185 +available anonymously to anyone, people without commit privileges 61.186 +found that they could not use the tools to interact with a project in 61.187 +a natural way, as they could not record their changes. 61.188 + 61.189 +The current generation of revision control tools is peer-to-peer in 61.190 +nature. All of these systems have dropped the dependency on a single 61.191 +central server, and allow people to distribute their revision control 61.192 +data to where it's actually needed. Collaboration over the Internet 61.193 +has moved from constrained by technology to a matter of choice and 61.194 +consensus. Modern tools can operate offline indefinitely and 61.195 +autonomously, with a network connection only needed when syncing 61.196 +changes with another repository. 61.197 + 61.198 +\section{A few of the advantages of distributed revision control} 61.199 + 61.200 +Even though distributed revision control tools have for several years 61.201 +been as robust and usable as their previous-generation counterparts, 61.202 +people using older tools have not yet necessarily woken up to their 61.203 +advantages. There are a number of ways in which distributed tools 61.204 +shine relative to centralised ones. 61.205 + 61.206 +For an individual developer, distributed tools are almost always much 61.207 +faster than centralised tools. This is for a simple reason: a 61.208 +centralised tool needs to talk over the network for many common 61.209 +operations, because most metadata is stored in a single copy on the 61.210 +central server. A distributed tool stores all of its metadata 61.211 +locally. All else being equal, talking over the network adds overhead 61.212 +to a centralised tool. Don't underestimate the value of a snappy, 61.213 +responsive tool: you're going to spend a lot of time interacting with 61.214 +your revision control software. 61.215 + 61.216 +Distributed tools are indifferent to the vagaries of your server 61.217 +infrastructure, again because they replicate metadata to so many 61.218 +locations. If you use a centralised system and your server catches 61.219 +fire, you'd better hope that your backup media are reliable, and that 61.220 +your last backup was recent and actually worked. With a distributed 61.221 +tool, you have many backups available on every contributor's computer. 61.222 + 61.223 +The reliability of your network will affect distributed tools far less 61.224 +than it will centralised tools. You can't even use a centralised tool 61.225 +without a network connection, except for a few highly constrained 61.226 +commands. With a distributed tool, if your network connection goes 61.227 +down while you're working, you may not even notice. The only thing 61.228 +you won't be able to do is talk to repositories on other computers, 61.229 +something that is relatively rare compared with local operations. If 61.230 +you have a far-flung team of collaborators, this may be significant. 61.231 + 61.232 +\subsection{Advantages for open source projects} 61.233 + 61.234 +If you take a shine to an open source project and decide that you 61.235 +would like to start hacking on it, and that project uses a distributed 61.236 +revision control tool, you are at once a peer with the people who 61.237 +consider themselves the ``core'' of that project. If they publish 61.238 +their repositories, you can immediately copy their project history, 61.239 +start making changes, and record your work, using the same tools in 61.240 +the same ways as insiders. By contrast, with a centralised tool, you 61.241 +must use the software in a ``read only'' mode unless someone grants 61.242 +you permission to commit changes to their central server. Until then, 61.243 +you won't be able to record changes, and your local modifications will 61.244 +be at risk of corruption any time you try to update your client's view 61.245 +of the repository. 61.246 + 61.247 +\subsubsection{The forking non-problem} 61.248 + 61.249 +It has been suggested that distributed revision control tools pose 61.250 +some sort of risk to open source projects because they make it easy to 61.251 +``fork'' the development of a project. A fork happens when there are 61.252 +differences in opinion or attitude between groups of developers that 61.253 +cause them to decide that they can't work together any longer. Each 61.254 +side takes a more or less complete copy of the project's source code, 61.255 +and goes off in its own direction. 61.256 + 61.257 +Sometimes the camps in a fork decide to reconcile their differences. 61.258 +With a centralised revision control system, the \emph{technical} 61.259 +process of reconciliation is painful, and has to be performed largely 61.260 +by hand. You have to decide whose revision history is going to 61.261 +``win'', and graft the other team's changes into the tree somehow. 61.262 +This usually loses some or all of one side's revision history. 61.263 + 61.264 +What distributed tools do with respect to forking is they make forking 61.265 +the \emph{only} way to develop a project. Every single change that 61.266 +you make is potentially a fork point. The great strength of this 61.267 +approach is that a distributed revision control tool has to be really 61.268 +good at \emph{merging} forks, because forks are absolutely 61.269 +fundamental: they happen all the time. 61.270 + 61.271 +If every piece of work that everybody does, all the time, is framed in 61.272 +terms of forking and merging, then what the open source world refers 61.273 +to as a ``fork'' becomes \emph{purely} a social issue. If anything, 61.274 +distributed tools \emph{lower} the likelihood of a fork: 61.275 +\begin{itemize} 61.276 +\item They eliminate the social distinction that centralised tools 61.277 + impose: that between insiders (people with commit access) and 61.278 + outsiders (people without). 61.279 +\item They make it easier to reconcile after a social fork, because 61.280 + all that's involved from the perspective of the revision control 61.281 + software is just another merge. 61.282 +\end{itemize} 61.283 + 61.284 +Some people resist distributed tools because they want to retain tight 61.285 +control over their projects, and they believe that centralised tools 61.286 +give them this control. However, if you're of this belief, and you 61.287 +publish your CVS or Subversion repositories publically, there are 61.288 +plenty of tools available that can pull out your entire project's 61.289 +history (albeit slowly) and recreate it somewhere that you don't 61.290 +control. So while your control in this case is illusory, you are 61.291 +forgoing the ability to fluidly collaborate with whatever people feel 61.292 +compelled to mirror and fork your history. 61.293 + 61.294 +\subsection{Advantages for commercial projects} 61.295 + 61.296 +Many commercial projects are undertaken by teams that are scattered 61.297 +across the globe. Contributors who are far from a central server will 61.298 +see slower command execution and perhaps less reliability. Commercial 61.299 +revision control systems attempt to ameliorate these problems with 61.300 +remote-site replication add-ons that are typically expensive to buy 61.301 +and cantankerous to administer. A distributed system doesn't suffer 61.302 +from these problems in the first place. Better yet, you can easily 61.303 +set up multiple authoritative servers, say one per site, so that 61.304 +there's no redundant communication between repositories over expensive 61.305 +long-haul network links. 61.306 + 61.307 +Centralised revision control systems tend to have relatively low 61.308 +scalability. It's not unusual for an expensive centralised system to 61.309 +fall over under the combined load of just a few dozen concurrent 61.310 +users. Once again, the typical response tends to be an expensive and 61.311 +clunky replication facility. Since the load on a central server---if 61.312 +you have one at all---is many times lower with a distributed 61.313 +tool (because all of the data is replicated everywhere), a single 61.314 +cheap server can handle the needs of a much larger team, and 61.315 +replication to balance load becomes a simple matter of scripting. 61.316 + 61.317 +If you have an employee in the field, troubleshooting a problem at a 61.318 +customer's site, they'll benefit from distributed revision control. 61.319 +The tool will let them generate custom builds, try different fixes in 61.320 +isolation from each other, and search efficiently through history for 61.321 +the sources of bugs and regressions in the customer's environment, all 61.322 +without needing to connect to your company's network. 61.323 + 61.324 +\section{Why choose Mercurial?} 61.325 + 61.326 +Mercurial has a unique set of properties that make it a particularly 61.327 +good choice as a revision control system. 61.328 +\begin{itemize} 61.329 +\item It is easy to learn and use. 61.330 +\item It is lightweight. 61.331 +\item It scales excellently. 61.332 +\item It is easy to customise. 61.333 +\end{itemize} 61.334 + 61.335 +If you are at all familiar with revision control systems, you should 61.336 +be able to get up and running with Mercurial in less than five 61.337 +minutes. Even if not, it will take no more than a few minutes 61.338 +longer. Mercurial's command and feature sets are generally uniform 61.339 +and consistent, so you can keep track of a few general rules instead 61.340 +of a host of exceptions. 61.341 + 61.342 +On a small project, you can start working with Mercurial in moments. 61.343 +Creating new changes and branches; transferring changes around 61.344 +(whether locally or over a network); and history and status operations 61.345 +are all fast. Mercurial attempts to stay nimble and largely out of 61.346 +your way by combining low cognitive overhead with blazingly fast 61.347 +operations. 61.348 + 61.349 +The usefulness of Mercurial is not limited to small projects: it is 61.350 +used by projects with hundreds to thousands of contributors, each 61.351 +containing tens of thousands of files and hundreds of megabytes of 61.352 +source code. 61.353 + 61.354 +If the core functionality of Mercurial is not enough for you, it's 61.355 +easy to build on. Mercurial is well suited to scripting tasks, and 61.356 +its clean internals and implementation in Python make it easy to add 61.357 +features in the form of extensions. There are a number of popular and 61.358 +useful extensions already available, ranging from helping to identify 61.359 +bugs to improving performance. 61.360 + 61.361 +\section{Mercurial compared with other tools} 61.362 + 61.363 +Before you read on, please understand that this section necessarily 61.364 +reflects my own experiences, interests, and (dare I say it) biases. I 61.365 +have used every one of the revision control tools listed below, in 61.366 +most cases for several years at a time. 61.367 + 61.368 + 61.369 +\subsection{Subversion} 61.370 + 61.371 +Subversion is a popular revision control tool, developed to replace 61.372 +CVS. It has a centralised client/server architecture. 61.373 + 61.374 +Subversion and Mercurial have similarly named commands for performing 61.375 +the same operations, so if you're familiar with one, it is easy to 61.376 +learn to use the other. Both tools are portable to all popular 61.377 +operating systems. 61.378 + 61.379 +Prior to version 1.5, Subversion had no useful support for merges. 61.380 +At the time of writing, its merge tracking capability is new, and known to be 61.381 +\href{http://svnbook.red-bean.com/nightly/en/svn.branchmerge.advanced.html#svn.branchmerge.advanced.finalword}{complicated 61.382 + and buggy}. 61.383 + 61.384 +Mercurial has a substantial performance advantage over Subversion on 61.385 +every revision control operation I have benchmarked. I have measured 61.386 +its advantage as ranging from a factor of two to a factor of six when 61.387 +compared with Subversion~1.4.3's \emph{ra\_local} file store, which is 61.388 +the fastest access method available. In more realistic deployments 61.389 +involving a network-based store, Subversion will be at a substantially 61.390 +larger disadvantage. Because many Subversion commands must talk to 61.391 +the server and Subversion does not have useful replication facilities, 61.392 +server capacity and network bandwidth become bottlenecks for modestly 61.393 +large projects. 61.394 + 61.395 +Additionally, Subversion incurs substantial storage overhead to avoid 61.396 +network transactions for a few common operations, such as finding 61.397 +modified files (\texttt{status}) and displaying modifications against 61.398 +the current revision (\texttt{diff}). As a result, a Subversion 61.399 +working copy is often the same size as, or larger than, a Mercurial 61.400 +repository and working directory, even though the Mercurial repository 61.401 +contains a complete history of the project. 61.402 + 61.403 +Subversion is widely supported by third party tools. Mercurial 61.404 +currently lags considerably in this area. This gap is closing, 61.405 +however, and indeed some of Mercurial's GUI tools now outshine their 61.406 +Subversion equivalents. Like Mercurial, Subversion has an excellent 61.407 +user manual. 61.408 + 61.409 +Because Subversion doesn't store revision history on the client, it is 61.410 +well suited to managing projects that deal with lots of large, opaque 61.411 +binary files. If you check in fifty revisions to an incompressible 61.412 +10MB file, Subversion's client-side space usage stays constant The 61.413 +space used by any distributed SCM will grow rapidly in proportion to 61.414 +the number of revisions, because the differences between each revision 61.415 +are large. 61.416 + 61.417 +In addition, it's often difficult or, more usually, impossible to 61.418 +merge different versions of a binary file. Subversion's ability to 61.419 +let a user lock a file, so that they temporarily have the exclusive 61.420 +right to commit changes to it, can be a significant advantage to a 61.421 +project where binary files are widely used. 61.422 + 61.423 +Mercurial can import revision history from a Subversion repository. 61.424 +It can also export revision history to a Subversion repository. This 61.425 +makes it easy to ``test the waters'' and use Mercurial and Subversion 61.426 +in parallel before deciding to switch. History conversion is 61.427 +incremental, so you can perform an initial conversion, then small 61.428 +additional conversions afterwards to bring in new changes. 61.429 + 61.430 + 61.431 +\subsection{Git} 61.432 + 61.433 +Git is a distributed revision control tool that was developed for 61.434 +managing the Linux kernel source tree. Like Mercurial, its early 61.435 +design was somewhat influenced by Monotone. 61.436 + 61.437 +Git has a very large command set, with version~1.5.0 providing~139 61.438 +individual commands. It has something of a reputation for being 61.439 +difficult to learn. Compared to Git, Mercurial has a strong focus on 61.440 +simplicity. 61.441 + 61.442 +In terms of performance, Git is extremely fast. In several cases, it 61.443 +is faster than Mercurial, at least on Linux, while Mercurial performs 61.444 +better on other operations. However, on Windows, the performance and 61.445 +general level of support that Git provides is, at the time of writing, 61.446 +far behind that of Mercurial. 61.447 + 61.448 +While a Mercurial repository needs no maintenance, a Git repository 61.449 +requires frequent manual ``repacks'' of its metadata. Without these, 61.450 +performance degrades, while space usage grows rapidly. A server that 61.451 +contains many Git repositories that are not rigorously and frequently 61.452 +repacked will become heavily disk-bound during backups, and there have 61.453 +been instances of daily backups taking far longer than~24 hours as a 61.454 +result. A freshly packed Git repository is slightly smaller than a 61.455 +Mercurial repository, but an unpacked repository is several orders of 61.456 +magnitude larger. 61.457 + 61.458 +The core of Git is written in C. Many Git commands are implemented as 61.459 +shell or Perl scripts, and the quality of these scripts varies widely. 61.460 +I have encountered several instances where scripts charged along 61.461 +blindly in the presence of errors that should have been fatal. 61.462 + 61.463 +Mercurial can import revision history from a Git repository. 61.464 + 61.465 + 61.466 +\subsection{CVS} 61.467 + 61.468 +CVS is probably the most widely used revision control tool in the 61.469 +world. Due to its age and internal untidiness, it has been only 61.470 +lightly maintained for many years. 61.471 + 61.472 +It has a centralised client/server architecture. It does not group 61.473 +related file changes into atomic commits, making it easy for people to 61.474 +``break the build'': one person can successfully commit part of a 61.475 +change and then be blocked by the need for a merge, causing other 61.476 +people to see only a portion of the work they intended to do. This 61.477 +also affects how you work with project history. If you want to see 61.478 +all of the modifications someone made as part of a task, you will need 61.479 +to manually inspect the descriptions and timestamps of the changes 61.480 +made to each file involved (if you even know what those files were). 61.481 + 61.482 +CVS has a muddled notion of tags and branches that I will not attempt 61.483 +to even describe. It does not support renaming of files or 61.484 +directories well, making it easy to corrupt a repository. It has 61.485 +almost no internal consistency checking capabilities, so it is usually 61.486 +not even possible to tell whether or how a repository is corrupt. I 61.487 +would not recommend CVS for any project, existing or new. 61.488 + 61.489 +Mercurial can import CVS revision history. However, there are a few 61.490 +caveats that apply; these are true of every other revision control 61.491 +tool's CVS importer, too. Due to CVS's lack of atomic changes and 61.492 +unversioned filesystem hierarchy, it is not possible to reconstruct 61.493 +CVS history completely accurately; some guesswork is involved, and 61.494 +renames will usually not show up. Because a lot of advanced CVS 61.495 +administration has to be done by hand and is hence error-prone, it's 61.496 +common for CVS importers to run into multiple problems with corrupted 61.497 +repositories (completely bogus revision timestamps and files that have 61.498 +remained locked for over a decade are just two of the less interesting 61.499 +problems I can recall from personal experience). 61.500 + 61.501 +Mercurial can import revision history from a CVS repository. 61.502 + 61.503 + 61.504 +\subsection{Commercial tools} 61.505 + 61.506 +Perforce has a centralised client/server architecture, with no 61.507 +client-side caching of any data. Unlike modern revision control 61.508 +tools, Perforce requires that a user run a command to inform the 61.509 +server about every file they intend to edit. 61.510 + 61.511 +The performance of Perforce is quite good for small teams, but it 61.512 +falls off rapidly as the number of users grows beyond a few dozen. 61.513 +Modestly large Perforce installations require the deployment of 61.514 +proxies to cope with the load their users generate. 61.515 + 61.516 + 61.517 +\subsection{Choosing a revision control tool} 61.518 + 61.519 +With the exception of CVS, all of the tools listed above have unique 61.520 +strengths that suit them to particular styles of work. There is no 61.521 +single revision control tool that is best in all situations. 61.522 + 61.523 +As an example, Subversion is a good choice for working with frequently 61.524 +edited binary files, due to its centralised nature and support for 61.525 +file locking. 61.526 + 61.527 +I personally find Mercurial's properties of simplicity, performance, 61.528 +and good merge support to be a compelling combination that has served 61.529 +me well for several years. 61.530 + 61.531 + 61.532 +\section{Switching from another tool to Mercurial} 61.533 + 61.534 +Mercurial is bundled with an extension named \hgext{convert}, which 61.535 +can incrementally import revision history from several other revision 61.536 +control tools. By ``incremental'', I mean that you can convert all of 61.537 +a project's history to date in one go, then rerun the conversion later 61.538 +to obtain new changes that happened after the initial conversion. 61.539 + 61.540 +The revision control tools supported by \hgext{convert} are as 61.541 +follows: 61.542 +\begin{itemize} 61.543 +\item Subversion 61.544 +\item CVS 61.545 +\item Git 61.546 +\item Darcs 61.547 +\end{itemize} 61.548 + 61.549 +In addition, \hgext{convert} can export changes from Mercurial to 61.550 +Subversion. This makes it possible to try Subversion and Mercurial in 61.551 +parallel before committing to a switchover, without risking the loss 61.552 +of any work. 61.553 + 61.554 +The \hgxcmd{conver}{convert} command is easy to use. Simply point it 61.555 +at the path or URL of the source repository, optionally give it the 61.556 +name of the destination repository, and it will start working. After 61.557 +the initial conversion, just run the same command again to import new 61.558 +changes. 61.559 + 61.560 + 61.561 +%%% Local Variables: 61.562 +%%% mode: latex 61.563 +%%% TeX-master: "00book" 61.564 +%%% End:
62.1 Binary file fr/kdiff3.png has changed
63.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 63.2 +++ b/fr/license.tex Thu Feb 05 12:37:03 2009 +0100 63.3 @@ -0,0 +1,138 @@ 63.4 +\chapter{Open Publication License} 63.5 +\label{cha:opl} 63.6 + 63.7 +Version 1.0, 8 June 1999 63.8 + 63.9 +\section{Requirements on both unmodified and modified versions} 63.10 + 63.11 +The Open Publication works may be reproduced and distributed in whole 63.12 +or in part, in any medium physical or electronic, provided that the 63.13 +terms of this license are adhered to, and that this license or an 63.14 +incorporation of it by reference (with any options elected by the 63.15 +author(s) and/or publisher) is displayed in the reproduction. 63.16 + 63.17 +Proper form for an incorporation by reference is as follows: 63.18 + 63.19 +\begin{quote} 63.20 + Copyright (c) \emph{year} by \emph{author's name or designee}. This 63.21 + material may be distributed only subject to the terms and conditions 63.22 + set forth in the Open Publication License, v\emph{x.y} or later (the 63.23 + latest version is presently available at 63.24 + \url{http://www.opencontent.org/openpub/}). 63.25 +\end{quote} 63.26 + 63.27 +The reference must be immediately followed with any options elected by 63.28 +the author(s) and/or publisher of the document (see 63.29 +section~\ref{sec:opl:options}). 63.30 + 63.31 +Commercial redistribution of Open Publication-licensed material is 63.32 +permitted. 63.33 + 63.34 +Any publication in standard (paper) book form shall require the 63.35 +citation of the original publisher and author. The publisher and 63.36 +author's names shall appear on all outer surfaces of the book. On all 63.37 +outer surfaces of the book the original publisher's name shall be as 63.38 +large as the title of the work and cited as possessive with respect to 63.39 +the title. 63.40 + 63.41 +\section{Copyright} 63.42 + 63.43 +The copyright to each Open Publication is owned by its author(s) or 63.44 +designee. 63.45 + 63.46 +\section{Scope of license} 63.47 + 63.48 +The following license terms apply to all Open Publication works, 63.49 +unless otherwise explicitly stated in the document. 63.50 + 63.51 +Mere aggregation of Open Publication works or a portion of an Open 63.52 +Publication work with other works or programs on the same media shall 63.53 +not cause this license to apply to those other works. The aggregate 63.54 +work shall contain a notice specifying the inclusion of the Open 63.55 +Publication material and appropriate copyright notice. 63.56 + 63.57 +\textbf{Severability}. If any part of this license is found to be 63.58 +unenforceable in any jurisdiction, the remaining portions of the 63.59 +license remain in force. 63.60 + 63.61 +\textbf{No warranty}. Open Publication works are licensed and provided 63.62 +``as is'' without warranty of any kind, express or implied, including, 63.63 +but not limited to, the implied warranties of merchantability and 63.64 +fitness for a particular purpose or a warranty of non-infringement. 63.65 + 63.66 +\section{Requirements on modified works} 63.67 + 63.68 +All modified versions of documents covered by this license, including 63.69 +translations, anthologies, compilations and partial documents, must 63.70 +meet the following requirements: 63.71 + 63.72 +\begin{enumerate} 63.73 +\item The modified version must be labeled as such. 63.74 +\item The person making the modifications must be identified and the 63.75 + modifications dated. 63.76 +\item Acknowledgement of the original author and publisher if 63.77 + applicable must be retained according to normal academic citation 63.78 + practices. 63.79 +\item The location of the original unmodified document must be 63.80 + identified. 63.81 +\item The original author's (or authors') name(s) may not be used to 63.82 + assert or imply endorsement of the resulting document without the 63.83 + original author's (or authors') permission. 63.84 +\end{enumerate} 63.85 + 63.86 +\section{Good-practice recommendations} 63.87 + 63.88 +In addition to the requirements of this license, it is requested from 63.89 +and strongly recommended of redistributors that: 63.90 + 63.91 +\begin{enumerate} 63.92 +\item If you are distributing Open Publication works on hardcopy or 63.93 + CD-ROM, you provide email notification to the authors of your intent 63.94 + to redistribute at least thirty days before your manuscript or media 63.95 + freeze, to give the authors time to provide updated documents. This 63.96 + notification should describe modifications, if any, made to the 63.97 + document. 63.98 +\item All substantive modifications (including deletions) be either 63.99 + clearly marked up in the document or else described in an attachment 63.100 + to the document. 63.101 +\item Finally, while it is not mandatory under this license, it is 63.102 + considered good form to offer a free copy of any hardcopy and CD-ROM 63.103 + expression of an Open Publication-licensed work to its author(s). 63.104 +\end{enumerate} 63.105 + 63.106 +\section{License options} 63.107 +\label{sec:opl:options} 63.108 + 63.109 +The author(s) and/or publisher of an Open Publication-licensed 63.110 +document may elect certain options by appending language to the 63.111 +reference to or copy of the license. These options are considered part 63.112 +of the license instance and must be included with the license (or its 63.113 +incorporation by reference) in derived works. 63.114 + 63.115 +\begin{enumerate}[A] 63.116 +\item To prohibit distribution of substantively modified versions 63.117 + without the explicit permission of the author(s). ``Substantive 63.118 + modification'' is defined as a change to the semantic content of the 63.119 + document, and excludes mere changes in format or typographical 63.120 + corrections. 63.121 + 63.122 + To accomplish this, add the phrase ``Distribution of substantively 63.123 + modified versions of this document is prohibited without the 63.124 + explicit permission of the copyright holder.'' to the license 63.125 + reference or copy. 63.126 + 63.127 +\item To prohibit any publication of this work or derivative works in 63.128 + whole or in part in standard (paper) book form for commercial 63.129 + purposes is prohibited unless prior permission is obtained from the 63.130 + copyright holder. 63.131 + 63.132 + To accomplish this, add the phrase ``Distribution of the work or 63.133 + derivative of the work in any standard (paper) book form is 63.134 + prohibited unless prior permission is obtained from the copyright 63.135 + holder.'' to the license reference or copy. 63.136 +\end{enumerate} 63.137 + 63.138 +%%% Local Variables: 63.139 +%%% mode: latex 63.140 +%%% TeX-master: "00book" 63.141 +%%% End:
64.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 64.2 +++ b/fr/metadata.svg Thu Feb 05 12:37:03 2009 +0100 64.3 @@ -0,0 +1,328 @@ 64.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 64.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 64.6 +<svg 64.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 64.8 + xmlns:cc="http://web.resource.org/cc/" 64.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 64.10 + xmlns:svg="http://www.w3.org/2000/svg" 64.11 + xmlns="http://www.w3.org/2000/svg" 64.12 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 64.13 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 64.14 + width="744.09448819" 64.15 + height="1052.3622047" 64.16 + id="svg2" 64.17 + sodipodi:version="0.32" 64.18 + inkscape:version="0.44.1" 64.19 + sodipodi:docname="metadata.svg" 64.20 + sodipodi:docbase="/home/bos/hg/hgbook/en"> 64.21 + <defs 64.22 + id="defs4"> 64.23 + <marker 64.24 + inkscape:stockid="Arrow1Mend" 64.25 + orient="auto" 64.26 + refY="0.0" 64.27 + refX="0.0" 64.28 + id="Arrow1Mend" 64.29 + style="overflow:visible;"> 64.30 + <path 64.31 + id="path2944" 64.32 + 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 " 64.33 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 64.34 + transform="scale(0.4) rotate(180) translate(10,0)" /> 64.35 + </marker> 64.36 + </defs> 64.37 + <sodipodi:namedview 64.38 + id="base" 64.39 + pagecolor="#ffffff" 64.40 + bordercolor="#666666" 64.41 + borderopacity="1.0" 64.42 + gridtolerance="10000" 64.43 + guidetolerance="10" 64.44 + objecttolerance="10" 64.45 + inkscape:pageopacity="0.0" 64.46 + inkscape:pageshadow="2" 64.47 + inkscape:zoom="1.4" 64.48 + inkscape:cx="232.14286" 64.49 + inkscape:cy="490.68696" 64.50 + inkscape:document-units="px" 64.51 + inkscape:current-layer="layer1" 64.52 + inkscape:window-width="906" 64.53 + inkscape:window-height="620" 64.54 + inkscape:window-x="181" 64.55 + inkscape:window-y="58" /> 64.56 + <metadata 64.57 + id="metadata7"> 64.58 + <rdf:RDF> 64.59 + <cc:Work 64.60 + rdf:about=""> 64.61 + <dc:format>image/svg+xml</dc:format> 64.62 + <dc:type 64.63 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 64.64 + </cc:Work> 64.65 + </rdf:RDF> 64.66 + </metadata> 64.67 + <g 64.68 + inkscape:label="Layer 1" 64.69 + inkscape:groupmode="layer" 64.70 + id="layer1"> 64.71 + <path 64.72 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a7a7a7;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:4.5, 1.5;stroke-dashoffset:0;stroke-opacity:1;display:inline" 64.73 + d="M 326.94646,467.18359 L 326.94646,510.98123" 64.74 + id="path1910" 64.75 + inkscape:connector-type="polyline" 64.76 + inkscape:connection-end="#rect2962" 64.77 + inkscape:connection-start="#rect2764" /> 64.78 + <path 64.79 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a7a7a7;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:4.5, 1.5;stroke-dashoffset:0;stroke-opacity:1;display:inline" 64.80 + d="M 326.94646,531.98123 L 326.94646,591.77887" 64.81 + id="path1912" 64.82 + inkscape:connector-type="polyline" 64.83 + inkscape:connection-start="#rect2962" 64.84 + inkscape:connection-end="#rect3000" /> 64.85 + <path 64.86 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a7a7a7;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:4.5, 1.5;stroke-dashoffset:0;stroke-opacity:1;display:inline" 64.87 + d="M 316.1622,531.98123 L 192.30212,652.57648" 64.88 + id="path1916" 64.89 + inkscape:connector-type="polyline" 64.90 + inkscape:connection-end="#rect3038" 64.91 + inkscape:connection-start="#rect2962" /> 64.92 + <path 64.93 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#484848;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:4.5, 1.5;stroke-dashoffset:0;stroke-opacity:1" 64.94 + d="M 254.23217,467.18359 L 254.23216,510.98123" 64.95 + id="path3088" 64.96 + inkscape:connector-type="polyline" 64.97 + inkscape:connection-start="#rect1872" 64.98 + inkscape:connection-end="#rect2960" /> 64.99 + <path 64.100 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#484848;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:4.5, 1.5;stroke-dashoffset:0;stroke-opacity:1" 64.101 + d="M 254.23215,531.98123 L 254.23215,591.77887" 64.102 + id="path3090" 64.103 + inkscape:connector-type="polyline" 64.104 + inkscape:connection-start="#rect2960" 64.105 + inkscape:connection-end="#rect2998" /> 64.106 + <path 64.107 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#484848;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:4.5, 1.5;stroke-dashoffset:0;stroke-opacity:1" 64.108 + d="M 248.84002,531.98123 L 186.90999,652.57648" 64.109 + id="path3092" 64.110 + inkscape:connector-type="polyline" 64.111 + inkscape:connection-start="#rect2960" 64.112 + inkscape:connection-end="#rect3038" /> 64.113 + <rect 64.114 + style="fill:#7b7df5;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.115 + id="rect1872" 64.116 + width="51.42857" 64.117 + height="20" 64.118 + x="228.51788" 64.119 + y="446.68359" /> 64.120 + <rect 64.121 + style="fill:#cacbfb;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.122 + id="rect2764" 64.123 + width="51.42857" 64.124 + height="20" 64.125 + x="301.23218" 64.126 + y="446.68359" /> 64.127 + <rect 64.128 + style="fill:#cacbfb;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.129 + id="rect2766" 64.130 + width="51.42857" 64.131 + height="20" 64.132 + x="155.80359" 64.133 + y="446.68359" /> 64.134 + <rect 64.135 + style="fill:#cacbfb;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.136 + id="rect2768" 64.137 + width="51.42857" 64.138 + height="20" 64.139 + x="83.089294" 64.140 + y="446.68359" /> 64.141 + <path 64.142 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.143 + d="M 135.01786,456.68359 L 155.30359,456.68359" 64.144 + id="path2770" 64.145 + inkscape:connector-type="polyline" 64.146 + inkscape:connection-start="#rect2768" 64.147 + inkscape:connection-end="#rect2766" /> 64.148 + <path 64.149 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.150 + d="M 207.73216,456.68359 L 228.01788,456.68359" 64.151 + id="path2772" 64.152 + inkscape:connector-type="polyline" 64.153 + inkscape:connection-start="#rect2766" 64.154 + inkscape:connection-end="#rect1872" /> 64.155 + <path 64.156 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.157 + d="M 280.44645,456.68359 L 300.73218,456.68359" 64.158 + id="path2774" 64.159 + inkscape:connector-type="polyline" 64.160 + inkscape:connection-start="#rect1872" 64.161 + inkscape:connection-end="#rect2764" /> 64.162 + <path 64.163 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1" 64.164 + d="M 62.303571,456.68359 L 82.589294,456.68359" 64.165 + id="path2778" 64.166 + inkscape:connector-type="polyline" 64.167 + inkscape:connection-end="#rect2768" /> 64.168 + <rect 64.169 + style="fill:#84f57b;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.170 + id="rect2960" 64.171 + width="51.42857" 64.172 + height="20" 64.173 + x="228.51787" 64.174 + y="511.48123" /> 64.175 + <rect 64.176 + style="fill:#cefbca;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.177 + id="rect2962" 64.178 + width="51.42857" 64.179 + height="20" 64.180 + x="301.23218" 64.181 + y="511.48123" /> 64.182 + <rect 64.183 + style="fill:#cefbca;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.184 + id="rect2964" 64.185 + width="51.42857" 64.186 + height="20" 64.187 + x="155.80357" 64.188 + y="511.48123" /> 64.189 + <rect 64.190 + style="fill:#cefbca;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.191 + id="rect2966" 64.192 + width="51.42857" 64.193 + height="20" 64.194 + x="83.089287" 64.195 + y="511.48123" /> 64.196 + <path 64.197 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.198 + d="M 135.01786,521.48121 L 155.30359,521.48121" 64.199 + id="path2968" 64.200 + inkscape:connector-type="polyline" /> 64.201 + <path 64.202 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.203 + d="M 207.73216,521.48121 L 228.01788,521.48121" 64.204 + id="path2970" 64.205 + inkscape:connector-type="polyline" /> 64.206 + <path 64.207 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.208 + d="M 280.44645,521.48121 L 300.73218,521.48121" 64.209 + id="path2972" 64.210 + inkscape:connector-type="polyline" /> 64.211 + <path 64.212 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1" 64.213 + d="M 62.30358,521.48121 L 82.5893,521.48121" 64.214 + id="path2974" 64.215 + inkscape:connector-type="polyline" /> 64.216 + <rect 64.217 + style="fill:#f57b8f;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.218 + id="rect2998" 64.219 + width="51.42857" 64.220 + height="20" 64.221 + x="228.51787" 64.222 + y="592.27887" /> 64.223 + <rect 64.224 + style="fill:#fbcad2;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.225 + id="rect3000" 64.226 + width="51.42857" 64.227 + height="20" 64.228 + x="301.23218" 64.229 + y="592.27887" /> 64.230 + <rect 64.231 + style="fill:#fbcad2;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.232 + id="rect3002" 64.233 + width="51.42857" 64.234 + height="20" 64.235 + x="155.80357" 64.236 + y="592.27887" /> 64.237 + <rect 64.238 + style="fill:#fbcad2;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.239 + id="rect3004" 64.240 + width="51.42857" 64.241 + height="20" 64.242 + x="83.089287" 64.243 + y="592.27887" /> 64.244 + <path 64.245 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.246 + d="M 135.01786,602.27884 L 155.30359,602.27884" 64.247 + id="path3006" 64.248 + inkscape:connector-type="polyline" /> 64.249 + <path 64.250 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.251 + d="M 207.73216,602.27884 L 228.01788,602.27884" 64.252 + id="path3008" 64.253 + inkscape:connector-type="polyline" /> 64.254 + <path 64.255 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.256 + d="M 280.44645,602.27884 L 300.73218,602.27884" 64.257 + id="path3010" 64.258 + inkscape:connector-type="polyline" /> 64.259 + <path 64.260 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1" 64.261 + d="M 62.30358,602.27884 L 82.5893,602.27884" 64.262 + id="path3012" 64.263 + inkscape:connector-type="polyline" /> 64.264 + <rect 64.265 + style="fill:#ffced6;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.266 + id="rect3034" 64.267 + width="51.42857" 64.268 + height="20" 64.269 + x="228.51787" 64.270 + y="653.07648" /> 64.271 + <rect 64.272 + style="fill:#f57b8f;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.273 + id="rect3038" 64.274 + width="51.42857" 64.275 + height="20" 64.276 + x="155.80357" 64.277 + y="653.07648" /> 64.278 + <rect 64.279 + style="fill:#fbcad2;fill-opacity:1;stroke:#595959;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 64.280 + id="rect3040" 64.281 + width="51.42857" 64.282 + height="20" 64.283 + x="83.089287" 64.284 + y="653.07648" /> 64.285 + <path 64.286 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.287 + d="M 135.01786,663.07646 L 155.30359,663.07646" 64.288 + id="path3042" 64.289 + inkscape:connector-type="polyline" /> 64.290 + <path 64.291 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 64.292 + d="M 207.73216,663.07646 L 228.01788,663.07646" 64.293 + id="path3044" 64.294 + inkscape:connector-type="polyline" /> 64.295 + <path 64.296 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#747474;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1" 64.297 + d="M 62.30358,663.07646 L 82.5893,663.07646" 64.298 + id="path3048" 64.299 + inkscape:connector-type="polyline" /> 64.300 + <text 64.301 + xml:space="preserve" 64.302 + 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" 64.303 + x="82.072548" 64.304 + y="432.64789" 64.305 + id="text3094"><tspan 64.306 + sodipodi:role="line" 64.307 + id="tspan3096" 64.308 + x="82.072548" 64.309 + y="432.64789">Changelog</tspan></text> 64.310 + <text 64.311 + xml:space="preserve" 64.312 + 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" 64.313 + x="82.306923" 64.314 + y="498.97327" 64.315 + id="text3098"><tspan 64.316 + sodipodi:role="line" 64.317 + id="tspan3100" 64.318 + x="82.306923" 64.319 + y="498.97327">Manifest</tspan></text> 64.320 + <text 64.321 + xml:space="preserve" 64.322 + 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" 64.323 + x="82.14286" 64.324 + y="580.08569" 64.325 + id="text3102"><tspan 64.326 + sodipodi:role="line" 64.327 + id="tspan3104" 64.328 + x="82.14286" 64.329 + y="580.08569">Filelogs</tspan></text> 64.330 + </g> 64.331 +</svg>
65.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 65.2 +++ b/fr/mq-collab.tex Thu Feb 05 12:37:03 2009 +0100 65.3 @@ -0,0 +1,393 @@ 65.4 +\chapter{Advanced uses of Mercurial Queues} 65.5 +\label{chap:mq-collab} 65.6 + 65.7 +While it's easy to pick up straightforward uses of Mercurial Queues, 65.8 +use of a little discipline and some of MQ's less frequently used 65.9 +capabilities makes it possible to work in complicated development 65.10 +environments. 65.11 + 65.12 +In this chapter, I will use as an example a technique I have used to 65.13 +manage the development of an Infiniband device driver for the Linux 65.14 +kernel. The driver in question is large (at least as drivers go), 65.15 +with 25,000 lines of code spread across 35 source files. It is 65.16 +maintained by a small team of developers. 65.17 + 65.18 +While much of the material in this chapter is specific to Linux, the 65.19 +same principles apply to any code base for which you're not the 65.20 +primary owner, and upon which you need to do a lot of development. 65.21 + 65.22 +\section{The problem of many targets} 65.23 + 65.24 +The Linux kernel changes rapidly, and has never been internally 65.25 +stable; developers frequently make drastic changes between releases. 65.26 +This means that a version of the driver that works well with a 65.27 +particular released version of the kernel will not even \emph{compile} 65.28 +correctly against, typically, any other version. 65.29 + 65.30 +To maintain a driver, we have to keep a number of distinct versions of 65.31 +Linux in mind. 65.32 +\begin{itemize} 65.33 +\item One target is the main Linux kernel development tree. 65.34 + Maintenance of the code is in this case partly shared by other 65.35 + developers in the kernel community, who make ``drive-by'' 65.36 + modifications to the driver as they develop and refine kernel 65.37 + subsystems. 65.38 +\item We also maintain a number of ``backports'' to older versions of 65.39 + the Linux kernel, to support the needs of customers who are running 65.40 + older Linux distributions that do not incorporate our drivers. (To 65.41 + \emph{backport} a piece of code is to modify it to work in an older 65.42 + version of its target environment than the version it was developed 65.43 + for.) 65.44 +\item Finally, we make software releases on a schedule that is 65.45 + necessarily not aligned with those used by Linux distributors and 65.46 + kernel developers, so that we can deliver new features to customers 65.47 + without forcing them to upgrade their entire kernels or 65.48 + distributions. 65.49 +\end{itemize} 65.50 + 65.51 +\subsection{Tempting approaches that don't work well} 65.52 + 65.53 +There are two ``standard'' ways to maintain a piece of software that 65.54 +has to target many different environments. 65.55 + 65.56 +The first is to maintain a number of branches, each intended for a 65.57 +single target. The trouble with this approach is that you must 65.58 +maintain iron discipline in the flow of changes between repositories. 65.59 +A new feature or bug fix must start life in a ``pristine'' repository, 65.60 +then percolate out to every backport repository. Backport changes are 65.61 +more limited in the branches they should propagate to; a backport 65.62 +change that is applied to a branch where it doesn't belong will 65.63 +probably stop the driver from compiling. 65.64 + 65.65 +The second is to maintain a single source tree filled with conditional 65.66 +statements that turn chunks of code on or off depending on the 65.67 +intended target. Because these ``ifdefs'' are not allowed in the 65.68 +Linux kernel tree, a manual or automatic process must be followed to 65.69 +strip them out and yield a clean tree. A code base maintained in this 65.70 +fashion rapidly becomes a rat's nest of conditional blocks that are 65.71 +difficult to understand and maintain. 65.72 + 65.73 +Neither of these approaches is well suited to a situation where you 65.74 +don't ``own'' the canonical copy of a source tree. In the case of a 65.75 +Linux driver that is distributed with the standard kernel, Linus's 65.76 +tree contains the copy of the code that will be treated by the world 65.77 +as canonical. The upstream version of ``my'' driver can be modified 65.78 +by people I don't know, without me even finding out about it until 65.79 +after the changes show up in Linus's tree. 65.80 + 65.81 +These approaches have the added weakness of making it difficult to 65.82 +generate well-formed patches to submit upstream. 65.83 + 65.84 +In principle, Mercurial Queues seems like a good candidate to manage a 65.85 +development scenario such as the above. While this is indeed the 65.86 +case, MQ contains a few added features that make the job more 65.87 +pleasant. 65.88 + 65.89 +\section{Conditionally applying patches with 65.90 + guards} 65.91 + 65.92 +Perhaps the best way to maintain sanity with so many targets is to be 65.93 +able to choose specific patches to apply for a given situation. MQ 65.94 +provides a feature called ``guards'' (which originates with quilt's 65.95 +\texttt{guards} command) that does just this. To start off, let's 65.96 +create a simple repository for experimenting in. 65.97 +\interaction{mq.guards.init} 65.98 +This gives us a tiny repository that contains two patches that don't 65.99 +have any dependencies on each other, because they touch different files. 65.100 + 65.101 +The idea behind conditional application is that you can ``tag'' a 65.102 +patch with a \emph{guard}, which is simply a text string of your 65.103 +choosing, then tell MQ to select specific guards to use when applying 65.104 +patches. MQ will then either apply, or skip over, a guarded patch, 65.105 +depending on the guards that you have selected. 65.106 + 65.107 +A patch can have an arbitrary number of guards; 65.108 +each one is \emph{positive} (``apply this patch if this guard is 65.109 +selected'') or \emph{negative} (``skip this patch if this guard is 65.110 +selected''). A patch with no guards is always applied. 65.111 + 65.112 +\section{Controlling the guards on a patch} 65.113 + 65.114 +The \hgxcmd{mq}{qguard} command lets you determine which guards should 65.115 +apply to a patch, or display the guards that are already in effect. 65.116 +Without any arguments, it displays the guards on the current topmost 65.117 +patch. 65.118 +\interaction{mq.guards.qguard} 65.119 +To set a positive guard on a patch, prefix the name of the guard with 65.120 +a ``\texttt{+}''. 65.121 +\interaction{mq.guards.qguard.pos} 65.122 +To set a negative guard on a patch, prefix the name of the guard with 65.123 +a ``\texttt{-}''. 65.124 +\interaction{mq.guards.qguard.neg} 65.125 + 65.126 +\begin{note} 65.127 + The \hgxcmd{mq}{qguard} command \emph{sets} the guards on a patch; it 65.128 + doesn't \emph{modify} them. What this means is that if you run 65.129 + \hgcmdargs{qguard}{+a +b} on a patch, then \hgcmdargs{qguard}{+c} on 65.130 + the same patch, the \emph{only} guard that will be set on it 65.131 + afterwards is \texttt{+c}. 65.132 +\end{note} 65.133 + 65.134 +Mercurial stores guards in the \sfilename{series} file; the form in 65.135 +which they are stored is easy both to understand and to edit by hand. 65.136 +(In other words, you don't have to use the \hgxcmd{mq}{qguard} command if 65.137 +you don't want to; it's okay to simply edit the \sfilename{series} 65.138 +file.) 65.139 +\interaction{mq.guards.series} 65.140 + 65.141 +\section{Selecting the guards to use} 65.142 + 65.143 +The \hgxcmd{mq}{qselect} command determines which guards are active at a 65.144 +given time. The effect of this is to determine which patches MQ will 65.145 +apply the next time you run \hgxcmd{mq}{qpush}. It has no other effect; in 65.146 +particular, it doesn't do anything to patches that are already 65.147 +applied. 65.148 + 65.149 +With no arguments, the \hgxcmd{mq}{qselect} command lists the guards 65.150 +currently in effect, one per line of output. Each argument is treated 65.151 +as the name of a guard to apply. 65.152 +\interaction{mq.guards.qselect.foo} 65.153 +In case you're interested, the currently selected guards are stored in 65.154 +the \sfilename{guards} file. 65.155 +\interaction{mq.guards.qselect.cat} 65.156 +We can see the effect the selected guards have when we run 65.157 +\hgxcmd{mq}{qpush}. 65.158 +\interaction{mq.guards.qselect.qpush} 65.159 + 65.160 +A guard cannot start with a ``\texttt{+}'' or ``\texttt{-}'' 65.161 +character. The name of a guard must not contain white space, but most 65.162 +other characters are acceptable. If you try to use a guard with an 65.163 +invalid name, MQ will complain: 65.164 +\interaction{mq.guards.qselect.error} 65.165 +Changing the selected guards changes the patches that are applied. 65.166 +\interaction{mq.guards.qselect.quux} 65.167 +You can see in the example below that negative guards take precedence 65.168 +over positive guards. 65.169 +\interaction{mq.guards.qselect.foobar} 65.170 + 65.171 +\section{MQ's rules for applying patches} 65.172 + 65.173 +The rules that MQ uses when deciding whether to apply a patch 65.174 +are as follows. 65.175 +\begin{itemize} 65.176 +\item A patch that has no guards is always applied. 65.177 +\item If the patch has any negative guard that matches any currently 65.178 + selected guard, the patch is skipped. 65.179 +\item If the patch has any positive guard that matches any currently 65.180 + selected guard, the patch is applied. 65.181 +\item If the patch has positive or negative guards, but none matches 65.182 + any currently selected guard, the patch is skipped. 65.183 +\end{itemize} 65.184 + 65.185 +\section{Trimming the work environment} 65.186 + 65.187 +In working on the device driver I mentioned earlier, I don't apply the 65.188 +patches to a normal Linux kernel tree. Instead, I use a repository 65.189 +that contains only a snapshot of the source files and headers that are 65.190 +relevant to Infiniband development. This repository is~1\% the size 65.191 +of a kernel repository, so it's easier to work with. 65.192 + 65.193 +I then choose a ``base'' version on top of which the patches are 65.194 +applied. This is a snapshot of the Linux kernel tree as of a revision 65.195 +of my choosing. When I take the snapshot, I record the changeset ID 65.196 +from the kernel repository in the commit message. Since the snapshot 65.197 +preserves the ``shape'' and content of the relevant parts of the 65.198 +kernel tree, I can apply my patches on top of either my tiny 65.199 +repository or a normal kernel tree. 65.200 + 65.201 +Normally, the base tree atop which the patches apply should be a 65.202 +snapshot of a very recent upstream tree. This best facilitates the 65.203 +development of patches that can easily be submitted upstream with few 65.204 +or no modifications. 65.205 + 65.206 +\section{Dividing up the \sfilename{series} file} 65.207 + 65.208 +I categorise the patches in the \sfilename{series} file into a number 65.209 +of logical groups. Each section of like patches begins with a block 65.210 +of comments that describes the purpose of the patches that follow. 65.211 + 65.212 +The sequence of patch groups that I maintain follows. The ordering of 65.213 +these groups is important; I'll describe why after I introduce the 65.214 +groups. 65.215 +\begin{itemize} 65.216 +\item The ``accepted'' group. Patches that the development team has 65.217 + submitted to the maintainer of the Infiniband subsystem, and which 65.218 + he has accepted, but which are not present in the snapshot that the 65.219 + tiny repository is based on. These are ``read only'' patches, 65.220 + present only to transform the tree into a similar state as it is in 65.221 + the upstream maintainer's repository. 65.222 +\item The ``rework'' group. Patches that I have submitted, but that 65.223 + the upstream maintainer has requested modifications to before he 65.224 + will accept them. 65.225 +\item The ``pending'' group. Patches that I have not yet submitted to 65.226 + the upstream maintainer, but which we have finished working on. 65.227 + These will be ``read only'' for a while. If the upstream maintainer 65.228 + accepts them upon submission, I'll move them to the end of the 65.229 + ``accepted'' group. If he requests that I modify any, I'll move 65.230 + them to the beginning of the ``rework'' group. 65.231 +\item The ``in progress'' group. Patches that are actively being 65.232 + developed, and should not be submitted anywhere yet. 65.233 +\item The ``backport'' group. Patches that adapt the source tree to 65.234 + older versions of the kernel tree. 65.235 +\item The ``do not ship'' group. Patches that for some reason should 65.236 + never be submitted upstream. For example, one such patch might 65.237 + change embedded driver identification strings to make it easier to 65.238 + distinguish, in the field, between an out-of-tree version of the 65.239 + driver and a version shipped by a distribution vendor. 65.240 +\end{itemize} 65.241 + 65.242 +Now to return to the reasons for ordering groups of patches in this 65.243 +way. We would like the lowest patches in the stack to be as stable as 65.244 +possible, so that we will not need to rework higher patches due to 65.245 +changes in context. Putting patches that will never be changed first 65.246 +in the \sfilename{series} file serves this purpose. 65.247 + 65.248 +We would also like the patches that we know we'll need to modify to be 65.249 +applied on top of a source tree that resembles the upstream tree as 65.250 +closely as possible. This is why we keep accepted patches around for 65.251 +a while. 65.252 + 65.253 +The ``backport'' and ``do not ship'' patches float at the end of the 65.254 +\sfilename{series} file. The backport patches must be applied on top 65.255 +of all other patches, and the ``do not ship'' patches might as well 65.256 +stay out of harm's way. 65.257 + 65.258 +\section{Maintaining the patch series} 65.259 + 65.260 +In my work, I use a number of guards to control which patches are to 65.261 +be applied. 65.262 + 65.263 +\begin{itemize} 65.264 +\item ``Accepted'' patches are guarded with \texttt{accepted}. I 65.265 + enable this guard most of the time. When I'm applying the patches 65.266 + on top of a tree where the patches are already present, I can turn 65.267 + this patch off, and the patches that follow it will apply cleanly. 65.268 +\item Patches that are ``finished'', but not yet submitted, have no 65.269 + guards. If I'm applying the patch stack to a copy of the upstream 65.270 + tree, I don't need to enable any guards in order to get a reasonably 65.271 + safe source tree. 65.272 +\item Those patches that need reworking before being resubmitted are 65.273 + guarded with \texttt{rework}. 65.274 +\item For those patches that are still under development, I use 65.275 + \texttt{devel}. 65.276 +\item A backport patch may have several guards, one for each version 65.277 + of the kernel to which it applies. For example, a patch that 65.278 + backports a piece of code to~2.6.9 will have a~\texttt{2.6.9} guard. 65.279 +\end{itemize} 65.280 +This variety of guards gives me considerable flexibility in 65.281 +determining what kind of source tree I want to end up with. For most 65.282 +situations, the selection of appropriate guards is automated during 65.283 +the build process, but I can manually tune the guards to use for less 65.284 +common circumstances. 65.285 + 65.286 +\subsection{The art of writing backport patches} 65.287 + 65.288 +Using MQ, writing a backport patch is a simple process. All such a 65.289 +patch has to do is modify a piece of code that uses a kernel feature 65.290 +not present in the older version of the kernel, so that the driver 65.291 +continues to work correctly under that older version. 65.292 + 65.293 +A useful goal when writing a good backport patch is to make your code 65.294 +look as if it was written for the older version of the kernel you're 65.295 +targeting. The less obtrusive the patch, the easier it will be to 65.296 +understand and maintain. If you're writing a collection of backport 65.297 +patches to avoid the ``rat's nest'' effect of lots of 65.298 +\texttt{\#ifdef}s (hunks of source code that are only used 65.299 +conditionally) in your code, don't introduce version-dependent 65.300 +\texttt{\#ifdef}s into the patches. Instead, write several patches, 65.301 +each of which makes unconditional changes, and control their 65.302 +application using guards. 65.303 + 65.304 +There are two reasons to divide backport patches into a distinct 65.305 +group, away from the ``regular'' patches whose effects they modify. 65.306 +The first is that intermingling the two makes it more difficult to use 65.307 +a tool like the \hgext{patchbomb} extension to automate the process of 65.308 +submitting the patches to an upstream maintainer. The second is that 65.309 +a backport patch could perturb the context in which a subsequent 65.310 +regular patch is applied, making it impossible to apply the regular 65.311 +patch cleanly \emph{without} the earlier backport patch already being 65.312 +applied. 65.313 + 65.314 +\section{Useful tips for developing with MQ} 65.315 + 65.316 +\subsection{Organising patches in directories} 65.317 + 65.318 +If you're working on a substantial project with MQ, it's not difficult 65.319 +to accumulate a large number of patches. For example, I have one 65.320 +patch repository that contains over 250 patches. 65.321 + 65.322 +If you can group these patches into separate logical categories, you 65.323 +can if you like store them in different directories; MQ has no 65.324 +problems with patch names that contain path separators. 65.325 + 65.326 +\subsection{Viewing the history of a patch} 65.327 +\label{mq-collab:tips:interdiff} 65.328 + 65.329 +If you're developing a set of patches over a long time, it's a good 65.330 +idea to maintain them in a repository, as discussed in 65.331 +section~\ref{sec:mq:repo}. If you do so, you'll quickly discover that 65.332 +using the \hgcmd{diff} command to look at the history of changes to a 65.333 +patch is unworkable. This is in part because you're looking at the 65.334 +second derivative of the real code (a diff of a diff), but also 65.335 +because MQ adds noise to the process by modifying time stamps and 65.336 +directory names when it updates a patch. 65.337 + 65.338 +However, you can use the \hgext{extdiff} extension, which is bundled 65.339 +with Mercurial, to turn a diff of two versions of a patch into 65.340 +something readable. To do this, you will need a third-party package 65.341 +called \package{patchutils}~\cite{web:patchutils}. This provides a 65.342 +command named \command{interdiff}, which shows the differences between 65.343 +two diffs as a diff. Used on two versions of the same diff, it 65.344 +generates a diff that represents the diff from the first to the second 65.345 +version. 65.346 + 65.347 +You can enable the \hgext{extdiff} extension in the usual way, by 65.348 +adding a line to the \rcsection{extensions} section of your \hgrc. 65.349 +\begin{codesample2} 65.350 + [extensions] 65.351 + extdiff = 65.352 +\end{codesample2} 65.353 +The \command{interdiff} command expects to be passed the names of two 65.354 +files, but the \hgext{extdiff} extension passes the program it runs a 65.355 +pair of directories, each of which can contain an arbitrary number of 65.356 +files. We thus need a small program that will run \command{interdiff} 65.357 +on each pair of files in these two directories. This program is 65.358 +available as \sfilename{hg-interdiff} in the \dirname{examples} 65.359 +directory of the source code repository that accompanies this book. 65.360 +\excode{hg-interdiff} 65.361 + 65.362 +With the \sfilename{hg-interdiff} program in your shell's search path, 65.363 +you can run it as follows, from inside an MQ patch directory: 65.364 +\begin{codesample2} 65.365 + hg extdiff -p hg-interdiff -r A:B my-change.patch 65.366 +\end{codesample2} 65.367 +Since you'll probably want to use this long-winded command a lot, you 65.368 +can get \hgext{hgext} to make it available as a normal Mercurial 65.369 +command, again by editing your \hgrc. 65.370 +\begin{codesample2} 65.371 + [extdiff] 65.372 + cmd.interdiff = hg-interdiff 65.373 +\end{codesample2} 65.374 +This directs \hgext{hgext} to make an \texttt{interdiff} command 65.375 +available, so you can now shorten the previous invocation of 65.376 +\hgxcmd{extdiff}{extdiff} to something a little more wieldy. 65.377 +\begin{codesample2} 65.378 + hg interdiff -r A:B my-change.patch 65.379 +\end{codesample2} 65.380 + 65.381 +\begin{note} 65.382 + The \command{interdiff} command works well only if the underlying 65.383 + files against which versions of a patch are generated remain the 65.384 + same. If you create a patch, modify the underlying files, and then 65.385 + regenerate the patch, \command{interdiff} may not produce useful 65.386 + output. 65.387 +\end{note} 65.388 + 65.389 +The \hgext{extdiff} extension is useful for more than merely improving 65.390 +the presentation of MQ~patches. To read more about it, go to 65.391 +section~\ref{sec:hgext:extdiff}. 65.392 + 65.393 +%%% Local Variables: 65.394 +%%% mode: latex 65.395 +%%% TeX-master: "00book" 65.396 +%%% End:
66.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 66.2 +++ b/fr/mq-ref.tex Thu Feb 05 12:37:03 2009 +0100 66.3 @@ -0,0 +1,349 @@ 66.4 +\chapter{Mercurial Queues reference} 66.5 +\label{chap:mqref} 66.6 + 66.7 +\section{MQ command reference} 66.8 +\label{sec:mqref:cmdref} 66.9 + 66.10 +For an overview of the commands provided by MQ, use the command 66.11 +\hgcmdargs{help}{mq}. 66.12 + 66.13 +\subsection{\hgxcmd{mq}{qapplied}---print applied patches} 66.14 + 66.15 +The \hgxcmd{mq}{qapplied} command prints the current stack of applied 66.16 +patches. Patches are printed in oldest-to-newest order, so the last 66.17 +patch in the list is the ``top'' patch. 66.18 + 66.19 +\subsection{\hgxcmd{mq}{qcommit}---commit changes in the queue repository} 66.20 + 66.21 +The \hgxcmd{mq}{qcommit} command commits any outstanding changes in the 66.22 +\sdirname{.hg/patches} repository. This command only works if the 66.23 +\sdirname{.hg/patches} directory is a repository, i.e.~you created the 66.24 +directory using \hgcmdargs{qinit}{\hgxopt{mq}{qinit}{-c}} or ran 66.25 +\hgcmd{init} in the directory after running \hgxcmd{mq}{qinit}. 66.26 + 66.27 +This command is shorthand for \hgcmdargs{commit}{--cwd .hg/patches}. 66.28 + 66.29 +\subsection{\hgxcmd{mq}{qdelete}---delete a patch from the 66.30 + \sfilename{series} file} 66.31 + 66.32 +The \hgxcmd{mq}{qdelete} command removes the entry for a patch from the 66.33 +\sfilename{series} file in the \sdirname{.hg/patches} directory. It 66.34 +does not pop the patch if the patch is already applied. By default, 66.35 +it does not delete the patch file; use the \hgxopt{mq}{qdel}{-f} option to 66.36 +do that. 66.37 + 66.38 +Options: 66.39 +\begin{itemize} 66.40 +\item[\hgxopt{mq}{qdel}{-f}] Delete the patch file. 66.41 +\end{itemize} 66.42 + 66.43 +\subsection{\hgxcmd{mq}{qdiff}---print a diff of the topmost applied patch} 66.44 + 66.45 +The \hgxcmd{mq}{qdiff} command prints a diff of the topmost applied patch. 66.46 +It is equivalent to \hgcmdargs{diff}{-r-2:-1}. 66.47 + 66.48 +\subsection{\hgxcmd{mq}{qfold}---merge (``fold'') several patches into one} 66.49 + 66.50 +The \hgxcmd{mq}{qfold} command merges multiple patches into the topmost 66.51 +applied patch, so that the topmost applied patch makes the union of 66.52 +all of the changes in the patches in question. 66.53 + 66.54 +The patches to fold must not be applied; \hgxcmd{mq}{qfold} will exit with 66.55 +an error if any is. The order in which patches are folded is 66.56 +significant; \hgcmdargs{qfold}{a b} means ``apply the current topmost 66.57 +patch, followed by \texttt{a}, followed by \texttt{b}''. 66.58 + 66.59 +The comments from the folded patches are appended to the comments of 66.60 +the destination patch, with each block of comments separated by three 66.61 +asterisk (``\texttt{*}'') characters. Use the \hgxopt{mq}{qfold}{-e} 66.62 +option to edit the commit message for the combined patch/changeset 66.63 +after the folding has completed. 66.64 + 66.65 +Options: 66.66 +\begin{itemize} 66.67 +\item[\hgxopt{mq}{qfold}{-e}] Edit the commit message and patch description 66.68 + for the newly folded patch. 66.69 +\item[\hgxopt{mq}{qfold}{-l}] Use the contents of the given file as the new 66.70 + commit message and patch description for the folded patch. 66.71 +\item[\hgxopt{mq}{qfold}{-m}] Use the given text as the new commit message 66.72 + and patch description for the folded patch. 66.73 +\end{itemize} 66.74 + 66.75 +\subsection{\hgxcmd{mq}{qheader}---display the header/description of a patch} 66.76 + 66.77 +The \hgxcmd{mq}{qheader} command prints the header, or description, of a 66.78 +patch. By default, it prints the header of the topmost applied patch. 66.79 +Given an argument, it prints the header of the named patch. 66.80 + 66.81 +\subsection{\hgxcmd{mq}{qimport}---import a third-party patch into the queue} 66.82 + 66.83 +The \hgxcmd{mq}{qimport} command adds an entry for an external patch to the 66.84 +\sfilename{series} file, and copies the patch into the 66.85 +\sdirname{.hg/patches} directory. It adds the entry immediately after 66.86 +the topmost applied patch, but does not push the patch. 66.87 + 66.88 +If the \sdirname{.hg/patches} directory is a repository, 66.89 +\hgxcmd{mq}{qimport} automatically does an \hgcmd{add} of the imported 66.90 +patch. 66.91 + 66.92 +\subsection{\hgxcmd{mq}{qinit}---prepare a repository to work with MQ} 66.93 + 66.94 +The \hgxcmd{mq}{qinit} command prepares a repository to work with MQ. It 66.95 +creates a directory called \sdirname{.hg/patches}. 66.96 + 66.97 +Options: 66.98 +\begin{itemize} 66.99 +\item[\hgxopt{mq}{qinit}{-c}] Create \sdirname{.hg/patches} as a repository 66.100 + in its own right. Also creates a \sfilename{.hgignore} file that 66.101 + will ignore the \sfilename{status} file. 66.102 +\end{itemize} 66.103 + 66.104 +When the \sdirname{.hg/patches} directory is a repository, the 66.105 +\hgxcmd{mq}{qimport} and \hgxcmd{mq}{qnew} commands automatically \hgcmd{add} 66.106 +new patches. 66.107 + 66.108 +\subsection{\hgxcmd{mq}{qnew}---create a new patch} 66.109 + 66.110 +The \hgxcmd{mq}{qnew} command creates a new patch. It takes one mandatory 66.111 +argument, the name to use for the patch file. The newly created patch 66.112 +is created empty by default. It is added to the \sfilename{series} 66.113 +file after the current topmost applied patch, and is immediately 66.114 +pushed on top of that patch. 66.115 + 66.116 +If \hgxcmd{mq}{qnew} finds modified files in the working directory, it will 66.117 +refuse to create a new patch unless the \hgxopt{mq}{qnew}{-f} option is 66.118 +used (see below). This behaviour allows you to \hgxcmd{mq}{qrefresh} your 66.119 +topmost applied patch before you apply a new patch on top of it. 66.120 + 66.121 +Options: 66.122 +\begin{itemize} 66.123 +\item[\hgxopt{mq}{qnew}{-f}] Create a new patch if the contents of the 66.124 + working directory are modified. Any outstanding modifications are 66.125 + added to the newly created patch, so after this command completes, 66.126 + the working directory will no longer be modified. 66.127 +\item[\hgxopt{mq}{qnew}{-m}] Use the given text as the commit message. 66.128 + This text will be stored at the beginning of the patch file, before 66.129 + the patch data. 66.130 +\end{itemize} 66.131 + 66.132 +\subsection{\hgxcmd{mq}{qnext}---print the name of the next patch} 66.133 + 66.134 +The \hgxcmd{mq}{qnext} command prints the name name of the next patch in 66.135 +the \sfilename{series} file after the topmost applied patch. This 66.136 +patch will become the topmost applied patch if you run \hgxcmd{mq}{qpush}. 66.137 + 66.138 +\subsection{\hgxcmd{mq}{qpop}---pop patches off the stack} 66.139 + 66.140 +The \hgxcmd{mq}{qpop} command removes applied patches from the top of the 66.141 +stack of applied patches. By default, it removes only one patch. 66.142 + 66.143 +This command removes the changesets that represent the popped patches 66.144 +from the repository, and updates the working directory to undo the 66.145 +effects of the patches. 66.146 + 66.147 +This command takes an optional argument, which it uses as the name or 66.148 +index of the patch to pop to. If given a name, it will pop patches 66.149 +until the named patch is the topmost applied patch. If given a 66.150 +number, \hgxcmd{mq}{qpop} treats the number as an index into the entries in 66.151 +the series file, counting from zero (empty lines and lines containing 66.152 +only comments do not count). It pops patches until the patch 66.153 +identified by the given index is the topmost applied patch. 66.154 + 66.155 +The \hgxcmd{mq}{qpop} command does not read or write patches or the 66.156 +\sfilename{series} file. It is thus safe to \hgxcmd{mq}{qpop} a patch that 66.157 +you have removed from the \sfilename{series} file, or a patch that you 66.158 +have renamed or deleted entirely. In the latter two cases, use the 66.159 +name of the patch as it was when you applied it. 66.160 + 66.161 +By default, the \hgxcmd{mq}{qpop} command will not pop any patches if the 66.162 +working directory has been modified. You can override this behaviour 66.163 +using the \hgxopt{mq}{qpop}{-f} option, which reverts all modifications in 66.164 +the working directory. 66.165 + 66.166 +Options: 66.167 +\begin{itemize} 66.168 +\item[\hgxopt{mq}{qpop}{-a}] Pop all applied patches. This returns the 66.169 + repository to its state before you applied any patches. 66.170 +\item[\hgxopt{mq}{qpop}{-f}] Forcibly revert any modifications to the 66.171 + working directory when popping. 66.172 +\item[\hgxopt{mq}{qpop}{-n}] Pop a patch from the named queue. 66.173 +\end{itemize} 66.174 + 66.175 +The \hgxcmd{mq}{qpop} command removes one line from the end of the 66.176 +\sfilename{status} file for each patch that it pops. 66.177 + 66.178 +\subsection{\hgxcmd{mq}{qprev}---print the name of the previous patch} 66.179 + 66.180 +The \hgxcmd{mq}{qprev} command prints the name of the patch in the 66.181 +\sfilename{series} file that comes before the topmost applied patch. 66.182 +This will become the topmost applied patch if you run \hgxcmd{mq}{qpop}. 66.183 + 66.184 +\subsection{\hgxcmd{mq}{qpush}---push patches onto the stack} 66.185 +\label{sec:mqref:cmd:qpush} 66.186 + 66.187 +The \hgxcmd{mq}{qpush} command adds patches onto the applied stack. By 66.188 +default, it adds only one patch. 66.189 + 66.190 +This command creates a new changeset to represent each applied patch, 66.191 +and updates the working directory to apply the effects of the patches. 66.192 + 66.193 +The default data used when creating a changeset are as follows: 66.194 +\begin{itemize} 66.195 +\item The commit date and time zone are the current date and time 66.196 + zone. Because these data are used to compute the identity of a 66.197 + changeset, this means that if you \hgxcmd{mq}{qpop} a patch and 66.198 + \hgxcmd{mq}{qpush} it again, the changeset that you push will have a 66.199 + different identity than the changeset you popped. 66.200 +\item The author is the same as the default used by the \hgcmd{commit} 66.201 + command. 66.202 +\item The commit message is any text from the patch file that comes 66.203 + before the first diff header. If there is no such text, a default 66.204 + commit message is used that identifies the name of the patch. 66.205 +\end{itemize} 66.206 +If a patch contains a Mercurial patch header (XXX add link), the 66.207 +information in the patch header overrides these defaults. 66.208 + 66.209 +Options: 66.210 +\begin{itemize} 66.211 +\item[\hgxopt{mq}{qpush}{-a}] Push all unapplied patches from the 66.212 + \sfilename{series} file until there are none left to push. 66.213 +\item[\hgxopt{mq}{qpush}{-l}] Add the name of the patch to the end 66.214 + of the commit message. 66.215 +\item[\hgxopt{mq}{qpush}{-m}] If a patch fails to apply cleanly, use the 66.216 + entry for the patch in another saved queue to compute the parameters 66.217 + for a three-way merge, and perform a three-way merge using the 66.218 + normal Mercurial merge machinery. Use the resolution of the merge 66.219 + as the new patch content. 66.220 +\item[\hgxopt{mq}{qpush}{-n}] Use the named queue if merging while pushing. 66.221 +\end{itemize} 66.222 + 66.223 +The \hgxcmd{mq}{qpush} command reads, but does not modify, the 66.224 +\sfilename{series} file. It appends one line to the \hgcmd{status} 66.225 +file for each patch that it pushes. 66.226 + 66.227 +\subsection{\hgxcmd{mq}{qrefresh}---update the topmost applied patch} 66.228 + 66.229 +The \hgxcmd{mq}{qrefresh} command updates the topmost applied patch. It 66.230 +modifies the patch, removes the old changeset that represented the 66.231 +patch, and creates a new changeset to represent the modified patch. 66.232 + 66.233 +The \hgxcmd{mq}{qrefresh} command looks for the following modifications: 66.234 +\begin{itemize} 66.235 +\item Changes to the commit message, i.e.~the text before the first 66.236 + diff header in the patch file, are reflected in the new changeset 66.237 + that represents the patch. 66.238 +\item Modifications to tracked files in the working directory are 66.239 + added to the patch. 66.240 +\item Changes to the files tracked using \hgcmd{add}, \hgcmd{copy}, 66.241 + \hgcmd{remove}, or \hgcmd{rename}. Added files and copy and rename 66.242 + destinations are added to the patch, while removed files and rename 66.243 + sources are removed. 66.244 +\end{itemize} 66.245 + 66.246 +Even if \hgxcmd{mq}{qrefresh} detects no changes, it still recreates the 66.247 +changeset that represents the patch. This causes the identity of the 66.248 +changeset to differ from the previous changeset that identified the 66.249 +patch. 66.250 + 66.251 +Options: 66.252 +\begin{itemize} 66.253 +\item[\hgxopt{mq}{qrefresh}{-e}] Modify the commit and patch description, 66.254 + using the preferred text editor. 66.255 +\item[\hgxopt{mq}{qrefresh}{-m}] Modify the commit message and patch 66.256 + description, using the given text. 66.257 +\item[\hgxopt{mq}{qrefresh}{-l}] Modify the commit message and patch 66.258 + description, using text from the given file. 66.259 +\end{itemize} 66.260 + 66.261 +\subsection{\hgxcmd{mq}{qrename}---rename a patch} 66.262 + 66.263 +The \hgxcmd{mq}{qrename} command renames a patch, and changes the entry for 66.264 +the patch in the \sfilename{series} file. 66.265 + 66.266 +With a single argument, \hgxcmd{mq}{qrename} renames the topmost applied 66.267 +patch. With two arguments, it renames its first argument to its 66.268 +second. 66.269 + 66.270 +\subsection{\hgxcmd{mq}{qrestore}---restore saved queue state} 66.271 + 66.272 +XXX No idea what this does. 66.273 + 66.274 +\subsection{\hgxcmd{mq}{qsave}---save current queue state} 66.275 + 66.276 +XXX Likewise. 66.277 + 66.278 +\subsection{\hgxcmd{mq}{qseries}---print the entire patch series} 66.279 + 66.280 +The \hgxcmd{mq}{qseries} command prints the entire patch series from the 66.281 +\sfilename{series} file. It prints only patch names, not empty lines 66.282 +or comments. It prints in order from first to be applied to last. 66.283 + 66.284 +\subsection{\hgxcmd{mq}{qtop}---print the name of the current patch} 66.285 + 66.286 +The \hgxcmd{mq}{qtop} prints the name of the topmost currently applied 66.287 +patch. 66.288 + 66.289 +\subsection{\hgxcmd{mq}{qunapplied}---print patches not yet applied} 66.290 + 66.291 +The \hgxcmd{mq}{qunapplied} command prints the names of patches from the 66.292 +\sfilename{series} file that are not yet applied. It prints them in 66.293 +order from the next patch that will be pushed to the last. 66.294 + 66.295 +\subsection{\hgcmd{strip}---remove a revision and descendants} 66.296 + 66.297 +The \hgcmd{strip} command removes a revision, and all of its 66.298 +descendants, from the repository. It undoes the effects of the 66.299 +removed revisions from the repository, and updates the working 66.300 +directory to the first parent of the removed revision. 66.301 + 66.302 +The \hgcmd{strip} command saves a backup of the removed changesets in 66.303 +a bundle, so that they can be reapplied if removed in error. 66.304 + 66.305 +Options: 66.306 +\begin{itemize} 66.307 +\item[\hgopt{strip}{-b}] Save unrelated changesets that are intermixed 66.308 + with the stripped changesets in the backup bundle. 66.309 +\item[\hgopt{strip}{-f}] If a branch has multiple heads, remove all 66.310 + heads. XXX This should be renamed, and use \texttt{-f} to strip revs 66.311 + when there are pending changes. 66.312 +\item[\hgopt{strip}{-n}] Do not save a backup bundle. 66.313 +\end{itemize} 66.314 + 66.315 +\section{MQ file reference} 66.316 + 66.317 +\subsection{The \sfilename{series} file} 66.318 + 66.319 +The \sfilename{series} file contains a list of the names of all 66.320 +patches that MQ can apply. It is represented as a list of names, with 66.321 +one name saved per line. Leading and trailing white space in each 66.322 +line are ignored. 66.323 + 66.324 +Lines may contain comments. A comment begins with the ``\texttt{\#}'' 66.325 +character, and extends to the end of the line. Empty lines, and lines 66.326 +that contain only comments, are ignored. 66.327 + 66.328 +You will often need to edit the \sfilename{series} file by hand, hence 66.329 +the support for comments and empty lines noted above. For example, 66.330 +you can comment out a patch temporarily, and \hgxcmd{mq}{qpush} will skip 66.331 +over that patch when applying patches. You can also change the order 66.332 +in which patches are applied by reordering their entries in the 66.333 +\sfilename{series} file. 66.334 + 66.335 +Placing the \sfilename{series} file under revision control is also 66.336 +supported; it is a good idea to place all of the patches that it 66.337 +refers to under revision control, as well. If you create a patch 66.338 +directory using the \hgxopt{mq}{qinit}{-c} option to \hgxcmd{mq}{qinit}, this 66.339 +will be done for you automatically. 66.340 + 66.341 +\subsection{The \sfilename{status} file} 66.342 + 66.343 +The \sfilename{status} file contains the names and changeset hashes of 66.344 +all patches that MQ currently has applied. Unlike the 66.345 +\sfilename{series} file, this file is not intended for editing. You 66.346 +should not place this file under revision control, or modify it in any 66.347 +way. It is used by MQ strictly for internal book-keeping. 66.348 + 66.349 +%%% Local Variables: 66.350 +%%% mode: latex 66.351 +%%% TeX-master: "00book" 66.352 +%%% End:
67.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 67.2 +++ b/fr/mq-stack.svg Thu Feb 05 12:37:03 2009 +0100 67.3 @@ -0,0 +1,270 @@ 67.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 67.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 67.6 +<svg 67.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 67.8 + xmlns:cc="http://web.resource.org/cc/" 67.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 67.10 + xmlns:svg="http://www.w3.org/2000/svg" 67.11 + xmlns="http://www.w3.org/2000/svg" 67.12 + xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" 67.13 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 67.14 + width="744.09448819" 67.15 + height="1052.3622047" 67.16 + id="svg2" 67.17 + sodipodi:version="0.32" 67.18 + inkscape:version="0.43" 67.19 + sodipodi:docname="mq-stack.svg" 67.20 + sodipodi:docbase="/home/bos/hg/hgbook/en"> 67.21 + <defs 67.22 + id="defs4" /> 67.23 + <sodipodi:namedview 67.24 + id="base" 67.25 + pagecolor="#ffffff" 67.26 + bordercolor="#666666" 67.27 + borderopacity="1.0" 67.28 + inkscape:pageopacity="0.0" 67.29 + inkscape:pageshadow="2" 67.30 + inkscape:zoom="1.4142136" 67.31 + inkscape:cx="299.33323" 67.32 + inkscape:cy="815.646" 67.33 + inkscape:document-units="px" 67.34 + inkscape:current-layer="layer1" 67.35 + inkscape:window-width="1014" 67.36 + inkscape:window-height="689" 67.37 + inkscape:window-x="0" 67.38 + inkscape:window-y="25" /> 67.39 + <metadata 67.40 + id="metadata7"> 67.41 + <rdf:RDF> 67.42 + <cc:Work 67.43 + rdf:about=""> 67.44 + <dc:format>image/svg+xml</dc:format> 67.45 + <dc:type 67.46 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 67.47 + </cc:Work> 67.48 + </rdf:RDF> 67.49 + </metadata> 67.50 + <g 67.51 + inkscape:label="Layer 1" 67.52 + inkscape:groupmode="layer" 67.53 + id="layer1"> 67.54 + <rect 67.55 + style="fill:#0000ff;fill-opacity:0.75;fill-rule:evenodd;stroke:#3c3c3c;stroke-width:1.05063355px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 67.56 + id="rect1307" 67.57 + width="202.93683" 67.58 + height="24.243662" 67.59 + x="230.01944" 67.60 + y="221.70146" /> 67.61 + <text 67.62 + xml:space="preserve" 67.63 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.64 + x="237.89606" 67.65 + y="237.13383" 67.66 + id="text1309"><tspan 67.67 + sodipodi:role="line" 67.68 + id="tspan1311" 67.69 + x="237.89606" 67.70 + y="237.13383">prevent-compiler-reorder.patch</tspan></text> 67.71 + <rect 67.72 + style="fill:#7979ff;fill-opacity:0.875;fill-rule:evenodd;stroke:#3c3c3c;stroke-width:1.05063355px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 67.73 + id="rect1320" 67.74 + width="202.93683" 67.75 + height="24.243662" 67.76 + x="230.01936" 67.77 + y="251.34325" /> 67.78 + <text 67.79 + xml:space="preserve" 67.80 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.81 + x="237.89598" 67.82 + y="266.77563" 67.83 + id="text1322"><tspan 67.84 + sodipodi:role="line" 67.85 + id="tspan1324" 67.86 + x="237.89598" 67.87 + y="266.77563">namespace-cleanup.patch</tspan></text> 67.88 + <rect 67.89 + style="fill:#7979ff;fill-opacity:0.875;fill-rule:evenodd;stroke:#3c3c3c;stroke-width:1.05063355px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 67.90 + id="rect2217" 67.91 + width="202.93683" 67.92 + height="24.243662" 67.93 + x="230.01936" 67.94 + y="280.98505" /> 67.95 + <text 67.96 + xml:space="preserve" 67.97 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.98 + x="237.89598" 67.99 + y="296.41742" 67.100 + id="text2219"><tspan 67.101 + sodipodi:role="line" 67.102 + id="tspan2221" 67.103 + x="237.89598" 67.104 + y="296.41742">powerpc-port-fixes.patch</tspan></text> 67.105 + <rect 67.106 + style="fill:#7979ff;fill-opacity:0.875;fill-rule:evenodd;stroke:#3c3c3c;stroke-width:1.05063355px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 67.107 + id="rect3114" 67.108 + width="202.93683" 67.109 + height="24.243662" 67.110 + x="230.01936" 67.111 + y="310.6268" /> 67.112 + <text 67.113 + xml:space="preserve" 67.114 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.115 + x="237.89598" 67.116 + y="326.05917" 67.117 + id="text3116"><tspan 67.118 + sodipodi:role="line" 67.119 + id="tspan3118" 67.120 + x="237.89598" 67.121 + y="326.05917">report-devinfo-correctly.patch</tspan></text> 67.122 + <text 67.123 + xml:space="preserve" 67.124 + style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.125 + x="200.01021" 67.126 + y="191.68094" 67.127 + id="text3170" 67.128 + sodipodi:linespacing="125%"><tspan 67.129 + sodipodi:role="line" 67.130 + id="tspan3172" 67.131 + x="200.01021" 67.132 + y="191.68094" 67.133 + style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">{</tspan></text> 67.134 + <text 67.135 + xml:space="preserve" 67.136 + style="font-size:15.25329685px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.137 + x="255.26627" 67.138 + y="248.79449" 67.139 + id="text3190" 67.140 + sodipodi:linespacing="125%" 67.141 + transform="scale(0.786716,1.271107)"><tspan 67.142 + sodipodi:role="line" 67.143 + id="tspan3192" 67.144 + x="255.26627" 67.145 + y="248.79449" 67.146 + style="font-size:61.01318741px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">{</tspan></text> 67.147 + <text 67.148 + xml:space="preserve" 67.149 + style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.150 + x="195.86807" 67.151 + y="173.17117" 67.152 + id="text4085" 67.153 + sodipodi:linespacing="125%"><tspan 67.154 + sodipodi:role="line" 67.155 + id="tspan4087" 67.156 + x="195.86807" 67.157 + y="173.17117" 67.158 + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;writing-mode:lr-tb;text-anchor:end;font-family:Bitstream Vera Sans">present in series,</tspan><tspan 67.159 + sodipodi:role="line" 67.160 + x="195.86807" 67.161 + y="188.17117" 67.162 + id="tspan4089" 67.163 + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;writing-mode:lr-tb;text-anchor:end;font-family:Bitstream Vera Sans">but not applied</tspan></text> 67.164 + <text 67.165 + xml:space="preserve" 67.166 + style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.167 + x="195.0712" 67.168 + y="288.91745" 67.169 + id="text4091" 67.170 + sodipodi:linespacing="125%"><tspan 67.171 + sodipodi:role="line" 67.172 + id="tspan4093" 67.173 + x="195.0712" 67.174 + y="288.91745" 67.175 + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;writing-mode:lr-tb;text-anchor:end;font-family:Bitstream Vera Sans">patches applied,</tspan><tspan 67.176 + sodipodi:role="line" 67.177 + x="195.0712" 67.178 + y="303.91745" 67.179 + id="tspan4111" 67.180 + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;writing-mode:lr-tb;text-anchor:end;font-family:Bitstream Vera Sans">changesets present</tspan></text> 67.181 + <text 67.182 + xml:space="preserve" 67.183 + style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.184 + x="195.0712" 67.185 + y="229.28813" 67.186 + id="text4095" 67.187 + sodipodi:linespacing="125%"><tspan 67.188 + sodipodi:role="line" 67.189 + id="tspan4097" 67.190 + x="195.0712" 67.191 + y="229.28813" 67.192 + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;writing-mode:lr-tb;text-anchor:end;font-family:Bitstream Vera Sans">topmost</tspan><tspan 67.193 + sodipodi:role="line" 67.194 + x="195.0712" 67.195 + y="244.28813" 67.196 + id="tspan4109" 67.197 + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;writing-mode:lr-tb;text-anchor:end;font-family:Bitstream Vera Sans">applied patch</tspan></text> 67.198 + <text 67.199 + xml:space="preserve" 67.200 + style="font-size:12px;font-style:normal;font-weight:normal;opacity:1;fill:#666666;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.201 + x="450.4975" 67.202 + y="238.29692" 67.203 + id="text4137"><tspan 67.204 + sodipodi:role="line" 67.205 + id="tspan4139" 67.206 + x="450.4975" 67.207 + y="238.29692">201ad3209902</tspan></text> 67.208 + <text 67.209 + xml:space="preserve" 67.210 + style="font-size:12px;font-style:normal;font-weight:normal;opacity:1;fill:#989898;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.211 + x="450.05804" 67.212 + y="267.93872" 67.213 + id="text4141"><tspan 67.214 + sodipodi:role="line" 67.215 + id="tspan4143" 67.216 + x="450.05804" 67.217 + y="267.93872">126b84e593ae</tspan></text> 67.218 + <text 67.219 + xml:space="preserve" 67.220 + style="font-size:12px;font-style:normal;font-weight:normal;opacity:1;fill:#989898;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.221 + x="450.6557" 67.222 + y="297.58051" 67.223 + id="text4145"><tspan 67.224 + sodipodi:role="line" 67.225 + id="tspan4147" 67.226 + x="450.6557" 67.227 + y="297.58051">a655daf15409</tspan></text> 67.228 + <text 67.229 + xml:space="preserve" 67.230 + style="font-size:12px;font-style:normal;font-weight:normal;opacity:1;fill:#989898;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.231 + x="450.71429" 67.232 + y="327.22226" 67.233 + id="text4149"><tspan 67.234 + sodipodi:role="line" 67.235 + id="tspan4151" 67.236 + x="450.71429" 67.237 + y="327.22226">e50d59aaea3a</tspan></text> 67.238 + <rect 67.239 + style="fill:#d7d7ff;fill-opacity:0.875;fill-rule:evenodd;stroke:#a6a6a6;stroke-width:1.05063355px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 67.240 + id="rect3106" 67.241 + width="202.93683" 67.242 + height="24.243662" 67.243 + x="230.01936" 67.244 + y="150.41792" /> 67.245 + <text 67.246 + xml:space="preserve" 67.247 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#808080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.248 + x="237.89598" 67.249 + y="165.8503" 67.250 + id="text3108"><tspan 67.251 + sodipodi:role="line" 67.252 + id="tspan3110" 67.253 + x="237.89598" 67.254 + y="165.8503">forbid-illegal-params.patch</tspan></text> 67.255 + <rect 67.256 + style="fill:#d7d7ff;fill-opacity:0.875;fill-rule:evenodd;stroke:#a6a6a6;stroke-width:1.05063355px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 67.257 + id="rect2241" 67.258 + width="202.93683" 67.259 + height="24.243662" 67.260 + x="230.16466" 67.261 + y="180.05968" /> 67.262 + <text 67.263 + xml:space="preserve" 67.264 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#808080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" 67.265 + x="238.04128" 67.266 + y="195.49205" 67.267 + id="text2243"><tspan 67.268 + sodipodi:role="line" 67.269 + id="tspan2245" 67.270 + x="238.04128" 67.271 + y="195.49205">fix-memory-leak.patch</tspan></text> 67.272 + </g> 67.273 +</svg>
68.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 68.2 +++ b/fr/mq.tex Thu Feb 05 12:37:03 2009 +0100 68.3 @@ -0,0 +1,1043 @@ 68.4 +\chapter{Managing change with Mercurial Queues} 68.5 +\label{chap:mq} 68.6 + 68.7 +\section{The patch management problem} 68.8 +\label{sec:mq:patch-mgmt} 68.9 + 68.10 +Here is a common scenario: you need to install a software package from 68.11 +source, but you find a bug that you must fix in the source before you 68.12 +can start using the package. You make your changes, forget about the 68.13 +package for a while, and a few months later you need to upgrade to a 68.14 +newer version of the package. If the newer version of the package 68.15 +still has the bug, you must extract your fix from the older source 68.16 +tree and apply it against the newer version. This is a tedious task, 68.17 +and it's easy to make mistakes. 68.18 + 68.19 +This is a simple case of the ``patch management'' problem. You have 68.20 +an ``upstream'' source tree that you can't change; you need to make 68.21 +some local changes on top of the upstream tree; and you'd like to be 68.22 +able to keep those changes separate, so that you can apply them to 68.23 +newer versions of the upstream source. 68.24 + 68.25 +The patch management problem arises in many situations. Probably the 68.26 +most visible is that a user of an open source software project will 68.27 +contribute a bug fix or new feature to the project's maintainers in the 68.28 +form of a patch. 68.29 + 68.30 +Distributors of operating systems that include open source software 68.31 +often need to make changes to the packages they distribute so that 68.32 +they will build properly in their environments. 68.33 + 68.34 +When you have few changes to maintain, it is easy to manage a single 68.35 +patch using the standard \command{diff} and \command{patch} programs 68.36 +(see section~\ref{sec:mq:patch} for a discussion of these tools). 68.37 +Once the number of changes grows, it starts to make sense to maintain 68.38 +patches as discrete ``chunks of work,'' so that for example a single 68.39 +patch will contain only one bug fix (the patch might modify several 68.40 +files, but it's doing ``only one thing''), and you may have a number 68.41 +of such patches for different bugs you need fixed and local changes 68.42 +you require. In this situation, if you submit a bug fix patch to the 68.43 +upstream maintainers of a package and they include your fix in a 68.44 +subsequent release, you can simply drop that single patch when you're 68.45 +updating to the newer release. 68.46 + 68.47 +Maintaining a single patch against an upstream tree is a little 68.48 +tedious and error-prone, but not difficult. However, the complexity 68.49 +of the problem grows rapidly as the number of patches you have to 68.50 +maintain increases. With more than a tiny number of patches in hand, 68.51 +understanding which ones you have applied and maintaining them moves 68.52 +from messy to overwhelming. 68.53 + 68.54 +Fortunately, Mercurial includes a powerful extension, Mercurial Queues 68.55 +(or simply ``MQ''), that massively simplifies the patch management 68.56 +problem. 68.57 + 68.58 +\section{The prehistory of Mercurial Queues} 68.59 +\label{sec:mq:history} 68.60 + 68.61 +During the late 1990s, several Linux kernel developers started to 68.62 +maintain ``patch series'' that modified the behaviour of the Linux 68.63 +kernel. Some of these series were focused on stability, some on 68.64 +feature coverage, and others were more speculative. 68.65 + 68.66 +The sizes of these patch series grew rapidly. In 2002, Andrew Morton 68.67 +published some shell scripts he had been using to automate the task of 68.68 +managing his patch queues. Andrew was successfully using these 68.69 +scripts to manage hundreds (sometimes thousands) of patches on top of 68.70 +the Linux kernel. 68.71 + 68.72 +\subsection{A patchwork quilt} 68.73 +\label{sec:mq:quilt} 68.74 + 68.75 +In early 2003, Andreas Gruenbacher and Martin Quinson borrowed the 68.76 +approach of Andrew's scripts and published a tool called ``patchwork 68.77 +quilt''~\cite{web:quilt}, or simply ``quilt'' 68.78 +(see~\cite{gruenbacher:2005} for a paper describing it). Because 68.79 +quilt substantially automated patch management, it rapidly gained a 68.80 +large following among open source software developers. 68.81 + 68.82 +Quilt manages a \emph{stack of patches} on top of a directory tree. 68.83 +To begin, you tell quilt to manage a directory tree, and tell it which 68.84 +files you want to manage; it stores away the names and contents of 68.85 +those files. To fix a bug, you create a new patch (using a single 68.86 +command), edit the files you need to fix, then ``refresh'' the patch. 68.87 + 68.88 +The refresh step causes quilt to scan the directory tree; it updates 68.89 +the patch with all of the changes you have made. You can create 68.90 +another patch on top of the first, which will track the changes 68.91 +required to modify the tree from ``tree with one patch applied'' to 68.92 +``tree with two patches applied''. 68.93 + 68.94 +You can \emph{change} which patches are applied to the tree. If you 68.95 +``pop'' a patch, the changes made by that patch will vanish from the 68.96 +directory tree. Quilt remembers which patches you have popped, 68.97 +though, so you can ``push'' a popped patch again, and the directory 68.98 +tree will be restored to contain the modifications in the patch. Most 68.99 +importantly, you can run the ``refresh'' command at any time, and the 68.100 +topmost applied patch will be updated. This means that you can, at 68.101 +any time, change both which patches are applied and what 68.102 +modifications those patches make. 68.103 + 68.104 +Quilt knows nothing about revision control tools, so it works equally 68.105 +well on top of an unpacked tarball or a Subversion working copy. 68.106 + 68.107 +\subsection{From patchwork quilt to Mercurial Queues} 68.108 +\label{sec:mq:quilt-mq} 68.109 + 68.110 +In mid-2005, Chris Mason took the features of quilt and wrote an 68.111 +extension that he called Mercurial Queues, which added quilt-like 68.112 +behaviour to Mercurial. 68.113 + 68.114 +The key difference between quilt and MQ is that quilt knows nothing 68.115 +about revision control systems, while MQ is \emph{integrated} into 68.116 +Mercurial. Each patch that you push is represented as a Mercurial 68.117 +changeset. Pop a patch, and the changeset goes away. 68.118 + 68.119 +Because quilt does not care about revision control tools, it is still 68.120 +a tremendously useful piece of software to know about for situations 68.121 +where you cannot use Mercurial and MQ. 68.122 + 68.123 +\section{The huge advantage of MQ} 68.124 + 68.125 +I cannot overstate the value that MQ offers through the unification of 68.126 +patches and revision control. 68.127 + 68.128 +A major reason that patches have persisted in the free software and 68.129 +open source world---in spite of the availability of increasingly 68.130 +capable revision control tools over the years---is the \emph{agility} 68.131 +they offer. 68.132 + 68.133 +Traditional revision control tools make a permanent, irreversible 68.134 +record of everything that you do. While this has great value, it's 68.135 +also somewhat stifling. If you want to perform a wild-eyed 68.136 +experiment, you have to be careful in how you go about it, or you risk 68.137 +leaving unneeded---or worse, misleading or destabilising---traces of 68.138 +your missteps and errors in the permanent revision record. 68.139 + 68.140 +By contrast, MQ's marriage of distributed revision control with 68.141 +patches makes it much easier to isolate your work. Your patches live 68.142 +on top of normal revision history, and you can make them disappear or 68.143 +reappear at will. If you don't like a patch, you can drop it. If a 68.144 +patch isn't quite as you want it to be, simply fix it---as many times 68.145 +as you need to, until you have refined it into the form you desire. 68.146 + 68.147 +As an example, the integration of patches with revision control makes 68.148 +understanding patches and debugging their effects---and their 68.149 +interplay with the code they're based on---\emph{enormously} easier. 68.150 +Since every applied patch has an associated changeset, you can use 68.151 +\hgcmdargs{log}{\emph{filename}} to see which changesets and patches 68.152 +affected a file. You can use the \hgext{bisect} command to 68.153 +binary-search through all changesets and applied patches to see where 68.154 +a bug got introduced or fixed. You can use the \hgcmd{annotate} 68.155 +command to see which changeset or patch modified a particular line of 68.156 +a source file. And so on. 68.157 + 68.158 +\section{Understanding patches} 68.159 +\label{sec:mq:patch} 68.160 + 68.161 +Because MQ doesn't hide its patch-oriented nature, it is helpful to 68.162 +understand what patches are, and a little about the tools that work 68.163 +with them. 68.164 + 68.165 +The traditional Unix \command{diff} command compares two files, and 68.166 +prints a list of differences between them. The \command{patch} command 68.167 +understands these differences as \emph{modifications} to make to a 68.168 +file. Take a look at figure~\ref{ex:mq:diff} for a simple example of 68.169 +these commands in action. 68.170 + 68.171 +\begin{figure}[ht] 68.172 + \interaction{mq.dodiff.diff} 68.173 + \caption{Simple uses of the \command{diff} and \command{patch} commands} 68.174 + \label{ex:mq:diff} 68.175 +\end{figure} 68.176 + 68.177 +The type of file that \command{diff} generates (and \command{patch} 68.178 +takes as input) is called a ``patch'' or a ``diff''; there is no 68.179 +difference between a patch and a diff. (We'll use the term ``patch'', 68.180 +since it's more commonly used.) 68.181 + 68.182 +A patch file can start with arbitrary text; the \command{patch} 68.183 +command ignores this text, but MQ uses it as the commit message when 68.184 +creating changesets. To find the beginning of the patch content, 68.185 +\command{patch} searches for the first line that starts with the 68.186 +string ``\texttt{diff~-}''. 68.187 + 68.188 +MQ works with \emph{unified} diffs (\command{patch} can accept several 68.189 +other diff formats, but MQ doesn't). A unified diff contains two 68.190 +kinds of header. The \emph{file header} describes the file being 68.191 +modified; it contains the name of the file to modify. When 68.192 +\command{patch} sees a new file header, it looks for a file with that 68.193 +name to start modifying. 68.194 + 68.195 +After the file header comes a series of \emph{hunks}. Each hunk 68.196 +starts with a header; this identifies the range of line numbers within 68.197 +the file that the hunk should modify. Following the header, a hunk 68.198 +starts and ends with a few (usually three) lines of text from the 68.199 +unmodified file; these are called the \emph{context} for the hunk. If 68.200 +there's only a small amount of context between successive hunks, 68.201 +\command{diff} doesn't print a new hunk header; it just runs the hunks 68.202 +together, with a few lines of context between modifications. 68.203 + 68.204 +Each line of context begins with a space character. Within the hunk, 68.205 +a line that begins with ``\texttt{-}'' means ``remove this line,'' 68.206 +while a line that begins with ``\texttt{+}'' means ``insert this 68.207 +line.'' For example, a line that is modified is represented by one 68.208 +deletion and one insertion. 68.209 + 68.210 +We will return to some of the more subtle aspects of patches later (in 68.211 +section~\ref{sec:mq:adv-patch}), but you should have enough information 68.212 +now to use MQ. 68.213 + 68.214 +\section{Getting started with Mercurial Queues} 68.215 +\label{sec:mq:start} 68.216 + 68.217 +Because MQ is implemented as an extension, you must explicitly enable 68.218 +before you can use it. (You don't need to download anything; MQ ships 68.219 +with the standard Mercurial distribution.) To enable MQ, edit your 68.220 +\tildefile{.hgrc} file, and add the lines in figure~\ref{ex:mq:config}. 68.221 + 68.222 +\begin{figure}[ht] 68.223 + \begin{codesample4} 68.224 + [extensions] 68.225 + hgext.mq = 68.226 + \end{codesample4} 68.227 + \label{ex:mq:config} 68.228 + \caption{Contents to add to \tildefile{.hgrc} to enable the MQ extension} 68.229 +\end{figure} 68.230 + 68.231 +Once the extension is enabled, it will make a number of new commands 68.232 +available. To verify that the extension is working, you can use 68.233 +\hgcmd{help} to see if the \hgxcmd{mq}{qinit} command is now available; see 68.234 +the example in figure~\ref{ex:mq:enabled}. 68.235 + 68.236 +\begin{figure}[ht] 68.237 + \interaction{mq.qinit-help.help} 68.238 + \caption{How to verify that MQ is enabled} 68.239 + \label{ex:mq:enabled} 68.240 +\end{figure} 68.241 + 68.242 +You can use MQ with \emph{any} Mercurial repository, and its commands 68.243 +only operate within that repository. To get started, simply prepare 68.244 +the repository using the \hgxcmd{mq}{qinit} command (see 68.245 +figure~\ref{ex:mq:qinit}). This command creates an empty directory 68.246 +called \sdirname{.hg/patches}, where MQ will keep its metadata. As 68.247 +with many Mercurial commands, the \hgxcmd{mq}{qinit} command prints nothing 68.248 +if it succeeds. 68.249 + 68.250 +\begin{figure}[ht] 68.251 + \interaction{mq.tutorial.qinit} 68.252 + \caption{Preparing a repository for use with MQ} 68.253 + \label{ex:mq:qinit} 68.254 +\end{figure} 68.255 + 68.256 +\begin{figure}[ht] 68.257 + \interaction{mq.tutorial.qnew} 68.258 + \caption{Creating a new patch} 68.259 + \label{ex:mq:qnew} 68.260 +\end{figure} 68.261 + 68.262 +\subsection{Creating a new patch} 68.263 + 68.264 +To begin work on a new patch, use the \hgxcmd{mq}{qnew} command. This 68.265 +command takes one argument, the name of the patch to create. MQ will 68.266 +use this as the name of an actual file in the \sdirname{.hg/patches} 68.267 +directory, as you can see in figure~\ref{ex:mq:qnew}. 68.268 + 68.269 +Also newly present in the \sdirname{.hg/patches} directory are two 68.270 +other files, \sfilename{series} and \sfilename{status}. The 68.271 +\sfilename{series} file lists all of the patches that MQ knows about 68.272 +for this repository, with one patch per line. Mercurial uses the 68.273 +\sfilename{status} file for internal book-keeping; it tracks all of the 68.274 +patches that MQ has \emph{applied} in this repository. 68.275 + 68.276 +\begin{note} 68.277 + You may sometimes want to edit the \sfilename{series} file by hand; 68.278 + for example, to change the sequence in which some patches are 68.279 + applied. However, manually editing the \sfilename{status} file is 68.280 + almost always a bad idea, as it's easy to corrupt MQ's idea of what 68.281 + is happening. 68.282 +\end{note} 68.283 + 68.284 +Once you have created your new patch, you can edit files in the 68.285 +working directory as you usually would. All of the normal Mercurial 68.286 +commands, such as \hgcmd{diff} and \hgcmd{annotate}, work exactly as 68.287 +they did before. 68.288 + 68.289 +\subsection{Refreshing a patch} 68.290 + 68.291 +When you reach a point where you want to save your work, use the 68.292 +\hgxcmd{mq}{qrefresh} command (figure~\ref{ex:mq:qnew}) to update the patch 68.293 +you are working on. This command folds the changes you have made in 68.294 +the working directory into your patch, and updates its corresponding 68.295 +changeset to contain those changes. 68.296 + 68.297 +\begin{figure}[ht] 68.298 + \interaction{mq.tutorial.qrefresh} 68.299 + \caption{Refreshing a patch} 68.300 + \label{ex:mq:qrefresh} 68.301 +\end{figure} 68.302 + 68.303 +You can run \hgxcmd{mq}{qrefresh} as often as you like, so it's a good way 68.304 +to ``checkpoint'' your work. Refresh your patch at an opportune 68.305 +time; try an experiment; and if the experiment doesn't work out, 68.306 +\hgcmd{revert} your modifications back to the last time you refreshed. 68.307 + 68.308 +\begin{figure}[ht] 68.309 + \interaction{mq.tutorial.qrefresh2} 68.310 + \caption{Refresh a patch many times to accumulate changes} 68.311 + \label{ex:mq:qrefresh2} 68.312 +\end{figure} 68.313 + 68.314 +\subsection{Stacking and tracking patches} 68.315 + 68.316 +Once you have finished working on a patch, or need to work on another, 68.317 +you can use the \hgxcmd{mq}{qnew} command again to create a new patch. 68.318 +Mercurial will apply this patch on top of your existing patch. See 68.319 +figure~\ref{ex:mq:qnew2} for an example. Notice that the patch 68.320 +contains the changes in our prior patch as part of its context (you 68.321 +can see this more clearly in the output of \hgcmd{annotate}). 68.322 + 68.323 +\begin{figure}[ht] 68.324 + \interaction{mq.tutorial.qnew2} 68.325 + \caption{Stacking a second patch on top of the first} 68.326 + \label{ex:mq:qnew2} 68.327 +\end{figure} 68.328 + 68.329 +So far, with the exception of \hgxcmd{mq}{qnew} and \hgxcmd{mq}{qrefresh}, we've 68.330 +been careful to only use regular Mercurial commands. However, MQ 68.331 +provides many commands that are easier to use when you are thinking 68.332 +about patches, as illustrated in figure~\ref{ex:mq:qseries}: 68.333 + 68.334 +\begin{itemize} 68.335 +\item The \hgxcmd{mq}{qseries} command lists every patch that MQ knows 68.336 + about in this repository, from oldest to newest (most recently 68.337 + \emph{created}). 68.338 +\item The \hgxcmd{mq}{qapplied} command lists every patch that MQ has 68.339 + \emph{applied} in this repository, again from oldest to newest (most 68.340 + recently applied). 68.341 +\end{itemize} 68.342 + 68.343 +\begin{figure}[ht] 68.344 + \interaction{mq.tutorial.qseries} 68.345 + \caption{Understanding the patch stack with \hgxcmd{mq}{qseries} and 68.346 + \hgxcmd{mq}{qapplied}} 68.347 + \label{ex:mq:qseries} 68.348 +\end{figure} 68.349 + 68.350 +\subsection{Manipulating the patch stack} 68.351 + 68.352 +The previous discussion implied that there must be a difference 68.353 +between ``known'' and ``applied'' patches, and there is. MQ can 68.354 +manage a patch without it being applied in the repository. 68.355 + 68.356 +An \emph{applied} patch has a corresponding changeset in the 68.357 +repository, and the effects of the patch and changeset are visible in 68.358 +the working directory. You can undo the application of a patch using 68.359 +the \hgxcmd{mq}{qpop} command. MQ still \emph{knows about}, or manages, a 68.360 +popped patch, but the patch no longer has a corresponding changeset in 68.361 +the repository, and the working directory does not contain the changes 68.362 +made by the patch. Figure~\ref{fig:mq:stack} illustrates the 68.363 +difference between applied and tracked patches. 68.364 + 68.365 +\begin{figure}[ht] 68.366 + \centering 68.367 + \grafix{mq-stack} 68.368 + \caption{Applied and unapplied patches in the MQ patch stack} 68.369 + \label{fig:mq:stack} 68.370 +\end{figure} 68.371 + 68.372 +You can reapply an unapplied, or popped, patch using the \hgxcmd{mq}{qpush} 68.373 +command. This creates a new changeset to correspond to the patch, and 68.374 +the patch's changes once again become present in the working 68.375 +directory. See figure~\ref{ex:mq:qpop} for examples of \hgxcmd{mq}{qpop} 68.376 +and \hgxcmd{mq}{qpush} in action. Notice that once we have popped a patch 68.377 +or two patches, the output of \hgxcmd{mq}{qseries} remains the same, while 68.378 +that of \hgxcmd{mq}{qapplied} has changed. 68.379 + 68.380 +\begin{figure}[ht] 68.381 + \interaction{mq.tutorial.qpop} 68.382 + \caption{Modifying the stack of applied patches} 68.383 + \label{ex:mq:qpop} 68.384 +\end{figure} 68.385 + 68.386 +\subsection{Pushing and popping many patches} 68.387 + 68.388 +While \hgxcmd{mq}{qpush} and \hgxcmd{mq}{qpop} each operate on a single patch at 68.389 +a time by default, you can push and pop many patches in one go. The 68.390 +\hgxopt{mq}{qpush}{-a} option to \hgxcmd{mq}{qpush} causes it to push all 68.391 +unapplied patches, while the \hgxopt{mq}{qpop}{-a} option to \hgxcmd{mq}{qpop} 68.392 +causes it to pop all applied patches. (For some more ways to push and 68.393 +pop many patches, see section~\ref{sec:mq:perf} below.) 68.394 + 68.395 +\begin{figure}[ht] 68.396 + \interaction{mq.tutorial.qpush-a} 68.397 + \caption{Pushing all unapplied patches} 68.398 + \label{ex:mq:qpush-a} 68.399 +\end{figure} 68.400 + 68.401 +\subsection{Safety checks, and overriding them} 68.402 + 68.403 +Several MQ commands check the working directory before they do 68.404 +anything, and fail if they find any modifications. They do this to 68.405 +ensure that you won't lose any changes that you have made, but not yet 68.406 +incorporated into a patch. Figure~\ref{ex:mq:add} illustrates this; 68.407 +the \hgxcmd{mq}{qnew} command will not create a new patch if there are 68.408 +outstanding changes, caused in this case by the \hgcmd{add} of 68.409 +\filename{file3}. 68.410 + 68.411 +\begin{figure}[ht] 68.412 + \interaction{mq.tutorial.add} 68.413 + \caption{Forcibly creating a patch} 68.414 + \label{ex:mq:add} 68.415 +\end{figure} 68.416 + 68.417 +Commands that check the working directory all take an ``I know what 68.418 +I'm doing'' option, which is always named \option{-f}. The exact 68.419 +meaning of \option{-f} depends on the command. For example, 68.420 +\hgcmdargs{qnew}{\hgxopt{mq}{qnew}{-f}} will incorporate any outstanding 68.421 +changes into the new patch it creates, but 68.422 +\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-f}} will revert modifications to any 68.423 +files affected by the patch that it is popping. Be sure to read the 68.424 +documentation for a command's \option{-f} option before you use it! 68.425 + 68.426 +\subsection{Working on several patches at once} 68.427 + 68.428 +The \hgxcmd{mq}{qrefresh} command always refreshes the \emph{topmost} 68.429 +applied patch. This means that you can suspend work on one patch (by 68.430 +refreshing it), pop or push to make a different patch the top, and 68.431 +work on \emph{that} patch for a while. 68.432 + 68.433 +Here's an example that illustrates how you can use this ability. 68.434 +Let's say you're developing a new feature as two patches. The first 68.435 +is a change to the core of your software, and the second---layered on 68.436 +top of the first---changes the user interface to use the code you just 68.437 +added to the core. If you notice a bug in the core while you're 68.438 +working on the UI patch, it's easy to fix the core. Simply 68.439 +\hgxcmd{mq}{qrefresh} the UI patch to save your in-progress changes, and 68.440 +\hgxcmd{mq}{qpop} down to the core patch. Fix the core bug, 68.441 +\hgxcmd{mq}{qrefresh} the core patch, and \hgxcmd{mq}{qpush} back to the UI 68.442 +patch to continue where you left off. 68.443 + 68.444 +\section{More about patches} 68.445 +\label{sec:mq:adv-patch} 68.446 + 68.447 +MQ uses the GNU \command{patch} command to apply patches, so it's 68.448 +helpful to know a few more detailed aspects of how \command{patch} 68.449 +works, and about patches themselves. 68.450 + 68.451 +\subsection{The strip count} 68.452 + 68.453 +If you look at the file headers in a patch, you will notice that the 68.454 +pathnames usually have an extra component on the front that isn't 68.455 +present in the actual path name. This is a holdover from the way that 68.456 +people used to generate patches (people still do this, but it's 68.457 +somewhat rare with modern revision control tools). 68.458 + 68.459 +Alice would unpack a tarball, edit her files, then decide that she 68.460 +wanted to create a patch. So she'd rename her working directory, 68.461 +unpack the tarball again (hence the need for the rename), and use the 68.462 +\cmdopt{diff}{-r} and \cmdopt{diff}{-N} options to \command{diff} to 68.463 +recursively generate a patch between the unmodified directory and the 68.464 +modified one. The result would be that the name of the unmodified 68.465 +directory would be at the front of the left-hand path in every file 68.466 +header, and the name of the modified directory would be at the front 68.467 +of the right-hand path. 68.468 + 68.469 +Since someone receiving a patch from the Alices of the net would be 68.470 +unlikely to have unmodified and modified directories with exactly the 68.471 +same names, the \command{patch} command has a \cmdopt{patch}{-p} 68.472 +option that indicates the number of leading path name components to 68.473 +strip when trying to apply a patch. This number is called the 68.474 +\emph{strip count}. 68.475 + 68.476 +An option of ``\texttt{-p1}'' means ``use a strip count of one''. If 68.477 +\command{patch} sees a file name \filename{foo/bar/baz} in a file 68.478 +header, it will strip \filename{foo} and try to patch a file named 68.479 +\filename{bar/baz}. (Strictly speaking, the strip count refers to the 68.480 +number of \emph{path separators} (and the components that go with them 68.481 +) to strip. A strip count of one will turn \filename{foo/bar} into 68.482 +\filename{bar}, but \filename{/foo/bar} (notice the extra leading 68.483 +slash) into \filename{foo/bar}.) 68.484 + 68.485 +The ``standard'' strip count for patches is one; almost all patches 68.486 +contain one leading path name component that needs to be stripped. 68.487 +Mercurial's \hgcmd{diff} command generates path names in this form, 68.488 +and the \hgcmd{import} command and MQ expect patches to have a strip 68.489 +count of one. 68.490 + 68.491 +If you receive a patch from someone that you want to add to your patch 68.492 +queue, and the patch needs a strip count other than one, you cannot 68.493 +just \hgxcmd{mq}{qimport} the patch, because \hgxcmd{mq}{qimport} does not yet 68.494 +have a \texttt{-p} option (see~\bug{311}). Your best bet is to 68.495 +\hgxcmd{mq}{qnew} a patch of your own, then use \cmdargs{patch}{-p\emph{N}} 68.496 +to apply their patch, followed by \hgcmd{addremove} to pick up any 68.497 +files added or removed by the patch, followed by \hgxcmd{mq}{qrefresh}. 68.498 +This complexity may become unnecessary; see~\bug{311} for details. 68.499 +\subsection{Strategies for applying a patch} 68.500 + 68.501 +When \command{patch} applies a hunk, it tries a handful of 68.502 +successively less accurate strategies to try to make the hunk apply. 68.503 +This falling-back technique often makes it possible to take a patch 68.504 +that was generated against an old version of a file, and apply it 68.505 +against a newer version of that file. 68.506 + 68.507 +First, \command{patch} tries an exact match, where the line numbers, 68.508 +the context, and the text to be modified must apply exactly. If it 68.509 +cannot make an exact match, it tries to find an exact match for the 68.510 +context, without honouring the line numbering information. If this 68.511 +succeeds, it prints a line of output saying that the hunk was applied, 68.512 +but at some \emph{offset} from the original line number. 68.513 + 68.514 +If a context-only match fails, \command{patch} removes the first and 68.515 +last lines of the context, and tries a \emph{reduced} context-only 68.516 +match. If the hunk with reduced context succeeds, it prints a message 68.517 +saying that it applied the hunk with a \emph{fuzz factor} (the number 68.518 +after the fuzz factor indicates how many lines of context 68.519 +\command{patch} had to trim before the patch applied). 68.520 + 68.521 +When neither of these techniques works, \command{patch} prints a 68.522 +message saying that the hunk in question was rejected. It saves 68.523 +rejected hunks (also simply called ``rejects'') to a file with the 68.524 +same name, and an added \sfilename{.rej} extension. It also saves an 68.525 +unmodified copy of the file with a \sfilename{.orig} extension; the 68.526 +copy of the file without any extensions will contain any changes made 68.527 +by hunks that \emph{did} apply cleanly. If you have a patch that 68.528 +modifies \filename{foo} with six hunks, and one of them fails to 68.529 +apply, you will have: an unmodified \filename{foo.orig}, a 68.530 +\filename{foo.rej} containing one hunk, and \filename{foo}, containing 68.531 +the changes made by the five successful hunks. 68.532 + 68.533 +\subsection{Some quirks of patch representation} 68.534 + 68.535 +There are a few useful things to know about how \command{patch} works 68.536 +with files. 68.537 +\begin{itemize} 68.538 +\item This should already be obvious, but \command{patch} cannot 68.539 + handle binary files. 68.540 +\item Neither does it care about the executable bit; it creates new 68.541 + files as readable, but not executable. 68.542 +\item \command{patch} treats the removal of a file as a diff between 68.543 + the file to be removed and the empty file. So your idea of ``I 68.544 + deleted this file'' looks like ``every line of this file was 68.545 + deleted'' in a patch. 68.546 +\item It treats the addition of a file as a diff between the empty 68.547 + file and the file to be added. So in a patch, your idea of ``I 68.548 + added this file'' looks like ``every line of this file was added''. 68.549 +\item It treats a renamed file as the removal of the old name, and the 68.550 + addition of the new name. This means that renamed files have a big 68.551 + footprint in patches. (Note also that Mercurial does not currently 68.552 + try to infer when files have been renamed or copied in a patch.) 68.553 +\item \command{patch} cannot represent empty files, so you cannot use 68.554 + a patch to represent the notion ``I added this empty file to the 68.555 + tree''. 68.556 +\end{itemize} 68.557 +\subsection{Beware the fuzz} 68.558 + 68.559 +While applying a hunk at an offset, or with a fuzz factor, will often 68.560 +be completely successful, these inexact techniques naturally leave 68.561 +open the possibility of corrupting the patched file. The most common 68.562 +cases typically involve applying a patch twice, or at an incorrect 68.563 +location in the file. If \command{patch} or \hgxcmd{mq}{qpush} ever 68.564 +mentions an offset or fuzz factor, you should make sure that the 68.565 +modified files are correct afterwards. 68.566 + 68.567 +It's often a good idea to refresh a patch that has applied with an 68.568 +offset or fuzz factor; refreshing the patch generates new context 68.569 +information that will make it apply cleanly. I say ``often,'' not 68.570 +``always,'' because sometimes refreshing a patch will make it fail to 68.571 +apply against a different revision of the underlying files. In some 68.572 +cases, such as when you're maintaining a patch that must sit on top of 68.573 +multiple versions of a source tree, it's acceptable to have a patch 68.574 +apply with some fuzz, provided you've verified the results of the 68.575 +patching process in such cases. 68.576 + 68.577 +\subsection{Handling rejection} 68.578 + 68.579 +If \hgxcmd{mq}{qpush} fails to apply a patch, it will print an error 68.580 +message and exit. If it has left \sfilename{.rej} files behind, it is 68.581 +usually best to fix up the rejected hunks before you push more patches 68.582 +or do any further work. 68.583 + 68.584 +If your patch \emph{used to} apply cleanly, and no longer does because 68.585 +you've changed the underlying code that your patches are based on, 68.586 +Mercurial Queues can help; see section~\ref{sec:mq:merge} for details. 68.587 + 68.588 +Unfortunately, there aren't any great techniques for dealing with 68.589 +rejected hunks. Most often, you'll need to view the \sfilename{.rej} 68.590 +file and edit the target file, applying the rejected hunks by hand. 68.591 + 68.592 +If you're feeling adventurous, Neil Brown, a Linux kernel hacker, 68.593 +wrote a tool called \command{wiggle}~\cite{web:wiggle}, which is more 68.594 +vigorous than \command{patch} in its attempts to make a patch apply. 68.595 + 68.596 +Another Linux kernel hacker, Chris Mason (the author of Mercurial 68.597 +Queues), wrote a similar tool called 68.598 +\command{mpatch}~\cite{web:mpatch}, which takes a simple approach to 68.599 +automating the application of hunks rejected by \command{patch}. The 68.600 +\command{mpatch} command can help with four common reasons that a hunk 68.601 +may be rejected: 68.602 + 68.603 +\begin{itemize} 68.604 +\item The context in the middle of a hunk has changed. 68.605 +\item A hunk is missing some context at the beginning or end. 68.606 +\item A large hunk might apply better---either entirely or in 68.607 + part---if it was broken up into smaller hunks. 68.608 +\item A hunk removes lines with slightly different content than those 68.609 + currently present in the file. 68.610 +\end{itemize} 68.611 + 68.612 +If you use \command{wiggle} or \command{mpatch}, you should be doubly 68.613 +careful to check your results when you're done. In fact, 68.614 +\command{mpatch} enforces this method of double-checking the tool's 68.615 +output, by automatically dropping you into a merge program when it has 68.616 +done its job, so that you can verify its work and finish off any 68.617 +remaining merges. 68.618 + 68.619 +\section{Getting the best performance out of MQ} 68.620 +\label{sec:mq:perf} 68.621 + 68.622 +MQ is very efficient at handling a large number of patches. I ran 68.623 +some performance experiments in mid-2006 for a talk that I gave at the 68.624 +2006 EuroPython conference~\cite{web:europython}. I used as my data 68.625 +set the Linux 2.6.17-mm1 patch series, which consists of 1,738 68.626 +patches. I applied these on top of a Linux kernel repository 68.627 +containing all 27,472 revisions between Linux 2.6.12-rc2 and Linux 68.628 +2.6.17. 68.629 + 68.630 +On my old, slow laptop, I was able to 68.631 +\hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-a}} all 1,738 patches in 3.5 minutes, 68.632 +and \hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a}} them all in 30 seconds. (On a 68.633 +newer laptop, the time to push all patches dropped to two minutes.) I 68.634 +could \hgxcmd{mq}{qrefresh} one of the biggest patches (which made 22,779 68.635 +lines of changes to 287 files) in 6.6 seconds. 68.636 + 68.637 +Clearly, MQ is well suited to working in large trees, but there are a 68.638 +few tricks you can use to get the best performance of it. 68.639 + 68.640 +First of all, try to ``batch'' operations together. Every time you 68.641 +run \hgxcmd{mq}{qpush} or \hgxcmd{mq}{qpop}, these commands scan the working 68.642 +directory once to make sure you haven't made some changes and then 68.643 +forgotten to run \hgxcmd{mq}{qrefresh}. On a small tree, the time that 68.644 +this scan takes is unnoticeable. However, on a medium-sized tree 68.645 +(containing tens of thousands of files), it can take a second or more. 68.646 + 68.647 +The \hgxcmd{mq}{qpush} and \hgxcmd{mq}{qpop} commands allow you to push and pop 68.648 +multiple patches at a time. You can identify the ``destination 68.649 +patch'' that you want to end up at. When you \hgxcmd{mq}{qpush} with a 68.650 +destination specified, it will push patches until that patch is at the 68.651 +top of the applied stack. When you \hgxcmd{mq}{qpop} to a destination, MQ 68.652 +will pop patches until the destination patch is at the top. 68.653 + 68.654 +You can identify a destination patch using either the name of the 68.655 +patch, or by number. If you use numeric addressing, patches are 68.656 +counted from zero; this means that the first patch is zero, the second 68.657 +is one, and so on. 68.658 + 68.659 +\section{Updating your patches when the underlying code changes} 68.660 +\label{sec:mq:merge} 68.661 + 68.662 +It's common to have a stack of patches on top of an underlying 68.663 +repository that you don't modify directly. If you're working on 68.664 +changes to third-party code, or on a feature that is taking longer to 68.665 +develop than the rate of change of the code beneath, you will often 68.666 +need to sync up with the underlying code, and fix up any hunks in your 68.667 +patches that no longer apply. This is called \emph{rebasing} your 68.668 +patch series. 68.669 + 68.670 +The simplest way to do this is to \hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a}} 68.671 +your patches, then \hgcmd{pull} changes into the underlying 68.672 +repository, and finally \hgcmdargs{qpush}{\hgxopt{mq}{qpop}{-a}} your 68.673 +patches again. MQ will stop pushing any time it runs across a patch 68.674 +that fails to apply during conflicts, allowing you to fix your 68.675 +conflicts, \hgxcmd{mq}{qrefresh} the affected patch, and continue pushing 68.676 +until you have fixed your entire stack. 68.677 + 68.678 +This approach is easy to use and works well if you don't expect 68.679 +changes to the underlying code to affect how well your patches apply. 68.680 +If your patch stack touches code that is modified frequently or 68.681 +invasively in the underlying repository, however, fixing up rejected 68.682 +hunks by hand quickly becomes tiresome. 68.683 + 68.684 +It's possible to partially automate the rebasing process. If your 68.685 +patches apply cleanly against some revision of the underlying repo, MQ 68.686 +can use this information to help you to resolve conflicts between your 68.687 +patches and a different revision. 68.688 + 68.689 +The process is a little involved. 68.690 +\begin{enumerate} 68.691 +\item To begin, \hgcmdargs{qpush}{-a} all of your patches on top of 68.692 + the revision where you know that they apply cleanly. 68.693 +\item Save a backup copy of your patch directory using 68.694 + \hgcmdargs{qsave}{\hgxopt{mq}{qsave}{-e} \hgxopt{mq}{qsave}{-c}}. This prints 68.695 + the name of the directory that it has saved the patches in. It will 68.696 + save the patches to a directory called 68.697 + \sdirname{.hg/patches.\emph{N}}, where \texttt{\emph{N}} is a small 68.698 + integer. It also commits a ``save changeset'' on top of your 68.699 + applied patches; this is for internal book-keeping, and records the 68.700 + states of the \sfilename{series} and \sfilename{status} files. 68.701 +\item Use \hgcmd{pull} to bring new changes into the underlying 68.702 + repository. (Don't run \hgcmdargs{pull}{-u}; see below for why.) 68.703 +\item Update to the new tip revision, using 68.704 + \hgcmdargs{update}{\hgopt{update}{-C}} to override the patches you 68.705 + have pushed. 68.706 +\item Merge all patches using \hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-m} 68.707 + \hgxopt{mq}{qpush}{-a}}. The \hgxopt{mq}{qpush}{-m} option to \hgxcmd{mq}{qpush} 68.708 + tells MQ to perform a three-way merge if the patch fails to apply. 68.709 +\end{enumerate} 68.710 + 68.711 +During the \hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-m}}, each patch in the 68.712 +\sfilename{series} file is applied normally. If a patch applies with 68.713 +fuzz or rejects, MQ looks at the queue you \hgxcmd{mq}{qsave}d, and 68.714 +performs a three-way merge with the corresponding changeset. This 68.715 +merge uses Mercurial's normal merge machinery, so it may pop up a GUI 68.716 +merge tool to help you to resolve problems. 68.717 + 68.718 +When you finish resolving the effects of a patch, MQ refreshes your 68.719 +patch based on the result of the merge. 68.720 + 68.721 +At the end of this process, your repository will have one extra head 68.722 +from the old patch queue, and a copy of the old patch queue will be in 68.723 +\sdirname{.hg/patches.\emph{N}}. You can remove the extra head using 68.724 +\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a} \hgxopt{mq}{qpop}{-n} patches.\emph{N}} 68.725 +or \hgcmd{strip}. You can delete \sdirname{.hg/patches.\emph{N}} once 68.726 +you are sure that you no longer need it as a backup. 68.727 + 68.728 +\section{Identifying patches} 68.729 + 68.730 +MQ commands that work with patches let you refer to a patch either by 68.731 +using its name or by a number. By name is obvious enough; pass the 68.732 +name \filename{foo.patch} to \hgxcmd{mq}{qpush}, for example, and it will 68.733 +push patches until \filename{foo.patch} is applied. 68.734 + 68.735 +As a shortcut, you can refer to a patch using both a name and a 68.736 +numeric offset; \texttt{foo.patch-2} means ``two patches before 68.737 +\texttt{foo.patch}'', while \texttt{bar.patch+4} means ``four patches 68.738 +after \texttt{bar.patch}''. 68.739 + 68.740 +Referring to a patch by index isn't much different. The first patch 68.741 +printed in the output of \hgxcmd{mq}{qseries} is patch zero (yes, it's one 68.742 +of those start-at-zero counting systems); the second is patch one; and 68.743 +so on. 68.744 + 68.745 +MQ also makes it easy to work with patches when you are using normal 68.746 +Mercurial commands. Every command that accepts a changeset ID will 68.747 +also accept the name of an applied patch. MQ augments the tags 68.748 +normally in the repository with an eponymous one for each applied 68.749 +patch. In addition, the special tags \index{tags!special tag 68.750 + names!\texttt{qbase}}\texttt{qbase} and \index{tags!special tag 68.751 + names!\texttt{qtip}}\texttt{qtip} identify the ``bottom-most'' and 68.752 +topmost applied patches, respectively. 68.753 + 68.754 +These additions to Mercurial's normal tagging capabilities make 68.755 +dealing with patches even more of a breeze. 68.756 +\begin{itemize} 68.757 +\item Want to patchbomb a mailing list with your latest series of 68.758 + changes? 68.759 + \begin{codesample4} 68.760 + hg email qbase:qtip 68.761 + \end{codesample4} 68.762 + (Don't know what ``patchbombing'' is? See 68.763 + section~\ref{sec:hgext:patchbomb}.) 68.764 +\item Need to see all of the patches since \texttt{foo.patch} that 68.765 + have touched files in a subdirectory of your tree? 68.766 + \begin{codesample4} 68.767 + hg log -r foo.patch:qtip \emph{subdir} 68.768 + \end{codesample4} 68.769 +\end{itemize} 68.770 + 68.771 +Because MQ makes the names of patches available to the rest of 68.772 +Mercurial through its normal internal tag machinery, you don't need to 68.773 +type in the entire name of a patch when you want to identify it by 68.774 +name. 68.775 + 68.776 +\begin{figure}[ht] 68.777 + \interaction{mq.id.output} 68.778 + \caption{Using MQ's tag features to work with patches} 68.779 + \label{ex:mq:id} 68.780 +\end{figure} 68.781 + 68.782 +Another nice consequence of representing patch names as tags is that 68.783 +when you run the \hgcmd{log} command, it will display a patch's name 68.784 +as a tag, simply as part of its normal output. This makes it easy to 68.785 +visually distinguish applied patches from underlying ``normal'' 68.786 +revisions. Figure~\ref{ex:mq:id} shows a few normal Mercurial 68.787 +commands in use with applied patches. 68.788 + 68.789 +\section{Useful things to know about} 68.790 + 68.791 +There are a number of aspects of MQ usage that don't fit tidily into 68.792 +sections of their own, but that are good to know. Here they are, in 68.793 +one place. 68.794 + 68.795 +\begin{itemize} 68.796 +\item Normally, when you \hgxcmd{mq}{qpop} a patch and \hgxcmd{mq}{qpush} it 68.797 + again, the changeset that represents the patch after the pop/push 68.798 + will have a \emph{different identity} than the changeset that 68.799 + represented the hash beforehand. See 68.800 + section~\ref{sec:mqref:cmd:qpush} for information as to why this is. 68.801 +\item It's not a good idea to \hgcmd{merge} changes from another 68.802 + branch with a patch changeset, at least if you want to maintain the 68.803 + ``patchiness'' of that changeset and changesets below it on the 68.804 + patch stack. If you try to do this, it will appear to succeed, but 68.805 + MQ will become confused. 68.806 +\end{itemize} 68.807 + 68.808 +\section{Managing patches in a repository} 68.809 +\label{sec:mq:repo} 68.810 + 68.811 +Because MQ's \sdirname{.hg/patches} directory resides outside a 68.812 +Mercurial repository's working directory, the ``underlying'' Mercurial 68.813 +repository knows nothing about the management or presence of patches. 68.814 + 68.815 +This presents the interesting possibility of managing the contents of 68.816 +the patch directory as a Mercurial repository in its own right. This 68.817 +can be a useful way to work. For example, you can work on a patch for 68.818 +a while, \hgxcmd{mq}{qrefresh} it, then \hgcmd{commit} the current state of 68.819 +the patch. This lets you ``roll back'' to that version of the patch 68.820 +later on. 68.821 + 68.822 +You can then share different versions of the same patch stack among 68.823 +multiple underlying repositories. I use this when I am developing a 68.824 +Linux kernel feature. I have a pristine copy of my kernel sources for 68.825 +each of several CPU architectures, and a cloned repository under each 68.826 +that contains the patches I am working on. When I want to test a 68.827 +change on a different architecture, I push my current patches to the 68.828 +patch repository associated with that kernel tree, pop and push all of 68.829 +my patches, and build and test that kernel. 68.830 + 68.831 +Managing patches in a repository makes it possible for multiple 68.832 +developers to work on the same patch series without colliding with 68.833 +each other, all on top of an underlying source base that they may or 68.834 +may not control. 68.835 + 68.836 +\subsection{MQ support for patch repositories} 68.837 + 68.838 +MQ helps you to work with the \sdirname{.hg/patches} directory as a 68.839 +repository; when you prepare a repository for working with patches 68.840 +using \hgxcmd{mq}{qinit}, you can pass the \hgxopt{mq}{qinit}{-c} option to 68.841 +create the \sdirname{.hg/patches} directory as a Mercurial repository. 68.842 + 68.843 +\begin{note} 68.844 + If you forget to use the \hgxopt{mq}{qinit}{-c} option, you can simply go 68.845 + into the \sdirname{.hg/patches} directory at any time and run 68.846 + \hgcmd{init}. Don't forget to add an entry for the 68.847 + \sfilename{status} file to the \sfilename{.hgignore} file, though 68.848 + 68.849 + (\hgcmdargs{qinit}{\hgxopt{mq}{qinit}{-c}} does this for you 68.850 + automatically); you \emph{really} don't want to manage the 68.851 + \sfilename{status} file. 68.852 +\end{note} 68.853 + 68.854 +As a convenience, if MQ notices that the \dirname{.hg/patches} 68.855 +directory is a repository, it will automatically \hgcmd{add} every 68.856 +patch that you create and import. 68.857 + 68.858 +MQ provides a shortcut command, \hgxcmd{mq}{qcommit}, that runs 68.859 +\hgcmd{commit} in the \sdirname{.hg/patches} directory. This saves 68.860 +some bothersome typing. 68.861 + 68.862 +Finally, as a convenience to manage the patch directory, you can 68.863 +define the alias \command{mq} on Unix systems. For example, on Linux 68.864 +systems using the \command{bash} shell, you can include the following 68.865 +snippet in your \tildefile{.bashrc}. 68.866 + 68.867 +\begin{codesample2} 68.868 + alias mq=`hg -R \$(hg root)/.hg/patches' 68.869 +\end{codesample2} 68.870 + 68.871 +You can then issue commands of the form \cmdargs{mq}{pull} from 68.872 +the main repository. 68.873 + 68.874 +\subsection{A few things to watch out for} 68.875 + 68.876 +MQ's support for working with a repository full of patches is limited 68.877 +in a few small respects. 68.878 + 68.879 +MQ cannot automatically detect changes that you make to the patch 68.880 +directory. If you \hgcmd{pull}, manually edit, or \hgcmd{update} 68.881 +changes to patches or the \sfilename{series} file, you will have to 68.882 +\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a}} and then 68.883 +\hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-a}} in the underlying repository to 68.884 +see those changes show up there. If you forget to do this, you can 68.885 +confuse MQ's idea of which patches are applied. 68.886 + 68.887 +\section{Third party tools for working with patches} 68.888 +\label{sec:mq:tools} 68.889 + 68.890 +Once you've been working with patches for a while, you'll find 68.891 +yourself hungry for tools that will help you to understand and 68.892 +manipulate the patches you're dealing with. 68.893 + 68.894 +The \command{diffstat} command~\cite{web:diffstat} generates a 68.895 +histogram of the modifications made to each file in a patch. It 68.896 +provides a good way to ``get a sense of'' a patch---which files it 68.897 +affects, and how much change it introduces to each file and as a 68.898 +whole. (I find that it's a good idea to use \command{diffstat}'s 68.899 +\cmdopt{diffstat}{-p} option as a matter of course, as otherwise it 68.900 +will try to do clever things with prefixes of file names that 68.901 +inevitably confuse at least me.) 68.902 + 68.903 +\begin{figure}[ht] 68.904 + \interaction{mq.tools.tools} 68.905 + \caption{The \command{diffstat}, \command{filterdiff}, and \command{lsdiff} commands} 68.906 + \label{ex:mq:tools} 68.907 +\end{figure} 68.908 + 68.909 +The \package{patchutils} package~\cite{web:patchutils} is invaluable. 68.910 +It provides a set of small utilities that follow the ``Unix 68.911 +philosophy;'' each does one useful thing with a patch. The 68.912 +\package{patchutils} command I use most is \command{filterdiff}, which 68.913 +extracts subsets from a patch file. For example, given a patch that 68.914 +modifies hundreds of files across dozens of directories, a single 68.915 +invocation of \command{filterdiff} can generate a smaller patch that 68.916 +only touches files whose names match a particular glob pattern. See 68.917 +section~\ref{mq-collab:tips:interdiff} for another example. 68.918 + 68.919 +\section{Good ways to work with patches} 68.920 + 68.921 +Whether you are working on a patch series to submit to a free software 68.922 +or open source project, or a series that you intend to treat as a 68.923 +sequence of regular changesets when you're done, you can use some 68.924 +simple techniques to keep your work well organised. 68.925 + 68.926 +Give your patches descriptive names. A good name for a patch might be 68.927 +\filename{rework-device-alloc.patch}, because it will immediately give 68.928 +you a hint what the purpose of the patch is. Long names shouldn't be 68.929 +a problem; you won't be typing the names often, but you \emph{will} be 68.930 +running commands like \hgxcmd{mq}{qapplied} and \hgxcmd{mq}{qtop} over and over. 68.931 +Good naming becomes especially important when you have a number of 68.932 +patches to work with, or if you are juggling a number of different 68.933 +tasks and your patches only get a fraction of your attention. 68.934 + 68.935 +Be aware of what patch you're working on. Use the \hgxcmd{mq}{qtop} 68.936 +command and skim over the text of your patches frequently---for 68.937 +example, using \hgcmdargs{tip}{\hgopt{tip}{-p}})---to be sure of where 68.938 +you stand. I have several times worked on and \hgxcmd{mq}{qrefresh}ed a 68.939 +patch other than the one I intended, and it's often tricky to migrate 68.940 +changes into the right patch after making them in the wrong one. 68.941 + 68.942 +For this reason, it is very much worth investing a little time to 68.943 +learn how to use some of the third-party tools I described in 68.944 +section~\ref{sec:mq:tools}, particularly \command{diffstat} and 68.945 +\command{filterdiff}. The former will give you a quick idea of what 68.946 +changes your patch is making, while the latter makes it easy to splice 68.947 +hunks selectively out of one patch and into another. 68.948 + 68.949 +\section{MQ cookbook} 68.950 + 68.951 +\subsection{Manage ``trivial'' patches} 68.952 + 68.953 +Because the overhead of dropping files into a new Mercurial repository 68.954 +is so low, it makes a lot of sense to manage patches this way even if 68.955 +you simply want to make a few changes to a source tarball that you 68.956 +downloaded. 68.957 + 68.958 +Begin by downloading and unpacking the source tarball, 68.959 +and turning it into a Mercurial repository. 68.960 +\interaction{mq.tarball.download} 68.961 + 68.962 +Continue by creating a patch stack and making your changes. 68.963 +\interaction{mq.tarball.qinit} 68.964 + 68.965 +Let's say a few weeks or months pass, and your package author releases 68.966 +a new version. First, bring their changes into the repository. 68.967 +\interaction{mq.tarball.newsource} 68.968 +The pipeline starting with \hgcmd{locate} above deletes all files in 68.969 +the working directory, so that \hgcmd{commit}'s 68.970 +\hgopt{commit}{--addremove} option can actually tell which files have 68.971 +really been removed in the newer version of the source. 68.972 + 68.973 +Finally, you can apply your patches on top of the new tree. 68.974 +\interaction{mq.tarball.repush} 68.975 + 68.976 +\subsection{Combining entire patches} 68.977 +\label{sec:mq:combine} 68.978 + 68.979 +MQ provides a command, \hgxcmd{mq}{qfold} that lets you combine entire 68.980 +patches. This ``folds'' the patches you name, in the order you name 68.981 +them, into the topmost applied patch, and concatenates their 68.982 +descriptions onto the end of its description. The patches that you 68.983 +fold must be unapplied before you fold them. 68.984 + 68.985 +The order in which you fold patches matters. If your topmost applied 68.986 +patch is \texttt{foo}, and you \hgxcmd{mq}{qfold} \texttt{bar} and 68.987 +\texttt{quux} into it, you will end up with a patch that has the same 68.988 +effect as if you applied first \texttt{foo}, then \texttt{bar}, 68.989 +followed by \texttt{quux}. 68.990 + 68.991 +\subsection{Merging part of one patch into another} 68.992 + 68.993 +Merging \emph{part} of one patch into another is more difficult than 68.994 +combining entire patches. 68.995 + 68.996 +If you want to move changes to entire files, you can use 68.997 +\command{filterdiff}'s \cmdopt{filterdiff}{-i} and 68.998 +\cmdopt{filterdiff}{-x} options to choose the modifications to snip 68.999 +out of one patch, concatenating its output onto the end of the patch 68.1000 +you want to merge into. You usually won't need to modify the patch 68.1001 +you've merged the changes from. Instead, MQ will report some rejected 68.1002 +hunks when you \hgxcmd{mq}{qpush} it (from the hunks you moved into the 68.1003 +other patch), and you can simply \hgxcmd{mq}{qrefresh} the patch to drop 68.1004 +the duplicate hunks. 68.1005 + 68.1006 +If you have a patch that has multiple hunks modifying a file, and you 68.1007 +only want to move a few of those hunks, the job becomes more messy, 68.1008 +but you can still partly automate it. Use \cmdargs{lsdiff}{-nvv} to 68.1009 +print some metadata about the patch. 68.1010 +\interaction{mq.tools.lsdiff} 68.1011 + 68.1012 +This command prints three different kinds of number: 68.1013 +\begin{itemize} 68.1014 +\item (in the first column) a \emph{file number} to identify each file 68.1015 + modified in the patch; 68.1016 +\item (on the next line, indented) the line number within a modified 68.1017 + file where a hunk starts; and 68.1018 +\item (on the same line) a \emph{hunk number} to identify that hunk. 68.1019 +\end{itemize} 68.1020 + 68.1021 +You'll have to use some visual inspection, and reading of the patch, 68.1022 +to identify the file and hunk numbers you'll want, but you can then 68.1023 +pass them to to \command{filterdiff}'s \cmdopt{filterdiff}{--files} 68.1024 +and \cmdopt{filterdiff}{--hunks} options, to select exactly the file 68.1025 +and hunk you want to extract. 68.1026 + 68.1027 +Once you have this hunk, you can concatenate it onto the end of your 68.1028 +destination patch and continue with the remainder of 68.1029 +section~\ref{sec:mq:combine}. 68.1030 + 68.1031 +\section{Differences between quilt and MQ} 68.1032 + 68.1033 +If you are already familiar with quilt, MQ provides a similar command 68.1034 +set. There are a few differences in the way that it works. 68.1035 + 68.1036 +You will already have noticed that most quilt commands have MQ 68.1037 +counterparts that simply begin with a ``\texttt{q}''. The exceptions 68.1038 +are quilt's \texttt{add} and \texttt{remove} commands, the 68.1039 +counterparts for which are the normal Mercurial \hgcmd{add} and 68.1040 +\hgcmd{remove} commands. There is no MQ equivalent of the quilt 68.1041 +\texttt{edit} command. 68.1042 + 68.1043 +%%% Local Variables: 68.1044 +%%% mode: latex 68.1045 +%%% TeX-master: "00book" 68.1046 +%%% End:
69.1 Binary file fr/note.png has changed
70.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 70.2 +++ b/fr/preface.tex Thu Feb 05 12:37:03 2009 +0100 70.3 @@ -0,0 +1,69 @@ 70.4 +\chapter*{Préface} 70.5 +\addcontentsline{toc}{chapter}{Preface} 70.6 +\label{chap:preface} 70.7 + 70.8 +La gestion de source distribué est encore un territoire peu exploré 70.9 +et par conséquent a grandis très rapidement grâce à la volonté de 70.10 +ses explorateurs. 70.11 + 70.12 +Je rédige un libre sur ce sujet car je crois que c'est un sujet 70.13 +important qui mérite bien un guide du ``terrain''. J'ai choisi d'écrire 70.14 +un livre sur Mercurial car c'est l'outil le plus simple pour découvrir 70.15 +ce nouveau monde et que, en outre, il répond très bien au besoin de 70.16 +réels environements, là où d'autres outils de gestion de source n'y 70.17 +parviennent pas. 70.18 + 70.19 +\section{Cet ouvrage est un travail en cours} 70.20 + 70.21 +Je publie ce livre tout en continuant à l'écrire, dans l'espoir qu'il 70.22 +vous sera utile. J'espère aussi que les lecteurs pourront ainsi contribuer 70.23 +si ils souhaitent. 70.24 + 70.25 +\section{A propros des exemples de ce livre} 70.26 + 70.27 +Ce livre a une approche particulière des extrait de code. Ceci sont 70.28 +toujours ``dynamique''---chacun est le résultat d'un script shell qui 70.29 +exécute les commandes mercurial que vous voyez. Chaque fois qu'une 70.30 +image du livre est construite tout les scripts d'exemple sont exécutés 70.31 +automatiquement, et les résultats comparés à ceux attendus. 70.32 + 70.33 +Cette approche a l'avantage de garantir que les exemples sont toujours 70.34 +juste; ils montrent \emph{exactement} le comportement de la version de 70.35 +Mercurial spécifié dans la couverture de ce livre. Si je met à jour cette 70.36 +version, et que les commandes changent, la génération du livre échouera. 70.37 + 70.38 +Il y a un petit désavantage à cette approche, qui que les dates et les 70.39 +temps onl 70.40 + 70.41 +There is a small disadvantage to this approach, which is that the 70.42 +dates and times you'll see in examples tend to be ``squashed'' 70.43 +together in a way that they wouldn't be if the same commands were 70.44 +being typed by a human. Where a human can issue no more than one 70.45 +command every few seconds, with any resulting timestamps 70.46 +correspondingly spread out, my automated example scripts run many 70.47 +commands in one second. 70.48 + 70.49 +As an instance of this, several consecutive commits in an example can 70.50 +show up as having occurred during the same second. You can see this 70.51 +occur in the \hgext{bisect} example in section~\ref{sec:undo:bisect}, 70.52 +for instance. 70.53 + 70.54 +So when you're reading examples, don't place too much weight on the 70.55 +dates or times you see in the output of commands. But \emph{do} be 70.56 +confident that the behaviour you're seeing is consistent and 70.57 +reproducible. 70.58 + 70.59 +\section{Colophon---this book is Free} 70.60 + 70.61 +This book is licensed under the Open Publication License, and is 70.62 +produced entirely using Free Software tools. It is typeset with 70.63 +\LaTeX{}; illustrations are drawn and rendered with 70.64 +\href{http://www.inkscape.org/}{Inkscape}. 70.65 + 70.66 +The complete source code for this book is published as a Mercurial 70.67 +repository, at \url{http://hg.serpentine.com/mercurial/book}. 70.68 + 70.69 +%%% Local Variables: 70.70 +%%% mode: latex 70.71 +%%% TeX-master: "00book" 70.72 +%%% End:
71.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 71.2 +++ b/fr/revlog.svg Thu Feb 05 12:37:03 2009 +0100 71.3 @@ -0,0 +1,1155 @@ 71.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 71.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 71.6 +<svg 71.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 71.8 + xmlns:cc="http://web.resource.org/cc/" 71.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 71.10 + xmlns:svg="http://www.w3.org/2000/svg" 71.11 + xmlns="http://www.w3.org/2000/svg" 71.12 + xmlns:xlink="http://www.w3.org/1999/xlink" 71.13 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 71.14 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 71.15 + width="744.09448819" 71.16 + height="1052.3622047" 71.17 + id="svg2" 71.18 + sodipodi:version="0.32" 71.19 + inkscape:version="0.44.1" 71.20 + sodipodi:docbase="/home/bos/hg/hgbook/en" 71.21 + sodipodi:docname="revlog.svg"> 71.22 + <defs 71.23 + id="defs4"> 71.24 + <marker 71.25 + inkscape:stockid="Arrow1Mend" 71.26 + orient="auto" 71.27 + refY="0.0" 71.28 + refX="0.0" 71.29 + id="Arrow1Mend" 71.30 + style="overflow:visible;"> 71.31 + <path 71.32 + id="path4852" 71.33 + 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 " 71.34 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 71.35 + transform="scale(0.4) rotate(180) translate(10,0)" /> 71.36 + </marker> 71.37 + <linearGradient 71.38 + id="linearGradient3092"> 71.39 + <stop 71.40 + style="stop-color:#44436f;stop-opacity:1;" 71.41 + offset="0" 71.42 + id="stop3094" /> 71.43 + <stop 71.44 + style="stop-color:#abade5;stop-opacity:1;" 71.45 + offset="1" 71.46 + id="stop3096" /> 71.47 + </linearGradient> 71.48 + <linearGradient 71.49 + inkscape:collect="always" 71.50 + xlink:href="#linearGradient3092" 71.51 + id="linearGradient3118" 71.52 + gradientUnits="userSpaceOnUse" 71.53 + x1="176.16635" 71.54 + y1="405.21934" 71.55 + x2="417.11935" 71.56 + y2="405.21934" /> 71.57 + <linearGradient 71.58 + inkscape:collect="always" 71.59 + xlink:href="#linearGradient3092" 71.60 + id="linearGradient3120" 71.61 + gradientUnits="userSpaceOnUse" 71.62 + x1="176.16635" 71.63 + y1="405.21934" 71.64 + x2="417.11935" 71.65 + y2="405.21934" /> 71.66 + <linearGradient 71.67 + inkscape:collect="always" 71.68 + xlink:href="#linearGradient3092" 71.69 + id="linearGradient3129" 71.70 + gradientUnits="userSpaceOnUse" 71.71 + x1="176.16635" 71.72 + y1="405.21934" 71.73 + x2="417.11935" 71.74 + y2="405.21934" 71.75 + gradientTransform="translate(-0.928574,-1.428574)" /> 71.76 + <linearGradient 71.77 + inkscape:collect="always" 71.78 + xlink:href="#linearGradient3092" 71.79 + id="linearGradient3133" 71.80 + gradientUnits="userSpaceOnUse" 71.81 + x1="176.16635" 71.82 + y1="405.21934" 71.83 + x2="417.11935" 71.84 + y2="405.21934" 71.85 + gradientTransform="translate(-0.928574,-1.428574)" /> 71.86 + <linearGradient 71.87 + inkscape:collect="always" 71.88 + xlink:href="#linearGradient3092" 71.89 + id="linearGradient3708" 71.90 + gradientUnits="userSpaceOnUse" 71.91 + gradientTransform="matrix(0.423343,0,0,0.423343,138.874,-67.01732)" 71.92 + x1="175.23776" 71.93 + y1="509.98154" 71.94 + x2="416.29077" 71.95 + y2="297.49997" /> 71.96 + <linearGradient 71.97 + inkscape:collect="always" 71.98 + xlink:href="#linearGradient3092" 71.99 + id="linearGradient5164" 71.100 + gradientUnits="userSpaceOnUse" 71.101 + gradientTransform="matrix(0.423343,0,0,0.423343,198.249,247.4358)" 71.102 + x1="175.23776" 71.103 + y1="509.98154" 71.104 + x2="416.29077" 71.105 + y2="297.49997" /> 71.106 + <linearGradient 71.107 + inkscape:collect="always" 71.108 + xlink:href="#linearGradient3092" 71.109 + id="linearGradient5584" 71.110 + gradientUnits="userSpaceOnUse" 71.111 + gradientTransform="matrix(0.423343,0,0,0.423343,143.9081,371.2915)" 71.112 + x1="175.23776" 71.113 + y1="509.98154" 71.114 + x2="416.29077" 71.115 + y2="297.49997" /> 71.116 + <linearGradient 71.117 + inkscape:collect="always" 71.118 + xlink:href="#linearGradient3092" 71.119 + id="linearGradient5784" 71.120 + gradientUnits="userSpaceOnUse" 71.121 + gradientTransform="matrix(0.423343,0,0,0.423343,76.37397,152.137)" 71.122 + x1="175.23776" 71.123 + y1="509.98154" 71.124 + x2="416.29077" 71.125 + y2="297.49997" /> 71.126 + <linearGradient 71.127 + inkscape:collect="always" 71.128 + xlink:href="#linearGradient3092" 71.129 + id="linearGradient5786" 71.130 + gradientUnits="userSpaceOnUse" 71.131 + gradientTransform="matrix(0.423343,0,0,0.423343,198.249,152.137)" 71.132 + x1="175.23776" 71.133 + y1="509.98154" 71.134 + x2="416.29077" 71.135 + y2="297.49997" /> 71.136 + <linearGradient 71.137 + inkscape:collect="always" 71.138 + xlink:href="#linearGradient3092" 71.139 + id="linearGradient5895" 71.140 + gradientUnits="userSpaceOnUse" 71.141 + gradientTransform="matrix(0.423343,0,0,0.423343,198.0215,261.7142)" 71.142 + x1="175.23776" 71.143 + y1="509.98154" 71.144 + x2="416.29077" 71.145 + y2="297.49997" /> 71.146 + <linearGradient 71.147 + inkscape:collect="always" 71.148 + xlink:href="#linearGradient3092" 71.149 + id="linearGradient5958" 71.150 + gradientUnits="userSpaceOnUse" 71.151 + gradientTransform="matrix(0.423343,0,0,0.423343,137.1978,42.55987)" 71.152 + x1="175.23776" 71.153 + y1="509.98154" 71.154 + x2="416.29077" 71.155 + y2="297.49997" /> 71.156 + </defs> 71.157 + <sodipodi:namedview 71.158 + id="base" 71.159 + pagecolor="#ffffff" 71.160 + bordercolor="#666666" 71.161 + borderopacity="1.0" 71.162 + gridtolerance="10000" 71.163 + guidetolerance="10" 71.164 + objecttolerance="10" 71.165 + inkscape:pageopacity="0.0" 71.166 + inkscape:pageshadow="2" 71.167 + inkscape:zoom="0.64" 71.168 + inkscape:cx="566.02368" 71.169 + inkscape:cy="688.16826" 71.170 + inkscape:document-units="px" 71.171 + inkscape:current-layer="layer1" 71.172 + inkscape:window-width="906" 71.173 + inkscape:window-height="620" 71.174 + inkscape:window-x="29" 71.175 + inkscape:window-y="79" 71.176 + inkscape:connector-spacing="11" /> 71.177 + <metadata 71.178 + id="metadata7"> 71.179 + <rdf:RDF> 71.180 + <cc:Work 71.181 + rdf:about=""> 71.182 + <dc:format>image/svg+xml</dc:format> 71.183 + <dc:type 71.184 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 71.185 + </cc:Work> 71.186 + </rdf:RDF> 71.187 + </metadata> 71.188 + <g 71.189 + inkscape:label="Layer 1" 71.190 + inkscape:groupmode="layer" 71.191 + id="layer1"> 71.192 + <rect 71.193 + y="168.74846" 71.194 + x="211.58516" 71.195 + height="89.506805" 71.196 + width="101.60232" 71.197 + id="rect3068" 71.198 + style="fill:url(#linearGradient5958);fill-opacity:1;stroke:black;stroke-width:0.48811448;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.199 + <g 71.200 + id="g3215" 71.201 + transform="matrix(0.423343,0,0,0.423343,137.1977,42.55985)"> 71.202 + <rect 71.203 + y="447.71451" 71.204 + x="299.67859" 71.205 + height="48.571426" 71.206 + width="103.14286" 71.207 + id="rect2899" 71.208 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.209 + <text 71.210 + id="text2903" 71.211 + y="464.8139" 71.212 + x="308.89639" 71.213 + 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" 71.214 + xml:space="preserve"><tspan 71.215 + y="464.8139" 71.216 + x="308.89639" 71.217 + sodipodi:role="line" 71.218 + id="tspan2905">Second parent</tspan></text> 71.219 + <text 71.220 + id="text2907" 71.221 + y="485.50256" 71.222 + x="308.20175" 71.223 + 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" 71.224 + xml:space="preserve"><tspan 71.225 + style="font-family:Courier" 71.226 + y="485.50256" 71.227 + x="308.20175" 71.228 + id="tspan2909" 71.229 + sodipodi:role="line">32bf9a5f22c0</tspan></text> 71.230 + </g> 71.231 + <g 71.232 + id="g3250" 71.233 + transform="matrix(0.423343,0,0,0.423343,137.1977,42.55986)"> 71.234 + <rect 71.235 + y="311.28598" 71.236 + x="188.6071" 71.237 + height="48.571426" 71.238 + width="103.14286" 71.239 + id="rect2936" 71.240 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.241 + <text 71.242 + id="text2940" 71.243 + y="328.38538" 71.244 + x="197.82495" 71.245 + 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" 71.246 + xml:space="preserve"><tspan 71.247 + y="328.38538" 71.248 + x="197.82495" 71.249 + sodipodi:role="line" 71.250 + id="tspan2942">Revision hash</tspan></text> 71.251 + <text 71.252 + id="text2944" 71.253 + y="349.07404" 71.254 + x="197.13031" 71.255 + 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" 71.256 + xml:space="preserve"><tspan 71.257 + style="font-family:Courier" 71.258 + y="349.07404" 71.259 + x="197.13031" 71.260 + id="tspan2946" 71.261 + sodipodi:role="line">34b8b7a15ea1</tspan></text> 71.262 + </g> 71.263 + <g 71.264 + id="g3243" 71.265 + transform="matrix(0.423343,0,0,0.423343,137.6664,43.91853)"> 71.266 + <rect 71.267 + y="363.07654" 71.268 + x="187.5" 71.269 + height="75" 71.270 + width="213.85715" 71.271 + id="rect2950" 71.272 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.273 + <text 71.274 + id="text2958" 71.275 + y="400.86459" 71.276 + x="196.02321" 71.277 + 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" 71.278 + xml:space="preserve"><tspan 71.279 + style="fill:black;fill-opacity:1;font-family:Courier" 71.280 + y="400.86459" 71.281 + x="196.02321" 71.282 + id="tspan2960" 71.283 + sodipodi:role="line">...</tspan></text> 71.284 + <text 71.285 + id="text2954" 71.286 + y="380.17593" 71.287 + x="196.71785" 71.288 + 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" 71.289 + xml:space="preserve"><tspan 71.290 + y="380.17593" 71.291 + x="196.71785" 71.292 + sodipodi:role="line" 71.293 + id="tspan2956" 71.294 + style="fill:black;fill-opacity:1">Revision data (delta or snapshot)</tspan></text> 71.295 + </g> 71.296 + <g 71.297 + id="g5529" 71.298 + transform="translate(-6.710312,-8.165836e-6)"> 71.299 + <rect 71.300 + style="fill:url(#linearGradient5584);fill-opacity:1;stroke:black;stroke-width:0.48811448;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.301 + id="rect3509" 71.302 + width="101.60232" 71.303 + height="89.506805" 71.304 + x="218.29547" 71.305 + y="497.4801" /> 71.306 + <g 71.307 + transform="matrix(0.423343,0,0,0.423343,143.908,371.2915)" 71.308 + id="g3513"> 71.309 + <g 71.310 + id="g3515"> 71.311 + <rect 71.312 + y="447.72418" 71.313 + x="188.6071" 71.314 + height="48.571426" 71.315 + width="103.14286" 71.316 + id="rect3517" 71.317 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.318 + <text 71.319 + id="text3519" 71.320 + y="464.82358" 71.321 + x="197.82495" 71.322 + 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" 71.323 + xml:space="preserve"><tspan 71.324 + y="464.82358" 71.325 + x="197.82495" 71.326 + sodipodi:role="line" 71.327 + id="tspan3521">First parent</tspan></text> 71.328 + <text 71.329 + id="text3523" 71.330 + y="485.51224" 71.331 + x="197.13031" 71.332 + 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" 71.333 + xml:space="preserve"><tspan 71.334 + style="font-family:Courier" 71.335 + y="485.51224" 71.336 + x="197.13031" 71.337 + id="tspan3525" 71.338 + sodipodi:role="line">000000000000</tspan></text> 71.339 + </g> 71.340 + <g 71.341 + id="g3527"> 71.342 + <rect 71.343 + y="447.71451" 71.344 + x="299.67859" 71.345 + height="48.571426" 71.346 + width="103.14286" 71.347 + id="rect3529" 71.348 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.349 + <text 71.350 + id="text3531" 71.351 + y="464.8139" 71.352 + x="308.89639" 71.353 + 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" 71.354 + xml:space="preserve"><tspan 71.355 + y="464.8139" 71.356 + x="308.89639" 71.357 + sodipodi:role="line" 71.358 + id="tspan3533">Second parent</tspan></text> 71.359 + <text 71.360 + id="text3535" 71.361 + y="485.50256" 71.362 + x="308.20175" 71.363 + 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" 71.364 + xml:space="preserve"><tspan 71.365 + style="font-family:Courier" 71.366 + y="485.50256" 71.367 + x="308.20175" 71.368 + id="tspan3537" 71.369 + sodipodi:role="line">000000000000</tspan></text> 71.370 + </g> 71.371 + </g> 71.372 + <g 71.373 + transform="matrix(0.423343,0,0,0.423343,143.908,371.2915)" 71.374 + id="g3539"> 71.375 + <rect 71.376 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.377 + id="rect3541" 71.378 + width="103.14286" 71.379 + height="48.571426" 71.380 + x="188.6071" 71.381 + y="311.28598" /> 71.382 + <text 71.383 + xml:space="preserve" 71.384 + 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" 71.385 + x="197.82495" 71.386 + y="328.38538" 71.387 + id="text3543"><tspan 71.388 + id="tspan3545" 71.389 + sodipodi:role="line" 71.390 + x="197.82495" 71.391 + y="328.38538">Revision hash</tspan></text> 71.392 + <text 71.393 + xml:space="preserve" 71.394 + 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" 71.395 + x="197.13031" 71.396 + y="349.07404" 71.397 + id="text3547"><tspan 71.398 + sodipodi:role="line" 71.399 + id="tspan3549" 71.400 + x="197.13031" 71.401 + y="349.07404" 71.402 + style="font-family:Courier">ff9dc8bc2a8b</tspan></text> 71.403 + </g> 71.404 + <g 71.405 + transform="matrix(0.423343,0,0,0.423343,144.3767,372.6502)" 71.406 + id="g3551"> 71.407 + <rect 71.408 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.409 + id="rect3553" 71.410 + width="213.85715" 71.411 + height="75" 71.412 + x="187.5" 71.413 + y="363.07654" /> 71.414 + <text 71.415 + xml:space="preserve" 71.416 + 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" 71.417 + x="196.02321" 71.418 + y="400.86459" 71.419 + id="text3555"><tspan 71.420 + sodipodi:role="line" 71.421 + id="tspan3557" 71.422 + x="196.02321" 71.423 + y="400.86459" 71.424 + style="fill:black;fill-opacity:1;font-family:Courier">...</tspan></text> 71.425 + <text 71.426 + xml:space="preserve" 71.427 + 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" 71.428 + x="196.71785" 71.429 + y="380.17593" 71.430 + id="text3559"><tspan 71.431 + style="fill:black;fill-opacity:1" 71.432 + id="tspan3561" 71.433 + sodipodi:role="line" 71.434 + x="196.71785" 71.435 + y="380.17593">Revision data (delta or snapshot)</tspan></text> 71.436 + </g> 71.437 + </g> 71.438 + <g 71.439 + id="g4868" 71.440 + transform="translate(-1.676208,-2.342463e-5)"> 71.441 + <rect 71.442 + style="fill:url(#linearGradient3708);fill-opacity:1;stroke:black;stroke-width:0.48811448;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.443 + id="rect3567" 71.444 + width="101.60232" 71.445 + height="89.506805" 71.446 + x="213.26137" 71.447 + y="59.171272" /> 71.448 + <g 71.449 + transform="matrix(0.423343,0,0,0.423343,138.8739,-67.01734)" 71.450 + id="g3573"> 71.451 + <rect 71.452 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.453 + id="rect3575" 71.454 + width="103.14286" 71.455 + height="48.571426" 71.456 + x="188.6071" 71.457 + y="447.72418" /> 71.458 + <text 71.459 + xml:space="preserve" 71.460 + 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" 71.461 + x="197.82495" 71.462 + y="464.82358" 71.463 + id="text3577"><tspan 71.464 + id="tspan3579" 71.465 + sodipodi:role="line" 71.466 + x="197.82495" 71.467 + y="464.82358">First parent</tspan></text> 71.468 + <text 71.469 + xml:space="preserve" 71.470 + 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" 71.471 + x="197.13031" 71.472 + y="485.51224" 71.473 + id="text3581"><tspan 71.474 + sodipodi:role="line" 71.475 + id="tspan3583" 71.476 + x="197.13031" 71.477 + y="485.51224" 71.478 + style="font-family:Courier">34b8b7a15ea1</tspan></text> 71.479 + </g> 71.480 + <g 71.481 + transform="matrix(0.423343,0,0,0.423343,138.8739,-67.01734)" 71.482 + id="g3585"> 71.483 + <rect 71.484 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.485 + id="rect3587" 71.486 + width="103.14286" 71.487 + height="48.571426" 71.488 + x="299.67859" 71.489 + y="447.71451" /> 71.490 + <text 71.491 + xml:space="preserve" 71.492 + 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" 71.493 + x="308.89639" 71.494 + y="464.8139" 71.495 + id="text3589"><tspan 71.496 + id="tspan3591" 71.497 + sodipodi:role="line" 71.498 + x="308.89639" 71.499 + y="464.8139">Second parent</tspan></text> 71.500 + <text 71.501 + xml:space="preserve" 71.502 + 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" 71.503 + x="308.20175" 71.504 + y="485.50256" 71.505 + id="text3593"><tspan 71.506 + sodipodi:role="line" 71.507 + id="tspan3595" 71.508 + x="308.20175" 71.509 + y="485.50256" 71.510 + style="font-family:Courier">000000000000</tspan></text> 71.511 + </g> 71.512 + <g 71.513 + transform="matrix(0.423343,0,0,0.423343,138.8739,-67.01733)" 71.514 + id="g3597"> 71.515 + <rect 71.516 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.517 + id="rect3599" 71.518 + width="103.14286" 71.519 + height="48.571426" 71.520 + x="188.6071" 71.521 + y="311.28598" /> 71.522 + <text 71.523 + xml:space="preserve" 71.524 + 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" 71.525 + x="197.82495" 71.526 + y="328.38538" 71.527 + id="text3601"><tspan 71.528 + id="tspan3603" 71.529 + sodipodi:role="line" 71.530 + x="197.82495" 71.531 + y="328.38538">Revision hash</tspan></text> 71.532 + <text 71.533 + xml:space="preserve" 71.534 + 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" 71.535 + x="197.13031" 71.536 + y="349.07404" 71.537 + id="text3605"><tspan 71.538 + sodipodi:role="line" 71.539 + id="tspan3607" 71.540 + x="197.13031" 71.541 + y="349.07404" 71.542 + style="font-family:Courier">1b67dc96f27a</tspan></text> 71.543 + </g> 71.544 + <g 71.545 + transform="matrix(0.423343,0,0,0.423343,139.3426,-65.65866)" 71.546 + id="g3609"> 71.547 + <rect 71.548 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.549 + id="rect3611" 71.550 + width="213.85715" 71.551 + height="75" 71.552 + x="187.5" 71.553 + y="363.07654" /> 71.554 + <text 71.555 + xml:space="preserve" 71.556 + 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" 71.557 + x="196.02321" 71.558 + y="400.86459" 71.559 + id="text3613"><tspan 71.560 + sodipodi:role="line" 71.561 + id="tspan3615" 71.562 + x="196.02321" 71.563 + y="400.86459" 71.564 + style="fill:black;fill-opacity:1;font-family:Courier">...</tspan></text> 71.565 + <text 71.566 + xml:space="preserve" 71.567 + 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" 71.568 + x="196.71785" 71.569 + y="380.17593" 71.570 + id="text3617"><tspan 71.571 + style="fill:black;fill-opacity:1" 71.572 + id="tspan3619" 71.573 + sodipodi:role="line" 71.574 + x="196.71785" 71.575 + y="380.17593">Revision data (delta or snapshot)</tspan></text> 71.576 + </g> 71.577 + </g> 71.578 + <path 71.579 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:url(#Arrow1Mend)" 71.580 + d="M 240.78255,143.08593 L 241.42595,171.75349" 71.581 + id="path3801" 71.582 + inkscape:connector-type="polyline" 71.583 + inkscape:connection-start="#g3573" 71.584 + inkscape:connection-end="#g3250" /> 71.585 + <g 71.586 + id="g5677"> 71.587 + <rect 71.588 + style="fill:url(#linearGradient5784);fill-opacity:1;stroke:black;stroke-width:0.48811448;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.589 + id="rect3393" 71.590 + width="101.60232" 71.591 + height="89.506805" 71.592 + x="150.76137" 71.593 + y="278.32565" /> 71.594 + <g 71.595 + transform="matrix(0.423343,0,0,0.423343,76.37397,152.137)" 71.596 + id="g3399"> 71.597 + <rect 71.598 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.599 + id="rect3401" 71.600 + width="103.14286" 71.601 + height="48.571426" 71.602 + x="188.6071" 71.603 + y="447.72418" /> 71.604 + <text 71.605 + xml:space="preserve" 71.606 + 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" 71.607 + x="197.82495" 71.608 + y="464.82358" 71.609 + id="text3403"><tspan 71.610 + id="tspan3405" 71.611 + sodipodi:role="line" 71.612 + x="197.82495" 71.613 + y="464.82358">First parent</tspan></text> 71.614 + <text 71.615 + xml:space="preserve" 71.616 + 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" 71.617 + x="197.13031" 71.618 + y="485.51224" 71.619 + id="text3407"><tspan 71.620 + sodipodi:role="line" 71.621 + id="tspan3409" 71.622 + x="197.13031" 71.623 + y="485.51224" 71.624 + style="font-family:Courier">ff9dc8bc2a8b</tspan></text> 71.625 + </g> 71.626 + <g 71.627 + transform="matrix(0.423343,0,0,0.423343,76.37397,152.137)" 71.628 + id="g3411"> 71.629 + <rect 71.630 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.631 + id="rect3413" 71.632 + width="103.14286" 71.633 + height="48.571426" 71.634 + x="299.67859" 71.635 + y="447.71451" /> 71.636 + <text 71.637 + xml:space="preserve" 71.638 + 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" 71.639 + x="308.89639" 71.640 + y="464.8139" 71.641 + id="text3415"><tspan 71.642 + id="tspan3417" 71.643 + sodipodi:role="line" 71.644 + x="308.89639" 71.645 + y="464.8139">Second parent</tspan></text> 71.646 + <text 71.647 + xml:space="preserve" 71.648 + 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" 71.649 + x="308.20175" 71.650 + y="485.50256" 71.651 + id="text3419"><tspan 71.652 + sodipodi:role="line" 71.653 + id="tspan3421" 71.654 + x="308.20175" 71.655 + y="485.50256" 71.656 + style="font-family:Courier">000000000000</tspan></text> 71.657 + </g> 71.658 + <g 71.659 + transform="matrix(0.423343,0,0,0.423343,76.37397,152.137)" 71.660 + id="g3423"> 71.661 + <rect 71.662 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.663 + id="rect3425" 71.664 + width="103.14286" 71.665 + height="48.571426" 71.666 + x="188.6071" 71.667 + y="311.28598" /> 71.668 + <text 71.669 + xml:space="preserve" 71.670 + 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" 71.671 + x="197.82495" 71.672 + y="328.38538" 71.673 + id="text3427"><tspan 71.674 + id="tspan3429" 71.675 + sodipodi:role="line" 71.676 + x="197.82495" 71.677 + y="328.38538">Revision hash</tspan></text> 71.678 + <text 71.679 + xml:space="preserve" 71.680 + 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" 71.681 + x="197.13031" 71.682 + y="349.07404" 71.683 + id="text3431"><tspan 71.684 + sodipodi:role="line" 71.685 + id="tspan3433" 71.686 + x="197.13031" 71.687 + y="349.07404" 71.688 + style="font-family:Courier">5b80c922ebdd</tspan></text> 71.689 + </g> 71.690 + <g 71.691 + transform="matrix(0.423343,0,0,0.423343,76.84265,153.4957)" 71.692 + id="g3435"> 71.693 + <rect 71.694 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.695 + id="rect3437" 71.696 + width="213.85715" 71.697 + height="75" 71.698 + x="187.5" 71.699 + y="363.07654" /> 71.700 + <text 71.701 + xml:space="preserve" 71.702 + 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" 71.703 + x="196.02321" 71.704 + y="400.86459" 71.705 + id="text3439"><tspan 71.706 + sodipodi:role="line" 71.707 + id="tspan3441" 71.708 + x="196.02321" 71.709 + y="400.86459" 71.710 + style="fill:black;fill-opacity:1;font-family:Courier">...</tspan></text> 71.711 + <text 71.712 + xml:space="preserve" 71.713 + 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" 71.714 + x="196.71785" 71.715 + y="380.17593" 71.716 + id="text3443"><tspan 71.717 + style="fill:black;fill-opacity:1" 71.718 + id="tspan3445" 71.719 + sodipodi:role="line" 71.720 + x="196.71785" 71.721 + y="380.17593">Revision data (delta or snapshot)</tspan></text> 71.722 + </g> 71.723 + </g> 71.724 + <g 71.725 + id="g5646" 71.726 + transform="translate(-0.227432,0)"> 71.727 + <rect 71.728 + style="fill:url(#linearGradient5786);fill-opacity:1;stroke:black;stroke-width:0.48811448;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.729 + id="rect3451" 71.730 + width="101.60232" 71.731 + height="89.506805" 71.732 + x="272.63638" 71.733 + y="278.32565" /> 71.734 + <g 71.735 + transform="matrix(0.423343,0,0,0.423343,198.2489,152.137)" 71.736 + id="g3457"> 71.737 + <rect 71.738 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.739 + id="rect3459" 71.740 + width="103.14286" 71.741 + height="48.571426" 71.742 + x="188.6071" 71.743 + y="447.72418" /> 71.744 + <text 71.745 + xml:space="preserve" 71.746 + 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" 71.747 + x="197.82495" 71.748 + y="464.82358" 71.749 + id="text3461"><tspan 71.750 + id="tspan3463" 71.751 + sodipodi:role="line" 71.752 + x="197.82495" 71.753 + y="464.82358">First parent</tspan></text> 71.754 + <text 71.755 + xml:space="preserve" 71.756 + 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" 71.757 + x="197.13031" 71.758 + y="485.51224" 71.759 + id="text3465"><tspan 71.760 + sodipodi:role="line" 71.761 + id="tspan3467" 71.762 + x="197.13031" 71.763 + y="485.51224" 71.764 + style="font-family:Courier">ecacb6b4c9fd</tspan></text> 71.765 + </g> 71.766 + <g 71.767 + transform="matrix(0.423343,0,0,0.423343,198.2489,152.137)" 71.768 + id="g3469"> 71.769 + <rect 71.770 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.771 + id="rect3471" 71.772 + width="103.14286" 71.773 + height="48.571426" 71.774 + x="299.67859" 71.775 + y="447.71451" /> 71.776 + <text 71.777 + xml:space="preserve" 71.778 + 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" 71.779 + x="308.89639" 71.780 + y="464.8139" 71.781 + id="text3473"><tspan 71.782 + id="tspan3475" 71.783 + sodipodi:role="line" 71.784 + x="308.89639" 71.785 + y="464.8139">Second parent</tspan></text> 71.786 + <text 71.787 + xml:space="preserve" 71.788 + 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" 71.789 + x="308.20175" 71.790 + y="485.50256" 71.791 + id="text3477"><tspan 71.792 + sodipodi:role="line" 71.793 + id="tspan3479" 71.794 + x="308.20175" 71.795 + y="485.50256" 71.796 + style="font-family:Courier">000000000000</tspan></text> 71.797 + </g> 71.798 + <g 71.799 + transform="matrix(0.423343,0,0,0.423343,198.2489,152.137)" 71.800 + id="g3481"> 71.801 + <rect 71.802 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.803 + id="rect3483" 71.804 + width="103.14286" 71.805 + height="48.571426" 71.806 + x="188.6071" 71.807 + y="311.28598" /> 71.808 + <text 71.809 + xml:space="preserve" 71.810 + 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" 71.811 + x="197.82495" 71.812 + y="328.38538" 71.813 + id="text3485"><tspan 71.814 + id="tspan3487" 71.815 + sodipodi:role="line" 71.816 + x="197.82495" 71.817 + y="328.38538">Revision hash</tspan></text> 71.818 + <text 71.819 + xml:space="preserve" 71.820 + 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" 71.821 + x="197.13031" 71.822 + y="349.07404" 71.823 + id="text3489"><tspan 71.824 + sodipodi:role="line" 71.825 + id="tspan3491" 71.826 + x="197.13031" 71.827 + y="349.07404" 71.828 + style="font-family:Courier">32bf9a5f22c0</tspan></text> 71.829 + </g> 71.830 + <g 71.831 + transform="matrix(0.423343,0,0,0.423343,198.7176,153.4957)" 71.832 + id="g3493"> 71.833 + <rect 71.834 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.835 + id="rect3495" 71.836 + width="213.85715" 71.837 + height="75" 71.838 + x="187.5" 71.839 + y="363.07654" /> 71.840 + <text 71.841 + xml:space="preserve" 71.842 + 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" 71.843 + x="196.02321" 71.844 + y="400.86459" 71.845 + id="text3497"><tspan 71.846 + sodipodi:role="line" 71.847 + id="tspan3499" 71.848 + x="196.02321" 71.849 + y="400.86459" 71.850 + style="fill:black;fill-opacity:1;font-family:Courier">...</tspan></text> 71.851 + <text 71.852 + xml:space="preserve" 71.853 + 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" 71.854 + x="196.71785" 71.855 + y="380.17593" 71.856 + id="text3501"><tspan 71.857 + style="fill:black;fill-opacity:1" 71.858 + id="tspan3503" 71.859 + sodipodi:role="line" 71.860 + x="196.71785" 71.861 + y="380.17593">Revision data (delta or snapshot)</tspan></text> 71.862 + </g> 71.863 + </g> 71.864 + <rect 71.865 + y="387.90286" 71.866 + x="272.40894" 71.867 + height="89.506805" 71.868 + width="101.60232" 71.869 + id="rect5081" 71.870 + style="fill:url(#linearGradient5895);fill-opacity:1;stroke:black;stroke-width:0.48811448;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.871 + <g 71.872 + id="g5087" 71.873 + transform="matrix(0.423343,0,0,0.423343,198.0214,261.7142)"> 71.874 + <rect 71.875 + y="447.72418" 71.876 + x="188.6071" 71.877 + height="48.571426" 71.878 + width="103.14286" 71.879 + id="rect5089" 71.880 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.881 + <text 71.882 + id="text5091" 71.883 + y="464.82358" 71.884 + x="197.82495" 71.885 + 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" 71.886 + xml:space="preserve"><tspan 71.887 + y="464.82358" 71.888 + x="197.82495" 71.889 + sodipodi:role="line" 71.890 + id="tspan5093">First parent</tspan></text> 71.891 + <text 71.892 + id="text5095" 71.893 + y="485.51224" 71.894 + x="197.13031" 71.895 + 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" 71.896 + xml:space="preserve"><tspan 71.897 + style="font-family:Courier" 71.898 + y="485.51224" 71.899 + x="197.13031" 71.900 + id="tspan5097" 71.901 + sodipodi:role="line">ff9dc8bc2a8b</tspan></text> 71.902 + </g> 71.903 + <g 71.904 + id="g5099" 71.905 + transform="matrix(0.423343,0,0,0.423343,198.0214,261.7142)"> 71.906 + <rect 71.907 + y="447.71451" 71.908 + x="299.67859" 71.909 + height="48.571426" 71.910 + width="103.14286" 71.911 + id="rect5101" 71.912 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.913 + <text 71.914 + id="text5103" 71.915 + y="464.8139" 71.916 + x="308.89639" 71.917 + 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" 71.918 + xml:space="preserve"><tspan 71.919 + y="464.8139" 71.920 + x="308.89639" 71.921 + sodipodi:role="line" 71.922 + id="tspan5105">Second parent</tspan></text> 71.923 + <text 71.924 + id="text5107" 71.925 + y="485.50256" 71.926 + x="308.20175" 71.927 + 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" 71.928 + xml:space="preserve"><tspan 71.929 + style="font-family:Courier" 71.930 + y="485.50256" 71.931 + x="308.20175" 71.932 + id="tspan5109" 71.933 + sodipodi:role="line">000000000000</tspan></text> 71.934 + </g> 71.935 + <g 71.936 + id="g5111" 71.937 + transform="matrix(0.423343,0,0,0.423343,198.0214,261.7142)"> 71.938 + <rect 71.939 + y="311.28598" 71.940 + x="188.6071" 71.941 + height="48.571426" 71.942 + width="103.14286" 71.943 + id="rect5113" 71.944 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.945 + <text 71.946 + id="text5115" 71.947 + y="328.38538" 71.948 + x="197.82495" 71.949 + 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" 71.950 + xml:space="preserve"><tspan 71.951 + y="328.38538" 71.952 + x="197.82495" 71.953 + sodipodi:role="line" 71.954 + id="tspan5117">Revision hash</tspan></text> 71.955 + <text 71.956 + id="text5119" 71.957 + y="349.07404" 71.958 + x="197.13031" 71.959 + 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" 71.960 + xml:space="preserve"><tspan 71.961 + style="font-family:Courier" 71.962 + y="349.07404" 71.963 + x="197.13031" 71.964 + id="tspan5121" 71.965 + sodipodi:role="line">ecacb6b4c9fd</tspan></text> 71.966 + </g> 71.967 + <g 71.968 + id="g5123" 71.969 + transform="matrix(0.423343,0,0,0.423343,198.4901,263.0729)"> 71.970 + <rect 71.971 + y="363.07654" 71.972 + x="187.5" 71.973 + height="75" 71.974 + width="213.85715" 71.975 + id="rect5125" 71.976 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 71.977 + <text 71.978 + id="text5127" 71.979 + y="400.86459" 71.980 + x="196.02321" 71.981 + 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" 71.982 + xml:space="preserve"><tspan 71.983 + style="fill:black;fill-opacity:1;font-family:Courier" 71.984 + y="400.86459" 71.985 + x="196.02321" 71.986 + id="tspan5129" 71.987 + sodipodi:role="line">...</tspan></text> 71.988 + <text 71.989 + id="text5131" 71.990 + y="380.17593" 71.991 + x="196.71785" 71.992 + 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" 71.993 + xml:space="preserve"><tspan 71.994 + y="380.17593" 71.995 + x="196.71785" 71.996 + sodipodi:role="line" 71.997 + id="tspan5133" 71.998 + style="fill:black;fill-opacity:1">Revision data (delta or snapshot)</tspan></text> 71.999 + </g> 71.1000 + <path 71.1001 + 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;display:inline" 71.1002 + d="M 299.69935,362.24027 L 299.69931,393.49494" 71.1003 + id="path5203" 71.1004 + inkscape:connector-type="polyline" 71.1005 + inkscape:connection-start="#g3457" 71.1006 + inkscape:connection-end="#g5111" /> 71.1007 + <path 71.1008 + 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" 71.1009 + d="M 182.35357,362.22647 L 241.2842,503.07224" 71.1010 + id="path5271" 71.1011 + inkscape:connector-type="polyline" 71.1012 + inkscape:connection-start="#g3399" 71.1013 + inkscape:connection-end="#g3539" /> 71.1014 + <path 71.1015 + 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;display:inline" 71.1016 + d="M 287.63109,471.81747 L 250.9438,503.07223" 71.1017 + id="path5285" 71.1018 + inkscape:connector-type="polyline" 71.1019 + inkscape:connection-start="#g5087" 71.1020 + inkscape:connection-end="#g3539" /> 71.1021 + <path 71.1022 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 71.1023 + d="M 290.80419,250.07192 L 297.80065,283.90394" 71.1024 + id="path5077" 71.1025 + inkscape:connector-type="polyline" 71.1026 + inkscape:connection-start="#g3215" 71.1027 + inkscape:connection-end="#g3481" /> 71.1028 + <path 71.1029 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 71.1030 + d="M 229.63373,250.07601 L 190.07484,283.90394" 71.1031 + id="path5075" 71.1032 + inkscape:connector-type="polyline" 71.1033 + inkscape:connection-end="#g3423" /> 71.1034 + <text 71.1035 + xml:space="preserve" 71.1036 + 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" 71.1037 + x="131.5625" 71.1038 + y="100.79968" 71.1039 + id="text5897"><tspan 71.1040 + sodipodi:role="line" 71.1041 + id="tspan5899" 71.1042 + x="131.5625" 71.1043 + y="100.79968" 71.1044 + style="text-align:end;text-anchor:end">Head revision</tspan><tspan 71.1045 + sodipodi:role="line" 71.1046 + x="131.5625" 71.1047 + y="115.79968" 71.1048 + id="tspan5901" 71.1049 + style="text-align:end;text-anchor:end">(no children)</tspan></text> 71.1050 + <text 71.1051 + xml:space="preserve" 71.1052 + 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" 71.1053 + x="131.5625" 71.1054 + y="207.04968" 71.1055 + id="text5903"><tspan 71.1056 + sodipodi:role="line" 71.1057 + id="tspan5905" 71.1058 + x="131.5625" 71.1059 + y="207.04968" 71.1060 + style="text-align:end;text-anchor:end">Merge revision</tspan><tspan 71.1061 + sodipodi:role="line" 71.1062 + x="131.5625" 71.1063 + y="222.04968" 71.1064 + id="tspan5907" 71.1065 + style="text-align:end;text-anchor:end">(two parents)</tspan></text> 71.1066 + <text 71.1067 + xml:space="preserve" 71.1068 + 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" 71.1069 + x="131.92578" 71.1070 + y="451.58093" 71.1071 + id="text5909"><tspan 71.1072 + sodipodi:role="line" 71.1073 + id="tspan5911" 71.1074 + x="131.92578" 71.1075 + y="451.58093" 71.1076 + style="text-align:end;text-anchor:end">Branches</tspan><tspan 71.1077 + sodipodi:role="line" 71.1078 + x="131.92578" 71.1079 + y="466.58093" 71.1080 + id="tspan5913" 71.1081 + style="text-align:end;text-anchor:end">(two revisions,</tspan><tspan 71.1082 + sodipodi:role="line" 71.1083 + x="131.92578" 71.1084 + y="481.58093" 71.1085 + id="tspan5915" 71.1086 + style="text-align:end;text-anchor:end">same parent)</tspan></text> 71.1087 + <path 71.1088 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:2, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" 71.1089 + d="M 111.71875,433.61218 L 154.7268,368.52294" 71.1090 + id="path5917" 71.1091 + inkscape:connector-type="polyline" /> 71.1092 + <path 71.1093 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:2, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" 71.1094 + d="M 134.375,464.86218 L 277.86691,440.37816" 71.1095 + id="path5919" 71.1096 + inkscape:connector-type="polyline" 71.1097 + inkscape:connection-end="#g5123" /> 71.1098 + <text 71.1099 + xml:space="preserve" 71.1100 + style="font-size:12px;font-style:normal;font-weight:normal;text-align:end;text-anchor:end;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 71.1101 + x="131.5625" 71.1102 + y="536.73718" 71.1103 + id="text5927"><tspan 71.1104 + sodipodi:role="line" 71.1105 + id="tspan5929" 71.1106 + x="131.5625" 71.1107 + y="536.73718">First revision</tspan><tspan 71.1108 + sodipodi:role="line" 71.1109 + x="131.5625" 71.1110 + y="551.73718" 71.1111 + id="tspan5931">(both parents null)</tspan></text> 71.1112 + <rect 71.1113 + style="fill:#bbb4ff;fill-opacity:1;stroke:none;stroke-width:0.95291203;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 71.1114 + id="rect2830" 71.1115 + width="43.664806" 71.1116 + height="20.562374" 71.1117 + x="217.0432" 71.1118 + y="232.10075" /> 71.1119 + <text 71.1120 + xml:space="preserve" 71.1121 + style="font-size:5.0801158px;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" 71.1122 + x="220.94551" 71.1123 + y="239.33966" 71.1124 + id="text2832"><tspan 71.1125 + id="tspan2836" 71.1126 + sodipodi:role="line" 71.1127 + x="220.94551" 71.1128 + y="239.33966">First parent</tspan></text> 71.1129 + <text 71.1130 + xml:space="preserve" 71.1131 + style="font-size:5.0801158px;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" 71.1132 + x="220.65144" 71.1133 + y="248.09805" 71.1134 + id="text2879"><tspan 71.1135 + sodipodi:role="line" 71.1136 + id="tspan2881" 71.1137 + x="220.65144" 71.1138 + y="248.09805" 71.1139 + style="font-family:Courier">5b80c922ebdd</tspan></text> 71.1140 + <path 71.1141 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:2, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" 71.1142 + d="M 139.84375,107.83093 L 210.15625,107.83093" 71.1143 + id="path5965" 71.1144 + inkscape:connector-type="polyline" /> 71.1145 + <path 71.1146 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:2, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" 71.1147 + d="M 137.5,213.29968 L 210.49036,214.09055" 71.1148 + id="path5967" 71.1149 + inkscape:connector-type="polyline" /> 71.1150 + <path 71.1151 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:2, 1;stroke-dashoffset:0;stroke-opacity:1;display:inline" 71.1152 + d="M 136.34375,544.54968 L 206.65625,544.54968" 71.1153 + id="path5969" 71.1154 + inkscape:connector-type="polyline" 71.1155 + inkscape:transform-center-y="-171.09375" 71.1156 + inkscape:transform-center-x="53.90625" /> 71.1157 + </g> 71.1158 +</svg>
72.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 72.2 +++ b/fr/snapshot.svg Thu Feb 05 12:37:03 2009 +0100 72.3 @@ -0,0 +1,202 @@ 72.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 72.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 72.6 +<svg 72.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 72.8 + xmlns:cc="http://web.resource.org/cc/" 72.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 72.10 + xmlns:svg="http://www.w3.org/2000/svg" 72.11 + xmlns="http://www.w3.org/2000/svg" 72.12 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 72.13 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 72.14 + width="744.09448819" 72.15 + height="1052.3622047" 72.16 + id="svg2807" 72.17 + sodipodi:version="0.32" 72.18 + inkscape:version="0.44.1" 72.19 + sodipodi:docbase="/home/bos/hg/hgbook/en" 72.20 + sodipodi:docname="snapshots.svg"> 72.21 + <defs 72.22 + id="defs2809" /> 72.23 + <sodipodi:namedview 72.24 + id="base" 72.25 + pagecolor="#ffffff" 72.26 + bordercolor="#666666" 72.27 + borderopacity="1.0" 72.28 + gridtolerance="10000" 72.29 + guidetolerance="10" 72.30 + objecttolerance="10" 72.31 + inkscape:pageopacity="0.0" 72.32 + inkscape:pageshadow="2" 72.33 + inkscape:zoom="1.4" 72.34 + inkscape:cx="252.04111" 72.35 + inkscape:cy="605.75448" 72.36 + inkscape:document-units="px" 72.37 + inkscape:current-layer="layer1" 72.38 + inkscape:window-width="906" 72.39 + inkscape:window-height="721" 72.40 + inkscape:window-x="0" 72.41 + inkscape:window-y="25" /> 72.42 + <metadata 72.43 + id="metadata2812"> 72.44 + <rdf:RDF> 72.45 + <cc:Work 72.46 + rdf:about=""> 72.47 + <dc:format>image/svg+xml</dc:format> 72.48 + <dc:type 72.49 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 72.50 + </cc:Work> 72.51 + </rdf:RDF> 72.52 + </metadata> 72.53 + <g 72.54 + inkscape:label="Layer 1" 72.55 + inkscape:groupmode="layer" 72.56 + id="layer1"> 72.57 + <rect 72.58 + style="opacity:1;fill:#d3ceff;fill-opacity:1;stroke:#a7a7a7;stroke-width:1.88795626;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 72.59 + id="rect2817" 72.60 + width="118.18347" 72.61 + height="245.32632" 72.62 + x="243.05112" 72.63 + y="315.4133" 72.64 + inkscape:transform-center-x="136.84403" 72.65 + inkscape:transform-center-y="-66.529183" /> 72.66 + <rect 72.67 + y="315.04153" 72.68 + x="46.965065" 72.69 + height="97.803009" 72.70 + width="108.92702" 72.71 + id="rect2815" 72.72 + style="fill:#ffced6;fill-opacity:1;stroke:#a7a7a7;stroke-width:1.14441991;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 72.73 + <g 72.74 + id="g3814"> 72.75 + <rect 72.76 + y="348.94302" 72.77 + x="59.285713" 72.78 + height="30" 72.79 + width="84.285713" 72.80 + id="rect2819" 72.81 + style="fill:#ff6e86;fill-opacity:1;stroke:#a7a7a7;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 72.82 + ry="0" /> 72.83 + <text 72.84 + id="text2821" 72.85 + y="368.02701" 72.86 + x="72.717636" 72.87 + 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" 72.88 + xml:space="preserve"><tspan 72.89 + y="368.02701" 72.90 + x="72.717636" 72.91 + id="tspan2823" 72.92 + sodipodi:role="line">Index, rev 7</tspan></text> 72.93 + </g> 72.94 + <text 72.95 + id="text3722" 72.96 + y="301.29074" 72.97 + x="46.187778" 72.98 + 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" 72.99 + xml:space="preserve"><tspan 72.100 + y="301.29074" 72.101 + x="46.187778" 72.102 + id="tspan3724" 72.103 + sodipodi:role="line">Revlog index (.i file)</tspan></text> 72.104 + <text 72.105 + id="text3726" 72.106 + y="301.29074" 72.107 + x="241.90207" 72.108 + 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" 72.109 + xml:space="preserve"><tspan 72.110 + y="301.29074" 72.111 + x="241.90207" 72.112 + id="tspan3728" 72.113 + sodipodi:role="line">Revlog data (.d file)</tspan></text> 72.114 + <path 72.115 + style="fill:#c695ff;fill-opacity:0.60109288;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 72.116 + d="M 143.57143,348.07647 L 255,368.07646 L 255.71429,544.50504 L 142.85714,379.50504 L 143.57143,348.07647 z " 72.117 + id="path3839" 72.118 + sodipodi:nodetypes="ccccc" /> 72.119 + <rect 72.120 + style="fill:#4733ff;fill-opacity:1;stroke:#a7a7a7;stroke-width:2.35124183;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 72.121 + id="rect3752" 72.122 + width="92.720184" 72.123 + height="67.005905" 72.124 + x="255.42564" 72.125 + y="368.64264" /> 72.126 + <text 72.127 + xml:space="preserve" 72.128 + 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" 72.129 + x="264.45859" 72.130 + y="387.30099" 72.131 + id="text3754"><tspan 72.132 + sodipodi:role="line" 72.133 + id="tspan3756" 72.134 + x="264.45859" 72.135 + y="387.30099">Snapshot, rev 4</tspan></text> 72.136 + <rect 72.137 + style="fill:#7c6eff;fill-opacity:1;stroke:#a7a7a7;stroke-width:1.57776296;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 72.138 + id="rect3761" 72.139 + width="93.49366" 72.140 + height="29.922237" 72.141 + x="255.03891" 72.142 + y="442.04395" /> 72.143 + <text 72.144 + xml:space="preserve" 72.145 + 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" 72.146 + x="263.2662" 72.147 + y="460.17206" 72.148 + id="text3763"><tspan 72.149 + sodipodi:role="line" 72.150 + id="tspan3765" 72.151 + x="263.2662" 72.152 + y="460.17206">Delta, rev 4 to 5</tspan></text> 72.153 + <rect 72.154 + style="fill:#7c6eff;fill-opacity:1;stroke:#a7a7a7;stroke-width:1.57776296;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 72.155 + id="rect3774" 72.156 + width="93.49366" 72.157 + height="29.922237" 72.158 + x="255.03891" 72.159 + y="477.97485" /> 72.160 + <text 72.161 + xml:space="preserve" 72.162 + 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" 72.163 + x="263.2662" 72.164 + y="496.10297" 72.165 + id="text3776"><tspan 72.166 + sodipodi:role="line" 72.167 + id="tspan3778" 72.168 + x="263.2662" 72.169 + y="496.10297">Delta, rev 5 to 6</tspan></text> 72.170 + <rect 72.171 + style="fill:#7c6eff;fill-opacity:1;stroke:#a7a7a7;stroke-width:1.57776296;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 72.172 + id="rect3782" 72.173 + width="93.49366" 72.174 + height="29.922237" 72.175 + x="255.03891" 72.176 + y="513.90576" /> 72.177 + <text 72.178 + xml:space="preserve" 72.179 + 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" 72.180 + x="263.2662" 72.181 + y="532.03387" 72.182 + id="text3784"><tspan 72.183 + sodipodi:role="line" 72.184 + id="tspan3786" 72.185 + x="263.2662" 72.186 + y="532.03387">Delta, rev 6 to 7</tspan></text> 72.187 + <rect 72.188 + style="fill:#7c6eff;fill-opacity:1;stroke:#a7a7a7;stroke-width:1.57776296;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 72.189 + id="rect3889" 72.190 + width="93.49366" 72.191 + height="29.922237" 72.192 + x="255.03891" 72.193 + y="332.32489" /> 72.194 + <text 72.195 + xml:space="preserve" 72.196 + 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" 72.197 + x="263.2662" 72.198 + y="350.453" 72.199 + id="text3891"><tspan 72.200 + sodipodi:role="line" 72.201 + id="tspan3893" 72.202 + x="263.2662" 72.203 + y="350.453">Delta, rev 2 to 3</tspan></text> 72.204 + </g> 72.205 +</svg>
73.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 73.2 +++ b/fr/srcinstall.tex Thu Feb 05 12:37:03 2009 +0100 73.3 @@ -0,0 +1,53 @@ 73.4 +\chapter{Installing Mercurial from source} 73.5 +\label{chap:srcinstall} 73.6 + 73.7 +\section{On a Unix-like system} 73.8 +\label{sec:srcinstall:unixlike} 73.9 + 73.10 +If you are using a Unix-like system that has a sufficiently recent 73.11 +version of Python (2.3~or newer) available, it is easy to install 73.12 +Mercurial from source. 73.13 +\begin{enumerate} 73.14 +\item Download a recent source tarball from 73.15 + \url{http://www.selenic.com/mercurial/download}. 73.16 +\item Unpack the tarball: 73.17 + \begin{codesample4} 73.18 + gzip -dc mercurial-\emph{version}.tar.gz | tar xf - 73.19 + \end{codesample4} 73.20 +\item Go into the source directory and run the installer script. This 73.21 + will build Mercurial and install it in your home directory. 73.22 + \begin{codesample4} 73.23 + cd mercurial-\emph{version} 73.24 + python setup.py install --force --home=\$HOME 73.25 + \end{codesample4} 73.26 +\end{enumerate} 73.27 +Once the install finishes, Mercurial will be in the \texttt{bin} 73.28 +subdirectory of your home directory. Don't forget to make sure that 73.29 +this directory is present in your shell's search path. 73.30 + 73.31 +You will probably need to set the \envar{PYTHONPATH} environment 73.32 +variable so that the Mercurial executable can find the rest of the 73.33 +Mercurial packages. For example, on my laptop, I have set it to 73.34 +\texttt{/home/bos/lib/python}. The exact path that you will need to 73.35 +use depends on how Python was built for your system, but should be 73.36 +easy to figure out. If you're uncertain, look through the output of 73.37 +the installer script above, and see where the contents of the 73.38 +\texttt{mercurial} directory were installed to. 73.39 + 73.40 +\section{On Windows} 73.41 + 73.42 +Building and installing Mercurial on Windows requires a variety of 73.43 +tools, a fair amount of technical knowledge, and considerable 73.44 +patience. I very much \emph{do not recommend} this route if you are a 73.45 +``casual user''. Unless you intend to hack on Mercurial, I strongly 73.46 +suggest that you use a binary package instead. 73.47 + 73.48 +If you are intent on building Mercurial from source on Windows, follow 73.49 +the ``hard way'' directions on the Mercurial wiki at 73.50 +\url{http://www.selenic.com/mercurial/wiki/index.cgi/WindowsInstall}, 73.51 +and expect the process to involve a lot of fiddly work. 73.52 + 73.53 +%%% Local Variables: 73.54 +%%% mode: latex 73.55 +%%% TeX-master: "00book" 73.56 +%%% End:
74.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 74.2 +++ b/fr/template.tex Thu Feb 05 12:37:03 2009 +0100 74.3 @@ -0,0 +1,475 @@ 74.4 +\chapter{Customising the output of Mercurial} 74.5 +\label{chap:template} 74.6 + 74.7 +Mercurial provides a powerful mechanism to let you control how it 74.8 +displays information. The mechanism is based on templates. You can 74.9 +use templates to generate specific output for a single command, or to 74.10 +customise the entire appearance of the built-in web interface. 74.11 + 74.12 +\section{Using precanned output styles} 74.13 +\label{sec:style} 74.14 + 74.15 +Packaged with Mercurial are some output styles that you can use 74.16 +immediately. A style is simply a precanned template that someone 74.17 +wrote and installed somewhere that Mercurial can find. 74.18 + 74.19 +Before we take a look at Mercurial's bundled styles, let's review its 74.20 +normal output. 74.21 + 74.22 +\interaction{template.simple.normal} 74.23 + 74.24 +This is somewhat informative, but it takes up a lot of space---five 74.25 +lines of output per changeset. The \texttt{compact} style reduces 74.26 +this to three lines, presented in a sparse manner. 74.27 + 74.28 +\interaction{template.simple.compact} 74.29 + 74.30 +The \texttt{changelog} style hints at the expressive power of 74.31 +Mercurial's templating engine. This style attempts to follow the GNU 74.32 +Project's changelog guidelines\cite{web:changelog}. 74.33 + 74.34 +\interaction{template.simple.changelog} 74.35 + 74.36 +You will not be shocked to learn that Mercurial's default output style 74.37 +is named \texttt{default}. 74.38 + 74.39 +\subsection{Setting a default style} 74.40 + 74.41 +You can modify the output style that Mercurial will use for every 74.42 +command by editing your \hgrc\ file, naming the style you would 74.43 +prefer to use. 74.44 + 74.45 +\begin{codesample2} 74.46 + [ui] 74.47 + style = compact 74.48 +\end{codesample2} 74.49 + 74.50 +If you write a style of your own, you can use it by either providing 74.51 +the path to your style file, or copying your style file into a 74.52 +location where Mercurial can find it (typically the \texttt{templates} 74.53 +subdirectory of your Mercurial install directory). 74.54 + 74.55 +\section{Commands that support styles and templates} 74.56 + 74.57 +All of Mercurial's ``\texttt{log}-like'' commands let you use styles 74.58 +and templates: \hgcmd{incoming}, \hgcmd{log}, \hgcmd{outgoing}, and 74.59 +\hgcmd{tip}. 74.60 + 74.61 +As I write this manual, these are so far the only commands that 74.62 +support styles and templates. Since these are the most important 74.63 +commands that need customisable output, there has been little pressure 74.64 +from the Mercurial user community to add style and template support to 74.65 +other commands. 74.66 + 74.67 +\section{The basics of templating} 74.68 + 74.69 +At its simplest, a Mercurial template is a piece of text. Some of the 74.70 +text never changes, while other parts are \emph{expanded}, or replaced 74.71 +with new text, when necessary. 74.72 + 74.73 +Before we continue, let's look again at a simple example of 74.74 +Mercurial's normal output. 74.75 + 74.76 +\interaction{template.simple.normal} 74.77 + 74.78 +Now, let's run the same command, but using a template to change its 74.79 +output. 74.80 + 74.81 +\interaction{template.simple.simplest} 74.82 + 74.83 +The example above illustrates the simplest possible template; it's 74.84 +just a piece of static text, printed once for each changeset. The 74.85 +\hgopt{log}{--template} option to the \hgcmd{log} command tells 74.86 +Mercurial to use the given text as the template when printing each 74.87 +changeset. 74.88 + 74.89 +Notice that the template string above ends with the text 74.90 +``\Verb+\n+''. This is an \emph{escape sequence}, telling Mercurial 74.91 +to print a newline at the end of each template item. If you omit this 74.92 +newline, Mercurial will run each piece of output together. See 74.93 +section~\ref{sec:template:escape} for more details of escape sequences. 74.94 + 74.95 +A template that prints a fixed string of text all the time isn't very 74.96 +useful; let's try something a bit more complex. 74.97 + 74.98 +\interaction{template.simple.simplesub} 74.99 + 74.100 +As you can see, the string ``\Verb+{desc}+'' in the template has been 74.101 +replaced in the output with the description of each changeset. Every 74.102 +time Mercurial finds text enclosed in curly braces (``\texttt{\{}'' 74.103 +and ``\texttt{\}}''), it will try to replace the braces and text with 74.104 +the expansion of whatever is inside. To print a literal curly brace, 74.105 +you must escape it, as described in section~\ref{sec:template:escape}. 74.106 + 74.107 +\section{Common template keywords} 74.108 +\label{sec:template:keyword} 74.109 + 74.110 +You can start writing simple templates immediately using the keywords 74.111 +below. 74.112 + 74.113 +\begin{itemize} 74.114 +\item[\tplkword{author}] String. The unmodified author of the changeset. 74.115 +\item[\tplkword{branches}] String. The name of the branch on which 74.116 + the changeset was committed. Will be empty if the branch name was 74.117 + \texttt{default}. 74.118 +\item[\tplkword{date}] Date information. The date when the changeset 74.119 + was committed. This is \emph{not} human-readable; you must pass it 74.120 + through a filter that will render it appropriately. See 74.121 + section~\ref{sec:template:filter} for more information on filters. 74.122 + The date is expressed as a pair of numbers. The first number is a 74.123 + Unix UTC timestamp (seconds since January 1, 1970); the second is 74.124 + the offset of the committer's timezone from UTC, in seconds. 74.125 +\item[\tplkword{desc}] String. The text of the changeset description. 74.126 +\item[\tplkword{files}] List of strings. All files modified, added, or 74.127 + removed by this changeset. 74.128 +\item[\tplkword{file\_adds}] List of strings. Files added by this 74.129 + changeset. 74.130 +\item[\tplkword{file\_dels}] List of strings. Files removed by this 74.131 + changeset. 74.132 +\item[\tplkword{node}] String. The changeset identification hash, as a 74.133 + 40-character hexadecimal string. 74.134 +\item[\tplkword{parents}] List of strings. The parents of the 74.135 + changeset. 74.136 +\item[\tplkword{rev}] Integer. The repository-local changeset revision 74.137 + number. 74.138 +\item[\tplkword{tags}] List of strings. Any tags associated with the 74.139 + changeset. 74.140 +\end{itemize} 74.141 + 74.142 +A few simple experiments will show us what to expect when we use these 74.143 +keywords; you can see the results in 74.144 +figure~\ref{fig:template:keywords}. 74.145 + 74.146 +\begin{figure} 74.147 + \interaction{template.simple.keywords} 74.148 + \caption{Template keywords in use} 74.149 + \label{fig:template:keywords} 74.150 +\end{figure} 74.151 + 74.152 +As we noted above, the date keyword does not produce human-readable 74.153 +output, so we must treat it specially. This involves using a 74.154 +\emph{filter}, about which more in section~\ref{sec:template:filter}. 74.155 + 74.156 +\interaction{template.simple.datekeyword} 74.157 + 74.158 +\section{Escape sequences} 74.159 +\label{sec:template:escape} 74.160 + 74.161 +Mercurial's templating engine recognises the most commonly used escape 74.162 +sequences in strings. When it sees a backslash (``\Verb+\+'') 74.163 +character, it looks at the following character and substitutes the two 74.164 +characters with a single replacement, as described below. 74.165 + 74.166 +\begin{itemize} 74.167 +\item[\Verb+\textbackslash\textbackslash+] Backslash, ``\Verb+\+'', 74.168 + ASCII~134. 74.169 +\item[\Verb+\textbackslash n+] Newline, ASCII~12. 74.170 +\item[\Verb+\textbackslash r+] Carriage return, ASCII~15. 74.171 +\item[\Verb+\textbackslash t+] Tab, ASCII~11. 74.172 +\item[\Verb+\textbackslash v+] Vertical tab, ASCII~13. 74.173 +\item[\Verb+\textbackslash \{+] Open curly brace, ``\Verb+{+'', ASCII~173. 74.174 +\item[\Verb+\textbackslash \}+] Close curly brace, ``\Verb+}+'', ASCII~175. 74.175 +\end{itemize} 74.176 + 74.177 +As indicated above, if you want the expansion of a template to contain 74.178 +a literal ``\Verb+\+'', ``\Verb+{+'', or ``\Verb+{+'' character, you 74.179 +must escape it. 74.180 + 74.181 +\section{Filtering keywords to change their results} 74.182 +\label{sec:template:filter} 74.183 + 74.184 +Some of the results of template expansion are not immediately easy to 74.185 +use. Mercurial lets you specify an optional chain of \emph{filters} 74.186 +to modify the result of expanding a keyword. You have already seen a 74.187 +common filter, \tplkwfilt{date}{isodate}, in action above, to make a 74.188 +date readable. 74.189 + 74.190 +Below is a list of the most commonly used filters that Mercurial 74.191 +supports. While some filters can be applied to any text, others can 74.192 +only be used in specific circumstances. The name of each filter is 74.193 +followed first by an indication of where it can be used, then a 74.194 +description of its effect. 74.195 + 74.196 +\begin{itemize} 74.197 +\item[\tplfilter{addbreaks}] Any text. Add an XHTML ``\Verb+<br/>+'' 74.198 + tag before the end of every line except the last. For example, 74.199 + ``\Verb+foo\nbar+'' becomes ``\Verb+foo<br/>\nbar+''. 74.200 +\item[\tplkwfilt{date}{age}] \tplkword{date} keyword. Render the 74.201 + age of the date, relative to the current time. Yields a string like 74.202 + ``\Verb+10 minutes+''. 74.203 +\item[\tplfilter{basename}] Any text, but most useful for the 74.204 + \tplkword{files} keyword and its relatives. Treat the text as a 74.205 + path, and return the basename. For example, ``\Verb+foo/bar/baz+'' 74.206 + becomes ``\Verb+baz+''. 74.207 +\item[\tplkwfilt{date}{date}] \tplkword{date} keyword. Render a date 74.208 + in a similar format to the Unix \tplkword{date} command, but with 74.209 + timezone included. Yields a string like 74.210 + ``\Verb+Mon Sep 04 15:13:13 2006 -0700+''. 74.211 +\item[\tplkwfilt{author}{domain}] Any text, but most useful for the 74.212 + \tplkword{author} keyword. Finds the first string that looks like 74.213 + an email address, and extract just the domain component. For 74.214 + example, ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' becomes 74.215 + ``\Verb+serpentine.com+''. 74.216 +\item[\tplkwfilt{author}{email}] Any text, but most useful for the 74.217 + \tplkword{author} keyword. Extract the first string that looks like 74.218 + an email address. For example, 74.219 + ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' becomes 74.220 + ``\Verb+bos@serpentine.com+''. 74.221 +\item[\tplfilter{escape}] Any text. Replace the special XML/XHTML 74.222 + characters ``\Verb+&+'', ``\Verb+<+'' and ``\Verb+>+'' with 74.223 + XML entities. 74.224 +\item[\tplfilter{fill68}] Any text. Wrap the text to fit in 68 74.225 + columns. This is useful before you pass text through the 74.226 + \tplfilter{tabindent} filter, and still want it to fit in an 74.227 + 80-column fixed-font window. 74.228 +\item[\tplfilter{fill76}] Any text. Wrap the text to fit in 76 74.229 + columns. 74.230 +\item[\tplfilter{firstline}] Any text. Yield the first line of text, 74.231 + without any trailing newlines. 74.232 +\item[\tplkwfilt{date}{hgdate}] \tplkword{date} keyword. Render the 74.233 + date as a pair of readable numbers. Yields a string like 74.234 + ``\Verb+1157407993 25200+''. 74.235 +\item[\tplkwfilt{date}{isodate}] \tplkword{date} keyword. Render the 74.236 + date as a text string in ISO~8601 format. Yields a string like 74.237 + ``\Verb+2006-09-04 15:13:13 -0700+''. 74.238 +\item[\tplfilter{obfuscate}] Any text, but most useful for the 74.239 + \tplkword{author} keyword. Yield the input text rendered as a 74.240 + sequence of XML entities. This helps to defeat some particularly 74.241 + stupid screen-scraping email harvesting spambots. 74.242 +\item[\tplkwfilt{author}{person}] Any text, but most useful for the 74.243 + \tplkword{author} keyword. Yield the text before an email address. 74.244 + For example, ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' 74.245 + becomes ``\Verb+Bryan O'Sullivan+''. 74.246 +\item[\tplkwfilt{date}{rfc822date}] \tplkword{date} keyword. Render a 74.247 + date using the same format used in email headers. Yields a string 74.248 + like ``\Verb+Mon, 04 Sep 2006 15:13:13 -0700+''. 74.249 +\item[\tplkwfilt{node}{short}] Changeset hash. Yield the short form 74.250 + of a changeset hash, i.e.~a 12-character hexadecimal string. 74.251 +\item[\tplkwfilt{date}{shortdate}] \tplkword{date} keyword. Render 74.252 + the year, month, and day of the date. Yields a string like 74.253 + ``\Verb+2006-09-04+''. 74.254 +\item[\tplfilter{strip}] Any text. Strip all leading and trailing 74.255 + whitespace from the string. 74.256 +\item[\tplfilter{tabindent}] Any text. Yield the text, with every line 74.257 + except the first starting with a tab character. 74.258 +\item[\tplfilter{urlescape}] Any text. Escape all characters that are 74.259 + considered ``special'' by URL parsers. For example, \Verb+foo bar+ 74.260 + becomes \Verb+foo%20bar+. 74.261 +\item[\tplkwfilt{author}{user}] Any text, but most useful for the 74.262 + \tplkword{author} keyword. Return the ``user'' portion of an email 74.263 + address. For example, 74.264 + ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' becomes 74.265 + ``\Verb+bos+''. 74.266 +\end{itemize} 74.267 + 74.268 +\begin{figure} 74.269 + \interaction{template.simple.manyfilters} 74.270 + \caption{Template filters in action} 74.271 + \label{fig:template:filters} 74.272 +\end{figure} 74.273 + 74.274 +\begin{note} 74.275 + If you try to apply a filter to a piece of data that it cannot 74.276 + process, Mercurial will fail and print a Python exception. For 74.277 + example, trying to run the output of the \tplkword{desc} keyword 74.278 + into the \tplkwfilt{date}{isodate} filter is not a good idea. 74.279 +\end{note} 74.280 + 74.281 +\subsection{Combining filters} 74.282 + 74.283 +It is easy to combine filters to yield output in the form you would 74.284 +like. The following chain of filters tidies up a description, then 74.285 +makes sure that it fits cleanly into 68 columns, then indents it by a 74.286 +further 8~characters (at least on Unix-like systems, where a tab is 74.287 +conventionally 8~characters wide). 74.288 + 74.289 +\interaction{template.simple.combine} 74.290 + 74.291 +Note the use of ``\Verb+\t+'' (a tab character) in the template to 74.292 +force the first line to be indented; this is necessary since 74.293 +\tplkword{tabindent} indents all lines \emph{except} the first. 74.294 + 74.295 +Keep in mind that the order of filters in a chain is significant. The 74.296 +first filter is applied to the result of the keyword; the second to 74.297 +the result of the first filter; and so on. For example, using 74.298 +\Verb+fill68|tabindent+ gives very different results from 74.299 +\Verb+tabindent|fill68+. 74.300 + 74.301 + 74.302 +\section{From templates to styles} 74.303 + 74.304 +A command line template provides a quick and simple way to format some 74.305 +output. Templates can become verbose, though, and it's useful to be 74.306 +able to give a template a name. A style file is a template with a 74.307 +name, stored in a file. 74.308 + 74.309 +More than that, using a style file unlocks the power of Mercurial's 74.310 +templating engine in ways that are not possible using the command line 74.311 +\hgopt{log}{--template} option. 74.312 + 74.313 +\subsection{The simplest of style files} 74.314 + 74.315 +Our simple style file contains just one line: 74.316 + 74.317 +\interaction{template.simple.rev} 74.318 + 74.319 +This tells Mercurial, ``if you're printing a changeset, use the text 74.320 +on the right as the template''. 74.321 + 74.322 +\subsection{Style file syntax} 74.323 + 74.324 +The syntax rules for a style file are simple. 74.325 + 74.326 +\begin{itemize} 74.327 +\item The file is processed one line at a time. 74.328 + 74.329 +\item Leading and trailing white space are ignored. 74.330 + 74.331 +\item Empty lines are skipped. 74.332 + 74.333 +\item If a line starts with either of the characters ``\texttt{\#}'' or 74.334 + ``\texttt{;}'', the entire line is treated as a comment, and skipped 74.335 + as if empty. 74.336 + 74.337 +\item A line starts with a keyword. This must start with an 74.338 + alphabetic character or underscore, and can subsequently contain any 74.339 + alphanumeric character or underscore. (In regexp notation, a 74.340 + keyword must match \Verb+[A-Za-z_][A-Za-z0-9_]*+.) 74.341 + 74.342 +\item The next element must be an ``\texttt{=}'' character, which can 74.343 + be preceded or followed by an arbitrary amount of white space. 74.344 + 74.345 +\item If the rest of the line starts and ends with matching quote 74.346 + characters (either single or double quote), it is treated as a 74.347 + template body. 74.348 + 74.349 +\item If the rest of the line \emph{does not} start with a quote 74.350 + character, it is treated as the name of a file; the contents of this 74.351 + file will be read and used as a template body. 74.352 +\end{itemize} 74.353 + 74.354 +\section{Style files by example} 74.355 + 74.356 +To illustrate how to write a style file, we will construct a few by 74.357 +example. Rather than provide a complete style file and walk through 74.358 +it, we'll mirror the usual process of developing a style file by 74.359 +starting with something very simple, and walking through a series of 74.360 +successively more complete examples. 74.361 + 74.362 +\subsection{Identifying mistakes in style files} 74.363 + 74.364 +If Mercurial encounters a problem in a style file you are working on, 74.365 +it prints a terse error message that, once you figure out what it 74.366 +means, is actually quite useful. 74.367 + 74.368 +\interaction{template.svnstyle.syntax.input} 74.369 + 74.370 +Notice that \filename{broken.style} attempts to define a 74.371 +\texttt{changeset} keyword, but forgets to give any content for it. 74.372 +When instructed to use this style file, Mercurial promptly complains. 74.373 + 74.374 +\interaction{template.svnstyle.syntax.error} 74.375 + 74.376 +This error message looks intimidating, but it is not too hard to 74.377 +follow. 74.378 + 74.379 +\begin{itemize} 74.380 +\item The first component is simply Mercurial's way of saying ``I am 74.381 + giving up''. 74.382 + \begin{codesample4} 74.383 + \textbf{abort:} broken.style:1: parse error 74.384 + \end{codesample4} 74.385 + 74.386 +\item Next comes the name of the style file that contains the error. 74.387 + \begin{codesample4} 74.388 + abort: \textbf{broken.style}:1: parse error 74.389 + \end{codesample4} 74.390 + 74.391 +\item Following the file name is the line number where the error was 74.392 + encountered. 74.393 + \begin{codesample4} 74.394 + abort: broken.style:\textbf{1}: parse error 74.395 + \end{codesample4} 74.396 + 74.397 +\item Finally, a description of what went wrong. 74.398 + \begin{codesample4} 74.399 + abort: broken.style:1: \textbf{parse error} 74.400 + \end{codesample4} 74.401 + The description of the problem is not always clear (as in this 74.402 + case), but even when it is cryptic, it is almost always trivial to 74.403 + visually inspect the offending line in the style file and see what 74.404 + is wrong. 74.405 +\end{itemize} 74.406 + 74.407 +\subsection{Uniquely identifying a repository} 74.408 + 74.409 +If you would like to be able to identify a Mercurial repository 74.410 +``fairly uniquely'' using a short string as an identifier, you can 74.411 +use the first revision in the repository. 74.412 +\interaction{template.svnstyle.id} 74.413 +This is not guaranteed to be unique, but it is nevertheless useful in 74.414 +many cases. 74.415 +\begin{itemize} 74.416 +\item It will not work in a completely empty repository, because such 74.417 + a repository does not have a revision~zero. 74.418 +\item Neither will it work in the (extremely rare) case where a 74.419 + repository is a merge of two or more formerly independent 74.420 + repositories, and you still have those repositories around. 74.421 +\end{itemize} 74.422 +Here are some uses to which you could put this identifier: 74.423 +\begin{itemize} 74.424 +\item As a key into a table for a database that manages repositories 74.425 + on a server. 74.426 +\item As half of a \{\emph{repository~ID}, \emph{revision~ID}\} tuple. 74.427 + Save this information away when you run an automated build or other 74.428 + activity, so that you can ``replay'' the build later if necessary. 74.429 +\end{itemize} 74.430 + 74.431 +\subsection{Mimicking Subversion's output} 74.432 + 74.433 +Let's try to emulate the default output format used by another 74.434 +revision control tool, Subversion. 74.435 +\interaction{template.svnstyle.short} 74.436 + 74.437 +Since Subversion's output style is fairly simple, it is easy to 74.438 +copy-and-paste a hunk of its output into a file, and replace the text 74.439 +produced above by Subversion with the template values we'd like to see 74.440 +expanded. 74.441 +\interaction{template.svnstyle.template} 74.442 + 74.443 +There are a few small ways in which this template deviates from the 74.444 +output produced by Subversion. 74.445 +\begin{itemize} 74.446 +\item Subversion prints a ``readable'' date (the ``\texttt{Wed, 27 Sep 74.447 + 2006}'' in the example output above) in parentheses. Mercurial's 74.448 + templating engine does not provide a way to display a date in this 74.449 + format without also printing the time and time zone. 74.450 +\item We emulate Subversion's printing of ``separator'' lines full of 74.451 + ``\texttt{-}'' characters by ending the template with such a line. 74.452 + We use the templating engine's \tplkword{header} keyword to print a 74.453 + separator line as the first line of output (see below), thus 74.454 + achieving similar output to Subversion. 74.455 +\item Subversion's output includes a count in the header of the number 74.456 + of lines in the commit message. We cannot replicate this in 74.457 + Mercurial; the templating engine does not currently provide a filter 74.458 + that counts the number of lines the template generates. 74.459 +\end{itemize} 74.460 +It took me no more than a minute or two of work to replace literal 74.461 +text from an example of Subversion's output with some keywords and 74.462 +filters to give the template above. The style file simply refers to 74.463 +the template. 74.464 +\interaction{template.svnstyle.style} 74.465 + 74.466 +We could have included the text of the template file directly in the 74.467 +style file by enclosing it in quotes and replacing the newlines with 74.468 +``\verb!\n!'' sequences, but it would have made the style file too 74.469 +difficult to read. Readability is a good guide when you're trying to 74.470 +decide whether some text belongs in a style file, or in a template 74.471 +file that the style file points to. If the style file will look too 74.472 +big or cluttered if you insert a literal piece of text, drop it into a 74.473 +template instead. 74.474 + 74.475 +%%% Local Variables: 74.476 +%%% mode: latex 74.477 +%%% TeX-master: "00book" 74.478 +%%% End:
75.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 75.2 +++ b/fr/tour-basic.tex Thu Feb 05 12:37:03 2009 +0100 75.3 @@ -0,0 +1,624 @@ 75.4 +\chapter{A tour of Mercurial: the basics} 75.5 +\label{chap:tour-basic} 75.6 + 75.7 +\section{Installing Mercurial on your system} 75.8 +\label{sec:tour:install} 75.9 + 75.10 +Prebuilt binary packages of Mercurial are available for every popular 75.11 +operating system. These make it easy to start using Mercurial on your 75.12 +computer immediately. 75.13 + 75.14 +\subsection{Linux} 75.15 + 75.16 +Because each Linux distribution has its own packaging tools, policies, 75.17 +and rate of development, it's difficult to give a comprehensive set of 75.18 +instructions on how to install Mercurial binaries. The version of 75.19 +Mercurial that you will end up with can vary depending on how active 75.20 +the person is who maintains the package for your distribution. 75.21 + 75.22 +To keep things simple, I will focus on installing Mercurial from the 75.23 +command line under the most popular Linux distributions. Most of 75.24 +these distributions provide graphical package managers that will let 75.25 +you install Mercurial with a single click; the package name to look 75.26 +for is \texttt{mercurial}. 75.27 + 75.28 +\begin{itemize} 75.29 +\item[Debian] 75.30 + \begin{codesample4} 75.31 + apt-get install mercurial 75.32 + \end{codesample4} 75.33 + 75.34 +\item[Fedora Core] 75.35 + \begin{codesample4} 75.36 + yum install mercurial 75.37 + \end{codesample4} 75.38 + 75.39 +\item[Gentoo] 75.40 + \begin{codesample4} 75.41 + emerge mercurial 75.42 + \end{codesample4} 75.43 + 75.44 +\item[OpenSUSE] 75.45 + \begin{codesample4} 75.46 + yum install mercurial 75.47 + \end{codesample4} 75.48 + 75.49 +\item[Ubuntu] Ubuntu's Mercurial package is based on Debian's. To 75.50 + install it, run the following command. 75.51 + \begin{codesample4} 75.52 + apt-get install mercurial 75.53 + \end{codesample4} 75.54 + The Ubuntu package for Mercurial tends to lag behind the Debian 75.55 + version by a considerable time margin (at the time of writing, seven 75.56 + months), which in some cases will mean that on Ubuntu, you may run 75.57 + into problems that have since been fixed in the Debian package. 75.58 +\end{itemize} 75.59 + 75.60 +\subsection{Solaris} 75.61 + 75.62 +SunFreeWare, at \url{http://www.sunfreeware.com}, is a good source for a 75.63 +large number of pre-built Solaris packages for 32 and 64 bit Intel and 75.64 +Sparc architectures, including current versions of Mercurial. 75.65 + 75.66 +\subsection{Mac OS X} 75.67 + 75.68 +Lee Cantey publishes an installer of Mercurial for Mac OS~X at 75.69 +\url{http://mercurial.berkwood.com}. This package works on both 75.70 +Intel-~and Power-based Macs. Before you can use it, you must install 75.71 +a compatible version of Universal MacPython~\cite{web:macpython}. This 75.72 +is easy to do; simply follow the instructions on Lee's site. 75.73 + 75.74 +It's also possible to install Mercurial using Fink or MacPorts, 75.75 +two popular free package managers for Mac OS X. If you have Fink, 75.76 +use \command{sudo apt-get install mercurial-py25}. If MacPorts, 75.77 +\command{sudo port install mercurial}. 75.78 + 75.79 +\subsection{Windows} 75.80 + 75.81 +Lee Cantey publishes an installer of Mercurial for Windows at 75.82 +\url{http://mercurial.berkwood.com}. This package has no external 75.83 +dependencies; it ``just works''. 75.84 + 75.85 +\begin{note} 75.86 + The Windows version of Mercurial does not automatically convert line 75.87 + endings between Windows and Unix styles. If you want to share work 75.88 + with Unix users, you must do a little additional configuration 75.89 + work. XXX Flesh this out. 75.90 +\end{note} 75.91 + 75.92 +\section{Getting started} 75.93 + 75.94 +To begin, we'll use the \hgcmd{version} command to find out whether 75.95 +Mercurial is actually installed properly. The actual version 75.96 +information that it prints isn't so important; it's whether it prints 75.97 +anything at all that we care about. 75.98 +\interaction{tour.version} 75.99 + 75.100 +\subsection{Built-in help} 75.101 + 75.102 +Mercurial provides a built-in help system. This is invaluable for those 75.103 +times when you find yourself stuck trying to remember how to run a 75.104 +command. If you are completely stuck, simply run \hgcmd{help}; it 75.105 +will print a brief list of commands, along with a description of what 75.106 +each does. If you ask for help on a specific command (as below), it 75.107 +prints more detailed information. 75.108 +\interaction{tour.help} 75.109 +For a more impressive level of detail (which you won't usually need) 75.110 +run \hgcmdargs{help}{\hggopt{-v}}. The \hggopt{-v} option is short 75.111 +for \hggopt{--verbose}, and tells Mercurial to print more information 75.112 +than it usually would. 75.113 + 75.114 +\section{Working with a repository} 75.115 + 75.116 +In Mercurial, everything happens inside a \emph{repository}. The 75.117 +repository for a project contains all of the files that ``belong to'' 75.118 +that project, along with a historical record of the project's files. 75.119 + 75.120 +There's nothing particularly magical about a repository; it is simply 75.121 +a directory tree in your filesystem that Mercurial treats as special. 75.122 +You can rename or delete a repository any time you like, using either the 75.123 +command line or your file browser. 75.124 + 75.125 +\subsection{Making a local copy of a repository} 75.126 + 75.127 +\emph{Copying} a repository is just a little bit special. While you 75.128 +could use a normal file copying command to make a copy of a 75.129 +repository, it's best to use a built-in command that Mercurial 75.130 +provides. This command is called \hgcmd{clone}, because it creates an 75.131 +identical copy of an existing repository. 75.132 +\interaction{tour.clone} 75.133 +If our clone succeeded, we should now have a local directory called 75.134 +\dirname{hello}. This directory will contain some files. 75.135 +\interaction{tour.ls} 75.136 +These files have the same contents and history in our repository as 75.137 +they do in the repository we cloned. 75.138 + 75.139 +Every Mercurial repository is complete, self-contained, and 75.140 +independent. It contains its own private copy of a project's files 75.141 +and history. A cloned repository remembers the location of the 75.142 +repository it was cloned from, but it does not communicate with that 75.143 +repository, or any other, unless you tell it to. 75.144 + 75.145 +What this means for now is that we're free to experiment with our 75.146 +repository, safe in the knowledge that it's a private ``sandbox'' that 75.147 +won't affect anyone else. 75.148 + 75.149 +\subsection{What's in a repository?} 75.150 + 75.151 +When we take a more detailed look inside a repository, we can see that 75.152 +it contains a directory named \dirname{.hg}. This is where Mercurial 75.153 +keeps all of its metadata for the repository. 75.154 +\interaction{tour.ls-a} 75.155 + 75.156 +The contents of the \dirname{.hg} directory and its subdirectories are 75.157 +private to Mercurial. Every other file and directory in the 75.158 +repository is yours to do with as you please. 75.159 + 75.160 +To introduce a little terminology, the \dirname{.hg} directory is the 75.161 +``real'' repository, and all of the files and directories that coexist 75.162 +with it are said to live in the \emph{working directory}. An easy way 75.163 +to remember the distinction is that the \emph{repository} contains the 75.164 +\emph{history} of your project, while the \emph{working directory} 75.165 +contains a \emph{snapshot} of your project at a particular point in 75.166 +history. 75.167 + 75.168 +\section{A tour through history} 75.169 + 75.170 +One of the first things we might want to do with a new, unfamiliar 75.171 +repository is understand its history. The \hgcmd{log} command gives 75.172 +us a view of history. 75.173 +\interaction{tour.log} 75.174 +By default, this command prints a brief paragraph of output for each 75.175 +change to the project that was recorded. In Mercurial terminology, we 75.176 +call each of these recorded events a \emph{changeset}, because it can 75.177 +contain a record of changes to several files. 75.178 + 75.179 +The fields in a record of output from \hgcmd{log} are as follows. 75.180 +\begin{itemize} 75.181 +\item[\texttt{changeset}] This field has the format of a number, 75.182 + followed by a colon, followed by a hexadecimal string. These are 75.183 + \emph{identifiers} for the changeset. There are two identifiers 75.184 + because the number is shorter and easier to type than the hex 75.185 + string. 75.186 +\item[\texttt{user}] The identity of the person who created the 75.187 + changeset. This is a free-form field, but it most often contains a 75.188 + person's name and email address. 75.189 +\item[\texttt{date}] The date and time on which the changeset was 75.190 + created, and the timezone in which it was created. (The date and 75.191 + time are local to that timezone; they display what time and date it 75.192 + was for the person who created the changeset.) 75.193 +\item[\texttt{summary}] The first line of the text message that the 75.194 + creator of the changeset entered to describe the changeset. 75.195 +\end{itemize} 75.196 +The default output printed by \hgcmd{log} is purely a summary; it is 75.197 +missing a lot of detail. 75.198 + 75.199 +Figure~\ref{fig:tour-basic:history} provides a graphical representation of 75.200 +the history of the \dirname{hello} repository, to make it a little 75.201 +easier to see which direction history is ``flowing'' in. We'll be 75.202 +returning to this figure several times in this chapter and the chapter 75.203 +that follows. 75.204 + 75.205 +\begin{figure}[ht] 75.206 + \centering 75.207 + \grafix{tour-history} 75.208 + \caption{Graphical history of the \dirname{hello} repository} 75.209 + \label{fig:tour-basic:history} 75.210 +\end{figure} 75.211 + 75.212 +\subsection{Changesets, revisions, and talking to other 75.213 + people} 75.214 + 75.215 +As English is a notoriously sloppy language, and computer science has 75.216 +a hallowed history of terminological confusion (why use one term when 75.217 +four will do?), revision control has a variety of words and phrases 75.218 +that mean the same thing. If you are talking about Mercurial history 75.219 +with other people, you will find that the word ``changeset'' is often 75.220 +compressed to ``change'' or (when written) ``cset'', and sometimes a 75.221 +changeset is referred to as a ``revision'' or a ``rev''. 75.222 + 75.223 +While it doesn't matter what \emph{word} you use to refer to the 75.224 +concept of ``a~changeset'', the \emph{identifier} that you use to 75.225 +refer to ``a~\emph{specific} changeset'' is of great importance. 75.226 +Recall that the \texttt{changeset} field in the output from 75.227 +\hgcmd{log} identifies a changeset using both a number and a 75.228 +hexadecimal string. 75.229 +\begin{itemize} 75.230 +\item The revision number is \emph{only valid in that repository}, 75.231 +\item while the hex string is the \emph{permanent, unchanging 75.232 + identifier} that will always identify that exact changeset in 75.233 + \emph{every} copy of the repository. 75.234 +\end{itemize} 75.235 +This distinction is important. If you send someone an email talking 75.236 +about ``revision~33'', there's a high likelihood that their 75.237 +revision~33 will \emph{not be the same} as yours. The reason for this 75.238 +is that a revision number depends on the order in which changes 75.239 +arrived in a repository, and there is no guarantee that the same 75.240 +changes will happen in the same order in different repositories. 75.241 +Three changes $a,b,c$ can easily appear in one repository as $0,1,2$, 75.242 +while in another as $1,0,2$. 75.243 + 75.244 +Mercurial uses revision numbers purely as a convenient shorthand. If 75.245 +you need to discuss a changeset with someone, or make a record of a 75.246 +changeset for some other reason (for example, in a bug report), use 75.247 +the hexadecimal identifier. 75.248 + 75.249 +\subsection{Viewing specific revisions} 75.250 + 75.251 +To narrow the output of \hgcmd{log} down to a single revision, use the 75.252 +\hgopt{log}{-r} (or \hgopt{log}{--rev}) option. You can use either a 75.253 +revision number or a long-form changeset identifier, and you can 75.254 +provide as many revisions as you want. \interaction{tour.log-r} 75.255 + 75.256 +If you want to see the history of several revisions without having to 75.257 +list each one, you can use \emph{range notation}; this lets you 75.258 +express the idea ``I want all revisions between $a$ and $b$, 75.259 +inclusive''. 75.260 +\interaction{tour.log.range} 75.261 +Mercurial also honours the order in which you specify revisions, so 75.262 +\hgcmdargs{log}{-r 2:4} prints $2,3,4$ while \hgcmdargs{log}{-r 4:2} 75.263 +prints $4,3,2$. 75.264 + 75.265 +\subsection{More detailed information} 75.266 + 75.267 +While the summary information printed by \hgcmd{log} is useful if you 75.268 +already know what you're looking for, you may need to see a complete 75.269 +description of the change, or a list of the files changed, if you're 75.270 +trying to decide whether a changeset is the one you're looking for. 75.271 +The \hgcmd{log} command's \hggopt{-v} (or \hggopt{--verbose}) 75.272 +option gives you this extra detail. 75.273 +\interaction{tour.log-v} 75.274 + 75.275 +If you want to see both the description and content of a change, add 75.276 +the \hgopt{log}{-p} (or \hgopt{log}{--patch}) option. This displays 75.277 +the content of a change as a \emph{unified diff} (if you've never seen 75.278 +a unified diff before, see section~\ref{sec:mq:patch} for an overview). 75.279 +\interaction{tour.log-vp} 75.280 + 75.281 +\section{All about command options} 75.282 + 75.283 +Let's take a brief break from exploring Mercurial commands to discuss 75.284 +a pattern in the way that they work; you may find this useful to keep 75.285 +in mind as we continue our tour. 75.286 + 75.287 +Mercurial has a consistent and straightforward approach to dealing 75.288 +with the options that you can pass to commands. It follows the 75.289 +conventions for options that are common to modern Linux and Unix 75.290 +systems. 75.291 +\begin{itemize} 75.292 +\item Every option has a long name. For example, as we've already 75.293 + seen, the \hgcmd{log} command accepts a \hgopt{log}{--rev} option. 75.294 +\item Most options have short names, too. Instead of 75.295 + \hgopt{log}{--rev}, we can use \hgopt{log}{-r}. (The reason that 75.296 + some options don't have short names is that the options in question 75.297 + are rarely used.) 75.298 +\item Long options start with two dashes (e.g.~\hgopt{log}{--rev}), 75.299 + while short options start with one (e.g.~\hgopt{log}{-r}). 75.300 +\item Option naming and usage is consistent across commands. For 75.301 + example, every command that lets you specify a changeset~ID or 75.302 + revision number accepts both \hgopt{log}{-r} and \hgopt{log}{--rev} 75.303 + arguments. 75.304 +\end{itemize} 75.305 +In the examples throughout this book, I use short options instead of 75.306 +long. This just reflects my own preference, so don't read anything 75.307 +significant into it. 75.308 + 75.309 +Most commands that print output of some kind will print more output 75.310 +when passed a \hggopt{-v} (or \hggopt{--verbose}) option, and less 75.311 +when passed \hggopt{-q} (or \hggopt{--quiet}). 75.312 + 75.313 +\section{Making and reviewing changes} 75.314 + 75.315 +Now that we have a grasp of viewing history in Mercurial, let's take a 75.316 +look at making some changes and examining them. 75.317 + 75.318 +The first thing we'll do is isolate our experiment in a repository of 75.319 +its own. We use the \hgcmd{clone} command, but we don't need to 75.320 +clone a copy of the remote repository. Since we already have a copy 75.321 +of it locally, we can just clone that instead. This is much faster 75.322 +than cloning over the network, and cloning a local repository uses 75.323 +less disk space in most cases, too. 75.324 +\interaction{tour.reclone} 75.325 +As an aside, it's often good practice to keep a ``pristine'' copy of a 75.326 +remote repository around, which you can then make temporary clones of 75.327 +to create sandboxes for each task you want to work on. This lets you 75.328 +work on multiple tasks in parallel, each isolated from the others 75.329 +until it's complete and you're ready to integrate it back. Because 75.330 +local clones are so cheap, there's almost no overhead to cloning and 75.331 +destroying repositories whenever you want. 75.332 + 75.333 +In our \dirname{my-hello} repository, we have a file 75.334 +\filename{hello.c} that contains the classic ``hello, world'' program. 75.335 +Let's use the ancient and venerable \command{sed} command to edit this 75.336 +file so that it prints a second line of output. (I'm only using 75.337 +\command{sed} to do this because it's easy to write a scripted example 75.338 +this way. Since you're not under the same constraint, you probably 75.339 +won't want to use \command{sed}; simply use your preferred text editor to 75.340 +do the same thing.) 75.341 +\interaction{tour.sed} 75.342 + 75.343 +Mercurial's \hgcmd{status} command will tell us what Mercurial knows 75.344 +about the files in the repository. 75.345 +\interaction{tour.status} 75.346 +The \hgcmd{status} command prints no output for some files, but a line 75.347 +starting with ``\texttt{M}'' for \filename{hello.c}. Unless you tell 75.348 +it to, \hgcmd{status} will not print any output for files that have 75.349 +not been modified. 75.350 + 75.351 +The ``\texttt{M}'' indicates that Mercurial has noticed that we 75.352 +modified \filename{hello.c}. We didn't need to \emph{inform} 75.353 +Mercurial that we were going to modify the file before we started, or 75.354 +that we had modified the file after we were done; it was able to 75.355 +figure this out itself. 75.356 + 75.357 +It's a little bit helpful to know that we've modified 75.358 +\filename{hello.c}, but we might prefer to know exactly \emph{what} 75.359 +changes we've made to it. To do this, we use the \hgcmd{diff} 75.360 +command. 75.361 +\interaction{tour.diff} 75.362 + 75.363 +\section{Recording changes in a new changeset} 75.364 + 75.365 +We can modify files, build and test our changes, and use 75.366 +\hgcmd{status} and \hgcmd{diff} to review our changes, until we're 75.367 +satisfied with what we've done and arrive at a natural stopping point 75.368 +where we want to record our work in a new changeset. 75.369 + 75.370 +The \hgcmd{commit} command lets us create a new changeset; we'll 75.371 +usually refer to this as ``making a commit'' or ``committing''. 75.372 + 75.373 +\subsection{Setting up a username} 75.374 + 75.375 +When you try to run \hgcmd{commit} for the first time, it is not 75.376 +guaranteed to succeed. Mercurial records your name and address with 75.377 +each change that you commit, so that you and others will later be able 75.378 +to tell who made each change. Mercurial tries to automatically figure 75.379 +out a sensible username to commit the change with. It will attempt 75.380 +each of the following methods, in order: 75.381 +\begin{enumerate} 75.382 +\item If you specify a \hgopt{commit}{-u} option to the \hgcmd{commit} 75.383 + command on the command line, followed by a username, this is always 75.384 + given the highest precedence. 75.385 +\item If you have set the \envar{HGUSER} environment variable, this is 75.386 + checked next. 75.387 +\item If you create a file in your home directory called 75.388 + \sfilename{.hgrc}, with a \rcitem{ui}{username} entry, that will be 75.389 + used next. To see what the contents of this file should look like, 75.390 + refer to section~\ref{sec:tour-basic:username} below. 75.391 +\item If you have set the \envar{EMAIL} environment variable, this 75.392 + will be used next. 75.393 +\item Mercurial will query your system to find out your local user 75.394 + name and host name, and construct a username from these components. 75.395 + Since this often results in a username that is not very useful, it 75.396 + will print a warning if it has to do this. 75.397 +\end{enumerate} 75.398 +If all of these mechanisms fail, Mercurial will fail, printing an 75.399 +error message. In this case, it will not let you commit until you set 75.400 +up a username. 75.401 + 75.402 +You should think of the \envar{HGUSER} environment variable and the 75.403 +\hgopt{commit}{-u} option to the \hgcmd{commit} command as ways to 75.404 +\emph{override} Mercurial's default selection of username. For normal 75.405 +use, the simplest and most robust way to set a username for yourself 75.406 +is by creating a \sfilename{.hgrc} file; see below for details. 75.407 + 75.408 +\subsubsection{Creating a Mercurial configuration file} 75.409 +\label{sec:tour-basic:username} 75.410 + 75.411 +To set a user name, use your favourite editor to create a file called 75.412 +\sfilename{.hgrc} in your home directory. Mercurial will use this 75.413 +file to look up your personalised configuration settings. The initial 75.414 +contents of your \sfilename{.hgrc} should look like this. 75.415 +\begin{codesample2} 75.416 + # This is a Mercurial configuration file. 75.417 + [ui] 75.418 + username = Firstname Lastname <email.address@domain.net> 75.419 +\end{codesample2} 75.420 +The ``\texttt{[ui]}'' line begins a \emph{section} of the config file, 75.421 +so you can read the ``\texttt{username = ...}'' line as meaning ``set 75.422 +the value of the \texttt{username} item in the \texttt{ui} section''. 75.423 +A section continues until a new section begins, or the end of the 75.424 +file. Mercurial ignores empty lines and treats any text from 75.425 +``\texttt{\#}'' to the end of a line as a comment. 75.426 + 75.427 +\subsubsection{Choosing a user name} 75.428 + 75.429 +You can use any text you like as the value of the \texttt{username} 75.430 +config item, since this information is for reading by other people, 75.431 +but for interpreting by Mercurial. The convention that most people 75.432 +follow is to use their name and email address, as in the example 75.433 +above. 75.434 + 75.435 +\begin{note} 75.436 + Mercurial's built-in web server obfuscates email addresses, to make 75.437 + it more difficult for the email harvesting tools that spammers use. 75.438 + This reduces the likelihood that you'll start receiving more junk 75.439 + email if you publish a Mercurial repository on the web. 75.440 +\end{note} 75.441 + 75.442 +\subsection{Writing a commit message} 75.443 + 75.444 +When we commit a change, Mercurial drops us into a text editor, to 75.445 +enter a message that will describe the modifications we've made in 75.446 +this changeset. This is called the \emph{commit message}. It will be 75.447 +a record for readers of what we did and why, and it will be printed by 75.448 +\hgcmd{log} after we've finished committing. 75.449 +\interaction{tour.commit} 75.450 + 75.451 +The editor that the \hgcmd{commit} command drops us into will contain 75.452 +an empty line, followed by a number of lines starting with 75.453 +``\texttt{HG:}''. 75.454 +\begin{codesample2} 75.455 + \emph{empty line} 75.456 + HG: changed hello.c 75.457 +\end{codesample2} 75.458 +Mercurial ignores the lines that start with ``\texttt{HG:}''; it uses 75.459 +them only to tell us which files it's recording changes to. Modifying 75.460 +or deleting these lines has no effect. 75.461 + 75.462 +\subsection{Writing a good commit message} 75.463 + 75.464 +Since \hgcmd{log} only prints the first line of a commit message by 75.465 +default, it's best to write a commit message whose first line stands 75.466 +alone. Here's a real example of a commit message that \emph{doesn't} 75.467 +follow this guideline, and hence has a summary that is not readable. 75.468 +\begin{codesample2} 75.469 + changeset: 73:584af0e231be 75.470 + user: Censored Person <censored.person@example.org> 75.471 + date: Tue Sep 26 21:37:07 2006 -0700 75.472 + summary: include buildmeister/commondefs. Add an exports and install 75.473 +\end{codesample2} 75.474 + 75.475 +As far as the remainder of the contents of the commit message are 75.476 +concerned, there are no hard-and-fast rules. Mercurial itself doesn't 75.477 +interpret or care about the contents of the commit message, though 75.478 +your project may have policies that dictate a certain kind of 75.479 +formatting. 75.480 + 75.481 +My personal preference is for short, but informative, commit messages 75.482 +that tell me something that I can't figure out with a quick glance at 75.483 +the output of \hgcmdargs{log}{--patch}. 75.484 + 75.485 +\subsection{Aborting a commit} 75.486 + 75.487 +If you decide that you don't want to commit while in the middle of 75.488 +editing a commit message, simply exit from your editor without saving 75.489 +the file that it's editing. This will cause nothing to happen to 75.490 +either the repository or the working directory. 75.491 + 75.492 +If we run the \hgcmd{commit} command without any arguments, it records 75.493 +all of the changes we've made, as reported by \hgcmd{status} and 75.494 +\hgcmd{diff}. 75.495 + 75.496 +\subsection{Admiring our new handiwork} 75.497 + 75.498 +Once we've finished the commit, we can use the \hgcmd{tip} command to 75.499 +display the changeset we just created. This command produces output 75.500 +that is identical to \hgcmd{log}, but it only displays the newest 75.501 +revision in the repository. 75.502 +\interaction{tour.tip} 75.503 +We refer to the newest revision in the repository as the tip revision, 75.504 +or simply the tip. 75.505 + 75.506 +\section{Sharing changes} 75.507 + 75.508 +We mentioned earlier that repositories in Mercurial are 75.509 +self-contained. This means that the changeset we just created exists 75.510 +only in our \dirname{my-hello} repository. Let's look at a few ways 75.511 +that we can propagate this change into other repositories. 75.512 + 75.513 +\subsection{Pulling changes from another repository} 75.514 +\label{sec:tour:pull} 75.515 + 75.516 +To get started, let's clone our original \dirname{hello} repository, 75.517 +which does not contain the change we just committed. We'll call our 75.518 +temporary repository \dirname{hello-pull}. 75.519 +\interaction{tour.clone-pull} 75.520 + 75.521 +We'll use the \hgcmd{pull} command to bring changes from 75.522 +\dirname{my-hello} into \dirname{hello-pull}. However, blindly 75.523 +pulling unknown changes into a repository is a somewhat scary 75.524 +prospect. Mercurial provides the \hgcmd{incoming} command to tell us 75.525 +what changes the \hgcmd{pull} command \emph{would} pull into the 75.526 +repository, without actually pulling the changes in. 75.527 +\interaction{tour.incoming} 75.528 +(Of course, someone could cause more changesets to appear in the 75.529 +repository that we ran \hgcmd{incoming} in, before we get a chance to 75.530 +\hgcmd{pull} the changes, so that we could end up pulling changes that we 75.531 +didn't expect.) 75.532 + 75.533 +Bringing changes into a repository is a simple matter of running the 75.534 +\hgcmd{pull} command, and telling it which repository to pull from. 75.535 +\interaction{tour.pull} 75.536 +As you can see from the before-and-after output of \hgcmd{tip}, we 75.537 +have successfully pulled changes into our repository. There remains 75.538 +one step before we can see these changes in the working directory. 75.539 + 75.540 +\subsection{Updating the working directory} 75.541 + 75.542 +We have so far glossed over the relationship between a repository and 75.543 +its working directory. The \hgcmd{pull} command that we ran in 75.544 +section~\ref{sec:tour:pull} brought changes into the repository, but 75.545 +if we check, there's no sign of those changes in the working 75.546 +directory. This is because \hgcmd{pull} does not (by default) touch 75.547 +the working directory. Instead, we use the \hgcmd{update} command to 75.548 +do this. 75.549 +\interaction{tour.update} 75.550 + 75.551 +It might seem a bit strange that \hgcmd{pull} doesn't update the 75.552 +working directory automatically. There's actually a good reason for 75.553 +this: you can use \hgcmd{update} to update the working directory to 75.554 +the state it was in at \emph{any revision} in the history of the 75.555 +repository. If you had the working directory updated to an old 75.556 +revision---to hunt down the origin of a bug, say---and ran a 75.557 +\hgcmd{pull} which automatically updated the working directory to a 75.558 +new revision, you might not be terribly happy. 75.559 + 75.560 +However, since pull-then-update is such a common thing to do, 75.561 +Mercurial lets you combine the two by passing the \hgopt{pull}{-u} 75.562 +option to \hgcmd{pull}. 75.563 +\begin{codesample2} 75.564 + hg pull -u 75.565 +\end{codesample2} 75.566 +If you look back at the output of \hgcmd{pull} in 75.567 +section~\ref{sec:tour:pull} when we ran it without \hgopt{pull}{-u}, 75.568 +you can see that it printed a helpful reminder that we'd have to take 75.569 +an explicit step to update the working directory: 75.570 +\begin{codesample2} 75.571 + (run 'hg update' to get a working copy) 75.572 +\end{codesample2} 75.573 + 75.574 +To find out what revision the working directory is at, use the 75.575 +\hgcmd{parents} command. 75.576 +\interaction{tour.parents} 75.577 +If you look back at figure~\ref{fig:tour-basic:history}, you'll see 75.578 +arrows connecting each changeset. The node that the arrow leads 75.579 +\emph{from} in each case is a parent, and the node that the arrow 75.580 +leads \emph{to} is its child. The working directory has a parent in 75.581 +just the same way; this is the changeset that the working directory 75.582 +currently contains. 75.583 + 75.584 +To update the working directory to a particular revision, give a 75.585 +revision number or changeset~ID to the \hgcmd{update} command. 75.586 +\interaction{tour.older} 75.587 +If you omit an explicit revision, \hgcmd{update} will update to the 75.588 +tip revision, as shown by the second call to \hgcmd{update} in the 75.589 +example above. 75.590 + 75.591 +\subsection{Pushing changes to another repository} 75.592 + 75.593 +Mercurial lets us push changes to another repository, from the 75.594 +repository we're currently visiting. As with the example of 75.595 +\hgcmd{pull} above, we'll create a temporary repository to push our 75.596 +changes into. 75.597 +\interaction{tour.clone-push} 75.598 +The \hgcmd{outgoing} command tells us what changes would be pushed 75.599 +into another repository. 75.600 +\interaction{tour.outgoing} 75.601 +And the \hgcmd{push} command does the actual push. 75.602 +\interaction{tour.push} 75.603 +As with \hgcmd{pull}, the \hgcmd{push} command does not update the 75.604 +working directory in the repository that it's pushing changes into. 75.605 +(Unlike \hgcmd{pull}, \hgcmd{push} does not provide a \texttt{-u} 75.606 +option that updates the other repository's working directory.) 75.607 + 75.608 +What happens if we try to pull or push changes and the receiving 75.609 +repository already has those changes? Nothing too exciting. 75.610 +\interaction{tour.push.nothing} 75.611 + 75.612 +\subsection{Sharing changes over a network} 75.613 + 75.614 +The commands we have covered in the previous few sections are not 75.615 +limited to working with local repositories. Each works in exactly the 75.616 +same fashion over a network connection; simply pass in a URL instead 75.617 +of a local path. 75.618 +\interaction{tour.outgoing.net} 75.619 +In this example, we can see what changes we could push to the remote 75.620 +repository, but the repository is understandably not set up to let 75.621 +anonymous users push to it. 75.622 +\interaction{tour.push.net} 75.623 + 75.624 +%%% Local Variables: 75.625 +%%% mode: latex 75.626 +%%% TeX-master: "00book" 75.627 +%%% End:
76.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 76.2 +++ b/fr/tour-history.svg Thu Feb 05 12:37:03 2009 +0100 76.3 @@ -0,0 +1,289 @@ 76.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 76.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 76.6 +<svg 76.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 76.8 + xmlns:cc="http://web.resource.org/cc/" 76.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 76.10 + xmlns:svg="http://www.w3.org/2000/svg" 76.11 + xmlns="http://www.w3.org/2000/svg" 76.12 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 76.13 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 76.14 + width="744.09448819" 76.15 + height="1052.3622047" 76.16 + id="svg2" 76.17 + sodipodi:version="0.32" 76.18 + inkscape:version="0.44.1" 76.19 + sodipodi:docname="tour-history.svg"> 76.20 + <defs 76.21 + id="defs4"> 76.22 + <marker 76.23 + inkscape:stockid="Arrow1Mstart" 76.24 + orient="auto" 76.25 + refY="0.0" 76.26 + refX="0.0" 76.27 + id="Arrow1Mstart" 76.28 + style="overflow:visible"> 76.29 + <path 76.30 + id="path2973" 76.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 " 76.32 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" 76.33 + transform="scale(0.4) translate(10,0)" /> 76.34 + </marker> 76.35 + <marker 76.36 + inkscape:stockid="Arrow1Mend" 76.37 + orient="auto" 76.38 + refY="0.0" 76.39 + refX="0.0" 76.40 + id="Arrow1Mend" 76.41 + style="overflow:visible;"> 76.42 + <path 76.43 + id="path3066" 76.44 + 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 " 76.45 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 76.46 + transform="scale(0.4) rotate(180) translate(10,0)" /> 76.47 + </marker> 76.48 + </defs> 76.49 + <sodipodi:namedview 76.50 + id="base" 76.51 + pagecolor="#ffffff" 76.52 + bordercolor="#666666" 76.53 + borderopacity="1.0" 76.54 + gridtolerance="10000" 76.55 + guidetolerance="10" 76.56 + objecttolerance="10" 76.57 + inkscape:pageopacity="0.0" 76.58 + inkscape:pageshadow="2" 76.59 + inkscape:zoom="1.4" 76.60 + inkscape:cx="232.14286" 76.61 + inkscape:cy="672.75296" 76.62 + inkscape:document-units="px" 76.63 + inkscape:current-layer="layer1" 76.64 + inkscape:window-width="906" 76.65 + inkscape:window-height="620" 76.66 + inkscape:window-x="5" 76.67 + inkscape:window-y="49" /> 76.68 + <metadata 76.69 + id="metadata7"> 76.70 + <rdf:RDF> 76.71 + <cc:Work 76.72 + rdf:about=""> 76.73 + <dc:format>image/svg+xml</dc:format> 76.74 + <dc:type 76.75 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 76.76 + </cc:Work> 76.77 + </rdf:RDF> 76.78 + </metadata> 76.79 + <g 76.80 + inkscape:label="Layer 1" 76.81 + inkscape:groupmode="layer" 76.82 + id="layer1"> 76.83 + <rect 76.84 + style="opacity:1;fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 76.85 + id="rect1878" 76.86 + width="94.285713" 76.87 + height="20.714285" 76.88 + x="138" 76.89 + y="479.50504" /> 76.90 + <text 76.91 + xml:space="preserve" 76.92 + 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:Courier" 76.93 + x="162.09892" 76.94 + y="493.12619" 76.95 + id="text1872"><tspan 76.96 + sodipodi:role="line" 76.97 + id="tspan1874" 76.98 + x="162.09892" 76.99 + y="493.12619" 76.100 + style="font-family:Courier"><tspan 76.101 + style="font-weight:bold" 76.102 + id="tspan1876">0</tspan>: REV0</tspan></text> 76.103 + <rect 76.104 + style="opacity:1;fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 76.105 + id="rect2800" 76.106 + width="94.285713" 76.107 + height="20.714285" 76.108 + x="138" 76.109 + y="432.63004" /> 76.110 + <text 76.111 + xml:space="preserve" 76.112 + 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:Courier" 76.113 + x="162.09892" 76.114 + y="446.25119" 76.115 + id="text2794"><tspan 76.116 + sodipodi:role="line" 76.117 + id="tspan2796" 76.118 + x="162.09892" 76.119 + y="446.25119" 76.120 + style="font-family:Courier"><tspan 76.121 + id="tspan2868" 76.122 + style="font-weight:bold">1</tspan>: REV1</tspan></text> 76.123 + <rect 76.124 + style="opacity:1;fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 76.125 + id="rect2810" 76.126 + width="94.285713" 76.127 + height="20.714285" 76.128 + x="138" 76.129 + y="385.75504" /> 76.130 + <text 76.131 + xml:space="preserve" 76.132 + 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:Courier" 76.133 + x="162.09892" 76.134 + y="399.37619" 76.135 + id="text2804"><tspan 76.136 + sodipodi:role="line" 76.137 + id="tspan2806" 76.138 + x="162.09892" 76.139 + y="399.37619" 76.140 + style="font-family:Courier"><tspan 76.141 + style="font-weight:bold" 76.142 + id="tspan2866">2</tspan>: REV2</tspan></text> 76.143 + <rect 76.144 + style="opacity:1;fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 76.145 + id="rect2820" 76.146 + width="94.285713" 76.147 + height="20.714285" 76.148 + x="138" 76.149 + y="338.88007" /> 76.150 + <text 76.151 + xml:space="preserve" 76.152 + 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:Courier" 76.153 + x="162.09892" 76.154 + y="352.50122" 76.155 + id="text2814"><tspan 76.156 + sodipodi:role="line" 76.157 + id="tspan2816" 76.158 + x="162.09892" 76.159 + y="352.50122" 76.160 + style="font-family:Courier"><tspan 76.161 + style="font-weight:bold" 76.162 + id="tspan2864">3</tspan>: REV3</tspan></text> 76.163 + <rect 76.164 + style="opacity:1;fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 76.165 + id="rect2830" 76.166 + width="94.285713" 76.167 + height="20.714285" 76.168 + x="138" 76.169 + y="292.00504" /> 76.170 + <text 76.171 + xml:space="preserve" 76.172 + 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:Courier" 76.173 + x="162.09892" 76.174 + y="305.62619" 76.175 + id="text2824"><tspan 76.176 + sodipodi:role="line" 76.177 + id="tspan2826" 76.178 + x="162.09892" 76.179 + y="305.62619" 76.180 + style="font-family:Courier"><tspan 76.181 + style="font-weight:bold" 76.182 + id="tspan2862">4</tspan>: REV4</tspan></text> 76.183 + <text 76.184 + xml:space="preserve" 76.185 + 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:Courier" 76.186 + x="173.57143" 76.187 + y="443.79074" 76.188 + id="text2832"><tspan 76.189 + sodipodi:role="line" 76.190 + id="tspan2834" 76.191 + x="173.57143" 76.192 + y="443.79074" /></text> 76.193 + <path 76.194 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 76.195 + d="M 185.14286,478.50504 L 185.14286,454.34432" 76.196 + id="path2894" 76.197 + inkscape:connector-type="polyline" /> 76.198 + <path 76.199 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 76.200 + d="M 185.14286,431.63004 L 185.14286,407.46932" 76.201 + id="path2896" 76.202 + inkscape:connector-type="polyline" /> 76.203 + <path 76.204 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 76.205 + d="M 185.14286,384.75504 L 185.14286,360.59435" 76.206 + id="path2898" 76.207 + inkscape:connector-type="polyline" /> 76.208 + <path 76.209 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 76.210 + d="M 185.14286,337.88007 L 185.14286,313.71932" 76.211 + id="path2900" 76.212 + inkscape:connector-type="polyline" /> 76.213 + <text 76.214 + xml:space="preserve" 76.215 + 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" 76.216 + x="244.60992" 76.217 + y="305.245" 76.218 + id="text1902"><tspan 76.219 + sodipodi:role="line" 76.220 + id="tspan1904" 76.221 + x="244.60992" 76.222 + y="305.245">(newest)</tspan></text> 76.223 + <text 76.224 + xml:space="preserve" 76.225 + 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" 76.226 + x="244.60992" 76.227 + y="492.745" 76.228 + id="text1906"><tspan 76.229 + sodipodi:role="line" 76.230 + id="tspan1908" 76.231 + x="244.60992" 76.232 + y="492.745">(oldest)</tspan></text> 76.233 + <rect 76.234 + style="opacity:1;fill:#d2e1e4;fill-opacity:1;stroke:#b1cbd0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 76.235 + id="rect1907" 76.236 + width="94.285713" 76.237 + height="20.714285" 76.238 + x="309.28571" 76.239 + y="324.86218" /> 76.240 + <text 76.241 + xml:space="preserve" 76.242 + 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:Courier" 76.243 + x="333.38464" 76.244 + y="338.48334" 76.245 + id="text1909"><tspan 76.246 + sodipodi:role="line" 76.247 + id="tspan1911" 76.248 + x="333.38464" 76.249 + y="338.48334" 76.250 + style="font-family:Courier"><tspan 76.251 + style="font-weight:bold" 76.252 + id="tspan1913">4</tspan>: REV4</tspan></text> 76.253 + <path 76.254 + 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" 76.255 + d="M 332.14286,375.21932 L 335.71429,347.36218" 76.256 + id="path2802" /> 76.257 + <path 76.258 + 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" 76.259 + d="M 372.69968,375.21932 L 369.12825,347.36218" 76.260 + id="path2986" /> 76.261 + <text 76.262 + xml:space="preserve" 76.263 + 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" 76.264 + x="335.14285" 76.265 + y="387.21933" 76.266 + id="text2988"><tspan 76.267 + sodipodi:role="line" 76.268 + x="335.14285" 76.269 + y="387.21933" 76.270 + id="tspan3020" 76.271 + style="text-align:end;text-anchor:end">revision</tspan><tspan 76.272 + sodipodi:role="line" 76.273 + x="335.14285" 76.274 + y="402.21933" 76.275 + id="tspan3014" 76.276 + style="text-align:end;text-anchor:end">number</tspan></text> 76.277 + <text 76.278 + xml:space="preserve" 76.279 + 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" 76.280 + x="368.71429" 76.281 + y="387.21933" 76.282 + id="text2994"><tspan 76.283 + sodipodi:role="line" 76.284 + id="tspan2996" 76.285 + x="368.71429" 76.286 + y="387.21933">changeset</tspan><tspan 76.287 + sodipodi:role="line" 76.288 + x="368.71429" 76.289 + y="402.21933" 76.290 + id="tspan2998">identifier</tspan></text> 76.291 + </g> 76.292 +</svg>
77.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 77.2 +++ b/fr/tour-merge-conflict.svg Thu Feb 05 12:37:03 2009 +0100 77.3 @@ -0,0 +1,210 @@ 77.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 77.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 77.6 +<svg 77.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 77.8 + xmlns:cc="http://web.resource.org/cc/" 77.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 77.10 + xmlns:svg="http://www.w3.org/2000/svg" 77.11 + xmlns="http://www.w3.org/2000/svg" 77.12 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 77.13 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 77.14 + width="744.09448819" 77.15 + height="1052.3622047" 77.16 + id="svg2" 77.17 + sodipodi:version="0.32" 77.18 + inkscape:version="0.44.1" 77.19 + sodipodi:docname="tour-merge-conflict.svg"> 77.20 + <defs 77.21 + id="defs4"> 77.22 + <marker 77.23 + inkscape:stockid="Arrow1Mend" 77.24 + orient="auto" 77.25 + refY="0.0" 77.26 + refX="0.0" 77.27 + id="Arrow1Mend" 77.28 + style="overflow:visible;"> 77.29 + <path 77.30 + id="path3053" 77.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 " 77.32 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 77.33 + transform="scale(0.4) rotate(180) translate(10,0)" /> 77.34 + </marker> 77.35 + </defs> 77.36 + <sodipodi:namedview 77.37 + id="base" 77.38 + pagecolor="#ffffff" 77.39 + bordercolor="#666666" 77.40 + borderopacity="1.0" 77.41 + gridtolerance="10000" 77.42 + guidetolerance="10" 77.43 + objecttolerance="10" 77.44 + inkscape:pageopacity="0.0" 77.45 + inkscape:pageshadow="2" 77.46 + inkscape:zoom="1.4" 77.47 + inkscape:cx="164.78349" 77.48 + inkscape:cy="590.07679" 77.49 + inkscape:document-units="px" 77.50 + inkscape:current-layer="layer1" 77.51 + inkscape:window-width="906" 77.52 + inkscape:window-height="620" 77.53 + inkscape:window-x="5" 77.54 + inkscape:window-y="49" /> 77.55 + <metadata 77.56 + id="metadata7"> 77.57 + <rdf:RDF> 77.58 + <cc:Work 77.59 + rdf:about=""> 77.60 + <dc:format>image/svg+xml</dc:format> 77.61 + <dc:type 77.62 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 77.63 + </cc:Work> 77.64 + </rdf:RDF> 77.65 + </metadata> 77.66 + <g 77.67 + inkscape:label="Layer 1" 77.68 + inkscape:groupmode="layer" 77.69 + id="layer1"> 77.70 + <g 77.71 + id="g1988" 77.72 + transform="translate(84.85711,0)"> 77.73 + <g 77.74 + id="g1876"> 77.75 + <path 77.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" 77.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 " 77.78 + id="path1872" 77.79 + sodipodi:nodetypes="cccccc" /> 77.80 + <path 77.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" 77.82 + d="M 191.55484,563.36862 L 191.6923,560.98794 L 192.69126,552.44884 L 203.80416,551.31242" 77.83 + id="path1874" 77.84 + sodipodi:nodetypes="cccc" /> 77.85 + </g> 77.86 + <flowRoot 77.87 + style="font-size:8px;font-family:Times New Roman" 77.88 + id="flowRoot1898" 77.89 + xml:space="preserve"><flowRegion 77.90 + id="flowRegion1900"><rect 77.91 + style="font-size:8px;font-family:Times New Roman" 77.92 + y="464.50504" 77.93 + x="122.85714" 77.94 + height="93.571426" 77.95 + width="76.428574" 77.96 + id="rect1902" /></flowRegion><flowPara 77.97 + id="flowPara1904">Greetings!</flowPara><flowPara 77.98 + id="flowPara1906" /><flowPara 77.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> 77.100 + <g 77.101 + id="g1966" 77.102 + transform="translate(82,0.35715)"> 77.103 + <g 77.104 + transform="translate(-77.85718,-140.0714)" 77.105 + id="g1910"> 77.106 + <path 77.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" 77.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 " 77.109 + id="path1912" 77.110 + sodipodi:nodetypes="cccccc" /> 77.111 + <path 77.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" 77.113 + d="M 191.55484,563.36862 L 191.6923,560.98794 L 192.69126,552.44884 L 203.80416,551.31242" 77.114 + id="path1914" 77.115 + sodipodi:nodetypes="cccc" /> 77.116 + </g> 77.117 + <flowRoot 77.118 + transform="translate(-77.85718,-140.0714)" 77.119 + style="font-size:8px;font-family:Times New Roman" 77.120 + id="flowRoot1916" 77.121 + xml:space="preserve"><flowRegion 77.122 + id="flowRegion1918"><rect 77.123 + style="font-size:8px;font-family:Times New Roman" 77.124 + y="464.50504" 77.125 + x="122.85714" 77.126 + height="93.571426" 77.127 + width="76.428574" 77.128 + id="rect1920" /></flowRegion><flowPara 77.129 + id="flowPara1922">Greetings!</flowPara><flowPara 77.130 + id="flowPara1924" /><flowPara 77.131 + id="flowPara1926">I am <flowSpan 77.132 + style="font-style:italic;fill:red" 77.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> 77.134 + <g 77.135 + id="g1977" 77.136 + transform="translate(81.99999,-0.35715)"> 77.137 + <g 77.138 + transform="translate(83.57141,-139.3571)" 77.139 + id="g1932"> 77.140 + <path 77.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" 77.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 " 77.143 + id="path1934" 77.144 + sodipodi:nodetypes="cccccc" /> 77.145 + <path 77.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" 77.147 + d="M 191.55484,563.36862 L 191.6923,560.98794 L 192.69126,552.44884 L 203.80416,551.31242" 77.148 + id="path1936" 77.149 + sodipodi:nodetypes="cccc" /> 77.150 + </g> 77.151 + <flowRoot 77.152 + transform="translate(83.57141,-139.3571)" 77.153 + style="font-size:8px;font-family:Times New Roman" 77.154 + id="flowRoot1938" 77.155 + xml:space="preserve"><flowRegion 77.156 + id="flowRegion1940"><rect 77.157 + style="font-size:8px;font-family:Times New Roman" 77.158 + y="464.50504" 77.159 + x="122.85714" 77.160 + height="93.571426" 77.161 + width="76.428574" 77.162 + id="rect1942" /></flowRegion><flowPara 77.163 + id="flowPara1944">Greetings!</flowPara><flowPara 77.164 + id="flowPara1946" /><flowPara 77.165 + id="flowPara1948">I am <flowSpan 77.166 + style="font-style:italic;fill:red" 77.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> 77.168 + <path 77.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" 77.170 + d="M 215.502,457.71933 L 196.35507,424.5765" 77.171 + id="path1999" 77.172 + inkscape:connector-type="polyline" 77.173 + inkscape:connection-start="#g1988" 77.174 + inkscape:connection-end="#g1966" /> 77.175 + <path 77.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" 77.177 + d="M 277.06936,457.71933 L 296.21629,424.5765" 77.178 + id="path2001" 77.179 + inkscape:connector-type="polyline" 77.180 + inkscape:connection-start="#g1988" 77.181 + inkscape:connection-end="#g1977" /> 77.182 + <text 77.183 + xml:space="preserve" 77.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" 77.185 + x="302.42859" 77.186 + y="515.08905" 77.187 + id="text1905"><tspan 77.188 + sodipodi:role="line" 77.189 + id="tspan1907" 77.190 + x="302.42859" 77.191 + y="515.08905">Base version</tspan></text> 77.192 + <text 77.193 + xml:space="preserve" 77.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" 77.195 + x="45.57143" 77.196 + y="374.1619" 77.197 + id="text1917"><tspan 77.198 + sodipodi:role="line" 77.199 + id="tspan1919" 77.200 + x="45.57143" 77.201 + y="374.1619">Our changes</tspan></text> 77.202 + <text 77.203 + xml:space="preserve" 77.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" 77.205 + x="385.71429" 77.206 + y="374.1619" 77.207 + id="text1921"><tspan 77.208 + sodipodi:role="line" 77.209 + id="tspan1923" 77.210 + x="385.71429" 77.211 + y="374.1619">Their changes</tspan></text> 77.212 + </g> 77.213 +</svg>
78.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 78.2 +++ b/fr/tour-merge-merge.svg Thu Feb 05 12:37:03 2009 +0100 78.3 @@ -0,0 +1,380 @@ 78.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 78.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 78.6 +<svg 78.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 78.8 + xmlns:cc="http://web.resource.org/cc/" 78.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 78.10 + xmlns:svg="http://www.w3.org/2000/svg" 78.11 + xmlns="http://www.w3.org/2000/svg" 78.12 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 78.13 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 78.14 + width="744.09448819" 78.15 + height="1052.3622047" 78.16 + id="svg2" 78.17 + sodipodi:version="0.32" 78.18 + inkscape:version="0.44.1" 78.19 + sodipodi:docname="tour-merge-merge.svg"> 78.20 + <defs 78.21 + id="defs4"> 78.22 + <marker 78.23 + inkscape:stockid="Arrow1Mstart" 78.24 + orient="auto" 78.25 + refY="0.0" 78.26 + refX="0.0" 78.27 + id="Arrow1Mstart" 78.28 + style="overflow:visible"> 78.29 + <path 78.30 + id="path2973" 78.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 " 78.32 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" 78.33 + transform="scale(0.4) translate(10,0)" /> 78.34 + </marker> 78.35 + <marker 78.36 + inkscape:stockid="Arrow1Mend" 78.37 + orient="auto" 78.38 + refY="0.0" 78.39 + refX="0.0" 78.40 + id="Arrow1Mend" 78.41 + style="overflow:visible;"> 78.42 + <path 78.43 + id="path3066" 78.44 + 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 " 78.45 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 78.46 + transform="scale(0.4) rotate(180) translate(10,0)" /> 78.47 + </marker> 78.48 + </defs> 78.49 + <sodipodi:namedview 78.50 + id="base" 78.51 + pagecolor="#ffffff" 78.52 + bordercolor="#666666" 78.53 + borderopacity="1.0" 78.54 + gridtolerance="10000" 78.55 + guidetolerance="10" 78.56 + objecttolerance="10" 78.57 + inkscape:pageopacity="0.0" 78.58 + inkscape:pageshadow="2" 78.59 + inkscape:zoom="1.4" 78.60 + inkscape:cx="247.53795" 78.61 + inkscape:cy="871.05738" 78.62 + inkscape:document-units="px" 78.63 + inkscape:current-layer="layer1" 78.64 + inkscape:window-width="906" 78.65 + inkscape:window-height="620" 78.66 + inkscape:window-x="38" 78.67 + inkscape:window-y="95" /> 78.68 + <metadata 78.69 + id="metadata7"> 78.70 + <rdf:RDF> 78.71 + <cc:Work 78.72 + rdf:about=""> 78.73 + <dc:format>image/svg+xml</dc:format> 78.74 + <dc:type 78.75 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 78.76 + </cc:Work> 78.77 + </rdf:RDF> 78.78 + </metadata> 78.79 + <g 78.80 + inkscape:label="Layer 1" 78.81 + inkscape:groupmode="layer" 78.82 + id="layer1"> 78.83 + <rect 78.84 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 78.85 + id="rect2995" 78.86 + width="94.285713" 78.87 + height="20.714285" 78.88 + x="532.85718" 78.89 + y="203.0479" /> 78.90 + <text 78.91 + xml:space="preserve" 78.92 + 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:Courier" 78.93 + x="173.57143" 78.94 + y="443.79074" 78.95 + id="text2832"><tspan 78.96 + sodipodi:role="line" 78.97 + id="tspan2834" 78.98 + x="173.57143" 78.99 + y="443.79074" /></text> 78.100 + <rect 78.101 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 78.102 + id="rect2830" 78.103 + width="94.285713" 78.104 + height="20.714285" 78.105 + x="138" 78.106 + y="297.76227" /> 78.107 + <text 78.108 + xml:space="preserve" 78.109 + 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:Courier" 78.110 + x="162.09892" 78.111 + y="311.38342" 78.112 + id="text2824"><tspan 78.113 + sodipodi:role="line" 78.114 + id="tspan2826" 78.115 + x="162.09892" 78.116 + y="311.38342" 78.117 + style="font-family:Courier"><tspan 78.118 + style="font-weight:bold" 78.119 + id="tspan2862">4</tspan>: REV4</tspan></text> 78.120 + <path 78.121 + 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" 78.122 + d="M 185.14286,343.63731 L 185.14286,319.47656" 78.123 + id="path2900" 78.124 + inkscape:connector-type="polyline" /> 78.125 + <rect 78.126 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 78.127 + id="rect2863" 78.128 + width="94.285713" 78.129 + height="20.714285" 78.130 + x="91.428574" 78.131 + y="250.47656" /> 78.132 + <text 78.133 + xml:space="preserve" 78.134 + style="font-size:12.00001812px;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:Courier" 78.135 + x="116.09886" 78.136 + y="264.56592" 78.137 + id="text1965" 78.138 + transform="scale(1.000002,0.999998)"><tspan 78.139 + sodipodi:role="line" 78.140 + id="tspan1967" 78.141 + x="116.09886" 78.142 + y="264.56592" 78.143 + style="font-family:Courier"><tspan 78.144 + style="font-weight:bold" 78.145 + id="tspan1973">5</tspan>: REV_my_new_hello</tspan></text> 78.146 + <path 78.147 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1.00000143px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;display:inline" 78.148 + d="M 173.95727,296.76228 L 149.75702,272.19085" 78.149 + id="path1971" 78.150 + inkscape:connector-type="polyline" 78.151 + inkscape:connection-end="#rect2863" 78.152 + inkscape:connection-start="#rect2830" /> 78.153 + <rect 78.154 + style="fill:#78a5ad;fill-opacity:1;stroke:#507b84;stroke-width:2.00000286;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 78.155 + id="rect2911" 78.156 + width="94.285995" 78.157 + height="20.714283" 78.158 + x="186.71414" 78.159 + y="204.40514" /> 78.160 + <text 78.161 + xml:space="preserve" 78.162 + style="font-size:12.00001812px;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:Courier" 78.163 + x="210.81311" 78.164 + y="218.02673" 78.165 + id="text2913" 78.166 + transform="scale(1.000002,0.999998)"><tspan 78.167 + sodipodi:role="line" 78.168 + id="tspan2915" 78.169 + x="210.81311" 78.170 + y="218.02673" 78.171 + style="font-family:Courier"><tspan 78.172 + id="tspan1966" 78.173 + style="font-weight:bold">6</tspan>: REV6_my_new_hello</tspan></text> 78.174 + <path 78.175 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1.00000143px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;display:inline" 78.176 + d="M 191.06908,296.76228 L 227.93092,226.11942" 78.177 + id="path2919" 78.178 + inkscape:connector-type="polyline" 78.179 + inkscape:connection-start="#rect2830" /> 78.180 + <text 78.181 + xml:space="preserve" 78.182 + 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" 78.183 + x="295.28571" 78.184 + y="217.56711" 78.185 + id="text2871"><tspan 78.186 + sodipodi:role="line" 78.187 + id="tspan2873" 78.188 + x="295.28571" 78.189 + y="217.56711">tip (and head)</tspan></text> 78.190 + <text 78.191 + xml:space="preserve" 78.192 + 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" 78.193 + x="76" 78.194 + y="264.91769" 78.195 + id="text2875"><tspan 78.196 + sodipodi:role="line" 78.197 + id="tspan2877" 78.198 + x="76" 78.199 + y="264.91769" 78.200 + style="text-align:end;text-anchor:end">head</tspan></text> 78.201 + <rect 78.202 + style="fill:#c8aaa5;fill-opacity:1;stroke:#a07163;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:2, 4;stroke-dashoffset:0;stroke-opacity:1" 78.203 + id="rect1913" 78.204 + width="94.285713" 78.205 + height="20.714285" 78.206 + x="138" 78.207 + y="156.90514" /> 78.208 + <path 78.209 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:2, 2;stroke-dashoffset:0;stroke-opacity:1" 78.210 + d="M 144.22399,249.47657 L 179.49029,178.61943" 78.211 + id="path1915" 78.212 + inkscape:connector-type="polyline" 78.213 + inkscape:connection-start="#rect2863" 78.214 + inkscape:connection-end="#rect1913" /> 78.215 + <path 78.216 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:2, 2;stroke-dashoffset:0;stroke-opacity:1" 78.217 + d="M 222.20966,203.40514 L 196.79033,178.61943" 78.218 + id="path1917" 78.219 + inkscape:connector-type="polyline" 78.220 + inkscape:connection-start="#rect2911" 78.221 + inkscape:connection-end="#rect1913" /> 78.222 + <text 78.223 + xml:space="preserve" 78.224 + 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" 78.225 + x="166.16823" 78.226 + y="168.52228" 78.227 + id="text2806"><tspan 78.228 + sodipodi:role="line" 78.229 + id="tspan2808" 78.230 + x="166.16823" 78.231 + y="168.52228" 78.232 + style="font-family:Courier">merge</tspan></text> 78.233 + <text 78.234 + xml:space="preserve" 78.235 + 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" 78.236 + x="246" 78.237 + y="162.63338" 78.238 + id="text2810"><tspan 78.239 + sodipodi:role="line" 78.240 + id="tspan2812" 78.241 + x="246" 78.242 + y="162.63338">working directory</tspan><tspan 78.243 + sodipodi:role="line" 78.244 + x="246" 78.245 + y="177.63338" 78.246 + id="tspan2814">during merge</tspan></text> 78.247 + <rect 78.248 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 78.249 + id="rect2816" 78.250 + width="94.285713" 78.251 + height="20.714285" 78.252 + x="483.14636" 78.253 + y="297.76227" /> 78.254 + <text 78.255 + xml:space="preserve" 78.256 + 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:Courier" 78.257 + x="507.24527" 78.258 + y="311.38342" 78.259 + id="text2818"><tspan 78.260 + sodipodi:role="line" 78.261 + id="tspan2820" 78.262 + x="507.24527" 78.263 + y="311.38342" 78.264 + style="font-family:Courier"><tspan 78.265 + style="font-weight:bold" 78.266 + id="tspan2822">4</tspan>: REV4</tspan></text> 78.267 + <path 78.268 + 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" 78.269 + d="M 530.28921,343.6373 L 530.28921,319.47655" 78.270 + id="path2824" 78.271 + inkscape:connector-type="polyline" /> 78.272 + <rect 78.273 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 78.274 + id="rect2826" 78.275 + width="94.285713" 78.276 + height="20.714285" 78.277 + x="436.57492" 78.278 + y="250.47656" /> 78.279 + <text 78.280 + xml:space="preserve" 78.281 + style="font-size:12.00001812px;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:Courier" 78.282 + x="461.24484" 78.283 + y="264.56613" 78.284 + id="text2828" 78.285 + transform="scale(1.000002,0.999998)"><tspan 78.286 + sodipodi:role="line" 78.287 + id="tspan2830" 78.288 + x="461.24484" 78.289 + y="264.56613" 78.290 + style="font-family:Courier"><tspan 78.291 + style="font-weight:bold" 78.292 + id="tspan2832">5</tspan>: REV_my_new_hello</tspan></text> 78.293 + <path 78.294 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1.00000143px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;display:inline" 78.295 + d="M 519.10362,296.76227 L 494.90337,272.19084" 78.296 + id="path2834" 78.297 + inkscape:connector-type="polyline" /> 78.298 + <rect 78.299 + style="fill:#78a5ad;fill-opacity:1;stroke:#507b84;stroke-width:2.00000286;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 78.300 + id="rect2836" 78.301 + width="94.285995" 78.302 + height="20.714283" 78.303 + x="483.14001" 78.304 + y="156.548" /> 78.305 + <text 78.306 + xml:space="preserve" 78.307 + style="font-size:12.00001812px;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:Courier" 78.308 + x="555.95911" 78.309 + y="218.02698" 78.310 + id="text2838" 78.311 + transform="scale(1.000002,0.999998)"><tspan 78.312 + sodipodi:role="line" 78.313 + id="tspan2840" 78.314 + x="555.95911" 78.315 + y="218.02698" 78.316 + style="font-family:Courier"><tspan 78.317 + id="tspan2842" 78.318 + style="font-weight:bold">6</tspan>: REV6_my_new_hello</tspan></text> 78.319 + <path 78.320 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1.00000143px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;display:inline" 78.321 + d="M 536.21543,296.76227 L 574.03453,224.76218" 78.322 + id="path2844" 78.323 + inkscape:connector-type="polyline" /> 78.324 + <text 78.325 + xml:space="preserve" 78.326 + 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" 78.327 + x="594.43207" 78.328 + y="169.78796" 78.329 + id="text2846"><tspan 78.330 + sodipodi:role="line" 78.331 + id="tspan2848" 78.332 + x="594.43207" 78.333 + y="169.78796">tip</tspan></text> 78.334 + <path 78.335 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" 78.336 + d="M 489.37034,249.47656 L 524.65575,178.26229" 78.337 + id="path2856" 78.338 + inkscape:connector-type="polyline" 78.339 + inkscape:connection-end="#rect2836" /> 78.340 + <path 78.341 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" 78.342 + d="M 567.85714,202.0479 L 542.42591,178.26229" 78.343 + id="path2858" 78.344 + inkscape:connector-type="polyline" 78.345 + inkscape:connection-end="#rect2836" 78.346 + inkscape:connection-start="#rect2995" /> 78.347 + <text 78.348 + xml:space="preserve" 78.349 + 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" 78.350 + x="504.54507" 78.351 + y="170.39714" 78.352 + id="text2860"><tspan 78.353 + sodipodi:role="line" 78.354 + id="tspan2863" 78.355 + x="504.54507" 78.356 + y="170.39714" 78.357 + style="font-family:Courier"><tspan 78.358 + style="font-weight:bold" 78.359 + id="tspan2997">7</tspan>: REV7_my_new_hello</tspan></text> 78.360 + <text 78.361 + xml:space="preserve" 78.362 + 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" 78.363 + x="90.323105" 78.364 + y="120.21933" 78.365 + id="text2929"><tspan 78.366 + sodipodi:role="line" 78.367 + id="tspan2931" 78.368 + x="90.323105" 78.369 + y="120.21933" 78.370 + style="font-weight:bold">Working directory during merge</tspan></text> 78.371 + <text 78.372 + xml:space="preserve" 78.373 + 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" 78.374 + x="435.35226" 78.375 + y="120.21933" 78.376 + id="text2937"><tspan 78.377 + sodipodi:role="line" 78.378 + id="tspan2939" 78.379 + x="435.35226" 78.380 + y="120.21933" 78.381 + style="font-weight:bold">Repository after merge committed</tspan></text> 78.382 + </g> 78.383 +</svg>
79.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 79.2 +++ b/fr/tour-merge-pull.svg Thu Feb 05 12:37:03 2009 +0100 79.3 @@ -0,0 +1,288 @@ 79.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 79.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 79.6 +<svg 79.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 79.8 + xmlns:cc="http://web.resource.org/cc/" 79.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 79.10 + xmlns:svg="http://www.w3.org/2000/svg" 79.11 + xmlns="http://www.w3.org/2000/svg" 79.12 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 79.13 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 79.14 + width="744.09448819" 79.15 + height="1052.3622047" 79.16 + id="svg2" 79.17 + sodipodi:version="0.32" 79.18 + inkscape:version="0.44.1" 79.19 + sodipodi:docname="tour-merge-pull.svg" 79.20 + sodipodi:docbase="/home/bos/hg/hgbook/en"> 79.21 + <defs 79.22 + id="defs4"> 79.23 + <marker 79.24 + inkscape:stockid="Arrow1Mstart" 79.25 + orient="auto" 79.26 + refY="0.0" 79.27 + refX="0.0" 79.28 + id="Arrow1Mstart" 79.29 + style="overflow:visible"> 79.30 + <path 79.31 + id="path2973" 79.32 + 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 " 79.33 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" 79.34 + transform="scale(0.4) translate(10,0)" /> 79.35 + </marker> 79.36 + <marker 79.37 + inkscape:stockid="Arrow1Mend" 79.38 + orient="auto" 79.39 + refY="0.0" 79.40 + refX="0.0" 79.41 + id="Arrow1Mend" 79.42 + style="overflow:visible;"> 79.43 + <path 79.44 + id="path3066" 79.45 + 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 " 79.46 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 79.47 + transform="scale(0.4) rotate(180) translate(10,0)" /> 79.48 + </marker> 79.49 + </defs> 79.50 + <sodipodi:namedview 79.51 + id="base" 79.52 + pagecolor="#ffffff" 79.53 + bordercolor="#666666" 79.54 + borderopacity="1.0" 79.55 + gridtolerance="10000" 79.56 + guidetolerance="10" 79.57 + objecttolerance="10" 79.58 + inkscape:pageopacity="0.0" 79.59 + inkscape:pageshadow="2" 79.60 + inkscape:zoom="1.4" 79.61 + inkscape:cx="233.63208" 79.62 + inkscape:cy="832.54381" 79.63 + inkscape:document-units="px" 79.64 + inkscape:current-layer="layer1" 79.65 + inkscape:window-width="906" 79.66 + inkscape:window-height="620" 79.67 + inkscape:window-x="237" 79.68 + inkscape:window-y="103" /> 79.69 + <metadata 79.70 + id="metadata7"> 79.71 + <rdf:RDF> 79.72 + <cc:Work 79.73 + rdf:about=""> 79.74 + <dc:format>image/svg+xml</dc:format> 79.75 + <dc:type 79.76 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 79.77 + </cc:Work> 79.78 + </rdf:RDF> 79.79 + </metadata> 79.80 + <g 79.81 + inkscape:label="Layer 1" 79.82 + inkscape:groupmode="layer" 79.83 + id="layer1"> 79.84 + <text 79.85 + xml:space="preserve" 79.86 + 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:Courier" 79.87 + x="173.57143" 79.88 + y="443.79074" 79.89 + id="text2832"><tspan 79.90 + sodipodi:role="line" 79.91 + id="tspan2834" 79.92 + x="173.57143" 79.93 + y="443.79074" /></text> 79.94 + <rect 79.95 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 79.96 + id="rect1878" 79.97 + width="94.285713" 79.98 + height="20.714285" 79.99 + x="138" 79.100 + y="479.50504" /> 79.101 + <text 79.102 + xml:space="preserve" 79.103 + 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:Courier" 79.104 + x="162.09892" 79.105 + y="493.12619" 79.106 + id="text1872"><tspan 79.107 + sodipodi:role="line" 79.108 + id="tspan1874" 79.109 + x="162.09892" 79.110 + y="493.12619" 79.111 + style="font-family:Courier"><tspan 79.112 + style="font-weight:bold" 79.113 + id="tspan1876">0</tspan>: REV0</tspan></text> 79.114 + <rect 79.115 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 79.116 + id="rect2800" 79.117 + width="94.285713" 79.118 + height="20.714285" 79.119 + x="138" 79.120 + y="432.63004" /> 79.121 + <text 79.122 + xml:space="preserve" 79.123 + 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:Courier" 79.124 + x="162.09892" 79.125 + y="446.25119" 79.126 + id="text2794"><tspan 79.127 + sodipodi:role="line" 79.128 + id="tspan2796" 79.129 + x="162.09892" 79.130 + y="446.25119" 79.131 + style="font-family:Courier"><tspan 79.132 + id="tspan2868" 79.133 + style="font-weight:bold">1</tspan>: REV1</tspan></text> 79.134 + <rect 79.135 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 79.136 + id="rect2810" 79.137 + width="94.285713" 79.138 + height="20.714285" 79.139 + x="138" 79.140 + y="385.75504" /> 79.141 + <text 79.142 + xml:space="preserve" 79.143 + 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:Courier" 79.144 + x="162.09892" 79.145 + y="399.37619" 79.146 + id="text2804"><tspan 79.147 + sodipodi:role="line" 79.148 + id="tspan2806" 79.149 + x="162.09892" 79.150 + y="399.37619" 79.151 + style="font-family:Courier"><tspan 79.152 + style="font-weight:bold" 79.153 + id="tspan2866">2</tspan>: REV2</tspan></text> 79.154 + <rect 79.155 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 79.156 + id="rect2820" 79.157 + width="94.285713" 79.158 + height="20.714285" 79.159 + x="138" 79.160 + y="338.88007" /> 79.161 + <text 79.162 + xml:space="preserve" 79.163 + 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:Courier" 79.164 + x="162.09892" 79.165 + y="352.50122" 79.166 + id="text2814"><tspan 79.167 + sodipodi:role="line" 79.168 + id="tspan2816" 79.169 + x="162.09892" 79.170 + y="352.50122" 79.171 + style="font-family:Courier"><tspan 79.172 + style="font-weight:bold" 79.173 + id="tspan2864">3</tspan>: REV3</tspan></text> 79.174 + <rect 79.175 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 79.176 + id="rect2830" 79.177 + width="94.285713" 79.178 + height="20.714285" 79.179 + x="138" 79.180 + y="292.00504" /> 79.181 + <text 79.182 + xml:space="preserve" 79.183 + 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:Courier" 79.184 + x="162.09892" 79.185 + y="305.62619" 79.186 + id="text2824"><tspan 79.187 + sodipodi:role="line" 79.188 + id="tspan2826" 79.189 + x="162.09892" 79.190 + y="305.62619" 79.191 + style="font-family:Courier"><tspan 79.192 + style="font-weight:bold" 79.193 + id="tspan2862">4</tspan>: REV4</tspan></text> 79.194 + <path 79.195 + 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" 79.196 + d="M 185.14286,478.50504 L 185.14286,454.34432" 79.197 + id="path2894" 79.198 + inkscape:connector-type="polyline" /> 79.199 + <path 79.200 + 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" 79.201 + d="M 185.14286,431.63004 L 185.14286,407.46932" 79.202 + id="path2896" 79.203 + inkscape:connector-type="polyline" /> 79.204 + <path 79.205 + 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" 79.206 + d="M 185.14286,384.75504 L 185.14286,360.59435" 79.207 + id="path2898" 79.208 + inkscape:connector-type="polyline" /> 79.209 + <path 79.210 + 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" 79.211 + d="M 185.14286,337.88007 L 185.14286,313.71932" 79.212 + id="path2900" 79.213 + inkscape:connector-type="polyline" /> 79.214 + <rect 79.215 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 79.216 + id="rect2863" 79.217 + width="94.285713" 79.218 + height="20.714285" 79.219 + x="91.428574" 79.220 + y="244.71933" /> 79.221 + <text 79.222 + xml:space="preserve" 79.223 + style="font-size:12.00001812px;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:Courier" 79.224 + x="116.09886" 79.225 + y="258.80865" 79.226 + id="text1965" 79.227 + transform="scale(1.000002,0.999998)"><tspan 79.228 + sodipodi:role="line" 79.229 + id="tspan1967" 79.230 + x="116.09886" 79.231 + y="258.80865" 79.232 + style="font-family:Courier"><tspan 79.233 + style="font-weight:bold" 79.234 + id="tspan1973">5</tspan>: REV_my_new_hello</tspan></text> 79.235 + <path 79.236 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1.00000143px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;display:inline" 79.237 + d="M 173.95727,291.00504 L 149.75702,266.43361" 79.238 + id="path1971" 79.239 + inkscape:connector-type="polyline" 79.240 + inkscape:connection-end="#rect2863" 79.241 + inkscape:connection-start="#rect2830" /> 79.242 + <rect 79.243 + style="fill:#78a5ad;fill-opacity:1;stroke:#507b84;stroke-width:2.00000286;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 79.244 + id="rect2911" 79.245 + width="94.285995" 79.246 + height="20.714283" 79.247 + x="186.71414" 79.248 + y="198.6479" /> 79.249 + <text 79.250 + xml:space="preserve" 79.251 + style="font-size:12.00001812px;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:Courier" 79.252 + x="210.81311" 79.253 + y="212.26949" 79.254 + id="text2913" 79.255 + transform="scale(1.000002,0.999998)"><tspan 79.256 + sodipodi:role="line" 79.257 + id="tspan2915" 79.258 + x="210.81311" 79.259 + y="212.26949" 79.260 + style="font-family:Courier"><tspan 79.261 + id="tspan1966" 79.262 + style="font-weight:bold">6</tspan>: REV6_my_new_hello</tspan></text> 79.263 + <path 79.264 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1.00000143px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1;display:inline" 79.265 + d="M 191.06908,291.00504 L 227.93092,220.36218" 79.266 + id="path2919" 79.267 + inkscape:connector-type="polyline" 79.268 + inkscape:connection-start="#rect2830" /> 79.269 + <text 79.270 + xml:space="preserve" 79.271 + 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" 79.272 + x="295.28571" 79.273 + y="211.80988" 79.274 + id="text2871"><tspan 79.275 + sodipodi:role="line" 79.276 + id="tspan2873" 79.277 + x="295.28571" 79.278 + y="211.80988">tip (and head)</tspan></text> 79.279 + <text 79.280 + xml:space="preserve" 79.281 + 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" 79.282 + x="76" 79.283 + y="259.16046" 79.284 + id="text2875"><tspan 79.285 + sodipodi:role="line" 79.286 + id="tspan2877" 79.287 + x="76" 79.288 + y="259.16046" 79.289 + style="text-align:end;text-anchor:end">head</tspan></text> 79.290 + </g> 79.291 +</svg>
80.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 80.2 +++ b/fr/tour-merge-sep-repos.svg Thu Feb 05 12:37:03 2009 +0100 80.3 @@ -0,0 +1,466 @@ 80.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 80.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 80.6 +<svg 80.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 80.8 + xmlns:cc="http://web.resource.org/cc/" 80.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 80.10 + xmlns:svg="http://www.w3.org/2000/svg" 80.11 + xmlns="http://www.w3.org/2000/svg" 80.12 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 80.13 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 80.14 + width="744.09448819" 80.15 + height="1052.3622047" 80.16 + id="svg2" 80.17 + sodipodi:version="0.32" 80.18 + inkscape:version="0.44.1" 80.19 + sodipodi:docname="tour-merge-sep-repos.svg"> 80.20 + <defs 80.21 + id="defs4"> 80.22 + <marker 80.23 + inkscape:stockid="Arrow1Mstart" 80.24 + orient="auto" 80.25 + refY="0.0" 80.26 + refX="0.0" 80.27 + id="Arrow1Mstart" 80.28 + style="overflow:visible"> 80.29 + <path 80.30 + id="path2973" 80.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 " 80.32 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" 80.33 + transform="scale(0.4) translate(10,0)" /> 80.34 + </marker> 80.35 + <marker 80.36 + inkscape:stockid="Arrow1Mend" 80.37 + orient="auto" 80.38 + refY="0.0" 80.39 + refX="0.0" 80.40 + id="Arrow1Mend" 80.41 + style="overflow:visible;"> 80.42 + <path 80.43 + id="path3066" 80.44 + 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 " 80.45 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 80.46 + transform="scale(0.4) rotate(180) translate(10,0)" /> 80.47 + </marker> 80.48 + </defs> 80.49 + <sodipodi:namedview 80.50 + id="base" 80.51 + pagecolor="#ffffff" 80.52 + bordercolor="#666666" 80.53 + borderopacity="1.0" 80.54 + gridtolerance="10000" 80.55 + guidetolerance="10" 80.56 + objecttolerance="10" 80.57 + inkscape:pageopacity="0.0" 80.58 + inkscape:pageshadow="2" 80.59 + inkscape:zoom="1.4" 80.60 + inkscape:cx="307.20351" 80.61 + inkscape:cy="716.87911" 80.62 + inkscape:document-units="px" 80.63 + inkscape:current-layer="layer1" 80.64 + inkscape:window-width="906" 80.65 + inkscape:window-height="620" 80.66 + inkscape:window-x="5" 80.67 + inkscape:window-y="49" /> 80.68 + <metadata 80.69 + id="metadata7"> 80.70 + <rdf:RDF> 80.71 + <cc:Work 80.72 + rdf:about=""> 80.73 + <dc:format>image/svg+xml</dc:format> 80.74 + <dc:type 80.75 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 80.76 + </cc:Work> 80.77 + </rdf:RDF> 80.78 + </metadata> 80.79 + <g 80.80 + inkscape:label="Layer 1" 80.81 + inkscape:groupmode="layer" 80.82 + id="layer1"> 80.83 + <text 80.84 + xml:space="preserve" 80.85 + 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:Courier" 80.86 + x="173.57143" 80.87 + y="443.79074" 80.88 + id="text2832"><tspan 80.89 + sodipodi:role="line" 80.90 + id="tspan2834" 80.91 + x="173.57143" 80.92 + y="443.79074" /></text> 80.93 + <rect 80.94 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.95 + id="rect1878" 80.96 + width="94.285713" 80.97 + height="20.714285" 80.98 + x="138" 80.99 + y="479.50504" /> 80.100 + <text 80.101 + xml:space="preserve" 80.102 + 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:Courier" 80.103 + x="162.09892" 80.104 + y="493.12619" 80.105 + id="text1872"><tspan 80.106 + sodipodi:role="line" 80.107 + id="tspan1874" 80.108 + x="162.09892" 80.109 + y="493.12619" 80.110 + style="font-family:Courier"><tspan 80.111 + style="font-weight:bold" 80.112 + id="tspan1876">0</tspan>: REV0</tspan></text> 80.113 + <rect 80.114 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.115 + id="rect2800" 80.116 + width="94.285713" 80.117 + height="20.714285" 80.118 + x="138" 80.119 + y="432.63004" /> 80.120 + <text 80.121 + xml:space="preserve" 80.122 + 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:Courier" 80.123 + x="162.09892" 80.124 + y="446.25119" 80.125 + id="text2794"><tspan 80.126 + sodipodi:role="line" 80.127 + id="tspan2796" 80.128 + x="162.09892" 80.129 + y="446.25119" 80.130 + style="font-family:Courier"><tspan 80.131 + id="tspan2868" 80.132 + style="font-weight:bold">1</tspan>: REV1</tspan></text> 80.133 + <rect 80.134 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.135 + id="rect2810" 80.136 + width="94.285713" 80.137 + height="20.714285" 80.138 + x="138" 80.139 + y="385.75504" /> 80.140 + <text 80.141 + xml:space="preserve" 80.142 + 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:Courier" 80.143 + x="162.09892" 80.144 + y="399.37619" 80.145 + id="text2804"><tspan 80.146 + sodipodi:role="line" 80.147 + id="tspan2806" 80.148 + x="162.09892" 80.149 + y="399.37619" 80.150 + style="font-family:Courier"><tspan 80.151 + style="font-weight:bold" 80.152 + id="tspan2866">2</tspan>: REV2</tspan></text> 80.153 + <rect 80.154 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.155 + id="rect2820" 80.156 + width="94.285713" 80.157 + height="20.714285" 80.158 + x="138" 80.159 + y="338.88007" /> 80.160 + <text 80.161 + xml:space="preserve" 80.162 + 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:Courier" 80.163 + x="162.09892" 80.164 + y="352.50122" 80.165 + id="text2814"><tspan 80.166 + sodipodi:role="line" 80.167 + id="tspan2816" 80.168 + x="162.09892" 80.169 + y="352.50122" 80.170 + style="font-family:Courier"><tspan 80.171 + style="font-weight:bold" 80.172 + id="tspan2864">3</tspan>: REV3</tspan></text> 80.173 + <rect 80.174 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.175 + id="rect2830" 80.176 + width="94.285713" 80.177 + height="20.714285" 80.178 + x="138" 80.179 + y="292.00504" /> 80.180 + <text 80.181 + xml:space="preserve" 80.182 + 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:Courier" 80.183 + x="162.09892" 80.184 + y="305.62619" 80.185 + id="text2824"><tspan 80.186 + sodipodi:role="line" 80.187 + id="tspan2826" 80.188 + x="162.09892" 80.189 + y="305.62619" 80.190 + style="font-family:Courier"><tspan 80.191 + style="font-weight:bold" 80.192 + id="tspan2862">4</tspan>: REV4</tspan></text> 80.193 + <path 80.194 + 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" 80.195 + d="M 185.14286,478.50504 L 185.14286,454.34432" 80.196 + id="path2894" 80.197 + inkscape:connector-type="polyline" /> 80.198 + <path 80.199 + 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" 80.200 + d="M 185.14286,431.63004 L 185.14286,407.46932" 80.201 + id="path2896" 80.202 + inkscape:connector-type="polyline" /> 80.203 + <path 80.204 + 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" 80.205 + d="M 185.14286,384.75504 L 185.14286,360.59435" 80.206 + id="path2898" 80.207 + inkscape:connector-type="polyline" /> 80.208 + <path 80.209 + 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" 80.210 + d="M 185.14286,337.88007 L 185.14286,313.71932" 80.211 + id="path2900" 80.212 + inkscape:connector-type="polyline" /> 80.213 + <rect 80.214 + style="fill:#78a5ad;fill-opacity:1;stroke:#507b84;stroke-width:2.00000286;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.215 + id="rect1963" 80.216 + width="94.285995" 80.217 + height="20.714283" 80.218 + x="138" 80.219 + y="245.18723" /> 80.220 + <text 80.221 + xml:space="preserve" 80.222 + style="font-size:12.00001812px;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:Courier" 80.223 + x="162.09877" 80.224 + y="258.80865" 80.225 + id="text1965" 80.226 + transform="scale(1.000002,0.999998)"><tspan 80.227 + sodipodi:role="line" 80.228 + id="tspan1967" 80.229 + x="162.09877" 80.230 + y="258.80865" 80.231 + style="font-family:Courier"><tspan 80.232 + style="font-weight:bold" 80.233 + id="tspan1973">5</tspan>: REV_my_hello</tspan></text> 80.234 + <path 80.235 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1.00000143px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 80.236 + d="M 185.143,291.06218 L 185.143,266.90143" 80.237 + id="path1971" 80.238 + inkscape:connector-type="polyline" /> 80.239 + <text 80.240 + xml:space="preserve" 80.241 + 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" 80.242 + x="136.90039" 80.243 + y="232.25546" 80.244 + id="text2921"><tspan 80.245 + sodipodi:role="line" 80.246 + id="tspan2923" 80.247 + x="136.90039" 80.248 + y="232.25546">my-hello</tspan></text> 80.249 + <rect 80.250 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.251 + id="rect2863" 80.252 + width="94.285713" 80.253 + height="20.714285" 80.254 + x="370.71414" 80.255 + y="479.49289" /> 80.256 + <text 80.257 + xml:space="preserve" 80.258 + 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:Courier" 80.259 + x="394.81305" 80.260 + y="493.11404" 80.261 + id="text2865"><tspan 80.262 + sodipodi:role="line" 80.263 + id="tspan2867" 80.264 + x="394.81305" 80.265 + y="493.11404" 80.266 + style="font-family:Courier"><tspan 80.267 + style="font-weight:bold" 80.268 + id="tspan2869">0</tspan>: REV0</tspan></text> 80.269 + <rect 80.270 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.271 + id="rect2871" 80.272 + width="94.285713" 80.273 + height="20.714285" 80.274 + x="370.71414" 80.275 + y="432.61789" /> 80.276 + <text 80.277 + xml:space="preserve" 80.278 + 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:Courier" 80.279 + x="394.81305" 80.280 + y="446.23904" 80.281 + id="text2873"><tspan 80.282 + sodipodi:role="line" 80.283 + id="tspan2875" 80.284 + x="394.81305" 80.285 + y="446.23904" 80.286 + style="font-family:Courier"><tspan 80.287 + id="tspan2877" 80.288 + style="font-weight:bold">1</tspan>: REV1</tspan></text> 80.289 + <rect 80.290 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.291 + id="rect2879" 80.292 + width="94.285713" 80.293 + height="20.714285" 80.294 + x="370.71414" 80.295 + y="385.74289" /> 80.296 + <text 80.297 + xml:space="preserve" 80.298 + 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:Courier" 80.299 + x="394.81305" 80.300 + y="399.36404" 80.301 + id="text2881"><tspan 80.302 + sodipodi:role="line" 80.303 + id="tspan2883" 80.304 + x="394.81305" 80.305 + y="399.36404" 80.306 + style="font-family:Courier"><tspan 80.307 + style="font-weight:bold" 80.308 + id="tspan2885">2</tspan>: REV2</tspan></text> 80.309 + <rect 80.310 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.311 + id="rect2887" 80.312 + width="94.285713" 80.313 + height="20.714285" 80.314 + x="370.71414" 80.315 + y="338.86792" /> 80.316 + <text 80.317 + xml:space="preserve" 80.318 + 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:Courier" 80.319 + x="394.81305" 80.320 + y="352.48907" 80.321 + id="text2889"><tspan 80.322 + sodipodi:role="line" 80.323 + id="tspan2891" 80.324 + x="394.81305" 80.325 + y="352.48907" 80.326 + style="font-family:Courier"><tspan 80.327 + style="font-weight:bold" 80.328 + id="tspan2893">3</tspan>: REV3</tspan></text> 80.329 + <rect 80.330 + style="fill:#a5c3c8;fill-opacity:1;stroke:#6396a0;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.331 + id="rect2895" 80.332 + width="94.285713" 80.333 + height="20.714285" 80.334 + x="370.71414" 80.335 + y="291.99289" /> 80.336 + <text 80.337 + xml:space="preserve" 80.338 + 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:Courier" 80.339 + x="394.81305" 80.340 + y="305.61404" 80.341 + id="text2897"><tspan 80.342 + sodipodi:role="line" 80.343 + id="tspan2899" 80.344 + x="394.81305" 80.345 + y="305.61404" 80.346 + style="font-family:Courier"><tspan 80.347 + style="font-weight:bold" 80.348 + id="tspan2901">4</tspan>: REV4</tspan></text> 80.349 + <path 80.350 + 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" 80.351 + d="M 417.85701,478.4929 L 417.85701,454.33218" 80.352 + id="path2903" 80.353 + inkscape:connector-type="polyline" /> 80.354 + <path 80.355 + 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" 80.356 + d="M 417.85701,431.6179 L 417.85701,407.45718" 80.357 + id="path2905" 80.358 + inkscape:connector-type="polyline" /> 80.359 + <path 80.360 + 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" 80.361 + d="M 417.85701,384.7429 L 417.85701,360.58221" 80.362 + id="path2907" 80.363 + inkscape:connector-type="polyline" /> 80.364 + <path 80.365 + 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" 80.366 + d="M 417.85701,337.86793 L 417.85701,313.70718" 80.367 + id="path2909" 80.368 + inkscape:connector-type="polyline" /> 80.369 + <rect 80.370 + style="fill:#78a5ad;fill-opacity:1;stroke:#507b84;stroke-width:2.00000286;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.371 + id="rect2911" 80.372 + width="94.285995" 80.373 + height="20.714283" 80.374 + x="370.71414" 80.375 + y="245.17511" /> 80.376 + <text 80.377 + xml:space="preserve" 80.378 + style="font-size:12.00001812px;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:Courier" 80.379 + x="394.81274" 80.380 + y="258.79678" 80.381 + id="text2913" 80.382 + transform="scale(1.000002,0.999998)"><tspan 80.383 + sodipodi:role="line" 80.384 + id="tspan2915" 80.385 + x="394.81274" 80.386 + y="258.79678" 80.387 + style="font-family:Courier"><tspan 80.388 + style="font-weight:bold" 80.389 + id="tspan2917">5</tspan>: REV_my_new_hello</tspan></text> 80.390 + <path 80.391 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1.00000143px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 80.392 + d="M 417.85715,291.05004 L 417.85715,266.88929" 80.393 + id="path2919" 80.394 + inkscape:connector-type="polyline" /> 80.395 + <text 80.396 + xml:space="preserve" 80.397 + 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" 80.398 + x="369.61453" 80.399 + y="232.25546" 80.400 + id="text2925"><tspan 80.401 + sodipodi:role="line" 80.402 + id="tspan2927" 80.403 + x="369.61453" 80.404 + y="232.25546">my-new-hello</tspan></text> 80.405 + <text 80.406 + xml:space="preserve" 80.407 + 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" 80.408 + x="300.54352" 80.409 + y="252.12723" 80.410 + id="text2933"><tspan 80.411 + sodipodi:role="line" 80.412 + id="tspan2935" 80.413 + x="300.54352" 80.414 + y="252.12723" 80.415 + style="text-align:center;text-anchor:middle">newest changes</tspan><tspan 80.416 + sodipodi:role="line" 80.417 + x="300.54352" 80.418 + y="267.12723" 80.419 + style="text-align:center;text-anchor:middle" 80.420 + id="tspan3132">differ</tspan></text> 80.421 + <text 80.422 + xml:space="preserve" 80.423 + style="font-size:12px;font-style:normal;font-weight:normal;text-align:start;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 80.424 + x="262.15436" 80.425 + y="398.37112" 80.426 + id="text2929"><tspan 80.427 + sodipodi:role="line" 80.428 + x="262.15436" 80.429 + y="398.37112" 80.430 + id="tspan3013" 80.431 + style="text-align:start;text-anchor:start">common history</tspan></text> 80.432 + <g 80.433 + id="g3107" 80.434 + transform="translate(0,0.855744)"> 80.435 + <path 80.436 + id="path3101" 80.437 + d="M 300.35713,381.29075 L 300.35713,304.50504" 80.438 + style="fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:4, 4;stroke-dashoffset:0;stroke-opacity:1" /> 80.439 + <path 80.440 + id="path3105" 80.441 + d="M 291.07142,301.64789 L 309.28571,301.64789" 80.442 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#bfbfbf;stroke-width:0.60000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> 80.443 + </g> 80.444 + <path 80.445 + style="fill:black;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:4, 4;stroke-dashoffset:0;stroke-opacity:1" 80.446 + d="M 300.53571,486.38926 L 300.53571,409.60355" 80.447 + id="path3113" /> 80.448 + <path 80.449 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#bfbfbf;stroke-width:0.60000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 80.450 + d="M 291.25,488.49641 L 309.46429,488.49641" 80.451 + id="path3115" /> 80.452 + <text 80.453 + xml:space="preserve" 80.454 + 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" 80.455 + x="480.71429" 80.456 + y="250.91507" 80.457 + id="text1949"><tspan 80.458 + sodipodi:role="line" 80.459 + id="tspan1951" 80.460 + x="480.71429" 80.461 + y="250.91507" 80.462 + style="text-align:start;text-anchor:start">head revision</tspan><tspan 80.463 + sodipodi:role="line" 80.464 + x="480.71429" 80.465 + y="265.91507" 80.466 + id="tspan1953" 80.467 + style="text-align:start;text-anchor:start">(has no children)</tspan></text> 80.468 + </g> 80.469 +</svg>
81.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 81.2 +++ b/fr/tour-merge.tex Thu Feb 05 12:37:03 2009 +0100 81.3 @@ -0,0 +1,283 @@ 81.4 +\chapter{A tour of Mercurial: merging work} 81.5 +\label{chap:tour-merge} 81.6 + 81.7 +We've now covered cloning a repository, making changes in a 81.8 +repository, and pulling or pushing changes from one repository into 81.9 +another. Our next step is \emph{merging} changes from separate 81.10 +repositories. 81.11 + 81.12 +\section{Merging streams of work} 81.13 + 81.14 +Merging is a fundamental part of working with a distributed revision 81.15 +control tool. 81.16 +\begin{itemize} 81.17 +\item Alice and Bob each have a personal copy of a repository for a 81.18 + project they're collaborating on. Alice fixes a bug in her 81.19 + repository; Bob adds a new feature in his. They want the shared 81.20 + repository to contain both the bug fix and the new feature. 81.21 +\item I frequently work on several different tasks for a single 81.22 + project at once, each safely isolated in its own repository. 81.23 + Working this way means that I often need to merge one piece of my 81.24 + own work with another. 81.25 +\end{itemize} 81.26 + 81.27 +Because merging is such a common thing to need to do, Mercurial makes 81.28 +it easy. Let's walk through the process. We'll begin by cloning yet 81.29 +another repository (see how often they spring up?) and making a change 81.30 +in it. 81.31 +\interaction{tour.merge.clone} 81.32 +We should now have two copies of \filename{hello.c} with different 81.33 +contents. The histories of the two repositories have also diverged, 81.34 +as illustrated in figure~\ref{fig:tour-merge:sep-repos}. 81.35 +\interaction{tour.merge.cat} 81.36 + 81.37 +\begin{figure}[ht] 81.38 + \centering 81.39 + \grafix{tour-merge-sep-repos} 81.40 + \caption{Divergent recent histories of the \dirname{my-hello} and 81.41 + \dirname{my-new-hello} repositories} 81.42 + \label{fig:tour-merge:sep-repos} 81.43 +\end{figure} 81.44 + 81.45 +We already know that pulling changes from our \dirname{my-hello} 81.46 +repository will have no effect on the working directory. 81.47 +\interaction{tour.merge.pull} 81.48 +However, the \hgcmd{pull} command says something about ``heads''. 81.49 + 81.50 +\subsection{Head changesets} 81.51 + 81.52 +A head is a change that has no descendants, or children, as they're 81.53 +also known. The tip revision is thus a head, because the newest 81.54 +revision in a repository doesn't have any children, but a repository 81.55 +can contain more than one head. 81.56 + 81.57 +\begin{figure}[ht] 81.58 + \centering 81.59 + \grafix{tour-merge-pull} 81.60 + \caption{Repository contents after pulling from \dirname{my-hello} into 81.61 + \dirname{my-new-hello}} 81.62 + \label{fig:tour-merge:pull} 81.63 +\end{figure} 81.64 + 81.65 +In figure~\ref{fig:tour-merge:pull}, you can see the effect of the 81.66 +pull from \dirname{my-hello} into \dirname{my-new-hello}. The history 81.67 +that was already present in \dirname{my-new-hello} is untouched, but a 81.68 +new revision has been added. By referring to 81.69 +figure~\ref{fig:tour-merge:sep-repos}, we can see that the 81.70 +\emph{changeset ID} remains the same in the new repository, but the 81.71 +\emph{revision number} has changed. (This, incidentally, is a fine 81.72 +example of why it's not safe to use revision numbers when discussing 81.73 +changesets.) We can view the heads in a repository using the 81.74 +\hgcmd{heads} command. 81.75 +\interaction{tour.merge.heads} 81.76 + 81.77 +\subsection{Performing the merge} 81.78 + 81.79 +What happens if we try to use the normal \hgcmd{update} command to 81.80 +update to the new tip? 81.81 +\interaction{tour.merge.update} 81.82 +Mercurial is telling us that the \hgcmd{update} command won't do a 81.83 +merge; it won't update the working directory when it thinks we might 81.84 +be wanting to do a merge, unless we force it to do so. Instead, we 81.85 +use the \hgcmd{merge} command to merge the two heads. 81.86 +\interaction{tour.merge.merge} 81.87 + 81.88 +\begin{figure}[ht] 81.89 + \centering 81.90 + \grafix{tour-merge-merge} 81.91 + \caption{Working directory and repository during merge, and 81.92 + following commit} 81.93 + \label{fig:tour-merge:merge} 81.94 +\end{figure} 81.95 + 81.96 +This updates the working directory so that it contains changes from 81.97 +\emph{both} heads, which is reflected in both the output of 81.98 +\hgcmd{parents} and the contents of \filename{hello.c}. 81.99 +\interaction{tour.merge.parents} 81.100 + 81.101 +\subsection{Committing the results of the merge} 81.102 + 81.103 +Whenever we've done a merge, \hgcmd{parents} will display two parents 81.104 +until we \hgcmd{commit} the results of the merge. 81.105 +\interaction{tour.merge.commit} 81.106 +We now have a new tip revision; notice that it has \emph{both} of 81.107 +our former heads as its parents. These are the same revisions that 81.108 +were previously displayed by \hgcmd{parents}. 81.109 +\interaction{tour.merge.tip} 81.110 +In figure~\ref{fig:tour-merge:merge}, you can see a representation of 81.111 +what happens to the working directory during the merge, and how this 81.112 +affects the repository when the commit happens. During the merge, the 81.113 +working directory has two parent changesets, and these become the 81.114 +parents of the new changeset. 81.115 + 81.116 +\section{Merging conflicting changes} 81.117 + 81.118 +Most merges are simple affairs, but sometimes you'll find yourself 81.119 +merging changes where each modifies the same portions of the same 81.120 +files. Unless both modifications are identical, this results in a 81.121 +\emph{conflict}, where you have to decide how to reconcile the 81.122 +different changes into something coherent. 81.123 + 81.124 +\begin{figure}[ht] 81.125 + \centering 81.126 + \grafix{tour-merge-conflict} 81.127 + \caption{Conflicting changes to a document} 81.128 + \label{fig:tour-merge:conflict} 81.129 +\end{figure} 81.130 + 81.131 +Figure~\ref{fig:tour-merge:conflict} illustrates an instance of two 81.132 +conflicting changes to a document. We started with a single version 81.133 +of the file; then we made some changes; while someone else made 81.134 +different changes to the same text. Our task in resolving the 81.135 +conflicting changes is to decide what the file should look like. 81.136 + 81.137 +Mercurial doesn't have a built-in facility for handling conflicts. 81.138 +Instead, it runs an external program called \command{hgmerge}. This 81.139 +is a shell script that is bundled with Mercurial; you can change it to 81.140 +behave however you please. What it does by default is try to find one 81.141 +of several different merging tools that are likely to be installed on 81.142 +your system. It first tries a few fully automatic merging tools; if 81.143 +these don't succeed (because the resolution process requires human 81.144 +guidance) or aren't present, the script tries a few different 81.145 +graphical merging tools. 81.146 + 81.147 +It's also possible to get Mercurial to run another program or script 81.148 +instead of \command{hgmerge}, by setting the \envar{HGMERGE} 81.149 +environment variable to the name of your preferred program. 81.150 + 81.151 +\subsection{Using a graphical merge tool} 81.152 + 81.153 +My preferred graphical merge tool is \command{kdiff3}, which I'll use 81.154 +to describe the features that are common to graphical file merging 81.155 +tools. You can see a screenshot of \command{kdiff3} in action in 81.156 +figure~\ref{fig:tour-merge:kdiff3}. The kind of merge it is 81.157 +performing is called a \emph{three-way merge}, because there are three 81.158 +different versions of the file of interest to us. The tool thus 81.159 +splits the upper portion of the window into three panes: 81.160 +\begin{itemize} 81.161 +\item At the left is the \emph{base} version of the file, i.e.~the 81.162 + most recent version from which the two versions we're trying to 81.163 + merge are descended. 81.164 +\item In the middle is ``our'' version of the file, with the contents 81.165 + that we modified. 81.166 +\item On the right is ``their'' version of the file, the one that 81.167 + from the changeset that we're trying to merge with. 81.168 +\end{itemize} 81.169 +In the pane below these is the current \emph{result} of the merge. 81.170 +Our task is to replace all of the red text, which indicates unresolved 81.171 +conflicts, with some sensible merger of the ``ours'' and ``theirs'' 81.172 +versions of the file. 81.173 + 81.174 +All four of these panes are \emph{locked together}; if we scroll 81.175 +vertically or horizontally in any of them, the others are updated to 81.176 +display the corresponding sections of their respective files. 81.177 + 81.178 +\begin{figure}[ht] 81.179 + \centering 81.180 + \grafix{kdiff3} 81.181 + \caption{Using \command{kdiff3} to merge versions of a file} 81.182 + \label{fig:tour-merge:kdiff3} 81.183 +\end{figure} 81.184 + 81.185 +For each conflicting portion of the file, we can choose to resolve 81.186 +the conflict using some combination of text from the base version, 81.187 +ours, or theirs. We can also manually edit the merged file at any 81.188 +time, in case we need to make further modifications. 81.189 + 81.190 +There are \emph{many} file merging tools available, too many to cover 81.191 +here. They vary in which platforms they are available for, and in 81.192 +their particular strengths and weaknesses. Most are tuned for merging 81.193 +files containing plain text, while a few are aimed at specialised file 81.194 +formats (generally XML). 81.195 + 81.196 +\subsection{A worked example} 81.197 + 81.198 +In this example, we will reproduce the file modification history of 81.199 +figure~\ref{fig:tour-merge:conflict} above. Let's begin by creating a 81.200 +repository with a base version of our document. 81.201 +\interaction{tour-merge-conflict.wife} 81.202 +We'll clone the repository and make a change to the file. 81.203 +\interaction{tour-merge-conflict.cousin} 81.204 +And another clone, to simulate someone else making a change to the 81.205 +file. (This hints at the idea that it's not all that unusual to merge 81.206 +with yourself when you isolate tasks in separate repositories, and 81.207 +indeed to find and resolve conflicts while doing so.) 81.208 +\interaction{tour-merge-conflict.son} 81.209 +Having created two different versions of the file, we'll set up an 81.210 +environment suitable for running our merge. 81.211 +\interaction{tour-merge-conflict.pull} 81.212 + 81.213 +In this example, I won't use Mercurial's normal \command{hgmerge} 81.214 +program to do the merge, because it would drop my nice automated 81.215 +example-running tool into a graphical user interface. Instead, I'll 81.216 +set \envar{HGMERGE} to tell Mercurial to use the non-interactive 81.217 +\command{merge} command. This is bundled with many Unix-like systems. 81.218 +If you're following this example on your computer, don't bother 81.219 +setting \envar{HGMERGE}. 81.220 +\interaction{tour-merge-conflict.merge} 81.221 +Because \command{merge} can't resolve the conflicting changes, it 81.222 +leaves \emph{merge markers} inside the file that has conflicts, 81.223 +indicating which lines have conflicts, and whether they came from our 81.224 +version of the file or theirs. 81.225 + 81.226 +Mercurial can tell from the way \command{merge} exits that it wasn't 81.227 +able to merge successfully, so it tells us what commands we'll need to 81.228 +run if we want to redo the merging operation. This could be useful 81.229 +if, for example, we were running a graphical merge tool and quit 81.230 +because we were confused or realised we had made a mistake. 81.231 + 81.232 +If automatic or manual merges fail, there's nothing to prevent us from 81.233 +``fixing up'' the affected files ourselves, and committing the results 81.234 +of our merge: 81.235 +\interaction{tour-merge-conflict.commit} 81.236 + 81.237 +\section{Simplifying the pull-merge-commit sequence} 81.238 +\label{sec:tour-merge:fetch} 81.239 + 81.240 +The process of merging changes as outlined above is straightforward, 81.241 +but requires running three commands in sequence. 81.242 +\begin{codesample2} 81.243 + hg pull 81.244 + hg merge 81.245 + hg commit -m 'Merged remote changes' 81.246 +\end{codesample2} 81.247 +In the case of the final commit, you also need to enter a commit 81.248 +message, which is almost always going to be a piece of uninteresting 81.249 +``boilerplate'' text. 81.250 + 81.251 +It would be nice to reduce the number of steps needed, if this were 81.252 +possible. Indeed, Mercurial is distributed with an extension called 81.253 +\hgext{fetch} that does just this. 81.254 + 81.255 +Mercurial provides a flexible extension mechanism that lets people 81.256 +extend its functionality, while keeping the core of Mercurial small 81.257 +and easy to deal with. Some extensions add new commands that you can 81.258 +use from the command line, while others work ``behind the scenes,'' 81.259 +for example adding capabilities to the server. 81.260 + 81.261 +The \hgext{fetch} extension adds a new command called, not 81.262 +surprisingly, \hgcmd{fetch}. This extension acts as a combination of 81.263 +\hgcmd{pull}, \hgcmd{update} and \hgcmd{merge}. It begins by pulling 81.264 +changes from another repository into the current repository. If it 81.265 +finds that the changes added a new head to the repository, it begins a 81.266 +merge, then commits the result of the merge with an 81.267 +automatically-generated commit message. If no new heads were added, 81.268 +it updates the working directory to the new tip changeset. 81.269 + 81.270 +Enabling the \hgext{fetch} extension is easy. Edit your 81.271 +\sfilename{.hgrc}, and either go to the \rcsection{extensions} section 81.272 +or create an \rcsection{extensions} section. Then add a line that 81.273 +simply reads ``\Verb+fetch +''. 81.274 +\begin{codesample2} 81.275 + [extensions] 81.276 + fetch = 81.277 +\end{codesample2} 81.278 +(Normally, on the right-hand side of the ``\texttt{=}'' would appear 81.279 +the location of the extension, but since the \hgext{fetch} extension 81.280 +is in the standard distribution, Mercurial knows where to search for 81.281 +it.) 81.282 + 81.283 +%%% Local Variables: 81.284 +%%% mode: latex 81.285 +%%% TeX-master: "00book" 81.286 +%%% End:
82.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 82.2 +++ b/fr/undo-manual-merge.dot Thu Feb 05 12:37:03 2009 +0100 82.3 @@ -0,0 +1,8 @@ 82.4 +digraph undo_manual { 82.5 + "first change" -> "second change"; 82.6 + "second change" -> "third change"; 82.7 + backout [label="back out\nsecond change", shape=box]; 82.8 + "second change" -> backout; 82.9 + "third change" -> "manual\nmerge"; 82.10 + backout -> "manual\nmerge"; 82.11 +}
83.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 83.2 +++ b/fr/undo-manual.dot Thu Feb 05 12:37:03 2009 +0100 83.3 @@ -0,0 +1,6 @@ 83.4 +digraph undo_manual { 83.5 + "first change" -> "second change"; 83.6 + "second change" -> "third change"; 83.7 + backout [label="back out\nsecond change", shape=box]; 83.8 + "second change" -> backout; 83.9 +}
84.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 84.2 +++ b/fr/undo-non-tip.dot Thu Feb 05 12:37:03 2009 +0100 84.3 @@ -0,0 +1,9 @@ 84.4 +digraph undo_non_tip { 84.5 + "first change" -> "second change"; 84.6 + "second change" -> "third change"; 84.7 + backout [label="back out\nsecond change", shape=box]; 84.8 + "second change" -> backout; 84.9 + merge [label="automated\nmerge", shape=box]; 84.10 + "third change" -> merge; 84.11 + backout -> merge; 84.12 +}
85.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 85.2 +++ b/fr/undo-simple.dot Thu Feb 05 12:37:03 2009 +0100 85.3 @@ -0,0 +1,4 @@ 85.4 +digraph undo_simple { 85.5 + "first change" -> "second change"; 85.6 + "second change" -> "back out\nsecond change"; 85.7 +}
86.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 86.2 +++ b/fr/undo.tex Thu Feb 05 12:37:03 2009 +0100 86.3 @@ -0,0 +1,767 @@ 86.4 +\chapter{Finding and fixing your mistakes} 86.5 +\label{chap:undo} 86.6 + 86.7 +To err might be human, but to really handle the consequences well 86.8 +takes a top-notch revision control system. In this chapter, we'll 86.9 +discuss some of the techniques you can use when you find that a 86.10 +problem has crept into your project. Mercurial has some highly 86.11 +capable features that will help you to isolate the sources of 86.12 +problems, and to handle them appropriately. 86.13 + 86.14 +\section{Erasing local history} 86.15 + 86.16 +\subsection{The accidental commit} 86.17 + 86.18 +I have the occasional but persistent problem of typing rather more 86.19 +quickly than I can think, which sometimes results in me committing a 86.20 +changeset that is either incomplete or plain wrong. In my case, the 86.21 +usual kind of incomplete changeset is one in which I've created a new 86.22 +source file, but forgotten to \hgcmd{add} it. A ``plain wrong'' 86.23 +changeset is not as common, but no less annoying. 86.24 + 86.25 +\subsection{Rolling back a transaction} 86.26 +\label{sec:undo:rollback} 86.27 + 86.28 +In section~\ref{sec:concepts:txn}, I mentioned that Mercurial treats 86.29 +each modification of a repository as a \emph{transaction}. Every time 86.30 +you commit a changeset or pull changes from another repository, 86.31 +Mercurial remembers what you did. You can undo, or \emph{roll back}, 86.32 +exactly one of these actions using the \hgcmd{rollback} command. (See 86.33 +section~\ref{sec:undo:rollback-after-push} for an important caveat 86.34 +about the use of this command.) 86.35 + 86.36 +Here's a mistake that I often find myself making: committing a change 86.37 +in which I've created a new file, but forgotten to \hgcmd{add} it. 86.38 +\interaction{rollback.commit} 86.39 +Looking at the output of \hgcmd{status} after the commit immediately 86.40 +confirms the error. 86.41 +\interaction{rollback.status} 86.42 +The commit captured the changes to the file \filename{a}, but not the 86.43 +new file \filename{b}. If I were to push this changeset to a 86.44 +repository that I shared with a colleague, the chances are high that 86.45 +something in \filename{a} would refer to \filename{b}, which would not 86.46 +be present in their repository when they pulled my changes. I would 86.47 +thus become the object of some indignation. 86.48 + 86.49 +However, luck is with me---I've caught my error before I pushed the 86.50 +changeset. I use the \hgcmd{rollback} command, and Mercurial makes 86.51 +that last changeset vanish. 86.52 +\interaction{rollback.rollback} 86.53 +Notice that the changeset is no longer present in the repository's 86.54 +history, and the working directory once again thinks that the file 86.55 +\filename{a} is modified. The commit and rollback have left the 86.56 +working directory exactly as it was prior to the commit; the changeset 86.57 +has been completely erased. I can now safely \hgcmd{add} the file 86.58 +\filename{b}, and rerun my commit. 86.59 +\interaction{rollback.add} 86.60 + 86.61 +\subsection{The erroneous pull} 86.62 + 86.63 +It's common practice with Mercurial to maintain separate development 86.64 +branches of a project in different repositories. Your development 86.65 +team might have one shared repository for your project's ``0.9'' 86.66 +release, and another, containing different changes, for the ``1.0'' 86.67 +release. 86.68 + 86.69 +Given this, you can imagine that the consequences could be messy if 86.70 +you had a local ``0.9'' repository, and accidentally pulled changes 86.71 +from the shared ``1.0'' repository into it. At worst, you could be 86.72 +paying insufficient attention, and push those changes into the shared 86.73 +``0.9'' tree, confusing your entire team (but don't worry, we'll 86.74 +return to this horror scenario later). However, it's more likely that 86.75 +you'll notice immediately, because Mercurial will display the URL it's 86.76 +pulling from, or you will see it pull a suspiciously large number of 86.77 +changes into the repository. 86.78 + 86.79 +The \hgcmd{rollback} command will work nicely to expunge all of the 86.80 +changesets that you just pulled. Mercurial groups all changes from 86.81 +one \hgcmd{pull} into a single transaction, so one \hgcmd{rollback} is 86.82 +all you need to undo this mistake. 86.83 + 86.84 +\subsection{Rolling back is useless once you've pushed} 86.85 +\label{sec:undo:rollback-after-push} 86.86 + 86.87 +The value of the \hgcmd{rollback} command drops to zero once you've 86.88 +pushed your changes to another repository. Rolling back a change 86.89 +makes it disappear entirely, but \emph{only} in the repository in 86.90 +which you perform the \hgcmd{rollback}. Because a rollback eliminates 86.91 +history, there's no way for the disappearance of a change to propagate 86.92 +between repositories. 86.93 + 86.94 +If you've pushed a change to another repository---particularly if it's 86.95 +a shared repository---it has essentially ``escaped into the wild,'' 86.96 +and you'll have to recover from your mistake in a different way. What 86.97 +will happen if you push a changeset somewhere, then roll it back, then 86.98 +pull from the repository you pushed to, is that the changeset will 86.99 +reappear in your repository. 86.100 + 86.101 +(If you absolutely know for sure that the change you want to roll back 86.102 +is the most recent change in the repository that you pushed to, 86.103 +\emph{and} you know that nobody else could have pulled it from that 86.104 +repository, you can roll back the changeset there, too, but you really 86.105 +should really not rely on this working reliably. If you do this, 86.106 +sooner or later a change really will make it into a repository that 86.107 +you don't directly control (or have forgotten about), and come back to 86.108 +bite you.) 86.109 + 86.110 +\subsection{You can only roll back once} 86.111 + 86.112 +Mercurial stores exactly one transaction in its transaction log; that 86.113 +transaction is the most recent one that occurred in the repository. 86.114 +This means that you can only roll back one transaction. If you expect 86.115 +to be able to roll back one transaction, then its predecessor, this is 86.116 +not the behaviour you will get. 86.117 +\interaction{rollback.twice} 86.118 +Once you've rolled back one transaction in a repository, you can't 86.119 +roll back again in that repository until you perform another commit or 86.120 +pull. 86.121 + 86.122 +\section{Reverting the mistaken change} 86.123 + 86.124 +If you make a modification to a file, and decide that you really 86.125 +didn't want to change the file at all, and you haven't yet committed 86.126 +your changes, the \hgcmd{revert} command is the one you'll need. It 86.127 +looks at the changeset that's the parent of the working directory, and 86.128 +restores the contents of the file to their state as of that changeset. 86.129 +(That's a long-winded way of saying that, in the normal case, it 86.130 +undoes your modifications.) 86.131 + 86.132 +Let's illustrate how the \hgcmd{revert} command works with yet another 86.133 +small example. We'll begin by modifying a file that Mercurial is 86.134 +already tracking. 86.135 +\interaction{daily.revert.modify} 86.136 +If we don't want that change, we can simply \hgcmd{revert} the file. 86.137 +\interaction{daily.revert.unmodify} 86.138 +The \hgcmd{revert} command provides us with an extra degree of safety 86.139 +by saving our modified file with a \filename{.orig} extension. 86.140 +\interaction{daily.revert.status} 86.141 + 86.142 +Here is a summary of the cases that the \hgcmd{revert} command can 86.143 +deal with. We will describe each of these in more detail in the 86.144 +section that follows. 86.145 +\begin{itemize} 86.146 +\item If you modify a file, it will restore the file to its unmodified 86.147 + state. 86.148 +\item If you \hgcmd{add} a file, it will undo the ``added'' state of 86.149 + the file, but leave the file itself untouched. 86.150 +\item If you delete a file without telling Mercurial, it will restore 86.151 + the file to its unmodified contents. 86.152 +\item If you use the \hgcmd{remove} command to remove a file, it will 86.153 + undo the ``removed'' state of the file, and restore the file to its 86.154 + unmodified contents. 86.155 +\end{itemize} 86.156 + 86.157 +\subsection{File management errors} 86.158 +\label{sec:undo:mgmt} 86.159 + 86.160 +The \hgcmd{revert} command is useful for more than just modified 86.161 +files. It lets you reverse the results of all of Mercurial's file 86.162 +management commands---\hgcmd{add}, \hgcmd{remove}, and so on. 86.163 + 86.164 +If you \hgcmd{add} a file, then decide that in fact you don't want 86.165 +Mercurial to track it, use \hgcmd{revert} to undo the add. Don't 86.166 +worry; Mercurial will not modify the file in any way. It will just 86.167 +``unmark'' the file. 86.168 +\interaction{daily.revert.add} 86.169 + 86.170 +Similarly, if you ask Mercurial to \hgcmd{remove} a file, you can use 86.171 +\hgcmd{revert} to restore it to the contents it had as of the parent 86.172 +of the working directory. 86.173 +\interaction{daily.revert.remove} 86.174 +This works just as well for a file that you deleted by hand, without 86.175 +telling Mercurial (recall that in Mercurial terminology, this kind of 86.176 +file is called ``missing''). 86.177 +\interaction{daily.revert.missing} 86.178 + 86.179 +If you revert a \hgcmd{copy}, the copied-to file remains in your 86.180 +working directory afterwards, untracked. Since a copy doesn't affect 86.181 +the copied-from file in any way, Mercurial doesn't do anything with 86.182 +the copied-from file. 86.183 +\interaction{daily.revert.copy} 86.184 + 86.185 +\subsubsection{A slightly special case: reverting a rename} 86.186 + 86.187 +If you \hgcmd{rename} a file, there is one small detail that 86.188 +you should remember. When you \hgcmd{revert} a rename, it's not 86.189 +enough to provide the name of the renamed-to file, as you can see 86.190 +here. 86.191 +\interaction{daily.revert.rename} 86.192 +As you can see from the output of \hgcmd{status}, the renamed-to file 86.193 +is no longer identified as added, but the renamed-\emph{from} file is 86.194 +still removed! This is counter-intuitive (at least to me), but at 86.195 +least it's easy to deal with. 86.196 +\interaction{daily.revert.rename-orig} 86.197 +So remember, to revert a \hgcmd{rename}, you must provide \emph{both} 86.198 +the source and destination names. 86.199 + 86.200 +% TODO: the output doesn't look like it will be removed! 86.201 + 86.202 +(By the way, if you rename a file, then modify the renamed-to file, 86.203 +then revert both components of the rename, when Mercurial restores the 86.204 +file that was removed as part of the rename, it will be unmodified. 86.205 +If you need the modifications in the renamed-to file to show up in the 86.206 +renamed-from file, don't forget to copy them over.) 86.207 + 86.208 +These fiddly aspects of reverting a rename arguably constitute a small 86.209 +bug in Mercurial. 86.210 + 86.211 +\section{Dealing with committed changes} 86.212 + 86.213 +Consider a case where you have committed a change $a$, and another 86.214 +change $b$ on top of it; you then realise that change $a$ was 86.215 +incorrect. Mercurial lets you ``back out'' an entire changeset 86.216 +automatically, and building blocks that let you reverse part of a 86.217 +changeset by hand. 86.218 + 86.219 +Before you read this section, here's something to keep in mind: the 86.220 +\hgcmd{backout} command undoes changes by \emph{adding} history, not 86.221 +by modifying or erasing it. It's the right tool to use if you're 86.222 +fixing bugs, but not if you're trying to undo some change that has 86.223 +catastrophic consequences. To deal with those, see 86.224 +section~\ref{sec:undo:aaaiiieee}. 86.225 + 86.226 +\subsection{Backing out a changeset} 86.227 + 86.228 +The \hgcmd{backout} command lets you ``undo'' the effects of an entire 86.229 +changeset in an automated fashion. Because Mercurial's history is 86.230 +immutable, this command \emph{does not} get rid of the changeset you 86.231 +want to undo. Instead, it creates a new changeset that 86.232 +\emph{reverses} the effect of the to-be-undone changeset. 86.233 + 86.234 +The operation of the \hgcmd{backout} command is a little intricate, so 86.235 +let's illustrate it with some examples. First, we'll create a 86.236 +repository with some simple changes. 86.237 +\interaction{backout.init} 86.238 + 86.239 +The \hgcmd{backout} command takes a single changeset ID as its 86.240 +argument; this is the changeset to back out. Normally, 86.241 +\hgcmd{backout} will drop you into a text editor to write a commit 86.242 +message, so you can record why you're backing the change out. In this 86.243 +example, we provide a commit message on the command line using the 86.244 +\hgopt{backout}{-m} option. 86.245 + 86.246 +\subsection{Backing out the tip changeset} 86.247 + 86.248 +We're going to start by backing out the last changeset we committed. 86.249 +\interaction{backout.simple} 86.250 +You can see that the second line from \filename{myfile} is no longer 86.251 +present. Taking a look at the output of \hgcmd{log} gives us an idea 86.252 +of what the \hgcmd{backout} command has done. 86.253 +\interaction{backout.simple.log} 86.254 +Notice that the new changeset that \hgcmd{backout} has created is a 86.255 +child of the changeset we backed out. It's easier to see this in 86.256 +figure~\ref{fig:undo:backout}, which presents a graphical view of the 86.257 +change history. As you can see, the history is nice and linear. 86.258 + 86.259 +\begin{figure}[htb] 86.260 + \centering 86.261 + \grafix{undo-simple} 86.262 + \caption{Backing out a change using the \hgcmd{backout} command} 86.263 + \label{fig:undo:backout} 86.264 +\end{figure} 86.265 + 86.266 +\subsection{Backing out a non-tip change} 86.267 + 86.268 +If you want to back out a change other than the last one you 86.269 +committed, pass the \hgopt{backout}{--merge} option to the 86.270 +\hgcmd{backout} command. 86.271 +\interaction{backout.non-tip.clone} 86.272 +This makes backing out any changeset a ``one-shot'' operation that's 86.273 +usually simple and fast. 86.274 +\interaction{backout.non-tip.backout} 86.275 + 86.276 +If you take a look at the contents of \filename{myfile} after the 86.277 +backout finishes, you'll see that the first and third changes are 86.278 +present, but not the second. 86.279 +\interaction{backout.non-tip.cat} 86.280 + 86.281 +As the graphical history in figure~\ref{fig:undo:backout-non-tip} 86.282 +illustrates, Mercurial actually commits \emph{two} changes in this 86.283 +kind of situation (the box-shaped nodes are the ones that Mercurial 86.284 +commits automatically). Before Mercurial begins the backout process, 86.285 +it first remembers what the current parent of the working directory 86.286 +is. It then backs out the target changeset, and commits that as a 86.287 +changeset. Finally, it merges back to the previous parent of the 86.288 +working directory, and commits the result of the merge. 86.289 + 86.290 +% TODO: to me it looks like mercurial doesn't commit the second merge automatically! 86.291 + 86.292 +\begin{figure}[htb] 86.293 + \centering 86.294 + \grafix{undo-non-tip} 86.295 + \caption{Automated backout of a non-tip change using the \hgcmd{backout} command} 86.296 + \label{fig:undo:backout-non-tip} 86.297 +\end{figure} 86.298 + 86.299 +The result is that you end up ``back where you were'', only with some 86.300 +extra history that undoes the effect of the changeset you wanted to 86.301 +back out. 86.302 + 86.303 +\subsubsection{Always use the \hgopt{backout}{--merge} option} 86.304 + 86.305 +In fact, since the \hgopt{backout}{--merge} option will do the ``right 86.306 +thing'' whether or not the changeset you're backing out is the tip 86.307 +(i.e.~it won't try to merge if it's backing out the tip, since there's 86.308 +no need), you should \emph{always} use this option when you run the 86.309 +\hgcmd{backout} command. 86.310 + 86.311 +\subsection{Gaining more control of the backout process} 86.312 + 86.313 +While I've recommended that you always use the 86.314 +\hgopt{backout}{--merge} option when backing out a change, the 86.315 +\hgcmd{backout} command lets you decide how to merge a backout 86.316 +changeset. Taking control of the backout process by hand is something 86.317 +you will rarely need to do, but it can be useful to understand what 86.318 +the \hgcmd{backout} command is doing for you automatically. To 86.319 +illustrate this, let's clone our first repository, but omit the 86.320 +backout change that it contains. 86.321 + 86.322 +\interaction{backout.manual.clone} 86.323 +As with our earlier example, We'll commit a third changeset, then back 86.324 +out its parent, and see what happens. 86.325 +\interaction{backout.manual.backout} 86.326 +Our new changeset is again a descendant of the changeset we backout 86.327 +out; it's thus a new head, \emph{not} a descendant of the changeset 86.328 +that was the tip. The \hgcmd{backout} command was quite explicit in 86.329 +telling us this. 86.330 +\interaction{backout.manual.log} 86.331 + 86.332 +Again, it's easier to see what has happened by looking at a graph of 86.333 +the revision history, in figure~\ref{fig:undo:backout-manual}. This 86.334 +makes it clear that when we use \hgcmd{backout} to back out a change 86.335 +other than the tip, Mercurial adds a new head to the repository (the 86.336 +change it committed is box-shaped). 86.337 + 86.338 +\begin{figure}[htb] 86.339 + \centering 86.340 + \grafix{undo-manual} 86.341 + \caption{Backing out a change using the \hgcmd{backout} command} 86.342 + \label{fig:undo:backout-manual} 86.343 +\end{figure} 86.344 + 86.345 +After the \hgcmd{backout} command has completed, it leaves the new 86.346 +``backout'' changeset as the parent of the working directory. 86.347 +\interaction{backout.manual.parents} 86.348 +Now we have two isolated sets of changes. 86.349 +\interaction{backout.manual.heads} 86.350 + 86.351 +Let's think about what we expect to see as the contents of 86.352 +\filename{myfile} now. The first change should be present, because 86.353 +we've never backed it out. The second change should be missing, as 86.354 +that's the change we backed out. Since the history graph shows the 86.355 +third change as a separate head, we \emph{don't} expect to see the 86.356 +third change present in \filename{myfile}. 86.357 +\interaction{backout.manual.cat} 86.358 +To get the third change back into the file, we just do a normal merge 86.359 +of our two heads. 86.360 +\interaction{backout.manual.merge} 86.361 +Afterwards, the graphical history of our repository looks like 86.362 +figure~\ref{fig:undo:backout-manual-merge}. 86.363 + 86.364 +\begin{figure}[htb] 86.365 + \centering 86.366 + \grafix{undo-manual-merge} 86.367 + \caption{Manually merging a backout change} 86.368 + \label{fig:undo:backout-manual-merge} 86.369 +\end{figure} 86.370 + 86.371 +\subsection{Why \hgcmd{backout} works as it does} 86.372 + 86.373 +Here's a brief description of how the \hgcmd{backout} command works. 86.374 +\begin{enumerate} 86.375 +\item It ensures that the working directory is ``clean'', i.e.~that 86.376 + the output of \hgcmd{status} would be empty. 86.377 +\item It remembers the current parent of the working directory. Let's 86.378 + call this changeset \texttt{orig} 86.379 +\item It does the equivalent of a \hgcmd{update} to sync the working 86.380 + directory to the changeset you want to back out. Let's call this 86.381 + changeset \texttt{backout} 86.382 +\item It finds the parent of that changeset. Let's call that 86.383 + changeset \texttt{parent}. 86.384 +\item For each file that the \texttt{backout} changeset affected, it 86.385 + does the equivalent of a \hgcmdargs{revert}{-r parent} on that file, 86.386 + to restore it to the contents it had before that changeset was 86.387 + committed. 86.388 +\item It commits the result as a new changeset. This changeset has 86.389 + \texttt{backout} as its parent. 86.390 +\item If you specify \hgopt{backout}{--merge} on the command line, it 86.391 + merges with \texttt{orig}, and commits the result of the merge. 86.392 +\end{enumerate} 86.393 + 86.394 +An alternative way to implement the \hgcmd{backout} command would be 86.395 +to \hgcmd{export} the to-be-backed-out changeset as a diff, then use 86.396 +the \cmdopt{patch}{--reverse} option to the \command{patch} command to 86.397 +reverse the effect of the change without fiddling with the working 86.398 +directory. This sounds much simpler, but it would not work nearly as 86.399 +well. 86.400 + 86.401 +The reason that \hgcmd{backout} does an update, a commit, a merge, and 86.402 +another commit is to give the merge machinery the best chance to do a 86.403 +good job when dealing with all the changes \emph{between} the change 86.404 +you're backing out and the current tip. 86.405 + 86.406 +If you're backing out a changeset that's~100 revisions back in your 86.407 +project's history, the chances that the \command{patch} command will 86.408 +be able to apply a reverse diff cleanly are not good, because 86.409 +intervening changes are likely to have ``broken the context'' that 86.410 +\command{patch} uses to determine whether it can apply a patch (if 86.411 +this sounds like gibberish, see \ref{sec:mq:patch} for a 86.412 +discussion of the \command{patch} command). Also, Mercurial's merge 86.413 +machinery will handle files and directories being renamed, permission 86.414 +changes, and modifications to binary files, none of which 86.415 +\command{patch} can deal with. 86.416 + 86.417 +\section{Changes that should never have been} 86.418 +\label{sec:undo:aaaiiieee} 86.419 + 86.420 +Most of the time, the \hgcmd{backout} command is exactly what you need 86.421 +if you want to undo the effects of a change. It leaves a permanent 86.422 +record of exactly what you did, both when committing the original 86.423 +changeset and when you cleaned up after it. 86.424 + 86.425 +On rare occasions, though, you may find that you've committed a change 86.426 +that really should not be present in the repository at all. For 86.427 +example, it would be very unusual, and usually considered a mistake, 86.428 +to commit a software project's object files as well as its source 86.429 +files. Object files have almost no intrinsic value, and they're 86.430 +\emph{big}, so they increase the size of the repository and the amount 86.431 +of time it takes to clone or pull changes. 86.432 + 86.433 +Before I discuss the options that you have if you commit a ``brown 86.434 +paper bag'' change (the kind that's so bad that you want to pull a 86.435 +brown paper bag over your head), let me first discuss some approaches 86.436 +that probably won't work. 86.437 + 86.438 +Since Mercurial treats history as accumulative---every change builds 86.439 +on top of all changes that preceded it---you generally can't just make 86.440 +disastrous changes disappear. The one exception is when you've just 86.441 +committed a change, and it hasn't been pushed or pulled into another 86.442 +repository. That's when you can safely use the \hgcmd{rollback} 86.443 +command, as I detailed in section~\ref{sec:undo:rollback}. 86.444 + 86.445 +After you've pushed a bad change to another repository, you 86.446 +\emph{could} still use \hgcmd{rollback} to make your local copy of the 86.447 +change disappear, but it won't have the consequences you want. The 86.448 +change will still be present in the remote repository, so it will 86.449 +reappear in your local repository the next time you pull. 86.450 + 86.451 +If a situation like this arises, and you know which repositories your 86.452 +bad change has propagated into, you can \emph{try} to get rid of the 86.453 +changeefrom \emph{every} one of those repositories. This is, of 86.454 +course, not a satisfactory solution: if you miss even a single 86.455 +repository while you're expunging, the change is still ``in the 86.456 +wild'', and could propagate further. 86.457 + 86.458 +If you've committed one or more changes \emph{after} the change that 86.459 +you'd like to see disappear, your options are further reduced. 86.460 +Mercurial doesn't provide a way to ``punch a hole'' in history, 86.461 +leaving changesets intact. 86.462 + 86.463 +XXX This needs filling out. The \texttt{hg-replay} script in the 86.464 +\texttt{examples} directory works, but doesn't handle merge 86.465 +changesets. Kind of an important omission. 86.466 + 86.467 +\subsection{Protect yourself from ``escaped'' changes} 86.468 + 86.469 +If you've committed some changes to your local repository and they've 86.470 +been pushed or pulled somewhere else, this isn't necessarily a 86.471 +disaster. You can protect yourself ahead of time against some classes 86.472 +of bad changeset. This is particularly easy if your team usually 86.473 +pulls changes from a central repository. 86.474 + 86.475 +By configuring some hooks on that repository to validate incoming 86.476 +changesets (see chapter~\ref{chap:hook}), you can automatically 86.477 +prevent some kinds of bad changeset from being pushed to the central 86.478 +repository at all. With such a configuration in place, some kinds of 86.479 +bad changeset will naturally tend to ``die out'' because they can't 86.480 +propagate into the central repository. Better yet, this happens 86.481 +without any need for explicit intervention. 86.482 + 86.483 +For instance, an incoming change hook that verifies that a changeset 86.484 +will actually compile can prevent people from inadvertantly ``breaking 86.485 +the build''. 86.486 + 86.487 +\section{Finding the source of a bug} 86.488 +\label{sec:undo:bisect} 86.489 + 86.490 +While it's all very well to be able to back out a changeset that 86.491 +introduced a bug, this requires that you know which changeset to back 86.492 +out. Mercurial provides an invaluable command, called 86.493 +\hgcmd{bisect}, that helps you to automate this process and accomplish 86.494 +it very efficiently. 86.495 + 86.496 +The idea behind the \hgcmd{bisect} command is that a changeset has 86.497 +introduced some change of behaviour that you can identify with a 86.498 +simple binary test. You don't know which piece of code introduced the 86.499 +change, but you know how to test for the presence of the bug. The 86.500 +\hgcmd{bisect} command uses your test to direct its search for the 86.501 +changeset that introduced the code that caused the bug. 86.502 + 86.503 +Here are a few scenarios to help you understand how you might apply 86.504 +this command. 86.505 +\begin{itemize} 86.506 +\item The most recent version of your software has a bug that you 86.507 + remember wasn't present a few weeks ago, but you don't know when it 86.508 + was introduced. Here, your binary test checks for the presence of 86.509 + that bug. 86.510 +\item You fixed a bug in a rush, and now it's time to close the entry 86.511 + in your team's bug database. The bug database requires a changeset 86.512 + ID when you close an entry, but you don't remember which changeset 86.513 + you fixed the bug in. Once again, your binary test checks for the 86.514 + presence of the bug. 86.515 +\item Your software works correctly, but runs~15\% slower than the 86.516 + last time you measured it. You want to know which changeset 86.517 + introduced the performance regression. In this case, your binary 86.518 + test measures the performance of your software, to see whether it's 86.519 + ``fast'' or ``slow''. 86.520 +\item The sizes of the components of your project that you ship 86.521 + exploded recently, and you suspect that something changed in the way 86.522 + you build your project. 86.523 +\end{itemize} 86.524 + 86.525 +From these examples, it should be clear that the \hgcmd{bisect} 86.526 +command is not useful only for finding the sources of bugs. You can 86.527 +use it to find any ``emergent property'' of a repository (anything 86.528 +that you can't find from a simple text search of the files in the 86.529 +tree) for which you can write a binary test. 86.530 + 86.531 +We'll introduce a little bit of terminology here, just to make it 86.532 +clear which parts of the search process are your responsibility, and 86.533 +which are Mercurial's. A \emph{test} is something that \emph{you} run 86.534 +when \hgcmd{bisect} chooses a changeset. A \emph{probe} is what 86.535 +\hgcmd{bisect} runs to tell whether a revision is good. Finally, 86.536 +we'll use the word ``bisect'', as both a noun and a verb, to stand in 86.537 +for the phrase ``search using the \hgcmd{bisect} command. 86.538 + 86.539 +One simple way to automate the searching process would be simply to 86.540 +probe every changeset. However, this scales poorly. If it took ten 86.541 +minutes to test a single changeset, and you had 10,000 changesets in 86.542 +your repository, the exhaustive approach would take on average~35 86.543 +\emph{days} to find the changeset that introduced a bug. Even if you 86.544 +knew that the bug was introduced by one of the last 500 changesets, 86.545 +and limited your search to those, you'd still be looking at over 40 86.546 +hours to find the changeset that introduced your bug. 86.547 + 86.548 +What the \hgcmd{bisect} command does is use its knowledge of the 86.549 +``shape'' of your project's revision history to perform a search in 86.550 +time proportional to the \emph{logarithm} of the number of changesets 86.551 +to check (the kind of search it performs is called a dichotomic 86.552 +search). With this approach, searching through 10,000 changesets will 86.553 +take less than three hours, even at ten minutes per test (the search 86.554 +will require about 14 tests). Limit your search to the last hundred 86.555 +changesets, and it will take only about an hour (roughly seven tests). 86.556 + 86.557 +The \hgcmd{bisect} command is aware of the ``branchy'' nature of a 86.558 +Mercurial project's revision history, so it has no problems dealing 86.559 +with branches, merges, or multiple heads in a repository. It can 86.560 +prune entire branches of history with a single probe, which is how it 86.561 +operates so efficiently. 86.562 + 86.563 +\subsection{Using the \hgcmd{bisect} command} 86.564 + 86.565 +Here's an example of \hgcmd{bisect} in action. 86.566 + 86.567 +\begin{note} 86.568 + In versions 0.9.5 and earlier of Mercurial, \hgcmd{bisect} was not a 86.569 + core command: it was distributed with Mercurial as an extension. 86.570 + This section describes the built-in command, not the old extension. 86.571 +\end{note} 86.572 + 86.573 +Now let's create a repository, so that we can try out the 86.574 +\hgcmd{bisect} command in isolation. 86.575 +\interaction{bisect.init} 86.576 +We'll simulate a project that has a bug in it in a simple-minded way: 86.577 +create trivial changes in a loop, and nominate one specific change 86.578 +that will have the ``bug''. This loop creates 35 changesets, each 86.579 +adding a single file to the repository. We'll represent our ``bug'' 86.580 +with a file that contains the text ``i have a gub''. 86.581 +\interaction{bisect.commits} 86.582 + 86.583 +The next thing that we'd like to do is figure out how to use the 86.584 +\hgcmd{bisect} command. We can use Mercurial's normal built-in help 86.585 +mechanism for this. 86.586 +\interaction{bisect.help} 86.587 + 86.588 +The \hgcmd{bisect} command works in steps. Each step proceeds as follows. 86.589 +\begin{enumerate} 86.590 +\item You run your binary test. 86.591 + \begin{itemize} 86.592 + \item If the test succeeded, you tell \hgcmd{bisect} by running the 86.593 + \hgcmdargs{bisect}{good} command. 86.594 + \item If it failed, run the \hgcmdargs{bisect}{--bad} command. 86.595 + \end{itemize} 86.596 +\item The command uses your information to decide which changeset to 86.597 + test next. 86.598 +\item It updates the working directory to that changeset, and the 86.599 + process begins again. 86.600 +\end{enumerate} 86.601 +The process ends when \hgcmd{bisect} identifies a unique changeset 86.602 +that marks the point where your test transitioned from ``succeeding'' 86.603 +to ``failing''. 86.604 + 86.605 +To start the search, we must run the \hgcmdargs{bisect}{--reset} command. 86.606 +\interaction{bisect.search.init} 86.607 + 86.608 +In our case, the binary test we use is simple: we check to see if any 86.609 +file in the repository contains the string ``i have a gub''. If it 86.610 +does, this changeset contains the change that ``caused the bug''. By 86.611 +convention, a changeset that has the property we're searching for is 86.612 +``bad'', while one that doesn't is ``good''. 86.613 + 86.614 +Most of the time, the revision to which the working directory is 86.615 +synced (usually the tip) already exhibits the problem introduced by 86.616 +the buggy change, so we'll mark it as ``bad''. 86.617 +\interaction{bisect.search.bad-init} 86.618 + 86.619 +Our next task is to nominate a changeset that we know \emph{doesn't} 86.620 +have the bug; the \hgcmd{bisect} command will ``bracket'' its search 86.621 +between the first pair of good and bad changesets. In our case, we 86.622 +know that revision~10 didn't have the bug. (I'll have more words 86.623 +about choosing the first ``good'' changeset later.) 86.624 +\interaction{bisect.search.good-init} 86.625 + 86.626 +Notice that this command printed some output. 86.627 +\begin{itemize} 86.628 +\item It told us how many changesets it must consider before it can 86.629 + identify the one that introduced the bug, and how many tests that 86.630 + will require. 86.631 +\item It updated the working directory to the next changeset to test, 86.632 + and told us which changeset it's testing. 86.633 +\end{itemize} 86.634 + 86.635 +We now run our test in the working directory. We use the 86.636 +\command{grep} command to see if our ``bad'' file is present in the 86.637 +working directory. If it is, this revision is bad; if not, this 86.638 +revision is good. 86.639 +\interaction{bisect.search.step1} 86.640 + 86.641 +This test looks like a perfect candidate for automation, so let's turn 86.642 +it into a shell function. 86.643 +\interaction{bisect.search.mytest} 86.644 +We can now run an entire test step with a single command, 86.645 +\texttt{mytest}. 86.646 +\interaction{bisect.search.step2} 86.647 +A few more invocations of our canned test step command, and we're 86.648 +done. 86.649 +\interaction{bisect.search.rest} 86.650 + 86.651 +Even though we had~40 changesets to search through, the \hgcmd{bisect} 86.652 +command let us find the changeset that introduced our ``bug'' with 86.653 +only five tests. Because the number of tests that the \hgcmd{bisect} 86.654 +command performs grows logarithmically with the number of changesets to 86.655 +search, the advantage that it has over the ``brute force'' search 86.656 +approach increases with every changeset you add. 86.657 + 86.658 +\subsection{Cleaning up after your search} 86.659 + 86.660 +When you're finished using the \hgcmd{bisect} command in a 86.661 +repository, you can use the \hgcmdargs{bisect}{reset} command to drop 86.662 +the information it was using to drive your search. The command 86.663 +doesn't use much space, so it doesn't matter if you forget to run this 86.664 +command. However, \hgcmd{bisect} won't let you start a new search in 86.665 +that repository until you do a \hgcmdargs{bisect}{reset}. 86.666 +\interaction{bisect.search.reset} 86.667 + 86.668 +\section{Tips for finding bugs effectively} 86.669 + 86.670 +\subsection{Give consistent input} 86.671 + 86.672 +The \hgcmd{bisect} command requires that you correctly report the 86.673 +result of every test you perform. If you tell it that a test failed 86.674 +when it really succeeded, it \emph{might} be able to detect the 86.675 +inconsistency. If it can identify an inconsistency in your reports, 86.676 +it will tell you that a particular changeset is both good and bad. 86.677 +However, it can't do this perfectly; it's about as likely to report 86.678 +the wrong changeset as the source of the bug. 86.679 + 86.680 +\subsection{Automate as much as possible} 86.681 + 86.682 +When I started using the \hgcmd{bisect} command, I tried a few times 86.683 +to run my tests by hand, on the command line. This is an approach 86.684 +that I, at least, am not suited to. After a few tries, I found that I 86.685 +was making enough mistakes that I was having to restart my searches 86.686 +several times before finally getting correct results. 86.687 + 86.688 +My initial problems with driving the \hgcmd{bisect} command by hand 86.689 +occurred even with simple searches on small repositories; if the 86.690 +problem you're looking for is more subtle, or the number of tests that 86.691 +\hgcmd{bisect} must perform increases, the likelihood of operator 86.692 +error ruining the search is much higher. Once I started automating my 86.693 +tests, I had much better results. 86.694 + 86.695 +The key to automated testing is twofold: 86.696 +\begin{itemize} 86.697 +\item always test for the same symptom, and 86.698 +\item always feed consistent input to the \hgcmd{bisect} command. 86.699 +\end{itemize} 86.700 +In my tutorial example above, the \command{grep} command tests for the 86.701 +symptom, and the \texttt{if} statement takes the result of this check 86.702 +and ensures that we always feed the same input to the \hgcmd{bisect} 86.703 +command. The \texttt{mytest} function marries these together in a 86.704 +reproducible way, so that every test is uniform and consistent. 86.705 + 86.706 +\subsection{Check your results} 86.707 + 86.708 +Because the output of a \hgcmd{bisect} search is only as good as the 86.709 +input you give it, don't take the changeset it reports as the 86.710 +absolute truth. A simple way to cross-check its report is to manually 86.711 +run your test at each of the following changesets: 86.712 +\begin{itemize} 86.713 +\item The changeset that it reports as the first bad revision. Your 86.714 + test should still report this as bad. 86.715 +\item The parent of that changeset (either parent, if it's a merge). 86.716 + Your test should report this changeset as good. 86.717 +\item A child of that changeset. Your test should report this 86.718 + changeset as bad. 86.719 +\end{itemize} 86.720 + 86.721 +\subsection{Beware interference between bugs} 86.722 + 86.723 +It's possible that your search for one bug could be disrupted by the 86.724 +presence of another. For example, let's say your software crashes at 86.725 +revision 100, and worked correctly at revision 50. Unknown to you, 86.726 +someone else introduced a different crashing bug at revision 60, and 86.727 +fixed it at revision 80. This could distort your results in one of 86.728 +several ways. 86.729 + 86.730 +It is possible that this other bug completely ``masks'' yours, which 86.731 +is to say that it occurs before your bug has a chance to manifest 86.732 +itself. If you can't avoid that other bug (for example, it prevents 86.733 +your project from building), and so can't tell whether your bug is 86.734 +present in a particular changeset, the \hgcmd{bisect} command cannot 86.735 +help you directly. Instead, you can mark a changeset as untested by 86.736 +running \hgcmdargs{bisect}{--skip}. 86.737 + 86.738 +A different problem could arise if your test for a bug's presence is 86.739 +not specific enough. If you check for ``my program crashes'', then 86.740 +both your crashing bug and an unrelated crashing bug that masks it 86.741 +will look like the same thing, and mislead \hgcmd{bisect}. 86.742 + 86.743 +Another useful situation in which to use \hgcmdargs{bisect}{--skip} is 86.744 +if you can't test a revision because your project was in a broken and 86.745 +hence untestable state at that revision, perhaps because someone 86.746 +checked in a change that prevented the project from building. 86.747 + 86.748 +\subsection{Bracket your search lazily} 86.749 + 86.750 +Choosing the first ``good'' and ``bad'' changesets that will mark the 86.751 +end points of your search is often easy, but it bears a little 86.752 +discussion nevertheless. From the perspective of \hgcmd{bisect}, the 86.753 +``newest'' changeset is conventionally ``bad'', and the older 86.754 +changeset is ``good''. 86.755 + 86.756 +If you're having trouble remembering when a suitable ``good'' change 86.757 +was, so that you can tell \hgcmd{bisect}, you could do worse than 86.758 +testing changesets at random. Just remember to eliminate contenders 86.759 +that can't possibly exhibit the bug (perhaps because the feature with 86.760 +the bug isn't present yet) and those where another problem masks the 86.761 +bug (as I discussed above). 86.762 + 86.763 +Even if you end up ``early'' by thousands of changesets or months of 86.764 +history, you will only add a handful of tests to the total number that 86.765 +\hgcmd{bisect} must perform, thanks to its logarithmic behaviour. 86.766 + 86.767 +%%% Local Variables: 86.768 +%%% mode: latex 86.769 +%%% TeX-master: "00book" 86.770 +%%% End:
87.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 87.2 +++ b/fr/wdir-after-commit.svg Thu Feb 05 12:37:03 2009 +0100 87.3 @@ -0,0 +1,394 @@ 87.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 87.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 87.6 +<svg 87.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 87.8 + xmlns:cc="http://web.resource.org/cc/" 87.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 87.10 + xmlns:svg="http://www.w3.org/2000/svg" 87.11 + xmlns="http://www.w3.org/2000/svg" 87.12 + xmlns:xlink="http://www.w3.org/1999/xlink" 87.13 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 87.14 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 87.15 + width="744.09448819" 87.16 + height="1052.3622047" 87.17 + id="svg5971" 87.18 + sodipodi:version="0.32" 87.19 + inkscape:version="0.44.1" 87.20 + sodipodi:docbase="/home/bos/hg/hgbook/en" 87.21 + sodipodi:docname="wdir-after-commit.svg"> 87.22 + <defs 87.23 + id="defs5973"> 87.24 + <linearGradient 87.25 + inkscape:collect="always" 87.26 + xlink:href="#linearGradient6049" 87.27 + id="linearGradient6445" 87.28 + gradientUnits="userSpaceOnUse" 87.29 + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" 87.30 + x1="333.91171" 87.31 + y1="488.79077" 87.32 + x2="508.94543" 87.33 + y2="263.79077" /> 87.34 + <marker 87.35 + inkscape:stockid="Arrow1Mstart" 87.36 + orient="auto" 87.37 + refY="0.0" 87.38 + refX="0.0" 87.39 + id="Arrow1Mstart" 87.40 + style="overflow:visible"> 87.41 + <path 87.42 + id="path4855" 87.43 + 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 " 87.44 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" 87.45 + transform="scale(0.4) translate(10,0)" /> 87.46 + </marker> 87.47 + <linearGradient 87.48 + id="linearGradient6049"> 87.49 + <stop 87.50 + style="stop-color:#686868;stop-opacity:1;" 87.51 + offset="0" 87.52 + id="stop6051" /> 87.53 + <stop 87.54 + style="stop-color:#f0f0f0;stop-opacity:1;" 87.55 + offset="1" 87.56 + id="stop6053" /> 87.57 + </linearGradient> 87.58 + <marker 87.59 + inkscape:stockid="Arrow1Mend" 87.60 + orient="auto" 87.61 + refY="0.0" 87.62 + refX="0.0" 87.63 + id="Arrow1Mend" 87.64 + style="overflow:visible;"> 87.65 + <path 87.66 + id="path4852" 87.67 + 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 " 87.68 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 87.69 + transform="scale(0.4) rotate(180) translate(10,0)" /> 87.70 + </marker> 87.71 + <linearGradient 87.72 + inkscape:collect="always" 87.73 + xlink:href="#linearGradient6049" 87.74 + id="linearGradient6083" 87.75 + gradientUnits="userSpaceOnUse" 87.76 + gradientTransform="translate(-240.0462,-8.633237e-6)" 87.77 + x1="333.91171" 87.78 + y1="488.79077" 87.79 + x2="508.94543" 87.80 + y2="263.79077" /> 87.81 + <linearGradient 87.82 + inkscape:collect="always" 87.83 + xlink:href="#linearGradient6049" 87.84 + id="linearGradient6142" 87.85 + gradientUnits="userSpaceOnUse" 87.86 + gradientTransform="translate(-42.00893,-30.49544)" 87.87 + x1="333.91171" 87.88 + y1="488.79077" 87.89 + x2="508.94543" 87.90 + y2="263.79077" /> 87.91 + <linearGradient 87.92 + inkscape:collect="always" 87.93 + xlink:href="#linearGradient6049" 87.94 + id="linearGradient6193" 87.95 + gradientUnits="userSpaceOnUse" 87.96 + gradientTransform="translate(-240.0462,-8.633237e-6)" 87.97 + x1="333.91171" 87.98 + y1="488.79077" 87.99 + x2="508.94543" 87.100 + y2="263.79077" /> 87.101 + <linearGradient 87.102 + inkscape:collect="always" 87.103 + xlink:href="#linearGradient6049" 87.104 + id="linearGradient6216" 87.105 + gradientUnits="userSpaceOnUse" 87.106 + gradientTransform="translate(-6.0462,-0.664361)" 87.107 + x1="333.91171" 87.108 + y1="488.79077" 87.109 + x2="508.94543" 87.110 + y2="263.79077" /> 87.111 + <linearGradient 87.112 + inkscape:collect="always" 87.113 + xlink:href="#linearGradient6049" 87.114 + id="linearGradient6232" 87.115 + gradientUnits="userSpaceOnUse" 87.116 + gradientTransform="matrix(1.000474,0,0,0.790947,222.8399,50.85693)" 87.117 + x1="333.91171" 87.118 + y1="488.79077" 87.119 + x2="508.94543" 87.120 + y2="263.79077" /> 87.121 + <linearGradient 87.122 + inkscape:collect="always" 87.123 + xlink:href="#linearGradient6049" 87.124 + id="linearGradient6772" 87.125 + gradientUnits="userSpaceOnUse" 87.126 + gradientTransform="matrix(1.000474,0,0,0.790947,222.8399,50.85693)" 87.127 + x1="333.91171" 87.128 + y1="488.79077" 87.129 + x2="508.94543" 87.130 + y2="263.79077" /> 87.131 + </defs> 87.132 + <sodipodi:namedview 87.133 + id="base" 87.134 + pagecolor="#ffffff" 87.135 + bordercolor="#666666" 87.136 + borderopacity="1.0" 87.137 + gridtolerance="10000" 87.138 + guidetolerance="10" 87.139 + objecttolerance="10" 87.140 + inkscape:pageopacity="0.0" 87.141 + inkscape:pageshadow="2" 87.142 + inkscape:zoom="0.90509668" 87.143 + inkscape:cx="390.0539" 87.144 + inkscape:cy="690.49342" 87.145 + inkscape:document-units="px" 87.146 + inkscape:current-layer="layer1" 87.147 + showguides="true" 87.148 + inkscape:guide-bbox="true" 87.149 + inkscape:window-width="906" 87.150 + inkscape:window-height="620" 87.151 + inkscape:window-x="0" 87.152 + inkscape:window-y="25"> 87.153 + <sodipodi:guide 87.154 + orientation="vertical" 87.155 + position="-1.4285714" 87.156 + id="guide6022" /> 87.157 + </sodipodi:namedview> 87.158 + <metadata 87.159 + id="metadata5976"> 87.160 + <rdf:RDF> 87.161 + <cc:Work 87.162 + rdf:about=""> 87.163 + <dc:format>image/svg+xml</dc:format> 87.164 + <dc:type 87.165 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 87.166 + </cc:Work> 87.167 + </rdf:RDF> 87.168 + </metadata> 87.169 + <g 87.170 + inkscape:label="Layer 1" 87.171 + inkscape:groupmode="layer" 87.172 + id="layer1"> 87.173 + <rect 87.174 + y="245.98355" 87.175 + x="328.23956" 87.176 + height="258.57144" 87.177 + width="174.28572" 87.178 + id="rect6047" 87.179 + style="fill:url(#linearGradient6216);fill-opacity:1;stroke:#686868;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 87.180 + <g 87.181 + id="g6261" 87.182 + transform="translate(234,0)"> 87.183 + <rect 87.184 + y="258.7149" 87.185 + x="114.11369" 87.186 + height="44.537449" 87.187 + width="134.53746" 87.188 + id="rect5983" 87.189 + style="fill:#b1b1b1;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 87.190 + <text 87.191 + id="text5985" 87.192 + y="284.47562" 87.193 + x="138.7962" 87.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" 87.195 + xml:space="preserve"><tspan 87.196 + style="font-family:Courier" 87.197 + y="284.47562" 87.198 + x="138.7962" 87.199 + id="tspan5987" 87.200 + sodipodi:role="line">dfbbb33f3fa3</tspan></text> 87.201 + </g> 87.202 + <rect 87.203 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" 87.204 + id="rect5996" 87.205 + width="134.53746" 87.206 + height="44.537449" 87.207 + x="348.11371" 87.208 + y="320.38159" /> 87.209 + <text 87.210 + xml:space="preserve" 87.211 + 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" 87.212 + x="372.7962" 87.213 + y="346.1423" 87.214 + id="text5998"><tspan 87.215 + sodipodi:role="line" 87.216 + id="tspan6000" 87.217 + x="372.7962" 87.218 + y="346.1423" 87.219 + style="font-family:Courier">e7639888bb2f</tspan></text> 87.220 + <rect 87.221 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" 87.222 + id="rect6004" 87.223 + width="134.53746" 87.224 + height="44.537449" 87.225 + x="348.11371" 87.226 + y="382.04825" /> 87.227 + <text 87.228 + xml:space="preserve" 87.229 + 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" 87.230 + x="370.65421" 87.231 + y="407.80896" 87.232 + id="text6006"><tspan 87.233 + sodipodi:role="line" 87.234 + id="tspan6008" 87.235 + x="370.65421" 87.236 + y="407.80896" 87.237 + style="font-family:Courier">7b064d8bac5e</tspan></text> 87.238 + <path 87.239 + inkscape:connector-type="polyline" 87.240 + id="path6018" 87.241 + d="M 415.38242,303.62646 L 415.38242,320.00744" 87.242 + 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" /> 87.243 + <path 87.244 + inkscape:connection-end="#rect6004" 87.245 + inkscape:connector-type="polyline" 87.246 + id="path6020" 87.247 + d="M 415.38242,365.29315 L 415.38243,381.67412" 87.248 + 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" /> 87.249 + <rect 87.250 + style="fill:#ededed;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 87.251 + id="rect6039" 87.252 + width="134.53746" 87.253 + height="44.537449" 87.254 + x="348.11359" 87.255 + y="443.71487" /> 87.256 + <text 87.257 + xml:space="preserve" 87.258 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 87.259 + x="372.79706" 87.260 + y="469.47556" 87.261 + id="text6041"><tspan 87.262 + sodipodi:role="line" 87.263 + id="tspan6043" 87.264 + x="372.79706" 87.265 + y="469.47556" 87.266 + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> 87.267 + <path 87.268 + inkscape:connection-end="#rect6039" 87.269 + inkscape:connector-type="polyline" 87.270 + id="path6045" 87.271 + d="M 415.38238,426.95981 L 415.38235,443.34087" 87.272 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#686868;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" /> 87.273 + <text 87.274 + xml:space="preserve" 87.275 + 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" 87.276 + x="327.66046" 87.277 + y="231.36218" 87.278 + id="text6102"><tspan 87.279 + sodipodi:role="line" 87.280 + id="tspan6104" 87.281 + x="327.66046" 87.282 + y="231.36218">History in repository</tspan></text> 87.283 + <rect 87.284 + y="245.94225" 87.285 + x="557.28418" 87.286 + height="204.51619" 87.287 + width="174.36833" 87.288 + id="rect6140" 87.289 + style="fill:url(#linearGradient6232);fill-opacity:1;stroke:#686868;stroke-width:0.66539276;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 87.290 + <g 87.291 + id="g6130" 87.292 + transform="translate(262.3254,24.38544)"> 87.293 + <rect 87.294 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" 87.295 + id="rect6106" 87.296 + width="134.53746" 87.297 + height="44.537449" 87.298 + x="314.87415" 87.299 + y="257.95059" /> 87.300 + <text 87.301 + xml:space="preserve" 87.302 + 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" 87.303 + x="339.55664" 87.304 + y="283.7113" 87.305 + id="text6108"><tspan 87.306 + sodipodi:role="line" 87.307 + id="tspan6110" 87.308 + x="339.55664" 87.309 + y="283.7113" 87.310 + style="font-family:Courier">dfbbb33f3fa3</tspan></text> 87.311 + </g> 87.312 + <g 87.313 + id="g6135" 87.314 + transform="translate(263.0396,49.83106)"> 87.315 + <rect 87.316 + inkscape:transform-center-y="102.85714" 87.317 + inkscape:transform-center-x="129.28571" 87.318 + style="fill:#ededed;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 87.319 + id="rect6112" 87.320 + width="134.53746" 87.321 + height="44.537449" 87.322 + x="314.15985" 87.323 + y="326.52203" /> 87.324 + <text 87.325 + inkscape:transform-center-y="102.7311" 87.326 + inkscape:transform-center-x="128.69672" 87.327 + xml:space="preserve" 87.328 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 87.329 + x="338.84335" 87.330 + y="352.28271" 87.331 + id="text6114"><tspan 87.332 + sodipodi:role="line" 87.333 + id="tspan6116" 87.334 + x="338.84335" 87.335 + y="352.28271" 87.336 + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> 87.337 + </g> 87.338 + <text 87.339 + xml:space="preserve" 87.340 + 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" 87.341 + x="576.63208" 87.342 + y="270.479" 87.343 + id="text6118"><tspan 87.344 + sodipodi:role="line" 87.345 + id="tspan6120" 87.346 + x="576.63208" 87.347 + y="270.479">First parent</tspan></text> 87.348 + <text 87.349 + xml:space="preserve" 87.350 + 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" 87.351 + x="576.07544" 87.352 + y="364.49615" 87.353 + id="text6122"><tspan 87.354 + sodipodi:role="line" 87.355 + id="tspan6124" 87.356 + x="576.07544" 87.357 + y="364.49615">Second parent</tspan></text> 87.358 + <text 87.359 + xml:space="preserve" 87.360 + 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" 87.361 + x="556.61743" 87.362 + y="231.36218" 87.363 + id="text6195"><tspan 87.364 + sodipodi:role="line" 87.365 + id="tspan6197" 87.366 + x="556.61743" 87.367 + y="231.36218">Parents of working directory</tspan></text> 87.368 + <path 87.369 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 87.370 + d="M 576.82542,297.63008 L 483.02528,287.95831" 87.371 + id="path6266" 87.372 + inkscape:connector-type="polyline" 87.373 + inkscape:connection-start="#g6130" 87.374 + inkscape:connection-end="#g6261" /> 87.375 + <path 87.376 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 87.377 + d="M 665.12232,418.17579 L 665.12232,418.17579" 87.378 + id="path6270" 87.379 + inkscape:connector-type="polyline" /> 87.380 + <text 87.381 + xml:space="preserve" 87.382 + 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" 87.383 + x="316.86407" 87.384 + y="275.6496" 87.385 + id="text6573"><tspan 87.386 + sodipodi:role="line" 87.387 + id="tspan6575" 87.388 + x="316.86407" 87.389 + y="275.6496" 87.390 + style="text-align:end;text-anchor:end">New</tspan><tspan 87.391 + sodipodi:role="line" 87.392 + x="316.86407" 87.393 + y="290.6496" 87.394 + id="tspan6577" 87.395 + style="text-align:end;text-anchor:end">changeset</tspan></text> 87.396 + </g> 87.397 +</svg>
88.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 88.2 +++ b/fr/wdir-branch.svg Thu Feb 05 12:37:03 2009 +0100 88.3 @@ -0,0 +1,418 @@ 88.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 88.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 88.6 +<svg 88.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 88.8 + xmlns:cc="http://web.resource.org/cc/" 88.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 88.10 + xmlns:svg="http://www.w3.org/2000/svg" 88.11 + xmlns="http://www.w3.org/2000/svg" 88.12 + xmlns:xlink="http://www.w3.org/1999/xlink" 88.13 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 88.14 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 88.15 + width="744.09448819" 88.16 + height="1052.3622047" 88.17 + id="svg5971" 88.18 + sodipodi:version="0.32" 88.19 + inkscape:version="0.44.1" 88.20 + sodipodi:docbase="/home/bos/hg/hgbook/en" 88.21 + sodipodi:docname="wdir-branch.svg"> 88.22 + <defs 88.23 + id="defs5973"> 88.24 + <marker 88.25 + inkscape:stockid="Arrow1Mstart" 88.26 + orient="auto" 88.27 + refY="0.0" 88.28 + refX="0.0" 88.29 + id="Arrow1Mstart" 88.30 + style="overflow:visible"> 88.31 + <path 88.32 + id="path4855" 88.33 + 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 " 88.34 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" 88.35 + transform="scale(0.4) translate(10,0)" /> 88.36 + </marker> 88.37 + <linearGradient 88.38 + id="linearGradient6049"> 88.39 + <stop 88.40 + style="stop-color:#686868;stop-opacity:1;" 88.41 + offset="0" 88.42 + id="stop6051" /> 88.43 + <stop 88.44 + style="stop-color:#f0f0f0;stop-opacity:1;" 88.45 + offset="1" 88.46 + id="stop6053" /> 88.47 + </linearGradient> 88.48 + <marker 88.49 + inkscape:stockid="Arrow1Mend" 88.50 + orient="auto" 88.51 + refY="0.0" 88.52 + refX="0.0" 88.53 + id="Arrow1Mend" 88.54 + style="overflow:visible;"> 88.55 + <path 88.56 + id="path4852" 88.57 + 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 " 88.58 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 88.59 + transform="scale(0.4) rotate(180) translate(10,0)" /> 88.60 + </marker> 88.61 + <linearGradient 88.62 + inkscape:collect="always" 88.63 + xlink:href="#linearGradient6049" 88.64 + id="linearGradient6083" 88.65 + gradientUnits="userSpaceOnUse" 88.66 + gradientTransform="translate(-240.0462,-8.633237e-6)" 88.67 + x1="333.91171" 88.68 + y1="488.79077" 88.69 + x2="508.94543" 88.70 + y2="263.79077" /> 88.71 + <linearGradient 88.72 + inkscape:collect="always" 88.73 + xlink:href="#linearGradient6049" 88.74 + id="linearGradient6142" 88.75 + gradientUnits="userSpaceOnUse" 88.76 + gradientTransform="translate(-42.00893,-30.49544)" 88.77 + x1="333.91171" 88.78 + y1="488.79077" 88.79 + x2="508.94543" 88.80 + y2="263.79077" /> 88.81 + <linearGradient 88.82 + inkscape:collect="always" 88.83 + xlink:href="#linearGradient6049" 88.84 + id="linearGradient6193" 88.85 + gradientUnits="userSpaceOnUse" 88.86 + gradientTransform="translate(-240.0462,-8.633237e-6)" 88.87 + x1="333.91171" 88.88 + y1="488.79077" 88.89 + x2="508.94543" 88.90 + y2="263.79077" /> 88.91 + <linearGradient 88.92 + inkscape:collect="always" 88.93 + xlink:href="#linearGradient6049" 88.94 + id="linearGradient6216" 88.95 + gradientUnits="userSpaceOnUse" 88.96 + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" 88.97 + x1="333.91171" 88.98 + y1="488.79077" 88.99 + x2="508.94543" 88.100 + y2="263.79077" /> 88.101 + <linearGradient 88.102 + inkscape:collect="always" 88.103 + xlink:href="#linearGradient6049" 88.104 + id="linearGradient6232" 88.105 + gradientUnits="userSpaceOnUse" 88.106 + gradientTransform="matrix(1.000473,0,0,0.790947,-11.16012,50.85693)" 88.107 + x1="333.91171" 88.108 + y1="488.79077" 88.109 + x2="508.94543" 88.110 + y2="263.79077" /> 88.111 + <linearGradient 88.112 + inkscape:collect="always" 88.113 + xlink:href="#linearGradient6049" 88.114 + id="linearGradient6445" 88.115 + gradientUnits="userSpaceOnUse" 88.116 + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" 88.117 + x1="333.91171" 88.118 + y1="488.79077" 88.119 + x2="508.94543" 88.120 + y2="263.79077" /> 88.121 + <linearGradient 88.122 + inkscape:collect="always" 88.123 + xlink:href="#linearGradient6049" 88.124 + id="linearGradient6974" 88.125 + gradientUnits="userSpaceOnUse" 88.126 + gradientTransform="matrix(1.911882,0,0,0.789965,-574.7896,51.22599)" 88.127 + x1="333.91171" 88.128 + y1="488.79077" 88.129 + x2="508.94543" 88.130 + y2="263.79077" /> 88.131 + <linearGradient 88.132 + inkscape:collect="always" 88.133 + xlink:href="#linearGradient6049" 88.134 + id="linearGradient6996" 88.135 + gradientUnits="userSpaceOnUse" 88.136 + gradientTransform="matrix(1.000473,0,0,0.790947,112.8399,50.85693)" 88.137 + x1="333.91171" 88.138 + y1="488.79077" 88.139 + x2="508.94543" 88.140 + y2="263.79077" /> 88.141 + </defs> 88.142 + <sodipodi:namedview 88.143 + id="base" 88.144 + pagecolor="#ffffff" 88.145 + bordercolor="#666666" 88.146 + borderopacity="1.0" 88.147 + gridtolerance="10000" 88.148 + guidetolerance="10" 88.149 + objecttolerance="10" 88.150 + inkscape:pageopacity="0.0" 88.151 + inkscape:pageshadow="2" 88.152 + inkscape:zoom="0.90509668" 88.153 + inkscape:cx="345.85973" 88.154 + inkscape:cy="690.49342" 88.155 + inkscape:document-units="px" 88.156 + inkscape:current-layer="layer1" 88.157 + showguides="true" 88.158 + inkscape:guide-bbox="true" 88.159 + inkscape:window-width="906" 88.160 + inkscape:window-height="620" 88.161 + inkscape:window-x="0" 88.162 + inkscape:window-y="25"> 88.163 + <sodipodi:guide 88.164 + orientation="vertical" 88.165 + position="-1.4285714" 88.166 + id="guide6022" /> 88.167 + </sodipodi:namedview> 88.168 + <metadata 88.169 + id="metadata5976"> 88.170 + <rdf:RDF> 88.171 + <cc:Work 88.172 + rdf:about=""> 88.173 + <dc:format>image/svg+xml</dc:format> 88.174 + <dc:type 88.175 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 88.176 + </cc:Work> 88.177 + </rdf:RDF> 88.178 + </metadata> 88.179 + <g 88.180 + inkscape:label="Layer 1" 88.181 + inkscape:groupmode="layer" 88.182 + id="layer1"> 88.183 + <rect 88.184 + y="246.06918" 88.185 + x="64.325172" 88.186 + height="204.26233" 88.187 + width="333.2135" 88.188 + id="rect6047" 88.189 + style="fill:url(#linearGradient6974);fill-opacity:1;stroke:#686868;stroke-width:0.91925466;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 88.190 + <g 88.191 + id="g1935"> 88.192 + <rect 88.193 + y="266.24374" 88.194 + x="84.113708" 88.195 + height="44.537449" 88.196 + width="134.53746" 88.197 + id="rect5996" 88.198 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 88.199 + <text 88.200 + id="text5998" 88.201 + y="292.00446" 88.202 + x="108.7962" 88.203 + 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" 88.204 + xml:space="preserve"><tspan 88.205 + style="font-family:Courier" 88.206 + y="292.00446" 88.207 + x="108.7962" 88.208 + id="tspan6000" 88.209 + sodipodi:role="line">e7639888bb2f</tspan></text> 88.210 + </g> 88.211 + <g 88.212 + id="g6976" 88.213 + transform="translate(70,0)"> 88.214 + <rect 88.215 + y="327.9104" 88.216 + x="40.113693" 88.217 + height="44.537449" 88.218 + width="134.53746" 88.219 + id="rect6004" 88.220 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 88.221 + <text 88.222 + id="text6006" 88.223 + y="353.67111" 88.224 + x="62.654205" 88.225 + 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" 88.226 + xml:space="preserve"><tspan 88.227 + style="font-family:Courier" 88.228 + y="353.67111" 88.229 + x="62.654205" 88.230 + id="tspan6008" 88.231 + sodipodi:role="line">7b064d8bac5e</tspan></text> 88.232 + </g> 88.233 + <path 88.234 + inkscape:connector-type="polyline" 88.235 + id="path6020" 88.236 + d="M 160.92915,311.15532 L 167.83571,327.53627" 88.237 + 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;display:inline" 88.238 + inkscape:connection-end="#g6976" 88.239 + inkscape:connection-start="#g1935" /> 88.240 + <rect 88.241 + style="fill:#ededed;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 88.242 + id="rect6039" 88.243 + width="134.53746" 88.244 + height="44.537449" 88.245 + x="110.11359" 88.246 + y="389.57703" /> 88.247 + <text 88.248 + xml:space="preserve" 88.249 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 88.250 + x="134.79706" 88.251 + y="415.33771" 88.252 + id="text6041"><tspan 88.253 + sodipodi:role="line" 88.254 + id="tspan6043" 88.255 + x="134.79706" 88.256 + y="415.33771" 88.257 + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> 88.258 + <path 88.259 + inkscape:connection-end="#rect6039" 88.260 + inkscape:connector-type="polyline" 88.261 + id="path6045" 88.262 + d="M 177.38238,372.82195 L 177.38235,389.20303" 88.263 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#686868;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" /> 88.264 + <rect 88.265 + y="245.94225" 88.266 + x="447.28412" 88.267 + height="204.51619" 88.268 + width="174.36833" 88.269 + id="rect6140" 88.270 + style="fill:url(#linearGradient6996);fill-opacity:1;stroke:#686868;stroke-width:0.66539276;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 88.271 + <g 88.272 + id="g6130" 88.273 + transform="translate(152.3254,24.38544)"> 88.274 + <rect 88.275 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" 88.276 + id="rect6106" 88.277 + width="134.53746" 88.278 + height="44.537449" 88.279 + x="314.87415" 88.280 + y="257.95059" /> 88.281 + <text 88.282 + xml:space="preserve" 88.283 + 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" 88.284 + x="339.55664" 88.285 + y="283.7113" 88.286 + id="text6108"><tspan 88.287 + sodipodi:role="line" 88.288 + id="tspan6110" 88.289 + x="339.55664" 88.290 + y="283.7113" 88.291 + style="font-family:Courier">ffb20e1701ea</tspan></text> 88.292 + </g> 88.293 + <g 88.294 + id="g6135" 88.295 + transform="translate(153.0396,49.83106)"> 88.296 + <rect 88.297 + inkscape:transform-center-y="102.85714" 88.298 + inkscape:transform-center-x="129.28571" 88.299 + style="fill:#ededed;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 88.300 + id="rect6112" 88.301 + width="134.53746" 88.302 + height="44.537449" 88.303 + x="314.15985" 88.304 + y="326.52203" /> 88.305 + <text 88.306 + inkscape:transform-center-y="102.7311" 88.307 + inkscape:transform-center-x="128.69672" 88.308 + xml:space="preserve" 88.309 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 88.310 + x="338.84335" 88.311 + y="352.28271" 88.312 + id="text6114"><tspan 88.313 + sodipodi:role="line" 88.314 + id="tspan6116" 88.315 + x="338.84335" 88.316 + y="352.28271" 88.317 + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> 88.318 + </g> 88.319 + <text 88.320 + xml:space="preserve" 88.321 + 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" 88.322 + x="466.63208" 88.323 + y="270.479" 88.324 + id="text6118"><tspan 88.325 + sodipodi:role="line" 88.326 + id="tspan6120" 88.327 + x="466.63208" 88.328 + y="270.479">First parent</tspan></text> 88.329 + <text 88.330 + xml:space="preserve" 88.331 + 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" 88.332 + x="466.07544" 88.333 + y="364.49615" 88.334 + id="text6122"><tspan 88.335 + sodipodi:role="line" 88.336 + id="tspan6124" 88.337 + x="466.07544" 88.338 + y="364.49615">Second parent</tspan></text> 88.339 + <text 88.340 + xml:space="preserve" 88.341 + 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" 88.342 + x="446.61743" 88.343 + y="231.36218" 88.344 + id="text6195"><tspan 88.345 + sodipodi:role="line" 88.346 + id="tspan6197" 88.347 + x="446.61743" 88.348 + y="231.36218">Parents of working directory</tspan></text> 88.349 + <path 88.350 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" 88.351 + d="M 466.82542,300.21999 L 377.00207,294.39744" 88.352 + id="path6266" 88.353 + inkscape:connector-type="polyline" 88.354 + inkscape:connection-start="#g6130" 88.355 + inkscape:connection-end="#rect1925" /> 88.356 + <path 88.357 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 88.358 + d="M 665.12232,418.17579 L 665.12232,418.17579" 88.359 + id="path6270" 88.360 + inkscape:connector-type="polyline" /> 88.361 + <g 88.362 + id="g2845"> 88.363 + <rect 88.364 + y="266.24374" 88.365 + x="242.09048" 88.366 + height="44.537449" 88.367 + width="134.53746" 88.368 + id="rect1925" 88.369 + style="fill:#9f9f9f;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 88.370 + <text 88.371 + id="text1927" 88.372 + y="292.00446" 88.373 + x="266.77298" 88.374 + 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" 88.375 + xml:space="preserve"><tspan 88.376 + style="font-family:Courier" 88.377 + y="292.00446" 88.378 + x="266.77298" 88.379 + id="tspan1929" 88.380 + sodipodi:role="line">ffb20e1701ea</tspan></text> 88.381 + </g> 88.382 + <path 88.383 + inkscape:connector-type="polyline" 88.384 + id="path1933" 88.385 + d="M 260.89978,311.15532 L 225.84185,327.53627" 88.386 + 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;display:inline" 88.387 + inkscape:connection-end="#g6976" /> 88.388 + <text 88.389 + xml:space="preserve" 88.390 + 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" 88.391 + x="109.45568" 88.392 + y="231.4554" 88.393 + id="text2837"><tspan 88.394 + sodipodi:role="line" 88.395 + id="tspan2839" 88.396 + x="109.45568" 88.397 + y="231.4554">Pre-existing head</tspan></text> 88.398 + <text 88.399 + xml:space="preserve" 88.400 + 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" 88.401 + x="237.54184" 88.402 + y="231.4554" 88.403 + id="text2841"><tspan 88.404 + sodipodi:role="line" 88.405 + id="tspan2843" 88.406 + x="237.54184" 88.407 + y="231.4554">Newly created head (and tip)</tspan></text> 88.408 + <path 88.409 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 88.410 + d="M 148.05048,235.87482 L 149.94915,265.86962" 88.411 + id="path2850" 88.412 + inkscape:connector-type="polyline" 88.413 + inkscape:connection-end="#g1935" /> 88.414 + <path 88.415 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 88.416 + d="M 303.83495,238.08453 L 306.87874,265.86962" 88.417 + id="path2852" 88.418 + inkscape:connector-type="polyline" 88.419 + inkscape:connection-end="#g2845" /> 88.420 + </g> 88.421 +</svg>
89.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 89.2 +++ b/fr/wdir-merge.svg Thu Feb 05 12:37:03 2009 +0100 89.3 @@ -0,0 +1,425 @@ 89.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 89.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 89.6 +<svg 89.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 89.8 + xmlns:cc="http://web.resource.org/cc/" 89.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 89.10 + xmlns:svg="http://www.w3.org/2000/svg" 89.11 + xmlns="http://www.w3.org/2000/svg" 89.12 + xmlns:xlink="http://www.w3.org/1999/xlink" 89.13 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 89.14 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 89.15 + width="744.09448819" 89.16 + height="1052.3622047" 89.17 + id="svg5971" 89.18 + sodipodi:version="0.32" 89.19 + inkscape:version="0.44.1" 89.20 + sodipodi:docbase="/home/bos/hg/hgbook/en" 89.21 + sodipodi:docname="wdir-merge.svg"> 89.22 + <defs 89.23 + id="defs5973"> 89.24 + <marker 89.25 + inkscape:stockid="Arrow1Mstart" 89.26 + orient="auto" 89.27 + refY="0.0" 89.28 + refX="0.0" 89.29 + id="Arrow1Mstart" 89.30 + style="overflow:visible"> 89.31 + <path 89.32 + id="path4855" 89.33 + 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 " 89.34 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" 89.35 + transform="scale(0.4) translate(10,0)" /> 89.36 + </marker> 89.37 + <linearGradient 89.38 + id="linearGradient6049"> 89.39 + <stop 89.40 + style="stop-color:#686868;stop-opacity:1;" 89.41 + offset="0" 89.42 + id="stop6051" /> 89.43 + <stop 89.44 + style="stop-color:#f0f0f0;stop-opacity:1;" 89.45 + offset="1" 89.46 + id="stop6053" /> 89.47 + </linearGradient> 89.48 + <marker 89.49 + inkscape:stockid="Arrow1Mend" 89.50 + orient="auto" 89.51 + refY="0.0" 89.52 + refX="0.0" 89.53 + id="Arrow1Mend" 89.54 + style="overflow:visible;"> 89.55 + <path 89.56 + id="path4852" 89.57 + 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 " 89.58 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 89.59 + transform="scale(0.4) rotate(180) translate(10,0)" /> 89.60 + </marker> 89.61 + <linearGradient 89.62 + inkscape:collect="always" 89.63 + xlink:href="#linearGradient6049" 89.64 + id="linearGradient6083" 89.65 + gradientUnits="userSpaceOnUse" 89.66 + gradientTransform="translate(-240.0462,-8.633237e-6)" 89.67 + x1="333.91171" 89.68 + y1="488.79077" 89.69 + x2="508.94543" 89.70 + y2="263.79077" /> 89.71 + <linearGradient 89.72 + inkscape:collect="always" 89.73 + xlink:href="#linearGradient6049" 89.74 + id="linearGradient6142" 89.75 + gradientUnits="userSpaceOnUse" 89.76 + gradientTransform="translate(-42.00893,-30.49544)" 89.77 + x1="333.91171" 89.78 + y1="488.79077" 89.79 + x2="508.94543" 89.80 + y2="263.79077" /> 89.81 + <linearGradient 89.82 + inkscape:collect="always" 89.83 + xlink:href="#linearGradient6049" 89.84 + id="linearGradient6193" 89.85 + gradientUnits="userSpaceOnUse" 89.86 + gradientTransform="translate(-240.0462,-8.633237e-6)" 89.87 + x1="333.91171" 89.88 + y1="488.79077" 89.89 + x2="508.94543" 89.90 + y2="263.79077" /> 89.91 + <linearGradient 89.92 + inkscape:collect="always" 89.93 + xlink:href="#linearGradient6049" 89.94 + id="linearGradient6216" 89.95 + gradientUnits="userSpaceOnUse" 89.96 + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" 89.97 + x1="333.91171" 89.98 + y1="488.79077" 89.99 + x2="508.94543" 89.100 + y2="263.79077" /> 89.101 + <linearGradient 89.102 + inkscape:collect="always" 89.103 + xlink:href="#linearGradient6049" 89.104 + id="linearGradient6232" 89.105 + gradientUnits="userSpaceOnUse" 89.106 + gradientTransform="matrix(1.000473,0,0,0.790947,-11.16012,50.85693)" 89.107 + x1="333.91171" 89.108 + y1="488.79077" 89.109 + x2="508.94543" 89.110 + y2="263.79077" /> 89.111 + <linearGradient 89.112 + inkscape:collect="always" 89.113 + xlink:href="#linearGradient6049" 89.114 + id="linearGradient6445" 89.115 + gradientUnits="userSpaceOnUse" 89.116 + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" 89.117 + x1="333.91171" 89.118 + y1="488.79077" 89.119 + x2="508.94543" 89.120 + y2="263.79077" /> 89.121 + <linearGradient 89.122 + inkscape:collect="always" 89.123 + xlink:href="#linearGradient6049" 89.124 + id="linearGradient6974" 89.125 + gradientUnits="userSpaceOnUse" 89.126 + gradientTransform="matrix(1.911882,0,0,0.789965,-574.7896,51.22599)" 89.127 + x1="333.91171" 89.128 + y1="488.79077" 89.129 + x2="508.94543" 89.130 + y2="263.79077" /> 89.131 + <linearGradient 89.132 + inkscape:collect="always" 89.133 + xlink:href="#linearGradient6049" 89.134 + id="linearGradient6996" 89.135 + gradientUnits="userSpaceOnUse" 89.136 + gradientTransform="matrix(1.000473,0,0,0.790947,112.8399,50.85693)" 89.137 + x1="333.91171" 89.138 + y1="488.79077" 89.139 + x2="508.94543" 89.140 + y2="263.79077" /> 89.141 + </defs> 89.142 + <sodipodi:namedview 89.143 + id="base" 89.144 + pagecolor="#ffffff" 89.145 + bordercolor="#666666" 89.146 + borderopacity="1.0" 89.147 + gridtolerance="10000" 89.148 + guidetolerance="10" 89.149 + objecttolerance="10" 89.150 + inkscape:pageopacity="0.0" 89.151 + inkscape:pageshadow="2" 89.152 + inkscape:zoom="1.28" 89.153 + inkscape:cx="345.85973" 89.154 + inkscape:cy="690.49342" 89.155 + inkscape:document-units="px" 89.156 + inkscape:current-layer="layer1" 89.157 + showguides="true" 89.158 + inkscape:guide-bbox="true" 89.159 + inkscape:window-width="906" 89.160 + inkscape:window-height="620" 89.161 + inkscape:window-x="0" 89.162 + inkscape:window-y="25"> 89.163 + <sodipodi:guide 89.164 + orientation="vertical" 89.165 + position="-1.4285714" 89.166 + id="guide6022" /> 89.167 + </sodipodi:namedview> 89.168 + <metadata 89.169 + id="metadata5976"> 89.170 + <rdf:RDF> 89.171 + <cc:Work 89.172 + rdf:about=""> 89.173 + <dc:format>image/svg+xml</dc:format> 89.174 + <dc:type 89.175 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 89.176 + </cc:Work> 89.177 + </rdf:RDF> 89.178 + </metadata> 89.179 + <g 89.180 + inkscape:label="Layer 1" 89.181 + inkscape:groupmode="layer" 89.182 + id="layer1"> 89.183 + <rect 89.184 + y="246.06918" 89.185 + x="64.325172" 89.186 + height="204.26233" 89.187 + width="333.2135" 89.188 + id="rect6047" 89.189 + style="fill:url(#linearGradient6974);fill-opacity:1;stroke:#686868;stroke-width:0.91925466;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 89.190 + <g 89.191 + id="g6976" 89.192 + transform="translate(70,0)"> 89.193 + <rect 89.194 + y="327.9104" 89.195 + x="40.113693" 89.196 + height="44.537449" 89.197 + width="134.53746" 89.198 + id="rect6004" 89.199 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 89.200 + <text 89.201 + id="text6006" 89.202 + y="353.67111" 89.203 + x="62.654205" 89.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" 89.205 + xml:space="preserve"><tspan 89.206 + style="font-family:Courier" 89.207 + y="353.67111" 89.208 + x="62.654205" 89.209 + id="tspan6008" 89.210 + sodipodi:role="line">7b064d8bac5e</tspan></text> 89.211 + </g> 89.212 + <path 89.213 + inkscape:connector-type="polyline" 89.214 + id="path6020" 89.215 + d="M 160.92915,311.15532 L 167.83571,327.53627" 89.216 + 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;display:inline" 89.217 + inkscape:connection-end="#g6976" 89.218 + inkscape:connection-start="#g1935" /> 89.219 + <rect 89.220 + style="fill:#ededed;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 89.221 + id="rect6039" 89.222 + width="134.53746" 89.223 + height="44.537449" 89.224 + x="110.11359" 89.225 + y="389.57703" /> 89.226 + <text 89.227 + xml:space="preserve" 89.228 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 89.229 + x="134.79706" 89.230 + y="415.33771" 89.231 + id="text6041"><tspan 89.232 + sodipodi:role="line" 89.233 + id="tspan6043" 89.234 + x="134.79706" 89.235 + y="415.33771" 89.236 + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> 89.237 + <path 89.238 + inkscape:connection-end="#rect6039" 89.239 + inkscape:connector-type="polyline" 89.240 + id="path6045" 89.241 + d="M 177.38238,372.82195 L 177.38235,389.20303" 89.242 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#686868;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" /> 89.243 + <rect 89.244 + y="245.94225" 89.245 + x="447.28412" 89.246 + height="204.51619" 89.247 + width="174.36833" 89.248 + id="rect6140" 89.249 + style="fill:url(#linearGradient6996);fill-opacity:1;stroke:#686868;stroke-width:0.66539276;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 89.250 + <g 89.251 + id="g6130" 89.252 + transform="translate(152.3254,24.38544)"> 89.253 + <rect 89.254 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" 89.255 + id="rect6106" 89.256 + width="134.53746" 89.257 + height="44.537449" 89.258 + x="314.87415" 89.259 + y="257.95059" /> 89.260 + <text 89.261 + xml:space="preserve" 89.262 + 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" 89.263 + x="339.55664" 89.264 + y="283.7113" 89.265 + id="text6108"><tspan 89.266 + sodipodi:role="line" 89.267 + id="tspan6110" 89.268 + x="339.55664" 89.269 + y="283.7113" 89.270 + style="font-family:Courier">ffb20e1701ea</tspan></text> 89.271 + </g> 89.272 + <g 89.273 + id="g6135" 89.274 + transform="translate(153.0396,49.83106)"> 89.275 + <rect 89.276 + inkscape:transform-center-y="102.85714" 89.277 + inkscape:transform-center-x="129.28571" 89.278 + style="fill:#d4d4d4;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 89.279 + id="rect6112" 89.280 + width="134.53746" 89.281 + height="44.537449" 89.282 + x="314.15985" 89.283 + y="326.52203" /> 89.284 + <text 89.285 + inkscape:transform-center-y="102.7311" 89.286 + inkscape:transform-center-x="128.69672" 89.287 + xml:space="preserve" 89.288 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 89.289 + x="338.84335" 89.290 + y="352.28271" 89.291 + id="text6114"><tspan 89.292 + sodipodi:role="line" 89.293 + id="tspan6116" 89.294 + x="338.84335" 89.295 + y="352.28271" 89.296 + style="fill:black;fill-opacity:1;font-family:Courier">e7639888bb2f</tspan></text> 89.297 + </g> 89.298 + <text 89.299 + xml:space="preserve" 89.300 + 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" 89.301 + x="466.63208" 89.302 + y="270.479" 89.303 + id="text6118"><tspan 89.304 + sodipodi:role="line" 89.305 + id="tspan6120" 89.306 + x="466.63208" 89.307 + y="270.479">First parent (unchanged)</tspan></text> 89.308 + <text 89.309 + xml:space="preserve" 89.310 + 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" 89.311 + x="466.07544" 89.312 + y="364.49615" 89.313 + id="text6122"><tspan 89.314 + sodipodi:role="line" 89.315 + id="tspan6124" 89.316 + x="466.07544" 89.317 + y="364.49615">Second parent</tspan></text> 89.318 + <text 89.319 + xml:space="preserve" 89.320 + 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" 89.321 + x="446.61743" 89.322 + y="231.36218" 89.323 + id="text6195"><tspan 89.324 + sodipodi:role="line" 89.325 + id="tspan6197" 89.326 + x="446.61743" 89.327 + y="231.36218">Parents of working directory</tspan></text> 89.328 + <path 89.329 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" 89.330 + d="M 466.82542,300.21999 L 377.00207,294.39744" 89.331 + id="path6266" 89.332 + inkscape:connector-type="polyline" 89.333 + inkscape:connection-start="#g6130" 89.334 + inkscape:connection-end="#rect1925" /> 89.335 + <path 89.336 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 89.337 + d="M 665.12232,418.17579 L 665.12232,418.17579" 89.338 + id="path6270" 89.339 + inkscape:connector-type="polyline" /> 89.340 + <g 89.341 + id="g2845"> 89.342 + <rect 89.343 + y="266.24374" 89.344 + x="242.09048" 89.345 + height="44.537449" 89.346 + width="134.53746" 89.347 + id="rect1925" 89.348 + style="fill:#9f9f9f;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 89.349 + <text 89.350 + id="text1927" 89.351 + y="292.00446" 89.352 + x="266.77298" 89.353 + 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" 89.354 + xml:space="preserve"><tspan 89.355 + style="font-family:Courier" 89.356 + y="292.00446" 89.357 + x="266.77298" 89.358 + id="tspan1929" 89.359 + sodipodi:role="line">ffb20e1701ea</tspan></text> 89.360 + </g> 89.361 + <path 89.362 + inkscape:connector-type="polyline" 89.363 + id="path1933" 89.364 + d="M 260.89978,311.15532 L 225.84185,327.53627" 89.365 + 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;display:inline" 89.366 + inkscape:connection-end="#g6976" /> 89.367 + <text 89.368 + xml:space="preserve" 89.369 + 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" 89.370 + x="109.45568" 89.371 + y="231.4554" 89.372 + id="text2837"><tspan 89.373 + sodipodi:role="line" 89.374 + id="tspan2839" 89.375 + x="109.45568" 89.376 + y="231.4554">Pre-existing head</tspan></text> 89.377 + <text 89.378 + xml:space="preserve" 89.379 + 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" 89.380 + x="237.54184" 89.381 + y="231.4554" 89.382 + id="text2841"><tspan 89.383 + sodipodi:role="line" 89.384 + id="tspan2843" 89.385 + x="237.54184" 89.386 + y="231.4554">Newly created head (and tip)</tspan></text> 89.387 + <path 89.388 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 89.389 + d="M 148.05048,235.87482 L 149.94915,265.86962" 89.390 + id="path2850" 89.391 + inkscape:connector-type="polyline" 89.392 + inkscape:connection-end="#g1935" /> 89.393 + <path 89.394 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)" 89.395 + d="M 303.83495,238.08453 L 306.87874,265.86962" 89.396 + id="path2852" 89.397 + inkscape:connector-type="polyline" 89.398 + inkscape:connection-end="#g2845" /> 89.399 + <path 89.400 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" 89.401 + d="M 466.82545,379.17944 L 219.0253,307.95488" 89.402 + id="path3016" 89.403 + inkscape:connector-type="polyline" 89.404 + inkscape:connection-start="#g6135" 89.405 + inkscape:connection-end="#g1935" /> 89.406 + <g 89.407 + id="g1935"> 89.408 + <rect 89.409 + y="266.24374" 89.410 + x="84.113708" 89.411 + height="44.537449" 89.412 + width="134.53746" 89.413 + id="rect5996" 89.414 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 89.415 + <text 89.416 + id="text5998" 89.417 + y="292.00446" 89.418 + x="108.7962" 89.419 + 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" 89.420 + xml:space="preserve"><tspan 89.421 + style="font-family:Courier" 89.422 + y="292.00446" 89.423 + x="108.7962" 89.424 + id="tspan6000" 89.425 + sodipodi:role="line">e7639888bb2f</tspan></text> 89.426 + </g> 89.427 + </g> 89.428 +</svg>
90.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 90.2 +++ b/fr/wdir-pre-branch.svg Thu Feb 05 12:37:03 2009 +0100 90.3 @@ -0,0 +1,364 @@ 90.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 90.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 90.6 +<svg 90.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 90.8 + xmlns:cc="http://web.resource.org/cc/" 90.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 90.10 + xmlns:svg="http://www.w3.org/2000/svg" 90.11 + xmlns="http://www.w3.org/2000/svg" 90.12 + xmlns:xlink="http://www.w3.org/1999/xlink" 90.13 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 90.14 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 90.15 + width="744.09448819" 90.16 + height="1052.3622047" 90.17 + id="svg5971" 90.18 + sodipodi:version="0.32" 90.19 + inkscape:version="0.44.1" 90.20 + sodipodi:docbase="/home/bos/hg/hgbook/en" 90.21 + sodipodi:docname="wdir-branch.svg"> 90.22 + <defs 90.23 + id="defs5973"> 90.24 + <marker 90.25 + inkscape:stockid="Arrow1Mstart" 90.26 + orient="auto" 90.27 + refY="0.0" 90.28 + refX="0.0" 90.29 + id="Arrow1Mstart" 90.30 + style="overflow:visible"> 90.31 + <path 90.32 + id="path4855" 90.33 + 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 " 90.34 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" 90.35 + transform="scale(0.4) translate(10,0)" /> 90.36 + </marker> 90.37 + <linearGradient 90.38 + id="linearGradient6049"> 90.39 + <stop 90.40 + style="stop-color:#686868;stop-opacity:1;" 90.41 + offset="0" 90.42 + id="stop6051" /> 90.43 + <stop 90.44 + style="stop-color:#f0f0f0;stop-opacity:1;" 90.45 + offset="1" 90.46 + id="stop6053" /> 90.47 + </linearGradient> 90.48 + <marker 90.49 + inkscape:stockid="Arrow1Mend" 90.50 + orient="auto" 90.51 + refY="0.0" 90.52 + refX="0.0" 90.53 + id="Arrow1Mend" 90.54 + style="overflow:visible;"> 90.55 + <path 90.56 + id="path4852" 90.57 + 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 " 90.58 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 90.59 + transform="scale(0.4) rotate(180) translate(10,0)" /> 90.60 + </marker> 90.61 + <linearGradient 90.62 + inkscape:collect="always" 90.63 + xlink:href="#linearGradient6049" 90.64 + id="linearGradient6083" 90.65 + gradientUnits="userSpaceOnUse" 90.66 + gradientTransform="translate(-240.0462,-8.633237e-6)" 90.67 + x1="333.91171" 90.68 + y1="488.79077" 90.69 + x2="508.94543" 90.70 + y2="263.79077" /> 90.71 + <linearGradient 90.72 + inkscape:collect="always" 90.73 + xlink:href="#linearGradient6049" 90.74 + id="linearGradient6142" 90.75 + gradientUnits="userSpaceOnUse" 90.76 + gradientTransform="translate(-42.00893,-30.49544)" 90.77 + x1="333.91171" 90.78 + y1="488.79077" 90.79 + x2="508.94543" 90.80 + y2="263.79077" /> 90.81 + <linearGradient 90.82 + inkscape:collect="always" 90.83 + xlink:href="#linearGradient6049" 90.84 + id="linearGradient6193" 90.85 + gradientUnits="userSpaceOnUse" 90.86 + gradientTransform="translate(-240.0462,-8.633237e-6)" 90.87 + x1="333.91171" 90.88 + y1="488.79077" 90.89 + x2="508.94543" 90.90 + y2="263.79077" /> 90.91 + <linearGradient 90.92 + inkscape:collect="always" 90.93 + xlink:href="#linearGradient6049" 90.94 + id="linearGradient6216" 90.95 + gradientUnits="userSpaceOnUse" 90.96 + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" 90.97 + x1="333.91171" 90.98 + y1="488.79077" 90.99 + x2="508.94543" 90.100 + y2="263.79077" /> 90.101 + <linearGradient 90.102 + inkscape:collect="always" 90.103 + xlink:href="#linearGradient6049" 90.104 + id="linearGradient6232" 90.105 + gradientUnits="userSpaceOnUse" 90.106 + gradientTransform="matrix(1.000473,0,0,0.790947,-11.16012,50.85693)" 90.107 + x1="333.91171" 90.108 + y1="488.79077" 90.109 + x2="508.94543" 90.110 + y2="263.79077" /> 90.111 + <linearGradient 90.112 + inkscape:collect="always" 90.113 + xlink:href="#linearGradient6049" 90.114 + id="linearGradient6445" 90.115 + gradientUnits="userSpaceOnUse" 90.116 + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" 90.117 + x1="333.91171" 90.118 + y1="488.79077" 90.119 + x2="508.94543" 90.120 + y2="263.79077" /> 90.121 + <linearGradient 90.122 + inkscape:collect="always" 90.123 + xlink:href="#linearGradient6049" 90.124 + id="linearGradient6974" 90.125 + gradientUnits="userSpaceOnUse" 90.126 + gradientTransform="matrix(1.000474,0,0,0.790947,-314.246,50.85694)" 90.127 + x1="333.91171" 90.128 + y1="488.79077" 90.129 + x2="508.94543" 90.130 + y2="263.79077" /> 90.131 + <linearGradient 90.132 + inkscape:collect="always" 90.133 + xlink:href="#linearGradient6049" 90.134 + id="linearGradient6996" 90.135 + gradientUnits="userSpaceOnUse" 90.136 + gradientTransform="matrix(1.000473,0,0,0.790947,-85.16012,50.85693)" 90.137 + x1="333.91171" 90.138 + y1="488.79077" 90.139 + x2="508.94543" 90.140 + y2="263.79077" /> 90.141 + </defs> 90.142 + <sodipodi:namedview 90.143 + id="base" 90.144 + pagecolor="#ffffff" 90.145 + bordercolor="#666666" 90.146 + borderopacity="1.0" 90.147 + gridtolerance="10000" 90.148 + guidetolerance="10" 90.149 + objecttolerance="10" 90.150 + inkscape:pageopacity="0.0" 90.151 + inkscape:pageshadow="2" 90.152 + inkscape:zoom="0.90509668" 90.153 + inkscape:cx="390.0539" 90.154 + inkscape:cy="690.49342" 90.155 + inkscape:document-units="px" 90.156 + inkscape:current-layer="layer1" 90.157 + showguides="true" 90.158 + inkscape:guide-bbox="true" 90.159 + inkscape:window-width="906" 90.160 + inkscape:window-height="620" 90.161 + inkscape:window-x="0" 90.162 + inkscape:window-y="25"> 90.163 + <sodipodi:guide 90.164 + orientation="vertical" 90.165 + position="-1.4285714" 90.166 + id="guide6022" /> 90.167 + </sodipodi:namedview> 90.168 + <metadata 90.169 + id="metadata5976"> 90.170 + <rdf:RDF> 90.171 + <cc:Work 90.172 + rdf:about=""> 90.173 + <dc:format>image/svg+xml</dc:format> 90.174 + <dc:type 90.175 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 90.176 + </cc:Work> 90.177 + </rdf:RDF> 90.178 + </metadata> 90.179 + <g 90.180 + inkscape:label="Layer 1" 90.181 + inkscape:groupmode="layer" 90.182 + id="layer1"> 90.183 + <rect 90.184 + y="245.94225" 90.185 + x="20.198257" 90.186 + height="204.51619" 90.187 + width="174.36833" 90.188 + id="rect6047" 90.189 + style="fill:url(#linearGradient6974);fill-opacity:1;stroke:#686868;stroke-width:0.66539276;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 90.190 + <rect 90.191 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" 90.192 + id="rect5996" 90.193 + width="134.53746" 90.194 + height="44.537449" 90.195 + x="40.113693" 90.196 + y="266.24374" /> 90.197 + <text 90.198 + xml:space="preserve" 90.199 + 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" 90.200 + x="64.796204" 90.201 + y="292.00446" 90.202 + id="text5998"><tspan 90.203 + sodipodi:role="line" 90.204 + id="tspan6000" 90.205 + x="64.796204" 90.206 + y="292.00446" 90.207 + style="font-family:Courier">e7639888bb2f</tspan></text> 90.208 + <g 90.209 + id="g6976"> 90.210 + <rect 90.211 + y="327.9104" 90.212 + x="40.113693" 90.213 + height="44.537449" 90.214 + width="134.53746" 90.215 + id="rect6004" 90.216 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 90.217 + <text 90.218 + id="text6006" 90.219 + y="353.67111" 90.220 + x="62.654205" 90.221 + 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" 90.222 + xml:space="preserve"><tspan 90.223 + style="font-family:Courier" 90.224 + y="353.67111" 90.225 + x="62.654205" 90.226 + id="tspan6008" 90.227 + sodipodi:role="line">7b064d8bac5e</tspan></text> 90.228 + </g> 90.229 + <path 90.230 + inkscape:connection-end="#rect6004" 90.231 + inkscape:connector-type="polyline" 90.232 + id="path6020" 90.233 + d="M 107.38242,311.15529 L 107.38242,327.53626" 90.234 + 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" /> 90.235 + <rect 90.236 + style="fill:#ededed;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 90.237 + id="rect6039" 90.238 + width="134.53746" 90.239 + height="44.537449" 90.240 + x="40.113571" 90.241 + y="389.57703" /> 90.242 + <text 90.243 + xml:space="preserve" 90.244 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 90.245 + x="64.797073" 90.246 + y="415.33771" 90.247 + id="text6041"><tspan 90.248 + sodipodi:role="line" 90.249 + id="tspan6043" 90.250 + x="64.797073" 90.251 + y="415.33771" 90.252 + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> 90.253 + <path 90.254 + inkscape:connection-end="#rect6039" 90.255 + inkscape:connector-type="polyline" 90.256 + id="path6045" 90.257 + d="M 107.38238,372.82195 L 107.38235,389.20301" 90.258 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#686868;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" /> 90.259 + <text 90.260 + xml:space="preserve" 90.261 + 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" 90.262 + x="19.660461" 90.263 + y="231.36218" 90.264 + id="text6102"><tspan 90.265 + sodipodi:role="line" 90.266 + id="tspan6104" 90.267 + x="19.660461" 90.268 + y="231.36218">History in repository</tspan></text> 90.269 + <rect 90.270 + y="245.94225" 90.271 + x="249.28412" 90.272 + height="204.51619" 90.273 + width="174.36833" 90.274 + id="rect6140" 90.275 + style="fill:url(#linearGradient6996);fill-opacity:1;stroke:#686868;stroke-width:0.66539276;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 90.276 + <g 90.277 + id="g6130" 90.278 + transform="translate(-45.67459,24.38544)"> 90.279 + <rect 90.280 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" 90.281 + id="rect6106" 90.282 + width="134.53746" 90.283 + height="44.537449" 90.284 + x="314.87415" 90.285 + y="257.95059" /> 90.286 + <text 90.287 + xml:space="preserve" 90.288 + 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" 90.289 + x="339.55664" 90.290 + y="283.7113" 90.291 + id="text6108"><tspan 90.292 + sodipodi:role="line" 90.293 + id="tspan6110" 90.294 + x="339.55664" 90.295 + y="283.7113" 90.296 + style="font-family:Courier">7b064d8bac5e</tspan></text> 90.297 + </g> 90.298 + <g 90.299 + id="g6135" 90.300 + transform="translate(-44.96042,49.83106)"> 90.301 + <rect 90.302 + inkscape:transform-center-y="102.85714" 90.303 + inkscape:transform-center-x="129.28571" 90.304 + style="fill:#ededed;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 90.305 + id="rect6112" 90.306 + width="134.53746" 90.307 + height="44.537449" 90.308 + x="314.15985" 90.309 + y="326.52203" /> 90.310 + <text 90.311 + inkscape:transform-center-y="102.7311" 90.312 + inkscape:transform-center-x="128.69672" 90.313 + xml:space="preserve" 90.314 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 90.315 + x="338.84335" 90.316 + y="352.28271" 90.317 + id="text6114"><tspan 90.318 + sodipodi:role="line" 90.319 + id="tspan6116" 90.320 + x="338.84335" 90.321 + y="352.28271" 90.322 + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> 90.323 + </g> 90.324 + <text 90.325 + xml:space="preserve" 90.326 + 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" 90.327 + x="268.63208" 90.328 + y="270.479" 90.329 + id="text6118"><tspan 90.330 + sodipodi:role="line" 90.331 + id="tspan6120" 90.332 + x="268.63208" 90.333 + y="270.479">First parent</tspan></text> 90.334 + <text 90.335 + xml:space="preserve" 90.336 + 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" 90.337 + x="268.07544" 90.338 + y="364.49615" 90.339 + id="text6122"><tspan 90.340 + sodipodi:role="line" 90.341 + id="tspan6124" 90.342 + x="268.07544" 90.343 + y="364.49615">Second parent</tspan></text> 90.344 + <text 90.345 + xml:space="preserve" 90.346 + 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" 90.347 + x="248.61746" 90.348 + y="231.36218" 90.349 + id="text6195"><tspan 90.350 + sodipodi:role="line" 90.351 + id="tspan6197" 90.352 + x="248.61746" 90.353 + y="231.36218">Parents of working directory</tspan></text> 90.354 + <path 90.355 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" 90.356 + d="M 268.82543,318.06163 L 175.02528,336.72225" 90.357 + id="path6266" 90.358 + inkscape:connector-type="polyline" 90.359 + inkscape:connection-end="#g6976" 90.360 + inkscape:connection-start="#g6130" /> 90.361 + <path 90.362 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 90.363 + d="M 665.12232,418.17579 L 665.12232,418.17579" 90.364 + id="path6270" 90.365 + inkscape:connector-type="polyline" /> 90.366 + </g> 90.367 +</svg>
91.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 91.2 +++ b/fr/wdir.svg Thu Feb 05 12:37:03 2009 +0100 91.3 @@ -0,0 +1,348 @@ 91.4 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 91.5 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 91.6 +<svg 91.7 + xmlns:dc="http://purl.org/dc/elements/1.1/" 91.8 + xmlns:cc="http://web.resource.org/cc/" 91.9 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 91.10 + xmlns:svg="http://www.w3.org/2000/svg" 91.11 + xmlns="http://www.w3.org/2000/svg" 91.12 + xmlns:xlink="http://www.w3.org/1999/xlink" 91.13 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 91.14 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 91.15 + width="744.09448819" 91.16 + height="1052.3622047" 91.17 + id="svg5971" 91.18 + sodipodi:version="0.32" 91.19 + inkscape:version="0.44.1" 91.20 + sodipodi:docbase="/home/bos/hg/hgbook/en" 91.21 + sodipodi:docname="wdir.svg"> 91.22 + <defs 91.23 + id="defs5973"> 91.24 + <marker 91.25 + inkscape:stockid="Arrow1Mstart" 91.26 + orient="auto" 91.27 + refY="0.0" 91.28 + refX="0.0" 91.29 + id="Arrow1Mstart" 91.30 + style="overflow:visible"> 91.31 + <path 91.32 + id="path4855" 91.33 + 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 " 91.34 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" 91.35 + transform="scale(0.4) translate(10,0)" /> 91.36 + </marker> 91.37 + <linearGradient 91.38 + id="linearGradient6049"> 91.39 + <stop 91.40 + style="stop-color:#686868;stop-opacity:1;" 91.41 + offset="0" 91.42 + id="stop6051" /> 91.43 + <stop 91.44 + style="stop-color:#f0f0f0;stop-opacity:1;" 91.45 + offset="1" 91.46 + id="stop6053" /> 91.47 + </linearGradient> 91.48 + <marker 91.49 + inkscape:stockid="Arrow1Mend" 91.50 + orient="auto" 91.51 + refY="0.0" 91.52 + refX="0.0" 91.53 + id="Arrow1Mend" 91.54 + style="overflow:visible;"> 91.55 + <path 91.56 + id="path4852" 91.57 + 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 " 91.58 + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" 91.59 + transform="scale(0.4) rotate(180) translate(10,0)" /> 91.60 + </marker> 91.61 + <linearGradient 91.62 + inkscape:collect="always" 91.63 + xlink:href="#linearGradient6049" 91.64 + id="linearGradient6083" 91.65 + gradientUnits="userSpaceOnUse" 91.66 + gradientTransform="translate(-240.0462,-8.633237e-6)" 91.67 + x1="333.91171" 91.68 + y1="488.79077" 91.69 + x2="508.94543" 91.70 + y2="263.79077" /> 91.71 + <linearGradient 91.72 + inkscape:collect="always" 91.73 + xlink:href="#linearGradient6049" 91.74 + id="linearGradient6142" 91.75 + gradientUnits="userSpaceOnUse" 91.76 + gradientTransform="translate(-42.00893,-30.49544)" 91.77 + x1="333.91171" 91.78 + y1="488.79077" 91.79 + x2="508.94543" 91.80 + y2="263.79077" /> 91.81 + <linearGradient 91.82 + inkscape:collect="always" 91.83 + xlink:href="#linearGradient6049" 91.84 + id="linearGradient6193" 91.85 + gradientUnits="userSpaceOnUse" 91.86 + gradientTransform="translate(-240.0462,-8.633237e-6)" 91.87 + x1="333.91171" 91.88 + y1="488.79077" 91.89 + x2="508.94543" 91.90 + y2="263.79077" /> 91.91 + <linearGradient 91.92 + inkscape:collect="always" 91.93 + xlink:href="#linearGradient6049" 91.94 + id="linearGradient6216" 91.95 + gradientUnits="userSpaceOnUse" 91.96 + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" 91.97 + x1="333.91171" 91.98 + y1="488.79077" 91.99 + x2="508.94543" 91.100 + y2="263.79077" /> 91.101 + <linearGradient 91.102 + inkscape:collect="always" 91.103 + xlink:href="#linearGradient6049" 91.104 + id="linearGradient6232" 91.105 + gradientUnits="userSpaceOnUse" 91.106 + gradientTransform="matrix(1.000473,0,0,0.790947,-11.16012,50.85693)" 91.107 + x1="333.91171" 91.108 + y1="488.79077" 91.109 + x2="508.94543" 91.110 + y2="263.79077" /> 91.111 + <linearGradient 91.112 + inkscape:collect="always" 91.113 + xlink:href="#linearGradient6049" 91.114 + id="linearGradient6445" 91.115 + gradientUnits="userSpaceOnUse" 91.116 + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" 91.117 + x1="333.91171" 91.118 + y1="488.79077" 91.119 + x2="508.94543" 91.120 + y2="263.79077" /> 91.121 + </defs> 91.122 + <sodipodi:namedview 91.123 + id="base" 91.124 + pagecolor="#ffffff" 91.125 + bordercolor="#666666" 91.126 + borderopacity="1.0" 91.127 + gridtolerance="10000" 91.128 + guidetolerance="10" 91.129 + objecttolerance="10" 91.130 + inkscape:pageopacity="0.0" 91.131 + inkscape:pageshadow="2" 91.132 + inkscape:zoom="0.90509668" 91.133 + inkscape:cx="390.0539" 91.134 + inkscape:cy="690.49342" 91.135 + inkscape:document-units="px" 91.136 + inkscape:current-layer="layer1" 91.137 + showguides="true" 91.138 + inkscape:guide-bbox="true" 91.139 + inkscape:window-width="906" 91.140 + inkscape:window-height="620" 91.141 + inkscape:window-x="0" 91.142 + inkscape:window-y="25"> 91.143 + <sodipodi:guide 91.144 + orientation="vertical" 91.145 + position="-1.4285714" 91.146 + id="guide6022" /> 91.147 + </sodipodi:namedview> 91.148 + <metadata 91.149 + id="metadata5976"> 91.150 + <rdf:RDF> 91.151 + <cc:Work 91.152 + rdf:about=""> 91.153 + <dc:format>image/svg+xml</dc:format> 91.154 + <dc:type 91.155 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 91.156 + </cc:Work> 91.157 + </rdf:RDF> 91.158 + </metadata> 91.159 + <g 91.160 + inkscape:label="Layer 1" 91.161 + inkscape:groupmode="layer" 91.162 + id="layer1"> 91.163 + <g 91.164 + id="g6431" 91.165 + transform="translate(0,-0.137863)"> 91.166 + <rect 91.167 + style="fill:url(#linearGradient6445);fill-opacity:1;stroke:#686868;stroke-width:0.66539276;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 91.168 + id="rect6047" 91.169 + width="174.36833" 91.170 + height="204.51619" 91.171 + x="94.198257" 91.172 + y="246.08011" /> 91.173 + <rect 91.174 + y="266.38159" 91.175 + x="114.11369" 91.176 + height="44.537449" 91.177 + width="134.53746" 91.178 + id="rect5996" 91.179 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 91.180 + <text 91.181 + id="text5998" 91.182 + y="292.1423" 91.183 + x="138.7962" 91.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" 91.185 + xml:space="preserve"><tspan 91.186 + style="font-family:Courier" 91.187 + y="292.1423" 91.188 + x="138.7962" 91.189 + id="tspan6000" 91.190 + sodipodi:role="line">e7639888bb2f</tspan></text> 91.191 + <rect 91.192 + y="328.04825" 91.193 + x="114.11369" 91.194 + height="44.537449" 91.195 + width="134.53746" 91.196 + id="rect6004" 91.197 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 91.198 + <text 91.199 + id="text6006" 91.200 + y="353.80896" 91.201 + x="136.65421" 91.202 + 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" 91.203 + xml:space="preserve"><tspan 91.204 + style="font-family:Courier" 91.205 + y="353.80896" 91.206 + x="136.65421" 91.207 + id="tspan6008" 91.208 + sodipodi:role="line">7b064d8bac5e</tspan></text> 91.209 + <path 91.210 + 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" 91.211 + d="M 181.38242,311.29315 L 181.38242,327.67412" 91.212 + id="path6020" 91.213 + inkscape:connector-type="polyline" 91.214 + inkscape:connection-end="#rect6004" /> 91.215 + <rect 91.216 + y="389.71487" 91.217 + x="114.11357" 91.218 + height="44.537449" 91.219 + width="134.53746" 91.220 + id="rect6039" 91.221 + style="fill:#ededed;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 91.222 + <text 91.223 + id="text6041" 91.224 + y="415.47556" 91.225 + x="138.79707" 91.226 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 91.227 + xml:space="preserve"><tspan 91.228 + style="fill:#979797;fill-opacity:1;font-family:Courier" 91.229 + y="415.47556" 91.230 + x="138.79707" 91.231 + id="tspan6043" 91.232 + sodipodi:role="line">000000000000</tspan></text> 91.233 + <path 91.234 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#686868;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-opacity:1" 91.235 + d="M 181.38238,372.95981 L 181.38235,389.34087" 91.236 + id="path6045" 91.237 + inkscape:connector-type="polyline" 91.238 + inkscape:connection-end="#rect6039" /> 91.239 + </g> 91.240 + <text 91.241 + xml:space="preserve" 91.242 + 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" 91.243 + x="93.660484" 91.244 + y="231.36218" 91.245 + id="text6102"><tspan 91.246 + sodipodi:role="line" 91.247 + id="tspan6104" 91.248 + x="93.660484" 91.249 + y="231.36218">History in repository</tspan></text> 91.250 + <g 91.251 + id="g6416"> 91.252 + <rect 91.253 + style="fill:url(#linearGradient6232);fill-opacity:1;stroke:#686868;stroke-width:0.66539276;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 91.254 + id="rect6140" 91.255 + width="174.36833" 91.256 + height="204.51619" 91.257 + x="323.28412" 91.258 + y="245.94225" /> 91.259 + <g 91.260 + transform="translate(28.32541,24.38544)" 91.261 + id="g6130"> 91.262 + <rect 91.263 + y="257.95059" 91.264 + x="314.87415" 91.265 + height="44.537449" 91.266 + width="134.53746" 91.267 + id="rect6106" 91.268 + style="fill:#d4d4d4;fill-opacity:1;stroke:black;stroke-width:0.7482574;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.49651474, 0.74825737;stroke-dashoffset:0;stroke-opacity:1" /> 91.269 + <text 91.270 + id="text6108" 91.271 + y="283.7113" 91.272 + x="339.55664" 91.273 + 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" 91.274 + xml:space="preserve"><tspan 91.275 + style="font-family:Courier" 91.276 + y="283.7113" 91.277 + x="339.55664" 91.278 + id="tspan6110" 91.279 + sodipodi:role="line">e7639888bb2f</tspan></text> 91.280 + </g> 91.281 + <g 91.282 + transform="translate(29.03958,49.83106)" 91.283 + id="g6135"> 91.284 + <rect 91.285 + y="326.52203" 91.286 + x="314.15985" 91.287 + height="44.537449" 91.288 + width="134.53746" 91.289 + id="rect6112" 91.290 + style="fill:#ededed;fill-opacity:1;stroke:#797979;stroke-width:0.74800003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 91.291 + inkscape:transform-center-x="129.28571" 91.292 + inkscape:transform-center-y="102.85714" /> 91.293 + <text 91.294 + id="text6114" 91.295 + y="352.28271" 91.296 + x="338.84335" 91.297 + style="font-size:12px;font-style:normal;font-weight:normal;fill:#979797;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Times New Roman" 91.298 + xml:space="preserve" 91.299 + inkscape:transform-center-x="128.69672" 91.300 + inkscape:transform-center-y="102.7311"><tspan 91.301 + style="fill:#979797;fill-opacity:1;font-family:Courier" 91.302 + y="352.28271" 91.303 + x="338.84335" 91.304 + id="tspan6116" 91.305 + sodipodi:role="line">000000000000</tspan></text> 91.306 + </g> 91.307 + <text 91.308 + id="text6118" 91.309 + y="270.479" 91.310 + x="342.63208" 91.311 + 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" 91.312 + xml:space="preserve"><tspan 91.313 + y="270.479" 91.314 + x="342.63208" 91.315 + id="tspan6120" 91.316 + sodipodi:role="line">First parent</tspan></text> 91.317 + <text 91.318 + id="text6122" 91.319 + y="364.49615" 91.320 + x="342.07544" 91.321 + 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" 91.322 + xml:space="preserve"><tspan 91.323 + y="364.49615" 91.324 + x="342.07544" 91.325 + id="tspan6124" 91.326 + sodipodi:role="line">Second parent</tspan></text> 91.327 + </g> 91.328 + <text 91.329 + xml:space="preserve" 91.330 + 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" 91.331 + x="322.61746" 91.332 + y="231.36218" 91.333 + id="text6195"><tspan 91.334 + sodipodi:role="line" 91.335 + id="tspan6197" 91.336 + x="322.61746" 91.337 + y="231.36218">Parents of working directory</tspan></text> 91.338 + <path 91.339 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" 91.340 + d="M 342.82543,299.89384 L 249.02528,293.36123" 91.341 + id="path6266" 91.342 + inkscape:connector-type="polyline" 91.343 + inkscape:connection-start="#g6130" 91.344 + inkscape:connection-end="#rect5996" /> 91.345 + <path 91.346 + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" 91.347 + d="M 665.12232,418.17579 L 665.12232,418.17579" 91.348 + id="path6270" 91.349 + inkscape:connector-type="polyline" /> 91.350 + </g> 91.351 +</svg>