Mercurial > hgbook
changeset 776:019040fbf5f5
merged to upstream: phase 1
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Tue, 21 Apr 2009 00:36:40 +0900 |
parents | 5981a0f7540a (diff) 29f0f79cf614 (current diff) |
children | 3274ff6650df |
files | en/00book.tex en/99book.bib en/99defs.tex en/Makefile en/bookhtml.cfg en/branch.tex en/cmdref.tex en/collab.tex en/concepts.tex en/daily.tex en/examples/backout.init.out en/examples/backout.manual.backout.out en/examples/backout.manual.cat.out en/examples/backout.manual.clone.out en/examples/backout.manual.heads.out en/examples/backout.manual.log.out en/examples/backout.manual.merge.out en/examples/backout.manual.parents.out en/examples/backout.non-tip.backout.out en/examples/backout.non-tip.cat.out en/examples/backout.non-tip.clone.out en/examples/backout.simple.log.out en/examples/backout.simple.out en/examples/bisect.commits.out en/examples/bisect.help.out en/examples/bisect.init.out en/examples/bisect.search.bad-init.out en/examples/bisect.search.good-init.out en/examples/bisect.search.init.out en/examples/bisect.search.mytest.out en/examples/bisect.search.reset.out en/examples/bisect.search.rest.out en/examples/bisect.search.step1.out en/examples/bisect.search.step2.out en/examples/branch-named.branch.out en/examples/branch-named.branches.out en/examples/branch-named.commit.out en/examples/branch-named.create.out en/examples/branch-named.foo-commit.out en/examples/branch-named.merge.out en/examples/branch-named.parents.out en/examples/branch-named.rebranch.out en/examples/branch-named.status.out en/examples/branch-named.update-bar.out en/examples/branch-named.update-foo.out en/examples/branch-named.update-nothing.out en/examples/branch-named.update-switchy.out en/examples/branch-named.update.out en/examples/branch-repo.bugfix.out en/examples/branch-repo.clone.out en/examples/branch-repo.merge.out en/examples/branch-repo.new.out en/examples/branch-repo.pull.out en/examples/branch-repo.tag.out en/examples/branching.clone.out en/examples/branching.init.out en/examples/branching.main.out en/examples/branching.merge.out en/examples/branching.stable.out en/examples/branching.tag.out en/examples/branching.update.out en/examples/cmdref.diff-p.out en/examples/daily.copy.after.out en/examples/daily.copy.cat.out en/examples/daily.copy.clone.out en/examples/daily.copy.copy.out en/examples/daily.copy.dir-dest.out en/examples/daily.copy.dir-src-dest.out en/examples/daily.copy.dir-src.out en/examples/daily.copy.init.out en/examples/daily.copy.merge.out en/examples/daily.copy.other.out en/examples/daily.copy.simple.out en/examples/daily.copy.status-copy.out en/examples/daily.copy.status.out en/examples/daily.files.add-dir.out en/examples/daily.files.add.out en/examples/daily.files.addremove.out en/examples/daily.files.commit-addremove.out en/examples/daily.files.hidden.out en/examples/daily.files.missing.out en/examples/daily.files.recover-missing.out en/examples/daily.files.remove-after.out en/examples/daily.files.remove.out en/examples/daily.rename.rename.out en/examples/daily.rename.status-copy.out en/examples/daily.rename.status.out en/examples/daily.revert.add.out en/examples/daily.revert.copy.out en/examples/daily.revert.missing.out en/examples/daily.revert.modify.out en/examples/daily.revert.remove.out en/examples/daily.revert.rename-orig.out en/examples/daily.revert.rename.out en/examples/daily.revert.status.out en/examples/daily.revert.unmodify.out en/examples/extdiff.diff.out en/examples/extdiff.extdiff-ctx.out en/examples/extdiff.extdiff.out en/examples/filenames.dirs.out en/examples/filenames.files.out en/examples/filenames.filter.exclude.out en/examples/filenames.filter.include.out en/examples/filenames.glob.group.out en/examples/filenames.glob.question.out en/examples/filenames.glob.range.out en/examples/filenames.glob.star-starstar.out en/examples/filenames.glob.star.out en/examples/filenames.glob.starstar.out en/examples/filenames.wdir-relname.out en/examples/filenames.wdir-subdir.out en/examples/hook.msglen.go.out en/examples/hook.msglen.run.out en/examples/hook.simple.ext.out en/examples/hook.simple.init.out en/examples/hook.simple.pretxncommit.out en/examples/hook.ws.better.out en/examples/hook.ws.simple.out en/examples/issue29.go.out en/examples/mq.dodiff.diff.out en/examples/mq.guards.init.out en/examples/mq.guards.qguard.neg.out en/examples/mq.guards.qguard.out en/examples/mq.guards.qguard.pos.out en/examples/mq.guards.qselect.cat.out en/examples/mq.guards.qselect.error.out en/examples/mq.guards.qselect.foo.out en/examples/mq.guards.qselect.foobar.out en/examples/mq.guards.qselect.qpush.out en/examples/mq.guards.qselect.quux.out en/examples/mq.guards.series.out en/examples/mq.id.out.out en/examples/mq.id.output.out en/examples/mq.qinit-help.help.out en/examples/mq.tarball.download.out en/examples/mq.tarball.newsource.out en/examples/mq.tarball.qinit.out en/examples/mq.tarball.repush.out en/examples/mq.tools.lsdiff.out en/examples/mq.tools.tools.out en/examples/mq.tutorial.add.out en/examples/mq.tutorial.qinit.out en/examples/mq.tutorial.qnew.out en/examples/mq.tutorial.qnew2.out en/examples/mq.tutorial.qpop.out en/examples/mq.tutorial.qpush-a.out en/examples/mq.tutorial.qrefresh.out en/examples/mq.tutorial.qrefresh2.out en/examples/mq.tutorial.qseries.out en/examples/rename.divergent.clone.out en/examples/rename.divergent.merge.out en/examples/rename.divergent.rename.anne.out en/examples/rename.divergent.rename.bob.out en/examples/rollback.add.out en/examples/rollback.commit.out en/examples/rollback.rollback.out en/examples/rollback.status.out en/examples/rollback.tip.out en/examples/rollback.twice.out en/examples/run-example en/examples/tag.init.out en/examples/tag.log.out en/examples/tag.log.v1.0.out en/examples/tag.remove.out en/examples/tag.replace.out en/examples/tag.tag.out en/examples/tag.tags.out en/examples/tag.tip.out en/examples/template.simple.changelog.out en/examples/template.simple.combine.out en/examples/template.simple.compact.out en/examples/template.simple.datekeyword.out en/examples/template.simple.keywords.out en/examples/template.simple.manyfilters.out en/examples/template.simple.normal.out en/examples/template.simple.rev.out en/examples/template.simple.simplest.out en/examples/template.simple.simplesub.out en/examples/template.svnstyle.id.out en/examples/template.svnstyle.result.out en/examples/template.svnstyle.short.out en/examples/template.svnstyle.simplest.out en/examples/template.svnstyle.style.out en/examples/template.svnstyle.syntax.error.out en/examples/template.svnstyle.syntax.input.out en/examples/template.svnstyle.template.out en/examples/tour-merge-conflict.commit.out en/examples/tour-merge-conflict.cousin.out en/examples/tour-merge-conflict.merge.out en/examples/tour-merge-conflict.pull.out en/examples/tour-merge-conflict.son.out en/examples/tour-merge-conflict.wife.out en/examples/tour.clone-pull.out en/examples/tour.clone-push.out en/examples/tour.clone.out en/examples/tour.commit.out en/examples/tour.diff.out en/examples/tour.help.out en/examples/tour.incoming.out en/examples/tour.log-r.out en/examples/tour.log-v.out en/examples/tour.log-vp.out en/examples/tour.log.out en/examples/tour.log.range.out en/examples/tour.ls-a.out en/examples/tour.ls.out en/examples/tour.merge.cat.out en/examples/tour.merge.clone.out en/examples/tour.merge.commit.out en/examples/tour.merge.heads.out en/examples/tour.merge.merge.out en/examples/tour.merge.parents.out en/examples/tour.merge.pull.out en/examples/tour.merge.tip.out en/examples/tour.merge.update.out en/examples/tour.older.out en/examples/tour.outgoing.net.out en/examples/tour.outgoing.out en/examples/tour.parents.out en/examples/tour.pull.out en/examples/tour.push.net.out en/examples/tour.push.nothing.out en/examples/tour.push.out en/examples/tour.reclone.out en/examples/tour.sed.out en/examples/tour.status.out en/examples/tour.tip.out en/examples/tour.update.out en/examples/tour.version.out en/feature-branches.dot en/filelog.svg en/filenames.tex en/fixhtml.py en/hgbook.css en/hgext.tex en/hook.tex en/htlatex.book en/intro.tex en/kdiff3.png en/license.tex en/metadata.svg en/mq-collab.tex en/mq-ref.tex en/mq-stack.svg en/mq.tex en/note.png en/preface.tex en/revlog.svg en/snapshot.svg en/srcinstall.tex en/template.tex en/tour-basic.tex en/tour-history.svg en/tour-merge-conflict.svg en/tour-merge-merge.svg en/tour-merge-pull.svg en/tour-merge-sep-repos.svg en/tour-merge.tex en/undo-manual-merge.dot en/undo-manual.dot en/undo-non-tip.dot en/undo-simple.dot en/undo.tex en/wdir-after-commit.svg en/wdir-branch.svg en/wdir-merge.svg en/wdir-pre-branch.svg en/wdir.svg es/99defs.tex examples/hg-interdiff examples/hg-replay html/hgicon.png html/index.en.html html/index.html.var ja/Makefile ja/Makefile.orig ja/examples/bisect ja/examples/branch-named ja/examples/daily.files ja/examples/rename.divergent ja/examples/run-example ja/examples/template.svnstyle ja/examples/tour ja/examples/tour-merge-conflict sillybench/sillybench.py |
diffstat | 311 files changed, 27462 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgtags Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +b0db5adf11c1e096c4b08f42befb8e7e18120ed0 japanese root +b0db5adf11c1e096c4b08f42befb8e7e18120ed0 ja_root +0000000000000000000000000000000000000000 japanese root
--- a/es/99defs.tex Thu Apr 16 23:46:45 2009 -0700 +++ b/es/99defs.tex Tue Apr 21 00:36:40 2009 +0900 @@ -50,18 +50,18 @@ \newcommand{\cmdargs}[2]{\index{\texttt{#1} comando de sistema}``\texttt{#1 #2}''} % Mercurial command option. -\newcommand{\hgopt}[2]{\index{\texttt{#1}, comando!opción \texttt{#2}}\texttt{#2}} +\newcommand{\hgopt}[2]{\index{\texttt{#1}, comando!opci$BC3(Bn \texttt{#2}}\texttt{#2}} % Mercurial command option, provided by an extension command. -\newcommand{\hgxopt}[3]{\index{\texttt{#2}, comando (extensión -\texttt{#1})!opción \texttt{#3}}\index{\texttt{#1}, extensión!comando -\texttt{#2}!opción\texttt{#3}}\texttt{#3}} +\newcommand{\hgxopt}[3]{\index{\texttt{#2}, comando (extensi$BC3(Bn +\texttt{#1})!opci$BC3(Bn \texttt{#3}}\index{\texttt{#1}, extensi$BC3(Bn!comando +\texttt{#2}!opci$BC3(Bn\texttt{#3}}\texttt{#3}} % Mercurial global option. -\newcommand{\hggopt}[1]{\index{opciones globales!opción \texttt{#1}}\texttt{#1}} +\newcommand{\hggopt}[1]{\index{opciones globales!opci$BC3(Bn \texttt{#1}}\texttt{#1}} % Shell/system command option. -\newcommand{\cmdopt}[2]{\index{\texttt{#1}, comando!opción \texttt{#2}}\texttt{#2}} +\newcommand{\cmdopt}[2]{\index{\texttt{#1}, comando!opci$BC3(Bn \texttt{#2}}\texttt{#2}} % Command option. \newcommand{\option}[1]{\texttt{#1}} @@ -70,19 +70,19 @@ \newcommand{\package}[1]{\index{\texttt{#1}, paquete}\texttt{#1}} % Section name from a hgrc file. -\newcommand{\rcsection}[1]{\index{\texttt{hgrc}, fichero!sección \texttt{#1}}\texttt{[#1]}} +\newcommand{\rcsection}[1]{\index{\texttt{hgrc}, fichero!secci$BC3(Bn \texttt{#1}}\texttt{[#1]}} % Named item in a hgrc file section. -\newcommand{\rcitem}[2]{\index{\texttt{hgrc}, fichero!sección +\newcommand{\rcitem}[2]{\index{\texttt{hgrc}, fichero!secci$BC3(Bn \texttt{#1}!entrada \texttt{#2}}\texttt{#2}} % hgrc file. -\newcommand{\hgrc}{\index{fichero de configuración!\texttt{hgrc} - (Linux/Unix)}\index{\texttt{hgrc}, fichero de configuración}\texttt{hgrc}} +\newcommand{\hgrc}{\index{fichero de configuraci$BC3(Bn!\texttt{hgrc} + (Linux/Unix)}\index{\texttt{hgrc}, fichero de configuraci$BC3(Bn}\texttt{hgrc}} % Mercurial.ini file. -\newcommand{\hgini}{\index{fichero de configuración!\texttt{Mercurial.ini} - (Windows)}\index{\texttt{Mercurial.ini}, fichero de configuración}\texttt{Mercurial.ini}} +\newcommand{\hgini}{\index{fichero de configuraci$BC3(Bn!\texttt{Mercurial.ini} + (Windows)}\index{\texttt{Mercurial.ini}, fichero de configuraci$BC3(Bn}\texttt{Mercurial.ini}} % Hook name. \newcommand{\hook}[1]{\index{\texttt{#1}, gancho}\index{ganchos!\texttt{#1}}\texttt{#1}} @@ -92,13 +92,13 @@ de entorno!\texttt{#1}}\texttt{#1}} % Python module. -\newcommand{\pymod}[1]{\index{\texttt{#1}, módulo}\texttt{#1}} +\newcommand{\pymod}[1]{\index{\texttt{#1}, m$BC3(Bdulo}\texttt{#1}} % Python class in a module. -\newcommand{\pymodclass}[2]{\index{\texttt{#1}, módulo!clase \texttt{#2}}\texttt{#1.#2}} +\newcommand{\pymodclass}[2]{\index{\texttt{#1}, m$BC3(Bdulo!clase \texttt{#2}}\texttt{#1.#2}} % Python function in a module. -\newcommand{\pymodfunc}[2]{\index{\texttt{#1}, módulo!función \texttt{#2}}\texttt{#1.#2}} +\newcommand{\pymodfunc}[2]{\index{\texttt{#1}, m$BC3(Bdulo!funci$BC3(Bn \texttt{#2}}\texttt{#1.#2}} % Note: blah blah. \newsavebox{\notebox} @@ -106,7 +106,7 @@ {\begin{lrbox}{\notebox}\begin{minipage}{0.7\textwidth}\textbf{Nota:}\space}% {\end{minipage}\end{lrbox}\fbox{\usebox{\notebox}}} \newenvironment{caution}% - {\begin{lrbox}{\notebox}\begin{minipage}{0.7\textwidth}\textbf{Precaución:}\space}% + {\begin{lrbox}{\notebox}\begin{minipage}{0.7\textwidth}\textbf{Precauci$BC3(Bn:}\space}% {\end{minipage}\end{lrbox}\fbox{\usebox{\notebox}}} % Code sample, eating 4 characters of leading space. @@ -131,16 +131,16 @@ \newcommand{\cmdref}[2]{\section{\hgcmd{#1}---#2}\label{cmdref:#1}\index{\texttt{#1}, comando}} % Reference entry for a command option with long and short forms. -\newcommand{\optref}[3]{\subsubsection{\hgopt{#1}{--#3}, también \hgopt{#1}{-#2}}} +\newcommand{\optref}[3]{\subsubsection{\hgopt{#1}{--#3}, tambi$BC)(Bn \hgopt{#1}{-#2}}} % Reference entry for a command option with only long form. -\newcommand{\loptref}[2]{\subsubsection{opción \hgopt{#1}{--#2}}} +\newcommand{\loptref}[2]{\subsubsection{opci$BC3(Bn \hgopt{#1}{--#2}}} % command to generate a footnote to be used as a translator's note \newcommand{\ndt}[1]{\footnote{\textbf{N. del T.} #1}} -%%% Local Variables: -%%% mode: latex +%%% Local Variables: +%%% mode: yatex %%% TeX-master: "00book" -%%% End: +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/00book.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,86 @@ +% The use of oneside here is a temporary hack; \marginpar entries +% don't show up on odd pages of PDF output without it. Sigh. +\documentclass[oneside]{book} +\usepackage{enumerate} +\usepackage{fullpage} +\usepackage{makeidx} +\usepackage{ifpdf} +\usepackage{graphicx} +\usepackage{pslatex} +\usepackage{fancyvrb} +% leave hyperref until last +\usepackage[colorlinks=true,bookmarks=true,pdftitle={Distributed + revision control with Mercurial},pdfsubject={Revision + control},pdfkeywords={Mercurial, Revision control, Distributed + revision control},pdfauthor={Bryan O'Sullivan}]{hyperref} + +\include{99defs} + +%\title{Distributed revision control with Mercurial} +\title{Mercurial$B$K$h$kJ,;6%j%S%8%g%s4IM}(B} +\author{Bryan O'Sullivan} +%\date{Copyright \copyright\ 2006, 2007 Bryan O'Sullivan.\\ +% This material may be distributed only subject to the terms and +% conditions set forth in version 1.0 of the Open Publication License. +% Please refer to Appendix~\ref{cha:opl} for the license text.\\ +% This book was prepared from +% \href{http://hg.serpentine.com/mercurial/book/}{rev~\input{build_id}} +% using \href{http://www.selenic.com/hg/}{rev~\input{hg_id}} of Mercurial.} +\date{Copyright \copyright\ 2006, 2007 Bryan O'Sullivan.\\ + $B$3$NJ8=q$O(B Open Publication License $B%P!<%8%g%s(B 1.0 $B$NDj$a$k>r7o(B + $B$K$N$_=>$C$FG[I[$5$l$k!%%i%$%;%s%9$NFbMF$K$D$$$F$OIUO?(B~\ref{cha:opl}$B$r(B + $B;2>H$5$l$?$$!%(B\\ + $B$3$N=q@R$O(BMercurial + \href{http://www.selenic.com/hg/}{rev~\input{hg_id}} + $B$K$h$C$F4IM}$5$l$k(B + \href{http://freehg.org/u/honeyplanet/hgbook/}{rev~\input{build_id}} + $B$+$i@=HG$5$l$?!%(B} + +\makeindex + +\begin{document} + +\maketitle + +\addcontentsline{toc}{chapter}{Contents} +\pagenumbering{roman} +\tableofcontents +\listoffigures +%\listoftables + +\pagenumbering{arabic} + +\include{preface} +\include{intro} +\include{tour-basic} +\include{tour-merge} +\include{concepts} +\include{daily} +\include{collab} +\include{filenames} +\include{branch} +\include{undo} +\include{hook} +\include{template} +\include{mq} +\include{mq-collab} +\include{hgext} + +\appendix +\include{cmdref} +\include{mq-ref} +\include{srcinstall} +\include{license} +\addcontentsline{toc}{chapter}{Bibliography} +\bibliographystyle{alpha} +\bibliography{99book} + +\addcontentsline{toc}{chapter}{Index} +\printindex + +\end{document} + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: t +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/99book.bib Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,76 @@ +@Unpublished{gruenbacher:2005, + author = {Andreas Gruenbacher}, + title = {How To Survive With Many Patches (Introduction to \texttt{quilt})}, + year = {2005}, + month = {June}, + note = {\url{http://www.suse.de/~agruen/quilt.pdf}}, +} + +@InProceedings{web:europython, + author = {Bryan O'Sullivan}, + title = {Achieving High Performance in Mercurial}, + booktitle = {EuroPython Conference}, + year = {2006}, + month = {July}, + note = {\url{XXX}}, +} + +@Misc{web:diffstat, + author = {Thomas Dickey}, + title = {\texttt{diffstat}--make a histogram of \texttt{diff} output}, + note = {\url{http://dickey.his.com/diffstat/diffstat.html}}, +} + +@Misc{web:quilt, + author = {Andreas Gruenbacher, Martin Quinson, Jean Delvare}, + title = {Patchwork Quilt}, + note = {\url{http://savannah.nongnu.org/projects/quilt}}, +} + +@Misc{web:patchutils, + author = {Tim Waugh}, + title = {\texttt{patchutils}--programs that operate on patch files}, + note = {\url{http://cyberelk.net/tim/patchutils/}}, +} + +@Misc{web:mpatch, + author = {Chris Mason}, + title = {\texttt{mpatch}--help solve patch rejects}, + note = {\url{http://oss.oracle.com/~mason/mpatch/}}, +} + +@Misc{web:wiggle, + author = {Neil Brown}, + title = {\texttt{wiggle}--apply conflicting patches}, + note = {\url{http://cgi.cse.unsw.edu.au/~neilb/source/wiggle/}}, +} + +@Misc{web:mysql-python, + author = {Andy Dustman}, + title = {MySQL for Python}, + note = {\url{http://sourceforge.net/projects/mysql-python}}, +} + +@Misc{web:changelog, + author = {Richard Stallman, GNU Project volunteers}, + title = {GNU Coding Standards---Change Logs}, + note = {\url{http://www.gnu.org/prep/standards/html_node/Change-Logs.html}}, +} + +@Misc{web:macpython, + author = {Bob Ippolito, Ronald Oussoren}, + title = {Universal MacPython}, + note = {\url{http://bob.pythonmac.org/archives/2006/04/10/python-and-universal-binaries-on-mac-os-x/}}, +} + +@Misc{web:putty, + author = {Simon Tatham}, + title = {PuTTY---open source ssh client for Windows}, + note = {\url{http://www.chiark.greenend.org.uk/~sgtatham/putty/}}, +} + +@Misc{web:configparser, + author = {Python.org}, + title = {\texttt{ConfigParser}---Configuration file parser}, + note = {\url{http://docs.python.org/lib/module-ConfigParser.html}}, +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/99defs.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,144 @@ +% Bug ID. +%\newcommand{\bug}[1]{\index{Mercurial bug database! +%\href{http://www.selenic.com/mercurial/bts/issue#1}{bug ~#1}}\href{http://www.selenic.com/mercurial/bts/issue#1}{Mercurial bug no.~#1}} + +\newcommand{\bug}[1]{\href{http://www.selenic.com/mercurial/bts/issue#1}{Mercurial bug no.~#1}} + +% File name in the user's home directory. +\newcommand{\tildefile}[1]{\texttt{\~{}/#1}} + +% File name. +\newcommand{\filename}[1]{\texttt{#1}} + +% Directory name. +\newcommand{\dirname}[1]{\texttt{#1}} + +% File name, with index entry. +% The ``s'' prefix comes from ``special''. +\newcommand{\sfilename}[1]{\index{\texttt{#1} file}\texttt{#1}} + +% Directory name, with index entry. +\newcommand{\sdirname}[1]{\index{\texttt{#1} directory}\texttt{#1}} + +% Mercurial extension. +\newcommand{\hgext}[1]{\index{\texttt{#1} extension}\texttt{#1}} + +% Command provided by a Mercurial extension. +\newcommand{\hgxcmd}[2]{\index{\texttt{#2} command (\texttt{#1} + extension)}\index{\texttt{#1} extension!\texttt{#2} command}``\texttt{hg #2}''} + +% Mercurial command. +\newcommand{\hgcmd}[1]{\index{\texttt{#1} command}``\texttt{hg #1}''} + +% Mercurial command, with arguments. +\newcommand{\hgcmdargs}[2]{\index{\texttt{#1} command}``\texttt{hg #1 #2}''} + +\newcommand{\tplkword}[1]{\index{\texttt{#1} template keyword}\index{template keywords!\texttt{#1}}\texttt{#1}} + +\newcommand{\tplkwfilt}[2]{\index{\texttt{#1} template keyword!\texttt{#2} + filter}\index{template filters!\texttt{#2}}\index{\texttt{#2} + template filter}\texttt{#2}} + +\newcommand{\tplfilter}[1]{\index{template + filters!\texttt{#1}}\index{\texttt{#1} template + filter}\texttt{#1}} + +% Shell/system command. +\newcommand{\command}[1]{\index{\texttt{#1} system command}\texttt{#1}} + +% Shell/system command, with arguments. +\newcommand{\cmdargs}[2]{\index{\texttt{#1} system command}``\texttt{#1 #2}''} + +% Mercurial command option. +\newcommand{\hgopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}} + +% Mercurial command option, provided by an extension command. +\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}} + +% Mercurial global option. +\newcommand{\hggopt}[1]{\index{global options!\texttt{#1} option}\texttt{#1}} + +% Shell/system command option. +\newcommand{\cmdopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}} + +% Command option. +\newcommand{\option}[1]{\texttt{#1}} + +% Software package. +\newcommand{\package}[1]{\index{\texttt{#1} package}\texttt{#1}} + +% Section name from a hgrc file. +\newcommand{\rcsection}[1]{\index{\texttt{hgrc} file!\texttt{#1} section}\texttt{[#1]}} + +% Named item in a hgrc file section. +\newcommand{\rcitem}[2]{\index{\texttt{hgrc} file!\texttt{#1} + section!\texttt{#2} entry}\texttt{#2}} + +% hgrc file. +\newcommand{\hgrc}{\index{configuration + file!\texttt{hgrc}(Linux/Unix)}\index{\texttt{hgrc} configuration + file}\texttt{hgrc}} + + +% Mercurial.ini file. +\newcommand{\hgini}{\index{configuration file!\texttt{Mercurial.ini} + (Windows)}\index{\texttt{Mercurial.ini} configuration file}\texttt{Mercurial.ini}} + +% Hook name. +\newcommand{\hook}[1]{\index{\texttt{#1} hook}\index{hooks!\texttt{#1}}\texttt{#1}} + +% Environment variable. +\newcommand{\envar}[1]{\index{\texttt{#1} environment + variable}\index{environment variables!\texttt{#1}}\texttt{#1}} + +% Python module. +\newcommand{\pymod}[1]{\index{\texttt{#1} module}\texttt{#1}} + +% Python class in a module. +\newcommand{\pymodclass}[2]{\index{\texttt{#1} module!\texttt{#2} + class}\texttt{#1.#2}} + +% Python function in a module. +\newcommand{\pymodfunc}[2]{\index{\texttt{#1} module!\texttt{#2} + function}\texttt{#1.#2}} + +% Note: blah blah. +\newsavebox{\notebox} +\newenvironment{note}% + {\begin{lrbox}{\notebox}\begin{minipage}{0.7\textwidth}\textbf{Note:}\space}% + {\end{minipage}\end{lrbox}\fbox{\usebox{\notebox}}} +\newenvironment{caution}% + {\begin{lrbox}{\notebox}\begin{minipage}{0.7\textwidth}\textbf{Caution:}\space}% + {\end{minipage}\end{lrbox}\fbox{\usebox{\notebox}}} + +% Code sample, eating 4 characters of leading space. +\DefineVerbatimEnvironment{codesample4}{Verbatim}{frame=single,gobble=4,numbers=left,commandchars=\\\{\}} + +% Code sample, eating 2 characters of leading space. +\DefineVerbatimEnvironment{codesample2}{Verbatim}{frame=single,gobble=2,numbers=left,commandchars=\\\{\}} + +% Interaction from the examples directory. +\newcommand{\interaction}[1]{\VerbatimInput[frame=single,numbers=left,commandchars=\\\{\}]{examples/#1.lxo}} +% Example code from the examples directory. +\newcommand{\excode}[1]{\VerbatimInput[frame=single,numbers=left,commandchars=\\\{\}]{../examples/#1}} + +% Graphics inclusion. +%\ifpdf + \newcommand{\grafix}[1]{\includegraphics{#1}} +%\else +% \newcommand{\grafix}[1]{\includegraphics{#1.png}} +%\fi + +% Reference entry for a command. +\newcommand{\cmdref}[2]{\section{\hgcmd{#1}---#2}\label{cmdref:#1}\index{\texttt{#1} command}} + +% Reference entry for a command option with long and short forms. +\newcommand{\optref}[3]{\subsubsection{\hgopt{#1}{--#3}, also \hgopt{#1}{-#2}}} + +% Reference entry for a command option with only long form. +\newcommand{\loptref}[2]{\subsubsection{\hgopt{#1}{--#2} option}} + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/Makefile Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,220 @@ +# This makefile requires GNU make. + +image-sources := $(wildcard figs/*.dot figs/*.gif figs/*.png figs/*.svg) + +xml-src-files := \ + 00book.xml \ + app*.xml \ + ch*.xml + +image-dot := $(filter %.dot,$(image-sources)) +image-svg := $(filter %.svg,$(image-sources)) +image-oth := $(filter %.gif %.png,$(image-sources)) + +obj-web := html +obj-websup := $(obj-web)/support +obj-web-read := $(obj-web)/read + +image-web := \ + $(image-dot:%.dot=$(obj-web-read)/%.png) \ + $(image-svg:%.svg=$(obj-web-read)/%.png) \ + $(image-oth:%=$(obj-web-read)/%) + +example-sources-by-name := \ + backout \ + bisect \ + branching \ + branch-named \ + branch-repo \ + cmdref \ + daily.copy \ + daily.files \ + daily.rename \ + daily.revert \ + extdiff \ + filenames \ + hook.msglen \ + hook.simple \ + hook.ws \ + issue29 \ + mq.guards \ + mq.qinit-help \ + mq.dodiff \ + mq.id \ + mq.tarball \ + mq.tools \ + mq.tutorial \ + rename.divergent \ + rollback \ + tag \ + template.simple \ + template.svnstyle \ + tour \ + tour-merge-conflict + +example-sources := \ + $(example-sources-by-name:%=examples/%) \ + $(wildcard examples/ch*/*) + +extras-web-base := \ + $(obj-web)/index.html \ + $(obj-web)/robots.txt \ + $(obj-websup)/form-min.js \ + $(obj-websup)/form.js \ + $(obj-websup)/hsbook.js \ + $(obj-websup)/jquery-min.js \ + $(obj-websup)/jquery.js \ + $(obj-websup)/styles.css + +extras-web := $(extras-web-base) $(extras-web-base:%=%.gz) + +xsltproc := xsltproc +xsltproc-opts := --nonet --xinclude --path '$(xml-path)' + +xmllint := xmllint +xmllint-opts := --noout --nonet --valid + +system-xsl-dir := $(firstword $(wildcard \ + /usr/share/sgml/docbook/xsl-stylesheets \ + /usr/share/xml/docbook/stylesheet/nwalsh \ + )) + +# Bletcherousness. + +ifneq ($(wildcard /usr/share/sgml/docbook/xml-dtd-4.4-*),) +dtd-dir := $(wildcard /usr/share/sgml/docbook/xml-dtd-4.4-*) +else +ifneq ($(wildcard /usr/share/xml/docbook/schema/dtd/4.4),) +dtd-dir := $(wildcard /usr/share/xml/docbook/schema/dtd/4.4) +else +$(error Do not know where to look for DocBook XML 4.4 DTD) +endif +endif + +ifeq ($(system-xsl-dir),) +$(error add a suitable directory to system-xsl-dir) +endif + +example-prereqs := \ + /usr/bin/merge + +dist-sources := \ + ../html/hgicon.png \ + ../html/index.html.var \ + ../html/index.en.html + +hg = $(shell which hg) + +hg-id = $(shell hg parents --template '{node|short}, dated {date|isodate},\n') + +hg-version = $(shell hg version -q | \ + sed 's,.*(version \(unknown\|[a-f0-9+]*\)),\1,') + +all: web complete.xml + +../stylesheets/system-xsl: $(system-xsl-dir) + ln -s $< $@ + +web: ../stylesheets/system-xsl websup html + +html: $(obj-web-read)/index.html + +../web/index-read.html.in: ../web/genindex.py $(xml-src-files) + cd ../web && ./genindex.py + +$(obj-web-read)/index.html: ../stylesheets/system-xsl .validated-00book.xml ../web/index-read.html.in + xsltproc $(xsltproc-opts) -o $(obj-web-read)/x ../stylesheets/chunk-stylesheet.xsl 00book.xml + python ../web/texpand.py ../web/index-read.html.in html/read/index.html + for i in $(obj-web-read)/*.html; do \ + gzip -9 -c $$i > $$i.gz; \ + done + +websup: $(extras-web) $(image-web) + mkdir -p $(obj-websup)/figs $(obj-web-read)/figs + cp ../stylesheets/system-xsl/images/*.png $(obj-websup)/figs + cp -f ../web/icons/*.png $(obj-websup)/figs + +complete.xml: .validated-00book.xml + $(xsltproc) $(xsltproc-opts) -o $@ ../stylesheets/dtd-profile.xsl 00book.xml + +all-ids.dat: ../stylesheets/all-ids.xsl $(xml-src-files) + $(xsltproc) $(xsltproc-opts) -o $@ ../stylesheets/all-ids.xsl 00book.xml + +web: websup + +valid: .validated-00book.xml + +.validated-00book.xml: $(xml-src-files) examples/.run + $(xmllint) --path '$(dtd-dir):$(xml-path)' $(xmllint-opts) $< + touch $@ + +# Produce 90dpi PNGs for the web. + +$(obj-web-read)/figs/%.png: $(obj-web-read)/figs/%.svg fixsvg + mkdir -p $(dir $@) + ./fixsvg $< + inkscape -D -e $@ $<-tmp.svg + rm $<-tmp.svg + +$(obj-web-read)/figs/%.png: figs/%.svg fixsvg + mkdir -p $(dir $@) + ./fixsvg $< + inkscape -D -e $@ $<-tmp.svg + rm $<-tmp.svg + +$(obj-web-read)/figs/%.gif: figs/%.gif + cp $< $@ + +$(obj-web-read)/figs/%.png: figs/%.png + cp $< $@ + +$(obj-web-read)/figs/%.svg: figs/%.dot + mkdir -p $(dir $@) + dot -Tsvg -o $@ $< + +examples: $(example-prereqs) examples/.run + +examples/.run: $(example-sources) + cd examples && ./run-example -a + +examples/%.run: examples/% examples/run-example + +clean: + -rm -rf dist html $(image-dot:%.dot=%.pdf) $(image-dot:%.dot=%.png) \ + $(image-svg:%.svg=%.png) examples/*.{lxo,run} examples/.run + +install: html $(dist-sources) + rm -rf dist + mkdir -p dist + cp html/*.{css,html,png} dist + cp $(dist-sources) dist + +rsync: install + rsync -avz --delete dist sp.red-bean.com:public_html/hgbook + +vpath %.css ../web +vpath %.html.in ../web +vpath %.js ../web/javascript + +$(obj-websup)/%.css: %.css + @mkdir -p $(dir $@) + cp $< $@ + +$(obj-websup)/%.jpg: %.jpg + @mkdir -p $(dir $@) + cp $< $@ + +$(obj-websup)/%.js: %.js + @mkdir -p $(dir $@) + cp $< $@ + +$(obj-web)/%: ../web/% + @mkdir -p $(dir $@) + cp $< $@ + +$(obj-web)/%.html: %.html.in + @mkdir -p $(dir $@) + python ../web/texpand.py $< $@ + +%.gz: % + gzip -9 -c $< > $@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/Makefile.orig Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,241 @@ +# This makefile requires GNU make. + +sources := \ + 00book.tex \ + 99book.bib \ + 99defs.tex \ + build_id.tex \ + branch.tex \ + cmdref.tex \ + collab.tex \ + concepts.tex \ + daily.tex \ + filenames.tex \ + hg_id.tex \ + hgext.tex \ + hook.tex \ + intro.tex \ + mq.tex \ + mq-collab.tex \ + mq-ref.tex \ + preface.tex \ + srcinstall.tex \ + template.tex \ + tour-basic.tex \ + tour-merge.tex \ + undo.tex + +image-sources := \ + feature-branches.dot \ + filelog.svg \ + kdiff3.png \ + metadata.svg \ + mq-stack.svg \ + note.png \ + revlog.svg \ + snapshot.svg \ + tour-history.svg \ + tour-merge-conflict.svg \ + tour-merge-merge.svg \ + tour-merge-pull.svg \ + tour-merge-sep-repos.svg \ + undo-manual.dot \ + undo-manual-merge.dot \ + undo-non-tip.dot \ + undo-simple.dot \ + wdir.svg \ + wdir-after-commit.svg \ + wdir-branch.svg \ + wdir-merge.svg \ + wdir-pre-branch.svg + +image-dot := $(filter %.dot,$(image-sources)) +image-svg := $(filter %.svg,$(image-sources)) +image-png := $(filter %.png,$(image-sources)) + +image-pdf := $(image-dot:%.dot=%.pdf) $(image-svg:%.svg=%.pdf) $(image-png) +image-html := $(image-dot:%.dot=%.png) $(image-svg:%.svg=%.png) $(image-png) +#image-eps := $(image-dot:%.dot=%.eps) $(image-svg:%.svg=%.eps) $(image-png) +image-eps := $(image-dot:%.dot=%.eps) $(image-svg:%.svg=%.eps) $(image-png:%.png=%.eps) + +example-sources := \ + backout \ + bisect \ + branching \ + branch-named \ + branch-repo \ + cmdref \ + daily.copy \ + daily.files \ + daily.rename \ + daily.revert \ + extdiff \ + filenames \ + hook.msglen \ + hook.simple \ + hook.ws \ + issue29 \ + mq.guards \ + mq.qinit-help \ + mq.dodiff \ + mq.id \ + mq.tarball \ + mq.tools \ + mq.tutorial \ + rename.divergent \ + rollback \ + tag \ + template.simple \ + template.svnstyle \ + tour \ + tour-merge-conflict + +example-prereqs := \ + /usr/bin/merge + +dist-sources := \ + ../html/hgicon.png \ + ../html/index.html.var \ + ../html/index.en.html + +latex-options = \ + -interaction batchmode \ + -output-directory $(dir $(1)) \ + -jobname $(basename $(notdir $(1))) + +hg = $(shell which hg) + +hg-id = $(shell hg parents --template '{node|short}, dated {date|isodate},\n') + +hg-version = $(shell hg version -q | \ + sed 's,.*(version \(unknown\|[a-f0-9+]*\)),\1,') + +all: dvi + +#dvi: $(sources) $(image-eps) examples +dvi: $(sources) $(image-eps) + platex 00book.tex + + cp 00book.aux hgbook.aux + bibtex hgbook + + platex 00book.tex + platex 00book.tex + platex 00book.tex + + + + + + +pdf: pdf/hgbook.pdf + +define pdf + mkdir -p $(dir $@) + TEXINPUTS=$(dir $<): pdflatex $(call latex-options,$@) $< || (rm -f $@; exit 1) + + cp 99book.bib $(dir $@) + + cd $(dir $@) && bibtex $(basename $(notdir $@)) + cd $(dir $@) && makeindex $(basename $(notdir $@)) + + TEXINPUTS=$(dir $<): pdflatex $(call latex-options,$@) $< || (rm -f $@; exit 1) + TEXINPUTS=$(dir $<): pdflatex $(call latex-options,$@) $< || (rm -f $@; exit 1) + if grep 'Reference.*undefined' $(@:.pdf=.log); then exit 1; fi +endef + +#pdf/hgbook.pdf: $(sources) $(image-pdf) examples +pdf/hgbook.pdf: $(sources) $(image-pdf) + $(call pdf) + +html: onepage split + +onepage: $(htlatex) html/onepage/hgbook.html html/onepage/hgbook.css $(image-html:%=html/onepage/%) + +html/onepage/%: % + cp $< $@ + +split: $(htlatex) html/split/hgbook.html html/split/hgbook.css $(image-html:%=html/split/%) + +html/split/%: % + cp $< $@ + +# This is a horrible hack to work around the fact that the htlatex +# command in tex4ht is itself a horrible hack. I really don't want to +# include verbatim the big wad of TeX that is repeated in that script, +# but I've given up and run a hacked copy as htlatex.book here. + +define htlatex + mkdir -p $(dir $(1)) + cp 99book.bib $(dir $(1)) + TEXINPUTS=$(dir $(2)): ./htlatex.book $(2) "bookhtml,html4-uni,$(3)" " -cunihtf -utf8" "$(dir $(1))" "$(call latex-options,$(1))" || (rm -f $(1); exit 1) + cd $(dir $(1)) && tex4ht -f/$(basename $(notdir $(1))) -cvalidate -cunihtf + cd $(dir $(1)) && t4ht -f/$(basename $(notdir $(1))) + ./fixhtml.py $(dir $(1))/*.html + rm $(dir $(1))/hgbook.css +endef + +#html/onepage/hgbook.html: $(sources) $(image-html) examples bookhtml.cfg +html/onepage/hgbook.html: $(sources) $(image-html) bookhtml.cfg + $(call htlatex,$@,$<) + +#html/split/hgbook.html: $(sources) examples bookhtml.cfg +html/split/hgbook.html: $(sources) bookhtml.cfg + $(call htlatex,$@,$<,2) + +# Produce 90dpi PNGs for the web. + +%.png: %.svg + inkscape -D -e $@ $< + +%.svg: %.dot + dot -Tsvg -o $@ $< + +# Produce eps & pdf for the pdf + +%.pdf: %.eps + epstopdf $< + +%.eps: %.svg + inkscape -E $@ $< + +%.eps: %.dot + dot -Tps -o $@ $< + +%.eps: %.png + convert $< ps:$@ + +examples: $(example-prereqs) examples/.run + +examples/.run: $(example-sources:%=examples/%.run) + touch examples/.run + +examples/%.run: examples/% examples/run-example + cd examples && ./run-example $(notdir $<) + +changelog := $(wildcard ../.hg/store/00changelog.[id]) +ifeq ($(changelog),) +changelog := $(wildcard ../.hg/00changelog.[id]) +endif + +build_id.tex: $(changelog) + echo -n '$(hg-id)' > build_id.tex + +hg_id.tex: $(hg) + echo -n '$(hg-version)' > hg_id.tex + +clean: + rm -rf dist html pdf \ + $(image-dot:%.dot=%.pdf) \ + $(image-dot:%.dot=%.png) \ + $(image-svg:%.svg=%.pdf) \ + $(image-svg:%.svg=%.png) \ + examples/*.{lxo,run} examples/.run build_id.tex hg_id.tex + +install: pdf split $(dist-sources) + rm -rf dist + mkdir -p dist + cp pdf/hgbook.pdf dist + cp html/split/*.{css,html,png} dist + cp $(dist-sources) dist +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/bookhtml.cfg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,18 @@ +% -*- latex -*- + +\Preamble{xhtml} + +% Tex4ht's default definition of lists is complete crap. +% Unfortunately, it can't distinguish between "ul" and "dl" lists. + +\ConfigureList{itemize}% + {\EndP\HCode{<ul>}\let\endItem=\empty} + {\ifvmode \IgnorePar\fi + \EndP\HCode{</li></ul>}\ShowPar} + {\endItem \def\endItem{\EndP\Tg</span>}\HCode{<li><span class="dt">}} + {\HCode{</span><span class="dd">}} +\def\textbullet{} + +\begin{document} + +\EndPreamble
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/branch.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,733 @@ +%\chapter{Managing releases and branchy development} +\chapter{$B%j%j!<%9$H%V%i%s%A3+H/$N4IM}(B} +\label{chap:branch} + +%Mercurial provides several mechanisms for you to manage a project that +%is making progress on multiple fronts at once. To understand these +%mechanisms, let's first take a brief look at a fairly normal software +%project structure. + +Mercurial$B$OF1;~$KJ#?t$N6ILL$G?J9T$7$F$$$/%W%m%8%'%/%H$r4IM}$9$k$N$KLrN)(B +$B$D5!G=$r;}$C$F$$$k!%$3$l$i$N5!G=$rM}2r$9$k$?$a!$$^$:DL>o$N%=%U%H%&%'%"%W(B +$B%m%8%'%/%H$N9=B$$r9M$($k!%(B + +%Many software projects issue periodic ``major'' releases that contain +%substantial new features. In parallel, they may issue ``minor'' +%releases. These are usually identical to the major releases off which +%they're based, but with a few bugs fixed. + +$BB?$/$N%=%U%H%&%'%"%W%m%8%'%/%H$G$O!$?75!G=$r;}$D%a%8%c!<%j%j!<%9$rDj4|E*(B +$B$K%j%j!<%9$9$k!%JB9T$7$FB??t$N%^%$%J!<%j%j!<%9$b9T$J$o$l$k!%$3$l$i$O%a(B +$B%8%c!<%j%j!<%9$N%P%0$r=$@5$7$?$b$N$G$"$k!%(B + +%In this chapter, we'll start by talking about how to keep records of +%project milestones such as releases. We'll then continue on to talk +%about the flow of work between different phases of a project, and how +%Mercurial can help you to isolate and manage this work. + +$B$3$N>O$G$O$^$:%j%j!<%9$N$h$&$J%W%m%8%'%/%H$N%^%$%k%9%H!<%s$K8@5Z$9$k!%<!$$(B +$B$G%W%m%8%'%/%H$N3F%U%'!<%:$G$NN.$l$r@bL@$7!$(BMercurial$B$G$I$N$h$&$K6hJ,$1(B +$B$7!$4IM}$G$-$k$N$+$r@bL@$9$k!%(B + +%\section{Giving a persistent name to a revision} +\section{$B%j%S%8%g%s$K1JB3E*$JL>A0$rIU$1$k(B} + +%Once you decide that you'd like to call a particular revision a +%``release'', it's a good idea to record the identity of that revision. +%This will let you reproduce that release at a later date, for whatever +%purpose you might need at the time (reproducing a bug, porting to a +%new platform, etc). +%\interaction{tag.init} + +$B$"$k%j%S%8%g%s$r%j%j!<%9$H7h$a$?;~$K!$$3$l$r5-O?$7$F$*$/$N$ONI$$9M$($G$"(B +$B$k!%$3$l$O8eF|!$%P%0$N:F8=$d%=%U%H%&%'%"$N0\?"$J$I$NL\E*$G%j%j!<%9$r:F8=(B +$B$9$k$N$KLrN)$D!%(B +\interaction{tag.init} + +%Mercurial lets you give a permanent name to any revision using the +%\hgcmd{tag} command. Not surprisingly, these names are called +%``tags''. +%\interaction{tag.tag} + +$BFCDj$N%j%S%8%g%s$K(BMercurial$B$G1JB3E*$JL>A0$rIU$1$k$3$H$,$G$-$k!%$3$NL>A0(B +$B$O%?%0$H8F$P$l$k!%(B +\interaction{tag.tag} + +%A tag is nothing more than a ``symbolic name'' for a revision. Tags +%exist purely for your convenience, so that you have a handy permanent +%way to refer to a revision; Mercurial doesn't interpret the tag names +%you use in any way. +%Neither does Mercurial place any restrictions on +%the name of a tag, beyond a few that are necessary to ensure that a +%tag can be parsed unambiguously. A tag name cannot contain any of the +%following characters: +%\begin{itemize} +%\item Colon (ASCII 58, ``\texttt{:}'') +%\item Carriage return (ASCII 13, ``\Verb+\r+'') +%\item Newline (ASCII 10, ``\Verb+\n+'') +%\end{itemize} + +$B%?%0$O<B$N$H$3$m%j%S%8%g%s$KIU$1$i$l$?%7%s%\%j%C%/%M!<%`$KB>$J$i$J$$!%%?(B +$B%0$OC1$K%f!<%6$NJX59$N$?$a$KIU$1$i$l$k!%%?%0$OFCDj$N%j%S%8%g%s$r;2>H$9$k(B +$B$?$a$N<j7Z$G1JB3E*$JJ}K!$G!$(BMercurial$B$O%?%0$rK]Lu$7$J$$!%%?%0$NL>A0$K$O!$(B +$BL@3N$K%Q!<%9$9$k$?$a$N$$$/$D$+$N$b$N0J30$N@)8B$O$J$$!%%?%0%M!<%`$O0J2<$N(B +$BJ8;z$r4^$`$3$H$O$G$-$J$$!%(B +\begin{itemize} +\item $B%3%m%s(B (ASCII 58, ``\texttt{:}'') +\item $BI|5"J8;z(B (ASCII 13, ``\Verb+\r+'') +\item $B2~9TJ8;z(B (ASCII 10, ``\Verb+\n+'') +\end{itemize} + + +%You can use the \hgcmd{tags} command to display the tags present in +%your repository. In the output, each tagged revision is identified +%first by its name, then by revision number, and finally by the unique +%hash of the revision. +%\interaction{tag.tags} +%Notice that \texttt{tip} is listed in the output of \hgcmd{tags}. The +%\texttt{tip} tag is a special ``floating'' tag, which always +%identifies the newest revision in the repository. + +\hgcmd{tags}$B%3%^%s%I$G%j%]%8%H%j$KB8:_$9$k%?%0$rI=<($9$k$3$H$,$G$-$k!%=P(B +$BNO$G$O!$%?%0IU$1$5$l$?%j%S%8%g%s$OL>A0!$%j%S%8%g%sHV9f!$8GM-$N%O%C%7%eCM(B +$B$N=g$K6hJL$5$l$k!%(B +\interaction{tag.tags} +\hgcmd{tags}$B$N=PNO$K(B\texttt{tip}$B$,4^$^$l$F$$$k$3$H$KCm0U!%(B\texttt{tip}$B%?(B +$B%0$O!$%j%]%8%H%j$NCf$G>o$K:G?7$N%j%S%8%g%s$KIU$1$i$l$F$$$kFCJL$J%U%m!<%F%#(B +$B%s%0%?%0$G$"$k!%(B + +%In the output of the \hgcmd{tags} command, tags are listed in reverse +%order, by revision number. This usually means that recent tags are +%listed before older tags. It also means that \texttt{tip} is always +%going to be the first tag listed in the output of \hgcmd{tags}. + +\hgcmd{tags}$B%3%^%s%I$N=PNO$K$*$$$F!$%?%0$O%j%S%8%g%sHV9f$K$h$C$F5U=g$GI=(B +$B<($5$l$F$$$k!%$3$l$K$h$C$F!$DL>o!$?7$7$$%?%0$,8E$$%?%0$h$j$bA0$KI=<($5$l(B +$B$k!%(B\texttt{tip}$B%?%0$O(B\hgcmd{tags}$B%3%^%s%I$N=PNO$N0lHV@hF,$KI=<($5$l$k!%(B + +%When you run \hgcmd{log}, if it displays a revision that has tags +%associated with it, it will print those tags. +%\interaction{tag.log} + +\hgcmd{log}$B%3%^%s%I$O%?%0$N7k$S$D$1$i$l$?%j%S%8%g%s$rI=<($9$k:]$K%?%0$b(B +$BI=<($9$k!%(B +\interaction{tag.log} + +%Any time you need to provide a revision~ID to a Mercurial command, the +%command will accept a tag name in its place. Internally, Mercurial +%will translate your tag name into the corresponding revision~ID, then +%use that. +%\interaction{tag.log.v1.0} + +Mecurial$B%3%^%s%I$K%j%S%8%g%sHV9f$rEO$9I,MW$,$"$k>l9g!$>o$K%?%0%M!<%`$r;H(B +$B$&$3$H$,$G$-$k!%FbItE*$K$O(BMercurial$B$O%?%0%M!<%`$rBP1~$9$k%j%S%8%g%s(BID$B$K(B +$BJQ49$7$F;HMQ$7$F$$$k!%(B +\interaction{tag.log.v1.0} + +%There's no limit on the number of tags you can have in a repository, or +%on the number of tags that a single revision can have. As a practical +%matter, it's not a great idea to have ``too many'' (a number which will +%vary from project to project), simply because tags are supposed to help +%you to find revisions. If you have lots of tags, the ease of using them +%to identify revisions diminishes rapidly. + +$B%j%]%8%H%j$NCf$G;H$($k%?%0?t!$0l$D$N%j%S%8%g%s$KIU$1$i$l$k%?%0?t$K>e8B$O(B +$B$J$$!%;v>p$O%W%m%8%'%/%H$K$h$C$F0[$J$k$@$m$&$,!$<BMQE*$K$O%?%0$rB?$/IU$1(B +$B$9$.$k$3$H$O$"$^$jNI$$9M$($H$O8@$($J$$!%%?%0$H$O%j%S%8%g%s$r8+$D$10W$/$9(B +$B$k$?$a$K;H$&$b$N$@$+$i$@!%%?%0$rB?$/IU$1$9$.$k$H!$%?%0$K$h$C$F%j%S%8%g%s(B +$B$N6hJL$r$9$k$3$H$,$H$?$s$KFq$7$/$J$k!%(B + +%For example, if your project has milestones as frequent as every few +%days, it's perfectly reasonable to tag each one of those. But if you +%have a continuous build system that makes sure every revision can be +%built cleanly, you'd be introducing a lot of noise if you were to tag +%every clean build. Instead, you could tag failed builds (on the +%assumption that they're rare!), or simply not use tags to track +%buildability. + +$BNc$($P$"$J$?$N%W%m%8%'%/%H$,?tF|Kh$K%^%$%k%9%H!<%s$r7^$($F$$$k>l9g!$$=$l(B +$B$>$l$K%?%0$rIU$1$k$3$H$OM}$KE,$C$F$$$k!%$7$+$7!$$=$l$>$l$N%j%S%8%g%s$,%/(B +$B%j!<%s$K%S%k%I$G$-$k$+8!>Z$9$k$?$a$N%S%k%I%7%9%F%`$r;}$C$F$$$k$h$&$J>l9g!$(B +$B$=$l$>$l$N%/%j!<%s%S%k%I$K%?%0$rIU$1$F$$$?$i<}=&$,$D$+$J$/$J$k$@$m$&!%$`(B +$B$7$m%S%k%I$,<:GT$9$k$3$H$,>/$J$$$N$G$"$l$P!$<:GT$7$?%j%S%8%g%s$K%?%0$r$D(B +$B$1$?J}$,NI$$$7!$C1$K%S%k%I$,DL$C$?$3$H$r<($9$N$K%?%0$rMQ$$$k$Y$-$G$O$J$$(B +$B$+$bCN$l$J$$!%(B + +%If you want to remove a tag that you no longer want, use +%\hgcmdargs{tag}{--remove}. +%\interaction{tag.remove} +%You can also modify a tag at any time, so that it identifies a +%different revision, by simply issuing a new \hgcmd{tag} command. +%You'll have to use the \hgopt{tag}{-f} option to tell Mercurial that +%you \emph{really} want to update the tag. +%\interaction{tag.replace} +%There will still be a permanent record of the previous identity of the +%tag, but Mercurial will no longer use it. There's thus no penalty to +%tagging the wrong revision; all you have to do is turn around and tag +%the correct revision once you discover your error. + +$B%?%0$,I,MW$J$/$J$C$?;~$O(B\hgcmdargs{tag}{--remove}$B%3%^%s%I$G>C$9$3$H$,$G(B +$B$-$k!%(B +\interaction{tag.remove} +$B%?%0$O$$$D$G$bJQ99$G$-$k$N$G!$$"$k%?%0$rB>$N%j%S%8%g%s$KIU$1BX$($k$h$&$J(B +$B$3$H$b$G$-$k!%(B +$B%?%0$r(B\emph{$BK\Ev(B}$B$K99?7$7$?$$>l9g$O(B\hgopt{tag}{-f}$B%*%W%7%g%s$r;XDj$9$kI,(B +$BMW$,$"$k!%(B +\interaction{tag.replace} +$B%?%0$N0JA0$N%"%$%G%s%F%#%F%#!<$N1JB3E*$J5-O?$O;D$C$F$$$k$,!$(BMercurial$B$O$b(B +$B$O$d$3$l$rMxMQ$7$J$$!%$h$C$F!$4V0c$C$?%j%S%8%g%s$K%?%0$rIU$1$k$3$H$G%Z%J(B +$B%k%F%#$,2]$;$i$l$k$H$$$&$3$H$O$J$$!%4V0c$$$r8+$D$1$?;~$OC1$K$d$jD>$7$F@5(B +$B$7$$%j%S%8%g%s$K%?%0$rIU$1$l$P$h$$!%(B + +%Mercurial stores tags in a normal revision-controlled file in your +%repository.If you've created any tags, you'll find them in a file +%named \sfilename{.hgtags}.When you run the \hgcmd{tag} command, +%Mercurial modifies this file, then automatically commits the change to +%it.This means that every time you run \hgcmd{tag}, you'll see a +%corresponding changeset in the output of \hgcmd{log}. +%\interaction{tag.tip} + +Mercurial$B$O%?%0$r%j%]%8%H%j$NCf$NDL>o$N%j%S%8%g%s4IM}%U%!%$%k$KJ]B8$9$k!%(B +$B%?%0$r:n@.$7$?;~!$(B\sfilename{.hgtags}$B$H$$$&%U%!%$%k$K%?%0$,J]B8$5$l$F$$(B +$B$k$N$,J,$+$k$@$m$&!%(B\hgcmd{tag}$B%3%^%s%I$r<B9T$9$k$H(BMercurial$B$O$3$N%U%!%$(B +$B%k$rJQ99$7!$JQ99$r$3$N%U%!%$%k$K%3%_%C%H$9$k!%$D$^$j(B\hgcmd{tag}$B$r<B9T$9(B +$B$k$H$$$D$b(B\hgcmd{log}$B$N=PNO$NCf$KBP1~$9$k%A%'%s%8%;%C%H$r8+$k$3$H$K$J$k!%(B +\interaction{tag.tip} + +%\subsection{Handling tag conflicts during a merge} +\subsection{$B%^!<%8$N:]$K%?%0$N%3%s%U%j%/%H$r2r7h$9$k(B} + +%You won't often need to care about the \sfilename{.hgtags} file, but +%it sometimes makes its presence known during a merge. The format of +%the file is simple: it consists of a series of lines. Each line +%starts with a changeset hash, followed by a space, followed by the +%name of a tag. + +\sfilename{.hgtags}$B$r5$$K$7$J$1$l$P$J$i$J$$$3$H$OB?$/$J$$$,!$%^!<%8$N:]$K(B +$B$OB8:_$rL@$i$+$K$9$k!%%U%!%$%k%U%)!<%^%C%H$O%7%s%W%k$G!$0lO"$N9T$r4^$`$@(B +$B$1$G$"$k!%$=$l$>$l$N9T$O%A%'%s%8%;%C%H$N%O%C%7%e$G;O$^$j!$(B1$B$D$N%9%Z!<%9(B +$B$,B3$-!$%?%0$NL>>N$,B3$/!%(B + +%If you're resolving a conflict in the \sfilename{.hgtags} file during +%a merge, there's one twist to modifying the \sfilename{.hgtags} file: +%when Mercurial is parsing the tags in a repository, it \emph{never} +%reads the working copy of the \sfilename{.hgtags} file. Instead, it +%reads the \emph{most recently committed} revision of the file. + +$B%^!<%8Cf$K(B\sfilename{.hgtags}$B%U%!%$%kFb$N%3%s%U%j%/%H$r2r7h$7$F$$$k>l9g!$(B +\sfilename{.hgtags}$B$rJQ99$9$k0lG1$j$,$"$k!%(BMercurial$B$,%j%]%8%H%jCf$N%?%0(B +$B$r%Q!<%9$9$k;~!$(BMercurial$B$O(B\sfilename{.hgtags}$B$N%o!<%-%s%0%3%T!<$r(B +\emph{$B7h$7$F(B}$BFI$^$J$$!%$=$NBe$o$j(B\emph{$B:G$b?7$7$/%3%_%C%H$5$l$?(B}$B%j%S%8%g(B +$B%s$rFI$`!%(B + +%An unfortunate consequence of this design is that you can't actually +%verify that your merged \sfilename{.hgtags} file is correct until +%\emph{after} you've committed a change. So if you find yourself +%resolving a conflict on \sfilename{.hgtags} during a merge, be sure to +%run \hgcmd{tags} after you commit.If it finds an error in the +%\sfilename{.hgtags} file, it will report the location of the error, +%which you can then fix and commit. You should then run \hgcmd{tags} +%again, just to be sure that your fix is correct. + +$B$3$N@_7W$N;DG0$J7k2L$O!$JQ99$r%3%_%C%H$7$?(B\emph{$B8e(B}$B$G$J$$$H%^!<%8$7$?(B +\sfilename{.hgtags}$B%U%!%$%k$r<B:]$K$O%Y%j%U%!%$$G$-$J$$$3$H$G$"$k!%$=$N$?(B +$B$a!$%^!<%8Cf$K(B\sfilename{.hgtags}$B$N%3%s%U%j%/%H2r7h$r$7$F$$$k>l9g$O!$%3%_%C(B +$B%H8e$KK:$l$:(B\hgcmd{tags}$B$r<B9T$9$kI,MW$,$"$k!%(B\sfilename{.hgtags}$B$K%(%i!<(B +$B$,8+$D$+$C$?>l9g!$%(%i!<$N$"$k>l=j$rJs9p$9$k!%$=$l$r8+$F=$@5$7!$%3%_%C%H(B +$B$9$k$3$H$,$G$-$k!%$=$3$G(B\hgcmd{tags}$B$r:F$SAv$i$;!$=$@5$,@5$7$$$3$H$r3NG'(B +$B$9$Y$-$G$"$k!%(B + + +%\subsection{Tags and cloning} +\subsection{$B%?%0$H%/%m!<%s(B} + +%You may have noticed that the \hgcmd{clone} command has a +%\hgopt{clone}{-r} option that lets you clone an exact copy of the +%repository as of a particular changeset.The new clone will not contain +%any project history that comes after the revision you specified. This +%has an interaction with tags that can surprise the unwary. + +\hgcmd{clone}$B%3%^%s%I$,(B\hgopt{clone}{-r}$B%*%W%7%g%s$r;}$C$F$$$k$3$H$K$9$G(B +$B$K5$$E$$$F$$$k$+$bCN$l$J$$!%$3$N%*%W%7%g%s$GFCDj$N%A%'%s%8%;%C%H$N%3%T!<(B +$B$r%/%m!<%s$9$k$3$H$,$G$-$k$,!"%/%m!<%s$7$?%3%T!<$O!$;XDj$7$?%j%S%8%g%s8e(B +$B$NMzNr$r;}$?$J$$$?$a!"ITMQ?4$J%f!<%6$O$7$P$7$P6C$/$3$H$K$J$k!#(B + +%Recall that a tag is stored as a revision to the \sfilename{.hgtags} +%file, so that when you create a tag, the changeset in which it's +%recorded necessarily refers to an older changeset. +%When you run \hgcmdargs{clone}{-r foo} to clone a repository as of tag +%\texttt{foo}, the new clone \emph{will not contain the history that +%created the tag} that you used to clone the repository. +%The resultis that you'll get exactly the right subset of the project's +%history in the new repository, but \emph{not} the tag you might have +%expected. + +$B%?%0$O(B\sfilename{.hgtags}$B%U%!%$%kFb$N%j%S%8%g%s$H$7$F5-O?$5$l$F$$$k$3$H$r(B +$B;W$$=P$7$FM_$7$$!%$3$N$?$a!$%?%0:n@.;~$K!$%?%0$,5-O?$5$l$F$$$k%A%'%s%8%;%C(B +$B%H$+$i8E$$%A%'%s%8%;%C%H$X$N;2>H$,@8$8$k!%%?%0(B\texttt{foo}$B$,IU$$$F$$$k%j(B +$B%]%8%H%j$r%/%m!<%s$9$k$?$a$K(B\hgcmdargs{clone}{-r foo}$B<B9T$9$k;~!$?7$7$$%/(B +$B%m!<%s$O%?%0$r@8@.$7$?MzNr$r(B\emph{$B4^$^$J$$(B}$B!%7k2L$H$7$F!$?7$7$$%j%]%8%H%j(B +$B$K4^$^$l$kMzNr$O!$%W%m%8%'%/%HMzNr$N%5%V%;%C%H$K$J$j!$%?%0$O4^$^$l$J$$!%(B + + +%\subsection{When permanent tags are too much} +\subsection{$B1J5W%?%0$,I,MW$G$J$$>l9g(B} + +%Since Mercurial's tags are revision controlled and carried around with +%a project's history, everyone you work with will see the tags you +%create. But giving names to revisions has uses beyond simply noting +%that revision \texttt{4237e45506ee} is really \texttt{v2.0.2}. If +%you're trying to track down a subtle bug, you might want a tag to +%remind you of something like ``Anne saw the symptoms with this +%revision''. + +Mercurial$B$N%?%0$O%j%S%8%g%s%3%s%H%m!<%k$5$l!$%W%m%8%'%/%HMzNr$KIU?o$7$F$$(B +$B$k$?$a!$F1$8%W%m%8%'%/%H$GF/$/?M$O3'%?%0$rCN$k$3$H$K$J$k!%%j%S%8%g%s$KL>(B +$BA0$rIU$1$k$3$H$O!$C1$K%j%S%8%g%s(B\texttt{4237e45506ee}$B$,%P!<%8%g%s(B +\texttt{v2.0.2}$B$G$"$k$H5-=R$9$k0J>e$N0UL#$r;}$D!%$b$7%P%0$rDI@W$7$F$$$k$J(B +$B$i!$(B``Anne saw the symptoms with this revision''$B!J%"%s$O$3$N%j%S%8%g%s$G(B +$B>I>u$r8+$?!K$J$I$N%?%0$rIU$1$?$/$J$k$@$m$&!%(B + +%For cases like this, what you might want to use are \emph{local} tags. +%You can create a local tag with the \hgopt{tag}{-l} option to the +%\hgcmd{tag} command. This will store the tag in a file called +%\sfilename{.hg/localtags}. Unlike \sfilename{.hgtags}, +%\sfilename{.hg/localtags} is not revision controlled. Any tags you +%create using \hgopt{tag}{-l} remain strictly local to the repository +%you're currently working in. + +$B$3$N$h$&$J>l9g!$(B\emph{$B%m!<%+%k(B}$B%?%0$r;H$$$?$/$J$k$O$:$@!%%m!<%+%k%?%0$O(B +\hgcmd{tag}$B%3%^%s%I$r(B\hgopt{tag}{-l}$B%*%W%7%g%sIU$-$G;H$&$3$H$G:n@.$G$-$k!%(B +$B$3$N%*%W%7%g%s$r;H$&$H!$%?%0$O(B\sfilename{.hg/localtags}$B$H$$$&%U%!%$%k$KJ](B +$BB8$5$l$k!%(B\sfilename{.hgtags}$B$H0c$C$F!$(B\sfilename{.hg/localtags}$B$O%j%S%8%g(B +$B%s%3%s%H%m!<%k$5$l$J$$!%(B\hgopt{tag}{-l}$B%*%W%7%g%s$G:n@.$7$?$"$i$f$k%?%0(B +$B$O87L)$K%m!<%+%k$K4IM}$5$l!$:#:n6H$7$F$$$k$m%]%8<h$j$K$O0l@ZH?1G$5$l$J$$!%(B + + +%\section{The flow of changes---big picture vs. little} +\section{$B99?7$NN.$l(B---$BBg6IE*(B vs.$B6I=jE*(B} + +%To return to the outline I sketched at the beginning of a chapter, +%let's think about a project that has multiple concurrent pieces of +%work under development at once. + +$B$3$N>O$N:G=i$G<($7$?%"%&%H%i%$%s$KLa$k$?$a$K!$%W%m%8%'%/%H$,3+H/Cf!$0lEY(B +$B$KJ#?t$NJB9T$7$?ItJ,$r;}$D$H9M$($h$&!%(B + +%There might be a push for a new ``main'' release; a new minor bugfix +%release to the last main release; and an unexpected ``hot fix'' to an +%old release that is now in maintenance mode. + +$B?7$7$$(B``main''$B$r%j%j!<%9$9$k>u67$G!$:G?7$N%a%$%s%j%j!<%9$KBP$9$k?7$7$$>.(B +$B5,LO$J%P%0%U%#%C%/%9%j%j!<%9$H4{$K%a%s%F%J%s%9%b!<%I$K$J$C$F$$$k8E$$%j%j!<(B +$B%98~$1$NM=4|$;$L(B``hot fix'' $B$r%j%j!<%9$9$k>u67$r9M$($k!%(B + + +%The usual way people refer to these different concurrent directions of +%development is as ``branches''. However, we've already seen numerous +%times that Mercurial treats \emph{all of history} as a series of +%branches and merges. Really, what we have here is two ideas that are +%peripherally related, but which happen to share a name. +%\begin{itemize} +%\item ``Big picture'' branches represent the sweep of a project's +% evolution; people give them names, and talk about them in +% conversation. +%\item ``Little picture'' branches are artefacts of the day-to-day +% activity of developing and merging changes. They expose the +% narrative of how the code was developed. +%\end{itemize} + +$B?M!9$,!$0[$J$C$?JB9TE*$J3+H/$NJ}8~@-$K$D$$$F?($l$k;~$O!$(B``$B%V%i%s%A(B''$B$H$7(B +$B$F8@5Z$9$k!%$7$+$7!$4{$K4vEY$H$J$/(BMercurial$B$,(B\emph{$BA4$F$NMzNr(B}$B$r0lO"$N%V(B +$B%i%s%A$H%^!<%8$H$7$F<h$j07$C$F$$$k$N$r8+$F$-$?!%$3$3$G$O!$$o$:$+$K4XO"$7(B +$B$F$$$k$,L>A0$r6&M-$7$F$$$k(B2$B$D$N%"%$%G%#%"$r9M$($k!%(B +\begin{itemize} +\item ``Big picture''$B%V%i%s%A$O%W%m%8%'%/%H$N?J2=$rI=$9!%3+H/<T$O$3$l$i(B + $B$KL>A0$rM?$(!$2qOC$GMQ$$$k!%(B +\item ``Little picture''$B%V%i%s%A$OF|!9$N3+H/$H%^!<%8$N=j;:$G!$%3!<%I$,$I(B + $B$N$h$&$K3+H/$5$l$?$+$r<($9$b$N$G$"$k!%(B +\end{itemize} + +%\section{Managing big-picture branches in repositories} +\section{$B%j%]%8%H%j4V$G$NBg6IE*%V%i%s%A$N4IM}(B} + +%The easiest way to isolate a ``big picture'' branch in Mercurial is in +%a dedicated repository. If you have an existing shared +%repository---let's call it \texttt{myproject}---that reaches a ``1.0'' +%milestone, you can start to prepare for future maintenance releases on +%top of version~1.0 by tagging the revision from which you prepared +%the~1.0 release. +%\interaction{branch-repo.tag} +%You can then clone a new shared \texttt{myproject-1.0.1} repository as +%of that tag. +%\interaction{branch-repo.clone} + +Mercurial$B$G(B``bit picture''$B$r3VN%$9$k:G$b4JC1$JJ}K!$O!$@lMQ$N%j%]%8%H%j$r(B +$BMQ0U$9$k$3$H$G$"$k!%$b$70l$D$N6&M-%j%]%8%H%j$r;}$C$F$$$k>l9g!$$3$l$r(B +\texttt{myproject}$B$H8F$V$3$H$K$7$k!%$3$l$,(B``1.0''$B%^%$%k%9%H!<%s$KE~C#$7$?(B +$B$i!$(B1.0$B$K(B1.0$B%j%j!<%9$H%?%0$rIU$1!$>-Mh$N%a%s%F%J%s%9%j%j!<%9$KHw$($k$3$H(B +$B$,$G$-$k!%(B +\interaction{branch-repo.tag} +$B$=$7$F?7$?$K(B\texttt{myproject-1.0.1}$B$H%?%0$rIU$1$F%j%]%8%H%j$r%/%m!<%s$9(B +$B$k!%(B +\interaction{branch-repo.clone} + +%Afterwards, if someone needs to work on a bug fix that ought to go +%into an upcoming~1.0.1 minor release, they clone the +%\texttt{myproject-1.0.1} repository, make their changes, and push them +%back. +%\interaction{branch-repo.bugfix} +%Meanwhile, development for the next major release can continue, +%isolated and unabated, in the \texttt{myproject} repository. +%\interaction{branch-repo.new} + +$B0J8e!$%P%0%U%#%C%/%9$r$7$?$$?M$O(B1.0.1$B%^%$%J!<%j%j!<%9$X$$$/$Y$-$G$"$k!%(B +$BH`$i$O(B\texttt{myproject-1.0.1}$B%j%]%8%H%j$r%/%m!<%s$7!$JQ99$r2C$(!$%W%C%7%e(B +$B$9$k!%(B +\interaction{branch-repo.bugfix} +$B0lJ}$G<!$N%a%8%c!<%j%j!<%9$K8~$1$F$N3+H/$O!$(B\texttt{myproject}$B%j%]%8%H%j(B +$B$NCf$G3VN%$5$l!$BZ$k;v$J$/7QB3$9$k$3$H$,2DG=$G$"$k!%(B +\interaction{branch-repo.new} + +%\section{Don't repeat yourself: merging across branches} +\section{$B<j$G7+$jJV$5$J$$$3$H!'%V%i%s%A4V$G$N%^!<%8(B} + +%In many cases, if you have a bug to fix on a maintenance branch, the +%chances are good that the bug exists on your project's main branch +%(and possibly other maintenance branches, too). It's a rare developer +%who wants to fix the same bug multiple times, so let's look at a few +%ways that Mercurial can help you to manage these bugfixes without +%duplicating your work. + +$B%a%s%F%J%s%9%V%i%s%A$G=$@5$9$Y$-%P%0$,$"$k$H$-!$B?$/$N>l9g!$%a%$%s%V%i%s(B +$B%A$K$=$N%P%0$,$"$k2DG=@-$O9b$$!%!J$5$i$KB>$N%a%s%F%J%s%9%V%i%s%A$K$*$$$F(B +$B$b!%!K%P%0$N=$@5$r2?EY$b7+$jJV$7$?$$$H;W$&3+H/<T$O$^$:$$$J$$!%$=$3$G%P%0(B +$B=$@5$r7+$jJV$9Be$o$j$N$G$O$J$/!$(BMercurial$B$G2r7h$G$-$k$$$/$D$+$NJ}K!$r8+(B +$B$F$_$k$3$H$K$7$h$&!%(B + +%In the simplest instance, all you need to do is pull changes from your +%maintenance branch into your local clone of the target branch. +%\interaction{branch-repo.pull} +%You'll then need to merge the heads of the two branches, and push back +%to the main branch. +%\interaction{branch-repo.merge} + +$B:G$b4JC1$J$N$O!$%a%s%F%J%s%9%V%i%s%A$+$iJQ99$r%?!<%2%C%H%V%i%s%A$N%m!<%+(B +$B%k%/%m!<%s$K(Bpull$B$9$kJ}K!$G$"$k!%(B +\interaction{branch-repo.pull} +$B$=$N8e(B2$B$D$N%V%i%s%A$N%X%C%IF1;N$r%^!<%8$7!$%a%$%s%V%i%s%A$X%W%C%7%e$9$k!%(B +\interaction{branch-repo.merge} + +%\section{Naming branches within one repository} +\section{1$B$D$N%j%]%8%H%jFb$G$N%V%i%s%A$NL?L>(B} + +%In most instances, isolating branches in repositories is the right +%approach. Its simplicity makes it easy to understand; and so it's +%hard to make mistakes. There's a one-to-one relationship between +%branches you're working in and directories on your system. This lets +%you use normal (non-Mercurial-aware) tools to work on files within a +%branch/repository. + +$BB?$/$N>l9g!$%V%i%s%AKh$KJ#?t$N%j%]%8%H%j$rMQ0U$73VN%$9$k$N$O@5$7$$%"%W%m!<(B +$B%A$G$"$k!%$3$l$OC1=c$J$?$aGD0.$,MF0W$G$"$j!$<:GT$rHH$92DG=@-$,Dc$$!%:n6H(B +$B$7$F$$$k%V%i%s%A$H%G%#%l%/%H%j$N4V$K$O(B1$BBP(B1$B$N4X78$,$"$k!%(BMercurial$B$r9MN8$7(B +$B$J$$DL>o$N%D!<%k$r%V%i%s%A!?%j%]%8%H%jFb$N%U%!%$%k$KBg$7$F;H$&$3$H$b2DG=(B +$B$G$"$k!%(B + +%If you're more in the ``power user'' category (\emph{and} your +%collaborators are too), there is an alternative way of handling +%branches that you can consider. I've already mentioned the +%human-level distinction between ``small picture'' and ``big picture'' +%branches. While Mercurial works with multiple ``small picture'' +%branches in a repository all the time (for example after you pull +%changes in, but before you merge them), it can \emph{also} work with +%multiple ``big picture'' branches. + +$B$"$J$?$H!J$"$J$?$N6(NO<T$,(B\emph{$B6&$K(B}$B!K(B``$B%Q%o!<%f!<%6(B''$B0J>e$N%+%F%4%j$KB0(B +$B$9$J$i!$%V%i%s%A$r<h$j07$&JL$NJ}K!$b9M$($i$l$k!%$9$G$K(B``$B6I=jE*$J%b%G%k(B'' +$B$H(B``$BBg6IE*$J%b%G%k(B''$B$H$$$&!$6hJL$K$D$$$F?($l$?!%(BMercurial$B$O!$J#?t$N(B``$B6I=j(B +$BE*$J(B''$B%V%i%s%A!J$?$H$($PJQ99$r(Bpull$B$7$F%^!<%8$7$F$$$J$$>l9g$J$I!KMQ$$$k$3(B +$B$H$,$G$-$k0lJ}$G!$J#?t$N(B``$BBg6IE*$J(B''$B%V%i%s%A$rMQ$$$k$3$H(B\emph{$B$b(B}$B$G$-$k!%(B + +%The key to working this way is that Mercurial lets you assign a +%persistent \emph{name} to a branch. There always exists a branch +%named \texttt{default}. Even before you start naming branches +%yourself, you can find traces of the \texttt{default} branch if you +%look for them. + +$B$3$NJ}K!$rMQ$$$k:]$N80$O!$(BMercurial$B$K$h$C$F%V%i%s%A$K1JB3E*$J(B\emph{$BL>A0(B} +$B$rIU$1$k$3$H$G$"$k!%%V%i%s%A$KL>A0$rIU$1$kA0$G$b!$(B\texttt{default}$B%V%i%s(B +$B%A$N%H%l!<%9$r8+$k$3$H$,$G$-$k!%(B + +%As an example, when you run the \hgcmd{commit} command, and it pops up +%your editor so that you can enter a commit message, look for a line +%that contains the text ``\texttt{HG: branch default}'' at the bottom. +%This is telling you that your commit will occur on the branch named +%\texttt{default}. + +$BNc$H$7$F!$(B\hgcmd{commit}$B%3%^%s%I$r<B9T$7!$%3%_%C%H%a%C%;!<%8$r=q$/$?$a$K(B +$B%(%G%#%?$,5/F0$5$l$?;~!$:G2<It$N(B``\texttt{HG: branch default}''$B$H$$$&9T(B +$B$r8+$F$[$7$$!%$3$N9T$O%3%_%C%H$,(B\texttt{default}$B$H$$$&L>A0$N%V%i%s%A$KBP(B +$B$7$F9T$o$l$k$3$H$r<($7$F$$$k!%(B + +%To start working with named branches, use the \hgcmd{branches} +%command. This command lists the named branches already present in +%your repository, telling you which changeset is the tip of each. +%\interaction{branch-named.branches} +%Since you haven't created any named branches yet, the only one that +%exists is \texttt{default}. + +$BL>A0IU$-%V%i%s%A$r;H$&$K$"$?$C$F!$$^$:(B\hgcmd{branches}$B$r;H$$!$%j%]%8%H%j(B +$BFb$K$9$G$KB8:_$9$kL>A0IU$-%V%i%s%A$rNs5s$9$k$3$H$+$i;O$a$k!%$3$N%3%^%s%I(B +$B$K$h$C$F$=$l$>$l$N%V%i%s%A$N(Btip$B$K$J$C$F$$$k%A%'%s%8%;%C%H$,$o$+$k!%(B +\interaction{branch-named.branches} +$B$3$3$G$O$^$@L>A0IU$-%V%i%s%A$r:n$C$F$$$J$$$N$G!$(B\texttt{default}$B%V%i%s%A(B +$B$@$1$,B8:_$9$k!%(B + +%To find out what the ``current'' branch is, run the \hgcmd{branch} +%command, giving it no arguments. This tells you what branch the +%parent of the current changeset is on. +%\interaction{branch-named.branch} + +$B8=:_$N%V%i%s%A$,2?$J$N$+$rCN$k$?$a$K$O!$(B\hgcmd{branch}$B%3%^%s%I$r0z?t$J$7(B +$B$G<B9T$9$k!%$3$N%3%^%s%I$G8=:_$N%A%'%s%8%;%C%H$N?F%V%i%s%A$,$o$+$k!%(B +\interaction{branch-named.branch} + +%To create a new branch, run the \hgcmd{branch} command again. This +%time, give it one argument: the name of the branch you want to create. +%\interaction{branch-named.create} + +$B?7$7$$%V%i%s%A$r:n$k$N$K$b(B\hgcmd{branch}$B%3%^%s%I$r;H$&!%$3$N>l9g$O!$:n@.(B +$B$7$?$$%V%i%s%A$NL>A0$r0z?t$H$7$FEO$9!%(B +\interaction{branch-named.create} + +%After you've created a branch, you might wonder what effect the +%\hgcmd{branch} command has had. What do the \hgcmd{status} and +%\hgcmd{tip} commands report? +%\interaction{branch-named.status} +%Nothing has changed in the working directory, and there's been no new +%history created. As this suggests, running the \hgcmd{branch} command +%has no permanent effect; it only tells Mercurial what branch name to +%use the \emph{next} time you commit a changeset. + +$B%V%i%s%A$r:n$C$?8e$G(B\hgcmd{branch}$B%3%^%s%I$,$I$N$h$&$J8z2L$r;}$C$F$$$k$N(B +$B$+J,$+$i$J$$$+$b$7$l$J$$!%(B\hgcmd{status}$B%3%^%s%I$H(B\hgcmd{tip}$B%3%^%s%I$O(B +$B$=$l$>$l2?$rI=<($9$k$@$m$&$+!)(B +\interaction{branch-named.status} +$B%o!<%-%s%0%G%#%l%/%H%jFb$G$O2?$bJQ2=$O5/$-$:!$2?$N%R%9%H%j$b@8@.$5$l$F$$(B +$B$J$$!%$3$l$+$iJ,$+$k$h$&$K!$(B\hgcmd{branch}$B%3%^%s%I$r<B9T$7$F$b!$1JB3E*$J(B +$B8z2L$O2?$b5/$-$J$$!%$3$N%3%^%s%I$O(B\emph{$B<!$N(B}$B%A%'%s%8%;%C%H$N%3%_%C%H$,(B +$B$I$N%V%i%s%A$KBP$7$F9T$o$l$k$+$r(BMercurial$B%3%^%s%I$K<($9$N$K;H$o$l$k!%(B + +%When you commit a change, Mercurial records the name of the branch on +%which you committed. Once you've switched from the \texttt{default} +%branch to another and committed, you'll see the name of the new branch +%show up in the output of \hgcmd{log}, \hgcmd{tip}, and other commands +%that display the same kind of output. +%\interaction{branch-named.commit} +%The \hgcmd{log}-like commands will print the branch name of every +%changeset that's not on the \texttt{default} branch. As a result, if +%you never use named branches, you'll never see this information. + +$BJQ99$r%3%_%C%H$9$k;~!$(BMercurial$B$O%3%_%C%H$9$k$NBP>]$K$J$k%V%i%s%A$NL>A0(B +$B$r5-O?$9$k!%$R$H$?$S(B\texttt{default}$B$+$iB>$XJQ99$9$l$P!$?7$7$$%V%i%s%AL>(B +$B$,(B\hgcmd{log}$B$d(B\hgcmd{tip}$B$N=PNO$K4^$^$l$k$N$,8+$F<h$l$k$@$m$&!%(B +\interaction{branch-named.commit} +\hgcmd{log}$B$N$h$&$J%3%^%s%I$O!$(B\texttt{default}$B%V%i%s%A0J30$KB0$9$k$9$Y$F(B +$B$N%A%'%s%8%;%C%H$KBP$7$F%V%i%s%AL>$rI=<($9$k!%%V%i%s%A$KL>A0$rIU$1$F$$$J(B +$B$$>l9g$O$3$N=PNO$rL\$K$9$k$3$H$O$J$$!%(B + +%Once you've named a branch and committed a change with that name, +%every subsequent commit that descends from that change will inherit +%the same branch name. You can change the name of a branch at any +%time, using the \hgcmd{branch} command. +%\interaction{branch-named.rebranch} +%In practice, this is something you won't do very often, as branch +%names tend to have fairly long lifetimes. (This isn't a rule, just an +%observation.) + +$B%V%i%s%A$KL>A0$rIU$1!$$=$NL>A0$r;H$C$FJQ99$N%3%_%C%H$r9T$&$H!$0J8e$KB3$/(B +$BA4$F$N%3%_%C%H$OF1$8L>A0$r;}$D!%L>A0$NJQ99$O(B\hgcmd{branch}$B%3%^%s%I$r;H$&$3(B +$B$H$G$O$$$D$G$b2DG=$@!%(B +\interaction{branch-named.rebranch} +$B<BMQ$K$*$$$F$O!$%V%i%s%AL>$O$+$J$jD9$$4|4V;H$o$l$k798~$,$"$j!$JQ99$OIQHK(B +$B$K$O9T$o$l$J$$!%!J$3$l$OK!B'$H8@$($k$h$&$J$b$N$G$O$J$/!$C1$J$k4QB,7k2L$G(B +$B$"$k!%!K(B + +%\section{Dealing with multiple named branches in a repository} +\section{$B%j%]%8%H%jFb$GJ#?t$NL>A0$NIU$$$?%V%i%s%A$N<h$j07$$(B} + +%If you have more than one named branch in a repository, Mercurial will +%remember the branch that your working directory on when you start a +%command like \hgcmd{update} or \hgcmdargs{pull}{-u}. It will update +%the working directory to the tip of this branch, no matter what the +%``repo-wide'' tip is. To update to a revision that's on a different +%named branch, you may need to use the \hgopt{update}{-C} option to +%\hgcmd{update}. + +1$B$D$N%j%]%8%H%jFb$K(B2$B$D0J>e$N%V%i%s%A$r;}$C$F$$$k>l9g!$(BMercurial$B$O!$(B +\hgcmd{update}$B$d(B\hgcmdargs{pull}{-u}$B$N$h$&$J%3%^%s%I$rN)$A>e$2$k$H$-$K!$(B +$B%o!<%-%s%0%G%#%l%/%H%j$,$I$N%V%i%s%A$G$"$k$+5-21$7$F$$$k!%(B +$B$3$l$i$N%3%^%s%I$O!$%j%]%8%H%jA4BN$G$N(Btip$B$,2?$G$"$k$+$K$O4X78$J$/!$%o!<%-(B +$B%s%0%G%#%l%/%H%j$r8=:_$N%V%i%s%A$N(Btip$B$K99?7$9$k!%(B +$BB>$NL>A0$D$-%V%i%s%A$KB0$9%j%S%8%g%s$X99?7$9$k$K$O!$(B\hgopt{update}{-C}$B%*(B +$B%W%7%g%sIU$-$G(B\hgcmd{update}$B%3%^%s%I$r<B9T$9$kI,MW$,$"$k$+$b$7$l$J$$!%(B + +%This behaviour is a little subtle, so let's see it in action. First, +%let's remind ourselves what branch we're currently on, and what +%branches are in our repository. +%\interaction{branch-named.parents} +%We're on the \texttt{bar} branch, but there also exists an older +%\texttt{foo} branch. + +$B$3$N$U$k$^$$$O$d$d4q0[$+$b$7$l$J$$!%<B:]$NF0:n$r8+$F$_$k$3$H$K$9$k!%$^$:(B +$B2f!9$,$I$N%V%i%s%A$K$$$k$+$rD4$Y!$%j%]%8%H%j$K$I$s$J%V%i%s%A$,$"$k$+8+$F(B +$B$_$h$&!%(B +\interaction{branch-named.parents} +$B:#$$$k$N$O(B\texttt{bar}$B%V%i%s%A$G!$(B\texttt{foo}$B%V%i%s%A$bB8:_$9$k!%(B + +%We can \hgcmd{update} back and forth between the tips of the +%\texttt{foo} and \texttt{bar} branches without needing to use the +%\hgopt{update}{-C} option, because this only involves going backwards +%and forwards linearly through our change history. +%\interaction{branch-named.update-switchy} + +\texttt{foo}$B$H(B\texttt{bar}$B$N(Btip$B$N4V$r(B\hgcmd{update}$B%3%^%s%I$G9T$-Mh$9$k$3(B +$B$H$,$G$-$k!%$3$NA`:n$O99?7MzNr$NCf$r@~7A$K0\F0$9$k$@$1$J$N$G!$(B +\hgopt{update}{-C}$B%*%W%7%g%s$OI,MW$J$$!%(B +\interaction{branch-named.update-switchy} + +%If we go back to the \texttt{foo} branch and then run \hgcmd{update}, +%it will keep us on \texttt{foo}, not move us to the tip of +%\texttt{bar}. +%\interaction{branch-named.update-nothing} + +\texttt{foo}$B%V%i%s%A$XLa$j!$(B\hgcmd{update}$B$r<B9T$7$F$b!$(B\texttt{bar}$B$N(B +tip$B$K$O0\F0$;$:!$(B\texttt{foo}$B$N$^$^$G$"$k!%(B +\interaction{branch-named.update-nothing} + +%Committing a new change on the \texttt{foo} branch introduces a new +%head. +%\interaction{branch-named.foo-commit} +%We can no longer update from \texttt{foo} to \texttt{bar} without +%going ``sideways'' in history, so Mercurial forces us to provide the +%\hgopt{update}{-C} option to \hgcmd{update}. +%\interaction{branch-named.update-bar} + +$B?7$7$$JQ99$r(B\texttt{foo}$B$K%3%_%C%H$9$k$H!$?7$7$$(Bhead$B$,:n$i$l$k!%(B +\interaction{branch-named.foo-commit} +$B$b$O$d(B\texttt{foo}$B$+$i(B\texttt{bar}$B$X$O!$OFF;$K0o$l$k$3$H$J$/99?7$9$k$3$H(B +$B$O$G$-$J$$!%$=$3$G!$(B\hgopt{update}{-C}$B%*%W%7%g%s$r;H$C$F(B\hgcmd{update}$B$r(B +$B<B9T$9$k$3$H$,I,MW$K$J$k!%(B +\interaction{branch-named.update-bar} + +%\section{Branch names and merging} +\section{$B%V%i%s%AL>$H%^!<%8(B} + +%As you've probably noticed, merges in Mercurial are not symmetrical. +%Let's say our repository has two heads, 17 and 23. If I +%\hgcmd{update} to 17 and then \hgcmd{merge} with 23, Mercurial records +%17 as the first parent of the merge, and 23 as the second. Whereas if +%I \hgcmd{update} to 23 and then \hgcmd{merge} with 17, it records 23 +%as the first parent, and 17 as the second. + +$B$*$=$i$/5$$E$$$F$$$k$3$H$H;W$&$,!$(BMercurial$B$G$N%^!<%8$OBP>NE*$G$O$J$$!%(B +$B:#!$%j%]%8%H%j$,(B17$B$H(B23$B$H$$$&(B2$B$D$N(Bhead$B$r;}$D$H$7$h$&!%$3$3$G(B +\hgcmd{update}$B$G(B17$B$K99?7$7!$(B\hgcmd{merge}$B$K$h$C$F(B23$B$H%^!<%8$9$k$H!$(B +Mercurial$B$O(B17$B$r%^!<%8$N:G=i$N?F!$(B23$B$r(B2$BHVL\$N?F$H$7$F5-O?$9$k!%5U$K(B +\hgcmd{update}$B$G(B23$B$K99?7$7!$(B\hgcmd{merge}$B$G(B17$B$H%^!<%8$9$l$P!$(B23$B$r:G=i$N(B +$B?F!$(B17$B$r(B2$BHVL\$N?F$H5-O?$9$k!%(B + +%This affects Mercurial's choice of branch name when you merge. After +%a merge, Mercurial will retain the branch name of the first parent +%when you commit the result of the merge. If your first parent's +%branch name is \texttt{foo}, and you merge with \texttt{bar}, the +%branch name will still be \texttt{foo} after you merge. + +$B$3$l$O%^!<%8$N:]$K(BMercurial$B$,%V%i%s%AL>$r$I$N$h$&$KA*$V$+$K1F6A$rM?$($k!%(B +$B%^!<%88e!"%^!<%8$N7k2L$r%3%_%C%H$9$k:]$K(BMercurial$B$O(B1$BHVL\$N?F$N%V%i%s%AL>(B +$B$rMQ$$$k!%(B1$BHVL\$N?F$N%V%i%s%AL>$,(B\texttt{foo}$B$G!$(B\texttt{bar}$B$H%^!<%8$r(B +$B9T$J$C$?$H$9$k$H!$%^!<%88e$N%V%i%s%AL>$O(B\texttt{foo}$B$H$J$k!%(B + +%It's not unusual for a repository to contain multiple heads, each with +%the same branch name. Let's say I'm working on the \texttt{foo} +%branch, and so are you. We commit different changes; I pull your +%changes; I now have two heads, each claiming to be on the \texttt{foo} +%branch. The result of a merge will be a single head on the +%\texttt{foo} branch, as you might hope. + +1$B$D$N%j%]%8%H%j$,F1$8%V%i%s%AL>$r;}$D$$$/$D$b$N(Bhead$B$r;}$C$F$$$k$3$H$ODA$7(B +$B$$$3$H$G$O$J$$!%:#!$;d$H$"$J$?$,F1$8(B\texttt{foo}$B%V%i%s%A$G:n6H$r$7$F$*$j!$(B +$B$=$l$>$l0[$J$C$?JQ99$r%3%_%C%H$9$k$H$7$h$&!%$"$J$?$N9T$J$C$?JQ99$r;d$,(B +pull$B$9$k$H!$;d$O(B\texttt{foo}$B%V%i%s%A$K(B2$B$D$N(Bhead$B$r;}$D$3$H$K$J$k!%%^!<%8(B +$B$N7k2L$O!$$"$J$?$,4|BT$9$k$h$&$K(B\texttt{foo}$B%V%i%s%A>e$G(B1$B$D$N(Bhead$B$K$J$k!%(B + +%But if I'm working on the \texttt{bar} branch, and I merge work from +%the \texttt{foo} branch, the result will remain on the \texttt{bar} +%branch. +%\interaction{branch-named.merge} + +$B$7$+$7!$;d$,(B\texttt{bar}$B%V%i%s%A$G:n6H$r$7$F$$$F!$(B\texttt{foo}$B%V%i%s%A$+(B +$B$i%^!<%8$r9T$J$&$H!$@.2LJ*$O(B\texttt{bar}$B%V%i%s%A$K;D$k$3$H$K$J$k!%(B +\interaction{branch-named.merge} + +%To give a more concrete example, if I'm working on the +%\texttt{bleeding-edge} branch, and I want to bring in the latest fixes +%from the \texttt{stable} branch, Mercurial will choose the ``right'' +%(\texttt{bleeding-edge}) branch name when I pull and merge from +%\texttt{stable}. + +$B$b$C$H6qBNE*$JNc$r5s$2$k$H!$$b$7;d$,(B\texttt{bleeding-edge}$B%V%i%s%A$G:n6H(B +$B$r$7$F$$$F!$(B\texttt{stable}$B%V%i%s%A$N?7$7$$=$@5$r<h$j9~$`$?$a$K(B +\texttt{stable}$B$+$i(Bpull$B$H(Bmerge$B$r9T$J$&$H!$(BMercurial$B$O(B``$B@5$7$$(B''$B%V%i%s%AL>(B +(\texttt{bleeding-edge})$B$rA*$V!%(B + +%\section{Branch naming is generally useful} +\section{$B%V%i%s%A$KL>A0$rIU$1$k$3$H$OLr$KN)$D(B} + +%You shouldn't think of named branches as applicable only to situations +%where you have multiple long-lived branches cohabiting in a single +%repository. They're very useful even in the one-branch-per-repository +%case. + +$BL>A0IU$-%V%i%s%A$r(B1$B$D$N%j%]%8%H%j$NCf$KD9L?$J%V%i%s%A$rJ#?t;}$D>u67$K$N$_(B +$BMQ$$$k$Y$-$@$H9M$($k$Y$-$G$O$J$$!%L>A0IU$-%V%i%s%A$O%V%i%s%AKh$K%j%]%8%H(B +$B%j$r;}$D>l9g$G$b6K$a$FM-MQ$G$"$k!%(B + +%In the simplest case, giving a name to each branch gives you a +%permanent record of which branch a changeset originated on. This +%gives you more context when you're trying to follow the history of a +%long-lived branchy project. + +$B:G$bC1=c$JNc$O!$$=$l$>$l$N%V%i%s%A$KL>A0$rM?$($k$3$H$G!$%A%'%s%8%;%C%H$,(B +$B$I$N%V%i%s%A$r5/8;$K;}$D$N$+1JB3E*$K5-O?$9$k$3$H$,$G$-$k!%$3$l$K$h$j!$D9(B +$BL?$J%V%i%s%A$r;}$D%W%m%8%'%/%H$NNr;K$rDI$$$+$1$k;~$K!$A08e4X78$,DO$_$d$9(B +$B$/$J$k!%(B + +%If you're working with shared repositories, you can set up a +%\hook{pretxnchangegroup} hook on each that will block incoming changes +%that have the ``wrong'' branch name. This provides a simple, but +%effective, defence against people accidentally pushing changes from a +%``bleeding edge'' branch to a ``stable'' branch. Such a hook might +%look like this inside the shared repo's \hgrc. +%\begin{codesample2} +% [hooks] +% pretxnchangegroup.branch = hg heads --template '{branches} ' | grep mybranch +%\end{codesample2} + +$B6&M-%j%]%8%H%j$r;H$C$F:n6H$7$F$$$k>l9g!$(B\hook{pretxnchangegroup}$B%U%C%/$r(B +$B@_Dj$9$k$3$H$G4V0c$C$?%V%i%s%AL>$r;}$D99?7$r%V%m%C%/$9$k$3$H$,$G$-$k!%$3(B +$B$l$ONc$($P(B``$B:G@hC<(B''$B%V%i%s%A$+$i(B``$B0BDj(B''$B%V%i%s%A$XJQ99$r(Bpush$B$9$k$h$&$J4V(B +$B0c$$$rKI$0$N$K%7%s%W%k$+$D8z2LE*$JJ}K!$G$"$k!%%U%C%/$O!$Nc$($P6&M-%j%]%8(B +$B%H%j$N(B \hgrc $B$K(B +\begin{codesample2} + [hooks] + pretxnchangegroup.branch = hg heads --template '{branches} ' | grep mybranch +\end{codesample2} +$B$N$h$&$K5-=R$5$l$k!%(B + + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/cmdref.py Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,156 @@ +#!/usr/bin/env python + +import getopt +import itertools +import os +import re +import sys + +def usage(exitcode): + print >> sys.stderr, ('usage: %s [-H|--hidden] hg_repo' % + os.path.basename(sys.argv[0])) + sys.exit(exitcode) + +try: + opts, args = getopt.getopt(sys.argv[1:], 'AHh?', ['all', 'help', 'hidden']) + opt_all = False + opt_hidden = False + for o, a in opts: + if o in ('-h', '-?', '--help'): + usage(0) + if o in ('-A', '--all'): + opt_all = True + if o in ('-H', '--hidden'): + opt_hidden = True +except getopt.GetoptError, err: + print >> sys.stderr, 'error:', err + usage(1) + +try: + hg_repo, ltx_file = args +except ValueError: + usage(1) + +if not os.path.isfile(os.path.join(hg_repo, 'mercurial', 'commands.py')): + print >> sys.stderr, ('error: %r does not contain mercurial code' % + hg_repo) + sys.exit(1) + +sys.path.insert(0, hg_repo) + +from mercurial import commands + +def get_commands(): + seen = {} + for name, info in sorted(commands.table.iteritems()): + aliases = name.split('|', 1) + name = aliases.pop(0).lstrip('^') + function, options, synopsis = info + seen[name] = {} + for shortopt, longopt, arg, desc in options: + seen[name][longopt] = shortopt + return seen + +def cmd_filter((name, aliases, options)): + if opt_all: + return True + if opt_hidden: + return name.startswith('debug') + return not name.startswith('debug') + +def scan(ltx_file): + cmdref_re = re.compile(r'^\\cmdref{(?P<cmd>\w+)}') + optref_re = re.compile(r'^\\l?optref{(?P<cmd>\w+)}' + r'(?:{(?P<short>[^}])})?' + r'{(?P<long>[^}]+)}') + + seen = {} + locs = {} + for lnum, line in enumerate(open(ltx_file)): + m = cmdref_re.match(line) + if m: + d = m.groupdict() + cmd = d['cmd'] + seen[cmd] = {} + locs[cmd] = lnum + 1 + continue + m = optref_re.match(line) + if m: + d = m.groupdict() + seen[d['cmd']][d['long']] = d['short'] + continue + return seen, locs + +documented, locs = scan(ltx_file) +known = get_commands() + +doc_set = set(documented) +known_set = set(known) + +errors = 0 + +for nonexistent in sorted(doc_set.difference(known_set)): + print >> sys.stderr, ('%s:%d: %r command does not exist' % + (ltx_file, locs[nonexistent], nonexistent)) + errors += 1 + +def optcmp(a, b): + la, sa = a + lb, sb = b + sc = cmp(sa, sb) + if sc: + return sc + return cmp(la, lb) + +for cmd in doc_set.intersection(known_set): + doc_opts = documented[cmd] + known_opts = known[cmd] + + do_set = set(doc_opts) + ko_set = set(known_opts) + + for nonexistent in sorted(do_set.difference(ko_set)): + print >> sys.stderr, ('%s:%d: %r option to %r command does not exist' % + (ltx_file, locs[cmd], nonexistent, cmd)) + errors += 1 + + def mycmp(la, lb): + sa = known_opts[la] + sb = known_opts[lb] + return optcmp((la, sa), (lb, sb)) + + for undocumented in sorted(ko_set.difference(do_set), cmp=mycmp): + print >> sys.stderr, ('%s:%d: %r option to %r command not documented' % + (ltx_file, locs[cmd], undocumented, cmd)) + shortopt = known_opts[undocumented] + if shortopt: + print '\optref{%s}{%s}{%s}' % (cmd, shortopt, undocumented) + else: + print '\loptref{%s}{%s}' % (cmd, undocumented) + errors += 1 + sys.stdout.flush() + +if errors: + sys.exit(1) + +sorted_locs = sorted(locs.iteritems(), key=lambda x:x[1]) + +def next_loc(cmd): + for i, (name, loc) in enumerate(sorted_locs): + if name >= cmd: + return sorted_locs[i-1][1] + 1 + return loc + +for undocumented in sorted(known_set.difference(doc_set)): + print >> sys.stderr, ('%s:%d: %r command not documented' % + (ltx_file, next_loc(undocumented), undocumented)) + print '\cmdref{%s}' % undocumented + for longopt, shortopt in sorted(known[undocumented].items(), cmp=optcmp): + if shortopt: + print '\optref{%s}{%s}{%s}' % (undocumented, shortopt, longopt) + else: + print '\loptref{%s}{%s}' % (undocumented, longopt) + sys.stdout.flush() + errors += 1 + +sys.exit(errors and 1 or 0)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/cmdref.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,287 @@ +%\chapter{Command reference} +\chapter{$B%3%^%s%I%j%U%!%l%s%9(B} +\label{cmdref} + +\cmdref{add}{$B<!2s$N%3%_%C%H$G%U%!%$%k$rDI2C(B} +\optref{add}{I}{include} +\optref{add}{X}{exclude} +\optref{add}{n}{dry-run} + +\cmdref{diff}{$B%R%9%H%j$^$?$O%o!<%-%s%0%G%#%l%/%H%jFb$NJQ99$rI=<((B} + +%Show differences between revisions for the specified files or +%directories, using the unified diff format. For a description of the +%unified diff format, see section~\ref{sec:mq:patch}. + +$B;XDj$7$?%U%!%$%k!"%G%#%l%/%H%j$K$D$$$F%j%S%8%g%s4V$G$N:9J,$rI=<($9$k!#(B +$BI=<($K$O(Bunified diff$B%U%)!<%^%C%H$,MQ$$$i$l$k!#(Bunified diff$B%U%)!<%^%C%H(B +$B$K$D$$$F$N@bL@$O(B\ref{sec:mq:patch}$B$r;2>H$N$3$H!#(B + +%By default, this command does not print diffs for files that Mercurial +%considers to contain binary data. To control this behaviour, see the +%\hgopt{diff}{-a} and \hgopt{diff}{--git} options. + +$B%G%U%)%k%H$G$O%P%$%J%j%G!<%?$H9M$($i$l$k%U%!%$%k$N:9J,$O=PNO$7$J$$!%$3$N(B +$B5sF0$O(B\hgopt{diff}{-a} $B$H(B \hgopt{diff}{--git}$B$K$h$C$FJQ99$G$-$k!%(B + + +\subsection{$B%*%W%7%g%s(B} + +\loptref{diff}{nodates} + +%Omit date and time information when printing diff headers. + +diff$B%X%C%@$+$iF|IU$H;~4V>pJs$r>JN,$9$k!%(B + +\optref{diff}{B}{$B6u9T$rL5;k$9$k(B} + +%Do not print changes that only insert or delete blank lines. A line +%that contains only whitespace is not considered blank. + +$B6u9T$NA^F~$^$?$O:o=|$@$1$NJQ99$rI=<($7$J$$!%6uGrJ8;z$,4^$^$l$k9T$O6u9T$H(B +$B$O8+$J$5$l$J$$!%(B + +\optref{diff}{I}{include} + +%Include files and directories whose names match the given patterns. + +$B;XDj$7$?%Q%?!<%s$H%^%C%A$9$k%U%!%$%k$^$?$O%G%#%l%/%H%j$rBP>]$K2C$($k(B + +\optref{diff}{X}{exclude} + +%Exclude files and directories whose names match the given patterns. + +$B;XDj$7$?%Q%?!<%s$H%^%C%A$9$k%U%!%$%k$^$?$O%G%#%l%/%H%j$rBP>]$+$i=|30$9$k(B + +\optref{diff}{a}{text} + +%If this option is not specified, \hgcmd{diff} will refuse to print +%diffs for files that it detects as binary. Specifying \hgopt{diff}{-a} +%forces \hgcmd{diff} to treat all files as text, and generate diffs for +%all of them. + +$B$3$N%*%W%7%g%s$,;XDj$5$l$J$1$l$P(B\hgcmd{diff}$B$O%P%$%J%j$HH=Dj$5$l$?%U%!%$(B +$B%k$KBP$9$k(Bdiff$B$N@8@.$r9T$J$o$J$$!%(B\hgopt{diff}{-a}$B$r;XDj$9$k$H(B +\hgcmd{diff}$B$OA4$F$N%U%!%$%k$r%F%-%9%H$H$7$F07$$!$A4$F$N%U%!%$%k$KBP$7$F(B +diff$B$r@8@.$9$k!%(B + +%This option is useful for files that are ``mostly text'' but have a +%few embedded NUL characters. If you use it on files that contain a +%lot of binary data, its output will be incomprehensible. + +$B$3$N%*%W%7%g%s$O!$$[$\A4$F$,%F%-%9%H$@$,0lIt$K(BNUL$BJ8;z$r4^$s$G$$$k$h$&$J%U%!(B +$B%$%k$KBP$7$FM-MQ$G$"$k!%$3$N%*%W%7%g%s$r%P%$%J%j%G!<%?$,B?$/4^$^$l$k%U%!(B +$B%$%k$KE,MQ$9$k$HL50UL#$J=PNO$K$J$k$@$m$&!%(B + +\optref{diff}{b}{ignore-space-change} + +%Do not print a line if the only change to that line is in the amount +%of white space it contains. + +$B6uGr$NJQ99$N$_$N9T$K$D$$$F=PNO$7$J$$!%(B + +\optref{diff}{g}{git} + +%Print \command{git}-compatible diffs. XXX reference a format +%description. + +\command{git}$B8_49$N(Bdiff$B$r=PNO$9$k!%(B + + +\optref{diff}{p}{show-function} + +%Display the name of the enclosing function in a hunk header, using a +%simple heuristic. This functionality is enabled by default, so the +%\hgopt{diff}{-p} option has no effect unless you change the value of +%the \rcitem{diff}{showfunc} config item, as in the following example. +%\interaction{cmdref.diff-p} + +$B%O%s%/%X%C%@$NCf$K4^$^$l$F$$$k4X?t$NL>A0$rI=<($9$k!%8!:w$OC1=c$JH/8+E*J}(B +$BK!$G9T$J$&!%$3$N5!G=$O%G%U%)%k%H$GM-8z$K$5$l$F$*$j!$(B\hgopt{diff}{-p}$B%*%W(B +$B%7%g%s$O2<$NNc$N$h$&$K(B\rcitem{diff}{showfunc}$B@_Dj$rJQ99$5$l$k$^$G0UL#$r$J(B +$B$5$J$$!%(B +\interaction{cmdref.diff-p} + +\optref{diff}{r}{rev} + +%Specify one or more revisions to compare. The \hgcmd{diff} command +%accepts up to two \hgopt{diff}{-r} options to specify the revisions to +%compare. + +$BHf3S$9$kBP>]$N%j%S%8%g%s$r0l$D0J>e;XDj$9$k!%(B\hgcmd{diff}$B%3%^%s%I$O!$(B +$BHf3S$9$k%j%S%8%g%s$r;XDj$9$k$?$a$K(B\hgopt{diff}{-r}$B%*%W%7%g%s$r(B2$B$D$^(B +$B$G<u$1IU$1$k!%(B + +%\begin{enumerate} +%\setcounter{enumi}{0} +%\item Display the differences between the parent revision of the +% working directory and the working directory. +%\item Display the differences between the specified changeset and the +% working directory. +%\item Display the differences between the two specified changesets. +%\end{enumerate} + +\begin{enumerate} +\setcounter{enumi}{0} +\item $B?F%j%S%8%g%s$N%o!<%-%s%0%G%#%l%/%H%j$H!$8=:_$N%o!<%-%s%0%G%#%l%/%H(B + $B%j$N:9J,$rI=<(!%(B +\item $B;XDj$5$l$?%A%'%s%8%;%C%H$H8=:_$N%o!<%-%s%0%G%#%l%/%H%j$N:9J,$rI=<(!%(B +\item $B;XDj$5$l$?(B2$B$D$N%A%'%s%8%;%C%H4V$N:9J,$rI=<(!%(B +\end{enumerate} + +%You can specify two revisions using either two \hgopt{diff}{-r} +%options or revision range notation. For example, the two revision +%specifications below are equivalent. + +2$B$D$N%j%S%8%g%s$r;XDj$9$kJ}K!$H$7$F!$(B\hgopt{diff}{-r}$B$r(B2$B$D;H$C$F$b$$$$$7!$(B +$B%j%S%8%g%s%l%s%85-K!$r;H$C$F$bNI$$!%Nc$($P!$2<$N(B2$B$D$N%j%S%8%g%s;XDj$OEy(B +$B2A$G$"$k!%(B +\begin{codesample2} + hg diff -r 10 -r 20 + hg diff -r10:20 +\end{codesample2} + +%When you provide two revisions, Mercurial treats the order of those +%revisions as significant. Thus, \hgcmdargs{diff}{-r10:20} will +%produce a diff that will transform files from their contents as of +%revision~10 to their contents as of revision~20, while +%\hgcmdargs{diff}{-r20:10} means the opposite: the diff that will +%transform files from their revision~20 contents to their revision~10 +%contents. You cannot reverse the ordering in this way if you are +%diffing against the working directory. + +2$B$D$N%j%S%8%g%s$r;XDj$9$k;~!$%j%S%8%g%s;XDj$N=g=x$K$O0UL#$,$"$k!%(B +\hgcmdargs{diff}{-r10:20}$B$O%U%!%$%k$NFbMF$,%j%S%8%g%s(B10$B$+$i%j%S%8%g%s(B20 +$B$KJQ$o$C$?$H$7$F:9J,$r:n@.$9$k!%(B\hgcmdargs{diff}{-r20:10}$B$G$"$l$P5U$N0U(B +$BL#$K$J$k!%%o!<%-%s%0%G%#%l%/%H%j$N:9J,$r<h$k>l9g$K$O$3$N$h$&$K%j%S%8%g%s(B +$B$N=g=x$r5U$K$9$k$3$H$O$G$-$J$$!%(B + +\optref{diff}{w}{ignore-all-space} + +\cmdref{version}{$B%P!<%8%g%s>pJs$H%3%T!<%i%$%H>pJs$rI=<($9$k(B} + +%This command displays the version of Mercurial you are running, and +%its copyright license. There are four kinds of version string that +%you may see. +$B$3$N%3%^%s%I$O8=:_F0:nCf$N(BMercurial$B$N%P!<%8%g%s$H%3%T!<%i%$%H%i%$%;%s%9(B +$B$rI=<($9$k!%%a%C%;!<%8$O(B4$B<oN`$"$k!%(B +%\begin{itemize} +%\item The string ``\texttt{unknown}''. This version of Mercurial was +% not built in a Mercurial repository, and cannot determine its own +% version. +%\item A short numeric string, such as ``\texttt{1.1}''. This is a +% build of a revision of Mercurial that was identified by a specific +% tag in the repository where it was built. (This doesn't necessarily +% mean that you're running an official release; someone else could +% have added that tag to any revision in the repository where they +% built Mercurial.) +%\item A hexadecimal string, such as ``\texttt{875489e31abe}''. This +% is a build of the given revision of Mercurial. +%\item A hexadecimal string followed by a date, such as +% ``\texttt{875489e31abe+20070205}''. This is a build of the given +% revision of Mercurial, where the build repository contained some +% local changes that had not been committed. +%\end{itemize} +\begin{itemize} +\item $BJ8;zNs(B``\texttt{unknown}''$B!%(B $B$3$N%P!<%8%g%s$N(BMercurial$B$O(BMercurial$B%j(B + $B%]%8%H%j$NCf$G%S%k%I$5$l$?$N$G$O$J$$$?$a!$<+J,<+?H$N%j%S%8%g%s$OJ,(B + $B$+$i$J$$(B +\item ``\texttt{1.1}''$B$N$h$&$JC;$$?tCMJ8;zNs!%$3$l$O%S%k%I%j%]%8%H%jFb$G(B + $B%?%0IU$1$5$l$?FCDj$N%j%S%8%g%s$N(BMercurial$B$G$"$k$3$H$r<($9!%!J$3$l$O(B + $B@5<0%j%j!<%9HG$G$"$k$H$$$&$3$H$rI,$:$7$b0UL#$7$J$$!%(BMercurial$B$r%S%k(B + $B%I$9$k%j%]%8%H%j$G%?%0$rIU$1$k$N$OC/$G$b$I$N%j%S%8%g%s$KBP$7$F$b2D(B + $BG=$G$"$k!K(B +\item ``\texttt{875489e31abe}''$B$N$h$&$J(B16$B?J?tJ8;zNs!%$3$l$O(BMercurial$B$,I=(B + $B<($5$l$?%j%S%8%g%s$N%S%k%I$G$"$k$3$H$r<($9!%(B + +\item ``\texttt{875489e31abe+20070205}''$B$N$h$&$J(B16$B?JJ8;zNs!\F|IU!%$3$l$O(B + $B$=$N%j%S%8%g%s$KBP$7$F%3%_%C%H$5$l$F$$$J$$%m!<%+%k$JJQ99$r2C$($?%=!<(B + $B%9$+$i%S%k%I$5$l$?(BMercurial$B$G$"$k$3$H$r<($9!%(B +\end{itemize} + +%\subsection{Tips and tricks} +\subsection{Tips and tricks} + +\subsubsection{Why do the results of \hgcmd{diff} and \hgcmd{status} + differ?} +\label{cmdref:diff-vs-status} + +%When you run the \hgcmd{status} command, you'll see a list of files +%that Mercurial will record changes for the next time you perform a +%commit. If you run the \hgcmd{diff} command, you may notice that it +%prints diffs for only a \emph{subset} of the files that \hgcmd{status} +%listed. There are two possible reasons for this. + +\hgcmd{status}$B$r<B9T$7$?;~!$(BMercurial$B$O<!2s$N%3%_%C%H$G5-O?$9$kJQ99$N%j(B +$B%9%H$rI=<($9$k!%(B\hgcmd{diff}$B$r<B9T$9$k$H!$(B\hgcmd{status}$B$N(B\emph{$B0lIt(B +$B$N(B}diff$B$,I=<($5$l$k$3$H$K5$IU$/$@$m$&!%$3$l$K$OFs$D$NM}M3$,9M$($i$l$k!%(B + +%The first is that \hgcmd{status} prints some kinds of modifications +%that \hgcmd{diff} doesn't normally display. The \hgcmd{diff} command +%normally outputs unified diffs, which don't have the ability to +%represent some changes that Mercurial can track. Most notably, +%traditional diffs can't represent a change in whether or not a file is +%executable, but Mercurial records this information. + +1$B$DL\$O(B\hgcmd{status}$B$,(B\hgcmd{diff}$B$,DL>oI=<($7$J$$2?<oN`$+$NJQ99$rI=<($9(B +$B$k$?$a$G$"$k!%(B\hgcmd{diff}$B$ODL>o(Bunified diff$B7A<0$G=PNO$9$k$,!$$3$l$O(B +Mercurial$B$,DI@W$G$-$kJQ99$N$$$/$D$+$rDI@W$G$-$J$$!%FC$K!$8E$$(Bdiff$B$G$O%U%!(B +$B%$%k$,<B9T$+$N$&$+$I$&$+$rI=8=$G$-$J$$$,!$(BMercurial$B$O$3$N>pJs$r5-O?$9$k!%(B + +%If you use the \hgopt{diff}{--git} option to \hgcmd{diff}, it will +%display \command{git}-compatible diffs that \emph{can} display this +%extra information. + +\hgcmd{diff}$B%3%^%s%I$G(B\hgopt{diff}{--git}$B%*%W%7%g%s$r;H$C$F$$$k>l9g!$(B +$B$3$N>pJs$rI=<($G$-$k(B\command{git}$B8_49$N(Bdiff$B$r=PNO$9$k!%(B + +%The second possible reason that \hgcmd{diff} might be printing diffs +%for a subset of the files displayed by \hgcmd{status} is that if you +%invoke it without any arguments, \hgcmd{diff} prints diffs against the +%first parent of the working directory.If you have run \hgcmd{merge} +%to merge two changesets, but you haven't yet committed the results of +%the merge,your working directory has two parents (use \hgcmd{parents} +%to see them).While \hgcmd{status} prints modifications relative to +%\emph{both} parents after an uncommitted merge, \hgcmd{diff} still +%operates relative only to the first parent. You can get it to print +%diffs relative to the second parent by specifying that parent with the +%\hgopt{diff}{-r} option. There is no way to print diffs relative to +%both parents. + +2$B$DL\$N9M$($i$l$kM}M3$O!$(B\hgcmd{diff}$B$r0z?t$J$7$G8F$s$G$$$k$?$a!$(B +\hgcmd{diff}$B$,%o!<%-%s%0%G%#%l%/%H%j$ND>@\$N?F$H$N:9J,$r<h$C$F$$$k$?$a$G(B +$B$"$k!%%A%'%s%8%;%C%H$r%^!<%8$9$k$?$a$K(B\hgcmd{merge}$B$r<B9T$9$k$H!$%o!<%-%s(B +$B%0%G%#%l%/%H%j$O(B2$B$D$N?F$r;}$D$3$H$K$J$k!%!J?F$rI=<($9$k$K$O(B +\hgcmd{parents}$B$r;H$&!%!K(B\hgcmd{status}$B$O%3%_%C%H$5$l$F$$$J$$%^!<%8$N(B +\emph{$BN>J}(B}$B$N?F$H$N:9J,$r<h$k$N$KBP$7$F!$(B\hgcmd{diff}$B$O=g=xE*$K@h$N?F$H(B +$B$N:9J,$r<h$k!%8e$N?F$H$N:9J,$r<h$k$?$a$K$O(B\hgopt{diff}{-r}$B%*%W%7%g%s$r;H(B +$B$&!%N>J}$N?F$H$N:9J,$r<h$kJ}K!$OB8:_$7$J$$!%(B + + +%\subsubsection{Generating safe binary diffs} +\subsubsection{$B%P%$%J%j$N:9J,$r0BA4$K<hF@$9$k(B} + +%If you use the \hgopt{diff}{-a} option to force Mercurial to print +%diffs of files that are either ``mostly text'' or contain lots of +%binary data, those diffs cannot subsequently be applied by either +%Mercurial's \hgcmd{import} command or the system's \command{patch} +%command. + +$BBgH>$,%F%-%9%H$G$"$k%U%!%$%kF1;N$d!$B?$/$N%P%$%J%j%G!<%?$,4^$^$l$k%U%!%$(B +$B%kF1;N$N:9J,$r<h$k$?$a$K(B\hgopt{diff}{-a}$B$r;XDj$9$k>l9g!$@8@.$5$l$?:9J,$O(B +Mercurial$B$N(B\hgcmd{import}$B%3%^%s%I$d%7%9%F%`$N(B\command{patch}$B$KMQ$$$k$3$H(B +$B$,$G$-$J$$!%(B + +%If you want to generate a diff of a binary file that is safe to use as +%input for \hgcmd{import}, use the \hgcmd{diff}{--git} option when you +%generate the patch. The system \command{patch} command cannot handle +%binary patches at all. + +\hgcmd{import}$B$GMxMQ$G$-$k%P%$%J%j%U%!%$%k$N:9J,$r@8@.$9$k$K$O!$(B +$B%Q%C%A@8@.$K(B\hgcmd{diff}{--git}$B%*%W%7%g%s$r;XDj$9$l$P$h$$!%%7%9%F%`$N(B +\command{patch}$B%3%^%s%I$+$i$O$3$N:9J,$OMxMQ$G$-$J$$!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/collab.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1933 @@ +%\chapter{Collaborating with other people} +\chapter{$BB>$N?M!9$H$N6&F1:n6H(B} +\label{cha:collab} + +%As a completely decentralised tool, Mercurial doesn't impose any +%policy on how people ought to work with each other. However, if +%you're new to distributed revision control, it helps to have some +%tools and examples in mind when you're thinking about possible +%workflow models. + +$B40A4$JJ,;67?%D!<%k$H$7$F!$(BMercurial$B$O%f!<%6$,B>$N%f!<%6$H$I$N$h$&$K:n6H$9(B +$B$k$+$N%]%j%7!<$r6/MW$9$k$3$H$O$J$$!%$7$+$7=i$a$FJ,;6%j%S%8%g%s%3%s%H%m!<(B +$B%k%D!<%k$r;H$&$N$G$"$l$P!$$$$/$D$+$N%D!<%k$N;HMQK!$H;HMQNc$rCN$k$3$H$,(B +$B<h$jF@$k%o!<%/%U%m!<%b%G%k$r9M$($k:]$K=u$1$H$J$k$G$"$m$&!%(B + +%\section{Mercurial's web interface} +\section{Mercurial$B$N%&%'%V%$%s%?%U%'!<%9(B} + +%Mercurial has a powerful web interface that provides several +%useful capabilities. + +Mercurial$B$O$$$/$D$+$NM-MQ$J5!G=$r;}$D6/NO$J%&%'%V%$%s%?%U%'!<%9$rHw$($F(B +$B$$$k!%(B + +%For interactive use, the web interface lets you browse a single +%repository or a collection of repositories. You can view the history +%of a repository, examine each change (comments and diffs), and view +%the contents of each directory and file. + +$BBPOCE*$JMxMQ$G$O!$%&%'%V%$%s%?%U%'!<%9$K$h$j(B1$B$D$N%j%]%8%H%j$^$?$O$$$/$D$+(B +$B$N%j%]%8%H%j$N%3%l%/%7%g%s$r1\Mw$9$k$3$H$,$G$-$k!%%j%]%8%H%j$NMzNr$r8+$?(B +$B$j!$3F!9$NJQ99!J%3%a%s%H$d:9J,$r4^$`!K$rD4$Y$?$j!$%G%#%l%/%H%j$d%U%!%$%k(B +$B$NFbMF$r8+$k$3$H$,$G$-$k!%(B + +%Also for human consumption, the web interface provides an RSS feed of +%the changes in a repository. This lets you ``subscribe'' to a +%repository using your favourite feed reader, and be automatically +%notified of activity in that repository as soon as it happens. I find +%this capability much more convenient than the model of subscribing to +%a mailing list to which notifications are sent, as it requires no +%additional configuration on the part of whoever is serving the +%repository. + +$B%&%'%V%$%s%?%U%'!<%9$O1\MwMQ$K%j%]%8%H%j$NJQ99$N(BRSS$B%U%#!<%I$rDs6!$9$k!%$3(B +$B$l$r;H$($P!$%j%]%8%H%j$NJQ2=$r9%$_$N%U%#!<%I%j!<%@$K$h$C$F(B``$B9XFI(B''$B$9$k$3(B +$B$H$,$G$-!$%j%]%8%H%j$G$N3hF0$,5/$3$k$H$9$0$5$^DLCN$r<u$1$i$l$k!%$3$N5!G=(B +$B$OC/$,%j%]%8%H%j$N%5!<%S%9$r9T$C$F$bDI2C$N@_Dj$rI,MW$H$7$J$$$?$a!$%a!<%j(B +$B%s%0%j%9%H$r9XFI$7$FDLCN$r<u$1$k%b%G%k$h$j$b$:$C$HJXMx$G$"$k!%(B + +%The web interface also lets remote users clone a repository, pull +%changes from it, and (when the server is configured to permit it) push +%changes back to it. Mercurial's HTTP tunneling protocol aggressively +%compresses data, so that it works efficiently even over low-bandwidth +%network connections. + +$B%j%b!<%H%f!<%6$O%&%'%V%$%s%?%U%'!<%9$rMQ$$$F%j%]%8%H%j$r%/%m!<%s$9$k$3$H(B +$B$b$G$-$k!%JQ99$r(Bpull$B$7$F!$!J%5!<%P$,5v2D$9$k@_Dj$K$J$C$F$$$l$P!K2C$($?JQ(B +$B99$r:F$S(Bpush$B$9$k$3$H$b$G$-$k!%(BMercurial$B$N(BHTTP$B%H%s%M%k%W%m%H%3%k$O%G!<%?$r(B +$B@Q6KE*$K05=L$9$k$?$a!$%P%s%II}$NDc$$%M%C%H%o!<%/%3%M%/%7%g%s$G$bM-8z$K5!(B +$BG=$9$k!%(B + +%The easiest way to get started with the web interface is to use your +%web browser to visit an existing repository, such as the master +%Mercurial repository at +%\url{http://www.selenic.com/repo/hg?style=gitweb}. + +$B%&%'%V%$%s%?%U%'!<%9$N:G$b4JC1$J;O$aJ}$O%&%'%V%V%i%&%6$r;H$C$F(BMercurial$B$N(B +$B%^%9%?%j%]%8%H%j(B\url{http://www.selenic.com/repo/hg?style=gitweb}$B$N$h$&$J(B +$B4{B8$N%j%]%8%H%j$r;2>H$9$k$3$H$G$"$k!%(B + +%If you're interested in providing a web interface to your own +%repositories, Mercurial provides two ways to do this. The first is +%using the \hgcmd{serve} command, which is best suited to short-term +%``lightweight'' serving. See section~\ref{sec:collab:serve} below for +%details of how to use this command. If you have a long-lived +%repository that you'd like to make permanently available, Mercurial +%has built-in support for the CGI (Common Gateway Interface) standard, +%which all common web servers support. See +%section~\ref{sec:collab:cgi} for details of CGI configuration. + +$B<+J,$N%j%]%8%H%j$K%&%'%V%$%s%?%U%'!<%9$rMQ0U$9$k>l9g!$(B2$BDL$j$N$d$jJ}$,$"(B +$B$k!%(B 1$B$DL\$NJ}K!$O(B\hgcmd{serve}$B%3%^%s%I$r;H$&J}K!$G!$$3$l$OC;4|4V$N(B``$B<j7Z(B +$B$J(B''$B%5!<%S%9$KE*$7$F$$$k!%$3$N%3%^%s%I$N>\:Y$J;HMQK!$K$D$$$F$O2<5-(B +$B$N(B~\ref{sec:collab:serve}$B@a$r;2>H$N$3$H!%%j%]%8%H%j$rD94|4V$K$o$?$j1JB3E*(B +$B$K%5!<%S%9$7$?$$>l9g$O!$(BMercurial$B$KFbB"$N(BCGI(Common Gateway Interface)$B%5(B +$B%]!<%H$rMxMQ$9$k$3$H$,$G$-$k!%(B CGI$B$N@_Dj$K$D$$$F$O(B~\ref{sec:collab:cgi}$B@a(B +$B$r;2>H$N$3$H!%(B + +%\section{Collaboration models} +\section{$B6&F1:n6H%b%G%k(B} + +%With a suitably flexible tool, making decisions about workflow is much +%more of a social engineering challenge than a technical one. +%Mercurial imposes few limitations on how you can structure the flow of +%work in a project, so it's up to you and your group to set up and live +%with a model that matches your own particular needs. + +$BE,@Z$G=@Fp$J%D!<%k$r$b$C$F$7$F$b!$%o!<%/%U%m!<$K4X$9$k7hDj$r$9$k$3$H$O5;(B +$B=QE*$H$$$&$h$j$O<R2q9)3XE*$J%A%c%l%s%8$G$"$k!%(B Mercurial$B$,%W%m%8%'%/%H$N(B +$B%o!<%/%U%m!<$K2]$9@)8B$O$[$H$s$I$J$$$?$a!$$3$l$r$$$+$K9=C[$9$k$+$O$"$J$?(B +$B$H$=$N6&F1:n6H<T$KG$$5$l$F$*$j!$8GM-$NMW5a%^%C%A$9$k%b%G%k$r:n$k$3$H$,$G(B +$B$-$k!%(B + +%\subsection{Factors to keep in mind} +\subsection{$B9MN8$9$Y$-MWAG(B} + +%The most important aspect of any model that you must keep in mind is +%how well it matches the needs and capabilities of the people who will +%be using it. This might seem self-evident; even so, you still can't +%afford to forget it for a moment. + +$B$I$N$h$&$J%b%G%k$r;H$&>l9g$G$b!$$=$l$,:n6H$9$k?M!9$NMW5a$HG=NO$KE,$C$?$b(B +$B$N$G$"$k$+$r>o$KG0F,$KCV$/$3$H$,:G$b=EMW$G$"$k!%(B +$B$3$l$O<+L@$N$3$H$N$h$&$K;W$($k$+$b$7$l$J$$$,!$JR;~$bK:$l$F$O$J$i$J$$!%(B + +%I once put together a workflow model that seemed to make perfect sense +%to me, but that caused a considerable amount of consternation and +%strife within my development team. In spite of my attempts to explain +%why we needed a complex set of branches, and how changes ought to flow +%between them, a few team members revolted. Even though they were +%smart people, they didn't want to pay attention to the constraints we +%were operating under, or face the consequences of those constraints in +%the details of the model that I was advocating. + +$B<+J,$K$H$C$F40A4$H;W$($k%o!<%/%U%m!<%b%G%k$r9=C[$7$?$D$b$j$,!$6&F13+H/%A!<(B +$B%`$K$H$C$F$OBg$-$J6C$-$H3kF#$rM?$($F$7$^$C$?$3$H$,$"$k!%J#;($J%V%i%s%A$N(B +$B=89g$,$J$<I,MW$J$N$+JQ99$,%V%i%s%A4V$G$I$N$h$&$KEAGE$9$k$N$+$r@bL@$7$?$K(B +$B$b$+$+$o$i$:!$4v?M$+$N%A!<%`%a%s%P!<$OH?H/$7$?!%H`$i$OAoL@$G$"$C$?$,!$;d(B +$B$,94$C$?%k!<%k$,:n6H$KM?$($k@)8B$d!$%b%G%k$N:YIt$KM?$($k1F6A$KCm0U$rJ'$&(B +$B$3$H$OK>$^$J$+$C$?!%(B + +%Don't sweep foreseeable social or technical problems under the rug. +%Whatever scheme you put into effect, you should plan for mistakes and +%problem scenarios. Consider adding automated machinery to prevent, or +%quickly recover from, trouble that you can anticipate. As an example, +%if you intend to have a branch with not-for-release changes in it, +%you'd do well to think early about the possibility that someone might +%accidentally merge those changes into a release branch. You could +%avoid this particular problem by writing a hook that prevents changes +%from being merged from an inappropriate branch. + +$B>-Mh5/$3$jF@$k<R2qE*$^$?$O5;=QE*LdBj$KL\$rbT$C$F$O$J$i$J$$!%$I$N$h$&$JJ}(B +$BK!$r$H$k$K$7$F$b!$4V0c$$$dLdBj$,5/$-$?>l9g$KHw$($F$*$/I,MW$,$"$k!%A[A|$7(B +$BF@$k%H%i%V%k$rKI;_$7$?$j!$%H%i%V%k$+$iAGAa$/2sI|$5$;$k$?$a$N<+F02=$5$l$?(B +$BJ}K!$r9M$($F$*$/I,MW$,$"$k!%$?$H$($P!$%j%j!<%9$K4^$a$J$$JQ99$r9T$C$?%V%i(B +$B%s%A$,$"$k$H$7$?$i!$C/$+$,8m$C$F$=$3$+$i%j%j!<%9%V%i%s%A$KJQ99$r%^!<%8$7(B +$B$F$7$^$&2DG=@-$K$D$$$F8!F$$7$F$*$/$Y$-$G$"$k!%$3$N>l9g$G$"$l$P!$ITE,@Z$J(B +$B%V%i%s%A$+$i$N%^!<%8$r6X;_$9$k%U%C%/$rMQ0U$9$k$3$H$GLdBj$r2sHr$9$k$3$H$,(B +$B$G$-$k!%(B + +%\subsection{Informal anarchy} +\subsection{$BHs8x<0$J:.Mp(B} + +%I wouldn't suggest an ``anything goes'' approach as something +%sustainable, but it's a model that's easy to grasp, and it works +%perfectly well in a few unusual situations. + +$B$3$3$G=R$Y$k(B``$B$J$s$G$b$"$j(B''$B%"%W%m!<%A$,;}B32DG=$G$"$k$H8@$$$?$$$o$1$G$O(B +$B$J$$$N$@$,!$$3$N%b%G%k$OGD0.$7$d$9$/!$$$$/$D$+$N>u67$G$O$&$^$/5!G=$9$k$b(B +$B$N$@!%(B + +%As one example, many projects have a loose-knit group of collaborators +%who rarely physically meet each other. Some groups like to overcome +%the isolation of working at a distance by organising occasional +%``sprints''. In a sprint, a number of people get together in a single +%location (a company's conference room, a hotel meeting room, that kind +%of place) and spend several days more or less locked in there, hacking +%intensely on a handful of projects. + +$BNc$($P%W%m%8%'%/%H$NB?$/$O<B:]$K$O$[$H$s$I2q$&$3$H$N$J$$6(NO<T$?$A$N4K$d(B +$B$+$J%0%k!<%W$r;}$D!%%0%k!<%W$N$$$/$D$+$O5!2qKh$KC;$$(B``$B%9%W%j%s%H(B''$B$r7A@.(B +$B$7!$N%$l$?>l=j$G$N3V@d$7$?:n6H$r9nI~$7$F$$$k!%%9%W%j%s%H$G$O!$!J4k6H$N2q(B +$B5D<<!$%[%F%k$N%_!<%F%#%s%0%k!<%`$N$h$&$J!K0l%+=j$K=8$^$C$F?tF|4V$K$o$?$C(B +$B$F>/?t$N%W%m%8%'%/%H$r=8CfE*$K%O%C%/$9$k!%(B + +%A sprint is the perfect place to use the \hgcmd{serve} command, since +%\hgcmd{serve} does not requires any fancy server infrastructure. You +%can get started with \hgcmd{serve} in moments, by reading +%section~\ref{sec:collab:serve} below. Then simply tell the person +%next to you that you're running a server, send the URL to them in an +%instant message, and you immediately have a quick-turnaround way to +%work together. They can type your URL into their web browser and +%quickly review your changes; or they can pull a bugfix from you and +%verify it; or they can clone a branch containing a new feature and try +%it out. + +$B%9%W%j%s%H$O(B\hgcmd{serve}$B%3%^%s%I$r;H$&$N$^$5$K$K$&$C$F$D$1$N4D6-$G$"$k!%(B +\hgcmd{serve}$B$O<j$N9~$s$@%5!<%P@_Hw$rI,MW$H$7$J$$!%2<$N(B +\ref{sec:collab:serve}$B%;%/%7%g%s$rFI$s$G$9$0$K(B\hgcmd{serve}$B%3%^%s%I$r;H$&(B +$B$3$H$,$G$-$k!%%5!<%P$r5/F0$7$F$$$k$3$H$rNY$N3+H/<T$KOC$7$?$j!$%0%k!<%W$K(B +URL$B$r%$%s%9%?%s%H%a%C%;!<%8$GAw$l$P!$$9$0$K?WB.$J6&F1:n6H$,$G$-$k!%(B +$BAw$C$?(BURL$B$rB>$N3+H/<T$,%V%i%&%6$KF~NO$9$l$P!$H`$i$O4JC1$K$"$J$?$NJQ99$r%l(B +$B%S%e!<$9$k$3$H$,$G$-$k$7!$$"$J$?$N9T$C$?%P%0%U%#%C%/%9$r(Bpull$B$7$F8!>Z$9$k(B +$B$3$H$b$G$-$k!%$5$i$K!$?75!G=$N<BAu$5$l$?%V%i%s%A$r%/%m!<%s$7$F;n$9$3$H$b(B +$B$G$-$k!%(B + +%The charm, and the problem, with doing things in an ad hoc fashion +%like this is that only people who know about your changes, and where +%they are, can see them. Such an informal approach simply doesn't +%scale beyond a handful people, because each individual needs to know +%about $n$ different repositories to pull from. + +$B%"%I%[%C%/$J$d$jJ}$G9T$&6&F1:n6H$NL%NO$HLdBj$O!$$"$J$?$NJQ99$rCN$C$F$$(B +$B$F!$>l=j$bJ,$+$C$F$$$k?M!9$7$+JQ99$r;2>H$G$-$J$$$3$H$G$"$k!%$3$N$h$&$JHs(B +$B8x<0$J%"%W%m!<%A$O!$3F?M$,(B$n$$B8D$N0[$J$C$?%j%]%8%H%j$N$I$l$+$i(Bpull$B$r9T$($P(B +$B$$$$$+J,$+$C$F$$$kI,MW$,$"$k$?$a!$>/?M?t0J>e$K%9%1!<%k$7$J$$!%(B + + +%\subsection{A single central repository} +\subsection{1$B$D$N=8Cf%j%]%8%H%j(B} + +%For smaller projects migrating from a centralised revision control +%tool, perhaps the easiest way to get started is to have changes flow +%through a single shared central repository. This is also the +%most common ``building block'' for more ambitious workflow schemes. + +$B=8Cf7?%j%S%8%g%s%3%s%H%m!<%k%D!<%k$r;H$C$F$$$?>.5,LO$J%W%m%8%'%/%H$,0\9T(B +$B$9$k>l9g$K$O!$Cf1{$KC10l$N6&M-%j%]%8%H%j$r@_$1$F!$$=$NCf$GJQ99$r4IM}$9$k(B +$B$N$,:G$b4JC1$JJ}K!$G$"$m$&!%$3$N$h$&$J%j%]%8%H%j$O$b$C$H[#Kf$J%o!<%/%U%m!<(B +$B%9%-!<%`$K$H$C$F$b6&DL$N4pHW$H$J$k!%(B + +%Contributors start by cloning a copy of this repository. They can +%pull changes from it whenever they need to, and some (perhaps all) +%developers have permission to push a change back when they're ready +%for other people to see it. + +$B6(NO<T$O%j%]%8%H%j$N%3%T!<$r%/%m!<%s$9$k$3$H$+$i;O$a$k!%$=$7$FI,MW$J;~$K(B +$BJQ99$r(Bpull$B$7!$4v?M$+$N!JA40w$+$b$7$l$J$$!K3+H/<T$O!$<+J,$N9T$C$?JQ99$rI,(B +$BMW$J;~$K(Bpush$B$9$k8"8B$r;}$D!%(B + +%Under this model, it can still often make sense for people to pull +%changes directly from each other, without going through the central +%repository. Consider a case in which I have a tentative bug fix, but +%I am worried that if I were to publish it to the central repository, +%it might subsequently break everyone else's trees as they pull it. To +%reduce the potential for damage, I can ask you to clone my repository +%into a temporary repository of your own and test it. This lets us put +%off publishing the potentially unsafe change until it has had a little +%testing. + +$B$3$N%b%G%k$G$b!$Cf1{$N%j%]%8%H%j$r;2>H$;$:B>$N3+H/<T$N%j%]%8%H%j$+$iD>@\(B +$BJQ99$r(Bpull$B$9$k$3$H$K$O0UL#$,$"$k!%<j85$G2>$N%P%0=$@5$r9T$C$?$,!$$3$l$rCf(B +$B1{$N%j%]%8%H%j$G8x3+$7!$B>$N3+H/<TC#$,(Bpull$B$9$k$H3F!9$N%=!<%9%D%j!<$,2u$l(B +$B$k$*$=$l$,$"$k>l9g$r9M$($k!%%@%a!<%8$N2DG=@-$r2<$2$k$?$a$K!$JL$N3+H/<T$K(B +$B<+J,$N%j%]%8%H%j$r%/%m!<%s$7!$%F%9%H$9$k$3$H$r0MMj$9$k$3$H$,9M$($i$l$k!%(B +$B$3$NJ}K!$r<h$k$3$H$G!$:GDc8B$N%F%9%H$r9T$&$^$G!$LdBj$N$"$k2DG=@-$N$"$kJQ(B +$B99$r8x3+$9$k$3$H$r0z$-1d$P$9$3$H$,$G$-$k!%(B + +%In this kind of scenario, people usually use the \command{ssh} +%protocol to securely push changes to the central repository, as +%documented in section~\ref{sec:collab:ssh}. It's also usual to +%publish a read-only copy of the repository over HTTP using CGI, as in +%section~\ref{sec:collab:cgi}. Publishing over HTTP satisfies the +%needs of people who don't have push access, and those who want to use +%web browsers to browse the repository's history. + +$B$3$N>u67$G$O!$3+H/<T$?$A$ODL>o!$Cf1{$N%j%]%8%H%j$XJQ99$r%W%C%7%e$9$k$?$a(B +$B$K!$(B~\ref{sec:collab:ssh}$B@a$G@bL@$7$?$h$&$K(B\command{ssh}$B%W%m%H%3%k$rMQ$$(B +$B$k!%$^$?(B~\ref{sec:collab:cgi}$B@a$G=R$Y$?$h$&$K!$%j%]%8%H%j$NFI$_<h$j@lMQ%3(B +$B%T!<$r(BCGI$B$rMQ$$$?(BHTTP$B$G8x3+$9$k$N$b0lHLE*$G$"$k!%(B HTTP$B$K$h$k8x3+$G!$%W%C(B +$B%7%e%"%/%;%98"$r;}$?$J$$?M!9$d%j%]%8%H%j$NMzNr$r%V%i%&%6$G;2>H$7$?$$?M$N(B +$B%K!<%:$rK~$?$9$3$H$,$G$-$k!%(B + +%\subsection{Working with multiple branches} +\subsection{$BJ#?t$N%V%i%s%A$G$N:n6H(B} + +%Projects of any significant size naturally tend to make progress on +%several fronts simultaneously. In the case of software, it's common +%for a project to go through periodic official releases. A release +%might then go into ``maintenance mode'' for a while after its first +%publication; maintenance releases tend to contain only bug fixes, not +%new features. In parallel with these maintenance releases, one or +%more future releases may be under development. People normally use +%the word ``branch'' to refer to one of these many slightly different +%directions in which development is proceeding. + +$B$"$kDxEY$N5,LO$N%W%m%8%'%/%H$G$O!$<+$:$H$$$/$D$b$NA0@~$G3+H/$r?J$a$F$$$/(B +$B$h$&$K$J$k!%%=%U%H%&%'%"$N>l9g!$Dj4|E*$K8x<0%j%j!<%9$r9T$&$N$,DLNc$G$"(B +$B$k!%%j%j!<%9$O!$8x3+8e;C$/$7$F(B``$B%a%s%F%J%s%9%b!<%I(B''$B$K0\9T$9$k$+$b$7$l$J(B +$B$$!%%a%s%F%J%s%9%j%j!<%9$G$O%P%0$N=$@5$@$1$r9T$$!$?75!G=$NDI2C$O9T$o$J$$(B +$B$N$,DLNc$G$"$k!%$3$l$i$N%a%s%F%J%s%9%j%j!<%9$HJB9T$7$F!$>-Mh$N%j%j!<%9$,(B +$B3+H/$5$l$k!%DL>o!$3+H/$N?J9T$7$F$$$/<c430[$J$C$?J}8~$N3F!9$rI=$9$?$a$K(B +``$B%V%i%s%A(B''$B$H$$$&8F>N$rMQ$$$k!%(B + +%Mercurial is particularly well suited to managing a number of +%simultaneous, but not identical, branches. Each ``development +%direction'' can live in its own central repository, and you can merge +%changes from one to another as the need arises. Because repositories +%are independent of each other, unstable changes in a development +%branch will never affect a stable branch unless someone explicitly +%merges those changes in. + +Mercurial$B$OJ#?t%V%i%s%A$K$h$kF1;~3+H/$r<h$j07$&$3$H$KFC$KE,$7$F$$$k!%3F!9(B +$B$N(B``$B3+H/J}8~(B''$B$OCf1{%j%]%8%H%j$KCV$/$3$H$,2DG=$G!$I,MW$K$J$kEY$K$"$k%V%i(B +$B%s%A$+$iJL$N%V%i%s%A$X%^!<%8$G$-$k!%%j%]%8%H%j$O$=$l$>$lFHN)$G$"$k$?$a!$(B +$B3+H/%V%i%s%A$G$NIT0BDj$JJQ99$O!$3+H/<T$NC/$+$,L@<(E*$K%^!<%8$r9T$o$J$$8B(B +$B$j0BDjHG%V%i%s%A$K$O$J$s$N1F6A$bM?$($J$$!%(B + +%Here's an example of how this can work in practice. Let's say you +%have one ``main branch'' on a central server. +%\interaction{branching.init} +%People clone it, make changes locally, test them, and push them back. + +$B<B:]$K$I$N$h$&$KF0:n$9$k$N$+$rNc$G<($9!%Cf1{$N%5!<%P$K(B1$B$D$N(B``$B%a%$%s%V%i(B +$B%s%A(B''$B$,$"$k$H$7$h$&!%(B +\interaction{branching.init} +$B3+H/<T$O$3$l$r%/%m!<%s$7!$%m!<%+%k$GJQ99$r2C$(!$%F%9%H$7!$$^$?(Bpush$B$9$k$H(B +$B$9$k!%(B + +%Once the main branch reaches a release milestone, you can use the +%\hgcmd{tag} command to give a permanent name to the milestone +%revision. +%\interaction{branching.tag} +%Let's say some ongoing development occurs on the main branch. +%\interaction{branching.main} +%Using the tag that was recorded at the milestone, people who clone +%that repository at any time in the future can use \hgcmd{update} to +%get a copy of the working directory exactly as it was when that tagged +%revision was committed. +%\interaction{branching.update} + +$B%a%$%s%V%i%s%A$,%j%j!<%9%^%$%k%9%H!<%s$KE~C#$7$?:]$K!$(B\hgcmd{tag}$B$G1JB3E*(B +$B$JL>A0$r%^%$%k%9%H!<%s%j%S%8%g%s$KIU$1$k$3$H$,$G$-$k!%(B +\interaction{branching.tag} +$B%a%$%s%V%i%s%A$G?J9TCf$N3+H/$K$D$$$F8+$F$_$h$&!%(B +\interaction{branching.main} +$B$3$l0J8e%j%]%8%H%j$r%/%m!<%s$7$??M$O%^%$%k%9%H!<%s$G5-O?$5$l$?%?%0$H(B +\hgcmd{update}$B%3%^%s%I$r;H$C$F!$%?%0$NIU$1$i$l$?%j%S%8%g%s$HA4$/F1$8%o!<(B +$B%-%s%0%G%#%l%/%H%j$rI|85$9$k$3$H$,$G$-$k!%(B +\interaction{branching.update} + +%In addition, immediately after the main branch is tagged, someone can +%then clone the main branch on the server to a new ``stable'' branch, +%also on the server. +%\interaction{branching.clone} + +$B$5$i$K!$%a%$%s%V%i%s%A$,%?%0IU$1$5$l$?D>8e$+$i%5!<%P>e$N%a%$%s%V%i%s%A$r(B +$B?7$?$J(B``stable''$B%V%i%s%A$K%/%m!<%s$G$-$k!%$3$l$O%5!<%P>e$G9T$&$3$H$b2DG=(B +$B$G$"$k!%(B +\interaction{branching.clone} + +%Someone who needs to make a change to the stable branch can then clone +%\emph{that} repository, make their changes, commit, and push their +%changes back there. +%\interaction{branching.stable} +%Because Mercurial repositories are independent, and Mercurial doesn't +%move changes around automatically, the stable and main branches are +%\emph{isolated} from each other. The changes that you made on the +%main branch don't ``leak'' to the stable branch, and vice versa. + +stable$B%V%i%s%A$KJQ99$r2C$($?$$>l9g!$(B\emph{$B$=$N(B}$B%j%]%8%H%j$r%/%m!<%s$7!$(B +$BJQ99$r9T$$!$%3%_%C%H$7$?8e$K$=$NJQ99$r%5!<%P$K(Bpush$B$7$FLa$9$3$H$,$G$-$k!%(B +\interaction{branching.stable} +Mercurial$B%j%]%8%H%j$OFHN)$G!$JQ99$r<+F0E*$KGH5Z$5$;$k$3$H$b$J$$$N$G!$(B +stable$B$H(Bmain$B%V%i%s%A$O8_$$$K(B\emph{$B3VN%$5$l$F$$$k(B}$B!%%a%$%s%V%i%s%A$K9T$C(B +$B$?JQ99$,(Bstable$B%V%i%s%A$KO3$l=P$7$?$j!$$=$N5U$K$J$C$?$j$9$k$3$H$O$J$$!%(B + +%You'll often want all of your bugfixes on the stable branch to show up + +%on the main branch, too. Rather than rewrite a bugfix on the main +%branch, you can simply pull and merge changes from the stable to the +%main branch, and Mercurial will bring those bugfixes in for you. +%\interaction{branching.merge} +%The main branch will still contain changes that are not on the stable +%branch, but it will also contain all of the bugfixes from the stable +%branch. The stable branch remains unaffected by these changes. + +$BB?$/$N>l9g!$(Bstable$B%V%i%s%A$KBP$7$F9T$C$?%P%0=$@5$r%a%$%s%V%i%s%A$KBP$7$F(B +$B$b<h$j9~$_$?$$$H9M$($k$@$m$&!%%P%0=$@5$r%a%$%s%V%i%s%A$G$b$&0lEY9T$&$N$G(B +$B$O$J$/!$(BMercurial$B$r;H$C$FJQ99$r(Bstable$B%V%i%s%A$+$i(Bpull$B$7$F4JC1$K%a%$%s%V%i(B +$B%s%A$X%^!<%8$9$k$3$H$,$G$-$k!%(B +\interaction{branching.merge} +$B%a%$%s%V%i%s%A$K$O(Bstable$B%V%i%s%A$K$J$$JQ99$,$"$k$,!$(Bstable$B%V%i%s%A$K$"$k(B +$B%P%0=$@5$O$9$Y$F<h$j9~$s$G$$$k!%$3$NA`:n$N8e$G$b(Bstable$B%V%i%s%A$O0JA0$HJQ(B +$B$o$i$J$$$^$^$G$"$k!%(B + +%\subsection{Feature branches} +\subsection{$B5!G=$K$h$k%V%i%s%A(B} + +%For larger projects, an effective way to manage change is to break up +%a team into smaller groups. Each group has a shared branch of its +%own, cloned from a single ``master'' branch used by the entire +%project. People working on an individual branch are typically quite +%isolated from developments on other branches. + +$BBg5,LO$J%W%m%8%'%/%H$GJQ99$r8z2LE*$K4IM}$9$kJ}K!$O!$%A!<%`$r>.$5$J%0%k!<(B +$B%W$KJ,3d$9$k$3$H$G$"$k!%3F!9$N%0%k!<%W$O%W%m%8%'%/%HA4BN$G;H$o$l$kC10l$N(B +$B%^%9%?!<%V%i%s%A$+$i%/%m!<%s$7$?8GM-$N6&M-%V%i%s%A$r;}$D!%3F!9$N%V%i%s%A(B +$B$G:n6H$9$k?MC#$O!$B>$N%V%i%s%A$G$N3+H/$+$i3VN%$5$l$F$$$k$N$,DLNc$G$"$k!%(B + +\begin{figure}[ht] + \centering + \grafix{feature-branches} +% \caption{Feature branches} + \caption{$B5!G=$K$h$k%V%i%s%A(B} + \label{fig:collab:feature-branches} +\end{figure} + +%When a particular feature is deemed to be in suitable shape, someone +%on that feature team pulls and merges from the master branch into the +%feature branch, then pushes back up to the master branch. + +$BFCDj$N5!G=$,==J,$J>uBV$K$J$C$?$H$-!$$=$N5!G=$N%A!<%`%a%s%P!<$O%^%9%?!<%V(B +$B%i%s%A$+$i5!G=%V%i%s%A$K(Bpull$B$H%^!<%8$r9T$$!$%^%9%?!<%V%i%s%A$K(Bpush$B$7$FLa(B +$B$9!%(B + +%\subsection{The release train} +\subsection{$B%j%j!<%9%H%l%$%s(B} + +%Some projects are organised on a ``train'' basis: a release is +%scheduled to happen every few months, and whatever features are ready +%when the ``train'' is ready to leave are allowed in. + +$B$$$/$D$+$N%W%m%8%'%/%H$O%H%l%$%sJ}<0$GAH?%$5$l$F$$$k!%?t%+7n$K0lEY%j%j!<(B +$B%9$r9T$&$h$&$K%9%1%8%e!<%k$5$l!$%H%l%$%s$,=PH/$G$-$k$h$&$K?75!G=$,=`Hw$5(B +$B$l$k!%(B + +%This model resembles working with feature branches. The difference is +%that when a feature branch misses a train, someone on the feature team +%pulls and merges the changes that went out on that train release into +%the feature branch, and the team continues its work on top of that +%release so that their feature can make the next release. + +$B$3$N%b%G%k$O5!G=%V%i%s%A$G$N:n6H$H;w$F$$$k!%0c$$$O!$5!G=%V%i%s%A$O%H%l%$(B +$B%s$rF($7$?>l9g!$5!G=%A!<%`$N%a%s%P!<$,5!G=%V%i%s%A$N%H%l%$%s%j%j!<%9$X9T(B +$B$/$Y$-JQ99$r5!G=%j%j!<%9$K(Bpull$B$*$h$S%^!<%8$7!$3+H/Cf$N5!G=$,<!$N%j%j!<%9(B +$B$KF~$k$h$&$K%A!<%`$O$=$N%j%j!<%9$N>e$G:n6H$rB3$1$k!%(B + +%\subsection{The Linux kernel model} +\subsection{Linux$B%+!<%M%k%b%G%k(B} + +%The development of the Linux kernel has a shallow hierarchical +%structure, surrounded by a cloud of apparent chaos. Because most +%Linux developers use \command{git}, a distributed revision control +%tool with capabilities similar to Mercurial, it's useful to describe +%the way work flows in that environment; if you like the ideas, the +%approach translates well across tools. + +Linux$B%+!<%M%k$N3+H/$G$O!$<~$j$K:.FY$H$7$?9-$,$j$r;}$D@u$$3,AX9=B$$,<h$i$l(B +$B$F$$$k!%KX$s$I$N(BLinux$B3+H/<T$O(BMercurial$B$HF1MM$N5!G=$r;}$D(B\command{git}$B$H$$(B +$B$&J,;6%j%S%8%g%s4IM}%D!<%k$rMxMQ$7$F$$$k$?$a!$H`$i$,<h$C$F$$$k%o!<%/%U%m!<(B +$B$r=R$Y$k$3$H$O2f!9$K$bLrN)$D!%H`$i$N%"%$%G%#%"$r5$$KF~$l$P!$$=$N%"%W%m!<(B +$B%A$O%D!<%k$N0c$$$r1[$($FM-8z$G$"$k!%(B + +%At the center of the community sits Linus Torvalds, the creator of +%Linux. He publishes a single source repository that is considered the +%``authoritative'' current tree by the entire developer community. +%Anyone can clone Linus's tree, but he is very choosy about whose trees +%he pulls from. + +$B3+H/%3%_%e%K%F%#$NCf?4$O(BLinux$B$NAOB$<T$G$"$k(BLinus Torvalds$B$G$"$k!%H`$O%j%](B +$B%8%H%j$r(B1$B$D8x3+$7$F$*$j!$$=$l$O3+H/%3%_%e%K%F%#A4BN$N8x<0%+%l%s%H%D%j!<$H(B +$B8+Pv$5$l$F$$$k!%C/$G$b(BLinus$B$N%D%j!<$r%/%m!<%s$G$-$k$,!$H`<+?H$O$I$3$+$i(B +pull$B$9$k$+$r87$7$/A*$s$G$$$k!%(B + +%Linus has a number of ``trusted lieutenants''. As a general rule, he +%pulls whatever changes they publish, in most cases without even +%reviewing those changes. Some of those lieutenants are generally +%agreed to be ``maintainers'', responsible for specific subsystems +%within the kernel. If a random kernel hacker wants to make a change +%to a subsystem that they want to end up in Linus's tree, they must +%find out who the subsystem's maintainer is, and ask that maintainer to +%take their change. If the maintainer reviews their changes and agrees +%to take them, they'll pass them along to Linus in due course. + +Linus$B$OB?$/$N(B``$B?.Mj$G$-$kBe9T<T(B''$B$r;}$C$F$$$k!%86B'E*$K$OH`$OH`$i$,8x3+$7(B +$B$?$b$N$O2?$G$b(Bpull$B$9$k!%B?$/$N>l9g!$H`$i$NJQ99$r%l%S%e!<$9$k$3$H$b$7$J(B +$B$$!%Be9T<T$N2??M$+$O%a%s%F%J!<$H$J$k$3$H$rF10U$7$F$*$j!$%+!<%M%kFb$NFCDj(B +$B$N%5%V%7%9%F%`$KBP$7$F@UG$$r;}$D!%%+!<%M%k%O%C%+!<$NC/$+$,(BLinus$B$N%D%j!<$N(B +$B%5%V%7%9%F%`$KJQ99$r2C$($?$$$H;W$C$?$i!$%5%V%7%9%F%`$N%a%s%F%J!<$r8+$D$1(B +$B=P$7$?>e$G!$%a%s%F%J!<$KJQ99$r<h$j9~$s$GLc$&$h$&$K0MMj$9$kI,MW$,$"$k!%%a(B +$B%s%F%J!<$,JQ99$r%l%S%e!<$7!$<h$j9~$`$3$H$KF10U$9$l$P!$@5<0$J%3!<%9$GJQ99(B +$B$r(BLinus$B$K<jEO$9!%(B + +%Individual lieutenants have their own approaches to reviewing, +%accepting, and publishing changes; and for deciding when to feed them +%to Linus. In addition, there are several well known branches that +%people use for different purposes. For example, a few people maintain +%``stable'' repositories of older versions of the kernel, to which they +%apply critical fixes as needed. Some maintainers publish multiple +%trees: one for experimental changes; one for changes that they are +%about to feed upstream; and so on. Others just publish a single +%tree. + +$B$=$l$>$l$NBeM}?M$O%l%S%e!<!$JQ99$N8x3+!$$$$D(BLinus$B$KDs=P$9$k$+$K$D$$$F$=$l(B +$B$>$lFH<+$N%"%W%m!<%A$r<h$C$F$$$k!%$^$?!$JL$NMQES8~$1$K$h$/CN$i$l$?%V%i%s(B +$B%A$,$$$/$D$+$"$j!$Nc$($P4v?M$+$N?M$O%+!<%M%k$N2a5n$N%P!<%8%g%s$N(B +``stable''$B%j%]%8%H%j$r%a%s%F%J%s%9$7!$=EMW$J=$@5$r9T$C$F$$$k!%JL$N%a%s%F(B +$B%J$O!$<B83E*$JJQ99$r<h$j9~$`%D%j!<!$>eN.$K<jEO$9@#A0$NJQ99$r<h$j9~$`%D%j!<(B +$B$J$I$N$h$&$KJ#?t$N%D%j!<$r8x3+$7$F$$$k!%$^$?(B1$B$D$N%D%j!<$@$1$r8x3+$7$F$$$k(B +$B%a%s%F%J$bB?$$!%(B + +%This model has two notable features. The first is that it's ``pull +%only''. You have to ask, convince, or beg another developer to take a +%change from you, because there are almost no trees to which more than +%one person can push, and there's no way to push changes into a tree +%that someone else controls. + +$B$3$N%b%G%k$OCmL\$9$Y$-FCD9$r(B2$B$D;}$C$F$$$k!%Bh0l$K!$$3$l$i$O(Bpull$B%*%s%j!<$G(B +$B$"$k!%JQ99$r<h$j9~$s$GLc$&$?$a$K$O!$B>$N3+H/<T$K0MMj$7$?$j!$@bF@$7$?$j!$(B +$B:)4j$7$?$j$7$J$1$l$P$J$i$J$$!%$J$<$J$i(B2$B?M0J>e$,%W%C%7%e$G$-$k%D%j!<$O$[$H(B +$B$s$I$J$/!$JL$N?M$,%3%s%H%m!<%k$7$F$$$k%D%j!<$KJQ99$r(Bpush$B$9$k=Q$O$J$$$+$i(B +$B$G$"$k!%(B + +%The second is that it's based on reputation and acclaim. If you're an +%unknown, Linus will probably ignore changes from you without even +%responding. But a subsystem maintainer will probably review them, and +%will likely take them if they pass their criteria for suitability. +%The more ``good'' changes you contribute to a maintainer, the more +%likely they are to trust your judgment and accept your changes. If +%you're well-known and maintain a long-lived branch for something Linus +%hasn't yet accepted, people with similar interests may pull your +%changes regularly to keep up with your work. + +$BBhFs$K!$$3$l$OI>H=$H>N;?$H$K$h$k%7%9%F%`$G$"$k$H$$$&$3$H$@!%L5L>$N3+H/<T(B +$B$NJQ99$KBP$7$F$O(BLinus$B$O$*$=$i$/H?1~$9$k$3$H$J$/L5;k$9$k!%$7$+$7%5%V%7%9%F(B +$B%`%a%s%F%J$OJQ99$r%l%S%e!<$7!$E,@Z$G$"$k$HH=CG$9$l$P:N$jF~$l$k!%3+H/<T$,(B +$BNI$$JQ99$r9T$($P9T$&$[$I!$%a%s%F%J$O3+H/<T$NH=CG$r?.MQ$7!$JQ99$r:N$jF~$l(B +$B$k$h$&$K$J$k$@$m$&!%3+H/<T$,CxL>$G!$(BLinus$B$,$$$^$@$K<u$1F~$l$F$$$J$$!$D94|(B +$B4V$K$o$?$k%V%i%s%A$N%a%s%F%J$G$"$k$J$i$P!$F1$86=L#$r;}$D?M!9$,H`$N:n6H$r(B +$B<h$j9~$`$?$a$KJQ99$rDj4|E*$K(Bpull$B$9$k$3$H$@$m$&!%(B + +%Reputation and acclaim don't necessarily cross subsystem or ``people'' +%boundaries. If you're a respected but specialised storage hacker, and +%you try to fix a networking bug, that change will receive a level of +%scrutiny from a network maintainer comparable to a change from a +%complete stranger. + +$BI>H=$H>N;?$O%5%V%7%9%F%`$r1[$($?$j!$<~JU$K$$$k?M!9$r1[$($k$3$H$O$J$$$@$m(B +$B$&!%$b$7$"$J$?$,%9%H%l!<%8$NJ,Ln$G7I0U$r=8$a$k%O%C%+!<$G$"$C$?$H$7$F$b!$(B +$B%M%C%H%o!<%/$N%P%0$r=$@5$7$h$&$H$7$?$N$J$i!$9T$C$?JQ99$O%M%C%H%o!<%/$N%a(B +$B%s%F%J$+$i40A4$JIt30<T$HF1Ey$N@:::$r<u$1$k$3$H$K$J$k$@$m$&!%(B + +%To people who come from more orderly project backgrounds, the +%comparatively chaotic Linux kernel development process often seems +%completely insane. It's subject to the whims of individuals; people +%make sweeping changes whenever they deem it appropriate; and the pace +%of development is astounding. And yet Linux is a highly successful, +%well-regarded piece of software. + +$B@0A3$H$7$?%W%m%8%'%/%H$+$iMh$?3+H/<T$K$H$C$F$O!$(BLinux$B%+!<%M%k$N:.FY$H$7$?(B +$B3+H/%W%m%;%9$O$7$P$7$P40A4$K685$$N:;BA$H;W$($k$3$H$@$m$&!%(BLinux$B%+!<%M%k$G(B +$B$O!$3+H/%W%m%;%9$O8D!9?M$N5$$^$0$l$K0MB8$7$F$*$j!$E,@Z$H9M$($?;~$OA4LLE*(B +$B$JJQ99$r9T$$!$3+H/%Z!<%9$OESJ}$b$J$$!%$=$l$G$b$7$+$7(BLinux$B$OBg$$$K@.8y$7$?(B +$BCmL\$9$Y$-%=%U%H%&%'%"$J$N$G$"$k!%(B + +%\subsection{Pull-only versus shared-push collaboration} +\subsection{Pull$B$N$_(B vs $B6&M-(Bpush$B%3%i%\%l!<%7%g%s(B} + +%A perpetual source of heat in the open source community is whether a +%development model in which people only ever pull changes from others +%is ``better than'' one in which multiple people can push changes to a +%shared repository. + +$B%*!<%W%s%=!<%9%3%_%e%K%F%#$G$OB>$N3+H/<T$N$H$3$m$+$iJQ99$r(Bpull$B$9$k$@$1$N(B +$B3+H/%b%G%k$,!$6&M-%j%]%8%H%j$KB??t$N3+H/<T$,(Bpush$B$G$-$k%b%G%k$h$j$b(B``$BM%$l(B +$B$F$$$k(B''$B$+$I$&$+$,>o$K7c$7$$O@Ah$N<o$K$J$k!%(B + +%Typically, the backers of the shared-push model use tools that +%actively enforce this approach. If you're using a centralised +%revision control tool such as Subversion, there's no way to make a +%choice over which model you'll use: the tool gives you shared-push, +%and if you want to do anything else, you'll have to roll your own +%approach on top (such as applying a patch by hand). + +$B6&M-%W%C%7%e%b%G%k$N;Y;}<T$O!$$3$N%"%W%m!<%A$r6/@)$9$k$h$&$J%D!<%k$r;H$C(B +$B$F$$$k$3$H$,B?$$!%$b$7(BSubversion$B$N$h$&$JCf1{=8Cf7?$N%j%S%8%g%s4IM}%D!<%k(B +$B$r;H$C$F$$$k$N$J$i!$;H$&%b%G%k$rA*$VM>CO$O$=$b$=$bB8:_$7$J$$!%(B +$B$3$l$i$N%D!<%k$G$O6&M-(Bpush$B%b%G%k$r;H$&B>$J$/!$$=$l0J30$N2?$+$r$7$?$$$N$G(B +$B$"$l$P!$!J<+NO$G%Q%C%A$rEv$F$k$J$I$NJ}K!$G!K30It$G9T$&I,MW$,$"$k!%(B + +%A good distributed revision control tool, such as Mercurial, will +%support both models. You and your collaborators can then structure +%how you work together based on your own needs and preferences, not on +%what contortions your tools force you into. + +Mercurial$B$N$h$&$JNI$$J,;6%j%S%8%g%s%3%s%H%m!<%k%D!<%k$O!$N>J}$N%b%G%k$r%5(B +$B%]!<%H$9$k!%%f!<%6$d6(NO<T$O%D!<%k$K$h$C$F6/MW$5$l$k%b%G%k$G$O$J$/!$MW5a(B +$B$d9%$_$K1~$8$?6&F1:n6H$N9=@.$r7h$a$k$3$H$,$G$-$k!%(B + +%\subsection{Where collaboration meets branch management} +\subsection{$B6&F1:n6H$,%V%i%s%A4IM}$HD>LL$9$k$H$3$m(B} + +%Once you and your team set up some shared repositories and start +%propagating changes back and forth between local and shared repos, you +%begin to face a related, but slightly different challenge: that of +%managing the multiple directions in which your team may be moving at +%once. Even though this subject is intimately related to how your team +%collaborates, it's dense enough to merit treatment of its own, in +%chapter~\ref{chap:branch}. + +$B3+H/<T$H$=$N%A!<%`$,6&M-%j%]%8%H%j$r%;%C%H%"%C%W$7!$%m!<%+%k$H6&M-%j%]%8(B +$B%H%j$N4V$GJQ99$r$d$j$H$j$7;O$a$k$H!$$3$l$H4XO"$9$k$,!$$d$d0[$J$C$?:$Fq$K(B +$BD>LL$9$k$h$&$K$J$k$@$m$&!%$=$l$O!$%A!<%`$,F1;~$K?J$a$kB?J}LL$X$N3+H/$r$I(B +$B$N$h$&$K4IM}$9$k$+$H$$$&LdBj$G$"$k!%$3$N2]Bj$O!$%A!<%`$,$I$N$h$&$K6&F1$9(B +$B$k$+$H:,8;E*$K4X78$7$F$*$j!$$3$l$@$1$N$?$a$K(B~\ref{chap:branch}$B$H$$$&0l>O$r(B +$BHq$d$92ACM$,$"$k$@$m$&!%(B + +%\section{The technical side of sharing} +\section{$B6&M-$N5;=QE*B&LL(B} + +%The remainder of this chapter is devoted to the question of serving +%data to your collaborators. + +$B$3$N>O$N;D$j$NItJ,$G$O!$6(NO<T$K%G!<%?$r%5!<%S%9$9$k:]$N5?LdE@$K$D$$$F=R(B +$B$Y$k!%(B + +%\section{Informal sharing with \hgcmd{serve}} +\section{\hgcmd{serve}$B$K$h$kHs8x<0$J6&M-(B} +\label{sec:collab:serve} + +%Mercurial's \hgcmd{serve} command is wonderfully suited to small, +%tight-knit, and fast-paced group environments. It also provides a +%great way to get a feel for using Mercurial commands over a network. + +Mercurial$B$N(B\hgcmd{serve}$B%3%^%s%I$O!$>.5,LO$G6[L)$J3+H/%Z!<%9$NB.$$%0%k!<(B +$B%W4D6-$K$H$F$bE,$7$F$$$k!%(BMercurial$B%3%^%s%I$r%M%C%H%o!<%/1[$7$K;H$&AG@2(B +$B$i$7$5$rBN46$G$-$k$@$m$&!%(B + +%Run \hgcmd{serve} inside a repository, and in under a second it will +%bring up a specialised HTTP server; this will accept connections from +%any client, and serve up data for that repository until you terminate +%it. Anyone who knows the URL of the server you just started, and can +%talk to your computer over the network, can then use a web browser or +%Mercurial to read data from that repository. A URL for a +%\hgcmd{serve} instance running on a laptop is likely to look something +%like \Verb|http://my-laptop.local:8000/|. + +$B%j%]%8%H%jFb$G(B\hgcmd{serve}$B%3%^%s%I$r5/F0$9$k$H!$$9$0$5$^FCJL$J(BHTTP$B%5!<%P(B +$B$,N)$A>e$2$i$l$k!%$3$l$O$"$i$f$k%/%i%$%"%s%H$+$i$N@\B3$r<u$1F~$l!$%j%]%8(B +$B%H%j$N%G!<%?$r%5!<%S%9$9$k!%5/F0$7$?%5!<%P$N(BURL$B$rCN$C$F$$$k?M$d$"$J$?$N%3(B +$B%s%T%e!<%?$K%M%C%H%o!<%/$r2p$7$F@\B32DG=$J?M$OC/$G$b!$%&%'%V%V%i%&%6$d(B +Mercurial$B$r;H$C$F%j%]%8%H%j$+$i%G!<%?$rFI$_=P$9$3$H$,$G$-$k!%%i%C%W%H%C%W(B +$B$G5/F0$5$l$?(B\hgcmd{serve}$B%$%s%9%?%s%9$X$N(BURL$B$O(B +\Verb|http://my-laptop.local:8000/|$B$N$h$&$K$J$k!%(B + +%The \hgcmd{serve} command is \emph{not} a general-purpose web server. +%It can do only two things: +\hgcmd{serve}$B%3%^%s%I$O0lHLMQES8~$1$N%&%'%V%5!<%P$G$O(B\emph{$B$J$$(B}$B!%$3$N%3(B +$B%^%s%I$O<!$N(B2$B$D$N$3$H$@$1$r9T$&!'(B +\begin{itemize} +%\item Allow people to browse the history of the repository it's +% serving, from their normal web browsers. + \item $BIaDL$N%&%'%V%V%i%&%6$r;H$C$F$$$k%f!<%6$KBP$7$F$O%j%]%8%H%j$NMzNr(B + $B$X$N;2>H!%(B +%\item Speak Mercurial's wire protocol, so that people can +% \hgcmd{clone} or \hgcmd{pull} changes from that repository. + \item Mercurial$B$r;H$C$F$$$k%f!<%6$KBP$7$F$O!$(B\hgcmd{clone}$B$^$?$O(B + \hgcmd{pull}$B$,$G$-$k$h$&$K(BMercurial$B%o%$%d%W%m%H%3%k$N%5%]!<%H!%(B + +\end{itemize} +%In particular, \hgcmd{serve} won't allow remote users to \emph{modify} +%your repository. It's intended for read-only use. + +\hgcmd{serve}$B$O%j%b!<%H%f!<%6$K%j%]%8%H%j$NJQ99$r5v2D$7$J$$!%$3$N%3%^%s(B +$B%I$OFI$_=P$7$N$_$N;HMQ$r0U?^$7$F$$$k!%(B + +%If you're getting started with Mercurial, there's nothing to prevent +%you from using \hgcmd{serve} to serve up a repository on your own +%computer, then use commands like \hgcmd{clone}, \hgcmd{incoming}, and +%so on to talk to that server as if the repository was hosted remotely. +%This can help you to quickly get acquainted with using commands on +%network-hosted repositories. + +Mercurial$B$N(B\hgcmd{serve}$B%3%^%s%I$r;H$C$F!$<j85$N%3%s%T%e!<%?$G%j%]%8%H%j(B +$B%5!<%S%9$r9T$&$N$O4JC1$G$"$k!%1sJ}$K$"$k%5!<%P$H$d$j$H$j$9$k$N$HF1MM$K(B +\hgcmd{clone}$B!$(B\hgcmd{incoming}$BEy$N%3%^%s%I$r;H$&$3$H$,$G$-$k!%$3$l$O%j%](B +$B%8%H%j$r%M%C%H%o!<%/$GDs6!$9$k$3$H$K47$l$k$N$KLrN)$D$@$m$&!%(B + +%\subsection{A few things to keep in mind} +\subsection{$B3P$($F$*$/$Y$-(B2, 3$B$NE@(B} + +%Because it provides unauthenticated read access to all clients, you +%should only use \hgcmd{serve} in an environment where you either don't +%care, or have complete control over, who can access your network and +%pull data from your repository. + +\hgcmd{serve}$B$O!$G'>Z$J$7$G%"%/%;%9$r5v$9$?$a!$%M%C%H%o!<%/$X$N%"%/%;%9(B +$B$d!$%j%]%8%H%j$+$i$N%G!<%?(Bpull$B$rC/$,9T$C$F$b9=$o$J$$$h$&$J%M%C%H%o!<%/4D(B +$B6-$d!$40A4$J@)8f$,2DG=$J%M%C%H%o!<%/4D6-$G$N$_;HMQ$9$Y$-$G$"$k!%(B + +%The \hgcmd{serve} command knows nothing about any firewall software +%you might have installed on your system or network. It cannot detect +%or control your firewall software. If other people are unable to talk +%to a running \hgcmd{serve} instance, the second thing you should do +%(\emph{after} you make sure that they're using the correct URL) is +%check your firewall configuration. + +\hgcmd{serve}$B%3%^%s%I$O!$%7%9%F%`$d%M%C%H%o!<%/$K%$%s%9%H!<%k$5$l$F$$$k%U%!(B +$B%$%"%&%)!<%k%=%U%H%&%'%"$K$D$$$F$O2?$b4XCN$7$J$$!%$3$N%3%^%s%I$O%U%!%$%"(B +$B%&%)!<%k$NH/8+$d@)8f$O$G$-$J$$!%B>$N%f!<%6$,(B\hgcmd{serve}$B%3%^%s%I$K%"%/%;(B +$B%9$G$-$J$$>l9g!$$^$:H`$i$,@5$7$$(BURL$B$r;HMQ$7$F$$$k$+3NG'$7!$$=$N<!$K$9$Y$-(B +$B$3$H$O!$%U%!%$%"%&%)!<%k$N@_Dj$r3NG'$9$k$3$H$G$"$k!%(B + +%By default, \hgcmd{serve} listens for incoming connections on +%port~8000. If another process is already listening on the port you +%want to use, you can specify a different port to listen on using the +%\hgopt{serve}{-p} option. + +$B%G%U%)%k%H$G$O(B\hgcmd{serve}$B$OE~Ce$9$k@\B3$r%]!<%H(B~8000$B$GBT$D!%(B +$B;HMQ$7$?$$%]!<%H$r$9$G$KB>$N%W%m%;%9$,;HMQ$7$F$$$k>l9g$O(B +\hgopt{serve}{-p}$B%*%W%7%g%s$r;H$C$FJL$N%]!<%H$GBT5!$9$k$h$&$K;XDj$9$k$3(B +$B$H$,$G$-$k!%(B + +%Normally, when \hgcmd{serve} starts, it prints no output, which can be +%a bit unnerving. If you'd like to confirm that it is indeed running +%correctly, and find out what URL you should send to your +%collaborators, start it with the \hggopt{-v} option. + +$BDL>o!$(B\hgcmd{serve}$B$O;OF0$7$F$b%a%C%;!<%8$N=PNO$r9T$o$J$$!%$3$l$OB?>/:.Mp(B +$B$5$;$k$+$b$7$l$J$$!%<B:]$K@5$7$/F0:n$7$F$$$k$+$I$&$+3NG'$7$?$$>l9g$d!$6((B +$BNO<T$K65$($k(BURL$B$,CN$j$?$$>l9g$O(B\hggopt{-v}$B%*%W%7%g%s$r;XDj$9$k!%(B + +%\section{Using the Secure Shell (ssh) protocol} +\section{Secure Shell (ssh)$B%W%m%H%3%k$N;HMQ(B} +\label{sec:collab:ssh} + +%You can pull and push changes securely over a network connection using +%the Secure Shell (\texttt{ssh}) protocol. To use this successfully, +%you may have to do a little bit of configuration on the client or +%server sides. + +Secure Shell (\texttt{ssh})$B%W%m%H%3%k$r;H$&$3$H$G!$JQ99$r%M%C%H%o!<%/>e$G(B +$B0BA4$K(Bpush$B$G$-$k!%$3$N%W%m%H%3%k$NMxMQ$K$O!$%/%i%$%"%s%HB&$+%5!<%PB&$K>/!9(B +$B@_Dj$,I,MW$G$"$k!%(B + +%If you're not familiar with ssh, it's a network protocol that lets you +%securely communicate with another computer. To use it with Mercurial, +%you'll be setting up one or more user accounts on a server so that +%remote users can log in and execute commands. + +ssh$B$r$"$^$j;H$C$?$3$H$,$J$$%f!<%6$N$?$a$K@bL@$9$k$H!$(Bssh$B$OB>$N%3%s%T%e!<(B +$B%?$H0BA4$KDL?.$r9T$&$?$a$N%M%C%H%o!<%/%W%m%H%3%k$G$"$k!%(B Mercurial$B$G;H$&(B +$B$?$a$K$O!$(B1$B$D0J>e$N%"%+%&%s%H$r%5!<%P$K@_Dj$7!$%j%b!<%H%f!<%6$,%m%0%$%s(B +$B$7!$%3%^%s%I$r<B9T$G$-$k$h$&$K$9$kI,MW$,$"$k!%(B + +%(If you \emph{are} familiar with ssh, you'll probably find some of the +%material that follows to be elementary in nature.) + +$B!J(Bssh$B$KFk@w$_$N$"$k%f!<%6$K$O0J2<$NOC$O=iJbE*$K46$8$i$l$k$K0c$$$J$$!%!K(B + +%\subsection{How to read and write ssh URLs} +\subsection{ssh$B$N(BURL$B$r$I$N$h$&$KFI$`$+(B} + +%An ssh URL tends to look like this: +ssh URL$B$O0lHL$K<!$N$h$&$K$J$k!'(B +\begin{codesample2} + ssh://bos@hg.serpentine.com:22/hg/hgbook +\end{codesample2} +\begin{enumerate} +%\item The ``\texttt{ssh://}'' part tells Mercurial to use the ssh +% protocol. + \item ``\texttt{ssh://}''$BIt$O(BMercurial$B$K(Bssh$B%W%m%H%3%k$r;H$&$3$H$r;X<($9(B + $B$k!%(B +%\item The ``\texttt{bos@}'' component indicates what username to log +% into the server as. You can leave this out if the remote username +% is the same as your local username. + \item ``\texttt{bos@}''$BIt$O%5!<%P$X$N%m%0%$%s$K;H$&%f!<%6L>$r;XDj$9$k!%(B +$B%m!<%+%k%^%7%s$G$N%f!<%6L>$HF1$8$b$N$r;HMQ$9$k>l9g$O;XDj$7$J$/$F$b$h$$!%(B +%\item The ``\texttt{hg.serpentine.com}'' gives the hostname of the +% server to log into. + \item ``\texttt{hg.serpentine.com}''$B$O%m%0%$%s$9$k%5!<%P$N%[%9%HL>$G$"(B + $B$k!%(B +%\item The ``:22'' identifies the port number to connect to the server +% on. The default port is~22, so you only need to specify this part +% if you're \emph{not} using port~22. + \item ``:22''$B%5!<%P$N@\B3%]!<%H$r@)Dj$9$k!%%G%U%)%k%H%]!<%H$O(B~22$B$J$N(B + $B$G!$(B22$BHV0J30$r;H$&;~$N$_;XDj$9$kI,MW$,$"$k!%(B +%\item The remainder of the URL is the local path to the repository on +% the server. + \item URL$B$N;D$j$NItJ,$O%5!<%P>e$N%j%]%8%H%j$X$N%m!<%+%k%Q%9$G$"$k!%(B +\end{enumerate} + +%There's plenty of scope for confusion with the path component of ssh +%URLs, as there is no standard way for tools to interpret it. Some +%programs behave differently than others when dealing with these paths. +%This isn't an ideal situation, but it's unlikely to change. Please +%read the following paragraphs carefully. + +ssh URL$B$N%Q%9It$K$D$$$F$O!$%D!<%k8~$1$KJQ49$9$kI8=`E*$JJ}K!$,$J$$$?$a!$:.(B +$BMp$,B?$$!%$$$/$D$+$N%W%m%0%i%`$H!$$=$NB>$N%W%m%0%i%`$G$O%Q%9$r07$&:]$N5s(B +$BF0$,0[$J$C$F$$$k!%$3$N>u67$OM}A[$H$O$+$1N%$l$F$$$k$,!$=$@5$9$k$N$O:$Fq$@(B +$B$H;W$o$l$k!%0J2<$NCJMn$rCm0U?<$/FI$s$GM_$7$$!%(B + +%Mercurial treats the path to a repository on the server as relative to +%the remote user's home directory. For example, if user \texttt{foo} +%on the server has a home directory of \dirname{/home/foo}, then an ssh +%URL that contains a path component of \dirname{bar} +%\emph{really} refers to the directory \dirname{/home/foo/bar}. +Mercurial$B$O%j%]%8%H%j$X$N%Q%9$r%j%b!<%H%f!<%6$N%[!<%`%G%#%l%/%H%j$+$i$NAj(B +$BBP%Q%9$H$7$F<h$j07$&!%Nc$($P%5!<%P$G%f!<%6(B\texttt{foo}$B$O%[!<%`%G%#%l%/%H(B +$B%j(B\dirname{/home/foo}$B$r;}$D!%=>$C$F(B\dirname{bar}$B$r4^$`(Bssh URL$B$N%Q%9It$O(B +\dirname{/home/foo/bar}$B$H$J$k!%(B + +%If you want to specify a path relative to another user's home +%directory, you can use a path that starts with a tilde character +%followed by the user's name (let's call them \texttt{otheruser}), like +%this. +$BB>$N%f!<%6$N%[!<%`%G%#%l%/%H%j$X$NAjBP%Q%9$r;XDj$7$?$$>l9g$O!$<!$NNc$N$h(B +$B$&$K%A%k%@$K%f!<%6L>$rB3$1$?%Q%9$r;H$&$3$H$,$G$-$k!%!J$3$3$G$OB>$N%f!<%6(B +$B$N%f!<%6L>$r(B\texttt{otheruser}$B$H$9$k!%!K(B +\begin{codesample2} + ssh://server/~otheruser/hg/repo +\end{codesample2} + +%And if you really want to specify an \emph{absolute} path on the +%server, begin the path component with two slashes, as in this example. +$B%5!<%P>e$G@dBP%Q%9$r;XDj$7$?$$>l9g$O!$<!$NNc$N$h$&$K%Q%9It$r(B2$B$D$N%9%i%C%7%e(B +$B$G;O$a$k!%(B +\begin{codesample2} + ssh://server//absolute/path +\end{codesample2} + +%\subsection{Finding an ssh client for your system} +\subsection{$BMxMQCf$N%7%9%F%`8~$1$N(Bssh client$B$r8+$D$1$k(B} + +%Almost every Unix-like system comes with OpenSSH preinstalled. If +%you're using such a system, run \Verb|which ssh| to find out if +%the \command{ssh} command is installed (it's usually in +%\dirname{/usr/bin}). In the unlikely event that it isn't present, +%take a look at your system documentation to figure out how to install +%it. + +Unix$B7O%7%9%F%`$NKX$s$I$O(BOpenSSH$B$,%W%j%$%s%9%H!<%k$5$l$F$$$k!%$=$N$h$&$J%7(B +$B%9%F%`$G$O!$(B\Verb|which ssh|$B$r<B9T$7$F(B\command{ssh}$B%3%^%s%I$,%$%s%9%H!<%k(B +$B$5$l$F$$$k$+$I$&$+D4$Y$k$3$H$,$G$-$k!%!JIaDL$O(B\dirname{/usr/bin}$B$K%$%s%9(B +$B%H!<%k$5$l$F$$$k$O$:$@!%!KK|$,0l%$%s%9%H!<%k$5$l$F$$$J$+$C$?>l9g$O!$%7%9(B +$B%F%`$N%I%-%e%a%s%H$r;2>H$7$F%$%s%9%H!<%kJ}K!$rD4$Y$FM_$7$$!%(B + +%On Windows, you'll first need to choose download a suitable ssh +%client. There are two alternatives. +Windows$B$G$O!$$^$:E,@Z$J(Bssh$B%/%i%$%"%s%H$r%@%&%s%m!<%I$9$kI,MW$,$"$k!%MxMQ(B +$B2DG=$J%/%i%$%"%s%H$O(B2$B$D$"$k!%(B +\begin{itemize} +%\item Simon Tatham's excellent PuTTY package~\cite{web:putty} provides +% a complete suite of ssh client commands. + \item Simon Tatham$B$K$h$kHs>o$KM%$l$?(BPuTTY$B%Q%C%1!<%8(B~\cite{web:putty}$B$O(B + ssh$B%/%i%$%"%s%H$N40A4$J%3%^%s%I72$rDs6!$9$k!%(B +%\item If you have a high tolerance for pain, you can use the Cygwin +% port of OpenSSH. + \item $BLLE]$r1^$o$J$$$N$G$"$l$P!$(BCygwin$BHG$N(BOpenSSH$B$r;H$&$3$H$b$G$-$k!%(B +\end{itemize} +%In either case, you'll need to edit your \hgini\ file to tell +%Mercurial where to find the actual client command. For example, if +%you're using PuTTY, you'll need to use the \command{plink} command as +%a command-line ssh client. + +$B$I$N>l9g$b(B\hgini\ $B%U%!%$%k$rJT=8$7!$(BMercurial$B$K<B:]$N%3%^%s%I$,$I$3$K$"$k(B +$B$N$+$r;X<($7$J$1$l$P$J$i$J$$!%Nc$($P(BPuTTY$B$r;H$&>l9g$O!$(B\command{plink}$B%3(B +$B%^%s%I$r%3%^%s%I%i%$%sHG(Bssh$B%/%i%$%"%s%H$H$7$F;HMQ$9$k!%(B + + +\begin{codesample2} + [ui] + ssh = C:/path/to/plink.exe -ssh -i "C:/path/to/my/private/key" +\end{codesample2} + +\begin{note} +% The path to \command{plink} shouldn't contain any whitespace +% characters, or Mercurial may not be able to run it correctly (so +% putting it in \dirname{C:\\Program Files} is probably not a good +% idea). +\command{plink}$B$X$N%Q%9$O6uGrJ8;z$r4^$s$G$O$J$i$J$$!%6uGr$r4^$`$H(B +Mercurial$B$O@5$7$/<B9T$9$k$3$H$,$G$-$J$$!%!J=>$C$F(B\dirname{C:\\Program +Files}$B$XCV$/$N$O$$$$9M$($H$O8@$($J$$!%!K(B +\end{note} + +%\subsection{Generating a key pair} +\subsection{$B80%Z%"$N:n@.(B} + +%To avoid the need to repetitively type a password every time you need +%to use your ssh client, I recommend generating a key pair. On a +%Unix-like system, the \command{ssh-keygen} command will do the trick. +%On Windows, if you're using PuTTY, the \command{puttygen} command is +%what you'll need. + +ssh$B%/%i%$%"%s%H$r;H$&EY$K7+JV$7%Q%9%o!<%I$rF~NO$9$k$N$rHr$1$k$?$a$K!$80(B +$B%Z%"$r:n@.$9$k$3$H$r4+$a$k!%(BUnix$B7O%7%9%F%`$G$O!$(B\command{ssh-keygen}$B%3%^(B +$B%s%I$G:n@.$G$-$k!%(BWindows$B$G(BPuTTY$B$r;H$C$F$$$k$N$G$"$l(B +$B$P!$(B\command{puttygen}$B$G:n@.$G$-$k!%(B + +%When you generate a key pair, it's usually \emph{highly} advisable to +%protect it with a passphrase. (The only time that you might not want +%to do this id when you're using the ssh protocol for automated tasks +%on a secure network.) + +$B80%Z%"$r:n$k:]$K$O$G$-$k$@$1%Q%9%U%l!<%:$GJ]8n$9$k$3$H$r6/$/4+$a$k!%!J0B(B +$BA4$J%M%C%H%o!<%/$G(Bssh$B%W%m%H%3%k$K$h$C$F<+F0%?%9%/$N<B9T$r$9$k>l9g$K$O$3(B +$B$&$7$?$/$J$$$@$m$&!%!K(B + +%Simply generating a key pair isn't enough, however. You'll need to +%add the public key to the set of authorised keys for whatever user +%you're logging in remotely as. For servers using OpenSSH (the vast +%majority), this will mean adding the public key to a list in a file +%called \sfilename{authorized\_keys} in their \sdirname{.ssh} +%directory. + +$B$7$+$780%Z%"$r:n$k$@$1$G$O==J,$G$J$$!%%j%b!<%H$K%m%0%$%s$7$?$$%^%7%s$N%f!<(B +$B%6$N(Bauthorised keys$B$H$7$F8x3+80$rDI2C$9$kI,MW$,$"$k!%(BOpenSSH$B$r;H$C$F$$$k(B +$B%5!<%P!JBgItJ,$,AjEv$9$k!K$G$O(B\sdirname{.ssh}$B%G%#%l%/%H%j$N(B +\sfilename{authorized\_keys}$B%U%!%$%k$X8x3+80$rDI2C$9$k!%(B + +%On a Unix-like system, your public key will have a \filename{.pub} +%extension. If you're using \command{puttygen} on Windows, you can +%save the public key to a file of your choosing, or paste it from the +%window it's displayed in straight into the +%\sfilename{authorized\_keys} file. + +Unix$B7O%7%9%F%`$G$O8x3+80$O(B\filename{.pub}$B$H$$$&3HD%;R$r;}$D!%(BWindows$B$G(B +\command{puttygen}$B$r;HMQ$9$k>l9g$O!$%U%!%$%k%;!<%V$7$?8x3+80$+!$80$rI=<((B +$B$7$F$$$k%&%#%s%I%&$+$i(B\sfilename{authorized\_keys}$B%U%!%$%k$K%Z!<%9%H$9$l(B +$B$P$h$$!%(B + +%\subsection{Using an authentication agent} +\subsection{$BG'>Z%(!<%8%'%s%H$N;HMQ(B} + +%An authentication agent is a daemon that stores passphrases in memory +%(so it will forget passphrases if you log out and log back in again). +%An ssh client will notice if it's running, and query it for a +%passphrase. If there's no authentication agent running, or the agent +%doesn't store the necessary passphrase, you'll have to type your +%passphrase every time Mercurial tries to communicate with a server on +%your behalf (e.g.~whenever you pull or push changes). + +$BG'>Z%(!<%8%'%s%H$O%Q%9%U%l!<%:$r%a%b%j$KJ]B8$9$k%(!<%8%'%s%H$G$"$k!%!J%m(B +$B%0%"%&%H$7!$:F$S%m%0%$%s$7$?;~$K$O%Q%9%U%l!<%:$O<:$o$l$F$$$k!%!K(Bssh$B%/%i%$(B +$B%"%s%H$O$3$N%G!<%b%s$,F0:n$7$F$$$k$3$H$rG'<1$7!$%Q%9%U%l!<%:$NLd$$9g$o$;(B +$B$r9T$&!%G'>Z%(!<%8%'%s%H$,F0:n$7$F$$$J$$>l9g$d%(!<%8%'%s%H$,I,MW$J%Q%9%U(B +$B%l!<%:$rJ]B8$7$F$$$J$$>l9g$O!$(BMercurial$B$,%5!<%P$H!JJQ99$r(Bpull$B$d(Bpush$B$9$k!K(B +$BDL?.$N;~$K%Q%9%U%l!<%:$rF~NO$9$kI,MW$,$"$k!%(B + +%The downside of storing passphrases in an agent is that it's possible +%for a well-prepared attacker to recover the plain text of your +%passphrases, in some cases even if your system has been power-cycled. +%You should make your own judgment as to whether this is an acceptable +%risk. It certainly saves a lot of repeated typing. + +$B%Q%9%U%l!<%:$r%(!<%8%'%s%H$K5-21$5$;$kJ@32$O!$%Q%o!<%5%$%/%k$r9T$C$F$b>l(B +$B9g$K$h$C$F$O<~E~$J<jCJ$rMQ$$$k967b<T$K%Q%9%U%l!<%:$N%W%l!<%s%F%-%9%H>pJs(B +$B$r<hF@$5$l$k2DG=@-$,$"$k$3$H$G$"$k!%$3$N%j%9%/$,5vMF$GCe$kJ*2TF/$+$O<+J,(B +$B<+?H$GH=CG$7$FM_$7$$!%$3$NJ}K!$rMQ$$$k$3$H$G!$%?%$%W2s?t$r8:$i$;$k$3$H$O(B +$B3N$+$G$"$k!%(B + +%On Unix-like systems, the agent is called \command{ssh-agent}, and +%it's often run automatically for you when you log in. You'll need to +%use the \command{ssh-add} command to add passphrases to the agent's +%store. On Windows, if you're using PuTTY, the \command{pageant} +%command acts as the agent. It adds an icon to your system tray that +%will let you manage stored passphrases. + +Unix$B7O%7%9%F%`$G$O%(!<%8%'%s%H$O(B\command{ssh-agent}$B$H8F$P$l!$%m%0%$%s$9$k(B +$B$H<+F0E*$K5/F0$5$l$k!%(B\command{ssh-add}$B%3%^%s%I$rMQ$$$F%Q%9%U%l!<%:$r%(!<(B +$B%8%'%s%H$K5-21$5$;$k!%(BWindows$B$G(BPuTTY$B$r;H$C$F$$$k>l9g$O!$(B\command{pageant}$B%3(B +$B%^%s%I$,%(!<%8%'%s%H$H$7$FF0:n$9$k!%$3$N%3%^%s%I$O5-21$7$?%Q%9%U%l!<%:$r(B +$B4IM}$9$k$?$a$K%7%9%F%`%H%l%$$K%"%$%3%s$rDI2C$9$k!%(B + + +%\subsection{Configuring the server side properly} +\subsection{$B%5!<%P$N@5$7$$@_Dj(B} + +%Because ssh can be fiddly to set up if you're new to it, there's a +%variety of things that can go wrong. Add Mercurial on top, and +%there's plenty more scope for head-scratching. Most of these +%potential problems occur on the server side, not the client side. The +%good news is that once you've gotten a configuration working, it will +%usually continue to work indefinitely. + +ssh$B$O47$l$F$$$J$$$H@_Dj$,Fq$7$$$?$a!$4V0c$$$rHH$9M>CO$O$$$?$k=j$K$"$k!%(B +Mercurial$B$H6&$KF0$+$9>l9g!$$5$i$KB?$/$,BT$A9=$($F$$$k!%$3$l$i$NKX$s$I$,%/(B +$B%i%$%"%s%HB&$G$O$J$/%5!<%PB&$G5/$-$k!%$7$+$70lEY$-$A$s$HF0:n$9$k@_Dj$r$7(B +$B$F$7$^$($P!$F0:n$O$:$C$HB3$/!%(B + +%Before you try using Mercurial to talk to an ssh server, it's best to +%make sure that you can use the normal \command{ssh} or \command{putty} +%command to talk to the server first. If you run into problems with +%using these commands directly, Mercurial surely won't work. Worse, it +%will obscure the underlying problem. Any time you want to debug +%ssh-related Mercurial problems, you should drop back to making sure +%that plain ssh client commands work first, \emph{before} you worry +%about whether there's a problem with Mercurial. + +Mercurial$B$+$i(Bssh$B%5!<%P$K@\B3$9$kA0$K!$(B\command{ssh}$B$^$?$O(B\command{putty} +$B%3%^%s%I$r;H$C$F%5!<%P$K@\B3$7$F$_$k$3$H$r4+$a$k!%$3$l$i$N%3%^%s%I$rD>@\(B +$B;H$C$FLdBj$,5/$-$k$h$&$G$"$l$P!$(BMercurial$B$OF0:n$7$J$$$O$:$@!%(B ssh$B$N>e$G(B +Mercurial$B$r;H$&$3$H$G!$2<0L$NLdBj$,1#$l$F$7$^$&$N$G!$(Bssh$B$K4XO"$7$?(B +Mercurial$B$NLdBj$r%G%P%C%0$9$k;~$O!$$^$:(Bssh$B%/%i%$%"%s%H%3%^%s%I<+BN$,F0:n(B +$B$9$k$3$H$r3NG'$7!$$=$N8e$K(BMercurial$B$NLdBj$r2r7h$9$Y$-$G$"$k!%(B + +%The first thing to be sure of on the server side is that you can +%actually log in from another machine at all. If you can't use +%\command{ssh} or \command{putty} to log in, the error message you get +%may give you a few hints as to what's wrong. The most common problems +%are as follows. + +$B%5!<%PB&$G$^$:3NG'$9$Y$-$J$N$O!$B>$N%^%7%s$+$i%m%0%$%s$G$-$k$+$I$&$+$G$"(B +$B$k!%(B \command{ssh}$B$^$?$O(B\command{putty}$B%3%^%s%I$G%m%0%$%s$G$-$J$$>l9g$O!$(B +$B%(%i!<%a%C%;!<%8$K2?$,0-$$$N$+<($9%R%s%H$,$"$k$+$bCN$l$J$$!%:G$b0lHLE*$J(B +$BLdBj$r0J2<$KNs5s$9$k!%(B +\begin{itemize} +%\item If you get a ``connection refused'' error, either there isn't an +% SSH daemon running on the server at all, or it's inaccessible due to +% firewall configuration. + \item ``connection refused''$B%(%i!<$,=P$k;~$O!$(BSSH$B%G!<%b%s$,F0:n$7$F$$$J(B + $B$$$+!$%U%!%$%"%&%)!<%k@_Dj$N$?$a$K%^%7%s$X$N%"%/%;%9$,IT2DG=$G$"(B + $B$k2DG=@-$,$"$k!%(B +%\item If you get a ``no route to host'' error, you either have an +% incorrect address for the server or a seriously locked down firewall +% that won't admit its existence at all. + \item ``no route to host''$B%(%i!<$,=P$k>l9g$O!$%5!<%P$N%"%I%l%9$r4V0c$((B + $B$F$$$k$+!$%U%!%$%"%&%)!<%k$,%5!<%P$r40A4$K1#$7$F$7$^$C$F$$$k$3$H(B + $B$,9M$($i$l$k!%(B +%\item If you get a ``permission denied'' error, you may have mistyped +% the username on the server, or you could have mistyped your key's +% passphrase or the remote user's password. + \item ``permission denied''$B%(%i!<$,=P$k>l9g$O!$%f!<%6L>$r4V0c$C$FF~NO$7(B + $B$F$$$k$+!$%m%0%$%sMQ80$N%Q%9%U%l!<%:$d%f!<%6%Q%9%o!<%I$r4V0c$C$F(B + $BF~NO$7$F$$$k2DG=@-$,$"$k!%(B +\end{itemize} +%In summary, if you're having trouble talking to the server's ssh +%daemon, first make sure that one is running at all. On many systems +%it will be installed, but disabled, by default. Once you're done with +%this step, you should then check that the server's firewall is +%configured to allow incoming connections on the port the ssh daemon is +%listening on (usually~22). Don't worry about more exotic +%possibilities for misconfiguration until you've checked these two +%first. + +$B$^$H$a$k$H!$%5!<%P$N(Bssh$B%G!<%b%s$X@\B3$9$k:]$K$O!$$^$:%G!<%b%s$,F0:n$7$F$$(B +$B$k$+$r3NG'$9$k$3$H!%%G%U%)%k%H$G%$%s%9%H!<%k$5$l$F$O$$$k$,!$Dd;_$5$l$F$$(B +$B$k%7%9%F%`$b$"$k!%$3$l$r3NG'$7$?8e$G%5!<%P$N%U%!%$%"%&%)!<%k$,(Bssh$B%G!<%b%s(B +$B$NBT5!$7$F$k%]!<%H!JDL>o$O(B22$BHV!K$X$N@\B3$r5v2D$7$F$$$k$+3NG'$9$k!%B>$N=t!9(B +$B$N2DG=@-$r9M$($kA0$K$^$:$3$N(B2$BE@$r3NG'$9$Y$-$G$"$k!%(B + +%If you're using an authentication agent on the client side to store +%passphrases for your keys, you ought to be able to log into the server +%without being prompted for a passphrase or a password. If you're +%prompted for a passphrase, there are a few possible culprits. + +$B%/%i%$%"%s%HB&$G80$N%Q%9%U%l!<%:$r5-21$5$;$k$?$a$KG'>Z%(!<%8%'%s%H$rF0$+(B +$B$7$F$$$k$J$i!$%Q%9%U%l!<%:$d%Q%9%o!<%I$NF~NO$rB%$5$l$k$3$H$J$7$K%5!<%P$K(B +$B%m%0%$%s$G$-$k$O$:$@!%$b$7%Q%9%U%l!<%:$NF~NO$rMW5a$5$l$k$J$i!$$$$/$D$+$N(B +$B2DG=@-$,9M$($i$l$k!%(B +\begin{itemize} +%\item You might have forgotten to use \command{ssh-add} or +% \command{pageant} to store the passphrase. + \item $B%Q%9%U%l!<%:$r5-21$5$;$k$?$a$K(B\command{ssh-add}$B$^$?$O(B + \command{pageant}$B$r<B9T$7$F$$$J$$!%(B +%\item You might have stored the passphrase for the wrong key. + \item $BJL$N%-!<$N%Q%9%U%l!<%:$r5-21$5$;$F$$$k!%(B +\end{itemize} +%If you're being prompted for the remote user's password, there are +%another few possible problems to check. +$B%j%b!<%H%f!<%6$N%Q%9%o!<%I$rMW5a$5$l$k>l9g$OJL$NLdBj$,$"$k$+$b$7$l$J$$!%(B +\begin{itemize} +%\item Either the user's home directory or their \sdirname{.ssh} +% directory might have excessively liberal permissions. As a result, + +% the ssh daemon will not trust or read their +% \sfilename{authorized\_keys} file. For example, a group-writable +% home or \sdirname{.ssh} directory will often cause this symptom. + \item $B%f!<%6$N%[!<%`%G%#%l%/%H%j$^$?$O(B\sdirname{.ssh}$B%G%#%l%/%H%j$N%Q!<(B + $B%_%C%7%g%s$,4K$9$.$k!%$3$N$?$a!$(Bssh$B%G!<%b%s$,(B + \sfilename{authorized\_keys}\sfilename{authorized\_keys}$B%U%!%$%k$r(B + $B?.Mj$G$-$J$$$+!$$"$k$$$OC1=c$KFI$a$J$$!%Nc$($P%0%k!<%W=q$-9~$_%Q!<(B + $B%_%C%7%g%s$N$"$k%[!<%`%G%#%l%/%H%j$^$?$O(B\sdirname{.ssh}$B%G%#%l%/%H(B + $B%j$O$3$NLdBj$r$7$P$7$P0z$-5/$3$9!%(B +%\item The user's \sfilename{authorized\_keys} file may have a problem. +% If anyone other than the user owns or can write to that file, the +% ssh daemon will not trust or read it. + \item $B%f!<%6$N(B\sfilename{authorized\_keys}$B%U%!%$%k$KLdBj$,$"$k!%%U%!%$(B + $B%k$N=jM-<T$,JL$N%f!<%6$@$C$?$j!$B>$N%f!<%6$,=q$-9~$_$G$-$k>l9g$O(B + ssh$B%G!<%b%s$O$3$N%U%!%$%k$r?.Mj$;$:!$FI$_9~$^$J$$!%(B +\end{itemize} + +%In the ideal world, you should be able to run the following command +%successfully, and it should print exactly one line of output, the +%current date and time. +$BM}A[$G$O!$<!$N%3%^%s%I$r<B9T$7!$(B1$B9T$G8=:_$NF|;~$rI=<($G$-$k$Y$-$G$"$k!%(B +\begin{codesample2} + ssh myserver date +\end{codesample2} + +%If, on your server, you have login scripts that print banners or other +%junk even when running non-interactive commands like this, you should +%fix them before you continue, so that they only print output if +%they're run interactively. Otherwise these banners will at least +%clutter up Mercurial's output. Worse, they could potentially cause +%problems with running Mercurial commands remotely. Mercurial makes +%tries to detect and ignore banners in non-interactive \command{ssh} +%sessions, but it is not foolproof. (If you're editing your login +%scripts on your server, the usual way to see if a login script is +%running in an interactive shell is to check the return code from the +%command \Verb|tty -s|.) + +$B%5!<%P$G!$%P%J!<$d$=$NB>$N0UL#$N$J$$J8;zNs$rI=<($9$k$h$&$J%m%0%$%s%9%/%j(B +$B%W%H$r;H$C$F$$$k>l9g!$BPOCE*$J%3%^%s%I0J30$G$O$3$l$i$rI=<($7$J$$$h$&$K$9(B +$B$k!%$3$l$i$NJ8;zNs$O(BMercurial$B$N=PNO$K:.F~$7$F$7$^$$!$(BMercurial$B%3%^%s%I$r(B +$B%j%b!<%H<B9T$9$kK8$2$H$J$k!%(B +Mercurial$B$OHsBPOCE*$J(B\command{ssh}$B$G$O$3$l$i$N%P%J!<$r8!=P$7!$L5;k$7$h$&(B +$B$H;n$_$k$,!$$3$l$OK|A4$G$O$J$$!%!J%5!<%P$N%m%0%$%s%9%/%j%W%H$rJT=8$9$k>l(B +$B9g!$%m%0%$%s%9%/%j%W%H$,BPOCE*%7%'%k$GF0:n$7$F$$$k$+$rCN$kJ}K!$H$7(B +$B$F!$(B\Verb|tty -s|$B%3%^%s%I$N%j%?!<%s%3!<%I$r%A%'%C%/$9$kJ}K!$,$"$k!%!K(B + +%Once you've verified that plain old ssh is working with your server, +%the next step is to ensure that Mercurial runs on the server. The +%following command should run successfully: +ssh$BC1BN$G%5!<%P$K@\B3$G$-$k$3$H$r3NG'$7$?$i!$(BMercurial$B$,%5!<%P$GF0:n$9$k(B +$B$3$H$r3NG'$9$k!%<!$N%3%^%s%I$,F0$/$+$I$&$+D4$Y$F$_$h$&!'(B +\begin{codesample2} + ssh myserver hg version +\end{codesample2} +%If you see an error message instead of normal \hgcmd{version} output, +%this is usually because you haven't installed Mercurial to +%\dirname{/usr/bin}. Don't worry if this is the case; you don't need +%to do that. But you should check for a few possible problems. +\hgcmd{version}$B$N=PNO$G$O$J$/%(%i!<%a%C%;!<%8$,I=<($5$l$k$H$-(B +$B$O!$(B\dirname{/usr/bin}$B$K(BMercurial$B$,%$%s%9%H!<%k$5$l$F$$$J$$$3$H$,B?$$!%(B +$B$3$N>l9g!$(B\dirname{/usr/bin}$B$K%$%s%9%H!<%k$7D>$9I,MW$O$J$$!%$=$NBe$o$j!$(B +$B$$$/$D$+$NLdBj$r%A%'%C%/$9$Y$-$G$"$k!%(B +\begin{itemize} +%\item Is Mercurial really installed on the server at all? I know this +% sounds trivial, but it's worth checking! + \item $B%5!<%P$K(BMercurial$B$OK\Ev$K%$%s%9%H!<%k$5$l$F$$$k$+!)(B $B$3$l$O2<$i$J(B + $B$$Ld$$$N$h$&$K;W$($k$,!$3NG'$9$k2ACM$O$"$k!%(B +%\item Maybe your shell's search path (usually set via the \envar{PATH} +% environment variable) is simply misconfigured. + \item $B%7%'%k$N%5!<%A%Q%9$,@5$7$/@_Dj$5$l$F$$$J$$!%!JDL>o$O4D6-JQ?t(B + \envar{PATH}$B$G@_Dj$5$l$k!%!K(B + +%\item Perhaps your \envar{PATH} environment variable is only being set +% to point to the location of the \command{hg} executable if the login + +% session is interactive. This can happen if you're setting the path +% in the wrong shell login script. See your shell's documentation for +% details. + \item $BBPOCE*$J%m%0%$%s%;%C%7%g%s$N$H$-0J30$O4D6-JQ?t(B\envar{PATH}$B$,(B + \command{hg}$B<B9T%U%!%$%k$N$"$k%Q%9$r;X$7$F$$$J$$!%(B\envar{PATH}$B$rIT(B + $BE,@Z$J%m%0%$%s%9%/%j%W%H$G@_Dj$7$F$$$k$H$3$NLdBj$,5/$-$k!%>\$7$/$O(B + $B%7%'%k$N%I%-%e%a%s%H$r;2>H$9$k$3$H!%(B +%\item The \envar{PYTHONPATH} environment variable may need to contain +% the path to the Mercurial Python modules. It might not be set at +% all; it could be incorrect; or it may be set only if the login is +% interactive. + \item $B4D6-JQ?t(B\envar{PYTHONPATH}$B$,(BMercurial Python$B%b%8%e!<%k$r4^$`I,MW(B + $B$,$"$k>l9g!%$3$l$,A4$/@_Dj$5$l$F$$$J$$$+!$BPOCE*$J%m%0%$%s$G$N$_(B + $BM-8z$K$J$C$F$$$k!%(B +\end{itemize} + +%If you can run \hgcmd{version} over an ssh connection, well done! +%You've got the server and client sorted out. You should now be able +%to use Mercurial to access repositories hosted by that username on +%that server. If you run into problems with Mercurial and ssh at this +%point, try using the \hggopt{--debug} option to get a clearer picture +%of what's going on. + +ssh$B@\B3$G(B\hgcmd{version}$B$r<B9T$G$-$?$N$J$i=`Hw$O40N;$@!%%5!<%P$H%/%i%$%"(B +$B%s%H$N@_Dj$O@5$7$/9T$o$l$F$$$k!%$3$l$G%5!<%PB&$N%f!<%6L>$r;H$C$F%[%9%H$5(B +$B$l$F$$$k%j%]%8%H%j$K(BMercurial$B$r;H$C$F%"%/%;%9$G$-$k$h$&$K$J$C$?!%$3$3$GLd(B +$BBj$,$"$k$N$J$i!$(B\hggopt{--debug}$B%*%W%7%g%s$r;H$C$F2?$,LdBj$J$N$+$r$h$jL@(B +$B3N$KGD0.$7$FM_$7$$!%(B + +%\subsection{Using compression with ssh} +\subsection{ssh$B$G$N05=L$NMxMQ(B} + +%Mercurial does not compress data when it uses the ssh protocol, +%because the ssh protocol can transparently compress data. However, +%the default behaviour of ssh clients is \emph{not} to request +%compression. + +Mercurial$B$O!$(Bssh$B%W%m%H%3%k$r;H$C$?>l9g$O!$%G!<%?$N05=L$O9T$o$J$$!%(Bssh$B%W%m(B +$B%H%3%k$,F)2aE*$K%G!<%?$N05=L$r9T$&$3$H$,$G$-$k$?$a$G$"$k!%$7$+$7(Bssh$B%/%i%$(B +$B%"%s%H$N%G%U%)%k%H$N5sF0$G$O!$05=L$r9T$o(B\emph{$B$J$$(B}$B!%(B + +%Over any network other than a fast LAN (even a wireless network), +%using compression is likely to significantly speed up Mercurial's +%network operations. For example, over a WAN, someone measured +%compression as reducing the amount of time required to clone a +%particularly large repository from~51 minutes to~17 minutes. + +$B9bB.$J(BLAN$B0J30$N%M%C%H%o!<%/!J%o%$%d%l%9%M%C%H%o!<%/$b4^$`!K$G(B +$B$O!$(BMercurial$B$N%M%C%H%o!<%/F0:n$r9bB.2=$9$k$N$K05=L$N;HMQ$O$H$F$b8z2LE*$G(B +$B$"$k!%$"$k%f!<%6$N7WB,$K$h$l$P!$(BWAN$B7PM3$G$NBg5,LO$J%j%]%8%H%j$N%/%m!<%s(B +$B$O!$05=L$r;H$&$3$H$G(B~51$BJ,$+$i(B~17$BJ,$KC;=L$9$k$3$H$,$G$-$?!%(B + +%Both \command{ssh} and \command{plink} accept a \cmdopt{ssh}{-C} +%option which turns on compression. You can easily edit your \hgrc\ to +%enable compression for all of Mercurial's uses of the ssh protocol. +\command{ssh}$B%3%^%s%I$b(B\command{plink}$B%3%^%s%I$b05=L$rM-8z$K$9$k(B +\cmdopt{ssh}{-C}$B%*%W%7%g%s$,;H$($k!%(B\hgrc\ $B%U%!%$%k$rJT=8$7$F(BMercurial$B$,(B +$B05=L$D$-$N(Bssh$B%W%m%H%3%k$r;HMQ$9$k$h$&$K@_Dj$9$k$3$H$,$G$-$k!%(B +\begin{codesample2} + [ui] + ssh = ssh -C +\end{codesample2} + +%If you use \command{ssh}, you can configure it to always use +%compression when talking to your server. To do this, edit your +%\sfilename{.ssh/config} file (which may not yet exist), as follows. +\command{ssh}$B$G%5!<%P$X@\B3$9$k;~$K>o$K05=L$r;HMQ$9$k$h$&$K@_Dj$9$k$3$H$,(B +$B$G$-$k!%(B\sfilename{.ssh/config}$B%U%!%$%k!JB8:_$7$J$$>l9g$O:n@.$9$k!K$r<!(B +$B$N$h$&$KJT=8$9$k!%(B +\begin{codesample2} + Host hg + Compression yes + HostName hg.example.com +\end{codesample2} +%This defines an alias, \texttt{hg}. When you use it on the +%\command{ssh} command line or in a Mercurial \texttt{ssh}-protocol +%URL, it will cause \command{ssh} to connect to \texttt{hg.example.com} +%and use compression. This gives you both a shorter name to type and +%compression, each of which is a good thing in its own right. +$B$3$l$O(Balias \texttt{hg}$B$rDj5A$9$k!%$3$N(Balias$B$r(B\command{ssh}$B$N%3%^%s%I%i%$(B +$B%s$G;H$&$+(BMercurial \texttt{ssh}-$B%W%m%H%3%k(B URL$B$G;HMQ$9$k$H(B\command{ssh} +$B%3%^%s%I(Bh$B$O(B\texttt{hg.example.com}$B$X05=L$rMQ$$$F@\B3$r9T$&!%C;=L7A$N%[%9(B +$B%HL>$H05=L$N@_Dj$rF1;~$K9T$&$3$H$,$G$-$k!%(B + +%\section{Serving over HTTP using CGI} +\section{CGI$B$r;HMQ$7$?(BHTTP$B$K$h$k%5!<%S%9(B} +\label{sec:collab:cgi} + +%Depending on how ambitious you are, configuring Mercurial's CGI +%interface can take anything from a few moments to several hours. + +$B$I$NDxEY$N$3$H$rA@$&$+$K$h$C$F!$(BMercurial$B$N(BCGI$B%$%s%?%U%'!<%9$N@_Dj$K$O?t(B +$BJ,$+$i?t;~4VDxEY$N;~4V$,$+$+$k!%(B + +%We'll begin with the simplest of examples, and work our way towards a +%more complex configuration. Even for the most basic case, you're +%almost certainly going to need to read and modify your web server's +%configuration. + +$B$3$3$G$O:G$bC1=c$JNc$+$i;O$a$F!$$h$jJ#;($J@_Dj$X?J$s$G$$$/$3$H$K$7$h$&!%(B +$B:G$bC1=c$J%1!<%9$G$b$*$=$i$/%&%'%V%5!<%P$N@_Dj$rD4$Y$FJQ99$9$kI,MW$,$"$k(B +$B$@$m$&!%(B + +\begin{note} +% Configuring a web server is a complex, fiddly, and highly +% system-dependent activity. I can't possibly give you instructions +% that will cover anything like all of the cases you will encounter. +% Please use your discretion and judgment in following the sections +% below. Be prepared to make plenty of mistakes, and to spend a lot +% of time reading your server's error logs. +$B%&%'%V%5!<%P$N@_Dj$OJ#;($+$DLq2p$G%7%9%F%`0MB8$N:n6H$G$"$k!%(B +$BFI<T$,Ax6x$9$k$9$Y$F$N%1!<%9$K$D$$$F<j0z$-$r$9$k$3$H$O$G$-$J$$$@$m$&!%(B +$B0J2<$N%;%/%7%g%s$G$O!$FI$_$J$,$iFI<T<+?H$N;WN8$HH=CG$rF/$+$;$FM_$7$$!%(B +$B$?$/$5$s$N%_%9$rHH$7!$%5!<%P$N%(%i!<%m%0$N2rFI$KB?$/$N;~4V$r3d$/$3$H$K$J(B +$B$k$N$r4N$KLC$8$F$*$$$FM_$7$$!%(B +\end{note} + +%\subsection{Web server configuration checklist} +\subsection{Web$B%5!<%P@_Dj$N%A%'%C%/%j%9%H(B} + +%Before you continue, do take a few moments to check a few aspects of +%your system's setup. +$B$3$3$+$i@h$X?J$`A0$K!$FI<T$N%7%9%F%`$K$D$$$F3NG'$r$7$F$*$3$&!%(B + +\begin{enumerate} +%\item Do you have a web server installed at all? Mac OS X ships with +% Apache, but many other systems may not have a web server installed. + \item $B%&%'%V%5!<%P$O$9$G$K%$%s%9%H!<%k$5$l$F$$$k$+!)(B Mac OS X$B$K$OI8=`$G(B + Apache$B$,%$%s%9%H!<%k$5$l$F$$$k$,!$B>$N%7%9%F%`$G$O%&%'%V%5!<%P$,(B + $B%$%s%9%H!<%k$5$l$F$$$J$$$3$H$b$"$k!%(B +%\item If you have a web server installed, is it actually running? On +% most systems, even if one is present, it will be disabled by +% default. + \item $B%&%'%V%5!<%P$,%$%s%9%H!<%k$5$l$F$$$k>l9g!$$9$G$KF0:n$7$F$$$k$+!)(B + $BB?$/$N%7%9%F%`$G$O!$%G%U%)%k%H$GDd;_$5$l$F$$$k!%(B +%\item Is your server configured to allow you to run CGI programs in +% the directory where you plan to do so? Most servers default to +% explicitly disabling the ability to run CGI programs. + \item $B%&%'%V%5!<%P$O(BCGI$B%W%m%0%i%`$rL\E*$N%G%#%l%/%H%j$GF0:n$G$-$k$h$&$K(B + $B@_Dj$5$l$F$$$k$+!)(B $BBgH>$N%5!<%P$G$O%G%U%)%k%H$G(BCGI$B%W%m%0%i%`$NF0(B + $B:n$rL@<(E*$K6X$8$F$$$k!%(B +\end{enumerate} + +%If you don't have a web server installed, and don't have substantial +%experience configuring Apache, you should consider using the +%\texttt{lighttpd} web server instead of Apache. Apache has a +%well-deserved reputation for baroque and confusing configuration. +%While \texttt{lighttpd} is less capable in some ways than Apache, most +%of these capabilities are not relevant to serving Mercurial +%repositories. And \texttt{lighttpd} is undeniably \emph{much} easier +%to get started with than Apache. + +$B%&%'%V%5!<%P$,%$%s%9%H!<%k$5$l$F$$$J$$>l9g$d!$(BApach$B$N@_Dj$K==J,$J7P83$,$J(B +$B$$>l9g$O!$(BApache$B$G$O$J$/(B\texttt{lighttpd}$B%&%'%V%5!<%P$r8!F$$7$?J}$,$h$$$@(B +$B$m$&!%(BApache$B$O4q0[$G:.Mp$9$k@_Dj$G0-L>$,9b$$!%(B \texttt{lighttpd}$B$O(BApache +$B$h$j$b$G$-$k$3$H$,>/$J$$$,!$$=$l$i$O(BMercurial$B%j%]%8%H%j$N%5!<%S%9$H$O4X78(B +$B$,$J$$!%(B \texttt{lighttpd}$B$O(BApache$B$h$j$bL@$i$+$K4JC1$K;H$&$3$H$,$G$-$k!%(B + +%\subsection{Basic CGI configuration} +\subsection{CGI$B$N4pK\E*$J@_Dj(B} + +%On Unix-like systems, it's common for users to have a subdirectory +%named something like \dirname{public\_html} in their home directory, +%from which they can serve up web pages. A file named \filename{foo} +%in this directory will be accessible at a URL of the form +%\texttt{http://www.example.com/\~username/foo}. + +Unix$B7O%7%9%F%`$G$O!$%f!<%6$N%[!<%`%G%#%l%/%H%j$K%&%'%V%Z!<%8$r%5!<%S%9$9(B +$B$k$?$a$N(B\dirname{public\_html}$B$H$$$&%5%V%G%#%l%/%H%j$,$"$k$3$H$,IaDL$G$"(B +$B$k!%$3$N%G%#%l%/%H%jFb$N(B\filename{foo}$B$H$$$&%U%!%$%k$O(B +\texttt{http://www.example.com/\~username/foo}$B$H$$$&(BURL$B$G%"%/%;%9$G$-$k!%(B + +%To get started, find the \sfilename{hgweb.cgi} script that should be +%present in your Mercurial installation. If you can't quickly find a +%local copy on your system, simply download one from the master +%Mercurial repository at +%\url{http://www.selenic.com/repo/hg/raw-file/tip/hgweb.cgi}. + +$B$^$:%$%s%9%H!<%k$5$l$F$$$k(BMercurial$B$+$i(B\sfilename{hgweb.cgi}$B%9%/%j%W%H$r(B +$B8+$D$1$k!%$9$0$K%m!<%+%k%3%T!<$,8+$D$+$i$J$1$l$P!$(BMercurial$B$N%^%9%?!<%j(B +$B%]%8%H%j(B \url{http://www.selenic.com/repo/hg/raw-file/tip/hgweb.cgi} $B$+(B +$B$i%@%&%s%m!<%I$9$k!%(B + +%You'll need to copy this script into your \dirname{public\_html} +%directory, and ensure that it's executable. + +$B$3$N%9%/%j%W%H$r(B\dirname{public\_html}$B%G%#%l%/%H%j$K%3%T!<$7!$%U%!%$%k$,(B +$B<B9T2DG=$G$"$k$+$r%A%'%C%/$9$k!%(B +\begin{codesample2} + cp .../hgweb.cgi ~/public_html + chmod 755 ~/public_html/hgweb.cgi +\end{codesample2} +%The \texttt{755} argument to \command{chmod} is a little more general +%than just making the script executable: it ensures that the script is +%executable by anyone, and that ``group'' and ``other'' write +%permissions are \emph{not} set. If you were to leave those write +%permissions enabled, Apache's \texttt{suexec} subsystem would likely +%refuse to execute the script. In fact, \texttt{suexec} also insists +%that the \emph{directory} in which the script resides must not be +%writable by others. + +\command{chmod}$B%3%^%s%I$X(B\texttt{755}$B$rEO$9$H!$%9%/%j%W%H$O<B9T2DG=$h$j$b(B +$B<c430lHLE*$K$J$k!%%9%/%j%W%H$OC/$+$i$b<B9T2DG=$@$,!$(B``group''$B$H(B``other'' +$B$N%f!<%6$+$i$O=q$-9~$a$J$/$J$k!%=q$-9~$_%Q!<%_%C%7%g%s$,M-8z$G$"$k(B +$B$H!$(BApache$B$N(B\texttt{suexec}$B%5%V%7%9%F%`$O%9%/%j%W%H$N<B9T$r5qH]$9$k2DG=@-(B +$B$,9b$$!%<B:]$N$H$3$m!$(B\texttt{suexec}$B$O$5$i$K%9%/%j%W%H$NCV$+$l$F$$$k(B +\emph{$B%G%#%l%/%H%j(B}$B$,B>$N%f!<%6$N=q$-9~$_$r5qH]$9$k@_Dj$G$"$k$3$H$rMW5a$9(B +$B$k!%(B + +\begin{codesample2} + chmod 755 ~/public_html +\end{codesample2} + +%\subsubsection{What could \emph{possibly} go wrong?} +\subsubsection{$B$I$3$,LdBj$H@.$jF@$k$+(B?} +\label{sec:collab:wtf} + +%Once you've copied the CGI script into place, go into a web browser, +%and try to open the URL \url{http://myhostname/~myuser/hgweb.cgi}, +%\emph{but} brace yourself for instant failure. There's a high +%probability that trying to visit this URL will fail, and there are +%many possible reasons for this. In fact, you're likely to stumble +%over almost every one of the possible errors below, so please read +%carefully. The following are all of the problems I ran into on a +%system running Fedora~7, with a fresh installation of Apache, and a +%user account that I created specially to perform this exercise. + +CGI$B%9%/%j%W%H$r=jDj$N>l=j$K%3%T!<$7$?$i!$%&%'%V%V%i%&%6$r5/F0$7$F(B +\url{http://myhostname/~myuser/hgweb.cgi} $B$r3+$/!%$7$+$7$3$N(BURL$B$K%"%/%;%9(B +$B$7$F$b%(%i!<$,$G$k2DG=@-$,9b$$$N$G!$Mn$ACe$$$FM_$7$$!%%(%i!<$K$OB?$/$NM}(B +$BM3$,9M$($i$l!$<B:]!$$=$N$9$Y$F$K0z$C3]$+$C$F$$$k2DG=@-$,9b$$$N$G!$0J2<$N(B +$B5-=R$rCm0U?<$/FI$s$GM_$7$$!%$3$3$K5s$2$?$N$O!$(BFedora~7$B$G!$?75,$K%$%s%9%H!<(B +$B%k$5$l$?(BApache$B$H!$$3$NNcBj$N$?$a$K?75,$K:n@.$7$?%f!<%6%"%+%&%s%H$GI.<T$,(B +$B<B:]$K$GAx6x$7$?LdBj$G$"$k!%(B + +%Your web server may have per-user directories disabled. If you're +%using Apache, search your config file for a \texttt{UserDir} +%directive. If there's none present, per-user directories will be +%disabled. If one exists, but its value is \texttt{disabled}, then +%per-user directories will be disabled. Otherwise, the string after +%\texttt{UserDir} gives the name of the subdirectory that Apache will +%look in under your home directory, for example \dirname{public\_html}. + +$B%&%'%V%5!<%P$O%f!<%6Kh$N%G%#%l%/%H%j%5!<%S%9$r6X;_$5$l$F$$$k$+$b$7$l$J$$!%(B +Apache$B$r;H$C$F$$$k>l9g!$@_Dj%U%!%$%k$N(B\texttt{UserDir}$B%G%#%l%/%F%#%V$r(B +$B%A%'%C%/$9$k!%$b$7B8:_$7$J$1$l$P!$%f!<%6Kh$N%G%#%l%/%H%j%5!<%S%9$O6X;_$5(B +$B$l$F$$$k!%B8:_$7$F$b!$CM$,(B\texttt{disabled}$B$K@_Dj$5$l$F$$$l$P!$%f!<%6Kh$N(B +$B%G%#%l%/%H%j%5!<%S%9$O6X;_$G$"$k!%$^$?!$(B\texttt{UserDir}$B%G%#%l%/%F%#%V$O(B +Apache$B$,%5!<%S%9MQ$KC5$9%[!<%`%G%#%l%/%H%jFb$N%5%V%G%#%l%/%H%j$r;XDj$9(B +$B$k!%E57?E*$JNc$O(B\dirname{public\_html}$B$G$"$k!%(B + +%Your file access permissions may be too restrictive. The web server +%must be able to traverse your home directory and directories under +%your \dirname{public\_html} directory, and read files under the latter +%too. Here's a quick recipe to help you to make your permissions more +%appropriate. +$B%U%!%$%k%"%/%;%9%Q!<%_%C%7%g%s$,$-$D$9$.$k!%%&%'%V%5!<%P$O%[!<%`%G%#%l%/(B +$B%H%j$H(B\dirname{public\_html}$BFb$N%G%#%l%/%H%j$rEO$C$F%U%!%$%k$rFI$a$J$1$l(B +$B$P$J$i$J$$!%%Q!<%_%C%7%g%s$rE,@Z$K@_Dj$9$k$K$ONc$($P<!$N$h$&$K$9$l$P$h$$!%(B +\begin{codesample2} + chmod 755 ~ + find ~/public_html -type d -print0 | xargs -0r chmod 755 + find ~/public_html -type f -print0 | xargs -0r chmod 644 +\end{codesample2} + +%The other possibility with permissions is that you might get a +%completely empty window when you try to load the script. In this +%case, it's likely that your access permissions are \emph{too +% permissive}. Apache's \texttt{suexec} subsystem won't execute a +%script that's group-~or world-writable, for example. + +$B%Q!<%_%C%7%g%s$K4X$9$k$=$NB>$N2DG=@-$H$7$F!$%9%/%j%W%H$r%m!<%I$7$h$&$H$9(B +$B$k$H6u$N%&%#%s%I%&$,I=<($5$l$kLdBj$,$"$k!%$3$N>l9g$O!$%Q!<%_%C%7%g%s@_Dj(B +$B$,(B\emph{$B4K$9$.$k(B}$B2DG=@-$,9b$$!%Nc$($P(BApache$B$N(B\texttt{suexec}$B%5%V%7%9%F%`(B +$B$O!$%0%k!<%W$dA4@$3&$+$i=q$-9~$_$N$G$-$k%9%/%j%W%H$r<B9T$7$J$$!%(B + +%Your web server may be configured to disallow execution of CGI +%programs in your per-user web directory. Here's Apache's +%default per-user configuration from my Fedora system. +$B%&%'%V%5!<%P$O(BCGI$B%W%m%0%i%`$N<B9T$r6X;_$9$k$h$&$K@_Dj$5$l$F$$$k$+$b$7$l(B +$B$J$$!%Cx<T$N(BFedora$B%7%9%F%`$+$i!$(BApache$B$N%f!<%6Kh$N%G%U%)%k%H@_Dj$rNc$H$7(B +$B$F<($9!%(B +\begin{codesample2} + <Directory /home/*/public_html> + AllowOverride FileInfo AuthConfig Limit + Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec + <Limit GET POST OPTIONS> + Order allow,deny + Allow from all + </Limit> + <LimitExcept GET POST OPTIONS> + Order deny,allow + Deny from all + </LimitExcept> + </Directory> +\end{codesample2} +%If you find a similar-looking \texttt{Directory} group in your Apache +%configuration, the directive to look at inside it is \texttt{Options}. +%Add \texttt{ExecCGI} to the end of this list if it's missing, and +%restart the web server. + +Apache$B@_Dj$NCf$KF1MM$N(B\texttt{Directory}$B%0%k!<%W$,$"$k>l9g!$$=$NCf$GCmL\(B +$B$9$Y$-%G%#%l%/%F%#%V$O(B\texttt{Options}$B$G$"$k!%(B \texttt{ExecCGI}$B$,%j%9%H$K(B +$BL5$1$l$P:G8e$KDI2C$7!$%&%'%V%5!<%P$r:F5/F0$9$k!%(B + +%If you find that Apache serves you the text of the CGI script instead +%of executing it, you may need to either uncomment (if already present) +%or add a directive like this. +Apache$B$,(BCGI$B%9%/%j%W%H$r<B9T$9$k$N$G$O$J$/!$%9%/%j%W%H<+BN$N%F%-%9%H$rAw$C(B +$B$F$/$k>l9g$O!$0J2<$N%G%#%l%/%F%#%V$rDI2C$9$k$+!$$9$G$KB8:_$7$F%3%a%s%H%"(B +$B%&%H$5$l$F$$$l$P!$%"%s%3%a%s%H$9$k!%(B +\begin{codesample2} + AddHandler cgi-script .cgi +\end{codesample2} + +%The next possibility is that you might be served with a colourful +%Python backtrace claiming that it can't import a +%\texttt{mercurial}-related module. This is actually progress! The +%server is now capable of executing your CGI script. This error is +%only likely to occur if you're running a private installation of +%Mercurial, instead of a system-wide version. Remember that the web +%server runs the CGI program without any of the environment variables +%that you take for granted in an interactive session. If this error +%happens to you, edit your copy of \sfilename{hgweb.cgi} and follow the +%directions inside it to correctly set your \envar{PYTHONPATH} +%environment variable. + +$B<!$N2DG=@-$O(B\texttt{mercurial}$B$K4XO"$7$?(Bmodule$B$,%$%s%]!<%H$G$-$J$$$3$H$r(B +$B7Y9p$9$k%+%i%U%k$J(BPython$B%P%C%/%H%l!<%9$,8+$($k$3$H$@!%$3$l$OA0?J$H8@$((B +$B$k!%%5!<%P$O(BCGI$B%9%/%j%W%H$r<B9T$G$-$k$h$&$K$J$C$?!%$3$N%(%i!<$O(BMercurial +$B$r%7%9%F%`%o%$%I$K%$%s%9%H!<%k$9$k$N$G$O$J$/!$%W%i%$%Y!<%H%$%s%9%H!<%k$7(B +$B$?>l9g$K$N$_5/$-$k!%BPOCE*$J%;%C%7%g%s$H$O0[$J$j!$%&%'%V%5!<%P$O(BCGI$B%W%m%0(B +$B%i%`$r4D6-JQ?t$J$7$G5/F0$9$k!%$3$N%(%i!<$,5/$-$?>l9g$O(B +\sfilename{hgweb.cgi}$B$rJT=8$7!$4D6-JQ?t(B\envar{PYTHONPATH}$B$,%;%C%H$5$l$k$h(B +$B$&$K$9$k!%(B + +%Finally, you are \emph{certain} to by served with another colourful +%Python backtrace: this one will complain that it can't find +%\dirname{/path/to/repository}. Edit your \sfilename{hgweb.cgi} script +%and replace the \dirname{/path/to/repository} string with the complete +%path to the repository you want to serve up. + +$B:#EY$O(B\emph{$B$*$=$i$/(B}$B%+%i%U%k$J(BPython$B$N%P%C%/%H%l!<%9$,8+$($k$O$:$@!%$3$l(B +$B$O(B\dirname{/path/to/repository}$B$,8+$D$+$i$J$$$3$H$r7Y9p$7$F$$$k!%(B +\sfilename{hgweb.cgi}$B%9%/%j%W%H$rJT=8$7!$(B\dirname{/path/to/repository}$B$H(B +$B$$$&J8;zNs$r!$%5!<%S%9$7$?$$%j%]%8%H%j$X$N40A4$J%Q%9$KCV$-49$($k!%(B + +%At this point, when you try to reload the page, you should be +%presented with a nice HTML view of your repository's history. Whew! + +$B$3$3$G%Z!<%8$r%j%m!<%I$9$k$H!$%j%]%8%H%j$NMzNr$rI=$9H~$7$$(BHTML$B$,8+$($k$O(B +$B$:$@!%$d$C$?!*(B + +%\subsubsection{Configuring lighttpd} +\subsubsection{lighttpd$B$N@_Dj(B} + +%To be exhaustive in my experiments, I tried configuring the +%increasingly popular \texttt{lighttpd} web server to serve the same +%repository as I described with Apache above. I had already overcome +%all of the problems I outlined with Apache, many of which are not +%server-specific. As a result, I was fairly sure that my file and +%directory permissions were good, and that my \sfilename{hgweb.cgi} +%script was properly edited. + +$BI.<T$N<B83$NCf$G$O!$(BApache$B$r;H$C$F%5!<%S%9$7$?$N$HF1$8%j%]%8%H%j$r?M5$$r(B +$B3MF@$7$D$D$"$k%&%'%V%5!<%P$G$"$k(B\texttt{lighttpd}$B$rMQ$$$F%5!<%S%9$9$k$3$H(B +$B$b;n$_$?!%(B Apache$B$K4X$9$kA4$F$NLdBjE@$r4{$K2r7h$7$F$$$?$,!$$=$NCf$NB?$/$O(B +$B%5!<%PFCM-$H$$$&$o$1$G$O$J$+$C$?!%7k2L$H$7$F!$%U%!%$%k$H%G%#%l%/%H%j$N%Q!<(B +$B%_%C%7%g%s@_Dj$,@5$7$$$3$H!$(B \sfilename{hgweb.cgi}$B%9%/%j%W%H$,@5$7$/@_Dj(B +$B$5$l$F$$$k$3$H$r3N?.$7$?!%(B + +%Once I had Apache running, getting \texttt{lighttpd} to serve the +%repository was a snap (in other words, even if you're trying to use +%\texttt{lighttpd}, you should read the Apache section). I first had +%to edit the \texttt{mod\_access} section of its config file to enable +%\texttt{mod\_cgi} and \texttt{mod\_userdir}, both of which were +%disabled by default on my system. I then added a few lines to the end +%of the config file, to configure these modules. +$B$9$G$K(BApache$B$r;H$C$F$$$?$N$G!$(B\texttt{lighttpd}$B$G%j%]%8%H%j$N%5!<%S%9$r9T(B +$B$&$3$H$O$?$d$9$+$C$?!%!J$3$l$O(B\texttt{lighttpd}$B$r;H$C$F%5!<%S%9$r;n$_$k>l(B +$B9g$b(BApache$B$N%;%/%7%g%s$rFI$`I,MW$,$"$k$H$$$&$3$H$G$b$"$k!%!KI.<T$N%7%9%F(B +$B%`$G$O(B\texttt{mod\_cgi}$B$H(B\texttt{mod\_userdir}$B$,6&$KL58z$K@_Dj$5$l$F$$$?(B +$B$N$G!$$3$l$i$rM-8z$K$9$k$?$a$K!$$^$:@_Dj%U%!%$%k$N(B\texttt{mod\_access}$B%;(B +$B%/%7%g%s$rJT=8$9$kI,MW$,$"$C$?!%$=$N8e$G!$2<5-$N%b%8%e!<%k$rM-8z$K$9$k$?(B +$B$a$K!$@_Dj%U%!%$%k$NKvHx$K?t9T$rDI2C$7$?!%(B +\begin{codesample2} + userdir.path = "public_html" + cgi.assign = ( ".cgi" => "" ) +\end{codesample2} +%With this done, \texttt{lighttpd} ran immediately for me. If I had +%configured \texttt{lighttpd} before Apache, I'd almost certainly have +%run into many of the same system-level configuration problems as I did +%with Apache. However, I found \texttt{lighttpd} to be noticeably +%easier to configure than Apache, even though I've used Apache for over +%a decade, and this was my first exposure to \texttt{lighttpd}. +$B$3$l$i$N@_Dj$r$9$k$@$1$G(B\texttt{lighttpd}$B$O$9$0$KF0:n$7$?!%(B Apache$B$h$jA0(B +$B$K(B\texttt{lighttpd}$B$r;n$7$F$$$?$i!$(BApache$B$GD>LL$7$?$h$&$JMM!9$J%7%9%F%`%l(B +$B%Y%k$N@_DjLdBj$KAx6x$7$F$$$?$K0c$$$J$$$,!$=i$a$F;H$&(B\texttt{lighttpd}$B$N@_(B +$BDj$NJ}$,!$$3$l$^$G(B10$BG/0J>e$K$o$?$C$F;H$C$F$-$?(BApache$B$N$=$l$h$j$bL@$i$+$K(B +$B4JC1$G$"$k$3$H$,J,$+$C$?!%(B + +%\subsection{Sharing multiple repositories with one CGI script} +\subsection{1$B$D$N(BCGI$B%9%/%j%W%H$GJ#?t$N%j%]%8%H%j$r6&M-$9$k(B} + +%The \sfilename{hgweb.cgi} script only lets you publish a single +%repository, which is an annoying restriction. If you want to publish +%more than one without wracking yourself with multiple copies of the +%same script, each with different names, a better choice is to use the +%\sfilename{hgwebdir.cgi} script. +\sfilename{hgweb.cgi}$B%9%/%j%W%H$K$O!$(B1$B$D$N%j%]%8%H%j$7$+8x3+$G$-$J$$$H$$(B +$B$&Lq2p$J@)8B$,$"$k!%(B 2$B$D0J>e$N%j%]%8%H%j$r8x3+$7$?$$>l9g$O!$F1$8%9%/%j%W(B +$B%H$rJL$NL>A0$G$$$/$D$bF0$+$9$N$G$O$J$/!$(B \sfilename{hgwebdir.cgi}$B%9%/%j%W(B +$B%H$r;H$&$N$,NI$$$@$m$&!%(B + +%The procedure to configure \sfilename{hgwebdir.cgi} is only a little +%more involved than for \sfilename{hgweb.cgi}. First, you must obtain +%a copy of the script. If you don't have one handy, you can download a +%copy from the master Mercurial repository at +%\url{http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi}. +\sfilename{hgwebdir.cgi}$B$N@_Dj$N<j=g$O(B\sfilename{hgweb.cgi}$B$h$j$b$o$:$+$K(B +$B9~$_F~$C$F$$$k$@$1$@!%<j6a$J$H$3$m$K%9%/%j%W%H$,$J$1$l$P!$(BMercurial$B$N%^%9(B +$B%?!<%j%]%8%H%j(B +\url{http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi}$B$+$i%9%/%j(B +$B%W%H$rF~<j$G$-$k!%(B + +%You'll need to copy this script into your \dirname{public\_html} +%directory, and ensure that it's executable. +$B$3$N%9%/%j%W%H$r(B\dirname{public\_html}$B%G%#%l%/%H%j$K%3%T!<$7!$<B9T%Q!<%_%C(B +$B%7%g%s$rM?$($k!%(B +\begin{codesample2} + cp .../hgwebdir.cgi ~/public_html + chmod 755 ~/public_html ~/public_html/hgwebdir.cgi +\end{codesample2} +%With basic configuration out of the way, try to visit +%\url{http://myhostname/~myuser/hgwebdir.cgi} in your browser. It +%should display an empty list of repositories. If you get a blank +%window or error message, try walking through the list of potential +%problems in section~\ref{sec:collab:wtf}. +$BDL>o$N@_Dj$N>l9g!$%V%i%&%6$G(B\url{http://myhostname/~myuser/hgwebdir.cgi} +$B$r3+$/$H!$Cf?H$,6u$N%j%]%8%H%j$rI=<($9$k$O$:$@!%%&%#%s%I%&<+BN$,6u$@$C$?(B +$B$j!$%(%i!<%a%C%;!<%8$,I=<($5$l$k>l9g$O!$%;%/%7%g%s(B~\ref{sec:collab:wtf} +$B$NLdBj%j%9%H$r;2>H$7$F$[$7$$!%(B + +%The \sfilename{hgwebdir.cgi} script relies on an external +%configuration file. By default, it searches for a file named +%\sfilename{hgweb.config} in the same directory as itself. You'll need +%to create this file, and make it world-readable. The format of the +%file is similar to a Windows ``ini'' file, as understood by Python's +%\texttt{ConfigParser}~\cite{web:configparser} module. +\sfilename{hgwebdir.cgi}$B$O30It$N@_Dj%U%!%$%k$r;HMQ$7$F$$$k!%%G%U%)%k%H$G(B +$B$OF1$8%G%#%l%/%H%jFb$N(B\sfilename{hgweb.config}$B$H$$$&%U%!%$%k$r;2>H$9$k!%(B +$B$3$N%U%!%$%k$r:n@.$7!$A4$F$N%f!<%6$+$iFI$a$k$h$&$K@_Dj$9$k!%(B +$B$3$N%U%!%$%k$O(BPython$B$N(B\texttt{ConfigParser}~\cite{web:configparser}$B$G=h(B +$BM}$G$-$k$h$&(BWindows$B$N(B``ini''$B%U%!%$%k$H;w$?7A<0$K$J$C$F$$$k!%(B + +%The easiest way to configure \sfilename{hgwebdir.cgi} is with a +%section named \texttt{collections}. This will automatically publish +%\emph{every} repository under the directories you name. The section +%should look like this: +\sfilename{hgwebdir.cgi}$B$N:G$b4JC1$J@_DjJ}K!$O!$(B\texttt{collections}$B%;%/(B +$B%7%g%s$rJT=8$9$k$3$H$G$"$k!%$3$l$O<+F0E*$K;XDj$7$?%G%#%l%/%H%j0J2<$N(B +\emph{$BA4$F$N(B}$B%j%]%8%H%j$r8x3+$9$k!%$3$N%;%/%7%g%s$O<!$N$h$&$K$J$C$F$$$k!'(B +\begin{codesample2} + [collections] + /my/root = /my/root +\end{codesample2} +%Mercurial interprets this by looking at the directory name on the +%\emph{right} hand side of the ``\texttt{=}'' sign; finding +%repositories in that directory hierarchy; and using the text on the +%\emph{left} to strip off matching text from the names it will actually +%list in the web interface. The remaining component of a path after +%this stripping has occurred is called a ``virtual path''. +Mercurial$B$O(B``\texttt{=}''$B5-9f$N(B\emph{$B1&B&(B}$B$N%G%#%l%/%H%jL>$r;2>H$7$F!$%G%#(B +$B%l%/%H%j3,AXFb$N%j%]%8%H%j$rC5$9!%8+$D$+$C$?;~$O!$%j%]%8%H%j$N%Q%9$+$i(B +\emph{$B:8B&(B}$B$NJ8;zNs$H%^%C%A$9$kItJ,$r:o$j!$<B:]$K%&%'%V%$%s%?%U%'!<%9$KI=(B +$B<($5$l$k%Q%9J8;zNs$r:n$k!%:o=|8e$N%Q%9$r(B``$B2>A[%Q%9(B''$B$H8F$V!%(B + +%Given the example above, if we have a repository whose local path is +%\dirname{/my/root/this/repo}, the CGI script will strip the leading +%\dirname{/my/root} from the name, and publish the repository with a +%virtual path of \dirname{this/repo}. If the base URL for our CGI +%script is \url{http://myhostname/~myuser/hgwebdir.cgi}, the complete +%URL for that repository will be +%\url{http://myhostname/~myuser/hgwebdir.cgi/this/repo}. +$B>e$NNc$G!$(BCGI$B%9%/%j%W%H$O!$%m!<%+%k%Q%9$,(B\dirname{/my/root/this/repo}$B$G$"(B +$B$k%j%]%8%H%j$KBP$7$F(B\dirname{/my/root}$B$r<h$j=|$-!$(B\dirname{this/repo}$B$H$$(B +$B$&2>A[%Q%9$r:n@.$7!$8x3+$9$k!%$b$7(BCGI$B%9%/%j%W%H$N%Y!<%9(BURL$B$,(B +\url{http://myhostname/~myuser/hgwebdir.cgi}$B$@$H$9$k$H!$%j%]%8%H%j$N40A4(B +$B$J(BURL$B$O(B\url{http://myhostname/~myuser/hgwebdir.cgi/this/repo}$B$H$J$k!%(B + +%If we replace \dirname{/my/root} on the left hand side of this example +%with \dirname{/my}, then \sfilename{hgwebdir.cgi} will only strip off +%\dirname{/my} from the repository name, and will give us a virtual +%path of \dirname{root/this/repo} instead of \dirname{this/repo}. +$B$3$NNc$N:8JU$N(B\dirname{/my/root}$B$r(B\dirname{/my}$B$GCV$-49$($k$H(B +\sfilename{hgwebdir.cgi}$B$O(B\dirname{/my}$B$@$1$r%j%]%8%H%jL>$+$i<h$j=|$-!$2>(B +$BA[%Q%9$H$7$F(B\dirname{this/repo}$B$G$O$J$/(B\dirname{root/this/repo}$B$r:n$k!%(B + +%The \sfilename{hgwebdir.cgi} script will recursively search each +%directory listed in the \texttt{collections} section of its +%configuration file, but it will \texttt{not} recurse into the +%repositories it finds. +\sfilename{hgwebdir.cgi}$B%9%/%j%W%H$O!$@_Dj%U%!%$%k$N(B\texttt{collections} +$B%;%/%7%g%s$K=q$+$l$?%G%#%l%/%H%j$r:F5"E*$K%5!<%A$9$k!%$3$N%9%/%j%W%H$O8+(B +$B$D$1$?%j%]%8%H%j$NCf$O%5!<%A(B\texttt{$B$7$J$$(B}$B!%(B + +%The \texttt{collections} mechanism makes it easy to publish many +%repositories in a ``fire and forget'' manner. You only need to set up +%the CGI script and configuration file one time. Afterwards, you can +%publish or unpublish a repository at any time by simply moving it +%into, or out of, the directory hierarchy in which you've configured +%\sfilename{hgwebdir.cgi} to look. +\texttt{collections}$B%a%+%K%:%`$K$h$C$FJ#?t$N%j%]%8%H%j$r4JC1$K8x3+$9$k$3(B +$B$H$,$G$-$k!%(BCGI$B%9%/%j%W%H$H@_Dj%U%!%$%k$rJT=8$9$k$N$O:G=i$N0l2s$@$1$G$h(B +$B$/!$%j%]%8%H%j$r(B\sfilename{hgwebdir.cgi}$B$NC5:w$9$k%G%#%l%/%H%j3,AXFb$K0\(B +$BF0$9$l$P8x3+$K!$3,AXFb$+$i30$;$PHs8x3+$K@_Dj$G$-$k!%(B + + +%\subsubsection{Explicitly specifying which repositories to publish} +\subsubsection{$B$I$N%j%]%8%H%j$rI=<($9$k$+L@<(E*$K;XDj$9$k(B} + +%In addition to the \texttt{collections} mechanism, the +%\sfilename{hgwebdir.cgi} script allows you to publish a specific list +%of repositories. To do so, create a \texttt{paths} section, with +%contents of the following form. +\sfilename{hgwebdir.cgi}$B%9%/%j%W%H$O(B\texttt{collections}$B$N%a%+%K%:%`$NB>(B +$B$K$b%j%]%8%H%j$NFCDj$N%j%9%H$r8x3+$9$kJ}K!$rMQ0U$7$F$$$k!%2<5-$N$h$&$J(B +$BFbMF$N(B\texttt{paths}$B%;%/%7%g%s$r:n$k!%(B +\begin{codesample2} + [paths] + repo1 = /my/path/to/some/repo + repo2 = /some/path/to/another +\end{codesample2} +%In this case, the virtual path (the component that will appear in a +%URL) is on the left hand side of each definition, while the path to +%the repository is on the right. Notice that there does not need to be +%any relationship between the virtual path you choose and the location +%of a repository in your filesystem. +$B$3$N>l9g!$3F!9$NDj5A$N:8JU$K2>A[%Q%9!J(BURL$B$K8=$l$kMWAG!K$,!$%j%]%8%H%j$X$N(B +$B%Q%9$,1&JU$K8=$l$k!%A*$s$@2>A[%Q%9$H%U%!%$%k%7%9%F%`Cf$G$N0LCV$N4V$K$O$$(B +$B$+$J$k4XO"@-$bI,MW$J$$!%(B + +%If you wish, you can use both the \texttt{collections} and +%\texttt{paths} mechanisms simultaneously in a single configuration +%file. +\texttt{collections}$B$H(B\texttt{paths}$B$NN>J}$N5!9=$rF10l$N@_Dj%U%!%$%kFb$G(B +$BF1;~$KMQ$$$k$3$H$b$G$-$k!%(B + +%\begin{note} +% If multiple repositories have the same virtual path, +% \sfilename{hgwebdir.cgi} will not report an error. Instead, it will +% behave unpredictably. +%\end{note} +\begin{note} +$BJ#?t$N%j%]%8%H%j$,F1$82>A[%Q%9$r;}$D>l9g!$(B\sfilename{hgwebdir.cgi}$B$O%(%i!<(B + $B$r@8$8$J$$$,!$5sF0$OM=B,$N$D$+$J$$$b$N$H$J$k!%(B +\end{note} + +%\subsection{Downloading source archives} +\subsection{$B%=!<%9%"!<%+%$%V$N%@%&%s%m!<%I(B} + +%Mercurial's web interface lets users download an archive of any +%revision. This archive will contain a snapshot of the working +%directory as of that revision, but it will not contain a copy of the +%repository data. +$B%f!<%6$O(BMercurial$B$N%&%'%V%$%s%?%U%'!<%9$+$i$I$N%j%S%8%g%s$N%"!<%+%$%V$b(B +$B%@%&%s%m!<%I$9$k$3$H$,$G$-$k!%%"!<%+%$%V$OEv3:%j%S%8%g%s$N%o!<%-%s%0%G%#(B +$B%l%/%H%j$N%9%J%C%W%7%g%C%H$r4^$`$,!$%j%]%8%H%j<+BN$N%G!<%?$O4^$^$J$$!%(B + +%By default, this feature is not enabled. To enable it, you'll need to +%add an \rcitem{web}{allow\_archive} item to the \rcsection{web} +%section of your \hgrc. +$B%G%U%)%k%H$G$O$3$N5!G=$OL58z$K$5$l$F$$$k!%M-8z$K$9$k$K$O(B +\rcitem{web}{allow\_archive}$B9`L\$r(B\hgrc $B$N(B\rcsection{web}$B%;%/%7%g%s$KDI(B +$B2C$9$kI,MW$,$"$k!%(B + +%\subsection{Web configuration options} +\subsection{Web$B@_Dj%*%W%7%g%s(B} + +%Mercurial's web interfaces (the \hgcmd{serve} command, and the +%\sfilename{hgweb.cgi} and \sfilename{hgwebdir.cgi} scripts) have a +%number of configuration options that you can set. These belong in a +%section named \rcsection{web}. +Mercurial$B%&%'%V%$%s%?%U%'!<%9(B(the \hgcmd{serve}$B%3%^%s(B +$B%I!$(B\sfilename{hgweb.cgi}$B$*$h$S(B\sfilename{hgwebdir.cgi}$B%9%/%j%W%H(B)$B$K$OB?(B +$B$/$N@_Dj%*%W%7%g%s$,$"$k!%$3$l$i$O(B\rcsection{web}$B%;%/%7%g%s$K4^$^$l$k!%(B + +\begin{itemize} +%\item[\rcitem{web}{allow\_archive}] Determines which (if any) archive +% download mechanisms Mercurial supports. If you enable this +% feature, users of the web interface will be able to download an +% archive of whatever revision of a repository they are viewing. +% To enable the archive feature, this item must take the form of a +% sequence of words drawn from the list below. +\item[\rcitem{web}{allow\_archive}] $B$I$N%"!<%+%$%V%@%&%s%m!<%I%a%+%K%:%`(B + $B$r(BMercurial$B$,%5%]!<%H$9$k$N$+$r7hDj$9$k!%$3$N5!G=$rM-8z$K$9(B + $B$k$H!$%&%'%V%$%s%?%U%'!<%9$N%f!<%6$O%j%]%8%H%j$NG$0U$N%j%S%8%g(B + $B%s$N%"!<%+%$%V$r%@%&%s%m!<%I$G$-$k$h$&$K$J$k!%%"!<%+%$%V:r(B + $BF|$rM-8z$K$9$k$K$O$3$N9`L\$O!$2<$N%j%9%H$K<($98l$+$i9=@.$5(B + $B$l$J$1$l$P$J$i$J$$!%(B + + \begin{itemize} +% \item[\texttt{bz2}] A \command{tar} archive, compressed using +% \texttt{bzip2} compression. This has the best compression ratio, +% but uses the most CPU time on the server. +\item[\texttt{bz2}] \texttt{bzip2}$B05=L$5$l$?(B\command{tar}$B%"!<%+%$%V!%05=LN($,:G(B + $B$b9b$$$,!$%5!<%P$N(BCPU$B;~4V$b0lHV;HMQ$9$k!%(B + +% \item[\texttt{gz}] A \command{tar} archive, compressed using +% \texttt{gzip} compression. +\item[\texttt{gz}] \texttt{gzip}$B05=L$5$l$?(B\command{tar}$B%"!<%+%$%V!%(B + +% \item[\texttt{zip}] A \command{zip} archive, compressed using LZW +% compression. This format has the worst compression ratio, but is +% widely used in the Windows world. +\item[\texttt{zip}] LZW$B05=L$5$l$?(B\command{zip}$B%"!<%+%$%V!%$3$NCf$G05=LN((B + $B$O:GDc$@$,!$(BWindows$B$N4D6-$G$O9-$/MQ$$$i$l$F$$$k!%(B + \end{itemize} + +% If you provide an empty list, or don't have an +% \rcitem{web}{allow\_archive} entry at all, this feature will be +% disabled. Here is an example of how to enable all three supported +% formats. +$B6u$N%j%9%H$rM?$($k$+!$(B\rcitem{web}{allow\_archive}$B$r5-=R$7$J$1$l$P!$$3$N(B + $B:rF|$OL58z2=$5$l$k!%%5%]!<%H$5$l$F$$$k(B3$B$D$N%U%)!<%^%C%HA4$F(B + $B$rM-8z$K$9$kNc$r<($9!%(B + \begin{codesample4} + [web] + allow_archive = bz2 gz zip + \end{codesample4} + +%\item[\rcitem{web}{allowpull}] Boolean. Determines whether the web +% interface allows remote users to \hgcmd{pull} and \hgcmd{clone} this +% repository over~HTTP. If set to \texttt{no} or \texttt{false}, only +% the ``human-oriented'' portion of the web interface is available. +\item[\rcitem{web}{allowpull}] $B%V!<%kCM!%%j%b!<%H%f!<%6$K%&%'%V%$%s%?%U%'!<(B + $B%9$rMQ$$$?(B~HTTP$B$K$h$k(B\hgcmd{pull}$B5Z$S(B\hgcmd{clone}$B$r5v2D$9(B + $B$k$+$I$&$+$r7h$a$k!%(B\texttt{no}$B$^$?$O(B\texttt{false}$B$N>l9g!$(B + $B%&%'%V%$%s%?%U%'!<%9$O?M4V$N1\Mw$N$_$,2DG=$K$J$k!%(B + +%\item[\rcitem{web}{contact}] String. A free-form (but preferably +% brief) string identifying the person or group in charge of the +% repository. This often contains the name and email address of a +% person or mailing list. It often makes sense to place this entry in +% a repository's own \sfilename{.hg/hgrc} file, but it can make sense +% to use in a global \hgrc\ if every repository has a single +% maintainer. +\item[\rcitem{web}{contact}] $BJ8;zNs!%<+M37A<0!J4J7i$JI=5-$,9%$^$7$$!K$G%j(B + $B%]%8%H%j$rC4Ev$9$k?MJ*$d%0%k!<%W$r5-=R$9$k!%DL>o$O?ML>$H!$8D(B + $B?M$^$?$O%a!<%j%s%0%j%9%H$N%"%I%l%9$r4^$`!%B?$/$N>l(B + $B9g!$(B\sfilename{.hg/hgrc}$B$K$3$N5-=R$rCV$/$N$,NI$$!%$b$7A4$F$N(B + $B%j%]%8%H%j$rF10l?MJ*$,4IM}$9$k$N$G$"$l$P!$%0%m!<%P%k$J(B + \hgrc\ $B$KCV$/$N$b$h$$!%(B + +%\item[\rcitem{web}{maxchanges}] Integer. The default maximum number +% of changesets to display in a single page of output. +\item[\rcitem{web}{maxchanges}] $B@0?t!%(B1$B%Z!<%8$KI=<($9$k%A%'%s%8%;%C%H$N(B + $B%G%U%)%k%H$N:GBg?t!%(B + +%\item[\rcitem{web}{maxfiles}] Integer. The default maximum number +% of modified files to display in a single page of output. +\item[\rcitem{web}{maxfiles}] $B@0?t!%(B1$B%Z!<%8$KI=<($9$k99?7$5$l$?%U%!%$%k(B + $B$N%G%U%)%k%H$N:GBg?t!%(B + +%\item[\rcitem{web}{stripes}] Integer. If the web interface displays +% alternating ``stripes'' to make it easier to visually align rows +% when you are looking at a table, this number controls the number of +% rows in each stripe. +\item[\rcitem{web}{stripes}] $B@0?t!%I=$NI=<($r9T$&:]$K!$9T$r8+0W$/$9$k$?$a(B + $B%&%'%V%$%s%?%U%'!<%9$,8r8_$K(B``$B%9%H%i%$%W(B''$BI=<($9$k>l9g!$$3$N(B + $BCM$G$=$l$>$l$N%9%H%i%$%W$N9T?t$r@_Dj$9$k!%(B + +%\item[\rcitem{web}{style}] Controls the template Mercurial uses to +% display the web interface. Mercurial ships with two web templates, +% named \texttt{default} and \texttt{gitweb} (the latter is much more +% visually attractive). You can also specify a custom template of +% your own; see chapter~\ref{chap:template} for details. Here, you +% can see how to enable the \texttt{gitweb} style. +\item[\rcitem{web}{style}] Mercurial$B$,%&%'%V%$%s%?!<%U%'!<%9$rI=<($9$k$?(B + $B$a$K;HMQ$9$k%F%s%W%l!<%H$r@)8f$9$k!%(BMercurial$B$K$O(B + \texttt{default}$B$H(B\texttt{gitweb}$B$H$$$&(B2$B$D$N%&%'%V%F%s%W%l!<(B + $B%H$,F1:-$5$l$F$$$k!%!J8e<T$NJ}$,8+1I$($,$9$k!%!KFH<+$N%F%s%W(B + $B%l!<%H$r;XDj$9$k$3$H$b2DG=$G$"$k!%>\:Y$O(B~\ref{chap:template}$B$r(B + $B;2>H$N$3$H!%$3$3$G$O(B\texttt{gitweb}$B%9%?%$%k$rM-8z$K$9$kJ}K!(B + $B$r<($9!%(B + \begin{codesample4} + [web] + style = gitweb + \end{codesample4} +%\item[\rcitem{web}{templates}] Path. The directory in which to search +% for template files. By default, Mercurial searches in the directory +% in which it was installed. +\item[\rcitem{web}{templates}] $B%Q%9!%%F%s%W%l!<%H%U%!%$%k$r8!:w$9$k%G%#%l(B + $B%/%H%j!%%G%U%)%k%H$G$O(BMercurial$B$O%$%s%9%H!<%k$5$l$?%G%#%l%/(B + $B%H%j$+$i%F%s%W%l!<%H$rC5$9!%(B +\end{itemize} +%If you are using \sfilename{hgwebdir.cgi}, you can place a few +%configuration items in a \rcsection{web} section of the +%\sfilename{hgweb.config} file instead of a \hgrc\ file, for +%convenience. These items are \rcitem{web}{motd} and +%\rcitem{web}{style}. +\sfilename{hgwebdir.cgi}$B$rMxMQ$9$k>l9g!$JXMx$N$?$a!$(B\hgrc\ $B%U%!%$%k$G$O$J$/(B +\sfilename{hgweb.config}$B%U%!%$%k$N(B\rcsection{web}$B%;%/%7%g%s$K(B\rcitem{web}{motd}$B$*$h$S(B\rcitem{web}{style}$B9`L\$rCV$/$3$H$,$G$-$k!%(B + +%\subsubsection{Options specific to an individual repository} +\subsubsection{$B8D!9$N%j%]%8%H%j$KFCM-$N%*%W%7%g%s(B} + +%A few \rcsection{web} configuration items ought to be placed in a +%repository's local \sfilename{.hg/hgrc}, rather than a user's or +%global \hgrc. +$B$$$/$D$+$N(B\rcsection{web} $B@_Dj9`L\$O%f!<%6$d%0%m!<%P%k$N(B \hgrc $B$G$O$J$/!$(B +$B%j%]%8%H%j%m!<%+%k$N(B\sfilename{.hg/hgrc}$B%U%!%$%k$K=q$+$l$k$N$,<+A3$G$"$k!%(B +\begin{itemize} +%\item[\rcitem{web}{description}] String. A free-form (but preferably +% brief) string that describes the contents or purpose of the +% repository. +\item[\rcitem{web}{description}] $BJ8;zNs!%%j%]%8%H%j$NFbMF$dL\E*$K$D$$$F(B + $B$N@bL@!%7A<0$O<+M3$@$,!$4J7i$J$b$N$,9%$^$l$k!%(B +%\item[\rcitem{web}{name}] String. The name to use for the repository +% in the web interface. This overrides the default name, which is the +% last component of the repository's path. +\item[\rcitem{web}{name}] $BJ8;zNs!%%&%'%V%$%s%?%U%'!<%9$G$N%j%]%8%H%jL>!%(B + $B$3$NL>A0$O%j%]%8%H%j%Q%9Cf$N:G8e$NMWAG$+$i:n$i$l$k%G%U%)%k%H(B + $BL>$r%*!<%P%i%$%I$9$k!%(B +\end{itemize} + +%\subsubsection{Options specific to the \hgcmd{serve} command} +\subsubsection{\hgcmd{serve}$B%3%^%s%IFCM-$N%*%W%7%g%s(B} + +%Some of the items in the \rcsection{web} section of a \hgrc\ file are +%only for use with the \hgcmd{serve} command. +\hgrc\ $B%U%!%$%k$N(B\rcsection{web}$B%;%/%7%g%s$N9`L\$O(B\hgcmd{serve}$B%3%^%s%I(B +$B$G$N$_MQ$$$i$l$k!%(B + +\begin{itemize} +%\item[\rcitem{web}{accesslog}] Path. The name of a file into which to +% write an access log. By default, the \hgcmd{serve} command writes +% this information to standard output, not to a file. Log entries are +% written in the standard ``combined'' file format used by almost all +% web servers. +\item[\rcitem{web}{accesslog}] $B%Q%9!%%"%/%;%9%m%0$r=PNO$9$k%U%!%$%k$NL>(B + $BA0!%%G%U%)%k%H$G$O(B\hgcmd{serve}$B%3%^%s%I$O%U%!%$%k$G$O$J$/I8(B + $B=`=PNO$X=PNO$r9T$&!%%m%0%(%s%H%j$O$[$H$s$I$N%&%'%V%5!<%P$G(B + $BI8=`$N%3%s%P%$%s%I%U%!%$%k7A<0$G9T$o$l$k!%(B + +%\item[\rcitem{web}{address}] String. The local address on which the +% server should listen for incoming connections. By default, the +% server listens on all addresses. +\item[\rcitem{web}{address}] $BJ8;zNs!%@\B3$KBP$7$F%5!<%P$,BT5!$9$k%m!<%+(B + $B%k%"%I%l%9!%%G%U%)%k%H$G$OA4$F$N%"%I%l%9$KBP$7$FBT5!$9$k!%(B + +%\item[\rcitem{web}{errorlog}] Path. The name of a file into which to +% write an error log. By default, the \hgcmd{serve} command writes this +% information to standard error, not to a file. +\item[\rcitem{web}{errorlog}] $B%Q%9!%%(%i!<$r5-O?$9$k%U%!%$%k$NL>A0!%%G%U%)(B + $B%k%H$G$O(B \hgcmd{serve}$B%3%^%s%I$O%U%!%$%k$G$O$J$/I8=`%(%i!<(B + $B=PNO$X=PNO$r9T$&!%(B + +%\item[\rcitem{web}{ipv6}] Boolean. Whether to use the IPv6 protocol. +% By default, IPv6 is not used. +\item[\rcitem{web}{ipv6}] $B%V!<%kCM!%(BIPv6$B%W%m%H%3%kMxMQ$NM-L5!%%G%U%)%k%H(B + $B$O(BIPv6$BIT;HMQ!%(B + +%\item[\rcitem{web}{port}] Integer. The TCP~port number on which the +% server should listen. The default port number used is~8000. +\item[\rcitem{web}{port}] $B@0?t!%%5!<%P$,BT5!$9$k(BTCP$B%]!<%HHV9f!%%G%U%)%k(B + $B%H$O(B8000$BHV(B. + +\end{itemize} + +%\subsubsection{Choosing the right \hgrc\ file to add \rcsection{web} + %items to} +\subsubsection{\rcsection{web}$B%"%$%F%`$rDI2C$9$k@5$7$$(B\hgrc $B%U%!%$%k$rA*$V(B} + +%It is important to remember that a web server like Apache or +%\texttt{lighttpd} will run under a user~ID that is different to yours. +%CGI scripts run by your server, such as \sfilename{hgweb.cgi}, will +%usually also run under that user~ID. + +Apache$B$d(B\texttt{lighttpd}$B$N$h$&$J%&%'%V%5!<%P$OFH<+$N%f!<%6(B~ID$B$GF0:n$9$k(B +$B$3$H$KN10U$9$kI,MW$,$"$k!%(B\sfilename{hgweb.cgi}$B$N$h$&$J(BCGI$B%9%/%j%W%H$ODL(B +$B>o%5!<%P$,%5!<%P$N%f!<%6(B~ID$B$GF0:n$5$;$k!%(B + +%If you add \rcsection{web} items to your own personal \hgrc\ file, CGI +%scripts won't read that \hgrc\ file. Those settings will thus only +%affect the behaviour of the \hgcmd{serve} command when you run it. To +%cause CGI scripts to see your settings, either create a \hgrc\ file in +%the home directory of the user ID that runs your web server, or add +%those settings to a system-wide \hgrc\ file. + +\rcsection{web}$B%"%$%F%`$r%f!<%68D?M$N(B\hgrc\ $B%U%!%$%k$KDI2C$7$F$b(BCGI$B%9%/%j(B +$B%W%H$O$=$N(B\hgrc\ $B$r;2>H$7$J$$!%$3$l$i$N@_Dj$O!$%f!<%6$,5/F0$9$k(B +\hgcmd{serve}$B%3%^%s%I$K$N$_1F6A$rM?$($k!%$"$J$?$,9T$C$?@_Dj$r(BCGI$B%9%/%j%W(B +$B%H$+$i;2>H$5$;$k$?$a$K$O!$%&%'%V%5!<%P$r5/F0$9$k%f!<%6(BID$B$N%[!<%`%G%#%l%/(B +$B%H%j$K(B\hgrc\ $B%U%!%$%k$r:n$j!$@_Dj$r%7%9%F%`$N(B\hgrc\ $B%U%!%$%k$K$bDI2C$9$k(B +$BI,MW$,$"$k!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/concepts.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,578 @@ +\chapter{Behind the scenes} +\label{chap:concepts} + +Unlike many revision control systems, the concepts upon which +Mercurial is built are simple enough that it's easy to understand how +the software really works. Knowing this certainly isn't necessary, +but I find it useful to have a ``mental model'' of what's going on. + +This understanding gives me confidence that Mercurial has been +carefully designed to be both \emph{safe} and \emph{efficient}. And +just as importantly, if it's easy for me to retain a good idea of what +the software is doing when I perform a revision control task, I'm less +likely to be surprised by its behaviour. + +In this chapter, we'll initially cover the core concepts behind +Mercurial's design, then continue to discuss some of the interesting +details of its implementation. + +\section{Mercurial's historical record} + +\subsection{Tracking the history of a single file} + +When Mercurial tracks modifications to a file, it stores the history +of that file in a metadata object called a \emph{filelog}. Each entry +in the filelog contains enough information to reconstruct one revision +of the file that is being tracked. Filelogs are stored as files in +the \sdirname{.hg/store/data} directory. A filelog contains two kinds +of information: revision data, and an index to help Mercurial to find +a revision efficiently. + +A file that is large, or has a lot of history, has its filelog stored +in separate data (``\texttt{.d}'' suffix) and index (``\texttt{.i}'' +suffix) files. For small files without much history, the revision +data and index are combined in a single ``\texttt{.i}'' file. The +correspondence between a file in the working directory and the filelog +that tracks its history in the repository is illustrated in +figure~\ref{fig:concepts:filelog}. + +\begin{figure}[ht] + \centering +% \grafix{filelog} + \includegraphics{filelog} + \caption{Relationships between files in working directory and + filelogs in repository} + \label{fig:concepts:filelog} +\end{figure} + +\subsection{Managing tracked files} + +Mercurial uses a structure called a \emph{manifest} to collect +together information about the files that it tracks. Each entry in +the manifest contains information about the files present in a single +changeset. An entry records which files are present in the changeset, +the revision of each file, and a few other pieces of file metadata. + +\subsection{Recording changeset information} + +The \emph{changelog} contains information about each changeset. Each +revision records who committed a change, the changeset comment, other +pieces of changeset-related information, and the revision of the +manifest to use. + +\subsection{Relationships between revisions} + +Within a changelog, a manifest, or a filelog, each revision stores a +pointer to its immediate parent (or to its two parents, if it's a +merge revision). As I mentioned above, there are also relationships +between revisions \emph{across} these structures, and they are +hierarchical in nature. + +For every changeset in a repository, there is exactly one revision +stored in the changelog. Each revision of the changelog contains a +pointer to a single revision of the manifest. A revision of the +manifest stores a pointer to a single revision of each filelog tracked +when that changeset was created. These relationships are illustrated +in figure~\ref{fig:concepts:metadata}. + +\begin{figure}[ht] + \centering + \includegraphics{metadata} + \caption{Metadata relationships} + \label{fig:concepts:metadata} +\end{figure} + +As the illustration shows, there is \emph{not} a ``one to one'' +relationship between revisions in the changelog, manifest, or filelog. +If the manifest hasn't changed between two changesets, the changelog +entries for those changesets will point to the same revision of the +manifest. If a file that Mercurial tracks hasn't changed between two +changesets, the entry for that file in the two revisions of the +manifest will point to the same revision of its filelog. + +\section{Safe, efficient storage} + +The underpinnings of changelogs, manifests, and filelogs are provided +by a single structure called the \emph{revlog}. + +\subsection{Efficient storage} + +The revlog provides efficient storage of revisions using a +\emph{delta} mechanism. Instead of storing a complete copy of a file +for each revision, it stores the changes needed to transform an older +revision into the new revision. For many kinds of file data, these +deltas are typically a fraction of a percent of the size of a full +copy of a file. + +Some obsolete revision control systems can only work with deltas of +text files. They must either store binary files as complete snapshots +or encoded into a text representation, both of which are wasteful +approaches. Mercurial can efficiently handle deltas of files with +arbitrary binary contents; it doesn't need to treat text as special. + +\subsection{Safe operation} +\label{sec:concepts:txn} + +Mercurial only ever \emph{appends} data to the end of a revlog file. +It never modifies a section of a file after it has written it. This +is both more robust and efficient than schemes that need to modify or +rewrite data. + +In addition, Mercurial treats every write as part of a +\emph{transaction} that can span a number of files. A transaction is +\emph{atomic}: either the entire transaction succeeds and its effects +are all visible to readers in one go, or the whole thing is undone. +This guarantee of atomicity means that if you're running two copies of +Mercurial, where one is reading data and one is writing it, the reader +will never see a partially written result that might confuse it. + +The fact that Mercurial only appends to files makes it easier to +provide this transactional guarantee. The easier it is to do stuff +like this, the more confident you should be that it's done correctly. + +\subsection{Fast retrieval} + +Mercurial cleverly avoids a pitfall common to all earlier +revision control systems: the problem of \emph{inefficient retrieval}. +Most revision control systems store the contents of a revision as an +incremental series of modifications against a ``snapshot''. To +reconstruct a specific revision, you must first read the snapshot, and +then every one of the revisions between the snapshot and your target +revision. The more history that a file accumulates, the more +revisions you must read, hence the longer it takes to reconstruct a +particular revision. + +\begin{figure}[ht] + \centering + \includegraphics{snapshot} + \caption{Snapshot of a revlog, with incremental deltas} + \label{fig:concepts:snapshot} +\end{figure} + +The innovation that Mercurial applies to this problem is simple but +effective. Once the cumulative amount of delta information stored +since the last snapshot exceeds a fixed threshold, it stores a new +snapshot (compressed, of course), instead of another delta. This +makes it possible to reconstruct \emph{any} revision of a file +quickly. This approach works so well that it has since been copied by +several other revision control systems. + +Figure~\ref{fig:concepts:snapshot} illustrates the idea. In an entry +in a revlog's index file, Mercurial stores the range of entries from +the data file that it must read to reconstruct a particular revision. + +\subsubsection{Aside: the influence of video compression} + +If you're familiar with video compression or have ever watched a TV +feed through a digital cable or satellite service, you may know that +most video compression schemes store each frame of video as a delta +against its predecessor frame. In addition, these schemes use +``lossy'' compression techniques to increase the compression ratio, so +visual errors accumulate over the course of a number of inter-frame +deltas. + +Because it's possible for a video stream to ``drop out'' occasionally +due to signal glitches, and to limit the accumulation of artefacts +introduced by the lossy compression process, video encoders +periodically insert a complete frame (called a ``key frame'') into the +video stream; the next delta is generated against that frame. This +means that if the video signal gets interrupted, it will resume once +the next key frame is received. Also, the accumulation of encoding +errors restarts anew with each key frame. + +\subsection{Identification and strong integrity} + +Along with delta or snapshot information, a revlog entry contains a +cryptographic hash of the data that it represents. This makes it +difficult to forge the contents of a revision, and easy to detect +accidental corruption. + +Hashes provide more than a mere check against corruption; they are +used as the identifiers for revisions. The changeset identification +hashes that you see as an end user are from revisions of the +changelog. Although filelogs and the manifest also use hashes, +Mercurial only uses these behind the scenes. + +Mercurial verifies that hashes are correct when it retrieves file +revisions and when it pulls changes from another repository. If it +encounters an integrity problem, it will complain and stop whatever +it's doing. + +In addition to the effect it has on retrieval efficiency, Mercurial's +use of periodic snapshots makes it more robust against partial data +corruption. If a revlog becomes partly corrupted due to a hardware +error or system bug, it's often possible to reconstruct some or most +revisions from the uncorrupted sections of the revlog, both before and +after the corrupted section. This would not be possible with a +delta-only storage model. + +\section{Revision history, branching, + and merging} + +Every entry in a Mercurial revlog knows the identity of its immediate +ancestor revision, usually referred to as its \emph{parent}. In fact, +a revision contains room for not one parent, but two. Mercurial uses +a special hash, called the ``null ID'', to represent the idea ``there +is no parent here''. This hash is simply a string of zeroes. + +In figure~\ref{fig:concepts:revlog}, you can see an example of the +conceptual structure of a revlog. Filelogs, manifests, and changelogs +all have this same structure; they differ only in the kind of data +stored in each delta or snapshot. + +The first revision in a revlog (at the bottom of the image) has the +null ID in both of its parent slots. For a ``normal'' revision, its +first parent slot contains the ID of its parent revision, and its +second contains the null ID, indicating that the revision has only one +real parent. Any two revisions that have the same parent ID are +branches. A revision that represents a merge between branches has two +normal revision IDs in its parent slots. + +\begin{figure}[ht] + \centering + \includegraphics{revlog} + \caption{} + \label{fig:concepts:revlog} +\end{figure} + +\section{The working directory} + +In the working directory, Mercurial stores a snapshot of the files +from the repository as of a particular changeset. + +The working directory ``knows'' which changeset it contains. When you +update the working directory to contain a particular changeset, +Mercurial looks up the appropriate revision of the manifest to find +out which files it was tracking at the time that changeset was +committed, and which revision of each file was then current. It then +recreates a copy of each of those files, with the same contents it had +when the changeset was committed. + +The \emph{dirstate} contains Mercurial's knowledge of the working +directory. This details which changeset the working directory is +updated to, and all of the files that Mercurial is tracking in the +working directory. + +Just as a revision of a revlog has room for two parents, so that it +can represent either a normal revision (with one parent) or a merge of +two earlier revisions, the dirstate has slots for two parents. When +you use the \hgcmd{update} command, the changeset that you update to +is stored in the ``first parent'' slot, and the null ID in the second. +When you \hgcmd{merge} with another changeset, the first parent +remains unchanged, and the second parent is filled in with the +changeset you're merging with. The \hgcmd{parents} command tells you +what the parents of the dirstate are. + +\subsection{What happens when you commit} + +The dirstate stores parent information for more than just book-keeping +purposes. Mercurial uses the parents of the dirstate as \emph{the + parents of a new changeset} when you perform a commit. + +\begin{figure}[ht] + \centering + \includegraphics{wdir} + \caption{The working directory can have two parents} + \label{fig:concepts:wdir} +\end{figure} + +Figure~\ref{fig:concepts:wdir} shows the normal state of the working +directory, where it has a single changeset as parent. That changeset +is the \emph{tip}, the newest changeset in the repository that has no +children. + +\begin{figure}[ht] + \centering + \includegraphics{wdir-after-commit} + \caption{The working directory gains new parents after a commit} + \label{fig:concepts:wdir-after-commit} +\end{figure} + +It's useful to think of the working directory as ``the changeset I'm +about to commit''. Any files that you tell Mercurial that you've +added, removed, renamed, or copied will be reflected in that +changeset, as will modifications to any files that Mercurial is +already tracking; the new changeset will have the parents of the +working directory as its parents. + +After a commit, Mercurial will update the parents of the working +directory, so that the first parent is the ID of the new changeset, +and the second is the null ID. This is shown in +figure~\ref{fig:concepts:wdir-after-commit}. Mercurial doesn't touch +any of the files in the working directory when you commit; it just +modifies the dirstate to note its new parents. + +\subsection{Creating a new head} + +It's perfectly normal to update the working directory to a changeset +other than the current tip. For example, you might want to know what +your project looked like last Tuesday, or you could be looking through +changesets to see which one introduced a bug. In cases like this, the +natural thing to do is update the working directory to the changeset +you're interested in, and then examine the files in the working +directory directly to see their contents as they werea when you +committed that changeset. The effect of this is shown in +figure~\ref{fig:concepts:wdir-pre-branch}. + +\begin{figure}[ht] + \centering + \includegraphics{wdir-pre-branch} + \caption{The working directory, updated to an older changeset} + \label{fig:concepts:wdir-pre-branch} +\end{figure} + +Having updated the working directory to an older changeset, what +happens if you make some changes, and then commit? Mercurial behaves +in the same way as I outlined above. The parents of the working +directory become the parents of the new changeset. This new changeset +has no children, so it becomes the new tip. And the repository now +contains two changesets that have no children; we call these +\emph{heads}. You can see the structure that this creates in +figure~\ref{fig:concepts:wdir-branch}. + +\begin{figure}[ht] + \centering + \includegraphics{wdir-branch} + \caption{After a commit made while synced to an older changeset} + \label{fig:concepts:wdir-branch} +\end{figure} + +\begin{note} + If you're new to Mercurial, you should keep in mind a common + ``error'', which is to use the \hgcmd{pull} command without any + options. By default, the \hgcmd{pull} command \emph{does not} + update the working directory, so you'll bring new changesets into + your repository, but the working directory will stay synced at the + same changeset as before the pull. If you make some changes and + commit afterwards, you'll thus create a new head, because your + working directory isn't synced to whatever the current tip is. + + I put the word ``error'' in quotes because all that you need to do + to rectify this situation is \hgcmd{merge}, then \hgcmd{commit}. In + other words, this almost never has negative consequences; it just + surprises people. I'll discuss other ways to avoid this behaviour, + and why Mercurial behaves in this initially surprising way, later + on. +\end{note} + +\subsection{Merging heads} + +When you run the \hgcmd{merge} command, Mercurial leaves the first +parent of the working directory unchanged, and sets the second parent +to the changeset you're merging with, as shown in +figure~\ref{fig:concepts:wdir-merge}. + +\begin{figure}[ht] + \centering + \includegraphics{wdir-merge} + \caption{Merging two heads} + \label{fig:concepts:wdir-merge} +\end{figure} + +Mercurial also has to modify the working directory, to merge the files +managed in the two changesets. Simplified a little, the merging +process goes like this, for every file in the manifests of both +changesets. +\begin{itemize} +\item If neither changeset has modified a file, do nothing with that + file. +\item If one changeset has modified a file, and the other hasn't, + create the modified copy of the file in the working directory. +\item If one changeset has removed a file, and the other hasn't (or + has also deleted it), delete the file from the working directory. +\item If one changeset has removed a file, but the other has modified + the file, ask the user what to do: keep the modified file, or remove + it? +\item If both changesets have modified a file, invoke an external + merge program to choose the new contents for the merged file. This + may require input from the user. +\item If one changeset has modified a file, and the other has renamed + or copied the file, make sure that the changes follow the new name + of the file. +\end{itemize} +There are more details---merging has plenty of corner cases---but +these are the most common choices that are involved in a merge. As +you can see, most cases are completely automatic, and indeed most +merges finish automatically, without requiring your input to resolve +any conflicts. + +When you're thinking about what happens when you commit after a merge, +once again the working directory is ``the changeset I'm about to +commit''. After the \hgcmd{merge} command completes, the working +directory has two parents; these will become the parents of the new +changeset. + +Mercurial lets you perform multiple merges, but you must commit the +results of each individual merge as you go. This is necessary because +Mercurial only tracks two parents for both revisions and the working +directory. While it would be technically possible to merge multiple +changesets at once, the prospect of user confusion and making a +terrible mess of a merge immediately becomes overwhelming. + +\section{Other interesting design features} + +In the sections above, I've tried to highlight some of the most +important aspects of Mercurial's design, to illustrate that it pays +careful attention to reliability and performance. However, the +attention to detail doesn't stop there. There are a number of other +aspects of Mercurial's construction that I personally find +interesting. I'll detail a few of them here, separate from the ``big +ticket'' items above, so that if you're interested, you can gain a +better idea of the amount of thinking that goes into a well-designed +system. + +\subsection{Clever compression} + +When appropriate, Mercurial will store both snapshots and deltas in +compressed form. It does this by always \emph{trying to} compress a +snapshot or delta, but only storing the compressed version if it's +smaller than the uncompressed version. + +This means that Mercurial does ``the right thing'' when storing a file +whose native form is compressed, such as a \texttt{zip} archive or a +JPEG image. When these types of files are compressed a second time, +the resulting file is usually bigger than the once-compressed form, +and so Mercurial will store the plain \texttt{zip} or JPEG. + +Deltas between revisions of a compressed file are usually larger than +snapshots of the file, and Mercurial again does ``the right thing'' in +these cases. It finds that such a delta exceeds the threshold at +which it should store a complete snapshot of the file, so it stores +the snapshot, again saving space compared to a naive delta-only +approach. + +\subsubsection{Network recompression} + +When storing revisions on disk, Mercurial uses the ``deflate'' +compression algorithm (the same one used by the popular \texttt{zip} +archive format), which balances good speed with a respectable +compression ratio. However, when transmitting revision data over a +network connection, Mercurial uncompresses the compressed revision +data. + +If the connection is over HTTP, Mercurial recompresses the entire +stream of data using a compression algorithm that gives a better +compression ratio (the Burrows-Wheeler algorithm from the widely used +\texttt{bzip2} compression package). This combination of algorithm +and compression of the entire stream (instead of a revision at a time) +substantially reduces the number of bytes to be transferred, yielding +better network performance over almost all kinds of network. + +(If the connection is over \command{ssh}, Mercurial \emph{doesn't} +recompress the stream, because \command{ssh} can already do this +itself.) + +\subsection{Read/write ordering and atomicity} + +Appending to files isn't the whole story when it comes to guaranteeing +that a reader won't see a partial write. If you recall +figure~\ref{fig:concepts:metadata}, revisions in the changelog point to +revisions in the manifest, and revisions in the manifest point to +revisions in filelogs. This hierarchy is deliberate. + +A writer starts a transaction by writing filelog and manifest data, +and doesn't write any changelog data until those are finished. A +reader starts by reading changelog data, then manifest data, followed +by filelog data. + +Since the writer has always finished writing filelog and manifest data +before it writes to the changelog, a reader will never read a pointer +to a partially written manifest revision from the changelog, and it will +never read a pointer to a partially written filelog revision from the +manifest. + +\subsection{Concurrent access} + +The read/write ordering and atomicity guarantees mean that Mercurial +never needs to \emph{lock} a repository when it's reading data, even +if the repository is being written to while the read is occurring. +This has a big effect on scalability; you can have an arbitrary number +of Mercurial processes safely reading data from a repository safely +all at once, no matter whether it's being written to or not. + +The lockless nature of reading means that if you're sharing a +repository on a multi-user system, you don't need to grant other local +users permission to \emph{write} to your repository in order for them +to be able to clone it or pull changes from it; they only need +\emph{read} permission. (This is \emph{not} a common feature among +revision control systems, so don't take it for granted! Most require +readers to be able to lock a repository to access it safely, and this +requires write permission on at least one directory, which of course +makes for all kinds of nasty and annoying security and administrative +problems.) + +Mercurial uses locks to ensure that only one process can write to a +repository at a time (the locking mechanism is safe even over +filesystems that are notoriously hostile to locking, such as NFS). If +a repository is locked, a writer will wait for a while to retry if the +repository becomes unlocked, but if the repository remains locked for +too long, the process attempting to write will time out after a while. +This means that your daily automated scripts won't get stuck forever +and pile up if a system crashes unnoticed, for example. (Yes, the +timeout is configurable, from zero to infinity.) + +\subsubsection{Safe dirstate access} + +As with revision data, Mercurial doesn't take a lock to read the +dirstate file; it does acquire a lock to write it. To avoid the +possibility of reading a partially written copy of the dirstate file, +Mercurial writes to a file with a unique name in the same directory as +the dirstate file, then renames the temporary file atomically to +\filename{dirstate}. The file named \filename{dirstate} is thus +guaranteed to be complete, not partially written. + +\subsection{Avoiding seeks} + +Critical to Mercurial's performance is the avoidance of seeks of the +disk head, since any seek is far more expensive than even a +comparatively large read operation. + +This is why, for example, the dirstate is stored in a single file. If +there were a dirstate file per directory that Mercurial tracked, the +disk would seek once per directory. Instead, Mercurial reads the +entire single dirstate file in one step. + +Mercurial also uses a ``copy on write'' scheme when cloning a +repository on local storage. Instead of copying every revlog file +from the old repository into the new repository, it makes a ``hard +link'', which is a shorthand way to say ``these two names point to the +same file''. When Mercurial is about to write to one of a revlog's +files, it checks to see if the number of names pointing at the file is +greater than one. If it is, more than one repository is using the +file, so Mercurial makes a new copy of the file that is private to +this repository. + +A few revision control developers have pointed out that this idea of +making a complete private copy of a file is not very efficient in its +use of storage. While this is true, storage is cheap, and this method +gives the highest performance while deferring most book-keeping to the +operating system. An alternative scheme would most likely reduce +performance and increase the complexity of the software, each of which +is much more important to the ``feel'' of day-to-day use. + +\subsection{Other contents of the dirstate} + +Because Mercurial doesn't force you to tell it when you're modifying a +file, it uses the dirstate to store some extra information so it can +determine efficiently whether you have modified a file. For each file +in the working directory, it stores the time that it last modified the +file itself, and the size of the file at that time. + +When you explicitly \hgcmd{add}, \hgcmd{remove}, \hgcmd{rename} or +\hgcmd{copy} files, Mercurial updates the dirstate so that it knows +what to do with those files when you commit. + +When Mercurial is checking the states of files in the working +directory, it first checks a file's modification time. If that has +not changed, the file must not have been modified. If the file's size +has changed, the file must have been modified. If the modification +time has changed, but the size has not, only then does Mercurial need +to read the actual contents of the file to see if they've changed. +Storing these few extra pieces of information dramatically reduces the +amount of data that Mercurial needs to read, which yields large +performance improvements compared to other revision control systems. + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/daily.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,685 @@ +%\chapter{Mercurial in daily use} +\chapter{Mercurial$B$G$NF|>o:n6H(B} +\label{chap:daily} + +%\section{Telling Mercurial which files to track} +\section{$BDI@W$9$Y$-%U%!%$%k$N(BMercurial$B$X$NEPO?(B} + +%Mercurial does not work with files in your repository unless you tell +%it to manage them. The \hgcmd{status} command will tell you which +%files Mercurial doesn't know about; it uses a ``\texttt{?}'' to +%display such files. + +Mercurial$B$O!$%f!<%6$K$h$k%U%!%$%k4IM}$N;X<($,$J$$8B$j!$%j%]%8%H%jFb$N%U%!(B +$B%$%k$G$"$C$F$b4IM}$r9T$o$J$$!%(BMercurial$B$,4IM}$7$J$$%U%!%$%k$O(B +\hgcmd{status}$B%3%^%s%I$r<B9T$9$k$H(B``\texttt{?}''$B$HI=<($5$l$k!%(B + +%To tell Mercurial to track a file, use the \hgcmd{add} command. Once +%you have added a file, the entry in the output of \hgcmd{status} for +%that file changes from ``\texttt{?}'' to ``\texttt{A}''. +%\interaction{daily.files.add} + +Mercurial$B$K%U%!%$%k$NDI@W$r$5$;$k$K$O!$(B\hgcmd{add}$B%3%^%s%I$rMQ$$$k!%0lEY(B +$B%U%!%$%k$rDI2C$9$k$H!$(B\hgcmd{status}$B%3%^%s%I$N=PNO$O(B``\texttt{?}''$B$+$i(B +``\texttt{A}''$B$KJQ$o$k!%(B +\interaction{daily.files.add} + +%After you run a \hgcmd{commit}, the files that you added before the +%commit will no longer be listed in the output of \hgcmd{status}. The +%reason for this is that \hgcmd{status} only tells you about +%``interesting'' files---those that you have modified or told Mercurial +%to do something with---by default. If you have a repository that +%contains thousands of files, you will rarely want to know about files +%that Mercurial is tracking, but that have not changed. (You can still +%get this information; we'll return to this later.) + +\hgcmd{commit}$B%3%^%s%I$r<B9T$9$k$H!$(Bcommit$B$NA0$KDI2C$7$?%U%!%$%k$O(B +\hgcmd{status}$B$N=PNO$K8=$l$J$/$J$k!%$3$l$O!$(B\hgcmd{status}$B$,%G%U%)%k%H$G(B +$B$OJQ99$r2C$($?$j!$(BMercurial$B$K2?$+$r$5$;$?$H$$$C$?(B``$BCmL\$9$Y$-(B''$B%U%!%$%k$N(B +$B$_$rI=<($9$k$?$a$G$"$k!%?t@i$N%U%!%$%k$+$i$J$k%j%]%8%H%j$N>l9g!$(BMercurial$B$,(B +$BDI@W$7$F$$$k$b$N$N!$JQ99$N2C$($i$l$F$$$J$$%U%!%$%k$K$D$$$F2?$+$rCN$j$?$$(B +$B$H$$$&$3$H$O5)$G$"$k!%!J$b$A$m$sCN$j$?$$>l9g$O>pJs$rF@$k$3$H$b$G$-$k!%$3(B +$B$l$K$D$$$F$O8e=R$9$k!%!K(B + +%Once you add a file, Mercurial doesn't do anything with it +%immediately. Instead, it will take a snapshot of the file's state the +%next time you perform a commit. It will then continue to track the +%changes you make to the file every time you commit, until you remove +%the file. + +$BDI2C$7$?%U%!%$%k$KBP$7$F(BMercurial$B$,D>$A$K9T$&$3$H$O2?$b$J$$$,!$$=$NBe$o$j(B +$B$K<!2s$N%3%_%C%H;~$K%U%!%$%k>uBV$N%9%J%C%W%7%g%C%H$r<h$k!%$=$7$F%U%!%$%k(B +$B$r:o=|$9$k$^$G%3%_%C%HKh$K%U%!%$%k$NJQ2=$rDI@W$9$k!%(B + +%\subsection{Explicit versus implicit file naming} +\subsection{$BL@<(E*$J%U%!%$%kL?L>BP0EL[$N%U%!%$%kL?L>(B} + +%A useful behaviour that Mercurial has is that if you pass the name of +%a directory to a command, every Mercurial command will treat this as +%``I want to operate on every file in this directory and its +%subdirectories''. +%\interaction{daily.files.add-dir} +%Notice in this example that Mercurial printed the names of the files +%it added, whereas it didn't do so when we added the file named +%\filename{a} in the earlier example. + +Mercurial$B$NA4$F$N%3%^%s%I$O!$0z?t$H$7$F%G%#%l%/%H%jL>$rEO$9$H!$%G%#%l%/%H(B +$B%j$NFb$NA4$F$N%U%!%$%k$H%5%V%G%#%l%/%H%j$KBP$9$kA`:n$G$"$k$H2r<a$9$k$?$a(B +$BJXMx$G$"$k!%(B +\interaction{daily.files.add-dir} +$B$3$NNc$G$O(BMercurial$B$ODI2C$7$?%U%!%$%kL>$rI=<($7$F$$$k$,!$A0$NNc$G(B +\filename{a}$B$H$$$&L>A0$N%U%!%$%k$rDI2C$7$?:]$K$OI=<($7$F$$$J$+$C$?E@$KCm(B +$B0U$5$l$?$$!%(B + +%What's going on is that in the former case, we explicitly named the +%file to add on the command line, so the assumption that Mercurial +%makes in such cases is that you know what you were doing, and it +%doesn't print any output. + +$BA0$NNc$G$O%3%^%s%I%i%$%s$G$I$N%U%!%$%k$rDI2C$9$k$N$+$rL@<(E*$K;XDj$7$?$?(B +$B$a!$(BMercurial$B$O%f!<%6$,2?$r$7$h$&$H$7$F$$$k$N$+J,$+$C$F$$$k$H?dDj$7$F2?$b(B +$BI=<($7$J$+$C$?!%(B + +%However, when we \emph{imply} the names of files by giving the name of +%a directory, Mercurial takes the extra step of printing the name of +%each file that it does something with. This makes it more clear what +%is happening, and reduces the likelihood of a silent and nasty +%surprise. This behaviour is common to most Mercurial commands. + +$B$7$+$7%G%#%l%/%H%jL>$rM?$($k$3$H$G%U%!%$%kL>$r0EL[E*$KM?$($?>l9g!"(B +Mercurial$B$O4XO"$9$k%U%!%$%k$NL>A0$r(B1$B$D$:$DI=<($9$kDI2C$N%9%F%C%W$rF'$`!%(B +$B$3$l$K$h$C$F2?$,5/$3$C$F$$$k$N$+M}2r$7$d$9$/$9$k$H6&$K!$D@L[N"$KLq2p$JLd(B +$BBj$,5/$3$k2DG=@-$r8:$i$7$F$$$k!%$3$N5sF0$O(BMercurial$B$NBgH>$N%3%^%s%I$K6&(B +$BDL$7$F$$$k!%(B + +%\subsection{Aside: Mercurial tracks files, not directories} +\subsection{$B$3$\$lOC(B: Mercurial$B$O%G%#%l%/%H%j$G$O$J$/%U%!%$%k$rDI@W$9$k(B} + +%Mercurial does not track directory information. Instead, it tracks +%the path to a file. Before creating a file, it first creates any +%missing directory components of the path. After it deletes a file, it +%then deletes any empty directories that were in the deleted file's +%path. This sounds like a trivial distinction, but it has one minor +%practical consequence: it is not possible to represent a completely +%empty directory in Mercurial. + +Mercurial$B$O%G%#%l%/%H%j>pJs$rDI@W$7$J$$!%$=$NBe$o$j!$%U%!%$%k$X$N%Q%9$rDI(B +$B@W$7$F$$$k!%%U%!%$%k$r:n@.$9$k:]$K$O!$$^$:%Q%9$N%G%#%l%/%H%jItJ,$rJd40$9(B +$B$k!%%U%!%$%k$r>C5n$7$?8e$O!$%U%!%$%k$N4^$^$l$F$$$?6u$N%G%#%l%/%H%j$rA4$F(B +$B>C5n$9$k!%$3$l$OEvA3$N5sF0$N$h$&$K8+$($k$,!$<B:]>e$O>.$5$JLdBj$r0z$-5/$3(B +$B$9!%$9$J$o$A!$(BMercurial$B$O40A4$K6u$N%G%#%l%/%H%j$rI=8=$9$k$3$H$,$G$-$J$$$N(B +$B$G$"$k!%(B + +%Empty directories are rarely useful, and there are unintrusive +%workarounds that you can use to achieve an appropriate effect. The +%developers of Mercurial thus felt that the complexity that would be +%required to manage empty directories was not worth the limited benefit +%this feature would bring. + +$B6u$N%G%#%l%/%H%j$,M-MQ$G$"$k$3$H$OLGB?$K$J$$$,!$E,Ev$J%o!<%/%"%i%&%s%I$H(B +$B$7$F!$%j%]%8%H%j$NF0$-$rK8$2$J$$J}K!$,B8:_$9$k!%(B +Mercurial$B$N3+H/<T$?$A$O!$6u$N%G%#%l%/%H%j$rI=8=$9$k$?$a$K2C$o$kJ#;($5$O!$$=(B +$B$N5!G=$K8+9g$o$J$$$H9M$($?!%(B + +%If you need an empty directory in your repository, there are a few +%ways to achieve this. One is to create a directory, then \hgcmd{add} a +%``hidden'' file to that directory. On Unix-like systems, any file +%name that begins with a period (``\texttt{.}'') is treated as hidden +%by most commands and GUI tools. This approach is illustrated in +%figure~\ref{ex:daily:hidden}. + +$B%j%]%8%H%j$K6u$N%G%#%l%/%H%j$,I,MW$J>l9g!$$3$l$r<B8=$9$kJ}K!$,$$$/$D$+$"(B +$B$k!%(B1$B$DL\$O!$$^$:%G%#%l%/%H%j$r:n@.$7!$1#$7%U%!%$%k$r$3$N%G%#%l%/%H%jFb$K(B +\hgcmd{add}$B$9$k!%(BUnix$B7O%7%9%F%`$G$O!$%T%j%*%I(B(``\texttt{.}'')$B$G;O$^$k%U%!(B +$B%$%k$OBgH>$N%3%^%s%I$H(BGUI$B%D!<%k$G1#$7%U%!%$%k$H$7$F<h$j07$o$l$k!%(B +$B>\:Y$K$D$$$F$O?^(B~\ref{ex:daily:hidden}$B$r;2>H$5$l$?$$!%(B + +\begin{figure}[ht] + \interaction{daily.files.hidden} +% \caption{Simulating an empty directory using a hidden file} + \caption{$B1#$7%U%!%$%k$r;H$C$F6u$N%G%#%l%/%H%j$r%7%_%e%l!<%H$9$k(B} + \label{ex:daily:hidden} +\end{figure} + +%Another way to tackle a need for an empty directory is to simply +%create one in your automated build scripts before they will need it. + +$B6u$N%G%#%l%/%H%j$r07$&JL$NJ}K!$K$O!$<+F0%S%k%I%9%/%j%W%H$NCf$G!$I,MW$K$J$k(B +$BA0$K:n@.$9$k$3$H$,$"$k!%(B + +%\section{How to stop tracking a file} +\section{$B%U%!%$%kDI@W$NDd;_(B} + +%Once you decide that a file no longer belongs in your repository, use +%the \hgcmd{remove} command; this deletes the file, and tells Mercurial +%to stop tracking it. A removed file is represented in the output of +%\hgcmd{status} with a ``\texttt{R}''. +%\interaction{daily.files.remove} + +$B%U%!%$%k$,%j%]%8%H%j$KI,MW$J$/$J$C$?;~$O(B\hgcmd{remove}$B%3%^%s%I$r<B9T$9(B +$B$k!%$3$N%3%^%s%I$O%U%!%$%k$r:o=|$7$?>e$G(BMercurial$B$K%U%!%$%kDI@W$NDd;_$r;X(B +$B<($9$k!%:o=|$5$l$?%U%!%$%k$O(B\hgcmd{status}$B%3%^%s%I$N=PNO$G(B``\texttt{R}'' +$B$HI=<($5$l$k!%(B +\interaction{daily.files.remove} + +%After you \hgcmd{remove} a file, Mercurial will no longer track +%changes to that file, even if you recreate a file with the same name +%in your working directory. If you do recreate a file with the same +%name and want Mercurial to track the new file, simply \hgcmd{add} it. +%Mercurial will know that the newly added file is not related to the +%old file of the same name. + +$B0lEY%U%!%$%k$r(B\hgcmd{remove}$B$7$?8e$G$O!$(BMercurial$B$O%o!<%-%s%0%G%#%l%/%H%j(B +$BFb$K$?$H$(F1$8L>A0$G%U%!%$%k$,:F@8@.$5$l$F$b%U%!%$%k$X$NJQ99$rDI@W$7$J$$!%(B +$B%U%!%$%k$r:F@8@.$7!$(BMercurial$B$KDI@W$5$;$?$$$N$G$"$l$P!$(B\hgcmd{add}$B$r9T$&!%(B +Mercurial$B$O!$?75,$KDI2C$5$l$?%U%!%$%k$rF1L>$N8E$$%U%!%$%k$H4X78$J$/07$&!%(B + +%\subsection{Removing a file does not affect its history} +\subsection{$B%U%!%$%k:o=|$OMzNr$K1F6A$rM?$($J$$(B} + +%It is important to understand that removing a file has only two +%effects. +$B%U%!%$%k$N:o=|$,%j%]%8%H%j$KM?$($k1F6A$O(B2$B$D$N$_$G$"$k!%(B +\begin{itemize} +%\item It removes the current version of the file from the working +% directory. + \item $B%o!<%-%s%0%G%#%l%/%H%j$+$i869F$N%P!<%8%g%s$N%U%!%$%k$r>C5n$9$k!%(B +%\item It stops Mercurial from tracking changes to the file, from the +% time of the next commit. + \item $B:o=|$9$k%U%!%$%k$X$NJQ99$r<!2s$N%3%_%C%H$+$i(BMercurial$B$,DI@W$7$J$$(B + $B$h$&$K$9$k!%(B +\end{itemize} +%Removing a file \emph{does not} in any way alter the \emph{history} of +%the file. +$B%U%!%$%k$r$I$N$h$&$K:o=|$7$F$b%U%!%$%k$N(B\emph{$BMzNr(B}$B$OJQ99(B\emph{$B$5$l$J$$(B}$B!%(B + +%If you update the working directory to a changeset in which a file +%that you have removed was still tracked, it will reappear in the +%working directory, with the contents it had when you committed that +%changeset. If you then update the working directory to a later +%changeset, in which the file had been removed, Mercurial will once +%again remove the file from the working directory. + +$B%o!<%-%s%0%G%#%l%/%H%j$r!$>C5n$7$?%U%!%$%k$r4^$`%A%'%s%8%;%C%H$K99?7$9$k(B +$B$H!$%U%!%$%k$O$=$N%A%'%s%8%;%C%H$G$NFbMF$G:F$S%o!<%-%s%0%G%#%l%/%H%j$K8=(B +$B$l$k!%$=$3$G%U%!%$%k$,>C5n$5$l$F$$$k8e$N%A%'%s%8%;%C%H$K99?7$9$k(B +$B$H!$(BMercurial$B$O%U%!%$%k$r:F$S%o!<%-%s%0%G%#%l%/%H%j$+$i>C5n$9$k!%(B + +%\subsection{Missing files} +\subsection{$B7gMn$7$?%U%!%$%k(B} + +%Mercurial considers a file that you have deleted, but not used +%\hgcmd{remove} to delete, to be \emph{missing}. A missing file is +%represented with ``\texttt{!}'' in the output of \hgcmd{status}. +%Mercurial commands will not generally do anything with missing files. +%\interaction{daily.files.missing} + +Mercurial$B$O!$(B\hgcmd{remove}$B$r;H$o$:$K>C5n$5$l$?%U%!%$%k$r(B\emph{$B7gMn(B}$B$7$?(B +$B%U%!%$%k$H$7$F07$&!%7gMn%U%!%$%k$O(B\hgcmd{status}$B%3%^%s%I$N=PNO$G(B +``\texttt{!}''$B$HI=<($5$l$k!%(BMercurial$B$N%3%^%s%I$O!$DL>o!$7gMn$7$?%U%!%$(B +$B%k$K$O2?$b9T$o$J$$!%(B +\interaction{daily.files.missing} + +%If your repository contains a file that \hgcmd{status} reports as +%missing, and you want the file to stay gone, you can run +%\hgcmdargs{remove}{\hgopt{remove}{--after}} at any time later on, to +%tell Mercurial that you really did mean to remove the file. +%\interaction{daily.files.remove-after} + +$B%j%]%8%H%jFb$G(B\hgcmd{status}$B%3%^%s%I$,7gMn$H%j%]!<%H$9$k%U%!%$%k$,$"$k>l(B +$B9g!$(B\hgcmdargs{remove}{\hgopt{remove}{--after}}$B$r<B9T$7$F!$(BMercurial$B$K7g(B +$BMn%U%!%$%k$,>C5n$5$l$?$b$N$G$"$k$3$H$r;X<($9$k$3$H$,$G$-$k!%(B +\interaction{daily.files.remove-after} + +%On the other hand, if you deleted the missing file by accident, use +%\hgcmdargs{revert}{\emph{filename}} to recover the file. It will +%reappear, in unmodified form. +%\interaction{daily.files.recover-missing} + +$B0lJ}$G!$8m$C$F%U%!%$%k$r>C5n$7$?>l9g!$(B\hgcmdargs{revert}{\emph{filename}}$B$r(B +$B<B9T$9$k$3$H$G%U%!%$%k$r=$I|$9$k$3$H$,$G$-$k!%%U%!%$%k$O2?$bJQ99$5$l$J$$>uBV(B +$B$G=$I|$5$l$k!%(B +\interaction{daily.files.recover-missing} + +%\subsection{Aside: why tell Mercurial explicitly to remove a file?} +\subsection{$B$3$\$lOC(B: $B$J$<(BMercurial$B$X%U%!%$%k$N:o=|$rL@<(E*$K;X<($7$J$1(B + $B$l$P$J$i$J$$$+(B} + +%You might wonder why Mercurial requires you to explicitly tell it that +%you are deleting a file. Early during the development of Mercurial, +%it let you delete a file however you pleased; Mercurial would notice +%the absence of the file automatically when you next ran a +%\hgcmd{commit}, and stop tracking the file. In practice, this made it +%too easy to accidentally remove a file without noticing. + +$B$J$<(BMercurial$B$K%U%!%$%k$N:o=|$rL@<(E*$K;X<($7$J$1$l$P$J$i$J$$$N$@$m$&$+!)(B +Mercurial$B$N3+H/$N=i4|$K$O!$%U%!%$%k$,$J$$$3$H$r8!CN$9$k$H!$<!$K(B +\hgcmd{commit}$B$,<B9T$5$l$k;~$K<+F0E*$K%U%!%$%k$NDI@W$r$d$a$F$$$?!%<B:]$K(B +$B;H$C$F$_$k$H$3$NF0:n$G$O%U%!%$%k$rCN$i$:$N$&$A$K<:$&$3$H$,IQH/$7$?$N$G$"(B +$B$k!%(B + +%\subsection{Useful shorthand---adding and removing files in one step} +\subsection{$BLr$KN)$D4JN,K!(B---$B%U%!%$%k$NDI2C$H:o=|$r(B1$B%9%F%C%W$G9T$&(B} + +%Mercurial offers a combination command, \hgcmd{addremove}, that adds +%untracked files and marks missing files as removed. +%\interaction{daily.files.addremove} +%The \hgcmd{commit} command also provides a \hgopt{commit}{-A} option +%that performs this same add-and-remove, immediately followed by a +%commit. +%\interaction{daily.files.commit-addremove} + +Mercurial$B$O(B\hgcmd{addremove}$B$H$$$&AH$_9g$o$;%3%^%s%I$r;}$C$F$$$k!%$3$N%3(B +$B%^%s%I$ODI@W$5$l$F$$$J$$%U%!%$%k72$rDI2C$7!$7gMn$7$F$$$k%U%!%$%k$r>C5n$5(B +$B$l$?$H%^!<%/$9$k!%(B +\interaction{daily.files.addremove} +\hgcmd{commit}$B%3%^%s%I$K$O(B\hgopt{commit}{-A}$B%*%W%7%g%s$,$"$j!$F1$8DI2C$H(B +$B:o=|$NA`:n$r%3%_%C%HD>8e$K9T$&!%(B +\interaction{daily.files.commit-addremove} + +%\section{Copying files} +\section{$B%U%!%$%k$N%3%T!<(B} + +%Mercurial provides a \hgcmd{copy} command that lets you make a new +%copy of a file. When you copy a file using this command, Mercurial +%makes a record of the fact that the new file is a copy of the original +%file. It treats these copied files specially when you merge your work +%with someone else's. + +Mercurial$B$K$O!$%U%!%$%k$N?7$7$$%3%T!<$r:n$k(B\hgcmd{copy}$B%3%^%s%I$,$"$k!%(B +$B$3$N%3%^%s%I$r;H$C$F%U%!%$%k$r%3%T!<$9$k$H!$(BMercurial$B$O?7$7$$%U%!%$%k$,(B +$B%*%j%8%J%k$NJ#@=$G$"$k$3$H$r5-O?$9$k!%J#@=$5$l$?%U%!%$%k$O!$JL$N?M$K$h$k(B +$BJQ99$r%^!<%8$9$k;~$KFCJL$J<h$j07$$$,$J$5$l$k!%(B + +%\subsection{The results of copying during a merge} +\subsection{$B%^!<%8Cf$N%3%T!<$N7k2L(B} + +%What happens during a merge is that changes ``follow'' a copy. To +%best illustrate what this means, let's create an example. We'll start +%with the usual tiny repository that contains a single file. +%\interaction{daily.copy.init} +%We need to do some work in parallel, so that we'll have something to +%merge. So let's clone our repository. +%\interaction{daily.copy.clone} +%Back in our initial repository, let's use the \hgcmd{copy} command to +%make a copy of the first file we created. +%\interaction{daily.copy.copy} + +$B%^!<%8Cf$K$O!$%3%T!<$K(B``$B=>$&(B''$B$3$H$,5/$-$k!%$3$l$N0UL#$9$k$H$3$m$r<($9$?(B +$B$a$K!$Nc$r5s$2$k$3$H$K$9$k!%$$$D$b$N$h$&$K!$%U%!%$%k(B1$B$D$@$1$r4^$`>.$5$J%j(B +$B%]%8%H%j$r:n@.$9$k!%(B +\interaction{daily.copy.init} +$B%^!<%8$9$Y$-FbMF$r:n$k$?$a$KJB9T$7$F$$$/$D$+$N:n6H$r9T$&I,MW$,$"$k$N$G!$(B +$B%j%]%8%H%j$N%/%m!<%s$r9T$&!%(B +\interaction{daily.copy.clone} +$B:G=i$N%j%]%8%H%j$KLa$C$F!$(B\hgcmd{copy}$B%3%^%s%I$r;H$C$F!$:n@.$7$?%U%!%$%k(B +$B$N%3%T!<$r9T$&!%(B +\interaction{daily.copy.copy} + +%If we look at the output of the \hgcmd{status} command afterwards, the +%copied file looks just like a normal added file. +%\interaction{daily.copy.status} +%But if we pass the \hgopt{status}{-C} option to \hgcmd{status}, it +%prints another line of output: this is the file that our newly-added +%file was copied \emph{from}. +%\interaction{daily.copy.status-copy} + +$B$=$N8e$G(B\hgcmd{status}$B%3%^%s%I$N=PNO$r8+$k$H%3%T!<$5$l$?%U%!%$%k$ODL>oDL(B +$B$j$KDI2C$5$l$?%U%!%$%k$H$7$F8+$($k!%(B +\interaction{daily.copy.status} +$B$7$+$7(B\hgcmd{status}$B%3%^%s%I$K(B\hgopt{status}{-C}$B%*%W%7%g%s$rEO$9$H!$?7$?(B +$B$KDI2C$5$l$?%U%!%$%k$,(B\emph{$B$I$N(B}$B%U%!%$%k$+$i%3%T!<$5$l$?$N$+$r<($99T$,(B +$B=PNO$5$l$k!%(B +\interaction{daily.copy.status-copy} + +%Now, back in the repository we cloned, let's make a change in +%parallel. We'll add a line of content to the original file that we +%created. +%\interaction{daily.copy.other} +%Now we have a modified \filename{file} in this repository. When we +%pull the changes from the first repository, and merge the two heads, +%Mercurial will propagate the changes that we made locally to +%\filename{file} into its copy, \filename{new-file}. +%\interaction{daily.copy.merge} + +$B$3$3$G%/%m!<%s$7$?%j%]%8%H%j$K$bJQ99$r2C$($k!%:n@.$7$?%U%!%$%k$K0l9T$rDI(B +$B2C$9$k!%(B +\interaction{daily.copy.other} +$B$3$l$G$3$N%j%]%8%H%j$K$bJQ99$5$l$?(B\filename{file}$B$,B8:_$9$k$3$H$K$J(B +$B$k!%$3$3$G:G=i$N%j%]%8%H%j$+$iJQ99$r(Bpull$B$7!$(B2$B$D$N(Bhead$B$r%^!<%8$9$k$H(B +Mercurial$B$O%m!<%+%k$J(B\filename{file}$B$KBP$9$kJQ99$r$=$N%3%T!<(B +\filename{new-file}$B$KGH5Z$5$;$k!%(B +\interaction{daily.copy.merge} + +%\subsection{Why should changes follow copies?} +\subsection{$BJQ99$O$J$<%3%T!<$K=>$o$J$1$l$P$J$i$J$$$+(B} +\label{sec:daily:why-copy} + +%This behaviour, of changes to a file propagating out to copies of the +%file, might seem esoteric, but in most cases it's highly desirable. + +$B%U%!%$%k$X$NJQ99$,$=$N%3%T!<$XGH5Z$9$kF0:n$OFq2r$K;W$($k$+$b$7$J$$$,!$B?(B +$B$/$N>l9g$OHs>o$KK>$^$7$$F0:n$G$"$k!%(B + +%First of all, remember that this propagation \emph{only} happens when +%you merge. So if you \hgcmd{copy} a file, and subsequently modify the +%original file during the normal course of your work, nothing will +%happen. + +$B$^$:Bh0l$K$3$NGH5Z$O%^!<%8$r9T$&$H$-$K(B\emph{$B$N$_(B}$BH/@8$9$k!%=>$C$F%U%!%$%k(B +$B$r(B\hgcmd{copy}$B$9$k>l9g$d!$DL>o$N:n6H$G%*%j%8%J%k%U%!%$%k$rJQ99$9$k>l9g$O(B +$B2?$b5/$-$J$$!%(B + +%The second thing to know is thatmodifications will only propagate +%across a copy as long as the repository that you're pulling changes +%from \emph{doesn't know} about the copy. + +$BCN$C$F$*$/$Y$-E@$N(B2$B$DL\$O!$JQ99$r(Bpull$B$9$k%j%]%8%H%j$,!$%3%T!<$K$D$$$F(B +\emph{$B4XCN$7$J$$(B}$B8B$j!$JQ99$OGH5Z$9$k$H$$$&$3$H$G$"$k!%(B + +%The reason that Mercurial does this is as follows. Let's say I make +%an important bug fix in a source file, and commit my changes. +%Meanwhile, you've decided to \hgcmd{copy} the file in your repository, +%without knowing about the bug or having seen the fix, and you have +%started hacking on your copy of the file. + +Mercurial$B$,$3$N$h$&$KF0:n$9$kM}M3$r@bL@$9$k!%:#!$;d$,=EMW$J%P%0=$@5$r(B1$B$D(B +$B$N%=!<%9%U%!%$%k$K$D$$$F9T$$!$JQ99$r%3%_%C%H$7$?$H$9$k!%$=$N4V!$$"$J$?$O(B +$B<+J,$N%j%]%8%H%j$NCf$G!$$=$N%P%0$"$k$$$O=$@5$rCN$i$:!$$=$N%U%!%$%k$N(B +\hgcmd{copy}$B$r9T$$!$%U%!%$%k$NJQ99$r;O$a$?$H$9$k!%(B + +%If you pulled and merged my changes, and Mercurial \emph{didn't} +%propagate changes across copies, your source file would now contain +%the bug, and unless you remembered to propagate the bug fix by hand, +%the bug would \emph{remain} in your copy of the file. + +$B$"$J$?$,;d$N9T$C$?JQ99$r(Bpull$B$7!$(Bmerge$B$7$?>l9g!$(BMercurial$B$OJQ99$r%3%T!<4V(B +$B$GGH5Z$5$;$J$$!%$"$J$?$N%=!<%9%U%!%$%k:#%P%0$r;}$C$F$$$k$+$b$7$l$J$$$,!$(B +$B%P%0=$@5$r<j$GGH5Z$5$;$J$1$l$P%P%0$O%U%!%$%k$N%3%T!<$K(B\emph{$B;D$k(B}$B!%(B + +%By automatically propagating the change that fixed the bug from the +%original file to the copy, Mercurial prevents this class of problem. +%To my knowledge, Mercurial is the \emph{only} revision control system +%that propagates changes across copies like this. + +$B%P%0$r=$@5$9$kJQ99$r<+F0E*$K%*%j%8%J%k%U%!%$%k$+$i%3%T!<$XGH5Z$5$;$k$3$H(B +$B$K$h$C$F!$(BMercurial$B$O$3$NN`$NLdBj$rHr$1$F$$$k!%;d$NCN$k8B(B +$B$j!$(BMercurial$B$O!$$3$N$h$&$J%3%T!<4V$GJQ99$rGH5Z$5$;$kM#0l$N%j%S%8%g%s%3%s(B +$B%H%m!<%k%7%9%F%`$G$"$k!%(B + +%Once your change history has a record that the copy and subsequent +%merge occurred, there's usually no further need to propagate changes +%from the original file to the copied file, and that's why Mercurial +%only propagates changes across copies until this point, and no +%further. + +$B%3%T!<$H8eB3$N%^!<%8$,5/$3$C$?$3$H$,99?7MzNr$K4^$^$l$k>l9g!$JQ99$r%*%j%8(B +$B%J%k%U%!%$%k$+$i%3%T!<$5$l$?%U%!%$%k$X$5$i$KGH5Z$5$;$kI,MW$O$J$$!%$3$l$,(B +Mercurial$B$,$3$N;~E@$^$G$N$_JQ99$r%3%T!<4V$GGH5Z$5$;!$$=$N8e$G$O9T$o$J$$M}(B +$BM3$G$"$k!%(B + +%\subsection{How to make changes \emph{not} follow a copy} +\subsection{$BJQ99$,%3%T!<$K=>$o$J$$$h$&$K$9$kJ}K!(B} + +%If, for some reason, you decide that this business of automatically +%propagating changes across copies is not for you, simply use your +%system's normal file copy command (on Unix-like systems, that's +%\command{cp}) to make a copy of a file, then \hgcmd{add} the new copy +%by hand. Before you do so, though, please do reread +%section~\ref{sec:daily:why-copy}, and make an informed decision that +%this behaviour is not appropriate to your specific case. + +$B2?$i$+$NM}M3$G$3$N$h$&$KJQ99$,<+F0E*$KGH5Z$9$k$d$jJ}$,9%$^$7$/$J$$$H;W$o(B +$B$l$k>l9g$O!$%7%9%F%`I8=`$N$"%U%!%$%k%3%T!<%3%^%s%I!J(BUNIX$B7O%7%9%F%`$G$O(B +\command{cp}$B!K$r;H$C$F%U%!%$%k$N%3%T!<$r9T$$!$(B\hgcmd{add}$B$G?7$7$$%3%T!<$r(B +$B<jF0$GDI2C$9$k$3$H$,$G$-$k!%$3$l$r<B:]$K9T$&A0(B +$B$K!$(B~\ref{sec:daily:why-copy}$B@a$r:FFI$7!$$3$N$d$jJ}$N>\:Y$rF'$^$($?>e$G!$(B +$B$"$J$?$N%1!<%9$KE,$7$F$$$k$+H=CG$7$F$[$7$$!%(B + +%\subsection{Behaviour of the \hgcmd{copy} command} +\subsection{\hgcmd{copy}$B%3%^%s%I$N5sF0(B} + +%When you use the \hgcmd{copy} command, Mercurial makes a copy of each +%source file as it currently stands in the working directory. This +%means that if you make some modifications to a file, then \hgcmd{copy} +%it without first having committed those changes, the new copy will +%also contain the modifications you have made up until that point. (I +%find this behaviour a little counterintuitive, which is why I mention +%it here.) + +\hgcmd{copy}$B%3%^%s%I$r;H$&;~!$(BMercurial$B$O%o!<%-%s%0%G%#%l%/%H%jFb$N%U%!%$(B +$B%k$r$=$N;~E@$N>uBV$G%3%T!<$9$k!%$9$J$o$A!$%U%!%$%k$K2?$i$+$NJQ99$r2C$(!$(B +$BJQ99$N%3%_%C%H$r$;$:$K(B\hgcmd{copy}$B$r9T$&$H!$?7$?$J%3%T!<$b$=$N;~E@$^$G$K(B +$B2C$($?JQ99$r4^$s$G$$$k!%(B $B!JI.<T$O$3$N5sF0$O$d$dD>4Q$KH?$9$k$H9M$($F$$$k$?(B +$B$a!$4:$($F$3$3$G8@5Z$7$?!%!K(B + +%The \hgcmd{copy} command acts similarly to the Unix \command{cp} +%command (you can use the \hgcmd{cp} alias if you prefer). The last +%argument is the \emph{destination}, and all prior arguments are +%\emph{sources}. If you pass it a single file as the source, and the +%destination does not exist, it creates a new file with that name. +%\interaction{daily.copy.simple} +%If the destination is a directory, Mercurial copies its sources into +%that directory. +%\interaction{daily.copy.dir-dest} +%Copying a directory is recursive, and preserves the directory +%structure of the source. +%\interaction{daily.copy.dir-src} +%If the source and destination are both directories, the source tree is +%recreated in the destination directory. +%\interaction{daily.copy.dir-src-dest} + +\hgcmd{copy}$B%3%^%s%I$O(BUnix$B$N(B\command{cp}$B$HF1MM$K?6Iq$&!%!J(B\hgcmd{cp}$B%(%$(B +$B%j%"%9$rDj5A$7$F;H$&$3$H$b2DG=$@!%!K0z?t$N:G8e$O(B\emph{$B%3%T!<@h(B}$B$G!$$=$l0J(B +$BA0$N0z?t$O(B\emph{$B%3%T!<85(B}$B$G$"$k!%%3%T!<85$H$7$FC10l$N%U%!%$%k$r;XDj$7!$%3(B +$B%T!<@h%U%!%$%k$,B8:_$7$J$$>l9g!$%3%^%s%I$O%3%T!<@h%U%!%$%k$r?75,$K:n@.$9(B +$B$k!%(B +\interaction{daily.copy.simple} +$B%3%T!<@h$,%G%#%l%/%H%j$N>l9g!$(BMercurial$B$O%3%T!<85$r%3%T!<@h%G%#%l%/%H%j(B +$B$NCf$K%3%T!<$9$k!%(B +\interaction{daily.copy.dir-dest} +$B%G%#%l%/%H%j$N%3%T!<$O:F5"E*$G!$%3%T!<85$N%G%#%l%/%H%j9=B$$rJ]$D!%(B +\interaction{daily.copy.dir-src} +$B%3%T!<85$H%3%T!<@h$,6&$K%G%#%l%/%H%j$N>l9g!$%3%T!<85$N%D%j!<9=B$$,%3%T!<(B +$B@h$N%G%#%l%/%H%j$NCf$K:F8=$5$l$k!%(B +\interaction{daily.copy.dir-src-dest} + +%As with the \hgcmd{rename} command, if you copy a file manually and +%then want Mercurial to know that you've copied the file, simply use +%the \hgopt{copy}{--after} option to \hgcmd{copy}. +%\interaction{daily.copy.after} + +\hgcmd{rename}$B%3%^%s%I$HF1MM$K!$%U%!%$%k$r<jF0$G%3%T!<$7$?8e$G!$(BMercurial$B$K(B +$BA`:n$rDLCN$7$?$$>l9g$O!$(B\hgcmd{copy}$B%3%^%s%I$K(B\hgopt{copy}{--after}$B%*%W(B +$B%7%g%s$rIU$1$l$P$h$$!%(B +\interaction{daily.copy.after} + +%\section{Renaming files} +\section{$B%U%!%$%k$N%j%M!<%`(B} + +%It's rather more common to need to rename a file than to make a copy +%of it. The reason I discussed the \hgcmd{copy} command before talking +%about renaming files is that Mercurial treats a rename in essentially +%the same way as a copy. Therefore, knowing what Mercurial does when +%you copy a file tells you what to expect when you rename a file. + +$B%U%!%$%k$r%j%M!<%`$9$k$3$H$O%U%!%$%k$N%3%T!<$h$j$b$h$/9T$o$l$k!%%U%!%$%k(B +$B$N%j%M!<%`$h$j$bA0$K(B\hgcmd{copy}$B$K$D$$$F=R$Y$?M}M3$O!$(B Mercurial$B$,K\<AE*(B +$B$K%j%M!<%`$r%3%T!<$HF1MM$K07$&$+$i$G$"$k!%=>$C$F!$%U%!%$%k$r%3%T!<$9$k;~(B +$B$K(BMercurial$B$,9T$&$3$H$rCN$k$3$H$O!$%j%M!<%`$N:]$K5/$3$k$3$H$rCN$k$3$H$K$J(B +$B$k!%(B + +%When you use the \hgcmd{rename} command, Mercurial makes a copy of +%each source file, then deletes it and marks the file as removed. +%\interaction{daily.rename.rename} +%The \hgcmd{status} command shows the newly copied file as added, and +%the copied-from file as removed. +%\interaction{daily.rename.status} + +\hgcmd{rename}$B%3%^%s%I$r;H$&;~!$(BMercurial$B$O3F!9$N%=!<%9%U%!%$%k$r%3%T!<(B +$B$7!$85$N%U%!%$%k$r:o=|$7$F!$>C5n:Q$_$H%^!<%/$9$k!%(B +\interaction{daily.rename.rename} +\hgcmd{status}$B%3%^%s%I$O?7$?$K%3%T!<$5$l$?%U%!%$%k$rDI2C$5$l$?%U%!%$%k$H(B +$B$7$FI=<($7!$%3%T!<$5$l$?%U%!%$%k$r>C5n$5$l$?%U%!%$%k$HI=<($9$k!%(B +\interaction{daily.rename.status} + +%As with the results of a \hgcmd{copy}, we must use the +%\hgopt{status}{-C} option to \hgcmd{status} to see that the added file +%is really being tracked by Mercurial as a copy of the original, now +%removed, file. +%\interaction{daily.rename.status-copy} + +\hgcmd{copy}$B%3%^%s%I$N>l9g$HF1MM$K!$(B \hgcmd{status}$B%3%^%s%I$K(B +\hgopt{status}{-C}$B%*%W%7%g%s$rMQ$$$F!$DI2C$5$l$?%U%!%$%k$,>C5n$5$l$?%*%j(B +$B%8%J%k%U%!%$%k$N%3%T!<$H$7$F(BMercurial$B$KDI@W$5$l$F$$$k$N$+$rD4$Y$k$3$H$,$G(B +$B$-$k!%(B +\interaction{daily.rename.status-copy} + +%As with \hgcmd{remove} and \hgcmd{copy}, you can tell Mercurial about +%a rename after the fact using the \hgopt{rename}{--after} option. In +%most other respects, the behaviour of the \hgcmd{rename} command, and +%the options it accepts, are similar to the \hgcmd{copy} command. + +\hgcmd{remove}$B$H(B\hgcmd{copy}$B$N$h$&$K!$(B\hgopt{rename}{--after}$B%*%W%7%g%s$r(B +$B;H$&$3$H$G!$;v8e$K%j%M!<%`$r$9$k$3$H$,$G$-$k!%B?$/$NE@$G(B\hgcmd{rename}$B%3(B +$B%^%s%I$N5sF0$H!$$3$N%3%^%s%I$,<u$1F~$l$k%*%W%7%g%s$O(B\hgcmd{copy}$B%3%^%s%I(B +$B$HN`;w$7$F$$$k!%(B + +%\subsection{Renaming files and merging changes} +\subsection{$B%U%!%$%k$N%j%M!<%`$HJQ99$N%^!<%8(B} + +%Since Mercurial's rename is implemented as copy-and-remove, the same +%propagation of changes happens when you merge after a rename as after +%a copy. + +Mercurial$B$N%j%M!<%`$O%3%T!<$H:o=|$H$7$F<BAu$5$l$F$*$j!$%j%M!<%`8e$K%^!<(B +$B%8$r9T$&$N$H!$%3%T!<8e$K%^!<%8$r9T$&$N$G$OF1$8JQ99$NGH5Z$,5/$-$k!%(B + +%If I modify a file, and you rename it to a new name, and then we merge +%our respective changes, my modifications to the file under its +%original name will be propagated into the file under its new name. +%(This is something you might expect to ``simply work,'' but not all +%revision control systems actually do this.) + +$B;d$,%U%!%$%k$rJQ99$7!$$"$J$?$,$=$N%U%!%$%k$r$r?7$7$$L>A0$K%j%M!<%`$7$?>l(B +$B9g!$2f!9$,$*8_$$$NJQ99$r%^!<%8$9$k$H85$N%U%!%$%kL>$KBP$9$k;d$NJQ99$O!$?7(B +$B$7$$%U%!%$%kL>$N%U%!%$%k$KGH5Z$9$k!%(B $B!J$3$l$,$G$-$k$N$OEv$?$jA0$H;W$&$+$b(B +$B$7$l$J$$$,!$<B$N$H$3$m!$A4$F$N%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$,$G$-$k$o$1(B +$B$G$O$J$$!%!K(B + +%Whereas having changes follow a copy is a feature where you can +%perhaps nod and say ``yes, that might be useful,'' it should be clear +%that having them follow a rename is definitely important. Without +%this facility, it would simply be too easy for changes to become +%orphaned when files are renamed. + +$BJQ99$,%3%T!<$K=>$&5!G=$,M-MQ$G$"$k$3$H$O!$$*$=$i$/MF0W$KF10U$,F@$i$l$k$H(B +$B$3$m$G$"$k$H;W$o$l$k!%$H$j$o$1%j%M!<%`$KDI=>$9$k5!G=$O$-$o$a$F=EMW$G$"$k(B +$B$3$H$OL@Gr$G$"$k!%$b$7$3$N5!G=$,$J$1$l$P!$%U%!%$%k$N%j%M!<%`$K$h$C$FJQ99(B +$B$OMF0W$/9T$->l$r<:$C$F$7$^$&$@$m$&!%(B + +%\subsection{Divergent renames and merging} +\subsection{$BL>A0$H%^!<%8$NH/;6(B} + +%The case of diverging names occurs when two developers start with a +%file---let's call it \filename{foo}---in their respective +%repositories. + +2$B?M$N3+H/<T$N%j%]%8%H%j4V$G(B1$B$D$N%U%!%$%k(B ---\filename{foo}$B$H8F$V$3$H$K$9(B +$B$k(B--- $B$K$D$$$FL>A0$NH/;6$,5/$3$C$?>l9g$K$D$$$F9M$($F$_$h$&!%(B + +\interaction{rename.divergent.clone} +%Anne renames the file to \filename{bar}. +$B%"%s$O%U%!%$%k$r(B\filename{bar}$B$H2~L>$7$?!%(B +\interaction{rename.divergent.rename.anne} +%Meanwhile, Bob renames it to \filename{quux}. +$B$=$N4V!$%\%V$OF1$8%U%!%$%k$r(B\filename{quux}$B$H2~L>$7$?!%(B +\interaction{rename.divergent.rename.bob} + +%I like to think of this as a conflict because each developer has +%expressed different intentions about what the file ought to be named. + +$B3F!9$N3+H/<T$O%U%!%$%k$,$I$N$h$&$K8F$P$l$k$Y$-$+$K$D$$$F0[$J$C$?0U?^$r;}$C(B +$B$F$*$j!$$3$l$O%3%s%U%j%/%H$H9M$($i$l$k!%(B + +%What do you think should happen when they merge their work? +%Mercurial's actual behaviour is that it always preserves \emph{both} +%names when it merges changesets that contain divergent renames. +%\interaction{rename.divergent.merge} + +$BH`$i$,%^!<%8$r9T$C$?:]$K$I$&$J$l$P$h$$$@$m$&$+!)(B Mercurial$B$N<B:]$N5sF0(B +$B$O!$H/;6$7$?%j%M!<%`$,$"$k%A%'%s%8%;%C%H$r%^!<%8$7$?>l9g$O>o$K(B\emph{$BN>J}(B}$B$N(B +$BL>A0$rJ]B8$9$k!%(B +\interaction{rename.divergent.merge} + +%Notice that Mercurial does warn about the divergent renames, but it +%leaves it up to you to do something about the divergence after the merge. + +Mercurial$B$OL>A0$NH/;6$K$D$$$F7Y9p$9$k$,!$%^!<%88e$bL>A0$NH/;6$N2r7h$O%f!<(B +$B%6$KG$$;$kE@$KCm0U!%(B + +%\subsection{Convergent renames and merging} +\subsection{$B%j%M!<%`$H%^!<%8$K$h$k<}B+(B} + +%Another kind of rename conflict occurs when two people choose to +%rename different \emph{source} files to the same \emph{destination}. +%In this case, Mercurial runs its normal merge machinery, and lets you +%guide it to a suitable resolution. + +2$B?M$N%f!<%6$,0[$J$k(B\emph{$B%=!<%9(B}$B%U%!%$%k72$rF10l$N(B\emph{$BL\E*(B}$B%U%!%$%k$K%j(B +$B%M!<%`$9$k$H>WFM$,5/$-$k!%$3$N>l9g!$(BMercurial$B$ODL>o$N%^!<%85!9=$r5/F0$7!$(B +$B%f!<%6$KE,@Z$J2r7h$rB%$9!%(B + +%\subsection{Other name-related corner cases} +\subsection{$BL>A0$K4XO"$7$?$$$/$D$+$NLdBj(B} + +%Mercurial has a longstanding bug in which it fails to handle a merge +%where one side has a file with a given name, while another has a +%directory with the same name. This is documented as~\bug{29} . +%\interaction{issue29.go} + +Mercurial$B$K$O!$0lJ}$rL>A0$rM?$($?%U%!%$%k!$$b$&0lJ}$rF1L>$N%G%#%l%/%H%j$H(B +$B$7$F%^!<%8$r9T$&$H<:GT$9$k%P%0$,0JA0$+$i$"$k!%$3$l$O(B~\bug{29}$B$H$7$F%I%-%e(B +$B%a%s%H2=$5$l$F$$$k!%(B +\interaction{issue29.go} + +%\section{Recovering from mistakes} +\section{$B%_%9$+$i$N2sI|(B} + +%Mercurial has some useful commands that will help you to recover from +%some common mistakes. + +Mercurial$B$K$O0lHLE*$J%_%9$+$i$N2sI|$r=u$1$k$$$/$D$+$NM-MQ$J%3%^%s%I$,$"$k!%(B + +%The \hgcmd{revert} command lets you undo changes that you have made to +%your working directory. For example, if you \hgcmd{add} a file by +%accident, just run \hgcmd{revert} with the name of the file you added, +%and while the file won't be touched in any way, it won't be tracked +%for adding by Mercurial any longer, either. You can also use +%\hgcmd{revert} to get rid of erroneous changes to a file. + +\hgcmd{revert}$B%3%^%s%I$O%o!<%-%s%0%G%#%l%/%H%jFb$G9T$C$?JQ99$r<h$j>C$9!%(B +$B$?$H$($P!$8m$C$F(B\hgcmd{add}$B$r9T$C$?>l9g!$DI2C$7$?%U%!%$%kL>$H6&$K(B +\hgcmd{revert}$B$r<B9T$9$l$P%U%!%$%k$O2?$bJQ99$5$l$:!$(BMercurial$B$N4IM}$+$i30(B +$B$5$l$k!%$^$?(B\hgcmd{revert}$B$O%U%!%$%k$X$N4V0c$C$?JQ99$r>C5n$9$k$N$b;H$($k!%(B + +%It's useful to remember that the \hgcmd{revert} command is useful for +%changes that you have not yet committed. Once you've committed a +%change, if you decide it was a mistake, you can still do something +%about it, though your options may be more limited. + +\hgcmd{revert}$B%3%^%s%I$OL$%3%_%C%H$NJQ99$KBP$7$FM-8z$G$"$k$3$H$r3P$($F$*(B +$B$/$HNI$$!%JQ99$r%3%_%C%H$7$?$"$H$G!$$3$l$,4V0c$$$G$"$C$?$3$H$K5$$E$$$?>l(B +$B9g$O!$$H$l$k<jCJ$O$d$d8B$i$l$k!%(B + +%For more information about the \hgcmd{revert} command, and details +%about how to deal with changes you have already committed, see +%chapter~\ref{chap:undo}. + +\hgcmd{revert}$B%3%^%s%I$K$D$$$F$N$h$j>\:Y$J>pJs$H!$$9$G$K%3%_%C%H$7$?JQ99(B +$B$X$NA`:n$K$D$$$F$O(B~\ref{chap:undo}$B$N>O$r;2>H$5$l$?$$!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,83 @@ +#!/bin/bash + +# We have to fake the merges here, because they cause conflicts with +# three-way command-line merge, and kdiff3 may not be available. + +export HGMERGE=$(mktemp) +echo '#!/bin/sh' >> $HGMERGE +echo 'echo first change > "$1"' >> $HGMERGE +echo 'echo third change >> "$1"' >> $HGMERGE +chmod 700 $HGMERGE + +#$ name: init + +hg init myrepo +cd myrepo +echo first change >> myfile +hg add myfile +hg commit -m 'first change' +echo second change >> myfile +hg commit -m 'second change' + +#$ name: simple + +hg backout -m 'back out second change' tip +cat myfile + +#$ name: simple.log +#$ ignore: \s+200[78]-.* + +hg log --style compact + +#$ name: non-tip.clone + +cd .. +hg clone -r1 myrepo non-tip-repo +cd non-tip-repo + +#$ name: non-tip.backout + +echo third change >> myfile +hg commit -m 'third change' +hg backout --merge -m 'back out second change' 1 + +#$ name: non-tip.cat +cat myfile + +#$ name: manual.clone + +cd .. +hg clone -r1 myrepo newrepo +cd newrepo + +#$ name: manual.backout + +echo third change >> myfile +hg commit -m 'third change' +hg backout -m 'back out second change' 1 + +#$ name: manual.log + +hg log --style compact + +#$ name: manual.parents + +hg parents + +#$ name: manual.heads + +hg heads + +#$ name: manual.cat + +cat myfile + +#$ name: manual.merge + +hg merge +hg commit -m 'merged backout with previous tip' +cat myfile + +#$ name: + +rm $HGMERGE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{hg init myrepo} +$ \textbf{cd myrepo} +$ \textbf{echo first change >> myfile} +$ \textbf{hg add myfile} +$ \textbf{hg commit -m 'first change'} +$ \textbf{echo second change >> myfile} +$ \textbf{hg commit -m 'second change'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.manual.backout.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{echo third change >> myfile} +$ \textbf{hg commit -m 'third change'} +$ \textbf{hg backout -m 'back out second change' 1} +reverting myfile +changeset backs out changeset +the backout changeset is a new head - do not forget to merge +(use "backout --merge" if you want to auto-merge)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.manual.cat.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{cat myfile} +first change
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.manual.clone.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +$ \textbf{cd ..} +$ \textbf{hg clone -r1 myrepo newrepo} +requesting all changes +adding changesets +adding manifests +adding file changes +added 2 changesets with 2 changes to 1 files +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd newrepo}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.manual.heads.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{hg heads} +changeset: +tag: tip +parent: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: back out second change + +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: third change +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.manual.log.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{hg log --style compact} +3[tip]:1 + back out second change + +2 + third change + +1 + second change + +0 + first change +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.manual.merge.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg merge} +merging myfile +0 files updated, 1 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +$ \textbf{hg commit -m 'merged backout with previous tip'} +$ \textbf{cat myfile} +first change +third change
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.manual.parents.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg parents} +changeset: +tag: tip +parent: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: back out second change +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.non-tip.backout.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +$ \textbf{echo third change >> myfile} +$ \textbf{hg commit -m 'third change'} +$ \textbf{hg backout --merge -m 'back out second change' 1} +reverting myfile +changeset backs out changeset +merging with changeset +merging myfile +0 files updated, 1 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.non-tip.cat.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cat myfile} +first change +third change
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.non-tip.clone.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +$ \textbf{cd ..} +$ \textbf{hg clone -r1 myrepo non-tip-repo} +requesting all changes +adding changesets +adding manifests +adding file changes +added 2 changesets with 2 changes to 1 files +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd non-tip-repo}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.simple.log.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{hg log --style compact} +2[tip] + back out second change + +1 + second change + +0 + first change +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/backout.simple.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{hg backout -m 'back out second change' tip} +reverting myfile +changeset backs out changeset +$ \textbf{cat myfile} +first change
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,92 @@ +#!/bin/bash + +if hg -v | head -1 | grep -e "version 0.*" +then +#On mercurial 1.0 and later bisect is a builtin +echo '[extensions]' >> $HGRC +echo 'hbisect =' >> $HGRC +fi + +# XXX There's some kind of horrible nondeterminism in the execution of +# bisect at the moment. Ugh. + +#$ ignore: .* + +#$ name: init + +hg init mybug +cd mybug + +#$ name: commits + +buggy_change=22 + +for (( i = 0; i < 35; i++ )); do + if [[ $i = $buggy_change ]]; then + echo 'i have a gub' > myfile$i + hg commit -q -A -m 'buggy changeset' + else + echo 'nothing to see here, move along' > myfile$i + hg commit -q -A -m 'normal changeset' + fi +done + +#$ name: help + +hg help bisect + +#$ name: search.init + +hg bisect init + +#$ name: search.bad-init + +hg bisect bad + +#$ name: search.good-init + +hg bisect good 10 + +#$ name: search.step1 + +if grep -q 'i have a gub' * +then + result=bad +else + result=good +fi + +echo this revision is $result +hg bisect --$result + +#$ name: search.mytest + +mytest() { + if grep -q 'i have a gub' * + then + result=bad + else + result=good + fi + + echo this revision is $result + hg bisect $result +} + +#$ name: search.step2 + +mytest + +#$ name: search.rest + +mytest +mytest +mytest + +#$ name: search.reset + +hg bisect reset + +#$ name: + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.commits.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.help.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.search.bad-init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.search.good-init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.search.init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.search.mytest.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.search.reset.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.search.rest.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.search.step1.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,12 @@ + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/bisect.search.step2.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,73 @@ +#!/bin/bash + +hg init a +cd a +echo hello > myfile +hg commit -A -m 'Initial commit' + +#$ name: branches + +hg tip +hg branches + +#$ name: branch + +hg branch + +#$ name: create + +hg branch foo +hg branch + +#$ name: status + +hg status +hg tip + +#$ name: commit + +echo 'hello again' >> myfile +hg commit -m 'Second commit' +hg tip + +#$ name: rebranch + +hg branch +hg branch bar +echo new file > newfile +hg commit -A -m 'Third commit' +hg tip + +#$ name: parents + +hg parents +hg branches + +#$ name: update-switchy + +hg update foo +hg parents +hg update bar +hg parents + +#$ name: update-nothing + +hg update foo +hg update + +#$ name: foo-commit + +echo something > somefile +hg commit -A -m 'New file' +hg heads + +#$ name: update-bar + +hg update bar + +#$ name: merge + +hg branch +hg merge foo +hg commit -m 'Merge' +hg tip
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.branch.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg branch} +default
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.branches.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +$ \textbf{hg tip} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Initial commit + +$ \textbf{hg branches} +default
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.commit.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{echo 'hello again' >> myfile} +$ \textbf{hg commit -m 'Second commit'} +$ \textbf{hg tip} +changeset: +branch: foo +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Second commit +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.create.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg branch foo} +marked working directory as branch foo +$ \textbf{hg branch} +foo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.foo-commit.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,18 @@ +$ \textbf{echo something > somefile} +$ \textbf{hg commit -A -m 'New file'} +adding somefile +$ \textbf{hg heads} +changeset: +branch: foo +tag: tip +parent: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: New file + +changeset: +branch: bar +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Third commit +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.merge.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,16 @@ +$ \textbf{hg branch} +bar +$ \textbf{hg merge} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +$ \textbf{hg commit -m 'Merge'} +$ \textbf{hg tip} +changeset: +branch: bar +tag: tip +parent: +parent: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Merge +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.parents.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,12 @@ +$ \textbf{hg parents} +changeset: +branch: bar +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Third commit + +$ \textbf{hg branches} +bar +foo (inactive) +default (inactive)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.rebranch.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,15 @@ +$ \textbf{hg branch} +foo +$ \textbf{hg branch bar} +marked working directory as branch bar +$ \textbf{echo new file > newfile} +$ \textbf{hg commit -A -m 'Third commit'} +adding newfile +$ \textbf{hg tip} +changeset: +branch: bar +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Third commit +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.status.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg status} +$ \textbf{hg tip} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Initial commit +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.update-bar.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg update bar} +abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes +$ \textbf{hg update -C bar} +1 files updated, 0 files merged, 1 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.update-foo.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{hg update foo} +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +$ \textbf{hg update} +0 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{hg parents} +changeset: +branch: foo +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Second commit + +$ \textbf{hg update bar} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.update-nothing.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg update foo} +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +$ \textbf{hg update} +0 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.update-switchy.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,19 @@ +$ \textbf{hg update foo} +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +$ \textbf{hg parents} +changeset: +branch: foo +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Second commit + +$ \textbf{hg update bar} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{hg parents} +changeset: +branch: bar +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Third commit +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-named.update.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{hg update foo} +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +$ \textbf{hg update} +0 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{hg parent} +changeset: +branch: foo +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Second commit + +$ \textbf{hg update bar} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-repo Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,48 @@ +#!/bin/bash + +hg init myproject +cd myproject +echo hello > myfile +hg commit -A -m 'Initial commit' +cd .. + +#$ name: tag + +cd myproject +hg tag v1.0 + +#$ name: clone + +cd .. +hg clone myproject myproject-1.0.1 + +#$ name: bugfix + +hg clone myproject-1.0.1 my-1.0.1-bugfix +cd my-1.0.1-bugfix +echo 'I fixed a bug using only echo!' >> myfile +hg commit -m 'Important fix for 1.0.1' +#$ ignore: /tmp/branch-repo.* +hg push + +#$ name: new + +cd .. +hg clone myproject my-feature +cd my-feature +echo 'This sure is an exciting new feature!' > mynewfile +hg commit -A -m 'New feature' +hg push + +#$ name: pull + +cd .. +hg clone myproject myproject-merge +cd myproject-merge +hg pull ../myproject-1.0.1 + +#$ name: merge + +hg merge +hg commit -m 'Merge bugfix from 1.0.1 branch' +hg push
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-repo.bugfix.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,12 @@ +$ \textbf{hg clone myproject-1.0.1 my-1.0.1-bugfix} +2 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd my-1.0.1-bugfix} +$ \textbf{echo 'I fixed a bug using only echo!' >> myfile} +$ \textbf{hg commit -m 'Important fix for 1.0.1'} +$ \textbf{hg push} +pushing to /tmp/branch-repo4rF-PL/myproject-1.0.1 +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-repo.clone.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cd ..} +$ \textbf{hg clone myproject myproject-1.0.1} +2 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-repo.merge.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,11 @@ +$ \textbf{hg merge} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +$ \textbf{hg commit -m 'Merge bugfix from 1.0.1 branch'} +$ \textbf{hg push} +pushing to +searching for changes +adding changesets +adding manifests +adding file changes +added 2 changesets with 1 changes to 1 files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-repo.new.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,14 @@ +$ \textbf{cd ..} +$ \textbf{hg clone myproject my-feature} +2 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd my-feature} +$ \textbf{echo 'This sure is an exciting new feature!' > mynewfile} +$ \textbf{hg commit -A -m 'New feature'} +adding mynewfile +$ \textbf{hg push} +pushing to +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-repo.pull.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,12 @@ +$ \textbf{cd ..} +$ \textbf{hg clone myproject myproject-merge} +3 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd myproject-merge} +$ \textbf{hg pull ../myproject-1.0.1} +pulling from ../myproject-1.0.1 +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files (+1 heads) +(run 'hg heads' to see heads, 'hg merge' to merge)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branch-repo.tag.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{cd myproject} +$ \textbf{hg tag v1.0}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branching Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,63 @@ +#!/bin/bash + +#$ name: init + +hg init main +cd main +echo 'This is a boring feature.' > myfile +hg commit -A -m 'We have reached an important milestone!' + +#$ name: tag + +hg tag v1.0 +hg tip +hg tags + +#$ name: main + +cd ../main +echo 'This is exciting and new!' >> myfile +hg commit -m 'Add a new feature' +cat myfile + +#$ name: update + +cd .. +hg clone -U main main-old +cd main-old +hg update v1.0 +cat myfile + +#$ name: clone + +cd .. +hg clone -rv1.0 main stable + +#$ name: stable + +hg clone stable stable-fix +cd stable-fix +echo 'This is a fix to a boring feature.' > myfile +hg commit -m 'Fix a bug' +#$ ignore: /tmp/branching.* +hg push + +#$ name: + +export HGMERGE=$(mktemp) +echo '#!/bin/sh' > $HGMERGE +echo 'echo "This is a fix to a boring feature." > "$1"' >> $HGMERGE +echo 'echo "This is exciting and new!" >> "$1"' >> $HGMERGE +chmod 700 $HGMERGE + +#$ name: merge + +cd ../main +hg pull ../stable +hg merge +hg commit -m 'Bring in bugfix from stable branch' +cat myfile + +#$ name: + +rm $HGMERGE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branching.clone.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{cd ..} +$ \textbf{hg clone -rv1.0 main stable} +requesting all changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branching.init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{hg init main} +$ \textbf{cd main} +$ \textbf{echo 'This is a boring feature.' > myfile} +$ \textbf{hg commit -A -m 'We have reached an important milestone!'} +adding myfile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branching.main.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ +$ \textbf{cd ../main} +$ \textbf{echo 'This is exciting and new!' >> myfile} +$ \textbf{hg commit -m 'Add a new feature'} +$ \textbf{cat myfile} +This is a boring feature. +This is exciting and new!
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branching.merge.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,17 @@ +$ \textbf{cd ../main} +$ \textbf{hg pull ../stable} +pulling from ../stable +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files (+1 heads) +(run 'hg heads' to see heads, 'hg merge' to merge) +$ \textbf{hg merge} +merging myfile +0 files updated, 1 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +$ \textbf{hg commit -m 'Bring in bugfix from stable branch'} +$ \textbf{cat myfile} +This is a fix to a boring feature. +This is exciting and new!
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branching.stable.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,12 @@ +$ \textbf{hg clone stable stable-fix} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd stable-fix} +$ \textbf{echo 'This is a fix to a boring feature.' > myfile} +$ \textbf{hg commit -m 'Fix a bug'} +$ \textbf{hg push} +pushing to /tmp/branchingfJgZac/stable +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branching.tag.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,11 @@ +$ \textbf{hg tag v1.0} +$ \textbf{hg tip} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added tag v1.0 for changeset + +$ \textbf{hg tags} +tip +v1.0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/branching.update.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{cd ..} +$ \textbf{hg clone -U main main-old} +$ \textbf{cd main-old} +$ \textbf{hg update v1.0} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cat myfile} +This is a boring feature.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/cmdref Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,22 @@ +#!/bin/bash + +hg init diff +cd diff +cat > myfile.c <<EOF +int myfunc() +{ + return 1; +} +EOF +hg ci -Ama + +sed -ie 's/return 1/return 10/' myfile.c + +#$ name: diff-p + +echo '[diff]' >> $HGRC +echo 'showfunc = False' >> $HGRC + +hg diff + +hg diff -p
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/cmdref.diff-p.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,22 @@ +$ \textbf{echo '[diff]' >> $HGRC} +$ \textbf{echo 'showfunc = False' >> $HGRC} +$ \textbf{hg diff} +diff -r myfile.c + + +@@ -1,4 +1,4 @@ + int myfunc() + \{ +- return 1; ++ return 10; + \} +$ \textbf{hg diff -p} +diff -r myfile.c + + +@@ -1,4 +1,4 @@ int myfunc() + int myfunc() + \{ +- return 1; ++ return 10; + \}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,82 @@ +#!/bin/bash + +#$ name: init + +hg init my-copy +cd my-copy +echo line > file +hg add file +hg commit -m 'Added a file' + +#$ name: clone + +cd .. +hg clone my-copy your-copy + +#$ name: copy + +cd my-copy +hg copy file new-file + +#$ name: status + +hg status + +#$ name: status-copy + +hg status -C +hg commit -m 'Copied file' + +#$ name: other + +cd ../your-copy +echo 'new contents' >> file +hg commit -m 'Changed file' + +#$ name: cat + +cat file +cat ../my-copy/new-file + +#$ name: merge + +hg pull ../my-copy +hg merge +cat new-file + +#$ name: + +cd .. +hg init copy-example +cd copy-example +echo a > a +echo b > b +mkdir c +mkdir c/a +echo c > c/a/c +hg ci -Ama + +#$ name: simple + +mkdir k +hg copy a k +ls k + +#$ name: dir-dest + +mkdir d +hg copy a b d +ls d + +#$ name: dir-src + +hg copy c e + +#$ name: dir-src-dest + +hg copy c d + +#$ name: after + +cp a z +hg copy --after a z
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.after.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{cp a z} +$ \textbf{hg copy --after a z}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.cat.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{cat file} +line +new contents +$ \textbf{cat ../my-copy/new-file} +line
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.clone.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cd ..} +$ \textbf{hg clone my-copy your-copy} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.copy.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{cd my-copy} +$ \textbf{hg copy file new-file}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.dir-dest.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{mkdir d} +$ \textbf{hg copy a b d} +$ \textbf{ls d} +a b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.dir-src-dest.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg copy c d} +copying c/a/c to d/c/a/c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.dir-src.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg copy c e} +copying c/a/c to e/a/c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{hg init my-copy} +$ \textbf{cd my-copy} +$ \textbf{echo line > file} +$ \textbf{hg add file} +$ \textbf{hg commit -m 'Added a file'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.merge.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,15 @@ +$ \textbf{hg pull ../my-copy} +pulling from ../my-copy +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files (+1 heads) +(run 'hg heads' to see heads, 'hg merge' to merge) +$ \textbf{hg merge} +merging file and new-file +0 files updated, 1 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +$ \textbf{cat new-file} +line +new contents
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.other.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cd ../your-copy} +$ \textbf{echo 'new contents' >> file} +$ \textbf{hg commit -m 'Changed file'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.simple.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{mkdir k} +$ \textbf{hg copy a k} +$ \textbf{ls k} +a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.status-copy.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg status -C} +A new-file + file +$ \textbf{hg commit -m 'Copied file'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.copy.status.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg status} +A new-file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,93 @@ +#!/bin/bash + +#$ name: add + +hg init add-example +cd add-example +echo a > myfile.txt +hg status +hg add myfile.txt +hg status +hg commit -m 'Added one file' +hg status + +#$ name: add-dir + +mkdir b +echo b > b/somefile.txt +echo c > b/source.cpp +mkdir b/d +echo d > b/d/test.h +hg add b +hg commit -m 'Added all files in subdirectory' + +#$ name: + +cd .. + +#$ name: hidden + +hg init hidden-example +cd hidden-example +mkdir empty +touch empty/.hidden +hg add empty/.hidden +hg commit -m 'Manage an empty-looking directory' +ls empty +cd .. +hg clone hidden-example tmp +ls tmp +ls tmp/empty + +#$ name: remove + +hg init remove-example +cd remove-example +echo a > a +mkdir b +echo b > b/b +hg add a b +hg commit -m 'Small example for file removal' +hg remove a +hg status +hg remove b + +#$ name: + +cd .. + +#$ name: missing +hg init missing-example +cd missing-example +echo a > a +hg add a +hg commit -m 'File about to be missing' +rm a +hg status + +#$ name: remove-after + +hg remove --after a +hg status + +#$ name: recover-missing +hg revert a +cat a +hg status + +#$ name: + +cd .. + +#$ name: addremove + +hg init addremove-example +cd addremove-example +echo a > a +echo b > b +hg addremove + +#$ name: commit-addremove + +echo c > c +hg commit -A -m 'Commit with addremove'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files.add-dir.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{mkdir b} +$ \textbf{echo b > b/b} +$ \textbf{echo c > b/c} +$ \textbf{mkdir b/d} +$ \textbf{echo d > b/d/d} +$ \textbf{hg add b} +adding b/b +adding b/c +adding b/d/d +$ \textbf{hg commit -m 'Added all files in subdirectory'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files.add.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{hg init add-example} +$ \textbf{cd add-example} +$ \textbf{echo a > a} +$ \textbf{hg status} +? a +$ \textbf{hg add a} +$ \textbf{hg status} +A a +$ \textbf{hg commit -m 'Added one file'} +$ \textbf{hg status}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files.addremove.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{hg init addremove-example} +$ \textbf{cd addremove-example} +$ \textbf{echo a > a} +$ \textbf{echo b > b} +$ \textbf{hg addremove} +adding a +adding b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files.commit-addremove.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{echo c > c} +$ \textbf{hg commit -A -m 'Commit with addremove'} +adding c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files.hidden.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{hg init hidden-example} +$ \textbf{cd hidden-example} +$ \textbf{mkdir empty} +$ \textbf{touch empty/.hidden} +$ \textbf{hg add empty/.hidden} +$ \textbf{hg commit -m 'Manage an empty-looking directory'} +$ \textbf{ls empty} +$ \textbf{cd ..} +$ \textbf{hg clone hidden-example tmp} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{ls tmp} +empty +$ \textbf{ls tmp/empty}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files.missing.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg init missing-example} +$ \textbf{cd missing-example} +$ \textbf{echo a > a} +$ \textbf{hg add a} +$ \textbf{hg commit -m 'File about to be missing'} +$ \textbf{rm a} +$ \textbf{hg status} +! a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files.recover-missing.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg revert a} +$ \textbf{cat a} +a +$ \textbf{hg status}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files.remove-after.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{hg remove --after a} +$ \textbf{hg status} +R a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.files.remove.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{hg init remove-example} +$ \textbf{cd remove-example} +$ \textbf{echo a > a} +$ \textbf{mkdir b} +$ \textbf{echo b > b/b} +$ \textbf{hg add a b} +adding b/b +$ \textbf{hg commit -m 'Small example for file removal'} +$ \textbf{hg remove a} +$ \textbf{hg status} +R a +$ \textbf{hg remove b} +removing b/b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.rename Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,18 @@ +#!/bin/bash + +hg init a +cd a +echo a > a +hg ci -Ama + +#$ name: rename + +hg rename a b + +#$ name: status + +hg status + +#$ name: status-copy + +hg status -C
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.rename.rename.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1 @@ +$ \textbf{hg rename a b}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.rename.status-copy.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg status -C} +A b + a +R a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.rename.status.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{hg status} +A b +R a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,74 @@ +#!/bin/bash + +hg init a +cd a +echo 'original content' > file +hg ci -Ama + +#$ name: modify + +cat file +echo unwanted change >> file +hg diff file + +#$ name: unmodify + +hg status +hg revert file +cat file + +#$ name: status + +hg status +cat file.orig + +#$ name: + +rm file.orig + +#$ name: add + +echo oops > oops +hg add oops +hg status oops +hg revert oops +hg status + +#$ name: + +rm oops + +#$ name: remove + +hg remove file +hg status +hg revert file +hg status +ls file + +#$ name: missing + +rm file +hg status +hg revert file +ls file + +#$ name: copy + +hg copy file new-file +hg revert new-file +hg status + +#$ name: + +rm new-file + +#$ name: rename + +hg rename file new-file +hg revert new-file +hg status + +#$ name: rename-orig +hg revert file +hg status
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert.add.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{echo oops > oops} +$ \textbf{hg add oops} +$ \textbf{hg status oops} +A oops +$ \textbf{hg revert oops} +$ \textbf{hg status} +? oops
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert.copy.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg copy file new-file} +$ \textbf{hg revert new-file} +$ \textbf{hg status} +? new-file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert.missing.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ +$ \textbf{rm file} +$ \textbf{hg status} +! file +$ \textbf{hg revert file} +$ \textbf{ls file} +file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert.modify.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{cat file} +original content +$ \textbf{echo unwanted change >> file} +$ \textbf{hg diff file} +diff -r file + + +@@ -1,1 +1,2 @@ original content + original content ++unwanted change
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert.remove.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{hg remove file} +$ \textbf{hg status} +R file +$ \textbf{hg revert file} +$ \textbf{hg status} +$ \textbf{ls file} +file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert.rename-orig.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg revert file} +no changes needed to file +$ \textbf{hg status} +? new-file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert.rename.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg rename file new-file} +$ \textbf{hg revert new-file} +$ \textbf{hg status} +? new-file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert.status.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{hg status} +? file.orig +$ \textbf{cat file.orig} +original content +unwanted change
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/daily.revert.unmodify.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{hg status} +M file +$ \textbf{hg revert file} +$ \textbf{cat file} +original content
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/data/check_whitespace.py Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,44 @@ +#!/usr/bin/python + +import re + +def trailing_whitespace(difflines): + added, linenum, header = [], 0, False + + for line in difflines: + if header: + # remember the name of the file that this diff affects + m = re.match(r'(?:---|\+\+\+) ([^\t]+)', line) + if m and m.group(1) != '/dev/null': + filename = m.group(1).split('/', 1)[-1] + if line.startswith('+++ '): + header = False + continue + if line.startswith('diff '): + header = True + continue + # hunk header - save the line number + m = re.match(r'@@ -\d+,\d+ \+(\d+),', line) + if m: + linenum = int(m.group(1)) + continue + # hunk body - check for an added line with trailing whitespace + m = re.match(r'\+.*\s$', line) + if m: + added.append((filename, linenum)) + if line and line[0] in ' +': + linenum += 1 + return added + +if __name__ == '__main__': + import os, sys + + added = trailing_whitespace(os.popen('hg export tip')) + if added: + for filename, linenum in added: + print >> sys.stderr, ('%s, line %d: trailing whitespace added' % + (filename, linenum)) + # save the commit message so we don't need to retype it + os.system('hg tip --template "{desc}" > .hg/commit.save') + print >> sys.stderr, 'commit message saved to .hg/commit.save' + sys.exit(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/data/remove-redundant-null-checks.patch Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,190 @@ + +From: Jesper Juhl <jesper.juhl@gmail.com> + +Remove redundant NULL chck before kfree + tiny CodingStyle cleanup for +drivers/ + +Signed-off-by: Jesper Juhl <jesper.juhl@gmail.com> +Signed-off-by: Andrew Morton <akpm@osdl.org> +--- + + drivers/char/agp/sgi-agp.c | 5 ++--- + drivers/char/hvcs.c | 11 +++++------ + drivers/message/fusion/mptfc.c | 6 ++---- + drivers/message/fusion/mptsas.c | 3 +-- + drivers/net/fs_enet/fs_enet-mii.c | 3 +-- + drivers/net/wireless/ipw2200.c | 22 ++++++---------------- + drivers/scsi/libata-scsi.c | 4 +--- + drivers/video/au1100fb.c | 3 +-- + 8 files changed, 19 insertions(+), 38 deletions(-) + +diff -puN drivers/char/agp/sgi-agp.c~remove-redundant-null-checks-before-free-in-drivers drivers/char/agp/sgi-agp.c +--- a/drivers/char/agp/sgi-agp.c~remove-redundant-null-checks-before-free-in-drivers ++++ a/drivers/char/agp/sgi-agp.c +@@ -329,9 +329,8 @@ static int __devinit agp_sgi_init(void) + + static void __devexit agp_sgi_cleanup(void) + { +- if (sgi_tioca_agp_bridges) +- kfree(sgi_tioca_agp_bridges); +- sgi_tioca_agp_bridges=NULL; ++ kfree(sgi_tioca_agp_bridges); ++ sgi_tioca_agp_bridges = NULL; + } + + module_init(agp_sgi_init); +diff -puN drivers/char/hvcs.c~remove-redundant-null-checks-before-free-in-drivers drivers/char/hvcs.c +--- a/drivers/char/hvcs.c~remove-redundant-null-checks-before-free-in-drivers ++++ a/drivers/char/hvcs.c +@@ -1320,11 +1320,12 @@ static struct tty_operations hvcs_ops = + static int hvcs_alloc_index_list(int n) + { + int i; ++ + hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); + if (!hvcs_index_list) + return -ENOMEM; + hvcs_index_count = n; +- for(i = 0; i < hvcs_index_count; i++) ++ for (i = 0; i < hvcs_index_count; i++) + hvcs_index_list[i] = -1; + return 0; + } +@@ -1332,11 +1333,9 @@ static int hvcs_alloc_index_list(int n) + static void hvcs_free_index_list(void) + { + /* Paranoia check to be thorough. */ +- if (hvcs_index_list) { +- kfree(hvcs_index_list); +- hvcs_index_list = NULL; +- hvcs_index_count = 0; +- } ++ kfree(hvcs_index_list); ++ hvcs_index_list = NULL; ++ hvcs_index_count = 0; + } + + static int __init hvcs_module_init(void) +diff -puN drivers/message/fusion/mptfc.c~remove-redundant-null-checks-before-free-in-drivers drivers/message/fusion/mptfc.c +--- a/drivers/message/fusion/mptfc.c~remove-redundant-null-checks-before-free-in-drivers ++++ a/drivers/message/fusion/mptfc.c +@@ -305,10 +305,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, in + } + + out: +- if (pp0_array) +- kfree(pp0_array); +- if (p0_array) +- kfree(p0_array); ++ kfree(pp0_array); ++ kfree(p0_array); + return rc; + } + +diff -puN drivers/message/fusion/mptsas.c~remove-redundant-null-checks-before-free-in-drivers drivers/message/fusion/mptsas.c +--- a/drivers/message/fusion/mptsas.c~remove-redundant-null-checks-before-free-in-drivers ++++ a/drivers/message/fusion/mptsas.c +@@ -1378,8 +1378,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) + return 0; + + out_free_port_info: +- if (hba) +- kfree(hba); ++ kfree(hba); + out: + return error; + } +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 +--- a/drivers/net/fs_enet/fs_enet-mii.c~remove-redundant-null-checks-before-free-in-drivers ++++ a/drivers/net/fs_enet/fs_enet-mii.c +@@ -431,8 +431,7 @@ static struct fs_enet_mii_bus *create_bu + return bus; + + err: +- if (bus) +- kfree(bus); ++ kfree(bus); + return ERR_PTR(ret); + } + +diff -puN drivers/net/wireless/ipw2200.c~remove-redundant-null-checks-before-free-in-drivers drivers/net/wireless/ipw2200.c +--- a/drivers/net/wireless/ipw2200.c~remove-redundant-null-checks-before-free-in-drivers ++++ a/drivers/net/wireless/ipw2200.c +@@ -1229,12 +1229,6 @@ static struct ipw_fw_error *ipw_alloc_er + return error; + } + +-static void ipw_free_error_log(struct ipw_fw_error *error) +-{ +- if (error) +- kfree(error); +-} +- + static ssize_t show_event_log(struct device *d, + struct device_attribute *attr, char *buf) + { +@@ -1296,10 +1290,9 @@ static ssize_t clear_error(struct device + const char *buf, size_t count) + { + struct ipw_priv *priv = dev_get_drvdata(d); +- if (priv->error) { +- ipw_free_error_log(priv->error); +- priv->error = NULL; +- } ++ ++ kfree(priv->error); ++ priv->error = NULL; + return count; + } + +@@ -1970,8 +1963,7 @@ static void ipw_irq_tasklet(struct ipw_p + struct ipw_fw_error *error = + ipw_alloc_error_log(priv); + ipw_dump_error_log(priv, error); +- if (error) +- ipw_free_error_log(error); ++ kfree(error); + } + #endif + } else { +@@ -11693,10 +11685,8 @@ static void ipw_pci_remove(struct pci_de + } + } + +- if (priv->error) { +- ipw_free_error_log(priv->error); +- priv->error = NULL; +- } ++ kfree(priv->error); ++ priv->error = NULL; + + #ifdef CONFIG_IPW2200_PROMISCUOUS + ipw_prom_free(priv); +diff -puN drivers/scsi/libata-scsi.c~remove-redundant-null-checks-before-free-in-drivers drivers/scsi/libata-scsi.c +--- a/drivers/scsi/libata-scsi.c~remove-redundant-null-checks-before-free-in-drivers ++++ a/drivers/scsi/libata-scsi.c +@@ -222,9 +222,7 @@ int ata_cmd_ioctl(struct scsi_device *sc + && copy_to_user(arg + sizeof(args), argbuf, argsize)) + rc = -EFAULT; + error: +- if (argbuf) +- kfree(argbuf); +- ++ kfree(argbuf); + return rc; + } + +diff -puN drivers/video/au1100fb.c~remove-redundant-null-checks-before-free-in-drivers drivers/video/au1100fb.c +--- a/drivers/video/au1100fb.c~remove-redundant-null-checks-before-free-in-drivers ++++ a/drivers/video/au1100fb.c +@@ -743,8 +743,7 @@ void __exit au1100fb_cleanup(void) + { + driver_unregister(&au1100fb_driver); + +- if (drv_info.opt_mode) +- kfree(drv_info.opt_mode); ++ kfree(drv_info.opt_mode); + } + + module_init(au1100fb_init); +_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/extdiff Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,28 @@ +#!/bin/bash + +echo '[extensions]' >> $HGRC +echo 'extdiff =' >> $HGRC + +hg init a +cd a +echo 'The first line.' > myfile +hg ci -Ama +echo 'The second line.' >> myfile + +#$ name: diff + +hg diff + +#$ name: extdiff + +hg extdiff + +#$ name: extdiff-ctx + +#$ ignore: ^\*\*\* a.* + +hg extdiff -o -NprcC5 + +#$ name: + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/extdiff.diff.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{hg diff} +diff -r myfile + + +@@ -1,1 +1,2 @@ The first line. + The first line. ++The second line.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/extdiff.extdiff-ctx.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg extdiff -o -NprcC5} + + +*************** +*** 1 **** + + The first line. ++ The second line.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/extdiff.extdiff.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ +$ \textbf{hg extdiff} + + +@@ -1 +1,2 @@ + The first line. ++The second line.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,61 @@ +#!/bin/bash + +hg init a +cd a +mkdir -p examples src/watcher +touch COPYING MANIFEST.in README setup.py +touch examples/performant.py examples/simple.py +touch src/main.py src/watcher/_watcher.c src/watcher/watcher.py src/xyzzy.txt + +#$ name: files + +hg add COPYING README examples/simple.py + +#$ name: dirs + +hg status src + +#$ name: wdir-subdir + +cd src +hg add -n +hg add -n . + +#$ name: wdir-relname + +hg status +hg status `hg root` + +#$ name: glob.star + +hg add 'glob:*.py' + +#$ name: glob.starstar + +cd .. +hg status 'glob:**.py' + +#$ name: glob.star-starstar + +hg status 'glob:*.py' +hg status 'glob:**.py' + +#$ name: glob.question + +hg status 'glob:**.?' + +#$ name: glob.range + +hg status 'glob:**[nr-t]' + +#$ name: glob.group + +hg status 'glob:*.{in,py}' + +#$ name: filter.include + +hg status -I '*.in' + +#$ name: filter.exclude + +hg status -X '**.py' src
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.dirs.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{hg status src} +? src/main.py +? src/watcher/_watcher.c +? src/watcher/watcher.py +? src/xyzzy.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.files.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1 @@ +$ \textbf{hg add COPYING README examples/simple.py}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.filter.exclude.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{hg status -X '**.py' src} +? src/watcher/_watcher.c +? src/xyzzy.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.filter.include.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg status -I '*.in'} +? MANIFEST.in
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.glob.group.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{hg status 'glob:*.\{in,py\}'} +? MANIFEST.in +? setup.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.glob.question.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg status 'glob:**.?'} +? src/watcher/_watcher.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.glob.range.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{hg status 'glob:**[nr-t]'} +? MANIFEST.in +? src/xyzzy.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.glob.star-starstar.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg status 'glob:*.py'} +? setup.py +$ \textbf{hg status 'glob:**.py'} +A examples/simple.py +A src/main.py +? examples/performant.py +? setup.py +? src/watcher/watcher.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.glob.star.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg add 'glob:*.py'} +adding main.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.glob.starstar.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{cd ..} +$ \textbf{hg status 'glob:**.py'} +A examples/simple.py +A src/main.py +? examples/performant.py +? setup.py +? src/watcher/watcher.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.wdir-relname.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,22 @@ +$ \textbf{hg status} +A COPYING +A README +A examples/simple.py +? MANIFEST.in +? examples/performant.py +? setup.py +? src/main.py +? src/watcher/_watcher.c +? src/watcher/watcher.py +? src/xyzzy.txt +$ \textbf{hg status `hg root`} +A ../COPYING +A ../README +A ../examples/simple.py +? ../MANIFEST.in +? ../examples/performant.py +? ../setup.py +? main.py +? watcher/_watcher.c +? watcher/watcher.py +? xyzzy.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/filenames.wdir-subdir.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,14 @@ +$ \textbf{cd src} +$ \textbf{hg add -n} +adding ../MANIFEST.in +adding ../examples/performant.py +adding ../setup.py +adding main.py +adding watcher/_watcher.c +adding watcher/watcher.py +adding xyzzy.txt +$ \textbf{hg add -n .} +adding main.py +adding watcher/_watcher.c +adding watcher/watcher.py +adding xyzzy.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.msglen Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,14 @@ +#!/bin/sh + +hg init a +cd a +echo '[hooks]' > .hg/hgrc +echo 'pretxncommit.msglen = test `hg tip --template {desc} | wc -c` -ge 10' >> .hg/hgrc + +#$ name: go + +cat .hg/hgrc +echo a > a +hg add a +hg commit -A -m 'too short' +hg commit -A -m 'long enough'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.msglen.go.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{cat .hg/hgrc} +[hooks] +pretxncommit.msglen = test `hg tip --template \{desc\} | wc -c` -ge 10 +$ \textbf{echo a > a} +$ \textbf{hg add a} +$ \textbf{hg commit -A -m 'too short'} +transaction abort! +rollback completed +abort: pretxncommit.msglen hook exited with status 1 +$ \textbf{hg commit -A -m 'long enough'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.msglen.run.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{cat .hg/hgrc} +[hooks] +pretxncommit.msglen = test `hg tip --template \{desc\} | wc -c` -ge 10 +$ \textbf{echo a > a} +$ \textbf{hg add a} +$ \textbf{hg commit -A -m 'too short'} +abort: pretxncommit.msglen hook exited with status 1 +transaction abort! +rollback completed +$ \textbf{hg commit -A -m 'long enough'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.simple Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,37 @@ +#!/bin/bash + +#$ name: init + +hg init hook-test +cd hook-test +echo '[hooks]' >> .hg/hgrc +echo 'commit = echo committed $HG_NODE' >> .hg/hgrc +cat .hg/hgrc +echo a > a +hg add a +hg commit -m 'testing commit hook' + +#$ name: ext +#$ ignore: ^date of commit.* + +echo 'commit.when = echo -n "date of commit: "; date' >> .hg/hgrc +echo a >> a +hg commit -m 'i have two hooks' + +#$ name: + +echo '#!/bin/sh' >> check_bug_id +echo '# check that a commit comment mentions a numeric bug id' >> check_bug_id +echo 'hg log -r $1 --template {desc} | grep -q "\<bug *[0-9]"' >> check_bug_id +chmod +x check_bug_id + +#$ name: pretxncommit + +cat check_bug_id + +echo 'pretxncommit.bug_id_required = ./check_bug_id $HG_NODE' >> .hg/hgrc + +echo a >> a +hg commit -m 'i am not mentioning a bug id' + +hg commit -m 'i refer you to bug 666'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.simple.ext.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{echo 'commit.when = echo -n "date of commit: "; date' >> .hg/hgrc} +$ \textbf{echo a >> a} +$ \textbf{hg commit -m 'i have two hooks'} +committed +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.simple.init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,11 @@ +$ \textbf{hg init hook-test} +$ \textbf{cd hook-test} +$ \textbf{echo '[hooks]' >> .hg/hgrc} +$ \textbf{echo 'commit = echo committed $HG_NODE' >> .hg/hgrc} +$ \textbf{cat .hg/hgrc} +[hooks] +commit = echo committed $HG_NODE +$ \textbf{echo a > a} +$ \textbf{hg add a} +$ \textbf{hg commit -m 'testing commit hook'} +committed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.simple.pretxncommit.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{cat check_bug_id} +#!/bin/sh +# check that a commit comment mentions a numeric bug id +hg log -r $1 --template \{desc\} | grep -q "\textbackslash{}<bug *[0-9]" +$ \textbf{echo 'pretxncommit.bug_id_required = ./check_bug_id $HG_NODE' >> .hg/hgrc} +$ \textbf{echo a >> a} +$ \textbf{hg commit -m 'i am not mentioning a bug id'} +transaction abort! +rollback completed +abort: pretxncommit.bug_id_required hook exited with status 1 +$ \textbf{hg commit -m 'i refer you to bug 666'} +committed +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.ws Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,31 @@ +#!/bin/bash + +hg init a +cd a +echo '[hooks]' > .hg/hgrc +echo "pretxncommit.whitespace = hg export tip | (! egrep -q '^\\+.*[ \\t]$')" >> .hg/hgrc + +#$ name: simple + +cat .hg/hgrc +echo 'a ' > a +hg commit -A -m 'test with trailing whitespace' +echo 'a' > a +hg commit -A -m 'drop trailing whitespace and try again' + +#$ name: + +echo '[hooks]' > .hg/hgrc +echo "pretxncommit.whitespace = .hg/check_whitespace.py" >> .hg/hgrc +cp $EXAMPLE_DIR/data/check_whitespace.py .hg + +#$ name: better + +cat .hg/hgrc +echo 'a ' >> a +hg commit -A -m 'add new line with trailing whitespace' +sed -i 's, *$,,' a +hg commit -A -m 'trimmed trailing whitespace' + +#$ name: +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.ws.better.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,17 @@ +$ \textbf{cat .hg/hgrc} +[hooks] +pretxncommit.whitespace = .hg/check_whitespace.py +$ \textbf{echo 'a ' >> a} +$ \textbf{hg commit -A -m 'add new line with trailing whitespace'} +a, line 2: trailing whitespace added +commit message saved to .hg/commit.save +transaction abort! +rollback completed +abort: pretxncommit.whitespace hook exited with status 1 +$ \textbf{sed -i 's, *$,,' a} +$ \textbf{hg commit -A -m 'trimmed trailing whitespace'} +a, line 2: trailing whitespace added +commit message saved to .hg/commit.save +transaction abort! +rollback completed +abort: pretxncommit.whitespace hook exited with status 1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/hook.ws.simple.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,11 @@ +$ \textbf{cat .hg/hgrc} +[hooks] +pretxncommit.whitespace = hg export tip | (! egrep -q '^\textbackslash{}+.*[ \textbackslash{}t]$') +$ \textbf{echo 'a ' > a} +$ \textbf{hg commit -A -m 'test with trailing whitespace'} +adding a +transaction abort! +rollback completed +abort: pretxncommit.whitespace hook exited with status 1 +$ \textbf{echo 'a' > a} +$ \textbf{hg commit -A -m 'drop trailing whitespace and try again'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/issue29 Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,22 @@ +#!/bin/bash + +#$ name: go + +hg init issue29 +cd issue29 +echo a > a +hg ci -Ama +echo b > b +hg ci -Amb +hg up 0 +mkdir b +echo b > b/b +hg ci -Amc + +#$ ignore: abort: Is a directory: .* +hg merge + +#$ name: +# This error is expected from the failed merge. + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/issue29.go.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,16 @@ +$ \textbf{hg init issue29} +$ \textbf{cd issue29} +$ \textbf{echo a > a} +$ \textbf{hg ci -Ama} +adding a +$ \textbf{echo b > b} +$ \textbf{hg ci -Amb} +adding b +$ \textbf{hg up 0} +0 files updated, 0 files merged, 1 files removed, 0 files unresolved +$ \textbf{mkdir b} +$ \textbf{echo b > b/b} +$ \textbf{hg ci -Amc} +adding b/b +$ \textbf{hg merge} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.dodiff Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,14 @@ +#!/bin/bash + +#$ name: diff + +echo 'this is my original thought' > oldfile +echo 'i have changed my mind' > newfile + +diff -u oldfile newfile > tiny.patch + +cat tiny.patch + +patch < tiny.patch + +cat oldfile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.dodiff.diff.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{echo 'this is my original thought' > oldfile} +$ \textbf{echo 'i have changed my mind' > newfile} +$ \textbf{diff -u oldfile newfile > tiny.patch} +$ \textbf{cat tiny.patch} + + +@@ -1 +1 @@ +-this is my original thought ++i have changed my mind +$ \textbf{patch < tiny.patch} +patching file oldfile +$ \textbf{cat oldfile} +i have changed my mind
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,67 @@ +#!/bin/bash + +echo '[extensions]' >> $HGRC +echo 'hgext.mq =' >> $HGRC + +hg init a +cd a + +#$ name: init + +hg qinit +hg qnew hello.patch +echo hello > hello +hg add hello +hg qrefresh +hg qnew goodbye.patch +echo goodbye > goodbye +hg add goodbye +hg qrefresh + +#$ name: qguard + +hg qguard + +#$ name: qguard.pos + +hg qguard +foo +hg qguard + +#$ name: qguard.neg + +hg qguard hello.patch -quux +hg qguard hello.patch + +#$ name: series + +cat .hg/patches/series + +#$ name: qselect.foo + +hg qpop -a +hg qselect +hg qselect foo +hg qselect + +#$ name: qselect.cat + +cat .hg/patches/guards + +#$ name: qselect.qpush +hg qpush -a + +#$ name: qselect.error + +hg qselect +foo + +#$ name: qselect.quux + +hg qselect quux +hg qpop -a +hg qpush -a + +#$ name: qselect.foobar + +hg qselect foo bar +hg qpop -a +hg qpush -a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +$ \textbf{hg qinit} +$ \textbf{hg qnew hello.patch} +$ \textbf{echo hello > hello} +$ \textbf{hg add hello} +$ \textbf{hg qrefresh} +$ \textbf{hg qnew goodbye.patch} +$ \textbf{echo goodbye > goodbye} +$ \textbf{hg add goodbye} +$ \textbf{hg qrefresh}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.qguard.neg.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{hg qguard hello.patch -quux} +$ \textbf{hg qguard hello.patch} +hello.patch: -quux
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.qguard.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg qguard} +goodbye.patch: unguarded
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.qguard.pos.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{hg qguard +foo} +$ \textbf{hg qguard} +goodbye.patch: +foo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.qselect.cat.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{cat .hg/patches/guards} +foo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.qselect.error.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg qselect +foo} +abort: guard '+foo' starts with invalid character: '+'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.qselect.foo.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg qpop -a} +Patch queue now empty +$ \textbf{hg qselect} +no active guards +$ \textbf{hg qselect foo} +number of unguarded, unapplied patches has changed from 1 to 2 +$ \textbf{hg qselect} +foo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.qselect.foobar.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg qselect foo bar} +number of unguarded, unapplied patches has changed from 0 to 2 +$ \textbf{hg qpop -a} +no patches applied +$ \textbf{hg qpush -a} +applying hello.patch +applying goodbye.patch +Now at: goodbye.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.qselect.qpush.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg qpush -a} +applying hello.patch +applying goodbye.patch +Now at: goodbye.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.qselect.quux.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ +$ \textbf{hg qselect quux} +number of guarded, applied patches has changed from 0 to 2 +$ \textbf{hg qpop -a} +Patch queue now empty +$ \textbf{hg qpush -a} +patch series already fully applied
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.guards.series.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cat .hg/patches/series} +hello.patch #-quux +goodbye.patch #+foo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.id Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,28 @@ +#!/bin/sh + +echo '[extensions]' >> $HGRC +echo 'hgext.mq =' >> $HGRC + +hg init a +cd a +hg qinit +echo 'int x;' > test.c +hg ci -Ama + +hg qnew first.patch +echo 'float c;' >> test.c +hg qrefresh + +hg qnew second.patch +echo 'double u;' > other.c +hg add other.c +hg qrefresh + +#$ name: output + +hg qapplied +hg log -r qbase:qtip +hg export second.patch + +#$ name: +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.id.out.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,32 @@ +$ \textbf{hg qapplied} +first.patch +second.patch +$ \textbf{hg log -r qbase:qtip} +changeset: +tag: first.patch +tag: qbase +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: patch queue: first.patch + +changeset: +tag: second.patch +tag: qtip +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: patch queue: second.patch + +$ \textbf{hg export second.patch} +# HG changeset patch +# User Bryan O'Sullivan <bos@serpentine.com> + +# Node ID +# Parent +patch queue: second.patch + +diff -r -r other.c + + +@@ -0,0 +1,1 @@ ++double u;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.id.output.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,32 @@ +$ \textbf{hg qapplied} +first.patch +second.patch +$ \textbf{hg log -r qbase:qtip} +changeset: +tag: first.patch +tag: qbase +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: [mq]: first.patch + +changeset: +tag: qtip +tag: second.patch +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: [mq]: second.patch + +$ \textbf{hg export second.patch} +# HG changeset patch +# User Bryan O'Sullivan <bos@serpentine.com> + +# Node ID +# Parent +[mq]: second.patch + +diff -r -r other.c + + +@@ -0,0 +1,1 @@ ++double u;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.qinit-help Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +#!/bin/bash + +echo '[extensions]' >> $HGRC +echo 'hgext.mq =' >> $HGRC + +#$ name: help +hg help qinit
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.qinit-help.help.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,16 @@ +$ \textbf{hg help qinit} +hg qinit [-c] + +init a new queue repository + + The queue repository is unversioned by default. If -c is + specified, qinit will create a separate nested repository + for patches (qinit -c may also be run later to convert + an unversioned patch repository into a versioned one). + You can use qcommit to commit changes to this queue repository. + +options: + + -c --create-repo create queue repository + +use "hg -v help qinit" to show global options
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tarball Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,51 @@ +#!/bin/bash + +cp $EXAMPLE_DIR/data/netplug-*.tar.bz2 . +ln -s /bin/true download +export PATH=`pwd`:$PATH + +#$ name: download + +download netplug-1.2.5.tar.bz2 +tar jxf netplug-1.2.5.tar.bz2 +cd netplug-1.2.5 +hg init +hg commit -q --addremove --message netplug-1.2.5 +cd .. +hg clone netplug-1.2.5 netplug + +#$ name: + +cd netplug +echo '[extensions]' >> $HGRC +echo 'hgext.mq =' >> $HGRC +cd .. + +#$ name: qinit + +cd netplug +hg qinit +hg qnew -m 'fix build problem with gcc 4' build-fix.patch +perl -pi -e 's/int addr_len/socklen_t addr_len/' netlink.c +hg qrefresh +hg tip -p + +#$ name: newsource + +hg qpop -a +cd .. +download netplug-1.2.8.tar.bz2 +hg clone netplug-1.2.5 netplug-1.2.8 +cd netplug-1.2.8 +hg locate -0 | xargs -0 rm +cd .. +tar jxf netplug-1.2.8.tar.bz2 +cd netplug-1.2.8 +hg commit --addremove --message netplug-1.2.8 + +#$ name: repush + +cd ../netplug +hg pull ../netplug-1.2.8 +hg qpush -a +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tarball.download.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{download netplug-1.2.5.tar.bz2} +$ \textbf{tar jxf netplug-1.2.5.tar.bz2} +$ \textbf{cd netplug-1.2.5} +$ \textbf{hg init} +$ \textbf{hg commit -q --addremove --message netplug-1.2.5} +$ \textbf{cd ..} +$ \textbf{hg clone netplug-1.2.5 netplug} +18 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tarball.newsource.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,12 @@ +$ \textbf{hg qpop -a} +Patch queue now empty +$ \textbf{cd ..} +$ \textbf{download netplug-1.2.8.tar.bz2} +$ \textbf{hg clone netplug-1.2.5 netplug-1.2.8} +18 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd netplug-1.2.8} +$ \textbf{hg locate -0 | xargs -0 rm} +$ \textbf{cd ..} +$ \textbf{tar jxf netplug-1.2.8.tar.bz2} +$ \textbf{cd netplug-1.2.8} +$ \textbf{hg commit --addremove --message netplug-1.2.8}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tarball.qinit.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,28 @@ +$ \textbf{cd netplug} +$ \textbf{hg qinit} +$ \textbf{hg qnew -m 'fix build problem with gcc 4' build-fix.patch} +$ \textbf{perl -pi -e 's/int addr_len/socklen_t addr_len/' netlink.c} +$ \textbf{hg qrefresh} +$ \textbf{hg tip -p} +changeset: +tag: qtip +tag: build-fix.patch +tag: tip +tag: qbase +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: fix build problem with gcc 4 + +diff -r -r netlink.c + + +@@ -275,7 +275,7 @@ netlink_open(void) + exit(1); + \} + +- int addr_len = sizeof(addr); ++ socklen_t addr_len = sizeof(addr); + + if (getsockname(fd, (struct sockaddr *) &addr, &addr_len) == -1) \{ + do_log(LOG_ERR, "Could not get socket details: %m"); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tarball.repush.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,12 @@ +$ \textbf{cd ../netplug} +$ \textbf{hg pull ../netplug-1.2.8} +pulling from ../netplug-1.2.8 +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 12 changes to 12 files +(run 'hg update' to get a working copy) +$ \textbf{hg qpush -a} +applying build-fix.patch +Now at: build-fix.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tools Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,11 @@ +#!/bin/bash + +cp $EXAMPLE_DIR/data/remove-redundant-null-checks.patch . + +#$ name: tools +diffstat -p1 remove-redundant-null-checks.patch + +filterdiff -i '*/video/*' remove-redundant-null-checks.patch + +#$ name: lsdiff +lsdiff -nvv remove-redundant-null-checks.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tools.lsdiff.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,21 @@ +$ \textbf{lsdiff -nvv remove-redundant-null-checks.patch} +22 File #1 a/drivers/char/agp/sgi-agp.c + 24 Hunk #1 static int __devinit agp_sgi_init(void) +37 File #2 a/drivers/char/hvcs.c + 39 Hunk #1 static struct tty_operations hvcs_ops = + 53 Hunk #2 static int hvcs_alloc_index_list(int n) +69 File #3 a/drivers/message/fusion/mptfc.c + 71 Hunk #1 mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, in +85 File #4 a/drivers/message/fusion/mptsas.c + 87 Hunk #1 mptsas_probe_hba_phys(MPT_ADAPTER *ioc) +98 File #5 a/drivers/net/fs_enet/fs_enet-mii.c + 100 Hunk #1 static struct fs_enet_mii_bus *create_bu +111 File #6 a/drivers/net/wireless/ipw2200.c + 113 Hunk #1 static struct ipw_fw_error *ipw_alloc_er + 126 Hunk #2 static ssize_t clear_error(struct device + 140 Hunk #3 static void ipw_irq_tasklet(struct ipw_p + 150 Hunk #4 static void ipw_pci_remove(struct pci_de +164 File #7 a/drivers/scsi/libata-scsi.c + 166 Hunk #1 int ata_cmd_ioctl(struct scsi_device *sc +178 File #8 a/drivers/video/au1100fb.c + 180 Hunk #1 void __exit au1100fb_cleanup(void)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tools.tools.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,23 @@ +$ \textbf{diffstat -p1 remove-redundant-null-checks.patch} + drivers/char/agp/sgi-agp.c | 5 ++--- + drivers/char/hvcs.c | 11 +++++------ + drivers/message/fusion/mptfc.c | 6 ++---- + drivers/message/fusion/mptsas.c | 3 +-- + drivers/net/fs_enet/fs_enet-mii.c | 3 +-- + drivers/net/wireless/ipw2200.c | 22 ++++++---------------- + drivers/scsi/libata-scsi.c | 4 +--- + drivers/video/au1100fb.c | 3 +-- + 8 files changed, 19 insertions(+), 38 deletions(-) +$ \textbf{filterdiff -i '*/video/*' remove-redundant-null-checks.patch} + + +@@ -743,8 +743,7 @@ void __exit au1100fb_cleanup(void) + \{ + driver_unregister(&au1100fb_driver); + +- if (drv_info.opt_mode) +- kfree(drv_info.opt_mode); ++ kfree(drv_info.opt_mode); + \} + + module_init(au1100fb_init);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,74 @@ +#!/bin/bash + +echo '[extensions]' >> $HGRC +echo 'hgext.mq =' >> $HGRC + +#$ name: qinit + +hg init mq-sandbox +cd mq-sandbox +echo 'line 1' > file1 +echo 'another line 1' > file2 +hg add file1 file2 +hg commit -m'first change' + +hg qinit + +#$ name: qnew + +hg tip +hg qnew first.patch +hg tip +ls .hg/patches + +#$ name: qrefresh +#$ ignore: \s+200[78]-.* + +echo 'line 2' >> file1 +hg diff +hg qrefresh +hg diff +hg tip --style=compact --patch + +#$ name: qrefresh2 + +echo 'line 3' >> file1 +hg status +hg qrefresh +hg tip --style=compact --patch + +#$ name: qnew2 + +hg qnew second.patch +hg log --style=compact --limit=2 +echo 'line 4' >> file1 +hg qrefresh +hg tip --style=compact --patch +hg annotate file1 + +#$ name: qseries + +hg qseries +hg qapplied + +#$ name: qpop + +hg qapplied +hg qpop +hg qseries +hg qapplied +cat file1 + +#$ name: qpush-a + +hg qpush -a +cat file1 + +#$ name: add + +echo 'file 3, line 1' >> file3 +hg qnew add-file3.patch +hg qnew -f add-file3.patch + +#$ name: +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial.add.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{echo 'file 3, line 1' >> file3} +$ \textbf{hg qnew add-file3.patch} +$ \textbf{hg qnew -f add-file3.patch} +abort: patch "add-file3.patch" already exists
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial.qinit.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{hg init mq-sandbox} +$ \textbf{cd mq-sandbox} +$ \textbf{echo 'line 1' > file1} +$ \textbf{echo 'another line 1' > file2} +$ \textbf{hg add file1 file2} +$ \textbf{hg commit -m'first change'} +$ \textbf{hg qinit}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial.qnew.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,20 @@ +$ \textbf{hg tip} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: first change + +$ \textbf{hg qnew first.patch} +$ \textbf{hg tip} +changeset: +tag: qtip +tag: first.patch +tag: tip +tag: qbase +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: [mq]: first.patch + +$ \textbf{ls .hg/patches} +first.patch series status
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial.qnew2.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,28 @@ +$ \textbf{hg qnew second.patch} +$ \textbf{hg log --style=compact --limit=2} +2[qtip,second.patch,tip] + [mq]: second.patch + +1[first.patch,qbase] + [mq]: first.patch + +$ \textbf{echo 'line 4' >> file1} +$ \textbf{hg qrefresh} +$ \textbf{hg tip --style=compact --patch} +2[qtip,second.patch,tip] + [mq]: second.patch + +diff -r -r file1 + + +@@ -1,3 +1,4 @@ line 1 + line 1 + line 2 + line 3 ++line 4 + +$ \textbf{hg annotate file1} +0: line 1 +1: line 2 +1: line 3 +2: line 4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial.qpop.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,14 @@ +$ \textbf{hg qapplied} +first.patch +second.patch +$ \textbf{hg qpop} +Now at: first.patch +$ \textbf{hg qseries} +first.patch +second.patch +$ \textbf{hg qapplied} +first.patch +$ \textbf{cat file1} +line 1 +line 2 +line 3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial.qpush-a.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg qpush -a} +applying second.patch +Now at: second.patch +$ \textbf{cat file1} +line 1 +line 2 +line 3 +line 4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial.qrefresh.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,21 @@ +$ \textbf{echo 'line 2' >> file1} +$ \textbf{hg diff} +diff -r file1 + + +@@ -1,1 +1,2 @@ line 1 + line 1 ++line 2 +$ \textbf{hg qrefresh} +$ \textbf{hg diff} +$ \textbf{hg tip --style=compact --patch} +1[qtip,first.patch,tip,qbase] + [mq]: first.patch + +diff -r -r file1 + + +@@ -1,1 +1,2 @@ line 1 + line 1 ++line 2 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial.qrefresh2.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,16 @@ +$ \textbf{echo 'line 3' >> file1} +$ \textbf{hg status} +M file1 +$ \textbf{hg qrefresh} +$ \textbf{hg tip --style=compact --patch} +1[qtip,first.patch,tip,qbase] + [mq]: first.patch + +diff -r -r file1 + + +@@ -1,1 +1,3 @@ line 1 + line 1 ++line 2 ++line 3 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/mq.tutorial.qseries.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ +$ \textbf{hg qseries} +first.patch +second.patch +$ \textbf{hg qapplied} +first.patch +second.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rename.divergent Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,33 @@ +#!/bin/bash + +hg init orig +cd orig +echo foo > foo +hg ci -A -m 'First commit' +cd .. + +#$ name: clone + +hg clone orig anne +hg clone orig bob + +#$ name: rename.anne + +cd anne +hg rename foo bar +hg ci -m 'Rename foo to bar' + +#$ name: rename.bob + +cd ../bob +hg mv foo quux +hg ci -m 'Rename foo to quux' + +#$ name: merge +# See http://www.selenic.com/mercurial/bts/issue455 + +cd ../orig +hg pull -u ../anne +hg pull ../bob +hg merge +ls
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rename.divergent.clone.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg clone orig anne} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{hg clone orig bob} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rename.divergent.merge.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,26 @@ +# See http://www.selenic.com/mercurial/bts/issue455 +$ \textbf{cd ../orig} +$ \textbf{hg pull -u ../anne} +pulling from ../anne +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +$ \textbf{hg pull ../bob} +pulling from ../bob +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files (+1 heads) +(run 'hg heads' to see heads, 'hg merge' to merge) +$ \textbf{hg merge} +warning: detected divergent renames of foo to: + bar + quux +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +$ \textbf{ls} +bar quux
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rename.divergent.rename.anne.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cd anne} +$ \textbf{hg mv foo bar} +$ \textbf{hg ci -m 'Rename foo to bar'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rename.divergent.rename.bob.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cd ../bob} +$ \textbf{hg mv foo quux} +$ \textbf{hg ci -m 'Rename foo to quux'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rollback Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,37 @@ +#!/bin/bash + +hg init a +cd a +echo a > a +hg ci -A -m 'First commit' + +echo a >> a + +#$ name: tip + +#$ name: commit + +hg status +echo b > b +hg commit -m 'Add file b' + +#$ name: status + +hg status +hg tip + +#$ name: rollback + +hg rollback +hg tip +hg status + +#$ name: add + +hg add b +hg commit -m 'Add file b, this time for real' + +#$ name: twice + +hg rollback +hg rollback
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rollback.add.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg add b} +$ \textbf{hg commit -m 'Add file b, this time for real'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rollback.commit.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg status} +M a +$ \textbf{echo b > b} +$ \textbf{hg commit -m 'Add file b'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rollback.rollback.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,12 @@ +$ \textbf{hg rollback} +rolling back last transaction +$ \textbf{hg tip} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: First commit + +$ \textbf{hg status} +M a +? b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rollback.status.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +$ \textbf{hg status} +? b +$ \textbf{hg tip} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Add file b +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/rollback.twice.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg rollback} +rolling back last transaction +$ \textbf{hg rollback} +no rollback information available
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/run-example Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,465 @@ +#!/usr/bin/env python +# +# This program takes something that resembles a shell script and runs +# it, spitting input (commands from the script) and output into text +# files, for use in examples. + +import cStringIO +import errno +import getopt +import glob +import os +import pty +import re +import select +import shutil +import signal +import stat +import sys +import tempfile +import time + +xml_subs = { + '<': '<', + '>': '>', + '&': '&', + } + +def gensubs(s): + start = 0 + for i, c in enumerate(s): + sub = xml_subs.get(c) + if sub: + yield s[start:i] + start = i + 1 + yield sub + yield s[start:] + +def xml_escape(s): + return ''.join(gensubs(s)) + +def maybe_unlink(name): + try: + os.unlink(name) + return True + except OSError, err: + if err.errno != errno.ENOENT: + raise + return False + +def find_path_to(program): + for p in os.environ.get('PATH', os.defpath).split(os.pathsep): + name = os.path.join(p, program) + if os.access(name, os.X_OK): + return p + return None + +def result_name(name): + return os.path.normpath(os.path.join('results', name.replace(os.sep, '-'))) + +def wopen(name): + path = os.path.dirname(name) + if path: + try: + os.makedirs(path) + except OSError, err: + if err.errno != errno.EEXIST: + raise + return open(name, 'w') + +class example: + entities = dict.fromkeys(l.rstrip() for l in open('auto-snippets.xml')) + + def __init__(self, name, verbose, keep_change): + self.name = os.path.normpath(name) + self.verbose = verbose + self.keep_change = keep_change + + def status(self, s): + sys.stdout.write(s) + if not s.endswith('\n'): + sys.stdout.flush() + + def rename_output(self, base, ignore=[]): + mangle_re = re.compile('(?:' + '|'.join(ignore) + ')') + def mangle(s): + return mangle_re.sub('', s) + def matchfp(fp1, fp2): + while True: + s1 = mangle(fp1.readline()) + s2 = mangle(fp2.readline()) + if cmp(s1, s2): + break + if not s1: + return True + return False + + oldname = result_name(base + '.out') + tmpname = result_name(base + '.tmp') + errname = result_name(base + '.err') + errfp = open(errname, 'w+') + for line in open(tmpname): + errfp.write(mangle_re.sub('', line)) + os.rename(tmpname, result_name(base + '.lxo')) + errfp.seek(0) + try: + oldfp = open(oldname) + except IOError, err: + if err.errno != errno.ENOENT: + raise + os.rename(errname, oldname) + return False + if matchfp(oldfp, errfp): + os.unlink(errname) + return False + else: + print >> sys.stderr, '\nOutput of %s has changed!' % base + if self.keep_change: + os.rename(errname, oldname) + return False + else: + os.system('diff -u %s %s 1>&2' % (oldname, errname)) + return True + +class static_example(example): + def run(self): + self.status('running %s\n' % self.name) + s = open(self.name).read().rstrip() + s = s.replace('&', '&').replace('<', '<').replace('>', '>') + ofp = wopen(result_name(self.name + '.tmp')) + ofp.write('<!-- BEGIN %s -->\n' % self.name) + ofp.write('<programlisting>') + ofp.write(s) + ofp.write('</programlisting>\n') + ofp.write('<!-- END %s -->\n' % self.name) + ofp.close() + self.rename_output(self.name) + norm = self.name.replace(os.sep, '-') + example.entities[ + '<!ENTITY %s SYSTEM "results/%s.lxo">' % (norm, norm)] = 1 + + +class shell_example(example): + shell = '/usr/bin/env bash' + ps1 = '__run_example_ps1__ ' + ps2 = '__run_example_ps2__ ' + pi_re = re.compile(r'#\$\s*(name|ignore):\s*(.*)$') + + timeout = 10 + + def __init__(self, name, verbose, keep_change): + example.__init__(self, name, verbose, keep_change) + self.poll = select.poll() + + def parse(self): + '''yield each hunk of input from the file.''' + fp = open(self.name) + cfp = cStringIO.StringIO() + for line in fp: + cfp.write(line) + if not line.rstrip().endswith('\\'): + yield cfp.getvalue() + cfp.seek(0) + cfp.truncate() + + def send(self, s): + if self.verbose: + print >> sys.stderr, '>', self.debugrepr(s) + while s: + count = os.write(self.cfd, s) + s = s[count:] + + def debugrepr(self, s): + rs = repr(s) + limit = 60 + if len(rs) > limit: + return ('%s%s ... [%d bytes]' % (rs[:limit], rs[0], len(s))) + else: + return rs + + timeout = 5 + + def read(self, hint): + events = self.poll.poll(self.timeout * 1000) + if not events: + print >> sys.stderr, ('[%stimed out after %d seconds]' % + (hint, self.timeout)) + os.kill(self.pid, signal.SIGHUP) + return '' + return os.read(self.cfd, 1024) + + def receive(self, hint): + out = cStringIO.StringIO() + while True: + try: + if self.verbose: + sys.stderr.write('< ') + s = self.read(hint) + except OSError, err: + if err.errno == errno.EIO: + return '', '' + raise + if self.verbose: + print >> sys.stderr, self.debugrepr(s) + out.write(s) + s = out.getvalue() + if s.endswith(self.ps1): + return self.ps1, s.replace('\r\n', '\n')[:-len(self.ps1)] + if s.endswith(self.ps2): + return self.ps2, s.replace('\r\n', '\n')[:-len(self.ps2)] + + def sendreceive(self, s, hint): + self.send(s) + ps, r = self.receive(hint) + if r.startswith(s): + r = r[len(s):] + return ps, r + + def run(self): + ofp = None + basename = os.path.basename(self.name) + self.status('running %s ' % basename) + tmpdir = tempfile.mkdtemp(prefix=basename) + + # remove the marker file that we tell make to use to see if + # this run succeeded + maybe_unlink(self.name + '.run') + + rcfile = os.path.join(tmpdir, '.hgrc') + rcfp = wopen(rcfile) + print >> rcfp, '[ui]' + print >> rcfp, "username = Bryan O'Sullivan <bos@serpentine.com>" + + rcfile = os.path.join(tmpdir, '.bashrc') + rcfp = wopen(rcfile) + print >> rcfp, 'PS1="%s"' % self.ps1 + print >> rcfp, 'PS2="%s"' % self.ps2 + print >> rcfp, 'unset HISTFILE' + path = ['/usr/bin', '/bin'] + hg = find_path_to('hg') + if hg and hg not in path: + path.append(hg) + def re_export(envar): + v = os.getenv(envar) + if v is not None: + print >> rcfp, 'export ' + envar + '=' + v + print >> rcfp, 'export PATH=' + ':'.join(path) + re_export('PYTHONPATH') + print >> rcfp, 'export EXAMPLE_DIR="%s"' % os.getcwd() + print >> rcfp, 'export HGMERGE=merge' + print >> rcfp, 'export LANG=C' + print >> rcfp, 'export LC_ALL=C' + print >> rcfp, 'export TZ=GMT' + print >> rcfp, 'export HGRC="%s/.hgrc"' % tmpdir + print >> rcfp, 'export HGRCPATH=$HGRC' + print >> rcfp, 'cd %s' % tmpdir + rcfp.close() + sys.stdout.flush() + sys.stderr.flush() + self.pid, self.cfd = pty.fork() + if self.pid == 0: + cmdline = ['/usr/bin/env', '-i', 'bash', '--noediting', + '--noprofile', '--norc'] + try: + os.execv(cmdline[0], cmdline) + except OSError, err: + print >> sys.stderr, '%s: %s' % (cmdline[0], err.strerror) + sys.stderr.flush() + os._exit(0) + self.poll.register(self.cfd, select.POLLIN | select.POLLERR | + select.POLLHUP) + + prompts = { + '': '', + self.ps1: '$', + self.ps2: '>', + } + + ignore = [ + r'\d+:[0-9a-f]{12}', # changeset number:hash + r'[0-9a-f]{40}', # long changeset hash + r'[0-9a-f]{12}', # short changeset hash + r'^(?:---|\+\+\+) .*', # diff header with dates + r'^date:.*', # date + #r'^diff -r.*', # "diff -r" is followed by hash + r'^# Date \d+ \d+', # hg patch header + ] + + err = False + read_hint = '' + + try: + try: + # eat first prompt string from shell + self.read(read_hint) + # setup env and prompt + ps, output = self.sendreceive('source %s\n' % rcfile, + read_hint) + for hunk in self.parse(): + # is this line a processing instruction? + m = self.pi_re.match(hunk) + if m: + pi, rest = m.groups() + if pi == 'name': + self.status('.') + out = rest + if out in ('err', 'lxo', 'out', 'run', 'tmp'): + print >> sys.stderr, ('%s: illegal section ' + 'name %r' % + (self.name, out)) + return 1 + assert os.sep not in out + if ofp is not None: + ofp.write('</screen>\n') + ofp.write('<!-- END %s -->\n' % ofp_basename) + ofp.close() + err |= self.rename_output(ofp_basename, ignore) + if out: + ofp_basename = '%s.%s' % (self.name, out) + norm = os.path.normpath(ofp_basename) + norm = norm.replace(os.sep, '-') + example.entities[ + '<!ENTITY interaction.%s ' + 'SYSTEM "results/%s.lxo">' + % (norm, norm)] = 1 + read_hint = ofp_basename + ' ' + ofp = wopen(result_name(ofp_basename + '.tmp')) + ofp.write('<!-- BEGIN %s -->\n' % ofp_basename) + ofp.write('<screen>') + else: + ofp = None + elif pi == 'ignore': + ignore.append(rest) + elif hunk.strip(): + # it's something we should execute + newps, output = self.sendreceive(hunk, read_hint) + if not ofp: + continue + # first, print the command we ran + if not hunk.startswith('#'): + nl = hunk.endswith('\n') + hunk = ('<prompt>%s</prompt> ' + '<userinput>%s</userinput>' % + (prompts[ps], + xml_escape(hunk.rstrip('\n')))) + if nl: hunk += '\n' + ofp.write(hunk) + # then its output + ofp.write(xml_escape(output)) + ps = newps + self.status('\n') + except: + print >> sys.stderr, '(killed)' + os.kill(self.pid, signal.SIGKILL) + pid, rc = os.wait() + raise + else: + try: + ps, output = self.sendreceive('exit\n', read_hint) + if ofp is not None: + ofp.write(output) + ofp.write('</screen>\n') + ofp.write('<!-- END %s -->\n' % ofp_basename) + ofp.close() + err |= self.rename_output(ofp_basename, ignore) + os.close(self.cfd) + except IOError: + pass + os.kill(self.pid, signal.SIGTERM) + pid, rc = os.wait() + err = err or rc + if err: + if os.WIFEXITED(rc): + print >> sys.stderr, '(exit %s)' % os.WEXITSTATUS(rc) + elif os.WIFSIGNALED(rc): + print >> sys.stderr, '(signal %s)' % os.WTERMSIG(rc) + else: + wopen(result_name(self.name + '.run')) + return err + finally: + shutil.rmtree(tmpdir) + +def print_help(exit, msg=None): + if msg: + print >> sys.stderr, 'Error:', msg + print >> sys.stderr, 'Usage: run-example [options] [test...]' + print >> sys.stderr, 'Options:' + print >> sys.stderr, ' -a --all run all examples in this directory' + print >> sys.stderr, ' -h --help print this help message' + print >> sys.stderr, ' --keep keep new output as desired output' + print >> sys.stderr, ' -v --verbose display extra debug output' + sys.exit(exit) + +def main(path='.'): + if os.path.realpath(path).split(os.sep)[-1] != 'examples': + print >> sys.stderr, 'Not being run from the examples directory!' + sys.exit(1) + + opts, args = getopt.getopt(sys.argv[1:], '?ahv', + ['all', 'help', 'keep', 'verbose']) + verbose = False + run_all = False + keep_change = False + + for o, a in opts: + if o in ('-h', '-?', '--help'): + print_help(0) + if o in ('-a', '--all'): + run_all = True + if o in ('--keep',): + keep_change = True + if o in ('-v', '--verbose'): + verbose = True + errs = 0 + if args: + for a in args: + try: + st = os.lstat(a) + except OSError, err: + print >> sys.stderr, '%s: %s' % (a, err.strerror) + errs += 1 + continue + if stat.S_ISREG(st.st_mode): + if st.st_mode & 0111: + if shell_example(a, verbose, keep_change).run(): + errs += 1 + elif a.endswith('.lst'): + static_example(a, verbose, keep_change).run() + else: + print >> sys.stderr, '%s: not a file, or not executable' % a + errs += 1 + elif run_all: + names = glob.glob("*") + glob.glob("app*/*") + glob.glob("ch*/*") + names.sort() + for name in names: + if name == 'run-example' or name.endswith('~'): continue + pathname = os.path.join(path, name) + try: + st = os.lstat(pathname) + except OSError, err: + # could be an output file that was removed while we ran + if err.errno != errno.ENOENT: + raise + continue + if stat.S_ISREG(st.st_mode): + if st.st_mode & 0111: + if shell_example(pathname, verbose, keep_change).run(): + errs += 1 + elif pathname.endswith('.lst'): + static_example(pathname, verbose, keep_change).run() + print >> wopen(os.path.join(path, '.run')), time.asctime() + else: + print_help(1, msg='no test names given, and --all not provided') + + fp = wopen('auto-snippets.xml') + for key in sorted(example.entities.iterkeys()): + print >> fp, key + fp.close() + return errs + +if __name__ == '__main__': + try: + sys.exit(main()) + except KeyboardInterrupt: + print >> sys.stderr, 'interrupted!' + sys.exit(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/svn-long.txt Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,11 @@ +------------------------------------------------------------------------ +r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines +Changed paths: + M /gen2/trunk/src/linux-kernel/infiniband/core/cma.c + +On reporting a route error, also include the status for the error, +rather than indicating a status of 0 when an error has occurred. + +Signed-off-by: Sean Hefty <sean.hefty@intel.com> + +------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/svn-short.txt Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +------------------------------------------------------------------------ +r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines + +On reporting a route error, also include the status for the error, +rather than indicating a status of 0 when an error has occurred. + +Signed-off-by: Sean Hefty <sean.hefty@intel.com> + +------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/svn.style Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +header = '------------------------------------------------------------------------\n\n' +changeset = svn.template
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/svn.template Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +r{rev} | {author|user} | {date|isodate} ({date|rfc822date}) + +{desc|strip|fill76} + +------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tag Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,44 @@ +#!/bin/bash + +#$ name: init + +hg init mytag +cd mytag + +echo hello > myfile +hg commit -A -m 'Initial commit' + +#$ name: tag + +hg tag v1.0 + +#$ name: tags + +hg tags + +#$ name: log + +hg log + +#$ name: log.v1.0 + +echo goodbye > myfile2 +hg commit -A -m 'Second commit' +hg log -r v1.0 + +#$ name: remove + +hg tag --remove v1.0 +hg tags + +#$ name: replace + +hg tag -r 1 v1.1 +hg tags +hg tag -r 2 v1.1 +hg tag -f -r 2 v1.1 +hg tags + +#$ name: tip + +hg tip
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tag.init.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{hg init mytag} +$ \textbf{cd mytag} +$ \textbf{echo hello > myfile} +$ \textbf{hg commit -A -m 'Initial commit'} +adding myfile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tag.log.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{hg log} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added tag v1.0 for changeset + +changeset: +tag: v1.0 +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Initial commit +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tag.log.v1.0.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{echo goodbye > myfile2} +$ \textbf{hg commit -A -m 'Second commit'} +adding myfile2 +$ \textbf{hg log -r v1.0} +changeset: +tag: v1.0 +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Initial commit +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tag.remove.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{hg tag --remove v1.0} +$ \textbf{hg tags} +tip
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tag.replace.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{hg tag -r 1 v1.1} +$ \textbf{hg tags} +tip +v1.1 +$ \textbf{hg tag -r 2 v1.1} +abort: a tag named v1.1 already exists (use -f to force) +$ \textbf{hg tag -f -r 2 v1.1} +$ \textbf{hg tags} +tip +v1.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tag.tag.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1 @@ +$ \textbf{hg tag v1.0}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tag.tags.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{hg tags} +tip +v1.0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tag.tip.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{hg tip} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added tag v1.1 for changeset +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,96 @@ +#!/bin/bash + +# So many different bits of random output, it would be a nightmare to +# ignore each individually. +#$ ignore: .* + +hg init myrepo +cd myrepo +echo hello > hello +hg commit -Am'added hello' + +echo hello >> hello +echo goodbye > goodbye +echo ' added line to end of <<hello>> file.' > ../msg +echo '' >> ../msg +echo 'in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.' >> ../msg + +hg commit -Al../msg + +hg tag mytag +hg tag v0.1 + +#$ name: normal + +hg log -r1 + +#$ name: compact + +hg log --style compact + +#$ name: changelog + +hg log --style changelog + +#$ name: simplest + +hg log -r1 --template 'i saw a changeset\n' + +#$ name: simplesub + +hg log --template 'i saw a changeset: {desc}\n' + +#$ name: keywords + +hg log -r1 --template 'author: {author}\n' +hg log -r1 --template 'desc:\n{desc}\n' +hg log -r1 --template 'files: {files}\n' +hg log -r1 --template 'file_adds: {file_adds}\n' +hg log -r1 --template 'file_dels: {file_dels}\n' +hg log -r1 --template 'node: {node}\n' +hg log -r1 --template 'parents: {parents}\n' +hg log -r1 --template 'rev: {rev}\n' +hg log -r1 --template 'tags: {tags}\n' + +#$ name: datekeyword + +hg log -r1 --template 'date: {date}\n' +hg log -r1 --template 'date: {date|isodate}\n' + +#$ name: manyfilters + +hg log -r1 --template '{author}\n' +hg log -r1 --template '{author|domain}\n' +hg log -r1 --template '{author|email}\n' +hg log -r1 --template '{author|obfuscate}\n' | cut -c-76 +hg log -r1 --template '{author|person}\n' +hg log -r1 --template '{author|user}\n' + +hg log -r1 --template 'looks almost right, but actually garbage: {date}\n' +hg log -r1 --template '{date|age}\n' +hg log -r1 --template '{date|date}\n' +hg log -r1 --template '{date|hgdate}\n' +hg log -r1 --template '{date|isodate}\n' +hg log -r1 --template '{date|rfc822date}\n' +hg log -r1 --template '{date|shortdate}\n' + +hg log -r1 --template '{desc}\n' | cut -c-76 +hg log -r1 --template '{desc|addbreaks}\n' | cut -c-76 +hg log -r1 --template '{desc|escape}\n' | cut -c-76 +hg log -r1 --template '{desc|fill68}\n' +hg log -r1 --template '{desc|fill76}\n' +hg log -r1 --template '{desc|firstline}\n' +hg log -r1 --template '{desc|strip}\n' | cut -c-76 +hg log -r1 --template '{desc|tabindent}\n' | expand | cut -c-76 + +hg log -r1 --template '{node}\n' +hg log -r1 --template '{node|short}\n' + +#$ name: combine + +hg log -r1 --template 'description:\n\t{desc|strip|fill68|tabindent}\n' + +#$ name: rev + +echo 'changeset = "rev: {rev}\n"' > rev +hg log -l1 --style ./rev
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.changelog.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.combine.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.compact.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ + + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.datekeyword.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.keywords.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.manyfilters.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.normal.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.rev.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.simplest.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.simple.simplesub.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.svnstyle Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,71 @@ +#!/bin/bash + +svn() { + cat $EXAMPLE_DIR/svn-short.txt +} + +#$ name: short + +svn log -r9653 + +#$ name: + +hg init myrepo +cd myrepo + +echo hello > hello +hg commit -Am'added hello' + +echo hello >> hello +echo goodbye > goodbye +echo ' added line to end of <<hello>> file.' > ../msg +echo '' >> ../msg +echo 'in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.' >> ../msg + +hg commit -Al../msg + +hg tag mytag +hg tag v0.1 + +echo 'changeset = "{node|short}\n"' > svn.style + +#$ name: id + +hg log -r0 --template '{node}' + +#$ name: simplest +#$ ignore: \d+-\d+-\d+ \d+:\d+ \+.* + +cat svn.style +hg log -r1 --style svn.style + +#$ name: + +echo 'changeset =' > broken.style + +#$ name: syntax.input + +cat broken.style + +#$ name: syntax.error + +hg log -r1 --style broken.style + +#$ name: + +cp $EXAMPLE_DIR/svn.style . +cp $EXAMPLE_DIR/svn.template . + +#$ name: template + +cat svn.template + +#$ name: style + +cat svn.style + +#$ name: result +#$ ignore: \| 200[78].* + +hg log -r1 --style svn.style +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.svnstyle.id.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1 @@ +$ \textbf{hg log -r0 --template '\{node\}'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.svnstyle.result.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,11 @@ +$ \textbf{hg log -r1 --style svn.style} +------------------------------------------------------------------------ + +r1 | bos + +added line to end of <<hello>> file. + +in addition, added a file with the helpful name (at least i hope that some +might consider it so) of goodbye. + +------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.svnstyle.short.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{svn log -r9653} +------------------------------------------------------------------------ +r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines + +On reporting a route error, also include the status for the error, +rather than indicating a status of 0 when an error has occurred. + +Signed-off-by: Sean Hefty <sean.hefty@intel.com> + +------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.svnstyle.simplest.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{cat svn.style} +changeset = "\{node|short\}\textbackslash{}n" +$ \textbf{hg log -r1 --style svn.style} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.svnstyle.style.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cat svn.style} +header = '------------------------------------------------------------------------\textbackslash{}n\textbackslash{}n' +changeset = svn.template
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.svnstyle.syntax.error.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg log -r1 --style broken.style} +abort: broken.style:1: parse error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.svnstyle.syntax.input.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{cat broken.style} +changeset =
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/template.svnstyle.template.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ +$ \textbf{cat svn.template} +r\{rev\} | \{author|user\} | \{date|isodate\} (\{date|rfc822date\}) + +\{desc|strip|fill76\} + +------------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,206 @@ +#!/bin/bash + +#$ name: version + +hg version + +#$ name: help + +hg help init + +#$ name: clone + +hg clone http://hg.serpentine.com/tutorial/hello + +#$ name: ls +#$ ignore: ^drwx.* +#$ ignore: ^total \d+ + +ls -l +ls hello + +#$ name: ls-a + +cd hello +ls -a + +#$ name: log + +hg log + +#$ name: log-r + +hg log -r 3 +hg log -r 0272e0d5a517 +hg log -r 1 -r 4 + +#$ name: log.range + +hg log -r 2:4 + +#$ name: log-v + +hg log -v -r 3 + +#$ name: log-vp + +hg log -v -p -r 2 + +#$ name: reclone + +cd .. +hg clone hello my-hello +cd my-hello + +#$ name: cat1 +cat hello.c + +#$ name: + +sed -i '/printf/a\\tprintf("hello again!\\n");' hello.c + +#$ name: cat2 +# ... edit edit edit ... +cat hello.c + +#$ name: status + +ls +hg status + +#$ name: diff + +hg diff + +#$ name: + +export HGEDITOR='echo Added an extra line of output >' + +#$ name: commit + +hg commit + +#$ name: merge.dummy1 + +hg log -r 5 | grep changeset | cut -c 16-19 2>/dev/null > /tmp/REV5.my-hello + +#$ name: tip + +hg tip -vp + +#$ name: clone-pull + +cd .. +hg clone hello hello-pull + +#$ name: incoming + +cd hello-pull +hg incoming ../my-hello + +#$ name: pull + +hg tip +hg pull ../my-hello +hg tip + +#$ name: update + +grep printf hello.c +hg update tip +grep printf hello.c + +#$ name: parents + +hg parents + +#$ name: older + +hg update 2 +hg parents +hg update + +#$ name: clone-push + +cd .. +hg clone hello hello-push + +#$ name: outgoing + +cd my-hello +hg outgoing ../hello-push + +#$ name: push + +hg push ../hello-push + +#$ name: push.nothing + +hg push ../hello-push + +#$ name: outgoing.net + +hg outgoing http://hg.serpentine.com/tutorial/hello + +#$ name: push.net + +hg push http://hg.serpentine.com/tutorial/hello + +#$ name: +cp hello.c ../new-hello.c +sed -i '/printf/i\\tprintf("once more, hello.\\n");' ../new-hello.c + +#$ name: merge.clone + +cd .. +hg clone hello my-new-hello +cd my-new-hello +# The file new-hello.c is lightly edited. +cp ../new-hello.c hello.c +hg commit -m 'A new hello for a new day.' + +#$ name: merge.dummy2 + +hg log -r 5 | grep changeset | cut -c 16-19 2>/dev/null > /tmp/REV5.my-new-hello + +#$ name: merge.cat + +cat hello.c +cat ../my-hello/hello.c + +#$ name: merge.pull + +hg pull ../my-hello + +#$ name: merge.dummy3 + +hg log -r 6 | grep changeset | cut -c 16-19 2>/dev/null > /tmp/REV6.my-new-hello + +#$ name: merge.heads + +hg heads + +#$ name: merge.update + +hg update + +#$ name: merge.merge + +hg merge + +#$ name: merge.parents + +hg parents +cat hello.c + +#$ name: merge.commit + +hg commit -m 'Merged changes' + +#$ name: merge.dummy4 + +hg log -r 7 | grep changeset | cut -c 16-19 2>/dev/null > /tmp/REV7.my-new-hello + +#$ name: merge.tip + +hg tip
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour-merge-conflict Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,73 @@ +#!/bin/bash + +hg init scam +cd scam + +#$ name: wife + +cat > letter.txt <<EOF +Greetings! + +I am Mariam Abacha, the wife of former +Nigerian dictator Sani Abacha. +EOF + +hg add letter.txt +hg commit -m '419 scam, first draft' + +#$ name: cousin + +cd .. +hg clone scam scam-cousin +cd scam-cousin + +cat > letter.txt <<EOF +Greetings! + +I am Shehu Musa Abacha, cousin to the former +Nigerian dictator Sani Abacha. +EOF + +hg commit -m '419 scam, with cousin' + +#$ name: son + +cd .. +hg clone scam scam-son +cd scam-son + +cat > letter.txt <<EOF +Greetings! + +I am Alhaji Abba Abacha, son of the former +Nigerian dictator Sani Abacha. +EOF + +hg commit -m '419 scam, with son' + +#$ name: pull + +cd .. +hg clone scam-cousin scam-merge +cd scam-merge +hg pull -u ../scam-son + +#$ name: merge +#$ ignore: [<>]{7} /tmp/.* + +export HGMERGE=merge +hg merge +cat letter.txt + +#$ name: commit + +cat > letter.txt <<EOF +Greetings! + +I am Bryan O'Sullivan, no relation of the former +Nigerian dictator Sani Abacha. +EOF + +hg resolve -m letter.txt +hg commit -m 'Send me your money' +hg tip
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour-merge-conflict.commit.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,15 @@ +$ \textbf{cat > letter.txt <<EOF} +> \textbf{Greetings!} +> \textbf{I am Bryan O'Sullivan, no relation of the former} +> \textbf{Nigerian dictator Sani Abacha.} +> \textbf{EOF} +$ \textbf{hg commit -m 'Send me your money'} +$ \textbf{hg tip} +changeset: +tag: tip +parent: +parent: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Send me your money +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour-merge-conflict.cousin.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{cd ..} +$ \textbf{hg clone scam scam-cousin} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd scam-cousin} +$ \textbf{cat > letter.txt <<EOF} +> \textbf{Greetings!} +> \textbf{I am Shehu Musa Abacha, cousin to the former} +> \textbf{Nigerian dictator Sani Abacha.} +> \textbf{EOF} +$ \textbf{hg commit -m '419 scam, with cousin'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour-merge-conflict.merge.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,17 @@ +$ \textbf{export HGMERGE=merge} +$ \textbf{hg merge} +merging letter.txt +merge: warning: conflicts during merge +merging letter.txt failed! +0 files updated, 0 files merged, 0 files removed, 1 files unresolved +There are unresolved merges, you can redo the full merge using: + hg update -C 1 + hg merge 2 +$ \textbf{cat letter.txt} +Greetings! + +I am Shehu Musa Abacha, cousin to the former +======= +I am Alhaji Abba Abacha, son of the former + +Nigerian dictator Sani Abacha.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour-merge-conflict.pull.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{cd ..} +$ \textbf{hg clone scam-cousin scam-merge} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd scam-merge} +$ \textbf{hg pull -u ../scam-son} +pulling from ../scam-son +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files (+1 heads) +not updating, since new heads added +(run 'hg heads' to see heads, 'hg merge' to merge)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour-merge-conflict.son.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{cd ..} +$ \textbf{hg clone scam scam-son} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd scam-son} +$ \textbf{cat > letter.txt <<EOF} +> \textbf{Greetings!} +> \textbf{I am Alhaji Abba Abacha, son of the former} +> \textbf{Nigerian dictator Sani Abacha.} +> \textbf{EOF} +$ \textbf{hg commit -m '419 scam, with son'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour-merge-conflict.wife.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{cat > letter.txt <<EOF} +> \textbf{Greetings!} +> \textbf{I am Mariam Abacha, the wife of former} +> \textbf{Nigerian dictator Sani Abacha.} +> \textbf{EOF} +$ \textbf{hg add letter.txt} +$ \textbf{hg commit -m '419 scam, first draft'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.clone-pull.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cd ..} +$ \textbf{hg clone hello hello-pull} +2 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.clone-push.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cd ..} +$ \textbf{hg clone hello hello-push} +2 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.clone.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg clone http://hg.serpentine.com/tutorial/hello} +destination directory: hello +requesting all changes +adding changesets +adding manifests +adding file changes +added 5 changesets with 5 changes to 2 files +2 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.commit.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1 @@ +$ \textbf{hg commit}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.diff.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,11 @@ +$ \textbf{hg diff} +diff -r hello.c + + +@@ -8,5 +8,6 @@ int main(int argc, char **argv) + int main(int argc, char **argv) + \{ + printf("hello, world!\textbackslash{}"); ++ printf("hello again!\textbackslash{}n"); + return 0; + \}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.help.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,20 @@ +$ \textbf{hg help init} +hg init [-e CMD] [--remotecmd CMD] [DEST] + +create a new repository in the given directory + + Initialize a new repository in the given directory. If the given + directory does not exist, it is created. + + If no directory is given, the current directory is used. + + It is possible to specify an ssh:// URL as the destination. + Look at the help text for the pull command for important details + about ssh:// URLs. + +options: + + -e --ssh specify ssh command to use + --remotecmd specify hg command to run on the remote side + +use "hg -v help init" to show global options
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.incoming.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{cd hello-pull} +$ \textbf{hg incoming ../my-hello} +comparing with ../my-hello +searching for changes +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added an extra line of output +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.log-r.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,24 @@ +$ \textbf{hg log -r 3} +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Get make to generate the final binary from a .o file. + +$ \textbf{hg log -r } +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Get make to generate the final binary from a .o file. + +$ \textbf{hg log -r 1 -r 4} +changeset: +user: mpm@selenic.com + +summary: Create a makefile + +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Trim comments. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.log-v.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +$ \textbf{hg log -v -r 3} +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +files: Makefile +description: +Get make to generate the final binary from a .o file. + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.log-vp.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,21 @@ +$ \textbf{hg log -v -p -r 2} +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +files: hello.c +description: +Introduce a typo into hello.c. + + +diff -r -r hello.c + + +@@ -11,6 +11,6 @@ + + int main(int argc, char **argv) + \{ +- printf("hello, world!\textbackslash{}n"); ++ printf("hello, world!\textbackslash{}"); + return 0; + \} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.log.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,27 @@ +$ \textbf{hg log} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Trim comments. + +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Get make to generate the final binary from a .o file. + +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Introduce a typo into hello.c. + +changeset: +user: mpm@selenic.com + +summary: Create a makefile + +changeset: +user: mpm@selenic.com + +summary: Create a standard "hello, world" program +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.log.range.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,17 @@ +$ \textbf{hg log -r 2:4} +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Introduce a typo into hello.c. + +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Get make to generate the final binary from a .o file. + +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Trim comments. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.ls-a.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,3 @@ +$ \textbf{cd hello} +$ \textbf{ls -a} +. .. .hg Makefile hello.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.ls.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,5 @@ +$ \textbf{ls -l} +total 4 + +$ \textbf{ls hello} +Makefile hello.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.merge.cat.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,28 @@ +$ \textbf{cat hello.c} +/* + * Placed in the public domain by Bryan O'Sullivan. This program is + * not covered by patents in the United States or other countries. + */ + +#include <stdio.h> + +int main(int argc, char **argv) +\{ + printf("once more, hello.\textbackslash{}n"); + printf("hello, world!\textbackslash{}"); + return 0; +\} +$ \textbf{cat ../my-hello/hello.c} +/* + * Placed in the public domain by Bryan O'Sullivan. This program is + * not covered by patents in the United States or other countries. + */ + +#include <stdio.h> + +int main(int argc, char **argv) +\{ + printf("hello, world!\textbackslash{}"); + printf("hello again!\textbackslash{}n"); + return 0; +\}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.merge.clone.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ +$ \textbf{cd ..} +$ \textbf{hg clone hello my-new-hello} +2 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd my-new-hello} +$ \textbf{sed -i '/printf/i\textbackslash{}\textbackslash{}tprintf("once more, hello.\textbackslash{}\textbackslash{}n");' hello.c} +$ \textbf{hg commit -m 'A new hello for a new day.'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.merge.commit.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1 @@ +$ \textbf{hg commit -m 'Merged changes'}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.merge.heads.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,13 @@ +$ \textbf{hg heads} +changeset: +tag: tip +parent: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added an extra line of output + +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: A new hello for a new day. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.merge.merge.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg merge} +merging hello.c +0 files updated, 1 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.merge.parents.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,28 @@ +$ \textbf{hg parents} +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: A new hello for a new day. + +changeset: +tag: tip +parent: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added an extra line of output + +$ \textbf{cat hello.c} +/* + * Placed in the public domain by Bryan O'Sullivan. This program is + * not covered by patents in the United States or other countries. + */ + +#include <stdio.h> + +int main(int argc, char **argv) +\{ + printf("once more, hello.\textbackslash{}n"); + printf("hello, world!\textbackslash{}"); + printf("hello again!\textbackslash{}n"); + return 0; +\}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.merge.pull.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +$ \textbf{hg pull ../my-hello} +pulling from ../my-hello +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files (+1 heads) +(run 'hg heads' to see heads, 'hg merge' to merge)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.merge.tip.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +$ \textbf{hg tip} +changeset: +tag: tip +parent: +parent: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Merged changes +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.merge.update.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2 @@ +$ \textbf{hg update} +abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.older.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{hg update 2} +2 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{hg parents} +changeset: +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Introduce a typo into hello.c. + +$ \textbf{hg update} +2 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.outgoing.net.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +$ \textbf{hg outgoing http://hg.serpentine.com/tutorial/hello} +comparing with http://hg.serpentine.com/tutorial/hello +searching for changes +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added an extra line of output +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.outgoing.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,10 @@ +$ \textbf{cd my-hello} +$ \textbf{hg outgoing ../hello-push} +comparing with ../hello-push +searching for changes +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added an extra line of output +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.parents.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{hg parents} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added an extra line of output +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.pull.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,22 @@ +$ \textbf{hg tip} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Trim comments. + +$ \textbf{hg pull ../my-hello} +pulling from ../my-hello +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +(run 'hg update' to get a working copy) +$ \textbf{hg tip} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +summary: Added an extra line of output +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.push.net.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg push http://hg.serpentine.com/tutorial/hello} +pushing to http://hg.serpentine.com/tutorial/hello +searching for changes +ssl required
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.push.nothing.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{hg push ../hello-push} +pushing to ../hello-push +searching for changes +no changes found
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.push.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{hg push ../hello-push} +pushing to ../hello-push +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.reclone.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{cd ..} +$ \textbf{hg clone hello my-hello} +2 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{cd my-hello}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.sed.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1 @@ +$ \textbf{sed -i '/printf/a\textbackslash{}\textbackslash{}tprintf("hello again!\textbackslash{}\textbackslash{}n");' hello.c}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.status.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +$ \textbf{ls} +Makefile hello.c +$ \textbf{hg status} +M hello.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.tip.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,21 @@ +$ \textbf{hg tip -vp} +changeset: +tag: tip +user: Bryan O'Sullivan <bos@serpentine.com> + +files: hello.c +description: +Added an extra line of output + + +diff -r -r hello.c + + +@@ -8,5 +8,6 @@ int main(int argc, char **argv) + int main(int argc, char **argv) + \{ + printf("hello, world!\textbackslash{}"); ++ printf("hello again!\textbackslash{}n"); + return 0; + \} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.update.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,7 @@ +$ \textbf{grep printf hello.c} + printf("hello, world!\textbackslash{}"); +$ \textbf{hg update tip} +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +$ \textbf{grep printf hello.c} + printf("hello, world!\textbackslash{}"); + printf("hello again!\textbackslash{}n");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/examples/tour.version.out Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ +$ \textbf{hg version} +Mercurial Distributed SCM (version ) + +Copyright (C) 2005-2007 Matt Mackall <mpm@selenic.com> and others +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/fblinks Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,67 @@ +#!/usr/bin/python + +import errno +import os +import re +import sys + +hg_id = sys.argv[1] + +dest_dir = sys.argv[2] + +empty_re = re.compile(r'^\s*$') +line_re = re.compile(r'^(\w+)(.*)') + +try: + os.makedirs(dest_dir) +except OSError, err: + if err.errno != errno.EEXIST: + raise + +def feedback(name, text, ctx_id): + return r'\marginpar{\scriptsize \href{http://demesne:8000/book/feedback/submit/%s/%s/%d/}{Feedback}}' % (hg_id, name, ctx_id) + +ctxs = {} +try: + cfp = open(os.path.join(dest_dir, 'rev-' + hg_id + '.ctx'), 'r+') + for line in cfp: + f, l, c = line.split(':', 2) + ctxs[(f, int(l))] = c.strip() +except IOError, err: + if err.errno != errno.ENOENT: raise + cfp = open(os.path.join(dest_dir, 'rev-' + hg_id + '.ctx'), 'w+') + +changes = 0 + +for name in sys.argv[3:]: + if not name.endswith('.tex'): + continue + dest_name = os.path.join(dest_dir, name) + ifp = open(name) + ofp = open(dest_name, 'w') + new_par = True + line_num = 0 + par_num = 0 + for line in ifp: + line_num += 1 + if new_par: + m = line_re.match(line) + if m: + par_num += 1 + ls = line.strip() + if ctxs.get((name, par_num)) != ls: + ctxs[(name, par_num)] = ls + changes += 1 + line = m.group(1) + feedback(name, line, par_num) + m.group(2) + new_par = False + elif not line.strip(): + new_par = True + ofp.write(line) + +if changes: + cfp.seek(0) + print '%s: %d changes' % (cfp.name, changes) + ctxs = ctxs.items() + ctxs.sort() + for ((file, line), content) in ctxs: + cfp.write('%s:%d: %s\n' % (file, line, content))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/feature-branches.dot Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +digraph feature_branches { + master -> crypto; + master -> filesystems; + master -> ipc; + master -> memory; + master -> network; + master -> security; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/filelog.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,373 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.45.1" + sodipodi:docname="filelog.svg" + sodipodi:docbase="/home/arun/hgbook/en" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path3128" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + <linearGradient + id="linearGradient2887"> + <stop + style="stop-color:#91cfcf;stop-opacity:1;" + offset="0" + id="stop2889" /> + <stop + style="stop-color:aqua;stop-opacity:0;" + offset="1" + id="stop2891" /> + </linearGradient> + <linearGradient + id="linearGradient2795"> + <stop + style="stop-color:#ccc;stop-opacity:1;" + offset="0" + id="stop2797" /> + <stop + style="stop-color:#ccc;stop-opacity:0;" + offset="1" + id="stop2799" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2795" + id="linearGradient3170" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(121.2183,94.95434)" + x1="81.322357" + y1="404.34424" + x2="201.52036" + y2="373.03967" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2887" + id="linearGradient3172" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(0,12)" + x1="62.634491" + y1="503.3392" + x2="248.49242" + y2="462.94327" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2795" + id="linearGradient3174" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.001035,0,0,0.653159,236.7075,153.0415)" + x1="81.322357" + y1="404.34424" + x2="201.52036" + y2="373.03967" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2887" + id="linearGradient3176" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(0,12)" + x1="62.634491" + y1="503.3392" + x2="248.49242" + y2="462.94327" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2795" + id="linearGradient3208" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.001035,0,0,0.653159,236.7075,153.0415)" + x1="81.322357" + y1="404.34424" + x2="201.52036" + y2="373.03967" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2887" + id="linearGradient3210" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(0,12)" + x1="62.634491" + y1="503.3392" + x2="248.49242" + y2="462.94327" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2795" + id="linearGradient3212" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(121.2183,94.95434)" + x1="81.322357" + y1="404.34424" + x2="201.52036" + y2="373.03967" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2887" + id="linearGradient3214" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(0,12)" + x1="62.634491" + y1="503.3392" + x2="248.49242" + y2="462.94327" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2795" + id="linearGradient3256" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.2343775,0,0,0.9981848,103.25588,95.681888)" + x1="74.301666" + y1="431.67441" + x2="260.05884" + y2="369.95322" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2887" + id="linearGradient3258" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.228929,0,0,0.9972824,-62.037003,13.312997)" + x1="62.634491" + y1="503.3392" + x2="248.49242" + y2="462.94327" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2795" + id="linearGradient3260" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.2300738,0,0,0.6517275,219.97511,153.61527)" + x1="74.387527" + y1="431.80576" + x2="259.97339" + y2="369.82224" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2887" + id="linearGradient3262" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.2289272,0,0,0.9972824,-62.036756,13.312985)" + x1="62.634491" + y1="503.3392" + x2="248.49242" + y2="462.94327" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4" + inkscape:cx="455.8122" + inkscape:cy="520" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="1680" + inkscape:window-height="970" + inkscape:window-x="0" + inkscape:window-y="54" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + 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" + id="rect3180" + width="273.81375" + height="199.06245" + x="369.1796" + y="351.79019" /> + <rect + 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" + id="rect3178" + width="273.81339" + height="199.06233" + x="72.699799" + y="351.78983" /> + <g + id="g3144" + transform="translate(80.467048,0.71578)"> + <g + id="g2940"> + <rect + 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" + id="rect2914" + width="227.38896" + height="39.500999" + x="311.92496" + y="395.08627" /> + <text + xml:space="preserve" + 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" + x="323.72824" + y="416.7626" + id="text2918"><tspan + sodipodi:role="line" + id="tspan2920" + x="323.72824" + y="416.7626" + style="font-family:Courier">.hg/store/data/README.i</tspan></text> + </g> + <g + transform="translate(3.79093e-5,-80.1853)" + id="g2945"> + <g + id="g2955"> + <rect + y="475.4968" + x="15.550935" + height="39.500999" + width="227.17694" + id="rect2947" + 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" /> + <text + id="text2949" + y="498.35123" + x="31.230644" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="498.35123" + x="31.230644" + id="tspan2951" + sodipodi:role="line">README</tspan></text> + </g> + </g> + <path + inkscape:connector-type="polyline" + id="path2960" + d="M 242.94685,414.91115 C 242.94685,414.91115 293.61127,415.26754 310.16269,415.38633" + 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" + sodipodi:nodetypes="cz" /> + </g> + <g + id="g3156" + transform="translate(80.467048,0.71578)"> + <g + transform="translate(116,0)" + id="g2831"> + <rect + 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" + id="rect1906" + width="228.18446" + height="60.499123" + x="195.52719" + y="465.51859" /> + <g + id="g2803" + transform="translate(-0.893671,1.833581)"> + <text + id="text1884" + y="483.92801" + x="208.95944" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="483.92801" + x="208.95944" + id="tspan1886" + sodipodi:role="line">.hg/store/data/src/hello.c.d</tspan></text> + <text + id="text1888" + y="507.79309" + x="208.95944" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="507.79309" + x="208.95944" + id="tspan1890" + sodipodi:role="line">.hg/store/data/src/hello.c.i</tspan></text> + </g> + </g> + <g + id="g2907"> + <rect + 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" + id="rect2843" + width="227.17728" + height="39.500999" + x="15.550805" + y="475.4968" /> + <text + xml:space="preserve" + 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" + x="31.230644" + y="498.35123" + id="text2847"><tspan + sodipodi:role="line" + id="tspan2849" + x="31.230644" + y="498.35123" + style="font-family:Courier">src/hello.c</tspan></text> + </g> + <path + inkscape:connection-end="#g2831" + inkscape:connection-start="#g2907" + inkscape:connector-type="polyline" + id="path2962" + d="M 242.4315,495.88043 C 242.4315,495.88043 292.8861,495.99942 310.04102,496.03909" + 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" + sodipodi:nodetypes="cs" /> + </g> + <text + xml:space="preserve" + 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" + x="98.496666" + y="373.96353" + id="text3216"><tspan + sodipodi:role="line" + id="tspan3218" + x="98.496666" + y="373.96353">Working directory</tspan></text> + <text + xml:space="preserve" + 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" + x="391.39197" + y="373.96353" + id="text3228"><tspan + sodipodi:role="line" + id="tspan3230" + x="391.39197" + y="373.96353">Repository</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/filenames.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,564 @@ +%\chapter{File names and pattern matching} +\chapter{$B%U%!%$%kL>$H%Q%?!<%s%^%C%A%s%0(B} +\label{chap:names} + +%Mercurial provides mechanisms that let you work with file names in a +%consistent and expressive way. + +Mercurial$B$O%U%!%$%kL>$K$D$$$F0l4S@-$N$"$jJ,$+$j$d$9$$%a%+%K%:%`$rDs6!$9(B +$B$k!%(B + +%\section{Simple file naming} +\section{$B%7%s%W%k$J%U%!%$%kL?L>(B} + +%Mercurial uses a unified piece of machinery ``under the hood'' to +%handle file names. Every command behaves uniformly with respect to +%file names. The way in which commands work with file names is as +%follows. + +Mercurial$B$O%U%!%$%kL>$r<h$j07$&FbIt$N%a%+%K%:%`$r;}$C$F$$$k!%$"$i$f$k%3%^(B +$B%s%I$O%U%!%$%kL>$KBP$7$FF10l$K$U$k$^$&!%%3%^%s%I$,%U%!%$%kL>$r07$&$d$jJ}(B +$B$r0J2<$K<($9!%(B + +%If you explicitly name real files on the command line, Mercurial works +%with exactly those files, as you would expect. +$B%3%^%s%I%i%$%s$K<B:]$N%U%!%$%kL>$rL@<(E*$KM?$($?;~$O!$(BMercurial$B$O$=$l$i(B +$B$N%U%!%$%k$=$N$b$N$r07$&!%(B +\interaction{filenames.files} + +%When you provide a directory name, Mercurial will interpret this as +%``operate on every file in this directory and its subdirectories''. +%Mercurial traverses the files and subdirectories in a directory in +%alphabetical order. When it encounters a subdirectory, it will +%traverse that subdirectory before continuing with the current +%directory. + +$B%G%#%l%/%H%jL>$rM?$($?>l9g$O!$(BMercurial$B$O(B``$B$3$N%G%#%l%/%H%j$H%5%V%G%#%l%/(B +$B%H%jFb$N$9$Y$F$N%U%!%$%k$KBP$7$F=hM}$r9T$&(B''$B$H2r<a$9$k!%(B +Mercurial$B$O%G%#%l%/%H%jFb$N%U%!%$%k$H%5%V%G%#%l%/%H%j$r%"%k%U%!%Y%C%H=g(B +$B$KEO$jJb$/!%%5%V%G%#%l%/%H%j$r8+$D$1$k$H!$%+%l%s%H%G%#%l%/%H%j$N=hM}$rB3(B +$B$1$k$N$G$O$J$/!$%5%V%G%#%l%/%H%jFb$r8+$K9T$/!%(B +\interaction{filenames.dirs} + +%\section{Running commands without any file names} +\section{$B%U%!%$%kL>$J$7$G%3%^%s%I$r<B9T$9$k(B} + +%Mercurial's commands that work with file names have useful default +%behaviours when you invoke them without providing any file names or +%patterns. What kind of behaviour you should expect depends on what +%the command does. Here are a few rules of thumb you can use to +%predict what a command is likely to do if you don't give it any names +%to work with. + +$B%U%!%$%kL>$r<h$k(BMercurial$B%3%^%s%I$O%U%!%$%kL>$d%Q%?!<%s$rM?$($J$$$G5/F0$7(B +$B$?>l9g$G$bM-MQ$J%G%U%)%k%H$N?6Iq$r;}$D!%4|BT$9$k5sF0$O!$2?$r$9$k%3%^%s%I(B +$B$+$K$h$k!%%3%^%s%I$K%U%!%$%kL>Ey$rM?$($J$+$C$?>l9g$K%3%^%s%I$,$I$N$h$&$K(B +$BF0$/$+?dB,$9$kBg$^$+$J%k!<%k$r$$$/$D$+5s$2$k!%(B + +\begin{itemize} +%\item Most commands will operate on the entire working directory. +% This is what the \hgcmd{add} command does, for example. + \item $BBgH>$N%3%^%s%I$O%o!<%-%s%0%G%#%l%/%H%jA4BN$KBP$7$FF/$/!%Nc$($P(B + \hgcmd{add}$B%3%^%s%I$N$U$k$^$$$,$3$l$K$"$?$k!%(B + +%\item If the command has effects that are difficult or impossible to +% reverse, it will force you to explicitly provide at least one name +% or pattern (see below). This protects you from accidentally +% deleting files by running \hgcmd{remove} with no arguments, for +% example. + \item $BI|85$,Fq$7$+$C$?$jIT2DG=$G$"$k$h$&$J8z2L$r;}$D%3%^%s%I$N>l9g!$:GDc(B + 1$B$D$NL>A0$d%Q%?!<%s$rM[$KMW5a$9$k!%!J2<5-$r;2>H!%!K$3$l$K$h$j!$Nc(B + $B$($P(B\hgcmd{remove}$B$K0z?t$rM?$($J$+$C$?$3$H$K$h$C$F8m$C$F%U%!%$%k$r(B + $B$9$Y$F>C$7$?$j$9$k$3$H$,$J$/$J$k!%(B +\end{itemize} + +%It's easy to work around these default behaviours if they don't suit +%you. If a command normally operates on the whole working directory, +%you can invoke it on just the current directory and its subdirectories +%by giving it the name ``\dirname{.}''. +%\interaction{filenames.wdir-subdir} + +$B%G%U%)%k%H$N5sF0$,5$$KF~$i$J$$>l9g!$$3$l$rJQ99$9$k$N$O$?$d$9$$!%(B +$B%3%^%s%I$,DL>o%o!<%-%s%0%G%#%l%/%H%jA4BN$KBP$7$FF0:n$9$k$H$7$h$&!%(B +$B$3$l$r%+%l%s%H%G%#%l%/%H%j$H$=$N%5%V%G%#%l%/%H%j$KBP$7$F$N$_F0:n$9$k$h$&(B +$B$KJQ$($k$K$O!$(B``\dirname{.}''$B$rEO$;$PNI$$!%(B +\interaction{filenames.wdir-subdir} + +%Along the same lines, some commands normally print file names relative +%to the root of the repository, even if you're invoking them from a +%subdirectory. Such a command will print file names relative to your + +%subdirectory if you give it explicit names. Here, we're going to run + +%\hgcmd{status} from a subdirectory, and get it to operate on the +%entire working directory while printing file names relative to our + +%subdirectory, by passing it the output of the \hgcmd{root} command. +%\interaction{filenames.wdir-relname} + +$B%5%V%G%#%l%/%H%j$+$i5/F0$7$F$b%j%]%8%H%j$N%k!<%H$X$NAjBP%Q%9$G%U%!%$%kL>(B +$B$rI=<($9$k%3%^%s%I$b$"$k!%$=$N$h$&$J%3%^%s%I$G$O!$%5%V%G%#%l%/%H%j$NL>A0(B +$B$rL@<(E*$KM?$($k$H!$%5%V%G%#%l%/%H%j$+$i$NAjBP%Q%9$rI=<($9$k$h$&$K$J$k!%(B + +$B$3$3$G$O%5%V%G%#%l%/%H%j$+$i(B\hgcmd{status}$B$r<B9T$9$k:]$K!$(B + + +$B$7$F!$(B +$B%3%^%s%I$,%o!<%-%s%0%G%#%l%/%H%jA4BN$N%U%!%$%kL>$r%5%V%G%#%l%/%H%j$KBP$7$FAjBPE*$K(B +$BI=<($9$kMM$r8+$F$_$h$&!%(B + + + + +%\section{Telling you what's going on} +\section{$B2?$,5/$-$F$$$k$N$+(B} + +%The \hgcmd{add} example in the preceding section illustrates something +%else that's helpful about Mercurial commands. If a command operates +%on a file that you didn't name explicitly on the command line, it will +%usually print the name of the file, so that you will not be surprised +%what's going on. + +$BA0%;%/%7%g%s$N(B\hgcmd{add}$B$NNc$O(BMercurial$B%3%^%s%I$K$D$$$FJL$NM-MQ$J>pJs$r(B +$B<($7$F$$$k!%%3%^%s%I%i%$%s$GL@<(E*$KL>A0$r;XDj$7$J$+$C$?%U%!%$%k$KBP$7$F(B +$B%3%^%s%I=hM}$r9T$&>l9g!$%U%!%$%kL>$rI=<($7!$2?$,5/$3$C$F$$$k$N$+J,$+$i$J(B +$B$/$J$i$J$$$h$&$K$7$F$$$k!%(B + +%The principle here is of \emph{least surprise}. If you've exactly +%named a file on the command line, there's no point in repeating it +%back at you. If Mercurial is acting on a file \emph{implicitly}, +%because you provided no names, or a directory, or a pattern (see +%below), it's safest to tell you what it's doing. + +\emph{$B$G$-$k$@$1$S$C$/$j$5$;$J$$(B}$B$H$$$&$N$,$3$3$G$N86B'$G$"$k!%%3%^%s%I%i(B +$B%$%s$G%U%!%$%kL>$r40A4$K;XDj$7$?>l9g!$%U%!%$%kL>$,I=<($5$l$k$3$H$O$J$$!%(B +Mercurial$B$O!$L>A0$rM?$($J$$$+!$%G%#%l%/%H%jL>!$0J2<$G2r@b$9$k%Q%?!<%s$rM?(B +$B$($?$?$a$K(B\emph{$B0EL[E*$K(B}$B;XDj$5$l$?%U%!%$%k$KBP$7$F%"%/%7%g%s$9$k>l9g$O!$(B +$B:G$b0BA4$J$d$jJ}$H$7$F!$8=:_$7$F$$$k$3$H$rI=<($9$k!%(B + +%For commands that behave this way, you can silence them using the +%\hggopt{-q} option. You can also get them to print the name of every +%file, even those you've named explicitly, using the \hggopt{-v} +%option. + +$B$3$N$h$&$K?6Iq$&%3%^%s%I$r!$(B\hggopt{-q}$B%*%W%7%g%s$rM?$($k$3$H$GD@L[$5$;$k(B +$B$3$H$b$G$-$k!%5U$KL@<(E*$K;XDj$7$?%U%!%$%k$X$NF0:n$G$"$C$F$b(B\hggopt{-v}$B%*(B +$B%W%7%g%s$rM?$($k$3$H$G$9$Y$F$N%U%!%$%kL>$rI=<($5$;$k$3$H$b$G$-$k!%(B + +%\section{Using patterns to identify files} +\section{$B%U%!%$%kL><1JL$K%Q%?!<%s$rMQ$$$k(B} + +%In addition to working with file and directory names, Mercurial lets +%you use \emph{patterns} to identify files. Mercurial's pattern +%handling is expressive. + +$B%U%!%$%k$d%G%#%l%/%H%jL>$r;H$C$?F0:n$NB>$K!$(BMercurial$B$G$O(B\emph{patterns} +$B$r;H$C$F%U%!%$%k$r<1JL$9$k$3$H$b$G$-$k!%(BMercurial$B$N%Q%?!<%s=hM}$O6/NO$G(B +$B$"$k!%(B + +%On Unix-like systems (Linux, MacOS, etc.), the job of matching file +%names to patterns normally falls to the shell. On these systems, you +%must explicitly tell Mercurial that a name is a pattern. On Windows, +%the shell does not expand patterns, so Mercurial will automatically +%identify names that are patterns, and expand them for you. + +Unix$B7O$N%7%9%F%`(B(Linux, MacOS$BEy(B)$B$G$O%U%!%$%kL>$H%Q%?!<%s$r%^%C%A$5$;$k;E(B +$B;v$O%7%'%k$KG$$5$l$k!%$3$l$i$N%7%9%F%`$G$O!$L>A0$,%Q%?!<%s$G$"$k$3$H$rL@(B +$B<(E*$K(BMercurial$B$K<($5$J$1$l$P$J$i$J$$!%(B Windows$B$G$O%7%'%k$O%Q%?!<%s$rE83+(B +$B$7$J$$$N$G!$(BMercurial$B$OM?$($i$l$?L>A0$,<+F0E*$K%Q%?!<%s$G$"$k$3$H$rG'<1(B +$B$7!$E83+$9$k!%(B + +%To provide a pattern in place of a regular name on the command line, +%the mechanism is simple: + +$B%3%^%s%I%i%$%s$GDL>o$NL>A0$NBe$o$j$K%Q%?!<%s$rEO$9$?$a$N%a%+%K%:%`$O%7%s(B +$B%W%k$G$"$k!%(B: +\begin{codesample2} + syntax:patternbody +\end{codesample2} +%That is, a pattern is identified by a short text string that says what +%kind of pattern this is, followed by a colon, followed by the actual +%pattern. + +$B$I$N$h$&$J%Q%?!<%s$J$N$+$r<1JL$9$k$?$a$NC;$$%F%-%9%H$N8e$m$K%3%m%s$r64$s(B +$B$G<B:]$N%Q%?!<%s$,B3$/!%(B + +%Mercurial supports two kinds of pattern syntax. The most frequently +%used is called \texttt{glob}; this is the same kind of pattern +%matching used by the Unix shell, and should be familiar to Windows +%command prompt users, too. + +Mercurial$B$O(B2$BDL$j$N%Q%?!<%s9=J8$r%5%]!<%H$9$k!%:G$b$h$/;H$o$l$k$N$O(B +\texttt{glob};$B$G!$(BUnix$B%7%'%k$,%Q%?!<%s%^%C%A%s%0$K;HMQ$7$F$$$k$b$N$HF1MM(B +$B$N%Q%?!<%s$G$"$j!$$3$l$O(BWindows$B$N%3%^%s%I%W%m%s%W%H%f!<%6$K$H$C$F$b?F$7(B +$B$_?<$$$b$N$G$"$k!%(B + +%When Mercurial does automatic pattern matching on Windows, it uses +%\texttt{glob} syntax. You can thus omit the ``\texttt{glob:}'' prefix +%on Windows, but it's safe to use it, too. + +Mercurial$B$O(BWindows$B$G$O<+F0E*$K%Q%?!<%s%^%C%A%s%0$r9T$&$H$-(B +$B$O!$(B\texttt{glob}$B9=J8$rMQ$$$k!%=>$C$F(BWindows$B$G$O(B``\texttt{glob:}''$B%W%l%U%#(B +$B%/%9$r>JN,$7$F$b0BA4$G$"$k!%(B + +%The \texttt{re} syntax is more powerful; it lets you specify patterns +%using regular expressions, also known as regexps. + +\texttt{re}$B9=J8$O$h$j6/NO$G!$@55,I=8=$rMQ$$$k$3$H$,$G$-$k!%(B + +%By the way, in the examples that follow, notice that I'm careful to +%wrap all of my patterns in quote characters, so that they won't get +%expanded by the shell before Mercurial sees them. + +$B8e$G<($9Nc$G$O!$(BMercurial$B$,8+$kA0$K%7%'%k$GE83+$5$l$k$N$rKI$0$?$a$K%Q%?!<(B +$B%s$r0zMQJ8;z$G$/$k$s$G$$$k$3$H$KCm0U$5$l$?$$!%(B + +%\subsection{Shell-style \texttt{glob} patterns} +\subsection{$B%7%'%k7A<0$N(B\texttt{glob}$B%Q%?!<%s(B} + +%This is an overview of the kinds of patterns you can use when you're +%matching on glob patterns. + +glob$B%Q%?!<%s$G%^%C%A%s%0$r9T$&;~$K;H$($k%Q%?!<%s$N35N,$r<($9!%(B + +%The ``\texttt{*}'' character matches any string, within a single +%directory. + +``\texttt{*}''$BJ8;z$O%G%#%l%/%H%jFb$NG$0U$NJ8;zNs$H%^%C%A$9$k!%(B + +\interaction{filenames.glob.star} + +%The ``\texttt{**}'' pattern matches any string, and crosses directory +%boundaries. It's not a standard Unix glob token, but it's accepted by +%several popular Unix shells, and is very useful. +%\interaction{filenames.glob.starstar} + +``\texttt{**}''$B%Q%?!<%s$O%G%#%l%/%H%j$r1[$($FG$0U$NJ8;zNs$K%^%C%A$9$k!%$3(B +$B$l$O(BUnix$BI8=`$N(Bglob$B%H!<%/%s$G$O$J$$$,!$$$$/$D$+$N?M5$$N$"$k(BUnix$B%7%'%k$G;H(B +$B$&$3$H$,$G$-!$$H$F$bM-MQ$G$"$k!%(B +\interaction{filenames.glob.starstar} + +%The ``\texttt{?}'' pattern matches any single character. +%\interaction{filenames.glob.question} + +``\texttt{?}''$B%Q%?!<%s$OG$0U$N(B1$BJ8;z$K%^%C%A$9$k!%(B +\interaction{filenames.glob.question} + +%The ``\texttt{[}'' character begins a \emph{character class}. This +%matches any single character within the class. The class ends with a +%``\texttt{]}'' character. A class may contain multiple \emph{range}s +%of the form ``\texttt{a-f}'', which is shorthand for +%``\texttt{abcdef}''. + +``\texttt{[}''$BJ8;z$O(B\emph{$BJ8;z%/%i%9(B}$B$r3+;O$9$k!%$3$l$O%/%i%9Fb$NG$0U$N(B1 +$BJ8;z$K%^%C%A$9$k!%%/%i%9$O(B``\texttt{]}''$BJ8;z$G=*$k!%%/%i%9$O(B +``\texttt{a-f}''$B$N$h$&$JHO0O$rJ#?t;}$D$3$H$,$G$-$k!%$3$NHO0O$O(B +``\texttt{abcdef}''$B$NC;=L7A$KAjEv$9$k!%(B +\interaction{filenames.glob.range} + +%If the first character after the ``\texttt{[}'' in a character class +%is a ``\texttt{!}'', it \emph{negates} the class, making it match any +%single character not in the class. + +$BJ8;z%/%i%9$G(B``\texttt{[}''$B$N8e$K(B``\texttt{!}''$B$,Mh$?>l9g!$$3$l$O%/%i%9$N(B +$BH]Dj$H$J$j!$%/%i%9$K4^$^$l$J$$G$0U$N(B1$BJ8;z$H%^%C%A$9$k!%(B + +%A ``\texttt{\{}'' begins a group of subpatterns, where the whole group +%matches if any subpattern in the group matches. The ``\texttt{,}'' +%character separates subpatterns, and ``\texttt{\}}'' ends the group. + +``\texttt{\{}''$B$O%5%V%Q%?!<%s$N%0%k!<%W$r3+;O$9$k!%%0%k!<%W$G$O!$%0%k!<%W(B +$BFb$NG$0U$N%5%V%Q%?!<%s$,%^%C%A$9$l$P%0%k!<%WA4BN$,%^%C%A$7$?$3$H$K$J$k!%(B +``\texttt{,}''$BJ8;z$O%5%V%Q%?!<%s$rJ,N%$7!$(B``\texttt{\}}''$B$O%0%k!<%W$r=*N;(B +$B$9$k!%(B +\interaction{filenames.glob.group} + +%\subsubsection{Watch out!} +\subsubsection{$B$3$3$KCm0U!*(B} + +%Don't forget that if you want to match a pattern in any directory, you +%should not be using the ``\texttt{*}'' match-any token, as this will +%only match within one directory. Instead, use the ``\texttt{**}'' +%token. This small example illustrates the difference between the two. + +$BG$0U$N%G%#%l%/%H%j$G%Q%?!<%s$r%^%C%A$5$;$k>l9g!$(B``\texttt{*}''$B$rA4$F$H%^%C(B +$B%A$9$k%H!<%/%s$H$7$F;H$&$3$H$O$G$-$J$$!%$3$NJ8;z$O(B1$B$D$N%G%#%l%/%H%jFb$G$N(B +$B$_%^%C%A$9$k!%$=$NBe$o$j!$(B``\texttt{**}''$B%H!<%/%s$r;H$&!%$3$l$i$N0c$$$r@b(B +$BL@$9$k$?$a$KNc$r<($9!%(B + +\interaction{filenames.glob.star-starstar} + +%\subsection{Regular expression matching with \texttt{re} patterns} +\subsection{\texttt{re}$B%Q%?!<%s$r;H$C$?@55,I=8=%^%C%A(B} + +%Mercurial accepts the same regular expression syntax as the Python +%programming language (it uses Python's regexp engine internally). +%This is based on the Perl language's regexp syntax, which is the most +%popular dialect in use (it's also used in Java, for example). + +Mercurial$B$O(BPython$B8@8l$HF1$8@55,I=8=9=J8$r<u$1IU$1$k!%!J(BMercurial$B$OFbIt$G(B +Python$B$N@55,I=8=%(%s%8%s$r;H$C$F$$$k!%!K$3$l$O(BPerl$B$N(Bregexp$B9=J8$r85$K$7$F(B +$B$$$k!%$3$N9=J8$O:G$b$h$/MQ$$$i$l$F$$$k$b$N$G$"$j!$$?$H$($P(BJava$B$G$bMxMQ$5(B +$B$l$F$$$k!%(B + +%I won't discuss Mercurial's regexp dialect in any detail here, as +%regexps are not often used. Perl-style regexps are in any case +%already exhaustively documented on a multitude of web sites, and in +%many books. Instead, I will focus here on a few things you should +%know if you find yourself needing to use regexps with Mercurial. + +regexp$B$,$=$l$[$I;H$o$l$F$$$J$$$+$N$h$&$K$3$3$G(BMercurial$B$N(Bregexp$B9=J8$K$D$$(B +$B$F5DO@$9$k$3$H$OHr$1$k!%(B Perl$B%9%?%$%k(Bregexp$B$O$9$G$KB?$/$N%&%'%V%5%$%H$d=q(B +$B@R$G$G>\:Y$KEO$C$F@bL@$5$l$F$$$k!%$=$NBe$o$j!$$3$3$G$O(BMercurial$B$G(Bregexp$B$r(B +$B;H$&:]$KCN$C$F$*$/$Y$-$$$/$D$+$NE@$K>GE@$rEv$F$k$3$H$K$9$k!%(B + +%A regexp is matched against an entire file name, relative to the root +%of the repository. In other words, even if you're already in +%subbdirectory \dirname{foo}, if you want to match files under this +%directory, your pattern must start with ``\texttt{foo/}''. + +regexp$B$O%U%!%$%kL>A4BN$H%^%C%A$9$k$,!$%U%!%$%kL>$O%j%]%8%H%j$N%k!<%H$+$i(B +$B$NAjBP%Q%9$GI=$5$l$k!%8@$$BX$($l$P!$$9$G$K%5%V%G%#%l%/%H%j(B\dirname{foo}$B$K(B +$B$$$k$H$7$F!$$3$N%G%#%l%/%H%jFb$N%U%!%$%k$K%^%C%A$5$;$?$1$l(B +$B$P!$(B``\texttt{foo/}''$B$G;O$^$k%Q%?!<%s$rEO$9I,MW$,$"$k!%(B + +%One thing to note, if you're familiar with Perl-style regexps, is that +%Mercurial's are \emph{rooted}. That is, a regexp starts matching +%against the beginning of a string; it doesn't look for a match +%anywhere within the string. To match anywhere in a string, start +%your pattern with ``\texttt{.*}''. + +Perl$B7A<0$N(Bregexp$B$K47$l$F$$$k$N$J$i!$(BMercurial$B$N(Bregexp$B$O(B\emph{root}$B$r;}$D(B +$B$H$$$&E@$KCm0U$7$F$*$/$H$h$$!%$9$J$o$A!$(Bregexp$B$OJ8;zNs$N;O$^$j$+$i%^%C%A(B +$B$7!$J8;zNs$NESCf$+$i$O%^%C%A$7$J$$!%J8;zNs$NESCf$+$i%^%C%A$5$;$?$$>l9g(B +$B$O!$%Q%?!<%s$r(B``\texttt{.*}''$B$G;O$a$kI,MW$,$"$k!%(B + +%\section{Filtering files} +\section{$B%U%!%$%k$r%U%#%k%?$9$k(B} + +%Not only does Mercurial give you a variety of ways to specify files; +%it lets you further winnow those files using \emph{filters}. Commands +%that work with file names accept two filtering options. + +Mercurial$B$O%U%!%$%k$r;XDj$9$kMM!9$JJ}K!$rDs6!$9$k$@$1$G$J$/!$$5$i$K(B +\emph{$B%U%#%k%?(B}$B$K$h$C$F%U%!%$%k$rA*JL$9$kJ}K!$rDs6!$9$k!%%U%!%$%kL>$r<h$C(B +$B$FF0:n$9$k%3%^%s%I$O(B2$B$D$N%U%#%k%?%*%W%7%g%s$r<u$1IU$1$k!%(B + +\begin{itemize} +%\item \hggopt{-I}, or \hggopt{--include}, lets you specify a pattern +% that file names must match in order to be processed. + \item \hggopt{-I}$B$^$?$O(B\hggopt{--include}$B%*%W%7%g%s$G;XDj$7$?%Q%?!<%s$K(B + $B%^%C%A$7$?%U%!%$%k$,=hM}$5$l$k!%(B +%\item \hggopt{-X}, or \hggopt{--exclude}, gives you a way to +% \emph{avoid} processing files, if they match this pattern. + \item \hggopt{-X}$B$^$?$O(B\hggopt{--exclude}$B%*%W%7%g%s$G;XDj$7$?%Q%?!<%s$K(B + $B%^%C%A$7$?%U%!%$%k$O=hM}$+$i=|30$5$l$k!%(B +\end{itemize} + +%You can provide multiple \hggopt{-I} and \hggopt{-X} options on the +%command line, and intermix them as you please. Mercurial interprets +%the patterns you provide using glob syntax by default (but you can use +%regexps if you need to). + +$B%3%^%s%I%i%$%s$GJ#?t$N(B\hggopt{-I}$B$*$h$S(B\hggopt{-X}$B%*%W%7%g%s$r;XDj$7!$=j(B +$BK>$NAH9g$;$K$9$k$3$H$,$G$-$k!%(B Mercurial$B$O%G%U%)%k%H$G$O(Bglob$B9=J8$GM?$($?(B +$B%Q%?!<%s$r2r<a$9$k$,!$@55,I=8=$r;H$&$3$H$b2DG=$G$"$k!%(B + +%You can read a \hggopt{-I} filter as ``process only the files that +%match this filter''. + +\hggopt{-I}$B%U%#%k%?$O(B``$B$3$N%U%#%k%?$K%^%C%A$9$k%U%!%$%k$@$1$r=hM}$9$k(B'' +$B$HFI$_BX$($k$3$H$,$G$-$k!%(B +\interaction{filenames.filter.include} + +%The \hggopt{-X} filter is best read as ``process only the files that +%don't match this pattern''. + +\hggopt{-X}$B%U%#%k%?$O(B``$B$3$N%Q%?!<%s$K%^%C%A$7$J$$%U%!%$%k$@$1$r=hM}$9$k(B''$B$H(B +$BFI$_BX$($k$N$,:G$bAj1~$7$$!%(B +\interaction{filenames.filter.exclude} + +%\section{Ignoring unwanted files and directories} +\section{$BITMW$J%U%!%$%k$d%G%#%l%/%H%j$rL5;k$9$k(B} + +XXX. + +%\section{Case sensitivity} +\section{$BBgJ8;z>.J8;z$N1F6A(B} +\label{sec:names:case} + +%If you're working in a mixed development environment that contains +%both Linux (or other Unix) systems and Macs or Windows systems, you +%should keep in the back of your mind the knowledge that they treat the +%case (``N'' versus ``n'') of file names in incompatible ways. This is +%not very likely to affect you, and it's easy to deal with if it does, +%but it could surprise you if you don't know about it. + +Linux$B$r$O$8$a$H$9$k(BUnix$B$d(BMac$B!$(BWindows$B$,:.:_$9$k3+H/4D6-$G:n6H$r$7$F$$$k$N(B +$B$J$i!$3F!9$N%7%9%F%`$O%U%!%$%kL>$N(B(``N''$B$H(B``n'')$B$N$h$&$JBg>.J8;z$r0[$J$C(B +$B$?$d$jJ}$G<h$j07$&$3$H$KN10U$9$Y$-$G$"$k!%$3$l$,LdBj$K$J$k$3$H$OLGB?$K$J(B +$B$/!$LdBj$K$J$k>l9g$G$b4JC1$K2r7h$G$-$k$,!$%7%9%F%`4V$G$N<h$j07$$$N0c$$$r(B +$BCN$i$J$1$l$P6C$/$3$H$K$J$k$@$m$&!%(B + +%Operating systems and filesystems differ in the way they handle the +%\emph{case} of characters in file and directory names. There are +%three common ways to handle case in names. +$B%*%Z%l!<%F%#%s%0%7%9%F%`$H%U%!%$%k%7%9%F%`$O!$%U%!%$%kL>$H%G%#%l%/%H%jL>(B +$B$N(B\emph{$BBg>.J8;z(B}$B$N07$$$G0[$J$C$F$$$k!%Bg>.J8;z$r07$&J}K!$O(B3$BDL$j$"$k!%(B + +\begin{itemize} +%\item Completely case insensitive. Uppercase and lowercase versions +% of a letter are treated as identical, both when creating a file and +% during subsequent accesses. This is common on older DOS-based +% systems. + \item $B40A4$KBg>.J8;z$r6hJL$7$J$$!%BgJ8;z$H>.J8;z$O!$%U%!%$%k$N:n@.$H$=(B + $B$N8e$N%"%/%;%9$GF10l$K07$o$l$k!%$3$l$O8E$$(BDOS$B%Y!<%9$N%7%9%F%`$GMQ(B + $B$$$i$l$F$$$?!%(B + +%\item Case preserving, but insensitive. When a file or directory is +% created, the case of its name is stored, and can be retrieved and +% displayed by the operating system. When an existing file is being +% looked up, its case is ignored. This is the standard arrangement on +% Windows and MacOS. The names \filename{foo} and \filename{FoO} +% identify the same file. This treatment of uppercase and lowercase +% letters as interchangeable is also referred to as \emph{case +% folding}. + \item $BBg>.J8;z$N0c$$$OJ]B8$5$l$k$,6hJL$5$l$J$$!%%U%!%$%k$d%G%#%l%/%H%j$,(B + $B:n$i$l$k$H!$%*%Z%l!<%F%#%s%0%7%9%F%`$OL>A0$NBg>.J8;z$rJ]B8$7!$I=<((B + $B$J$I$K;HMQ$9$k!%4{B8$N%U%!%$%k$,;2>H$5$l$k;~$O!$Bg>.J8;z$OL5;k$5$l(B + $B$k!%$3$l$O(BWindows$B$H(BMacOS$B$GI8=`E*$J<h$j07$$$G$"$k!%(B\filename{foo}$B$H(B + \filename{FoO}$B$OF10l$N%U%!%$%k$HG'<1$5$l$k!%$3$N$h$&$JBg>.J8;z$N<h(B + $B$j07$$$O(B\emph{case folding}$B$H8F$P$l$k$3$H$b$"$k!%(B + +%\item Case sensitive. The case of a name is significant at all times. +% The names \filename{foo} and {FoO} identify different files. This +% is the way Linux and Unix systems normally work. + \item $BBg>.J8;z$r6hJL$9$k!%>o$KBg>.J8;z$GL>A0$r6hJL$9$k!%(B\filename{foo} + $B$H(B{FoO}$B$OJL$N%U%!%$%k$HG'<1$5$l$k!%$3$l$O(BLinux$B$d(BUnix$B%7%9%F%`$NDL(B + $B>o$N<h$j07$$$G$"$k!%(B + +\end{itemize} + +%On Unix-like systems, it is possible to have any or all of the above +%ways of handling case in action at once. For example, if you use a +%USB thumb drive formatted with a FAT32 filesystem on a Linux system, +%Linux will handle names on that filesystem in a case preserving, but +%insensitive, way. +Unix$B7O$N%7%9%F%`$G$OF1;~$K>e5-$NJ}K!$rMxMQ$9$k$3$H$,2DG=$G$"$k!%Nc$($P(B +USB$B%a%b%j$r(BLinux$B$G(BFAT32$B%U%!%$%k%7%9%F%`$H$7$F%U%)!<%^%C%H$7$?>l9g!$(B +Linux$B$O$=$N%U%!%$%k%7%9%F%`>e$N%U%!%$%kL>$rBg>.J8;zJ]B8$@$,6hJL$;$:$K<h$j(B +$B07$&!%(B + + +%\subsection{Safe, portable repository storage} +\subsection{$B0BA4$G2DHB$J%j%]%8%H%j%9%H%l!<%8(B} + +%Mercurial's repository storage mechanism is \emph{case safe}. It +%translates file names so that they can be safely stored on both case +%sensitive and case insensitive filesystems. This means that you can +%use normal file copying tools to transfer a Mercurial repository onto, +%for example, a USB thumb drive, and safely move that drive and +%repository back and forth between a Mac, a PC running Windows, and a +%Linux box. + +Mercurial$B$N%j%]%8%H%j3JG<%a%+%K%:%`$O(B\emph{$BBg>.J8;z%;!<%U(B}$B$G$"$k!%(B +Mercurial$B$OBg>.J8;z$N6hJL$r$9$k%7%9%F%`$G$b$7$J$$%7%9%F%`$G$b0BA4$KJ]B8$G(B +$B$-$k$h$&$K%U%!%$%kL>$rJQ49$9$k!%$3$N$?$a!$DL>o$N%U%!%$%k%3%T!<%D!<%k$r;H$C(B +$B$F(BMercurial$B%j%]%8%H%j$r(BUSB$B%a%b%j$KE>Aw$7!$(BMac$B!$(BWindows$B$NF0$/(BPC$B!$(BLinux$B%^%7(B +$B%s$N4V$G0\F0$7$F$b0BA4$G$"$k!%(B + + +%\subsection{Detecting case conflicts} +\subsection{$BBgJ8;z>.J8;z$N>WFM$r8!=P$9$k(B} + +%When operating in the working directory, Mercurial honours the naming +%policy of the filesystem where the working directory is located. If +%the filesystem is case preserving, but insensitive, Mercurial will +%treat names that differ only in case as the same. + +$B%o!<%-%s%0%G%#%l%/%H%j$G$NF0:n$N:]$K!$(B Mercurial$B$O%o!<%-%s%0%G%#%l%/%H%j(B +$B$N$"$k%U%!%$%k%7%9%F%`$N%M!<%_%s%0%]%j%7!<$rB:=E$9$k!%Bg>.J8;z$rJ]B8$9$k(B +$B$,6hJL$7$J$$%U%!%$%k%7%9%F%`$N>l9g!$(BMercurial$B$OL>A0$NBg>.$@$1$,0[$J$C$F$$(B +$B$k%U%!%$%k$rF1$8%U%!%$%k$H$7$F<h$j07$&!%(B + +%An important aspect of this approach is that it is possible to commit +%a changeset on a case sensitive (typically Linux or Unix) filesystem +%that will cause trouble for users on case insensitive (usually Windows +%and MacOS) users. If a Linux user commits changes to two files, one +%named \filename{myfile.c} and the other named \filename{MyFile.C}, +%they will be stored correctly in the repository. And in the working +%directories of other Linux users, they will be correctly represented +%as separate files. + +$B$3$N%"%W%m!<%A$G=EMW$J$N$O!$Bg>.$r6hJL$9$k%U%!%$%k%7%9%F%`!JE57?E*$K$O(B +Linux$B$*$h$S(BUnix$B!K$GBg>.$r6hJL$7$J$$%7%9%F%`!JDL>o!$(BWindows$B$^$?$O(BMacOS$B!K$N(B +$B%f!<%6$K$H$C$F%H%i%V%k$H$J$k$h$&$J%A%'%s%8%;%C%H$r%3%_%C%H$9$k$3$H$,2DG=(B +$B$G$"$k$H$$$&E@$G$"$k!%$b$7(BLinux$B%f!<%6$,(B\filename{myfile.c}$B$H$$$&%U%!%$%k(B +$B$H(B\filename{MyFile.C}$B$H$$$&%U%!%$%k$KBP$9$k%A%'%s%8%;%C%H$r%3%_%C%H$7$?>l(B +$B9g!$$=$l$i$O%j%]%8%H%j$K@5$7$/J]B8$5$l!$B>$N(BLinux$B%f!<%6$N%o!<%-%s%0%G%#%l(B +$B%/%H%j$G$b@5$7$/JL!9$N%U%!%$%k$H$7$F8=$l$k!%(B + +%If a Windows or Mac user pulls this change, they will not initially +%have a problem, because Mercurial's repository storage mechanism is +%case safe. However, once they try to \hgcmd{update} the working +%directory to that changeset, or \hgcmd{merge} with that changeset, +%Mercurial will spot the conflict between the two file names that the +%filesystem would treat as the same, and forbid the update or merge +%from occurring. + +$B$3$3$G(BWindows$B$^$?$O(BMac$B$N%f!<%6$,$3$N%A%'%s%8%;%C%H$r(Bpull$B$9$k$H!$(B +Mercurial$B$N%j%]%8%H%j3JG<%a%+%K%:%`$OBg>.J8;z$KBP$7$F0BA4$J$?$a!$:G=i$N$&(B +$B$A$OLdBj$H$J$i$J$$!%$7$+$7%o!<%-%s%0%G%#%l%/%H%j$r$=$N%A%'%s%8%;%C%H$K(B +\hgcmd{update}$B$7$h$&$H$7$?$j!$$=$N%A%'%s%8%;%C%H$H(B\hgcmd{merge}$B$7$h$&$H$9(B +$B$k$H!$(BMercurial$B$O!$(B 2$B$D$N%U%!%$%kL>$r%U%!%$%k%7%9%F%`$,F1$8L>A0$H$7$F07$&(B +$B$?$a$K@8$8$k%3%s%U%j%/%H$r8!=P$7!$(B update$B$d(Bmerge$B$r5v$5$J$$!%(B + +%\subsection{Fixing a case conflict} +\subsection{$BBgJ8;z>.J8;z$N>WFM$r2r7h$9$k(B} + +%If you are using Windows or a Mac in a mixed environment where some of +%your collaborators are using Linux or Unix, and Mercurial reports a +%case folding conflict when you try to \hgcmd{update} or \hgcmd{merge}, +%the procedure to fix the problem is simple. + +$B$b$7$"$J$?$,(BWindows$B$d(BMac$B$r;H$C$F$$$F!$2??M$+$N6(NO<T$,(BLinux$B$^$?$O(BUnix$B$r;H$C(B +$B$F$$$k:.9g4D6-$G3+H/$r$7$F$*$j!$(B \hgcmd{update}$B$^$?$O(B\hgcmd{merge}$B$G(B +Mercurial$B$,Bg>.J8;z$N%3%s%U%j%/%H$r8!=P$9$k$N$G$"$l$P!$2r7hJ}K!$O%7%s%W%k(B +$B$G$"$k!%(B + +%Just find a nearby Linux or Unix box, clone the problem repository +%onto it, and use Mercurial's \hgcmd{rename} command to change the +%names of any offending files or directories so that they will no +%longer cause case folding conflicts. Commit this change, \hgcmd{pull} +%or \hgcmd{push} it across to your Windows or MacOS system, and +%\hgcmd{update} to the revision with the non-conflicting names. + +$B<j6a$J(BLinux$B$^$?$O(BUnix$B%^%7%s$N>e$K!$LdBj$N$"$k%j%]%8%H%j$r%/%m!<%s$7!$(B +Mercurial$B$N(B\hgcmd{rename}$B$r<B9T$7$FLdBj$N$"$k%U%!%$%k$d%G%#%l%/%H%j$NL>A0(B +$B$rJQ99$7!$%3%s%U%j%/%H$r2r7h$9$k!%$3$NJQ99$r%3%_%C%H$7!$(B\hgcmd{pull}$B$^$?(B +$B$O(B\hgcmd{push}$B%3%^%s%I$G$"$J$?$N(BWindows$B$^$?$O(BMacOS$B%7%9%F%`$KE>Aw(B +$B$7!$(B\hgcmd{update}$B$G%3%s%U%j%/%H$N$J$$%j%S%8%g%s$X99?7$9$l$P$h$$!%(B + +%The changeset with case-conflicting names will remain in your +%project's history, and you still won't be able to \hgcmd{update} your +%working directory to that changeset on a Windows or MacOS system, but +%you can continue development unimpeded. + +$BBg>.J8;z$N%U%!%$%kL>%3%s%U%j%/%H$,$"$k%A%'%s%8%;%C%H$O%W%m%8%'%/%H$NMzNr(B +$B$K;D$C$F$*$j!$(B Windows$B$d(BMacOS$B$7$9$F$`$G$O$=$N%A%'%s%8%;%C%H$X(B +\hgcmd{update}$B$9$k$3$H$O$G$-$J$$$b$N$N!$LdBj$J$/3+H/$rB3$1$k$3$H$,$G$-$k!%(B + +\begin{note} +% Prior to version~0.9.3, Mercurial did not use a case safe repository +% storage mechanism, and did not detect case folding conflicts. If +% you are using an older version of Mercurial on Windows or MacOS, I +% strongly recommend that you upgrade. +0.9.3$B$h$jA0$N(BMercurial$B$O(Bcase$B%;!<%U$N%9%H%l!<%85!9=$r;H$C$F$*$i$:!$(Bcase$B$N(B + $B>WFM$r8!=P$G$-$J$+$C$?!%(BWindows$B$d(BMacOS$B$G8E$$%P!<%8%g%s$N(BMercurial$B$r;H$C(B + $B$F$$$k$J$i$P!$%"%C%W%G!<%H$9$k$3$H$r6/$/4+$a$k!%(B +\end{note} + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/fixhtml.py Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# +# This script attempts to work around some of the more bizarre and +# quirky behaviours of htlatex. +# +# - We've persuaded htlatex to produce UTF-8, which unfortunately +# causes it to use huge character sequences to represent even the +# safe 7-bit ASCII subset of UTF-8. We fix that up. +# +# - BUT we have to treat angle brackets (for example, redirections in +# shell script snippets) specially, otherwise they'll break the +# generated HTML. (Reported by Johannes Hoff.) +# +# - For some reason, htlatex gives a unique ID to each fancyvrb +# environment, which makes writing a sane, small CSS stylesheet +# impossible. We squish all those IDs down to nothing. + +import os +import sys +import re + +angle_re = re.compile(r'([CE];)') +unicode_re = re.compile(r'�([0-7][0-9A-F]);') +fancyvrb_re = re.compile(r'id="fancyvrb\d+"', re.I) +ligature_re = re.compile(r'ྰ([0-4]);') + +tmpsuffix = '.tmp.' + str(os.getpid()) + +def hide_angle(m): + return m.group(1).lower() + +def fix_ascii(m): + return chr(int(m.group(1), 16)) + +ligatures = ['ff', 'fi', 'fl', 'ffi', 'ffl'] + +def expand_ligature(m): + return ligatures[int(m.group(1))] + +for name in sys.argv[1:]: + tmpname = name + tmpsuffix + ofp = file(tmpname, 'w') + for line in file(name): + line = angle_re.sub(hide_angle, line) + line = unicode_re.sub(fix_ascii, line) + line = ligature_re.sub(expand_ligature, line) + line = fancyvrb_re.sub('id="fancyvrb"', line) + ofp.write(line) + ofp.close() + os.rename(tmpname, name)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/hgbook.css Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,441 @@ +body { + font: 12px/1.5 Verdana, sans-serif; + padding-top: 50px; + padding-left: 80px; + padding-right: 80px; + padding-bottom: 90px; +} +.ptmr7t- { + font-family: monospace; +} +.ptmr7t-x-x-172 { + font-size: 172%; + font-family: monospace; +} +.ptmr7t-x-x-120 { + font-size: 120%; +} +.zpzccmry-x-x-120 { + font-size: 120%; + font-weight: bold; + font-style: italic; +} +.zpzccmry-x-x-120 { + font-weight: bold; + font-style: italic; +} +.pcrr7tn- { + font-family: monospace; +} +.ptmri7t- { + font-style: italic; +} +.ptmr7t-x-x-50 { + font-size: 50%; + font-family: monospace; +} +.ptmb7t- { + font-weight: bold; +} +.zptmcmr- { + font-style: italic; +} +.zptmcmrm- { + font-style: italic; +} +.zpzccmry- { + font-weight: bold; + font-style: italic; +} +.pcrb7t- { + font-family: monospace; + font-weight: bold; +} +.pcrro7t- { + font-family: monospace; + font-style: oblique; +} +p.noindent { + text-indent: 0em; + margin: 0em; +} +p.nopar { + text-indent: 0em; +} +p.indent { + text-indent: 1.5em; + margin: 0em; +} +a img { + border-top: 0; + border-left: 0; + border-right: 0; +} +center { + margin-top: 1em; + margin-bottom: 1em; +} +td center { + margin-top: 0em; + margin-bottom: 0em; +} +.Canvas { + position: relative; +} +img.math { + vertical-align: middle; +} +li p.indent { + text-indent: 0em; +} +.enumerate1 { + list-style-type: decimal; +} +.enumerate2 { + list-style-type: lower-alpha; +} +.enumerate3 { + list-style-type: lower-roman; +} +.enumerate4 { + list-style-type: upper-alpha; +} +div.newtheorem { + margin-bottom: 2em; + margin-top: 2em; +} +.obeylines-h,.obeylines-v { + white-space: nowrap; +} +div.obeylines-v p { + margin-top: 0; + margin-bottom: 0; +} +.overline { + text-decoration: overline; +} +.overline img { + border-top: 1px solid black; +} +td.displaylines { + text-align: center; + white-space: nowrap; +} +.centerline { + text-align: center; +} +.rightline { + text-align: right; +} +div.verbatim { + font-family: monospace; + white-space: nowrap; +} +table.verbatim { + width: 100%; +} +.fbox { + background: url(note.png) no-repeat #cec; + padding-left: 65px; + padding-top: 1em; + padding-bottom: 1em; + padding-right: 1em; + text-indent: 0pt; + border: dotted black 1px; +} +div.center div.fbox { + text-align: center; + clear: both; + padding-left: 3.0pt; + padding-right: 3.0pt; + text-indent: 0pt; + border: solid black 0.4pt; +} +table.minipage { + width: 100%; +} +div.center, div.center div.center { + text-align: center; + margin-left: 1em; + margin-right: 1em; +} +div.center div { + text-align: left; +} +div.flushright, div.flushright div.flushright { + text-align: right; +} +div.flushright div { + text-align: left; +} +div.flushleft { + text-align: left; +} +.underline { + text-decoration: underline; +} +.underline img { + border-bottom: 1px solid black; + margin-bottom: 1pt; +} +.framebox-c, .framebox-l, .framebox-r { + padding-left: 3.0pt; + padding-right: 3.0pt; + text-indent: 0pt; + border: solid black 0.4pt; +} +.framebox-c { + text-align: center; +} +.framebox-l { + text-align: left; +} +.framebox-r { + text-align: right; +} +span.thank-mark { + vertical-align: super +} +span.footnote-mark sup.textsuperscript, span.footnote-mark a sup.textsuperscript { + font-size: 80%; +} +div.tabular, div.center div.tabular { + text-align: center; + margin-top: 0.5em; + margin-bottom: 0.5em; +} +table.tabular td p { + margin-top: 0em; +} +table.tabular { + margin-left: auto; + margin-right: auto; +} +div.td00 { + margin-left: 0pt; + margin-right: 0pt; +} +div.td01 { + margin-left: 0pt; + margin-right: 5pt; +} +div.td10 { + margin-left: 5pt; + margin-right: 0pt; +} +div.td11 { + margin-left: 5pt; + margin-right: 5pt; +} +table[rules] { + border-left: solid black 0.4pt; + border-right: solid black 0.4pt; +} +td.td00 { + padding-left: 0pt; + padding-right: 0pt; +} +td.td01 { + padding-left: 0pt; + padding-right: 5pt; +} +td.td10 { + padding-left: 5pt; + padding-right: 0pt; +} +td.td11 { + padding-left: 5pt; + padding-right: 5pt; +} +table[rules] { + border-left: solid black 0.4pt; + border-right: solid black 0.4pt; +} +.hline hr, .cline hr { + height : 1px; + margin: 0px; +} +.tabbing-right { + text-align: right; +} +span.TEX { + letter-spacing: -0.125em; +} +span.TEX span.E { + position: relative;top: 0.5ex;left: -0.0417em; +} +a span.TEX span.E { + text-decoration: none; +} +span.LATEX span.A { + position: relative; + top: -0.5ex; + left: -0.4em; + font-size: 85%; +} +span.LATEX span.TEX { + position: relative; + left: -0.4em; +} +div.float img, div.float .caption { + text-align: center; +} +div.figure img, div.figure .caption { + text-align: center; +} +.marginpar { + width: 20%; + float: right; + text-align: left; + margin-left: auto; + margin-top: 0.5em; + font-size: 85%; + text-decoration: underline; +} +.marginpar p { + margin-top: 0.4em; + margin-bottom: 0.4em; +} +table.equation { + width: 100%; +} +.equation td { + text-align: center; +} +td.equation { + margin-top: 1em; + margin-bottom: 1em; +} +td.equation-label { + width: 5%; + text-align: center; +} +td.eqnarray4 { + width: 5%; + white-space: normal; +} +td.eqnarray2 { + width: 5%; +} +table.eqnarray-star, table.eqnarray { + width: 100%; +} +div.eqnarray { + text-align: center; +} +div.array { + text-align: center; +} +div.pmatrix { + text-align: center; +} +table.pmatrix { + width: 100%; +} +span.pmatrix img { + vertical-align: middle; +} +div.pmatrix { + text-align: center; +} +table.pmatrix { + width: 100%; +} +img.cdots { + vertical-align: middle; +} +.partToc a, .partToc, .likepartToc a, .likepartToc { + line-height: 200%; + font-weight: bold; + font-size: 110%; +} +.chapterToc a, .chapterToc, .likechapterToc a, .likechapterToc, .appendixToc a, .appendixToc { + line-height: 200%; + font-weight: bold; +} +.caption td.id { + font-weight: bold; + white-space: nowrap; +} +table.caption { + text-align: center; +} +h1.partHead { + text-align: center; +} +p.bibitem { + text-indent: -2em; + margin-left: 2em; + margin-top: 0.6em; + margin-bottom: 0.6em; +} +p.bibitem-p { + text-indent: 0em; + margin-left: 2em; + margin-top: 0.6em; + margin-bottom: 0.6em; +} +.paragraphHead, .likeparagraphHead { + margin-top: 2em; + font-weight: bold; +} +.subparagraphHead, .likesubparagraphHead { + font-weight: bold; +} +.quote { + margin-bottom: 0.25em; + margin-top: 0.25em; + margin-left: 1em; + margin-right: 1em; + text-align: justify; +} +.verse { + white-space: nowrap; + margin-left: 2em} +div.maketitle { + text-align: center; +} +h2.titleHead { + text-align: center; +} +div.maketitle { + margin-bottom: 2em; +} +div.author, div.date { + text-align: center; +} +div.thanks { + text-align: left; + margin-left: 10%; + font-size: 85%; + font-style: italic; +} +div.author { + white-space: nowrap; +} +.quotation { + margin-bottom: 0.25em; + margin-top: 0.25em; + margin-left: 1em; +} +h1.partHead { + text-align: center; +} +img.graphics { + margin-left: 10%; +} +.figure { + width: 100%; +} +P.fancyvrb { + white-space: nowrap; +} +hr { + border: 0; + height: 1px; +} +div#fancyvrb { + white-space: nowrap; + background: #eee; + padding: 1em; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/hgext.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,767 @@ +%\chapter{Adding functionality with extensions} +\chapter{$B3HD%$K$h$k5!G=$NDI2C(B} +\label{chap:hgext} + +%While the core of Mercurial is quite complete from a functionality +%standpoint, it's deliberately shorn of fancy features. This approach +%of preserving simplicity keeps the software easy to deal with for both +%maintainers and users. + +$B5!G=$N4QE@$+$i8+$k$H(BMercurial$B$O$+$J$j40Hw$7$F$$$k$,!$GI<j$J5!G=$K$D$$$F$O(B +$B0U?^E*$KGS=|$7$F$$$k!%(BMercurial$B$N%a%s%F%J$H%f!<%6$NAPJ}$K$H$C$FC1=c$5$rJ](B +$B$D$?$a$K$3$N%"%W%m!<%A$r<h$C$F$$$k!%(B + +%However, Mercurial doesn't box you in with an inflexible command set: +%you can add features to it as \emph{extensions} (sometimes known as +%\emph{plugins}). We've already discussed a few of these extensions in +%earlier chapters. + +$B$7$+$7$J$,$i!$(BMercurial$B$OM;DL$NMx$+$J$$%3%^%s%I%;%C%H$rDs6!$7$F$$$k$N$G$O(B +$B$J$$!%(B\emph{extensions}$B!J$"$k$$$O(B\emph{plugins}$B$H8F$P$l$k$3$H$b$"$k!K$K$h$C(B +$B$F5!G=$rDI2C$9$k$3$H$,$G$-$k!%$3$l$i$N$$$/$D$+$K$D$$$F$O!$0JA0$N>O$G8+$F(B +$B$$$k!%(B + +\begin{itemize} +%\item Section~\ref{sec:tour-merge:fetch} covers the \hgext{fetch} +% extension; this combines pulling new changes and merging them with +% local changes into a single command, \hgxcmd{fetch}{fetch}. +\item $B%;%/%7%g%s(B\ref{sec:tour-merge:fetch}$B$O(B\hgext{fetch}$B%(%/%9%F%s%7%g%s(B + $B$r%+%P!<$7$F$$$k!%$3$l$O?7$7$$JQ99$r(Bpull$B$7!$%m!<%+%k$JJQ99$H%^!<%8(B + $B$rC10l$N%3%^%s%I(B\hgxcmd{fetch}{fetch}$B$G<B9T$9$k!%(B +%\item In chapter~\ref{chap:hook}, we covered several extensions that +% are useful for hook-related functionality: \hgext{acl} adds access +% control lists; \hgext{bugzilla} adds integration with the Bugzilla +% bug tracking system; and \hgext{notify} sends notification emails on +% new changes. +\item \ref{chap:hook}$B$G$O!$%U%C%/$K4XO"$7$?$$$/$D$+$N3HD%$K$D$$$F07$&!%(B +\hgext{acl}$B$O%"%/%;%9@)8f%j%9%H$rDI2C$9$k!%(B\hgext{bugzilla}$B$O(BBugzilla$B5!G=(B +$B$NE}9g5!G=$rDs6!$9$k!%(B\hgext{notify}$B$O!$?7$?$JJQ99$N:]$KDLCNEE;R%a!<%k$r(B +$BAw$k5!G=$rDs6!$9$k!%(B +%\item The Mercurial Queues patch management extension is so invaluable +% that it merits two chapters and an appendix all to itself. +% Chapter~\ref{chap:mq} covers the basics; +% chapter~\ref{chap:mq-collab} discusses advanced topics; and +% appendix~\ref{chap:mqref} goes into detail on each command. +\item Mercurial Queue$B$H$$$&%Q%C%A%^%M!<%8%a%s%H3HD%$O!$Hs>o$K=EMW$J$N$G(B2 + $B>O$HIUO?(B1$B>O$rHq$d$7$F@bL@$9$k!%(B + Chapter~\ref{chap:mq}$B$O4pK\E*$J5!G=$r@bL@$9$k!%(B + chapter~\ref{chap:mq-collab}$B$G$O9bEY$J5!G=$K$D$$$F@bL@$7!$(B + appendix~\ref{chap:mqref}$B$G$O3F%3%^%s%I$N>\:Y$r@bL@$9$k!%(B +\end{itemize} + +%In this chapter, we'll cover some of the other extensions that are +%available for Mercurial, and briefly touch on some of the machinery +%you'll need to know about if you want to write an extension of your +%own. +$B$3$N>O$G$O(BMercurial$B$GMxMQ2DG=$J$=$NB>$N3HD%$K$D$$$F<h$j07$$!$$^$?<+J,$G(B +Mercurial$B3HD%$r=q$/;~$KLrN)$DFbIt$N5!9=$K$D$$$F$b@bL@$9$k!%(B +\begin{itemize} +%\item In section~\ref{sec:hgext:inotify}, we'll discuss the +% possibility of \emph{huge} performance improvements using the +% \hgext{inotify} extension. +\item \ref{sec:hgext:inotify}$B@a$G$O(B\hgext{inotify}$B3HD%$rMQ$$$k$3$H$GF@$i(B + $B$l$k(B\emph{$BBg$-$J(B}$B@-G=8~>e$K$D$$$F=R$Y$k!%(B +\end{itemize} + +%\section{Improve performance with the \hgext{inotify} extension} +\section{\hgext{inotify}$B3HD%$K$h$k@-G=8~>e(B} +\label{sec:hgext:inotify} + +%Are you interested in having some of the most common Mercurial +%operations run as much as a hundred times faster? Read on! +Mercurial$B$N:G$bB?MQ$5$l$k%3%^%s%I$N$$$/$D$+$,?tI4G\B.$/$J$k$3$H$K6=L#$,$"(B +$B$k$J$i$P$<$RFI$s$GM_$7$$!*(B + +%Mercurial has great performance under normal circumstances. For +%example, when you run the \hgcmd{status} command, Mercurial has to +%scan almost every directory and file in your repository so that it can +%display file status. Many other Mercurial commands need to do the +%same work behind the scenes; for example, the \hgcmd{diff} command +%uses the status machinery to avoid doing an expensive comparison +%operation on files that obviously haven't changed. + +$BDL>o$N>r7o2<$G(BMercurial$B$O9b$$@-G=$r;}$C$F$$$k$,!$(B \hgcmd{status}$B%3%^%s%I(B +$B$r<B9T$7$?;~!$(BMercurial$B$O$[$\A4$F$N%G%#%l%/%H%j$H%U%!%$%k$r%9%-%c%s$9$k$3(B +$B$H$K$J$k!%B>$NB?$/$N(BMercurial$B%3%^%s%I$O!$$3$N$h$&$JA`:n$r0U<1$5$;$J$$$h$&(B +$B$K$J$C$F$$$k!%Nc$($P(B\hgcmd{diff}$B$O%9%F!<%?%95!9=$rMQ$$$F!$L@$i$+$KJQ99$5(B +$B$l$F$$$J$$%U%!%$%k$NHf3S$rHr$1$F$$$k!%(B + +%Because obtaining file status is crucial to good performance, the +%authors of Mercurial have optimised this code to within an inch of its +%life. However, there's no avoiding the fact that when you run +%\hgcmd{status}, Mercurial is going to have to perform at least one +%expensive system call for each managed file to determine whether it's +%changed since the last time Mercurial checked. For a sufficiently +%large repository, this can take a long time. + +$BNI$$@-G=$rF@$k$?$a$K$O!$%U%!%$%k%9%F!<%?%9$N<hF@$,=EMW$J4X?4;v$H$J$k$?(B +$B$a!$(BMercurial$B$N:n<T$?$A$O$3$l$r$.$j$.$j$N$H$3$m$^$G:GE,2=$7$F$$$k!%$7$+$7(B +\hgcmd{status}$B%3%^%s%I$G$O$3$l$rHr$1$k<jN)$F$,$J$$!%(B Mercurial$B$O!$4IM}$7(B +$B$F$$$k%U%!%$%k$,:G8e$K%A%'%C%/$7$?;~$+$iJQ99$5$l$F$$$k$+D4$Y$k$?$a$K!$>/(B +$B$J$/$H$b0l$D$N9b2A$J%7%9%F%`%3!<%k$r$9$kI,MW$,$"$k!%$"$kDxEY0J>eBg$-$J%j(B +$B%]%8%H%j$G$O!$$3$NA`:n$K$OD9$$;~4V$rMW$9$k!%(B + +%To put a number on the magnitude of this effect, I created a +%repository containing 150,000 managed files. I timed \hgcmd{status} +%as taking ten seconds to run, even when \emph{none} of those files had +%been modified. + +$B$3$N1F6A$K$D$$$FD4$Y$k$?$a$K(B150,000$B$N%U%!%$%k$rMJ$9$k%j%]%8%H%j$r:n@.$7(B +$B$?!%(B\emph{$B$^$C$?$/(B}$BJQ99$,$J$$>l9g$G$b(B\hgcmd{status}$B%3%^%s%I$N<B9T$K$O(B10 +$BIC$rMW$7$?!%(B + +%Many modern operating systems contain a file notification facility. +%If a program signs up to an appropriate service, the operating system +%will notify it every time a file of interest is created, modified, or +%deleted. On Linux systems, the kernel component that does this is +%called \texttt{inotify}. + +$B6aG/$N%*%Z%l!<%F%#%s%0%7%9%F%`$O!$%U%!%$%kDLCN$N5!9=$rHw$($F$$$k!%%W%m%0(B +$B%i%`$,E,@Z$J%5!<%S%9$KEPO?$9$k$H!$%*%Z%l!<%F%#%s%0%7%9%F%`$OBP>]$H$J$k%U%!(B +$B%$%k$N:n@.!$JQ99!$:o=|$r%W%m%0%i%`$KDLCN$9$k!%(B Linux$B%7%9%F%`$G$O$3$l$r9T(B +$B$&%+!<%M%k%3%s%]!<%M%s%H$O(B\texttt{inotify}$B$H8F$P$l$k!%(B + +%Mercurial's \hgext{inotify} extension talks to the kernel's +%\texttt{inotify} component to optimise \hgcmd{status} commands. The +%extension has two components. A daemon sits in the background and +%receives notifications from the \texttt{inotify} subsystem. It also +%listens for connections from a regular Mercurial command. The +%extension modifies Mercurial's behaviour so that instead of scanning +%the filesystem, it queries the daemon. Since the daemon has perfect +%information about the state of the repository, it can respond with a +%result instantaneously, avoiding the need to scan every directory and +%file in the repository. + +Mercurial$B$N(B\hgext{inotify}$B3HD%$O!$(B\hgcmd{status}$B%3%^%s%I$r:GE,2=$9$k$?$a(B +$B$K!$%+!<%M%k$N(B\texttt{inotify}$B%3%s%]!<%M%s%H$X%"%/%;%9$9$k!%$3$N3HD%$O(B2$B$D(B +$B$N%3%s%]!<%M%s%H$+$i$J$k!%(B \texttt{inotify}$B%5%V%7%9%F%`$+$iDLCN$r<u$1<h$k(B +$B$?$a$N%G!<%b%s$,%P%C%/%0%i%s%I$GF0:n$9$k!%$3$N%G!<%b%s$O(BMercurial$B$NB>$N%3(B +$B%^%s%I$+$i$N@\B3$b<u$1IU$1$k!%$3$N3HD%$O(BMercurial$B$N5sF0$rJQ99$7!$%U%!%$%k(B +$B%7%9%F%`$r%9%-%c%s$9$k$N$G$O$J$/!$%G!<%b%s$X$NLd$$9g$o$;$r9T$&$h$&$K$9(B +$B$k!%%G!<%b%s$O%j%]%8%H%j$N>uBV$r40A4$KGD0.$7$F$$$k$N$G!$D>$A$KLd$$9g$o$;(B +$B$KJVEz$9$k$3$H$,$G$-!$%j%]%8%H%j$N%G%#%l%/%H%j$H%U%!%$%k$N%9%-%c%s$rHr$1(B +$B$k$3$H$,$G$-$k!%(B + +%Recall the ten seconds that I measured plain Mercurial as taking to +%run \hgcmd{status} on a 150,000 file repository. With the +%\hgext{inotify} extension enabled, the time dropped to 0.1~seconds, a +%factor of \emph{one hundred} faster. + +$B%W%l!<%s$J(BMercurial$B$G$O(B\hgcmd{status}$B%3%^%s%I$,(B150,000$B%U%!%$%k$N%j%]%8%H(B +$B%j$KBP$7$F(B10$BIC$rMW$7$F$$$?$3$H$r;W$$=P$7$FM_$7$$!#(B +\hgext{inotify}$B3HD%$r;H$C$?>l9g!"=jMW;~4V$O(B0.1$BIC$K2<$,$j!$(B\emph{100}$BG\B.(B +$B$/$J$C$F$$$k$3$H$,J,$+$k!%(B + +%Before we continue, please pay attention to some caveats. +$B$5$i$K?J$`A0$K!$Cm0UE@$r5s$2$k!%(B +\begin{itemize} +%\item The \hgext{inotify} extension is Linux-specific. Because it +% interfaces directly to the Linux kernel's \texttt{inotify} +% subsystem, it does not work on other operating systems. + \item \hgext{inotify}$B3HD%$O(BLinux$BFCM-$N$b$N$G$"$k!%$3$N5!G=3HD%$O(BLinux$B$N(B + \texttt{inotify}$B%5%V%7%9%F%`$KD>@\%"%/%;%9$9$k$?$a!$B>$N%*%Z%l!<(B + $B%F%#%s%0%7%9%F%`$G$OF0:n$7$J$$!%(B + +%\item It should work on any Linux distribution that was released after +% early~2005. Older distributions are likely to have a kernel that +% lacks \texttt{inotify}, or a version of \texttt{glibc} that does not +% have the necessary interfacing support. + \item 2005$BG/=i$a0J9_$K%j%j!<%9$5$l$?$I$N$h$&$J(BLinux$B%G%#%9%H%j%S%e!<%7%g(B + $B%s$G$bF0:n$9$k$O$:$@$,!$8E$$%G%#%9%H%j%S%e!<%7%g%s$G$O(B + \texttt{inotify}$B$r7g$$$F$$$?$j!$I,MW$J%$%s%?!<%U%'!<%9%5%]!<%H$r(B + \texttt{glibc}$B$,Ds6!$7$F$$$J$+$C$?$j$9$k2DG=@-$,$"$k!%(B + +%\item Not all filesystems are suitable for use with the +% \hgext{inotify} extension. Network filesystems such as NFS are a +% non-starter, for example, particularly if you're running Mercurial + +% on several systems, all mounting the same network filesystem. The +% kernel's \texttt{inotify} system has no way of knowing about changes +% made on another system. Most local filesystems (e.g.~ext3, XFS, +% ReiserFS) should work fine. + \item $BA4$F$N%U%!%$%k%7%9%F%`$,(B\hgext{inotify}$B3HD%$GMxMQ2DG=$J$o$1$G$O$J(B + $B$$!%Nc$((B +$B$P(BMercurial$B$r$$$/$D$+$N%7%9%F%`$GF0:n$5$;$F$$$k>l9g!$F10l$N%M%C%H%o!<%/%U%!(B +$B%$%k%7%9%F%`$r3F!9$N%7%9%F%`$G%^%&%s%H$7$F$$$k$3$H$,B?$$$,!$(B NFS$B$J$I$N%M%C(B +$B%H%o!<%/%U%!%$%k%7%9%F%`$O9MN8$5$l$F$$$J$$!%(B +\end{itemize} + +%The \hgext{inotify} extension is not yet shipped with Mercurial as of +%May~2007, so it's a little more involved to set up than other +%extensions. But the performance improvement is worth it! + +2007$BG/(B5$B7n$^$G$O(B\hgext{inotify}$B3HD%$O(BMercurial$B$KF1:-$5$l$F$$$J$+$C$?!%$=$N(B +$B$?$a!$%;%C%H%"%C%W$OB>$N3HD%$KHf$Y$F$d$dJ#;($@$,!$F@$i$l$k@-G=8~>e$O$K$O(B +$B$=$l$@$1$N2ACM$,$"$k!%(B + +%The extension currently comes in two parts: a set of patches to the +%Mercurial source code, and a library of Python bindings to the +%\texttt{inotify} subsystem. + +$B8=:_!$3HD%$O(B2$B$D$N%Q!<%H$KJ,$+$l$F$$$k!%(BMercurial$B%=!<%9%3!<%I$X$N%Q%C%A$H(B +\texttt{inotify}$B%5%V%7%9%F%`$X$N(BPython$B%P%$%s%G%#%s%0%i%$%V%i%j$G$"$k!%(B + +\begin{note} +% There are \emph{two} Python \texttt{inotify} binding libraries. One +% of them is called \texttt{pyinotify}, and is packaged by some Linux +% distributions as \texttt{python-inotify}. This is \emph{not} the +% one you'll need, as it is too buggy and inefficient to be practical. + +Python$B$N(B\texttt{inotify}$B%P%$%s%G%#%s%0%i%$%V%i%j$O(B\emph{2$B$D(B}$B$"$k!%(B1$B$D$O(B +\texttt{pyinotify}$B$G$"$j!$$$$/$D$+$N(BLinux$B%G%#%9%H%j%S%e!<%7%g%s$G$O(B +\texttt{python-inotify}$B$H$7$F%Q%C%1!<%82=$5$l$F$$$k!%$3$l$O%P%0$,Hs>o$KB?(B +$B$/!$<BMQ$9$k$K$OHs8zN(E*$G$"$j!$;H$&$Y$-$G(B\emph{$B$J$$(B}$B!%(B +\end{note} + +%To get going, it's best to already have a functioning copy of +%Mercurial installed. +$B@h$X?J$`$KEv$C$F!$@5$7$/5!G=$9$k(BMercurial$B$,%$%s%9%H!<%k$5$l$F$$$k$3$H$,(B +$BK>$^$7$$!%(B + +\begin{note} +% If you follow the instructions below, you'll be \emph{replacing} and +% overwriting any existing installation of Mercurial that you might +% already have, using the latest ``bleeding edge'' Mercurial code. +% Don't say you weren't warned! +$B0J2<$N;X<($K=>$C$F%$%s%9%H!<%k$7$?(BMercurial$B$r!$:G?7$N(BMercurial$B%3!<%I$G(B +\emph{$BCV$-49$($k(B}$B$3$H$,$G$-$k!%!J7Y9p$5$l$J$+$C$?$H$O8@$o$J$$$3$H!K(B + +\end{note} +\begin{enumerate} +%\item Clone the Python \texttt{inotify} binding repository. Build and +% install it. +\item Python \texttt{inotify}$B%P%$%s%G%#%s%0$N%j%]%8%H%j$r%/%m!<%s$7!$%S(B + $B%k%I$H%$%s%9%H!<%k$r9T$&!%(B + \begin{codesample4} + hg clone http://hg.kublai.com/python/inotify + cd inotify + python setup.py build --force + sudo python setup.py install --skip-build + \end{codesample4} +%\item Clone the \dirname{crew} Mercurial repository. Clone the +% \hgext{inotify} patch repository so that Mercurial Queues will be +% able to apply patches to your cope of the \dirname{crew} repository. + \item Merecurial$B$N(B\dirname{crew}$B%j%]%8%H%j$r%/%m!<%s$9(B + $B$k!%(B\hgext{inotify}$B%Q%C%A%j%]%8%H%j$r%/%m!<%s$7!$(BMercurial Queues + $B$,(B\dirname{crew}$B%j%]%8%H%j$K%Q%C%A$rEv$F$i$l$k$h$&$K$9$k!%(B + \begin{codesample4} + hg clone http://hg.intevation.org/mercurial/crew + hg clone crew inotify + hg clone http://hg.kublai.com/mercurial/patches/inotify inotify/.hg/patches + \end{codesample4} +%\item Make sure that you have the Mercurial Queues extension, +% \hgext{mq}, enabled. If you've never used MQ, read +% section~\ref{sec:mq:start} to get started quickly. + +\item Mercurial Queues$B3HD%!J(B\hgext{mq}$B!K$,M-8z$K$J$C$F$$$k$3$H$r3NG'$9(B + $B$k!%(BMQ$B$r;H$C$?$3$H$,$J$1$l$P!$(B\ref{sec:mq:start}$B$r0lFI$9$k$3$H$r$*(B + $B$9$9$a$9$k!%(B + +%\item Go into the \dirname{inotify} repo, and apply all of the +% \hgext{inotify} patches using the \hgxopt{mq}{qpush}{-a} option to +% the \hgxcmd{mq}{qpush} command. +\item \dirname{inotify}$B%j%]%8%H%j$X9T$-!$(B\hgxcmd{mq}{qpush}$B%3%^%s%I$K(B + \hgxopt{mq}{qpush}{-a}$B%*%W%7%g%s$r;H$C$F(B\hgext{inotify}$B$N%Q%C%A$r$9(B + $B$Y$FE,MQ$9$k!%(B + + \begin{codesample4} + cd inotify + hg qpush -a + \end{codesample4} +% If you get an error message from \hgxcmd{mq}{qpush}, you should not +% continue. Instead, ask for help. + +\hgxcmd{mq}{qpush}$B$G%(%i!<$,5/$-$?>l9g!$@h$X?J$^$:$K=u8@$r5a$a$FM_$7$$!%(B + +%\item Build and install the patched version of Mercurial. +\item $B%Q%C%A$rEv$F$?(BMercurial$B$r%S%k%I$7$F%$%s%9%H!<%k$9$k!%(B + \begin{codesample4} + python setup.py build --force + sudo python setup.py install --skip-build + \end{codesample4} +\end{enumerate} +%Once you've build a suitably patched version of Mercurial, all you +%need to do to enable the \hgext{inotify} extension is add an entry to +%your \hgrc. + +$BE,@Z$J%Q%C%A$NEv$C$?(BMercurial$B$r%S%k%I$9$l$P!$8e$O(B\hgext{inotify}$B3HD%$rMx(B +$BMQ$9$k$h$&$K(B\hgrc $B$r@_Dj$9$k$@$1$G$"$k!%(B + +\begin{codesample2} + [extensions] + inotify = +\end{codesample2} +%When the \hgext{inotify} extension is enabled, Mercurial will +%automatically and transparently start the status daemon the first time +%you run a command that needs status in a repository. It runs one +%status daemon per repository. + +\hgext{inotify}$B$,M-8z$K$J$C$F$$$k$H!$(BMercurial$B$O%j%]%8%H%jFb$G%3%^%s%I$,(B +$B:G=i$K<B9T$5$l$?;~$K<+F0E*$+$DF)2aE*$K%9%F!<%?%9%G!<%b%s$r5/F0$9$k!%%j%](B +$B%8%H%j(B1$B$D$4$H$K(B1$B$D$N%9%F!<%?%9%G!<%b%s$,5/F0$5$l$k!%(B + +%The status daemon is started silently, and runs in the background. If +%you look at a list of running processes after you've enabled the +%\hgext{inotify} extension and run a few commands in different +%repositories, you'll thus see a few \texttt{hg} processes sitting +%around, waiting for updates from the kernel and queries from +%Mercurial. + +$B%9%F!<%?%9%G!<%b%s$O2?$b=PNO$r9T$o$:!$%P%C%/%0%i%&%s%I$GF0:n$9(B +$B$k!%(B\hgext{inotify}$B3HD%$rM-8z$K$7$?8e$GJL$N%j%]%8%H%jFb$G$$$/$D$+%3%^%s%I(B +$B$r<B9T$7!$<B9TCf$N%W%m%;%9$N%j%9%H$r8+$k$H!$$$$/$D$+$N(B\texttt{hg}$B%W%m%;%9(B +$B$,%+!<%M%k$+$i$N%"%C%W%G!<%H$H(BMercurial$B$+$i$NLd$$9g$o$;$rBT$C$F$$$k$N$,(B +$B8+$i$l$k$@$m$&!%(B + +%The first time you run a Mercurial command in a repository when you +%have the \hgext{inotify} extension enabled, it will run with about the +%same performance as a normal Mercurial command. This is because the +%status daemon needs to perform a normal status scan so that it has a +%baseline against which to apply later updates from the kernel. +%However, \emph{every} subsequent command that does any kind of status +%check should be noticeably faster on repositories of even fairly +%modest size. Better yet, the bigger your repository is, the greater a +%performance advantage you'll see. The \hgext{inotify} daemon makes +%status operations almost instantaneous on repositories of all sizes! + +\hgext{inotify}$B3HD%$rM-8z$K$7!$%j%]%8%H%jFb$G(BMercurial$B%3%^%s%I$r:G=i$K<B(B +$B9T$7$?;~$ODL>o$N(BMercurial$B%3%^%s%I$HF1MM$N@-G=$GF0$/!%%9%F!<%?%9%G!<%b%s$O(B +$BDL>o$N%9%F!<%?%9%9%-%c%s$r9T$$!$%+!<%M%k$+$i99?7$NDLCN$r<u$1$k$?$a$N%Y!<(B +$B%9%i%$%s$r<hF@$7$F$*$+$J$1$l$P$J$i$J$$$+$i$G$"$k!%0lJ}$G!$8eB3$N%9%F!<%?(B +$B%9%A%'%C%/$r9T$&(B\emph{$B$9$Y$F$N(B}$B%3%^%s%I$O!$$=$3$=$3$NBg$-$5$N%j%]%8%H%j$K(B +$BBP$7$F$bL\$K8+$($F9bB.2=$5$l$k!%$5$i$K%j%]%8%H%j$,Bg$-$/$J$k$KO"$l$F@-G=(B +$B$N8~>e$OBg$-$/$J$k!%(B\hgext{inotify}$B%G!<%b%s$O!$%j%]%8%H%j$N%5%$%:$K4X$o$i(B +$B$:!$%9%F!<%?%9<hF@$r$[$\=V;~$K9T$&$3$H$,$G$-$k!%(B + +%If you like, you can manually start a status daemon using the +%\hgxcmd{inotify}{inserve} command. This gives you slightly finer +%control over how the daemon ought to run. This command will of course +%only be available when the \hgext{inotify} extension is enabled. + +\hgxcmd{inotify}{inserve}$B%3%^%s%I$r;H$C$F%9%F!<%?%9%G!<%b%s$r<jF0$G<B9T$9(B +$B$k$3$H$b2DG=$G$"$k!%$3$l$K$h$j!$%G!<%b%s$,$I$N$h$&$KF0:n$9$k$N$+$r$d$d:Y(B +$B$+$/%3%s%H%m!<%k$9$k$3$H$,$G$-$k!%EvA3$J$,$i!$$3$N%3%^%s%I$O(B +\hgext{inotify}$B$,M-8z$N>l9g$N$_MxMQ2DG=$G$"$k!%(B + + +%When you're using the \hgext{inotify} extension, you should notice +%\emph{no difference at all} in Mercurial's behaviour, with the sole +%exception of status-related commands running a whole lot faster than +%they used to. You should specifically expect that commands will not +%print different output; neither should they give different results. +%If either of these situations occurs, please report a bug. + +\hgext{inotify}$B3HD%$r;H$C$F$$$k;~$O(BMercurial$B$N(B\emph{$BA4$/JQ2=$J$7(B}$B$H$$$&F0(B +$B:n$K5$IU$/$@$m$&!%%9%F!<%?%9$K4X78$9$k%3%^%s%I$O0JA0$h$j$:$C$H9bB.$K$J$C(B +$B$F$$$k$H$$$&0l$D$NNc30$r=|$$$F%3%^%s%I$OFCJL$N=PNO$b7k2L$b=PNO$7$J$$$3$H(B +$B$KN10U$5$l$?$$!%2?$+FCJL$J$3$H$,5/$-$?$i%P%0$H$7$FJs9p$7$FM_$7$$!%(B + +%\section{Flexible diff support with the \hgext{extdiff} extension} +\section{\hgext{extdiff}$B3HD%$K$h$k=@Fp$J(Bdiff$B%5%]!<%H(B} +\label{sec:hgext:extdiff} + +%Mercurial's built-in \hgcmd{diff} command outputs plaintext unified +%diffs. +%\interaction{extdiff.diff} +%If you would like to use an external tool to display modifications, +%you'll want to use the \hgext{extdiff} extension. This will let you +%use, for example, a graphical diff tool. + +Mercurial$B$N%S%k%H%$%s%3%^%s%I(B\hgcmd{diff}$B$O(Bunified$B7A<0$N(Bdiff$B$r%W%l!<%s%F(B +$B%-%9%H$G=PNO$9$k!%(B +\interaction{extdiff.diff} +$BJQ99$r30It%D!<%k$r;H$C$FI=<($7$?$$$J$i$P!$(B\hgext{extdiff}$B3HD%$r;H$&$HNI(B +$B$$!%$3$N3HD%$ONc$($P%0%i%U%#%+%k$J(Bdiff$BI=<($r9T$&!%(B + +%The \hgext{extdiff} extension is bundled with Mercurial, so it's easy +%to set up. In the \rcsection{extensions} section of your \hgrc, +%simply add a one-line entry to enable the extension. + +\hgext{extdiff}$B3HD%$O(BMercurial$B$KF1:-$5$l$F$$$k$N$G!$%;%C%H%"%C%W$OMF0W$G(B +$B$"$k!%(B\hgrc $B$NCf$N(B\rcsection{extensions}$B%;%/%7%g%s$K(B1$B9T$N@_Dj$rDI2C$9$k(B +$B$@$1$GNI$$!%(B +\begin{codesample2} + [extensions] + extdiff = +\end{codesample2} + +%This introduces a command named \hgxcmd{extdiff}{extdiff}, which by +%default uses your system's \command{diff} command to generate a +%unified diff in the same form as the built-in \hgcmd{diff} command. +%\interaction{extdiff.extdiff} +%The result won't be exactly the same as with the built-in \hgcmd{diff} +%variations, because the output of \command{diff} varies from one +%system to another, even when passed the same options. + +$B$3$N3HD%$G(B\hgxcmd{extdiff}{extdiff}$B$H$$$&%3%^%s%I$,;H$($k$h$&$K$J$k!%(B +$B$3$N%3%^%s%I$O%7%9%F%`$N(B\command{diff}$B$r;H$C$FAH$_9~$_$N(B\hgcmd{diff}$B%3%^(B +$B%s%I$HF1MM$N(Bunified$B7A<0$N(Bdiff$B$r@8@.$9$k!%(B +\interaction{extdiff.extdiff} +$BF@$i$l$k@.2LJ*$OAH$_9~$_$N(B\hgcmd{diff}$B$HA4$/F1$8$K$O$J$i$J$$$@$m$&!%M}M3(B +$B$O(B\command{diff}$B%3%^%s%I$O%7%9%F%`Kh$K0[$J$j!$F1$8%*%W%7%g%s$rEO$7$F$bF1(B +$B$8=PNO$r$9$k$H$O8B$i$J$$$+$i$@!%(B + +%As the ``\texttt{making snapshot}'' lines of output above imply, the +%\hgxcmd{extdiff}{extdiff} command works by creating two snapshots of +%your source tree. The first snapshot is of the source revision; the +%second, of the target revision or working directory. The +%\hgxcmd{extdiff}{extdiff} command generates these snapshots in a +%temporary directory, passes the name of each directory to an external +%diff viewer, then deletes the temporary directory. For efficiency, it +%only snapshots the directories and files that have changed between the +%two revisions. + +$B=PNO$N(B``\texttt{making snapshot}''$B9T$,<gD%$9$k$h$&(B +$B$K!$(B\hgxcmd{extdiff}{extdiff}$B%3%^%s%I$O%=!<%9%D%j!<$N(B2$B$D$N%9%J%C%W%7%g%C(B +$B%H$r:n$k$h$&$KF/$/!%(B 1$B$DL\$N%9%J%C%W%7%g%C%H$O%=!<%9%j%S%8%g%s$G!$(B2$B$DL\$O(B +$B%o!<%-%s%0%G%#%l%/%H%j$N%?!<%2%C%H%j%S%8%g%s$G$"$k!%(B +\hgxcmd{extdiff}{extdiff}$B%3%^%s%I$O$3$l$i$N%9%J%C%W%7%g%C%H$r%F%s%]%i%j%G%#(B +$B%l%/%H%j$K:n$j!$30It(Bdiff$B%S%e!<%"$K$=$l$>$l$N%G%#%l%/%H%j$NL>A0$rEO$9!%$=(B +$B$N8e!$%F%s%]%i%j%G%#%l%/%H%j$r>C5n$9$k!%8zN($N$?$a$K(B2$B$D$N%j%S%8%g%s4V$GJQ(B +$B99$N$"$C$?%G%#%l%/%H%j$H%U%!%$%k$N%9%J%C%W%7%g%C%H$@$1$r<h$k!%(B + +%Snapshot directory names have the same base name as your repository. +%If your repository path is \dirname{/quux/bar/foo}, then \dirname{foo} +%will be the name of each snapshot directory. Each snapshot directory +%name has its changeset ID appended, if appropriate. If a snapshot is +%of revision \texttt{a631aca1083f}, the directory will be named +%\dirname{foo.a631aca1083f}. A snapshot of the working directory won't +%have a changeset ID appended, so it would just be \dirname{foo} in + +%this example. To see what this looks like in practice, look again at +%the \hgxcmd{extdiff}{extdiff} example above. Notice that the diff has +%the snapshot directory names embedded in its header. + +$B%9%J%C%W%7%g%C%H%G%#%l%/%H%j$NL>A0$O%j%]%8%H%j$HF1$8%Y!<%9%M!<%`$r;}$D!%(B +$B%j%]%8%H%j$N%Q%9$,(B\dirname{/quux/bar/foo}$B$J$i$P!$(B\dirname{foo}$B$,%9%J%C%W(B +$B%7%g%C%H%G%#%l%/%H%j$N%Y!<%9%M!<%`$K$J$j!$$3$3$K%A%'%s%8%;%C%H(BID$B$,IU2C$5(B +$B$l$k!%%9%J%C%W%7%g%C%H$N%j%S%8%g%s$,(B\texttt{a631aca1083f}$B$J$i!$%G%#%l%/%H(B +$B%j$O(B\dirname{foo.a631aca1083f}$B$H$J$k!%%o!<%-%s%0%G%#%l%/%H%j$N%9%J%C%W(B +$B%7%g%C%H$O%A%'%s%8%;%C%H(BID$B$r;}$?$J$$$N$G!$$3$NNc$G$O(B\dirname{foo}$B$H$$$&L>(B +$BA0$K$J$k!%<B:]$NF0:n$r8+$k$K$O!$>e5-$N(B\hgxcmd{extdiff}{extdiff}$B$r;2>H$5$l(B +$B$?$$!%(B diff$B$N%X%C%@$K$O%9%J%C%W%7%g%C%H%G%#%l%/%H%jL>$,Kd$a9~$^$l$F$$$kE@(B +$B$KN10U$5$l$?$$!%(B + +%The \hgxcmd{extdiff}{extdiff} command accepts two important options. +%The \hgxopt{extdiff}{extdiff}{-p} option lets you choose a program to +%view differences with, instead of \command{diff}. With the +%\hgxopt{extdiff}{extdiff}{-o} option, you can change the options that +%\hgxcmd{extdiff}{extdiff} passes to the program (by default, these +%options are ``\texttt{-Npru}'', which only make sense if you're +%running \command{diff}). In other respects, the +%\hgxcmd{extdiff}{extdiff} command acts similarly to the built-in +%\hgcmd{diff} command: you use the same option names, syntax, and +%arguments to specify the revisions you want, the files you want, and +%so on. + +\hgxcmd{extdiff}{extdiff}$B%3%^%s%I$K$O=EMW$J%*%W%7%g%s$,(B2$B$D$"$k!%(B +\hgxopt{extdiff}{extdiff}{-p}$B%*%W%7%g%s$G:9J,$r<h$k%3%^%s%I$H$7$F(B +\command{diff}$B0J30$N%3%^%s%I$r;XDj$G$-$k!%(B \hgxopt{extdiff}{extdiff}{-o} +$B%*%W%7%g%s$G(B\hgxcmd{extdiff}{extdiff}$B$,30It%W%m%0%i%`$KEO$9%*%W%7%g%s$rJQ(B +$B99$9$k$3$H$,$G$-$k!%!J%G%U%)%k%H$G$O(B``\texttt{-Npru}''$B$,EO$5$l$k!%$3$l$O(B +\command{diff}$B$,5/F0$5$l$k;~$N$_0UL#$r;}$D!%!K$=$NB>$NE@$G$O(B +\hgxcmd{extdiff}{extdiff}$B%3%^%s%I$O%S%k%H%$%s$N(B\hgcmd{diff}$B$HF1MM$NF0:n$r(B +$B$9$k!%$9$J$o$A!$F1$8%*%W%7%g%sL>!$J8K!!$%j%S%8%g%s$d%U%!%$%k$r;XDj$9$k=q(B +$B<0$J$I$r;}$D!%(B + +%As an example, here's how to run the normal system \command{diff} +%command, getting it to generate context diffs (using the + +%\cmdopt{diff}{-c} option) instead of unified diffs, and five lines of +%context instead of the default three (passing \texttt{5} as the +%argument to the \cmdopt{diff}{-C} option). +%\interaction{extdiff.extdiff-ctx} + +$B$3$3$G%7%9%F%`$NDL>o%3%^%s%I$N(B\command{diff}$B$r!$(Bunified diff$B7A<0$G$O$J(B +$B$/!$!J(B\cmdopt{diff}{-c}$B%*%W%7%g%s$r;H$C$F!K(Bcontext diff$B7A<0$r=PNO$5$;$kNc(B +$B$r8+$F$_$h$&!%(Bcontext diff$B$K4^$^$l$k%3%s%F%-%9%H$N9T?t$b%G%U%)%k%H$N(B3$B9T$G(B +$B$O$J$/!$!J(B\cmdopt{diff}{-C}$B$X(B\texttt{5}$B%*%W%7%g%s$rEO$7$F!K(B5$B9T=PNO$5$;$k(B +$B$h$&$K$9$k!%(B + +%Launching a visual diff tool is just as easy. Here's how to launch +%the \command{kdiff3} viewer. +$B%S%8%e%"%k(Bdiff$B%D!<%k$N5/F0$O$?$d$9$$!%$3$3$G$O(B\command{kdiff3}$B%S%e!<%"$N(B +$B5/F0J}K!$r<($9!%(B +\begin{codesample2} + hg extdiff -p kdiff3 -o '' +\end{codesample2} + +%If your diff viewing command can't deal with directories, you can +%easily work around this with a little scripting. For an example of +%such scripting in action with the \hgext{mq} extension and the +%\command{interdiff} command, see +%section~\ref{mq-collab:tips:interdiff}. + +$BMxMQ$7$h$&$H$9$k(Bdiff$B%S%e!<%3%^%s%I$,%G%#%l%/%H%j$r07$($J$$>l9g!$$o$:$+$J(B +$B%9%/%j%W%H$r=q$/$3$H$G4JC1$K$3$NLdBj$r2sHr$9$k$3$H$,$G$-$k!%<B:]$K;H$o$l(B +$B$F$$$k%9%/%j%W%HNc$H$7$F$O!$(B\hgext{mq}$B3HD%$H(B\command{interdiff}$B%3%^%s%I$N(B +$B4V$N$b$N$,$"$k!%$3$l$K$D$$$F$O(B\ref{mq-collab:tips:interdiff}$B$r;2>H$5$l$?(B +$B$$!%(B + +%\subsection{Defining command aliases} +\subsection{$B%3%^%s%I$N%(%$%j%"%9$r:n$k(B} + +%It can be cumbersome to remember the options to both the +%\hgxcmd{extdiff}{extdiff} command and the diff viewer you want to use, +%so the \hgext{extdiff} extension lets you define \emph{new} commands +%that will invoke your diff viewer with exactly the right options. + +\hgxcmd{extdiff}{extdiff}$B%3%^%s%I$H(Bdiff$B%S%e!<%"APJ}$N%*%W%7%g%s$r3P$($F$*(B +$B$/$N$OLq2p$J$?$a!$(B\hgext{extdiff}$B3HD%$G(Bdiff$B%S%e!<%"$r@5$7$$%*%W%7%g%s$G5/(B +$BF0$9$k(B\emph{$B?7$7$$(B}$B%3%^%s%I$rDj5A$9$k$3$H$,$G$-$k!%(B + +%All you need to do is edit your \hgrc, and add a section named +%\rcsection{extdiff}. Inside this section, you can define multiple +%commands. Here's how to add a \texttt{kdiff3} command. Once you've +%defined this, you can type ``\texttt{hg kdiff3}'' and the +%\hgext{extdiff} extension will run \command{kdiff3} for you. + +$B$3$N$?$a$K$O(B\hgrc $B$rJT=8$7(B\rcsection{extdiff}$B$H$$$&L>A0$N?7$7$$%;%/%7%g%s(B +$B$rDI2C$9$l$P$h$$!%$3$N%;%/%7%g%sFb$G$OJ#?t$N%3%^%s%I$rDj5A$9$k$3$H$,$G$-(B +$B$k!%(B\texttt{kdiff3}$B%3%^%s%I$rDI2C$9$kJ}K!$rNc$H$7$F<($9!%0lEYDj5A$r9T$((B +$B$P!$(B``\texttt{hg kdiff3}''$B$H%?%$%W$9$k$3$H$G(B\hgext{extdiff}$B3HD%$,(B +\command{kdiff3}$B$r<B9T$9$k!%(B + +\begin{codesample2} + [extdiff] + cmd.kdiff3 = +\end{codesample2} + +%If you leave the right hand side of the definition empty, as above, +%the \hgext{extdiff} extension uses the name of the command you defined +%as the name of the external program to run. But these names don't +%have to be the same. Here, we define a command named ``\texttt{hg +% wibble}'', which runs \command{kdiff3}. + +$B>e$NNc$N$h$&$K1&JU$r6u$K$7$F$*$/$H!$(B\hgext{extdiff}$B3HD%$O30It$G5/F0$9$Y$-(B +$B%3%^%s%IL>$H$7$FDj5A$rMQ$$$k!%$3$NL>A0$O=EJ#$7$F$O$J$i$J$$!%$3$3$G$O(B +``\texttt{hg wibble}''$B$H$$$&L>A0$G%3%^%s%I(B\command{kdiff3}$B$r8F$S=P$9$rDj(B +$B5A$7$F$$$k!%(B + +\begin{codesample2} + [extdiff] + cmd.wibble = kdiff3 +\end{codesample2} + +%You can also specify the default options that you want to invoke your +%diff viewing program with. The prefix to use is ``\texttt{opts.}'', +%followed by the name of the command to which the options apply. This +%example defines a ``\texttt{hg vimdiff}'' command that runs the +%\command{vim} editor's \texttt{DirDiff} extension. + +diff$B%S%e!<%"$r5/F0$9$k:]$N%G%U%)%k%H%*%W%7%g%s$bDj5A$G$-$k!%Dj5A$G$O%*%W(B +$B%7%g%s$rDj5A$7$?$$%3%^%s%I$NA0$K(B``\texttt{opts.}''$B$H$$$&@\F,<-$rIU$1$k!%(B +$B$3$NNc$G$O(B\command{vim}$B%(%G%#%?$r(B\texttt{DirDiff}$B%*%W%7%g%sIU$-$G5/F0$9$k(B +``\texttt{hg vimdiff}''$B%3%^%s%I$rDj5A$7$F$$$k!%(B + +\begin{codesample2} + [extdiff] + cmd.vimdiff = vim + opts.vimdiff = -f '+next' '+execute "DirDiff" argv(0) argv(1)' +\end{codesample2} + +%\section{Cherrypicking changes with the \hgext{transplant} extension} +\section{\hgext{transplant}$B3HD%$rMQ$$$?%A%'%j!<%T%C%-%s%099?7(B} +\label{sec:hgext:transplant} + +%Need to have a long chat with Brendan about this. +$B!J(BBrendan$B$H$h$/OC$r$9$kI,MW$,$"$k!%!K(B + +%\section{Send changes via email with the \hgext{patchbomb} extension} +\section{\hgext{patchbomb}$B3HD%$K$h$C$FJQ99$r%a!<%k$9$k(B} +\label{sec:hgext:patchbomb} + +%Many projects have a culture of ``change review'', in which people +%send their modifications to a mailing list for others to read and +%comment on before they commit the final version to a shared +%repository. Some projects have people who act as gatekeepers; they +%apply changes from other people to a repository to which those others +%don't have access. + +$BB?$/$N%W%m%8%'%/%H$,(B``$B99?7$N%l%S%e!<(B''$B$NJ82=$r;}$C$F$$$k!%3+H/<T$?$A$O:G(B +$B=*%P!<%8%g%s$r6&M-%j%]%8%H%j$K%3%_%C%H$9$kA0$K!$%Q%C%A$r::FI<TC#$,$$$k%a!<(B +$B%j%s%0%j%9%H$XJQ99$rAw$j!$%A%'%C%/$d<u$1$?$j%3%a%s%H$rLc$C$?$j$9$k!%$$$/(B +$B$D$+$N%W%m%8%'%/%H$G$OLgHV$N$h$&$J?M!9$r;}$C$F$$$?$j$5$($9$k!%H`$i$N;E;v(B +$B$O!$?M!9$+$iAw$i$l$?JQ99$r!$H`$i0J30$K%"%/%;%98"$N$J$$%j%]%8%H%j$XE,MQ$9(B +$B$k$3$H$G$"$k!%(B + +%Mercurial makes it easy to send changes over email for review or +%application, via its \hgext{patchbomb} extension. The extension is so +%namd because changes are formatted as patches, and it's usual to send +%one changeset per email message. Sending a long series of changes by +%email is thus much like ``bombing'' the recipient's inbox, hence +%``patchbomb''. + +Mercurial$B$G$O(B\hgext{patchbomb}$B3HD%$rMQ$$$k$H%l%S%e!<$dE,MQ$N$?$a$KJQ99$r(B +$B%a!<%k$GAw?.$9$k$3$H$,MF0W$K$J$k!%$3$N3HD%$NL>A0$OJQ99$r%Q%C%A$H$7$F%U%)!<(B +$B%^%C%H$7!$(B1$B$D$N%A%'%s%8%;%C%HKh$K%a!<%k(B1$BDL$rAw?.$9$k$3$H$KM3Mh$9$k!%(B +$B0lO"$NJQ99$rO"B3$7$F%a!<%k$GAw?.$9$k$3$H$r(B``$BGz7b(B''$B$K8+N)$F$F$$$k!%=>$C$F(B +$B<u?.<T$,<u$1<h$k$N$O(B``$B%Q%C%AGzCF(B''$B$G$"$k!%(B + +%As usual, the basic configuration of the \hgext{patchbomb} extension +%takes just one or two lines in your \hgrc. +$BDL>o!$(B\hgext{patchbomb}$B3HD%$N4pK\@_Dj$O(B\hgrc $B$NCf$G(B1$B!$(B2$B9T$[$I$G$"$k!%(B + +\begin{codesample2} + [extensions] + patchbomb = +\end{codesample2} +%Once you've enabled the extension, you will have a new command +%available, named \hgxcmd{patchbomb}{email}. + +$B3HD%$rM-8z$K$9$k$H!$(B\hgxcmd{patchbomb}{email}$B%3%^%s%I$,;H$($k$h$&$K$J$k!%(B + +%The safest and best way to invoke the \hgxcmd{patchbomb}{email} +%command is to \emph{always} run it first with the +%\hgxopt{patchbomb}{email}{-n} option. This will show you what the +%command \emph{would} send, without actually sending anything. Once +%you've had a quick glance over the changes and verified that you are +%sending the right ones, you can rerun the same command, with the +%\hgxopt{patchbomb}{email}{-n} option removed. + +\hgxcmd{patchbomb}{email}$B$r5/F0$9$k$N$K:G$b0BA4$GNI$$J}K!$O!$$^$::G=i$K(B +\hgxopt{patchbomb}{email}{-n}$B%*%W%7%g%s$rIU$1$F<B9T$7$F$_$k$3$H$@!%(B +$B$3$l$K$h$j!$<B:]$NAw?.$O9T$o$:$K2?$,5/$-$k$N$+$r8+$k$3$H$,$G$-$k!%JQ99$K(B +$BL\$rDL$7$F@5$7$$JQ99$rAw?.$9$k$3$H$r3NG'$G$-$?$i!$F1$8%3%^%s%I$r(B +\hgxopt{patchbomb}{email}{-n}$B%*%W%7%g%s$J$7$G<B9T$9$k!%(B + +%The \hgxcmd{patchbomb}{email} command accepts the same kind of +%revision syntax as every other Mercurial command. For example, this +%command will send every revision between 7 and \texttt{tip}, +%inclusive. + +\hgxcmd{patchbomb}{email}$B%3%^%s%I$OB>$N(BMercurial$B%3%^%s%I$HF1MM$N%j%S%8%g(B +$B%s;XDj9=J8$r<u$1IU$1$k!%Nc$($P%j%S%8%g%s(B7$B$+$i(Btip$B$^$G$r4^$`JQ99$rAw?.$9$k(B +$B$J$I$N$h$&$K;XDj$,2DG=$G$"$k!%(B +\begin{codesample2} + hg email -n 7:tip +\end{codesample2} + +%You can also specify a \emph{repository} to compare with. If you +%provide a repository but no revisions, the \hgxcmd{patchbomb}{email} +%command will send all revisions in the local repository that are not + +%present in the remote repository. If you additionally specify +%revisions or a branch name (the latter using the +%\hgxopt{patchbomb}{email}{-b} option), this will constrain the +%revisions sent. + +$BHf3SBP>]$H$7$F(B\emph{$B%j%]%8%H%j(B}$B$r;XDj$9$k$3$H$b$G$-$k!%%j%]%8%H%j$r;XDj(B +$B$7!$%j%S%8%g%s$r;XDj$7$J$$>l9g!$(B\hgxcmd{patchbomb}{email}$B$O%m!<%+%k%j%]%8(B +$B%H%j$K$"$C$F%j%b!<%H%j%]%8%H%j$K$J$$A4$F$N%P!<%8%g%s$rAw?.$9$k!%%j%S%8%g(B +$B%s$^$?$O%V%i%s%AL>$r;XDj$9$k$H!J8e<T$O(B\hgxopt{patchbomb}{email}{-b}$B$rMQ$$(B +$B$k!K!$Aw?.$5$l$k%j%S%8%g%s$K@)8B$,2C$o$k!%(B + +%It's perfectly safe to run the \hgxcmd{patchbomb}{email} command +%without the names of the people you want to send to: if you do this, +%it will just prompt you for those values interactively. (If you're +%using a Linux or Unix-like system, you should have enhanced +%\texttt{readline}-style editing capabilities when entering those +%headers, too, which is useful.) + +$BAw?.$7$?$$?MC#$NL>A0$r;XDj$;$:$K(B\hgxcmd{patchbomb}{email}$B%3%^%s%I$r;H$C$F(B +$B$bA4$/0BA4$G$"$k!%$3$N>l9g!$BPOCE*$KF~NO$r5a$a$k!%(BLinux$B$^$?$O(BUnix$B7O$N%7%9(B +$B%F%`$r;H$C$F$$$l$P!$%X%C%@$NF~NO$K;H$$$d$9$$(B\texttt{readline}$B%9%?%$%k$NJT(B +$B=85!G=$rMxMQ$G$-$k(B + +%When you are sending just one revision, the \hgxcmd{patchbomb}{email} +%command will by default use the first line of the changeset +%description as the subject of the single email message it sends. + +$B$?$@(B1$B$D$N%j%S%8%g%s$rAw$k>l9g!$(B\hgxcmd{patchbomb}{email}$B%3%^%s%I$O%G%U%)(B +$B%k%H$G%A%'%s%8%;%C%H$N@bL@$N:G=i$N9T$r%a!<%k$N7oL>$H$7$FMQ$$$k!%(B + +%If you send multiple revisions, the \hgxcmd{patchbomb}{email} command +%will usually send one message per changeset. It will preface the +%series with an introductory message, in which you should describe the +%purpose of the series of changes you're sending. + +$BJ#?t$N%j%S%8%g%s$rAw$k>l9g!$(B\hgxcmd{patchbomb}{email}$B%3%^%s%I$O(B1$B$D$N%A%'(B +$B%s%8%;%C%HKh$K(B1$BDL$N%a!<%k$rAw?.$9$k!%3+;O$N%a!<%k$K$O0lO"$NJQ99$NL\E*$r5-(B +$B=R$9$k@bL@J8$rIU$1$k!%(B + + +%\subsection{Changing the behaviour of patchbombs} +\subsection{patchbombs$B$N5sF0$rJQ99$9$k(B} + +%Not every project has exactly the same conventions for sending changes +%in email; the \hgext{patchbomb} extension tries to accommodate a +%number of variations through command line options. + +$BA4$F$N%W%m%8%'%/%H$,F1$8$h$&$J%a!<%k$K$h$kJQ99$NAwIU$N=,47$r;}$C$F$$$k$o(B +$B$1$G$O$J$$!%(B\hgext{patchbomb}$B3HD%$O%3%^%s%I%i%$%s%*%W%7%g%s$GMM!9$JJ}K!(B +$B$KBP1~$G$-$k$h$&$K$J$C$F$$$k!%(B + +\begin{itemize} +%\item You can write a subject for the introductory message on the +% command line using the \hgxopt{patchbomb}{email}{-s} option. This +% takes one argument, the text of the subject to use. + \item $B%3%^%s%I%i%$%s$+$i(B\hgxopt{patchbomb}{email}{-s}$B%*%W%7%g%s$r;H$C(B + $B$F!$@bL@J8$K$J$k7oL>$rF~NO$9$k$3$H$,$G$-$k!%$3$N%*%W%7%g%s$O7oL>$H(B + $B$7$F;H$o$l$k%F%-%9%H$r0z?t$H$7$F<h$k!%(B + +%\item To change the email address from which the messages originate, +% use the \hgxopt{patchbomb}{email}{-f} option. This takes one +% argument, the email address to use. + \item $B%a%C%;!<%8$NAw?.85$N%"%I%l%9$rJQ99$9$k$K$O(B + \hgxopt{patchbomb}{email}{-f}$B%*%W%7%g%s$rMQ$$$k!%$3$N%*%W%7%g%s$O(B + $B%a!<%k%"%I%l%9$r0z?t$H$7$F<h$k!%(B + +%\item The default behaviour is to send unified diffs (see +% section~\ref{sec:mq:patch} for a description of the format), one per +% message. You can send a binary bundle instead with the +% \hgxopt{patchbomb}{email}{-b} option. + \item $B%G%U%)%k%H$G$O(B1$B%a%C%;!<%8Kh$K(Bunified$B7A<0(Bdiff$B$rAw?.$9$k!%!J$3$N%U%)!<(B + $B%^%C%H$K$D$$$F$O(B\ref{sec:mq:patch}$B$r;2(B + $B>H!%!K(B\hgxopt{patchbomb}{email}{-b}$B%*%W%7%g%s$r;H$($P!$%P%$%J%j7A(B + $B<0$N%G!<%?$rE:IU$9$k$3$H$b$G$-$k!%(B + +%\item Unified diffs are normally prefaced with a metadata header. You +% can omit this, and send unadorned diffs, with the +% \hgxopt{patchbomb}{email}{--plain} option. + \item unified$B7A<0(Bdiff$B$ODL>o%a%?%G!<%?$N%X%C%@$r;}(B + $B$D!%(B\hgxopt{patchbomb}{email}{--plain}$B%*%W%7%g%s$r;H$&$3$H$G$3$l(B + $B$r3d0&$9$k$3$H$,$G$-$k!%(B + +%\item Diffs are normally sent ``inline'', in the same body part as the +% description of a patch. This makes it easiest for the largest +% number of readers to quote and respond to parts of a diff, as some +% mail clients will only quote the first MIME body part in a message. +% If you'd prefer to send the description and the diff in separate +% body parts, use the \hgxopt{patchbomb}{email}{-a} option. + \item $BDL>o!$:9J,$O%Q%C%A$N@bL@$HF1$8%\%G%#$NCf$K(B``$B%$%s%i%$%s(B''$B$G=q$-9~$^(B + $B$l$k!%$$$/$D$+$N%a!<%k%/%i%$%"%s%H$G$O:G=i$N(BMIME$B%Q!<%H$N$_$+$i0zMQ(B + $B$,2DG=$J$?$a!$$3$&$9$k$3$H$,:G$bB?$/$N?M$K$H$C$F%Q%C%A$NFCDj$NItJ,(B + $B$K%3%a%s%H$7$?$j$9$k$N$K9%ET9g$G$"$k!%@bL@J8$H(Bdiff$B$rJL$N%\%G%#%Q!<(B + $B%H$K$7$FAw?.$7$?$$>l9g$O(B\hgxopt{patchbomb}{email}{-a}$B%*%W%7%g%s$r(B + $B;H$&!%(B + +%\item Instead of sending mail messages, you can write them to an +% \texttt{mbox}-format mail folder using the +% \hgxopt{patchbomb}{email}{-m} option. That option takes one +% argument, the name of the file to write to. + \item $B%a!<%k$G%a%C%;!<%8$rAw?.$9$kJQ$o$j(B + $B$K!$(B\hgxopt{patchbomb}{email}{-m}$B%*%W%7%g%s$r;H$C$F(B + \texttt{mbox}$B%U%)!<%^%C%H$G=PNO$5$;$k$3$H$b2DG=$@!%(B + $B$3$N%*%W%7%g%s$O=PNO%U%!%$%kL>$r0l$D%*%W%7%g%s$H$7$F<h$k!%(B + +%\item If you would like to add a \command{diffstat}-format summary to +% each patch, and one to the introductory message, use the +% \hgxopt{patchbomb}{email}{-d} option. The \command{diffstat} +% command displays a table containing the name of each file patched, +% the number of lines affected, and a histogram showing how much each +% file is modified. This gives readers a qualitative glance at how +% complex a patch is. + \item \command{diffstat}$B%U%)!<%^%C%H$N%5%^%j$r3F!9$N%Q%C%A$KIU$1!$@bL@J8(B + $B$rIU$1$?$$>l9g$O!$(B\hgxopt{patchbomb}{email}{-d}$B%*%W%7%g%s$r;H$&$H(B + $BNI$$!%(B\command{diffstat}$B%3%^%s%I$O%Q%C%A$5$l$?3F!9$N%U%!%$%kL>!$1F(B + $B6A$r<u$1$?9T?t!$3F%U%!%$%k$,$I$l$@$1JQ99$5$l$?$+$r<($9%R%9%H%0%i%`(B + $B$r$r4^$`%F!<%V%k$rI=<($9$k!%$3$N>pJs$O!$%Q%C%A$NJ#;($5$K$D$$$FDj@-(B + $BE*$JM}2r$rF@$k$N$KLrN)$D!%(B + +\end{itemize} + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/hook.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,2062 @@ +%\chapter{Handling repository events with hooks} +\chapter{$B%j%]%8%H%j%$%Y%s%H$r%U%C%/$G<h$j07$&(B} +\label{chap:hook} + +%Mercurial offers a powerful mechanism to let you perform automated +%actions in response to events that occur in a repository. In some +%cases, you can even control Mercurial's response to those events. + +Mercurial$B$O!$%j%]%8%H%j$K5/$3$k%$%Y%s%H$KBP$7$F<+F02=$5$l$?%"%/%7%g%s$r9T(B +$B$&6/NO$J%a%+%K%:%`$r;}$C$F$$$k!%$$$/$D$+$N%$%Y%s%H$KBP$7$F$O!$(BMercurial$B$N(B +$BH?1~$r@)8f$9$k$3$H$b$G$-$k!%(B + +%The name Mercurial uses for one of these actions is a \emph{hook}. +%Hooks are called ``triggers'' in some revision control systems, but +%the two names refer to the same idea. + +Mercurial$B$O(B\emph{$B%U%C%/(B}$B$H8F$P$l$k5!9=$r;H$C$F%"%/%7%g%s$r9T$&!%%U%C%/$O(B +$BB>$N%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$G$O(B``$B%H%j%,(B''$B$H8F$P$l$k$3$H$b$"$k$,!$(B +$B$3$l$i$O<B:]$OF1$8$b$N$G$"$k!%(B + +%\section{An overview of hooks in Mercurial} +\section{Mercurial$B$G$N%U%C%/$N35MW(B} + +%Here is a brief list of the hooks that Mercurial supports. We will +%revisit each of these hooks in more detail later, in +%section~\ref{sec:hook:ref}. + +Mercurial$B$,%5%]!<%H$9$k%U%C%/$N0lIt$rNs5s$9$k!%8D!9$N%U%C%/$K$D$$$F$O(B +$B8e$[$I(Bsection~\ref{sec:hook:ref}$B$G>\:Y$K?($l$k!%(B + +\begin{itemize} +%\item[\small\hook{changegroup}] This is run after a group of +% changesets has been brought into the repository from elsewhere. +\item[\small\hook{changegroup}] $B%A%'%s%8%;%C%H%0%k!<%W$,30It$+$i%j%]%8%H(B + $B%j$K2C$o$C$?8e$G8F$S=P$5$l$k!%(B + +%\item[\small\hook{commit}] This is run after a new changeset has been +% created in the local repository. +\item[\small\hook{commit}] $B%m!<%+%k%j%]%8%H%j$G?7$7$$%A%'%s%8%;%C%H$,:n(B + $B@.$5$l$?8e$K8F$S=P$5$l$k!%(B + +%\item[\small\hook{incoming}] This is run once for each new changeset +% that is brought into the repository from elsewhere. Notice the +% difference from \hook{changegroup}, which is run once per +% \emph{group} of changesets brought in. + +\item[\small\hook{incoming}] $B?7$7$$%A%'%s%8%;%C%H$,30It$+$i%j%]%8%H%j$K2C(B + $B$o$kKh$K8F$S=P$5$l$k!%(B\emph{group}$B$,2C$o$kKh$K8F$S=P$5$l$k%U%C(B + $B%/$K(B\hook{changegroup}$B%U%C%/$,$"$k!%(B + +%\item[\small\hook{outgoing}] This is run after a group of changesets +% has been transmitted from this repository. +\item[\small\hook{outgoing}] $B%j%]%8%H%j$+$i%A%'%s%8%;%C%H%0%k!<%W$,30It(B + $B$KAw?.$5$l$?8e$K8F$S=P$5$l$k!%(B + +%\item[\small\hook{prechangegroup}] This is run before starting to +% bring a group of changesets into the repository. +\item[\small\hook{prechangegroup}] $B%A%'%s%8%;%C%H%0%k!<%W$r%j%]%8%H%j$+(B + $B$i30It$K;}$A=P$9A0$K8F$S=P$5$l$k!%(B + +%\item[\small\hook{precommit}] Controlling. This is run before starting +% a commit. +\item[\small\hook{precommit}] Controlling. $B%3%_%C%H$,;O$^$kA0$K8F$S=P$5(B + $B$l$k!%(B + +%\item[\small\hook{preoutgoing}] Controlling. This is run before +% starting to transmit a group of changesets from this repository. +\item[\small\hook{preoutgoing}] Controlling. $B%A%'%s%8%;%C%H%0%k!<%W$r%j(B + $B%]%8%H%j$+$i30It$KAw?.$9$kA0$K8F$S=P$5$l$k!%(B + +%\item[\small\hook{pretag}] Controlling. This is run before creating a tag. +\item[\small\hook{pretag}] Controlling. $B%?%0$,:n@.$5$l$kA0$K8F$S=P$5$l$k!%(B + +%\item[\small\hook{pretxnchangegroup}] Controlling. This is run after a +% group of changesets has been brought into the local repository from +% another, but before the transaction completes that will make the +% changes permanent in the repository. +\item[\small\hook{pretxnchangegroup}] Controlling. $B%A%'%s%8%;%C%H%0%k!<%W(B + $B$,30It$+$i%m!<%+%k%j%]%8%H%j$K2C$o$C$?8e!$1JB3E*$K5-O?$9$k$?(B + $B$a$N%H%i%s%6%/%7%g%s$,40N;$9$kA0$K8F$S=P$5$l$k!%(B + +%\item[\small\hook{pretxncommit}] Controlling. This is run after a new +% changeset has been created in the local repository, but before the +% transaction completes that will make it permanent. +\item[\small\hook{pretxncommit}] Controlling. $B?7$7$$%A%'%s%8%;%C%H$,%m!<(B + $B%+%k%j%]%8%H%j$G:n@.$5$l$?8e!$1JB3E*$K5-O?$9$k$?$a$N%H%i%s%6(B + $B%/%7%g%s$,40N;$9$kA0$K8F$S=P$5$l$k!%(B + +%\item[\small\hook{preupdate}] Controlling. This is run before starting +% an update or merge of the working directory. +\item[\small\hook{preupdate}] Controlling. $B%o!<%-%s%0%G%#%l%/%H%j$N99?7(B + $B$^$?$O%^!<%8$,9T$o$l$kA0$K8F$S=P$5$l$k!%(B + +%\item[\small\hook{tag}] This is run after a tag is created. +\item[\small\hook{tag}] $B%?%0$,:n@.$5$l$?8e$G8F$S=P$5$l$k!%(B + +%\item[\small\hook{update}] This is run after an update or merge of the +% working directory has finished. +\item[\small\hook{update}] $B%o!<%-%s%0%G%#%l%/%H%j$N99?7$+%^!<%8$,40N;$7(B + $B$?;~$K8F$S=P$5$l$k!%(B +\end{itemize} +%Each of the hooks whose description begins with the word +%``Controlling'' has the ability to determine whether an activity can +%proceed. If the hook succeeds, the activity may proceed; if it fails, +%the activity is either not permitted or undone, depending on the hook. + +$B%U%C%/$N$&$A!$@bL@$,(B``Controlling''$B$H$$$&8l$G;O$^$k$b$N$O!$%U%C%/$N@.H]$r(B +$BH=Dj$7!$0J8e$NF0:n$r9T$&$+$I$&$+7hDj$9$k5!G=$,$"$k!%%U%C%/$,@.8y$9$k$HF0(B +$B:n$O@h$X?J$`!%%U%C%/$,@.8y$7$J$+$C$?>l9g$O0J8e$NF0:n$O<B9T$,5v2D$5$l$J$$(B +$B$+!$F0:n$,40N;$;$:=*$k!%(B + +%\section{Hooks and security} +\section{$B%U%C%/$H%;%-%e%j%F%#(B} + +%\subsection{Hooks are run with your privileges} +\subsection{$B%U%C%/$O%f!<%6$N8"8B$GF0:n$9$k(B} + +%When you run a Mercurial command in a repository, and the command +%causes a hook to run, that hook runs on \emph{your} system, under +%\emph{your} user account, with \emph{your} privilege level. Since +%hooks are arbitrary pieces of executable code, you should treat them +%with an appropriate level of suspicion. Do not install a hook unless +%you are confident that you know who created it and what it does. + +$B%j%]%8%H%jFb$G(BMercurial$B%3%^%s%I$r<B9T$7!$%3%^%s%I$,%U%C%/$r8F$S=P$7$?>l(B +$B9g!$%U%C%/$O(B\emph{$BA`:n<T(B}$B$N%7%9%F%`$G!$(B\emph{$BA`:n<T(B}$B$NFC8"%l%Y%k$GF0:n$9(B +$B$k!%%U%C%/$OG$0U$N<B9T%3!<%I$J$N$G!$Aj1~$NN10U$,I,MW$G$"$k!%%U%C%/$r:n$C(B +$B$?$N$,C/$G!$$=$N%U%C%/$,2?$r$9$k$N$+$-$A$s$HM}2r$9$k$3$H$J$7$K%U%C%/$r%$(B +$B%s%9%H!<%k$7$F$O$J$i$J$$!%(B + +%In some cases, you may be exposed to hooks that you did not install +%yourself. If you work with Mercurial on an unfamiliar system, +%Mercurial will run hooks defined in that system's global \hgrc\ file. + +$B<+J,$G%$%s%9%H!<%k$7$?$N$G$O$J$$%U%C%/$r<B9T$5$;$F$7$^$&$3$H$bM-$jF@$k!%(B +$BB>=j$N%7%9%F%`$N>e$G(BMercurial$B$r;H$&>l9g!$(BMercurial$B$,%7%9%F%`%o%$%I$N(B +\hgrc\ $B%U%!%$%k$GDj5A$5$l$?%U%C%/$r5/F0$9$k2DG=@-$,$"$k!%(B + +%If you are working with a repository owned by another user, Mercurial +%can run hooks defined in that user's repository, but it will still run +%them as ``you''. For example, if you \hgcmd{pull} from that +%repository, and its \sfilename{.hg/hgrc} defines a local +%\hook{outgoing} hook, that hook will run under your user account, even +%though you don't own that repository. + +$BB>$N%f!<%6$,=jM-$9$k%j%]%8%H%j$G:n6H$9$k>l9g!$(BMercurial$B$O=jM-<T$N%j%]%8(B +$B%H%jFb$GDj5A$5$l$?%U%C%/$r<B9T$7F@$k$,!$<B9T8"8B$O$"$J$?$N$b$N$G9T$o$l$k!%(B +$BNc$($P$=$N%j%]%8%H%j$+$i(B\hgcmd{pull}$B$r9T$&$H$-!$%j%]%8%H%jFb$N(B +\sfilename{.hg/hgrc}$B%U%!%$%k$G%m!<%+%k$J(B\hook{outgoing}$B%U%C%/$,Dj5A$5$l$F(B +$B$$$k$H!$$"$J$?$O$=$N%j%]%8%H%j$r=jM-$7$F$$$J$$$K$b$+$+$o$i$:$=$N%U%C%/$O(B +$B$"$J$?$N8"8B$G<B9T$5$l$k!%(B + +%\begin{note} +% This only applies if you are pulling from a repository on a local or +% network filesystem. If you're pulling over http or ssh, any +% \hook{outgoing} hook will run under whatever account is executing +% the server process, on the server. +%\end{note} +\begin{note} +$B$3$l$O%m!<%+%k$J%j%]%8%H%j$d%M%C%H%o!<%/%U%!%$%k%7%9%F%`>e$N%j%]%8%H%j$+(B + $B$i(Bpull$B$7$?>l9g$K$N$_E,MQ$5$l$k!%(Bhttp$B$^$?$O(Bssh$B$r;H$C$F(Bpull$B$7$?>l9g!$$9$Y(B + $B$F$N(B\hook{outgoing}$B%U%C%/$O%5!<%P>e$G%5!<%P%W%m%;%9$r<B9T$7$F$$$k%"%+%&(B + $B%s%H$N8"8B$G<B9T$5$l$k!%(B +\end{note} + +%XXX To see what hooks are defined in a repository, use the +%\hgcmdargs{config}{hooks} command. If you are working in one +%repository, but talking to another that you do not own (e.g.~using +%\hgcmd{pull} or \hgcmd{incoming}), remember that it is the other +%repository's hooks you should be checking, not your own. + +XXX $B%j%]%8%H%jFb$GDj5A$5$l$F$$$k%U%C%/$r8+$k$K$O(B +\hgcmdargs{config}{hooks}$B%3%^%s%I$r;H$&!%$"$k%j%]%8%H%j$G:n6H$7$F$$$F!$?7(B +$B$7$$%3!<%I$rB>$N%j%]%8%H%j$+$iF~<j$9$k$?$a$KDL?.$r9T$&>l9g!JNc$($P(B +\hgcmd{pull}$B$+(B\hgcmd{incoming}$B$r<B9T$9$k!K(B $B!$%A%'%C%/$9$Y$-%U%C%/$O<j85$N(B +$B%j%]%8%H%j$N$b$N$G$O$J$/!$%j%b!<%H$N%j%]%8%H%j$N%U%C%/$G$"$k!%(B + +%\subsection{Hooks do not propagate} +\subsection{$B%U%C%/$OEAGE$7$J$$(B} + +%In Mercurial, hooks are not revision controlled, and do not propagate +%when you clone, or pull from, a repository. The reason for this is +%simple: a hook is a completely arbitrary piece of executable code. It +%runs under your user identity, with your privilege level, on your +%machine. + +Mercurial$B$G$O!$%U%C%/$O%j%S%8%g%s4IM}$5$l$:!$%j%]%8%H%j$+$i%/%m!<%s$7$?$j(B +pull$B$7$F$bEAGE$7$J$$!%$3$&$J$C$F$$$kM}M3$OC1=c$G!$%U%C%/$OG$0U$N<B9T2DG=(B +$B%3!<%I$G$"$k$+$i$G$"$k!%%U%C%/$O$"$J$?$N%^%7%s$N>e$G$"$J$?$N%f!<%6!<(BID$B$H(B +$BFC8"%l%Y%k$GF0:n$GF0$/!%(B + +%It would be extremely reckless for any distributed revision control +%system to implement revision-controlled hooks, as this would offer an +%easily exploitable way to subvert the accounts of users of the +%revision control system. + +$BJ,;6%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$K%j%S%8%g%s4IM}$5$l$?%U%C%/$r<BAu$9$k(B +$B$N$O$H$F$bL5KE$G$"$k!%$3$N$h$&$J5!9=$,$"$k$H%j%S%8%g%s%3%s%H%m!<%k%7%9%F(B +$B%`$N%f!<%6%"%+%&%s%H$r56Au$9$k$h$&$J;E3]$1$r4JC1$K<B8=$G$-$F$7$^$&!%(B + +%Since Mercurial does not propagate hooks, if you are collaborating +%with other people on a common project, you should not assume that they +%are using the same Mercurial hooks as you are, or that theirs are +%correctly configured. You should document the hooks you expect people +%to use. + +Mercurial$B$O%U%C%/$rEAGE$5$;$J$$$N$G!$6&DL$N%W%m%8%'%/%H$GB>$N3+H/<T$H6(NO(B +$B$7$F$$$k>l9g!$H`$i$O$"$J$?$,;H$C$F$k$N$HF1$8(BMercurial$B%U%C%/$r;H$C$F$$$k$H(B +$B2>Dj$7$?$j!$H`$i$N%j%]%8%H%j$G$b%U%C%/$,F1MM$K@5$7$/@_Dj$5$l$F$$$k$H2>Dj(B +$B$9$Y$-$G$O$J$$!%H`$i$,%U%C%/$r;H$&$h$&$KK>$`$N$G$"$l$P!$;HMQK!$K$D$$$F%I(B +$B%-%e%a%s%H$r:n@.$9$Y$-$G$"$k!%(B + +%In a corporate intranet, this is somewhat easier to control, as you +%can for example provide a ``standard'' installation of Mercurial on an +%NFS filesystem, and use a site-wide \hgrc\ file to define hooks that +%all users will see. However, this too has its limits; see below. + +$B4k6HFb$N%$%s%H%i%M%C%H$G$O%3%s%H%m!<%k$O4vJ,4JC1$G$"$k!%(B NFS$B%U%!%$%k%7%9(B +$B%F%`>e$G(BMercurial$B$N(B``$BI8=`(B''$B%$%s%9%H%l!<%7%g%sNc$rDs6!$7!$$9$Y$F$N%f!<%6$,(B +$B;2>H$9$k%5%$%H%o%$%I$N(B\hgrc\ $B%U%!%$%k$rMQ0U$7!$$=$NCf$G%U%C%/$rDj5A$9$k$3(B +$B$H$,$G$-$k!%$7$+$7$3$NJ}K!$K$b2<5-$N$h$&$J7gE@$,$"$k!%(B + +%\subsection{Hooks can be overridden} +\subsection{$B%U%C%/$O%*!<%P%i%$%I2DG=$G$"$k(B} + +%Mercurial allows you to override a hook definition by redefining the +%hook. You can disable it by setting its value to the empty string, or +%change its behaviour as you wish. + +Mercurial$B$G$O!$%U%C%/$r:FDj5A$9$k$3$H$K$h$C$F!$4{B8$N%U%C%/Dj5A$r%*!<%P%i(B +$B%$%I$9$k$3$H$,$G$-$k!%$3$l$OJQ?t$r6u$NJ8;zNs$K$7$?$j!$5sF0$rJQ99$9$k$3$H(B +$B$G6X;_$9$k$3$H$,$G$-$k!%(B + +%If you deploy a system-~or site-wide \hgrc\ file that defines some +%hooks, you should thus understand that your users can disable or +%override those hooks. + +$B%U%C%/$rDj5A$7$?%7%9%F%`%o%$%I$^$?$O%5%$%H%o%$%I$N(B\hgrc\ $B%U%!%$%k$r;HMQ$7(B +$B$F$b!$%j%]%8%H%j$N%f!<%6$,%U%C%/$r6X;_$7$?$j%*!<%P%i%$%I$G$-$F$7$^$&$N$K(B +$B5$IU$/$@$m$&!%(B + +%\subsection{Ensuring that critical hooks are run} +\subsection{$B%/%j%F%#%+%k$J%U%C%/$,3N<B$K<B9T$5$l$k$h$&$K$9$k(B} + +%Sometimes you may want to enforce a policy that you do not want others +%to be able to work around. For example, you may have a requirement +%that every changeset must pass a rigorous set of tests. Defining this +%requirement via a hook in a site-wide \hgrc\ won't work for remote +%users on laptops, and of course local users can subvert it at will by +%overriding the hook. + +$B;~$K$OB>$N3+H/<T$,2sHr:v$r$H$l$J$$$h$&$J%]%j%7!<$rMW@A$7$?$$>l9g$,$"$k$@(B +$B$m$&!%Nc$($P$9$Y$F$N%A%'%s%8%;%C%H$,873J$J%F%9%H%;%C%H$K%Q%9$9$k$3$H$rI,(B +$BMW$H$9$k>l9g$,9M$($i$l$k!%$3$l$r%5%$%H%o%$%I$N(B\hgrc\ $B$G%U%C%/$H$7$FDj5A(B +$B$7$?>l9g!$$3$l$O%i%C%W%H%C%W$r;H$C$F$$$k%j%b!<%H%f!<%6$K$O5!G=$7$J$$$7!$(B +$B%U%C%/$r%*!<%P%i%$%I$G$-$k$?$a!$%m!<%+%k%f!<%6$K$H$C$F$bL5;k$G$-$F$7$^$&!%(B + +%Instead, you can set up your policies for use of Mercurial so that +%people are expected to propagate changes through a well-known +%``canonical'' server that you have locked down and configured +%appropriately. + +$B$=$NBe$o$j!$(BMercurial$B$N;HMQ$K4X$9$k%]%j%7!<$r@_Dj$7!$E,@Z$K@_Dj$5$l!$87=E(B +$B$K4IM}$5$l$?4{CN$N(B``$B%+%N%K%+%k(B''$B%5!<%P$rDL$8$FJQ99$,GH5Z$9$k$h$&$K$9$k$3(B +$B$H$,$G$-$k!%(B + +%One way to do this is via a combination of social engineering and +%technology. Set up a restricted-access account; users can push +%changes over the network to repositories managed by this account, but +%they cannot log into the account and run normal shell commands. In +%this scenario, a user can commit a changeset that contains any old +%garbage they want. + +$B$3$l$r<B8=$9$k0lK!$O%=!<%7%c%k%(%s%8%K%"%j%s%0$H5;=Q$NAH$_9g$o$;$G9T$&J}(B +$BK!$G$"$k!%8BDj%"%/%;%9%"%+%&%s%H$r@_Dj$7!$$3$N%"%+%&%s%H$G4IM}$5$l$F$$$k(B +$B%j%]%8%H%j$KBP$7$F%f!<%6$OJQ99$r%M%C%H%o!<%/$r2p$7$F(Bpush$B$G$-$k!%$7$+$7%f!<(B +$B%6$O$3$N%"%+%&%s%H$G%m%0%$%s$7$?$j!$DL>o$N%7%'%k%3%^%s%I$r<B9T$9$k$3$H$O(B +$B$G$-$J$$!%$3$N%7%J%j%*$G$O!$%f!<%6$O$I$s$J8E$$%4%_$r4^$s$@%A%'%s%8%;%C%H(B +$B$G$b%3%_%C%H$9$k$3$H$,$G$-$k!%(B + +%When someone pushes a changeset to the server that everyone pulls +%from, the server will test the changeset before it accepts it as +%permanent, and reject it if it fails to pass the test suite. If +%people only pull changes from this filtering server, it will serve to +%ensure that all changes that people pull have been automatically +%vetted. + +$BB?$/$N%f!<%6$,(Bpull$B$9$k%5!<%P$KC/$+$,%A%'%s%8%;%C%H$r(Bpush$B$7$?>l9g!$%5!<%P(B +$B$O%A%'%s%8%;%C%H$r915WE*$K<u$1F~$l$kA0$K%A%'%C%/$r9T$$!$0lO"$N%F%9%H$r%Q(B +$B%9$G$-$J$1$l$P%j%8%'%/%H$r9T$&!%%f!<%6$,$3$N%U%#%k%?%5!<%P$+$i$N$_(Bpull$B$r(B +$B9T$&$N$G$"$l$P!$A4$F$NJQ99$O<+F0E*$KA4$F8!::$5$l$F$$$k$3$H$K$J$k!%(B + +%\section{Care with \texttt{pretxn} hooks in a shared-access repository} +\section{$B6&M-%"%/%;%9%j%]%8%H%j$G(B\texttt{pretxn}$B%U%C%/$r;H$&(B} + +%If you want to use hooks to do some automated work in a repository +%that a number of people have shared access to, you need to be careful +%in how you do this. + +$BJ#?t$N%f!<%6$,6&M-%"%/%;%9$r9T$&%j%]%8%H%j$G!$<+F02=$5$l$?:n6H$r9T$&$?$a(B +$B$K%U%C%/$r;HMQ$7$?$$$J$i!$$I$N$h$&$K9T$&$+Cm0U?<$/9M$($kI,MW$,$"$k!%(B + +%Mercurial only locks a repository when it is writing to the +%repository, and only the parts of Mercurial that write to the +%repository pay attention to locks. Write locks are necessary to +%prevent multiple simultaneous writers from scribbling on each other's +%work, corrupting the repository. + +Mercurial$B$O%j%]%8%H%j$K=q$-9~$_$r9T$&$H$-$K$@$1%j%]%8%H%j$r%m%C%/$9$k!%(B +$B$^$?(BMercurial$B$N=q$-9~$_$r9T$&ItJ,$N$_$,%m%C%/$r9MN8$9$k!%=q$-9~$_%m%C%/(B +$B$O!$J#?t$NF1;~=q$-9~$_$,B>$NJQ99$r>e=q$-$7!$%j%]%8%H%j$rGKB;$9$k$N$rKI$0!%(B + +%Because Mercurial is careful with the order in which it reads and +%writes data, it does not need to acquire a lock when it wants to read +%data from the repository. The parts of Mercurial that read from the +%repository never pay attention to locks. This lockless reading scheme +%greatly increases performance and concurrency. + +Mercurial$B$O%G!<%?$NFI$_=q$-$N=g=x$rCm0U?<$/9T$&$?$a!$%j%]%8%H%j$+$i$N%G!<(B +$B%?FI$_=P$7$N:]$K%m%C%/$r<hF@$9$kI,MW$,$J$$!%(B Mercurial$B$N%j%]%8%H%j$+$iFI(B +$B$_=P$7$r9T$&ItJ,$O!$%m%C%/$rA4$/5$$K$9$kI,MW$,$J$$!%$3$NL5%m%C%/FI$_=P$7(B +$B$K$h$C$F!$F1;~<B9T@-$H@-G=$rBgI}$K9b$a$F$$$k!%(B + +%With great performance comes a trade-off, though, one which has the +%potential to cause you trouble unless you're aware of it. To describe +%this requires a little detail about how Mercurial adds changesets to a +%repository and reads those changes. + +$B$7$+$7$J$,$i$3$N9b@-G=$O$=$l$rCN$i$J$1$l$PLdBj$r0z$-5/$3$9$"$k%H%l!<%I%*(B +$B%U$r$b$b$?$i$9!%$3$l$r@bL@$9$k$?$a$K!$(BMercurial$B$,$I$N$h$&$K%A%'%s%8%;%C%H(B +$B$r%j%]%8%H%j$KDI2C$7!$$=$l$i$rFI$_=P$9$+$N>\:Y$K?($l$J$1$l$P$J$i$J$$!%(B + +%When Mercurial \emph{writes} metadata, it writes it straight into the +%destination file. It writes file data first, then manifest data +%(which contains pointers to the new file data), then changelog data +%(which contains pointers to the new manifest data). Before the first +%write to each file, it stores a record of where the end of the file +%was in its transaction log. If the transaction must be rolled back, +%Mercurial simply truncates each file back to the size it was before the +%transaction began. + +Mercurial$B$O%a%?%G!<%?$r(B\emph{$B=q$-9~$`(B}$B$H$-!$D>@\L\E*$N%U%!%$%k$K=q$-9~$_(B +$B$9$k!%(BMercurial$B$O$^$:%U%!%$%k%G!<%?$r=q$-9~$_!$<!$$$G!J?7$7$$%U%!%$%k%G!<(B +$B%?$N>l=j$r<($9%]%$%s%?$r4^$`!K%^%K%U%'%9%H%G!<%?$r=q$-9~$`!%$=$7$F!J?7$7(B +$B$$%^%K%U%'%9%H%G!<%?$N>l=j$r<($9%]%$%s%?$r4^$`!K%A%'%s%8%m%0%G!<%?$r=q$-(B +$B9~$`!%3F!9$N%U%!%$%k$X$N:G=i$N=q$-9~$_$NA0$K!$%U%!%$%k$NKvHx$N%l%3!<%I$r(B +$B%H%i%s%6%/%7%g%s%m%0$KJ]B8$9$k!%%H%i%s%6%/%7%g%s$,%m!<%k%P%C%/$5$l$k>l9g(B +$B$O!$(BMercurial$B$O3F!9$N%U%!%$%k$r%H%i%s%6%/%7%g%s$,;O$^$kA0$N%5%$%:$K@Z$j5M(B +$B$a$k!%(B + +%When Mercurial \emph{reads} metadata, it reads the changelog first, +%then everything else. Since a reader will only access parts of the +%manifest or file metadata that it can see in the changelog, it can +%never see partially written data. + +Mercurial$B$O%a%?%G!<%?$r(B\emph{$BFI$`(B}$B;~$K$^$:%A%'%s%8%m%0$rFI$_!$<!$$$G;D$j(B +$B$NItJ,$rFI$`!%%j!<%@$O%A%'%s%8%m%0$K8=$l$k%^%K%U%'%9%H$N0lIt$^$?$O%U%!%$(B +$B%k%a%?%G!<%?$N0lIt$K$N$_%"%/%;%9$9$k$?$a!$ItJ,E*$K=q$+$l$?%G!<%?$r8+$k$3(B +$B$H$O$G$-$J$$!%(B + +%Some controlling hooks (\hook{pretxncommit} and +%\hook{pretxnchangegroup}) run when a transaction is almost complete. +%All of the metadata has been written, but Mercurial can still roll the +%transaction back and cause the newly-written data to disappear. + +$B$$$/$D$+$N@)8f%U%C%/!J(B\hook{pretxncommit}$B$H(B\hook{pretxnchangegroup}$B!K$O%H(B +$B%i%s%6%/%7%g%s$,$[$\40N;$7$?;~$K<B9T$5$l$k!%$9$Y$F$N%a%?%G!<%?$,=q$-9~$^(B +$B$l$k$,!$$3$N;~E@$G$b(BMercurial$B$O%H%i%s%6%/%7%g%s$r85$KLa$9$3$H$,$G$-!$$=$N(B +$B>l9g$O?7$7$/=q$+$l$?%G!<%?$O>C<:$9$k!%(B + +%If one of these hooks runs for long, it opens a window of time during +%which a reader can see the metadata for changesets that are not yet +%permanent, and should not be thought of as ``really there''. The +%longer the hook runs, the longer that window is open. + +$B$3$l$i$N%U%C%/$N$&$A(B1$B$D$,D9;~4V$K$o$?$C$F<B9T$5$l$F$$$k$H!$%j!<%@$,%A%'%s(B +$B%8%;%C%H$N%a%?%G!<%?$rFI$`$3$H$N$G$-$k%?%$%`%&%#%s%I%&$,3+$/!%$3$N%A%'%s(B +$B%8%;%C%H$O$^$@1JB3E*$J$b$N$K$J$C$F$*$i$:!$=>$C$F<B:_$9$k$H9M$($k$Y$-$G$O(B +$B$J$$$b$N$G$"$k!%%U%C%/$,<B9T$5$l$F$$$k;~4V$,D9$/$J$l$P$J$k$[$I!$%?%$%`%&%#(B +$B%s%I%&$,3+$/;~4V$bD9$/$J$k!%(B + +%\subsection{The problem illustrated} +\subsection{$BLdBj$N>\:Y(B} + +%In principle, a good use for the \hook{pretxnchangegroup} hook would +%be to automatically build and test incoming changes before they are +%accepted into a central repository. This could let you guarantee that +%nobody can push changes to this repository that ``break the build''. +%But if a client can pull changes while they're being tested, the +%usefulness of the test is zero; an unsuspecting someone can pull +%untested changes, potentially breaking their build. + +$B<BMQ$K$*$1$k(B\hook{pretxnchangegroup}$B%U%C%/$NNI$$;HMQK!$H$7$F$O!$E~Ce$7$?(B +$BJQ99$,Cf1{$N%j%]%8%H%j$K<h$j9~$^$l$kA0$K<+F0$G%S%k%I$H%F%9%H$r9T$&$3$H$,(B +$B9M$($i$l$k!%$3$l$K$h$j!$%S%k%I$rK8$2$kJQ99$OC/$b%j%]%8%H%j$K(Bpush$B$G$-$J$$(B +$B$3$H$,3N<B$K$J$k!%%/%i%$%"%s%H$,%F%9%HCf$KJQ99$r(Bpull$B$9$k$3$H$,$G$-$l$P!$(B +$B$3$N%F%9%H$NM-MQ@-$O%<%m$K$J$C$F$7$^$&!%5?$$$r;}$?$:$KC/$+$,%F%9%H$5$l$F(B +$B$$$J$$JQ99$r(Bpull$B$G$-$k$N$G$"$l$P!$H`$i$N%S%k%I$O<:GT$9$k2DG=@-$,$"$k!%(B + +%The safest technological answer to this challenge is to set up such a +%``gatekeeper'' repository as \emph{unidirectional}. Let it take +%changes pushed in from the outside, but do not allow anyone to pull +%changes from it (use the \hook{preoutgoing} hook to lock it down). +%Configure a \hook{changegroup} hook so that if a build or test +%succeeds, the hook will push the new changes out to another repository +%that people \emph{can} pull from. + +$B$3$NLdBj$X$N5;=QE*$K:G$b0BA4$J2sEz$O!$(B``$BLgHV(B''$B%j%]%8%H%j$r(B\emph{$B0lJ}8~(B}$B$K(B +$B@_Dj$9$k$3$H$G$"$k!%%j%]%8%H%j$r30It$+$i(Bpush$B$5$l$?JQ99$r<u$1<h$k$,!$C/$b(B +pull$B$G$-$J$$$h$&$K@_Dj$9$k!J(B\hook{preoutgoing}$B%U%C%/$r;H$C$F%j%]%8%H%j$r(B +$B%m%C%/$9$k!K!%(B\hook{changegroup}$B%U%C%/$r@_Dj$7!$%S%k%I$d%F%9%H$,@.8y$7$?(B +$B$H$-$K8B$C$F!$%U%C%/$,?7$?$JJQ99$r%f!<%6$N(Bpull\emph{$B$G$-$k(B}$BJL$N%j%]%8%H(B +$B%j$K(Bpush$B$9$k$h$&$K$9$k!%(B + +%In practice, putting a centralised bottleneck like this in place is +%not often a good idea, and transaction visibility has nothing to do +%with the problem. As the size of a project---and the time it takes to +%build and test---grows, you rapidly run into a wall with this ``try +%before you buy'' approach, where you have more changesets to test than +%time in which to deal with them. The inevitable result is frustration +%on the part of all involved. + +$B<B:]>e$O!$$3$N$h$&$K=8Cf$7$?%\%H%k%M%C%/$rCV$/$3$H$ONI$$9M$($H$O8@$($:!$(B +$B%H%i%s%6%/%7%g%s$N2D;k@-$OA4$/$J$$!%%W%m%8%'%/%H$N%5%$%:$*$h$S%S%k%I$H%F(B +$B%9%H$KMW$9$k;~4V$,A}2C$9$k$K=>$C$F!$$3$N$h$&$J(B``$B;vA0$K;n$9(B''$B<jK!$OJI$KFM(B +$B$-Ev$?$k!%%F%9%H$K;H$($k;~4V$G;+$-@Z$l$J$$$[$I$N%A%'%s%8%;%C%H$r;n$5$J$1(B +$B$l$P$J$i$J$/$J$k$+$i$G$"$k!%%U%i%9%H%l!<%7%g%s$,Cy$k$N$OHr$1$i$l$J$$$@$m(B +$B$&!%(B + +%An approach that scales better is to get people to build and test +%before they push, then run automated builds and tests centrally +%\emph{after} a push, to be sure all is well. The advantage of this +%approach is that it does not impose a limit on the rate at which the +%repository can accept changes. + +$B$h$j%9%1!<%k$9$k<jK!$O!$3+H/<T$K(Bpush$BA0$N%S%k%I$H%F%9%H$r$5$;$k$3$H$G$"(B +$B$k!%Cf1{$G<+F0$K$h$k%S%k%I$H%F%9%H$r9T$&$N$O!$(Bpush\emph{$B8e(B}$B$K!$A4$F$KLdBj(B +$B$,$J$$$3$H$r3NG'$9$k$?$a$K9T$&!%$3$N%"%W%m!<%A$NMxE@$O%j%]%8%H%j$,JQ99$r(B +$B<u$1F~$l$k%Z!<%9$K2?$b@)8B$r2]$5$J$$$3$H$G$"$k!%(B + +%\section{A short tutorial on using hooks} +\section{$B%U%C%/$N;HMQK!(B} +\label{sec:hook:simple} + +%It is easy to write a Mercurial hook. Let's start with a hook that +%runs when you finish a \hgcmd{commit}, and simply prints the hash of +%the changeset you just created. The hook is called \hook{commit}. + +Mercurial$B%U%C%/$r=q$/$N$OMF0W$$!%$3$3$G$O(B\hgcmd{commit}$B%3%^%s%I$,=*N;$7(B +$B$?:]$K!$:n@.$5$l$?%A%'%s%8%;%C%H$N%O%C%7%eCM$rI=<($9$k$/%U%C%/$r=q$$$F$_(B +$B$h$&!%$3$N%U%C%/$r(B\hook{commit}$B$H8F$V$3$H$K$9$k!%(B + +\begin{figure}[ht] + \interaction{hook.simple.init} +% \caption{A simple hook that runs when a changeset is committed} + \caption{$B%A%'%s%8%;%C%H$,%3%_%C%H$5$l$?;~$KF0:n$9$kC1=c$J%U%C%/(B} + \label{ex:hook:init} +\end{figure} + +%All hooks follow the pattern in example~\ref{ex:hook:init}. You add +%an entry to the \rcsection{hooks} section of your \hgrc\. On the left +%is the name of the event to trigger on; on the right is the action to +%take. As you can see, you can run an arbitrary shell command in a +%hook. Mercurial passes extra information to the hook using +%environment variables (look for \envar{HG\_NODE} in the example). + +$BA4$F$N%U%C%/$ONc(B~\ref{ex:hook:init}$B$HF1$8%Q%?!<%s$K$J$k!%(B \hgrc $B%U%!%$%k$N(B +\rcsection{hooks}$B%;%/%7%g%s$K%(%s%H%j$rDI2C$9$k!%:8JU$K%H%j%,!<$H$J$k%Y%s(B +$B%H$r5-=R$7!$1&JU$KBP1~$9$k%"%/%7%g%s$r5-=R$9$k!%Nc$K<($7$?DL$j!$%U%C%/$K(B +$B$OG$0U$N%7%'%k%3%^%s%I$r=q$/$3$H$,$G$-$k!%4D6-JQ?t$r@_Dj$9$k$3$H$G(B +Mercurial$B$+$i%U%C%/$KDI2C$N>pJs$rEO$9$3$H$,$G$-$k!%!JNc$N(B +\envar{HG\_NODE}$B$r;2>H!%!K(B + +%\subsection{Performing multiple actions per event} +\subsection{1$B$D$N%$%Y%s%H$KJ#?t$N%"%/%7%g%s$r9T$&(B} + +%Quite often, you will want to define more than one hook for a +%particular kind of event, as shown in example~\ref{ex:hook:ext}. +%Mercurial lets you do this by adding an \emph{extension} to the end of +%a hook's name. You extend a hook's name by giving the name of the +%hook, followed by a full stop (the ``\texttt{.}'' character), followed +%by some more text of your choosing. For example, Mercurial will run +%both \texttt{commit.foo} and \texttt{commit.bar} when the +%\texttt{commit} event occurs. + +$BNc(B~\ref{ex:hook:ext}$B$K<($7$?$h$&$K!$FCDj$N%$%Y%s%H$K(B2$B$D0J>e$N%U%C%/$rDj5A(B +$B$9$k$3$H$,I,MW$K$J$k$3$H$,B?$$$@$m$&!%(B Mercurial$B$G$O!$%U%C%/L>$N:G8e$K(B +\emph{$B3HD%;R(B}$B$rDI2C$9$k$3$H$G$3$l$,2DG=$K$J$k!%3HD%;R$rIU$1$k$K(B +$B$O!$(B``\texttt{.}'' $BJ8;z$H!$$3$l$KB3$/2?J8;z$+$+$i$J$kL>A0$r%U%C%/$K$D$1$l(B +$B$P$h$$!%Nc$($P(BMercurial$B$O(B\texttt{commit}$B%$%Y%s%H$,5/$-$?;~$K(B +\texttt{commit.foo}$B$H(B\texttt{commit.bar}$B%U%C%/$NN>J}$r8F$S=P$9!%(B + +\begin{figure}[ht] + \interaction{hook.simple.ext} +% \caption{Defining a second \hook{commit} hook} + \caption{2$BHVL\$N(B\hook{commit}$B%U%C%/$rDj5A$9$k(B} + \label{ex:hook:ext} +\end{figure} + +%To give a well-defined order of execution when there are multiple +%hooks defined for an event, Mercurial sorts hooks by extension, and +%executes the hook commands in this sorted order. In the above +%example, it will execute \texttt{commit.bar} before +%\texttt{commit.foo}, and \texttt{commit} before both. + +1$B$D$N%$%Y%s%H$KJ#?t$N%U%C%/$,Dj5A$5$l$F$$$k;~!$(BMercurial$B$O%U%C%/$r3HD%;R(B +$B$G%=!<%H$7!$%=!<%H$5$l$?=g=x$K=>$C$F%U%C%/$r<B9T$9$k!%>e5-$NNc$G$O(B +\texttt{commit}$B!$(B\texttt{commit.bar}$B!$(B\texttt{commit.foo}$B$N=g$K<B9T$9$k!%(B + +%It is a good idea to use a somewhat descriptive extension when you +%define a new hook. This will help you to remember what the hook was +%for. If the hook fails, you'll get an error message that contains the +%hook name and extension, so using a descriptive extension could give +%you an immediate hint as to why the hook failed (see +%section~\ref{sec:hook:perm} for an example). + +$B?7$7$$%U%C%/$rDj5A$9$k;~$K!$FbMF$r@bL@$9$k$h$&$J3HD%;R$rIU$1$k$N$O$h$$9M(B +$B$($G$"$k!%$3$&$9$k$3$H$K$h$C$F!$%U%C%/$NL\E*$,2?$J$N$+$r3P$($d$9$/$J$k!%(B +$B%U%C%/$,<:GT$7$?>l9g!$%(%i!<%a%C%;!<%8$K$O%U%C%/L>$H3HD%;R$,4^$^$l$k!%@b(B +$BL@E*$J3HD%;R$O%U%C%/$,<:GT$7$?M}M3$rCN$k$h$$<j$,$+$j$H$J$k!%!JNc(B +$B$O(B~\ref{sec:hook:perm}$B$r;2>H$N$3$H!%!K(B + +%\subsection{Controlling whether an activity can proceed} +\subsection{$BF0:n$,?J9T$G$-$k$+$I$&$+@)8f$9$k(B} +\label{sec:hook:perm} + +%In our earlier examples, we used the \hook{commit} hook, which is +%run after a commit has completed. This is one of several Mercurial +%hooks that run after an activity finishes. Such hooks have no way of +%influencing the activity itself. + +$BA0$NNc$G$O%3%_%C%H$,40N;$7$?8e$K<B9T$5$l$k(B\hook{commit}$B%U%C%/$rMQ$$$?!%$3(B +$B$l$O(BMercurial$B%U%C%/$N$&$A!$F0:n$,=*N;$7$?8e$K<B9T$5$l$k$b$N$N$&$A$N(B1$B$D$G(B +$B$"$k!%$3$N$h$&$J%U%C%/$O!$(BMercurial$B$NF0:n$=$N$b$N$K1F6A$r5Z$\$5$J$$!%(B + +%Mercurial defines a number of events that occur before an activity +%starts; or after it starts, but before it finishes. Hooks that +%trigger on these events have the added ability to choose whether the +%activity can continue, or will abort. + +Mercurial$B$OF0:n$N3+;OA0$d!$3+;O8e=*N;$9$k$^$G$N4V$KH/@8$9$k%$%Y%s%H$rB??t(B +$BDj5A$7$F$$$k!%$3$l$i$N%$%Y%s%H$G%H%j%,!<$5$l$k%U%C%/$O!$F0:n$rB39T$9$k$+(B +$BCfCG$9$k$+7h$a$k$3$H$,$G$-$k!%(B + +%The \hook{pretxncommit} hook runs after a commit has all but +%completed. In other words, the metadata representing the changeset +%has been written out to disk, but the transaction has not yet been +%allowed to complete. The \hook{pretxncommit} hook has the ability to +%decide whether the transaction can complete, or must be rolled back. + +\hook{pretxncommit}$B%U%C%/$O%3%_%C%H8e!$%3%_%C%H$N40N;A0$K8F$S=P$5$l$k!%(B +$B8@$$BX$($k$H!$%A%'%s%8%;%C%H$r<($9%a%?%G!<%?$,%G%#%9%/$K=q$-9~$^$l$?8e(B +$B$G!$%H%i%s%6%/%7%g%s$,40N;$9$kA0$K8F$S=P$5$l$k!%(B +\hook{pretxncommit}$B%U%C%/$O%H%i%s%6%/%7%g%s$r40N;$9$k$+!$%m!<%k%P%C%/$9(B +$B$k$+$r7hDj$9$k5!G=$,$"$k!%(B + +%If the \hook{pretxncommit} hook exits with a status code of zero, the +%transaction is allowed to complete; the commit finishes; and the +%\hook{commit} hook is run. If the \hook{pretxncommit} hook exits with +%a non-zero status code, the transaction is rolled back; the metadata +%representing the changeset is erased; and the \hook{commit} hook is +%not run. + +\hook{pretxncommit}$B%U%C%/$,%9%F!<%?%9%3!<%I(B0$B$G=*N;$9$k$H%H%i%s%6%/%7%g%s(B +$B$O40N;$9$k$3$H$,$G$-!$%3%_%C%H$,=*N;$7!$(B\hook{commit}$B%U%C%/$,8F$S=P$5$l$k!%(B +\hook{pretxncommit}$B%U%C%/$,Hs(B0$B$N%9%F!<%?%9%3!<%I$G=*N;$9$k$H!$%H%i%s%6%/(B +$B%7%g%s$O%m!<%k%P%C%/$5$l!$%A%'%s%8%;%C%H$r<($9%a%?%G!<%?$O>C5n$5$l$k!%$3(B +$B$N>l9g(B\hook{commit}$B%U%C%/$O8F$S=P$5$l$J$$!%(B + +\begin{figure}[ht] + \interaction{hook.simple.pretxncommit} +% \caption{Using the \hook{pretxncommit} hook to control commits} + \caption{$B%3%_%C%H$r@)8f$9$k$?$a$K(B\hook{pretxncommit}$B%U%C%/$r;HMQ$9$k(B} + \label{ex:hook:pretxncommit} +\end{figure} + +%The hook in example~\ref{ex:hook:pretxncommit} checks that a commit +%comment contains a bug ID. If it does, the commit can complete. If +%not, the commit is rolled back. + +~\ref{ex:hook:pretxncommit}$B$O%3%_%C%H%3%a%s%H$,%P%0(BID$B$r4^$`$+$r%A%'%C%/(B +$B$9$k!%$b$74^$^$l$l$P%3%_%C%H$O40N;$9$k!%4^$^$J$$>l9g$O%3%_%C%H$O%m!<%k%P%C(B +$B%/$5$l$k!%(B + +%\section{Writing your own hooks} +\section{$B%*%j%8%J%k$N%U%C%/$r=q$/(B} + +%When you are writing a hook, you might find it useful to run Mercurial +%either with the \hggopt{-v} option, or the \rcitem{ui}{verbose} config +%item set to ``true''. When you do so, Mercurial will print a message +%before it calls each hook. + +$B%U%C%/$r=q$/>l9g!$(BMercurial$B$r(B\hggopt{-v}$B%*%W%7%g%s$rIU$1$?$j(B +\rcitem{ui}{verbose}$B@_Dj9`L\$r(B``true''$B$K@_Dj$9$k$3$H$OLr$KN)$D!%$3$N>l(B +$B9g!$(BMercurial$B$O3F!9$N%U%C%/$r8F$VA0$K%a%C%;!<%8$rI=<($9$k!%(B + +%\subsection{Choosing how your hook should run} +\subsection{$B%U%C%/$,$NF0:nJ}K!$rA*$V(B} +\label{sec:hook:lang} + +%You can write a hook either as a normal program---typically a shell +%script---or as a Python function that is executed within the Mercurial +%process. + +$B%U%C%/$O%7%'%k%9%/%j%W%H$N$h$&$JDL>o$N%W%m%0%i%`$H$7$F=q$/$3$H$b$G$-$k$7!$(B +Mercurial$B%W%m%;%9$NFbIt$G8F$S=P$5$l$k(BPython$B4X?t$H$7$F=q$/$3$H$b$G$-$k!%(B + +%Writing a hook as an external program has the advantage that it +%requires no knowledge of Mercurial's internals. You can call normal +%Mercurial commands to get any added information you need. The +%trade-off is that external hooks are slower than in-process hooks. + +$B%U%C%/$r30It%W%m%0%i%`$H$7$F=q$/MxE@$O(BMercurial$B$NFbItF0:n$rCN$i$J$/$F$b%U%C(B +$B%/$,=q$1$k$3$H$G$"$k!%I,MW$JDI2C$N>pJs$rF@$k$?$a$KDL>o$N(BMercurial$B%3%^%s%I(B +$B$r8F$S=P$9$3$H$,$G$-$k!%30It%U%C%/$O%W%m%;%9Fb%U%C%/$h$j$bDcB.$J$N$,%H%l!<(B +$B%I%*%U$G$"$k!%(B + +%An in-process Python hook has complete access to the Mercurial API, +%and does not ``shell out'' to another process, so it is inherently +%faster than an external hook. It is also easier to obtain much of the +%information that a hook requires by using the Mercurial API than by +%running Mercurial commands. + +Python$B%W%m%;%9Fb%U%C%/$O(BMercurial API$B$X$N40A4$J%"%/%;%9$,2DG=$G$"$k!%(B +$BB>$N%W%m%;%9$r@8@.$9$k$3$H$,$J$$$?$a!$K\<AE*$K30It%U%C%/$h$j$b9bB.$G$"$k!%(B +$B%U%C%/$,I,MW$H$9$k>pJs$NBgH>$O!$(BMercurial$B%3%^%s%I$r<B9T$9$k$h$j$b(B +Mercurial API$B$r;H$C$F=8$a$kJ}$,MF0W$$!%(B + +%If you are comfortable with Python, or require high performance, +%writing your hooks in Python may be a good choice. However, when you +%have a straightforward hook to write and you don't need to care about +%performance (probably the majority of hooks), a shell script is +%perfectly fine. + +Python$B$r;H$$47$l$F$$$?$j!$9b$$@-G=$,I,MW$J$i$P!$%U%C%/$r(BPython$B$G=q$/$N$,(B +$B$h$$$@$m$&!%$7$+$7=q$3$&$H$9$k$N$,C1=cL@2r$J%U%C%/$G!$!JB?$/$N%U%C%/$,$=(B +$B$&$G$"$k$h$&$K!K@-G=$K$OFC$K4X?4$,$J$$>l9g!$%7%'%k%9%/%j%W%H$H$7$F=q$$$F(B +$B$bA4$/LdBj$J$$!%(B + +%\subsection{Hook parameters} +\subsection{$B%U%C%/%Q%i%a!<%?(B} +\label{sec:hook:param} + +%Mercurial calls each hook with a set of well-defined parameters. In +%Python, a parameter is passed as a keyword argument to your hook +%function. For an external program, a parameter is passed as an +%environment variable. + +Mercurial$B$O3F!9$N%U%C%/$N8F=P$7$N:]$K$-$A$s$HDj5A$5$l$?%Q%i%a!<%?$rEO(B +$B$9!%(BPython$B$G$O%Q%i%a!<%?$O%-!<%o!<%I0z?t$H$7$F%U%C%/4X?t$KEO$5$l$k!%30It(B +$B%W%m%0%i%`$K$O!$%Q%i%a!<%?$O4D6-JQ?t$H$7$FEO$5$l$k!%(B + +%Whether your hook is written in Python or as a shell script, the +%hook-specific parameter names and values will be the same. A boolean +%parameter will be represented as a boolean value in Python, but as the +%number 1 (for ``true'') or 0 (for ``false'') as an environment +%variable for an external hook. If a hook parameter is named +%\texttt{foo}, the keyword argument for a Python hook will also be +%named \texttt{foo}, while the environment variable for an external +%hook will be named \texttt{HG\_FOO}. + +$B%U%C%/$,(BPython$B$G=q$+$l$F$$$k$+!$%7%'%k%9%/%j%W%H$7$F=q$+$l$F$$$k$+$K4X$o(B +$B$i$:!$%U%C%/8GM-$N%Q%i%a!<%?L>$HCM$OF1$8$b$N$,MQ$$$i$l$k!%%V!<%k7?%Q%i%a!<(B +$B%?$O(BPython$B$G$O%V!<%kCM$H$7$F07$o$l$k$,!$30It%U%C%/$N$?$a$N4D6-JQ?t$G(B +$B$O!$(B1$B!J(B``$B??(B''$B!K$^$?$O(B0$B!J(B``$B56(B''$B!K$H$$$&?tCM$H$7$F07$o$l$k!%(B +$B%U%C%/%Q%i%a!<%?$K(B\texttt{foo}$B$H$$$&L>A0$,IU$1$i$l$F$$$k$H$-!$(BPython$B%U%C(B +$B%/$X$N%-!<%o!<%I0z?t$bF1$8(B\texttt{foo}$B$H$$$&L>A0$K$J$k!%(B +$B0lJ}!$30It%U%C%/$N$?$a$N4D6-JQ?t$G$O(B\texttt{HG\_FOO}$B$H$$$&L>A0$K$J$k!%(B + +%\subsection{Hook return values and activity control} +\subsection{$B%U%C%/$NLa$jCM$HF0:n$N@)8f(B} + +%A hook that executes successfully must exit with a status of zero if +%external, or return boolean ``false'' if in-process. Failure is +%indicated with a non-zero exit status from an external hook, or an +%in-process hook returning boolean ``true''. If an in-process hook +%raises an exception, the hook is considered to have failed. + +%For a hook that controls whether an activity can proceed, zero/false +%means ``allow'', while non-zero/true/exception means ``deny''. + +%\subsection{Writing an external hook} +\subsection{$B30It%U%C%/$r:n@.$9$k(B} + +%When you define an external hook in your \hgrc\ and the hook is run, +%its value is passed to your shell, which interprets it. This means +%that you can use normal shell constructs in the body of the hook. + +$B30It%U%C%/$r(B \hgrc\ $B$GDj5A$7!$<B9T$9$k>l9g!$%U%C%/$O%7%'%k$KEO$5$l$kCM$r(B +$BJQ49$9$?$a!$%U%C%/$NK\BNItJ,$G%7%'%k%9%/%j%W%H$r5-=R$9$k$3$H$,$G$-$k!%(B + +%An executable hook is always run with its current directory set to a +%repository's root directory. + +$B30It%U%C%/$O>o$K%j%]%8%H%j$N%k!<%H%G%#%l%/%H%j$r%+%l%s%H%G%#%l%/%H%j$H$7(B +$B$F<B9T$5$l$k!%(B + +%Each hook parameter is passed in as an environment variable; the name +%is upper-cased, and prefixed with the string ``\texttt{HG\_}''. + +$B3F!9$N%U%C%/%Q%i%a!<%?$O4D6-JQ?t$H$7$FEO$5$l$k!%$9$J$o$A!$L>A0$OA4$FBgJ8(B +$B;z$K$J$j!$(B``\texttt{HG\_}''$B$H$$$&@\F,<-$,IU$1$i$l$k!%(B + +%With the exception of hook parameters, Mercurial does not set or +%modify any environment variables when running a hook. This is useful +%to remember if you are writing a site-wide hook that may be run by a +%number of different users with differing environment variables set. +%In multi-user situations, you should not rely on environment variables +%being set to the values you have in your environment when testing the +%hook. + +$B%U%C%/%Q%i%a!<%?$rNc30$H$7$F!$(BMercurial$B$O%U%C%/$r<B9T$9$k:]$K4D6-JQ?t$NDj(B +$B5A$dJQ99$r9T$o$J$$!%B?$/$N%f!<%6$,<B9T$9$k%5%$%H%o%$%I$N%U%C%/$r:n@.$9$k(B +$B>l9g!$%f!<%6$,@_Dj$7$F$$$k4D6-JQ?t$O0[$J$k$3$H$r5-21$7$F$*$/$Y$-$G$"$k!%(B +$B%^%k%A%f!<%64D6-$N>l9g!$%U%C%/$r;n$9:]$K$"$J$?$,@_Dj$7$F$$$k4D6-JQ?t$K0M(B +$BB8$9$Y$-$G$O$J$$!%(B + +%\subsection{Telling Mercurial to use an in-process hook} +\subsection{Mercurial$B$K%W%m%;%9Fb%U%C%/$r;H$&$h$&$K;X<($9$k(B} + +%The \hgrc\ syntax for defining an in-process hook is slightly +%different than for an executable hook. The value of the hook must +%start with the text ``\texttt{python:}'', and continue with the +%fully-qualified name of a callable object to use as the hook's value. + +$B%W%m%;%9$J$$%U%C%/$rDj5A$9$k(B \hgrc\ $B9=J8$O<B9T2DG=%U%C%/$H$O6O$+$K0[$J$C(B +$B$F$$$k!%%U%C%/$NCM$OI,$:(B``\texttt{python:}''$B$G;O$^$j!$8e$K%U%C%/CM$H$7$F(B +$BMQ$$$i$l$k8F=P$72DG=%*%V%8%'%/%H$N40A4$JL>A0$,B3$+$J$1$l$P$J$i$J$$!%(B + +%The module in which a hook lives is automatically imported when a hook +%is run. So long as you have the module name and \envar{PYTHONPATH} +%right, it should ``just work''. + +$B%U%C%/$,4^$^$l$k%b%8%e!<%k$O%U%C%/$,<B9T$5$l$k;~$K<+F0E*$KFI$_9~$^$l$k!%(B +$B%b%8%e!<%kL>$*$h$S(B\envar{PYTHONPATH}$B$,@5$7$$$+$.$jI,$:F0:n$9$k$O$:$G$"$k!%(B + +%The following \hgrc\ example snippet illustrates the syntax and +%meaning of the notions we just described. +%\begin{codesample2} +% [hooks] +% commit.example = python:mymodule.submodule.myhook +%\end{codesample2} +%When Mercurial runs the \texttt{commit.example} hook, it imports +%\texttt{mymodule.submodule}, looks for the callable object named +%\texttt{myhook}, and calls it. + +$B:#@bL@$7$?9=J8$H35G0$r@bL@$9$kCGJRE*$JNc$r0J2<$N(B\hgrc\ $B$K<($9!%(B +\begin{codesample2} + [hooks] + commit.example = python:mymodule.submodule.myhook +\end{codesample2} +Mercurial$B$,(B\texttt{commit.example}$B%U%C%/$r<B9T$9$k;~!$(B +\texttt{mymodule.submodule}$B$rFI$_9~$_!$8F=P$72DG=%*%V%8%'%/%H(B +\texttt{myhook}$B$rC5$7!$<B9T$9$k!%(B + +%\subsection{Writing an in-process hook} +\subsection{$B%W%m%;%9Fb%U%C%/$r:n@.$9$k(B} + +%The simplest in-process hook does nothing, but illustrates the basic +%shape of the hook API: +%\begin{codesample2} +% def myhook(ui, repo, **kwargs): +% pass +%\end{codesample2} +%The first argument to a Python hook is always a +%\pymodclass{mercurial.ui}{ui} object. The second is a repository object; +%at the moment, it is always an instance of +%\pymodclass{mercurial.localrepo}{localrepository}. Following these two +%arguments are other keyword arguments. Which ones are passed in +%depends on the hook being called, but a hook can ignore arguments it +%doesn't care about by dropping them into a keyword argument dict, as +%with \texttt{**kwargs} above. + +$B<B:]$K$O2?$b9T$o$J$$:G$bC1=c$J%W%m%;%9Fb%U%C%/$r%U%C%/(BAPI$B$N4pK\E*$J;H$$J}(B +$B$r@bL@$9$k$?$a$K<($9!%(B +\begin{codesample2} + def myhook(ui, repo, **kwargs): + pass +\end{codesample2} +Python$B%U%C%/$X$N:G=i$N0z?t$O>o$K(B\pymodclass{mercurial.ui}{ui}$B%*%V%8%'%/%H(B +$B$G$"$k!%(B2$BHVL\$N0z?t$O%j%]%8%H%j%*%V%8%'%/%H$G!$8=:_$N$H$3$m>o$K(B +\pymodclass{mercurial.localrepo}{localrepository}$B$N%$%s%9%?%s%9$G$"$k!%B>(B +$B$N%-!<%o!<%I0z?t$O$3$l$i$N(B2$B$D$N0z?t$KB3$/!%$3$l$i$O8F$S=P$5$l$F$$$k%U%C%/(B +$B$K0MB8$9$k$,!$%U%C%/$O%-!<%o!<%I$N<-=q$K(B\texttt{**kwargs}$B$H5-=R$9$k$3$H(B +$B$G!$I,MW$N$J$$0z?t$rL5;k$9$k$3$H$b$G$-$k!%(B + +%\section{Some hook examples} +\section{$B%U%C%/$NNc(B} + +%\subsection{Writing meaningful commit messages} +\subsection{$B0UL#$N$"$k%3%_%C%H%a%C%;!<%8$r=PNO$9$k(B} + +%It's hard to imagine a useful commit message being very short. The +%simple \hook{pretxncommit} hook of figure~\ref{ex:hook:msglen.go} +%will prevent you from committing a changeset with a message that is +%less than ten bytes long. + +$BHs>o$KC;$$%3%_%C%H%a%C%;!<%8$,M-MQ$G$"$k$3$H$O$^$:$J$$!%(B +$B?^(B~\ref{ex:hook:msglen.go}$B$K<($9(B\hook{pretxncommit}$B$H$$$&C1=c$J%U%C%/$O(B10 +$B%P%$%H0J2<$ND9$5$N%3%_%C%H%a%C%;!<%8$G%3%_%C%H$r9T$&$3$H$r6X;_$9$k!%(B + +\begin{figure}[ht] + \interaction{hook.msglen.go} +% \caption{A hook that forbids overly short commit messages} + \caption{$B6KC<$KC;$$%3%_%C%H%a%C%;!<%8$r6X;_$9$k%U%C%/(B} + \label{ex:hook:msglen.go} +\end{figure} + +%\subsection{Checking for trailing whitespace} +\subsection{$B$V$i2<$,$C$?6uGr$r%A%'%C%/$9$k(B} + +%An interesting use of a commit-related hook is to help you to write +%cleaner code. A simple example of ``cleaner code'' is the dictum that +%a change should not add any new lines of text that contain ``trailing +%whitespace''. Trailing whitespace is a series of space and tab +%characters at the end of a line of text. In most cases, trailing +%whitespace is unnecessary, invisible noise, but it is occasionally +%problematic, and people often prefer to get rid of it. + +$B%3%_%C%H$K4XO"$7$?%U%C%/$N6=L#?<$$;HMQK!$N0l$D$K$h$j4qNo$J%3!<%I$r=q$/<j(B +$B=u$1$,$"$k!%(B ``$B4qNo$J%3!<%I(B''$B$N$4$/C1=c$JNc$O!$Nc$($P!$?7$?$J$V$i2<$,$C$?(B +$B6uGr$r4^$`9T$r4^$^$J$$$b$N$G$"$k!%$V$i2<$,$C$?6uGr$H$O!$9TKv$N0lO"$N%9%Z!<(B +$B%9$d%?%V$G$"$k!%$[$H$s$I$N>l9g!$$V$i2<$,$C$?6uGr$OITI,MW$J8+$($J$$%N%$%:(B +$B$G$"$k$,!$LdBj$r0z$-5/$3$9>l9g$b$"$j!$=|5n$7$?$,$k?M$,B?$$!%(B + +%You can use either the \hook{precommit} or \hook{pretxncommit} hook to +%tell whether you have a trailing whitespace problem. If you use the +%\hook{precommit} hook, the hook will not know which files you are +%committing, so it will have to check every modified file in the +%repository for trailing white space. If you want to commit a change +%to just the file \filename{foo}, but the file \filename{bar} contains +%trailing whitespace, doing a check in the \hook{precommit} hook will +%prevent you from committing \filename{foo} due to the problem with +%\filename{bar}. This doesn't seem right. + +$B$V$i2<$,$j6uGr$NLdBj$rD>$9$?$a$K(B\hook{precommit}$B%U%C%/$d(B +\hook{pretxncommit}$B%U%C%/$rMQ$$$k$3$H$,$G$-$k!%(B\hook{precommit}$B%U%C%/$r;H(B +$B$&>l9g!$$I$N%U%!%$%k$r%3%_%C%H$9$k$N$+%U%C%/$OCN$k$3$H$,$J$$!%$=$N$?$a!$(B +$B%j%]%8%H%j$GJQ99$5$l$?%U%!%$%k$9$Y$F$K$D$$$F$V$i2<$,$j6uGr$r%A%'%C%/$9$k(B +$BI,MW$,$"$k!%(B \filename{foo}$B$H$$$&%U%!%$%k$r%3%_%C%H$7$?$$(B +$B$,!$(B\filename{bar}$B%U%!%$%k$,$V$i2<$,$j6uGr$r4^$s$G$$$k>l(B +$B9g!$(B\hook{precommit}$B%U%C%/$G%A%'%C%/$r9T$&$H!$%U%!%$%k(B\filename{bar}$B$NLd(B +$BBj$N$?$a$K(B\filename{foo}$B$N%3%_%C%H$,$G$-$J$/$J$k!%$3$l$O@5$7$$5sF0$H$O8@(B +$B$($J$$!%(B + +%Should you choose the \hook{pretxncommit} hook, the check won't occur +%until just before the transaction for the commit completes. This will +%allow you to check for problems only the exact files that are being +%committed. However, if you entered the commit message interactively +%and the hook fails, the transaction will roll back; you'll have to +%re-enter the commit message after you fix the trailing whitespace and +%run \hgcmd{commit} again. + +\hook{pretxncommit}$B%U%C%/$rA*$S!$%A%'%C%/$,%3%_%C%H40N;%H%i%s%6%/%7%g%s$N(B +$BD>A0$^$G5/$-$J$$$h$&$K$9$Y$-$G$"$k!%$3$l$K$h$j!$%3%_%C%H$5$l$h$&$H$9$k%U%!(B +$B%$%k$@$1$r%A%'%C%/$9$k$3$H$,$G$-$k$h$&$K$J$k!%$7$+$7$J$,$i!$%3%_%C%H%a%C(B +$B%;!<%8$rBPOCE*$KF~NO$7!$%3%_%C%H$,<:GT$9$k$H%H%i%s%6%/%7%g%s$O%m!<%k%P%C(B +$B%/$9$k$?$a!$$V$i2<$,$j6uGr$r=$@5$7!$(B\hgcmd{commit}$B$r:F$S<B9T$7!$%3%_%C%H(B +$B$9$k:]$K%3%_%C%H%a%C%;!<%8$r:FF~NO$7$J$1$l$P$J$i$J$$!%(B + +\begin{figure}[ht] + \interaction{hook.ws.simple} +% \caption{A simple hook that checks for trailing whitespace} + \caption{$B$V$i2<$,$C$?6uGr$r%A%'%C%/$9$kC1=c$J%U%C%/(B} + \label{ex:hook:ws.simple} +\end{figure} + +%Figure~\ref{ex:hook:ws.simple} introduces a simple \hook{pretxncommit} +%hook that checks for trailing whitespace. This hook is short, but not +%very helpful. It exits with an error status if a change adds a line +%with trailing whitespace to any file, but does not print any +%information that might help us to identify the offending file or +%line. It also has the nice property of not paying attention to +%unmodified lines; only lines that introduce new trailing whitespace +%cause problems. + +$B?^(B~\ref{ex:hook:ws.simple}$B$O(B\hook{pretxncommit}$B$H$$$&$V$i2<$,$j6uGr$r%A%'%C(B +$B%/$9$kC1=c$J%U%C%/$rF3F~$7$F$$$k!%$3$N%U%C%/$OC;$$$,!$$=$l$[$IM-MQ$G$O$J(B +$B$$!%99?7$,$V$i2<$,$j6uGr$r4^$`9T$r$I$N%U%!%$%k$KDI2C$7$F$b!$$3$N%U%C%/$O(B +$B%(%i!<%9%F!<%?%9$H6&$K=*N;$9$k$,!$LdBj$N$"$k%U%!%$%k$d9T$rFCDj$9$k$?$a$N(B +$B>pJs$O0l@ZI=<($7$J$$!%$3$N%U%C%/$OJQ99$N$J$$9T$K$OA4$/4X?4$r;}$?$J$$$H$$(B +$B$&NI$$@-<A$b;}$C$F$$$k!%?75,$K$V$i2<$,$j6uGr$r2C$($kLdBj$N$"$k9T$N$_$r8!(B +$B::$9$k!%(B + +\begin{figure}[ht] + \interaction{hook.ws.better} +% \caption{A better trailing whitespace hook} + \caption{$B$V$i2<$,$j6uGr$r%A%'%C%/$9$k%U%C%/$N2~NIHG(B} + \label{ex:hook:ws.better} +\end{figure} + +%The example of figure~\ref{ex:hook:ws.better} is much more complex, +%but also more useful. It parses a unified diff to see if any lines +%add trailing whitespace, and prints the name of the file and the line +%number of each such occurrence. Even better, if the change adds +%trailing whitespace, this hook saves the commit comment and prints the +%name of the save file before exiting and telling Mercurial to roll the +%transaction back, so you can use +%\hgcmdargs{commit}{\hgopt{commit}{-l}~\emph{filename}} to reuse the +%saved commit message once you've corrected the problem. + +$B?^(B~\ref{ex:hook:ws.better}$B$O$+$J$jJ#;($@$,!$$h$jM-MQ$G$"$k!%$3$N%U%C%/$OE}(B +$B9g7A<0$N(Bdiff$B$r%Q!<%9$7!$$V$i2<$,$j6uGr$r4^$`%i%$%s$rC5$9!%$=$7$F8+$D$1$k(B +$B$H%U%!%$%kL>$H9THV9f$rI=<($9$k!%$5$i$KJQ99$,$V$i2<$,$j6uGr$rDI2C$9$k$H!$(B +$B$3$N%U%C%/$O%3%_%C%H%3%a%s%H$rJ]B8$7!$=*N;A0$KJ]B8%U%!%$%k$NL>A0$rI=<($9(B +$B$k!%$=$7$F(BMercurial$B$K%H%i%s%6%/%7%g%s$r%m!<%k%P%C%/$9$k$3$H$r;X<($9$k!%Ld(B +$BBj$r=$@5$7$?8e$GJ]B8$5$l$?%3%_%C%H%a%C%;!<%8$r;H$&$K$O(B +\hgcmdargs{commit}{\hgopt{commit}{-l}~\emph{filename}}$B$H$9$l$P$h$$!%(B + +%As a final aside, note in figure~\ref{ex:hook:ws.better} the use of +%\command{perl}'s in-place editing feature to get rid of trailing +%whitespace from a file. This is concise and useful enough that I will +%reproduce it here. + +$B:G8e$K!$?^(B~\ref{ex:hook:ws.better}$B$N$h$&$K%U%!%$%k$+$i$V$i2<$,$j6uGr$r=|5n(B +$B$9$k$?$a$K(B\command{perl}$B%3%^%s%I$N%$%s%W%l%$%9JT=85!G=$rMQ$$$k!%$3$l$O$3(B +$B$3$G:F8=$9$k$KEv$?$C$F==J,C;$/$+$DM-8z$G$"$k!%(B + +\begin{codesample2} + perl -pi -e 's,\\s+\$,,' filename +\end{codesample2} + +%\section{Bundled hooks} +\section{$BAH$_9g$o$;%U%C%/(B} + +%Mercurial ships with several bundled hooks. You can find them in the +%\dirname{hgext} directory of a Mercurial source tree. If you are +%using a Mercurial binary package, the hooks will be located in the +%\dirname{hgext} directory of wherever your package installer put +%Mercurial. + +Mercurial$B$K$O$$$/$D$+$N%U%C%/$,F1:-$5$l$F$$$k!%%U%C%/$O(BMercurial$B%=!<%9%D(B +$B%j!<$N(B\dirname{hgext}$B%G%#%l%/%H%j$K$"$k!%(B Mercurial$B$N%P%$%J%j%Q%C%1!<%8$r(B +$B;HMQ$7$F$$$k$N$G$"$l$P!$%U%C%/$O%Q%C%1!<%8%$%s%9%H!<%i$,(BMercurial$B$r%$%s%9(B +$B%H!<%k$7$?%G%#%l%/%H%jFb$N(B\dirname{hgext}$B%G%#%l%/%H%j$K$"$k$O$:$@!%(B + +%\subsection{\hgext{acl}---access control for parts of a repository} +\subsection{\hgext{acl}---$B%j%]%8%H%j$NItJ,$KBP$9$k%"%/%;%9%3%s%H%m!<%k(B} + +%The \hgext{acl} extension lets you control which remote users are +%allowed to push changesets to a networked server. You can protect any +%portion of a repository (including the entire repo), so that a +%specific remote user can push changes that do not affect the protected +%portion. + +\hgext{acl}$B%(%/%9%F%s%7%g%s$O!$%j%b!<%H%f!<%6$K%A%'%s%8%;%C%H$r%M%C%H%o!<(B +$B%/@\B3$5$l$?%5!<%P$K%W%C%7%e$G$-$k$h$&$K$9$k!%FCDj$N%j%b!<%H%f!<%6$,J]8n(B +$B$5$l$?0J30$NItJ,$NJQ99$r%W%C%7%e$G$-$k$h$&$K%j%]%8%H%j$NG$0U$NItJ,!JA4BN(B +$B$r$b4^$`!K$rJ]8n$9$k$3$H$,$G$-$k!%(B + +%This extension implements access control based on the identity of the +%user performing a push, \emph{not} on who committed the changesets +%they're pushing. It makes sense to use this hook only if you have a +%locked-down server environment that authenticates remote users, and +%you want to be sure that only specific users are allowed to push +%changes to that server. + +$B$3$N%(%/%9%F%s%7%g%s$O%f!<%6$,%W%C%7%e$r9T$&:]$K!$C/$,%A%'%s%8%;%C%H$r%3(B +$B%_%C%H(B\emph{$B$G$-$J$$(B}$B$h$&$K$9$k$3$H$G%"%/%;%9%3%s%H%m!<%k$r<BAu$7$F$$$k!%(B +$B$3$N%U%C%/$O!$%j%b!<%H%f!<%6$NG'>Z$r9T$&J]8n$5$l$?%5!<%P4D6-$G!$;XDj$5$l(B +$B$?%f!<%6$@$1$,JQ99$r%5!<%P$K%W%C%7%e$G$-$k$h$&$K$7$?$$>l9g$K$N$_0UL#$r$J(B +$B$9!%(B + +%\subsubsection{Configuring the \hook{acl} hook} +\subsubsection{\hook{acl}$B%U%C%/$N@_Dj(B} + +%In order to manage incoming changesets, the \hgext{acl} hook must be +%used as a \hook{pretxnchangegroup} hook. This lets it see which files +%are modified by each incoming changeset, and roll back a group of +%changesets if they modify ``forbidden'' files. Example: +%\begin{codesample2} +% [hooks] +% pretxnchangegroup.acl = python:hgext.acl.hook +%\end{codesample2} + +\hgext{acl}$B%U%C%/$r!$E~Ce$9$k%A%'%s%8%;%C%H$r4IM}$9$k$?$a$K;H$&$?$a$K$O!$(B +\hook{pretxnchangegroup}$B%U%C%/$H$7$FMQ$$$kI,MW$,$"$k!%$3$N%U%C%/$O!$3F!9(B +$B$N%A%'%s%8%;%C%H$G$I$N%U%!%$%k$,JQ99$5$l$?$N$+$r%A%'%C%/$7!$JQ996X;_$N%U%!(B +$B%$%k$XJQ99$,$"$C$?>l9g$O%A%'%s%8%;%C%H$r%m!<%k%P%C%/$9$k!%Nc!'(B +\begin{codesample2} + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook +\end{codesample2} + +%The \hgext{acl} extension is configured using three sections. + +\hgext{acl}$B%(%/%9%F%s%7%g%s$O(B3$B$D$N%;%/%7%g%s$G@_Dj$5$l$k!%(B + +%The \rcsection{acl} section has only one entry, \rcitem{acl}{sources}, +%which lists the sources of incoming changesets that the hook should +%pay attention to. You don't normally need to configure this section. +%\begin{itemize} +%\item[\rcitem{acl}{serve}] Control incoming changesets that are arriving +% from a remote repository over http or ssh. This is the default +% value of \rcitem{acl}{sources}, and usually the only setting you'll +% need for this configuration item. +%\item[\rcitem{acl}{pull}] Control incoming changesets that are +% arriving via a pull from a local repository. +%\item[\rcitem{acl}{push}] Control incoming changesets that are +% arriving via a push from a local repository. +%\item[\rcitem{acl}{bundle}] Control incoming changesets that are +% arriving from another repository via a bundle. +%\end{itemize} + +\rcsection{acl}$B%;%/%7%g%s$O!$(B\rcitem{acl}{sources}$B$H$$$&%(%s%H%j(B1$B$D$r;}(B +$B$D!%$3$N%(%s%H%j$G%U%C%/$,4F;k$9$Y$-E~Ce%A%'%s%8%;%C%HFb%=!<%9(B +$B$rNs5s$9$k!%(B +\begin{itemize} +\item[\rcitem{acl}{serve}] $B%j%b!<%H%j%]%8%H%j$+$i(Bhttp$B$^$?$O(Bssh$B$r;H$C$FE~(B + $BCe$9$k%A%'%s%8%;%C%H$r@)8f$9$k!%(B\rcitem{acl}{sources}$B$N%G%U%)(B + $B%k%HCM$G!$DL>o$O$3$N@_DjFb$GM#0l@_Dj$9$kI,MW$N$"$k9`L\$G$"(B + $B$k!%(B +\item[\rcitem{acl}{pull}] $B%m!<%+%k%j%]%8%H%j$+$i(Bpull$B$7$?%A%'%s%8%;%C%H$r(B + $B@)8f$9$k!%(B +\item[\rcitem{acl}{push}] $B%m!<%+%k%j%]%8%H%j$+$i(Bpush$B$7$?%A%'%s%8%;%C%H$r(B + $B@)8f$9$k!%(B +\item[\rcitem{acl}{bundle}] $BJL$N%j%]%8%H%j$+$i%P%s%I%k$K$h$C$FE~Ce$7$?%A%'(B + $B%s%8%;%C%H$r@)8f$9$k!%(B +\end{itemize} + +%The \rcsection{acl.allow} section controls the users that are allowed to +%add changesets to the repository. If this section is not present, all +%users that are not explicitly denied are allowed. If this section is +%present, all users that are not explicitly allowed are denied (so an +%empty section means that all users are denied). + +\rcsection{acl.allow}$B%;%/%7%g%s$O%A%'%s%8%;%C%H$N%j%]%8%H%j$X$NDI2C$r5v(B +$B2D$5$l$F$$$k%f!<%6$r@_Dj$9$k!%$3$N%;%/%7%g%s$,B8:_$7$J$$>l9g!$L@<(E*$K5q(B +$BH]$5$l$F$$$J$$$9$Y$F$N%f!<%6$O5v2D$5$l$k!%$3$N%;%/%7%g%s$,B8:_$9$k>l9g!$(B +$BL@<(E*$K5v2D$5$l$F$$$J$$$9$Y$F$N%f!<%6$O5qH]$5$l$k!%!J$9$J$o$A!$6u$N%;%/(B +$B%7%g%s$O$9$Y$F$N%f!<%6$N5qH]$H$$$&0UL#$K$J$k!%!K(B + +%The \rcsection{acl.deny} section determines which users are denied +%from adding changesets to the repository. If this section is not +%present or is empty, no users are denied. + +\rcsection{acl.deny}$B%;%/%7%g%s$O!$%j%]%8%H%j$X$N%A%'%s%8%;%C%HDI2C$r5qH](B +$B$9$k%f!<%6$r@_Dj$9$k!%$3$N%;%/%7%g%s$,B8:_$7$J$$$+!$6u$N>l9g$O$I$N%f!<%6(B +$B$b5qH]$5$l$J$$!%(B + +%The syntaxes for the \rcsection{acl.allow} and \rcsection{acl.deny} +%sections are identical. On the left of each entry is a glob pattern +%that matches files or directories, relative to the root of the +%repository; on the right, a user name. + +\rcsection{acl.allow}$B$H(B\rcsection{acl.deny}$B%;%/%7%g%s$N9=J8$OF10l$G$"$k!%(B +$B3F!9$N%(%s%H%j$N:8JU$O%U%!%$%k$^$?$O%G%#%l%/%H%j$K%^%C%A$9$k(Bglob$B%Q%?!<%s(B +$B$G!$%j%]%8%H%j%k!<%H$+$i$NAjBP%Q%9$G$"$k!%1&JU$O%f!<%6L>$G$"$k!%(B + +%In the following example, the user \texttt{docwriter} can only push +%changes to the \dirname{docs} subtree of the repository, while +%\texttt{intern} can push changes to any file or directory except +%\dirname{source/sensitive}. +%\begin{codesample2} +% [acl.allow] +% docs/** = docwriter +% +% [acl.deny] +% source/sensitive/** = intern +%\end{codesample2} + +$B0J2<$NNc$G$O!$(B\texttt{docwriter}$B$H$$$&%f!<%6$O!$%j%]%8%H%j$N(B +\dirname{docs}$B%5%V%D%j!<$K$7$+(Bpush$B$G$-$J$$!%$^$?(B\texttt{intern}$B$O(B +\dirname{source/sensitive}$B0J30$J$i$P$I$N%G%#%l%/%H%j$N$I$N%U%!%$%k$K$bJQ(B +$B99$r(Bpush$B$9$k$3$H$,$G$-$k!%(B +\begin{codesample2} + [acl.allow] + docs/** = docwriter + + [acl.deny] + source/sensitive/** = intern +\end{codesample2} + +%\subsubsection{Testing and troubleshooting} +\subsubsection{$B%F%9%H$HLdBj2r7h(B} + +%If you want to test the \hgext{acl} hook, run it with Mercurial's + +%debugging output enabled. Since you'll probably be running it on a +%server where it's not convenient (or sometimes possible) to pass in +%the \hggopt{--debug} option, don't forget that you can enable +%debugging output in your \hgrc: +%\begin{codesample2} +% [ui] +% debug = true +%\end{codesample2} +%With this enabled, the \hgext{acl} hook will print enough information +%to let you figure out why it is allowing or forbidding pushes from +%specific users. + +\hgext{acl}$B%U%C%/$r%F%9%H$7$?$$>l9g$O!$(BMercurial$B$N%G%P%C%0=PNO$rM-8z$K$7(B +$B$F<B9T$9$k$HNI$$!%%5!<%P>e$G<B9T$9$k$N$G$"$l$P!"(B\hggopt{--debug}$B%*%W%7%g(B +$B%s$rEO$9$N$OITJX$G$"$C$?$j!"IT2DG=$G$"$C$?$j$9$k$3$H$,$"$k!#$3$N$?$a!"%G(B +$B%P%C%0=PNO$O(B \hgrc $B$G$($bM-8z$K$G$-$k$3$H$r5-21$7$F$*$/$Y$-$G$"$k!%(B +\begin{codesample2} + [ui] + debug = true +\end{codesample2} +$B%G%P%C%0=PNO$,M-8z$N>l9g!$(B\hgext{acl}$B%U%C%/$O!$FCDj$N%f!<%6$r5v2D$"$k$$(B +$B$O5qH]$7$?M}M3$rCN$k$N$K==J,$J>pJs$r=PNO$9$k!%(B + +%\subsection{\hgext{bugzilla}---integration with Bugzilla} +\subsection{\hgext{bugzilla}---Bugzilla$B$H$N7k9g(B} + +%The \hgext{bugzilla} extension adds a comment to a Bugzilla bug +%whenever it finds a reference to that bug ID in a commit comment. You +%can install this hook on a shared server, so that any time a remote +%user pushes changes to this server, the hook gets run. + +\hgext{bugzilla}$B%(%/%9%F%s%7%g%s$O!$(BBugzilla$B$G4IM}$5$l$F$$$k%P%0$X!$%3%_%C(B +$B%H%3%a%s%H$NCf$G%P%0(BID$B$r;2>H$7$F$$$k>l9g%3%a%s%H$rDI2C$9$k!%(B +$B$3$N%U%C%/$O6&M-%5!<%P$K$b%$%s%9%H!<%k$G$-$k$N$G!$%j%b!<%H%f!<%6$,(B +$BJQ99$r(Bpush$B$7$?>l9g$K$bF0:n$9$k!%(B + +%It adds a comment to the bug that looks like this (you can configure +%the contents of the comment---see below): +%\begin{codesample2} +% Changeset aad8b264143a, made by Joe User <joe.user@domain.com> in +% the frobnitz repository, refers to this bug. +% +% For complete details, see +% http://hg.domain.com/frobnitz?cmd=changeset;node=aad8b264143a +% +% Changeset description: +% Fix bug 10483 by guarding against some NULL pointers +%\end{codesample2} +%The value of this hook is that it automates the process of updating a +%bug any time a changeset refers to it. If you configure the hook +%properly, it makes it easy for people to browse straight from a +%Bugzilla bug to a changeset that refers to that bug. + +$B$3$N%U%C%/$O<!$N$h$&$K%P%0$X%3%a%s%H$rDI2C$9$k!%!J%3%a%s%H$NFbMF$O@_Dj2D(B +$BG=$G$"$k!%$3$l$K$D$$$F$O2<5-$r;2>H!%!K(B +\begin{codesample2} + Changeset aad8b264143a, made by Joe User <joe.user@domain.com> in + the frobnitz repository, refers to this bug. + + For complete details, see + http://hg.domain.com/frobnitz?cmd=changeset;node=aad8b264143a + + Changeset description: + Fix bug 10483 by guarding against some NULL pointers +\end{codesample2} +$B$3$N%U%C%/$O!$%A%'%s%8%;%C%H$,%P%0$r;2>H$7$?>l9g!$%P%0$N99?7$r<+F02=$G$-(B +$B$k$H$3$m$K2ACM$,$"$k!%$3$N%U%C%/$r$-$A$s$H@_Dj$9$l$P!$(BBugzilla$B%P%0$r1\Mw(B +$B$7$F$$$k%f!<%6$,!$%P%0$+$iD>$A$K4X78$9$k%A%'%s%8%;%C%H$r;2>H$G$-$k$h$&$K(B +$B$J$k!%(B + +%You can use the code in this hook as a starting point for some more +%exotic Bugzilla integration recipes. Here are a few possibilities: +%\begin{itemize} +%\item Require that every changeset pushed to the server have a valid +% bug~ID in its commit comment. In this case, you'd want to configure +% the hook as a \hook{pretxncommit} hook. This would allow the hook +% to reject changes that didn't contain bug IDs. +%\item Allow incoming changesets to automatically modify the +% \emph{state} of a bug, as well as simply adding a comment. For +% example, the hook could recognise the string ``fixed bug 31337'' as +% indicating that it should update the state of bug 31337 to +% ``requires testing''. +%\end{itemize} + +$B$3$N%U%C%/$N%3!<%I$r=PH/E@$H$7$F!$JL$N(BBugzilla$B$H$N7k9g$r9T$&$3$H$b2DG=(B +$B$G$"$k!%$$$/$D$+$NNc$r5s$2$k!'(B +\begin{itemize} + \item $B%5!<%P$K%W%C%7%e$5$l$?%A%'%s%8%;%C%H$9$Y$F$K%3%_%C%H%3%a%s%H$KM-8z(B + $B$J%P%0(BID$B$,$"$k$3$H$rMW5a$9$k!%$3$N>l9g!$%U%C%/$r(B + \hook{pretxncommit}$B%U%C%/$H$7$F@_Dj$9$kI,MW$,$"$k!%$3$l$K$h$C$F!$(B + $B%P%0(BID$B$r4^$^$J$$JQ99$r5qH]$9$k$3$H$,$G$-$k!%(B + \item $BE~Ce$9$k%A%'%s%8%;%C%H$K!$%3%a%s%HDI2C$K2C$($F!$%P%0$N(B\emph{$B%9%F!<(B + $B%H(B}$B$r<+F0E*$KJQ99$9$k$h$&$K$G$-$k!%Nc$($P!$%U%C%/$,(B``fixed bug + 31337''$B$N$h$&$JJ8;zNs$rG'<1$7$F!$(Bbug 31337$B$N%9%F!<%H$r(B``requires + testing''$B$KJQ99$9$k$J$I$,9M$($i$l$k!%(B +\end{itemize} + +%\subsubsection{Configuring the \hook{bugzilla} hook} +\subsubsection{\hook{bugzilla}$B%U%C%/$N@_Dj(B} +\label{sec:hook:bugzilla:config} + +%You should configure this hook in your server's \hgrc\ as an +%\hook{incoming} hook, for example as follows: +%\begin{codesample2} +% [hooks] +% incoming.bugzilla = python:hgext.bugzilla.hook +%\end{codesample2} + +$B$3$N%U%C%/$O<!$NNc$N$h$&$K%5!<%P>e$N(B\hgrc\ $B$G(B\hook{incoming}$B%U%C%/$H@_Dj(B +$B$9$Y$-$G$"$k!%(B +\begin{codesample2} + [hooks] + incoming.bugzilla = python:hgext.bugzilla.hook +\end{codesample2} + +%Because of the specialised nature of this hook, and because Bugzilla +%was not written with this kind of integration in mind, configuring +%this hook is a somewhat involved process. + +$B$3$N%U%C%/$NFCJL$J@-<A!$(BBugzilla$B$,$3$N$h$&$J7k9g$rG0F,$K=q$+$l$F$$$J$$$3(B +$B$H$K$h$C$F!$$3$N%U%C%/$N@_Dj$OJ#;($J%W%m%;%9$H$J$k!%(B + +%Before you begin, you must install the MySQL bindings for Python on +%the host(s) where you'll be running the hook. If this is not +%available as a binary package for your system, you can download it +%from~\cite{web:mysql-python}. + +$B@_Dj$r3+;O$9$kA0$K!$%U%C%/$r<B9T$9$k%[%9%H>e$G(BPython$BMQ$N(BMySQL$B%P%$%s%G%#%s(B +$B%0$r%$%s%9%H!<%k$9$kI,MW$,$"$k!%<B9T4D6-MQ$K%P%$%J%j%Q%C%1!<%8$,MQ0U$5$l(B +$B$F$$$J$1$l$P!$%=!<%9%U%!%$%k$r(B\cite{web:mysql-python}$B$+$i%@%&%s%m!<%I$9$k(B +$B$3$H$,$G$-$k!%(B + +%Configuration information for this hook lives in the +%\rcsection{bugzilla} section of your \hgrc. +$B$3$N%U%C%/$N@_Dj>pJs$O!$(B\hgrc $B%U%!%$%k$N(B\rcsection{bugzilla}$B%;%/%7%g%s$K(B +$B$"$k!%(B +\begin{itemize} +%\item[\rcitem{bugzilla}{version}] The version of Bugzilla installed on +% the server. The database schema that Bugzilla uses changes +% occasionally, so this hook has to know exactly which schema to use. +% At the moment, the only version supported is \texttt{2.16}. + \item[\rcitem{bugzilla}{version}] $B%5!<%P$X%$%s%9%H!<%k$5$l$?(BBugzilla$B$N%P!<(B + $B%8%g%s!%(BBugzilla$B$N;HMQ$9$k%G!<%?%Y!<%9$N%9%-!<%^$O;~$KJQ99(B + $B$5$l$k$?$a!$%U%C%/$O$I$N%9%-!<%^$,;HMQ$5$l$k$N$+$rCN$kI,MW(B + $B$,$"$k!%8=;~E@$G$O(BBugzilla\texttt{2.16}$B$@$1$,%5%]!<%H$5$l(B + $B$F$$$k!%(B + +%\item[\rcitem{bugzilla}{host}] The hostname of the MySQL server that +% stores your Bugzilla data. The database must be configured to allow +% connections from whatever host you are running the \hook{bugzilla} +% hook on. + \item[\rcitem{bugzilla}{host}] Bugzilla$B%G!<%?$r3JG<$7$F$$$k(BMySQL$B%5!<%P$N(B + $B%[%9%H%M!<%`!%%G!<%?%Y!<%9$O(B\hook{bugzilla}$B%U%C%/$r<B9T$9(B + $B$k%[%9%H$+$i@\B32DG=$K@_Dj$5$l$F$$$J$1$l$P$J$i$J$$!%(B + +%\item[\rcitem{bugzilla}{user}] The username with which to connect to +% the MySQL server. The database must be configured to allow this +% user to connect from whatever host you are running the +% \hook{bugzilla} hook on. This user must be able to access and +% modify Bugzilla tables. The default value of this item is +% \texttt{bugs}, which is the standard name of the Bugzilla user in a +% MySQL database. + \item[\rcitem{bugzilla}{user}] MySQL$B%5!<%P$K@\B3$9$k%f!<%6L>!%%G!<%?%Y!<(B + $B%9$O(B\hook{bugzilla}$B%U%C%/$r<B9T$9$k%[%9%H>e$+$i$3$N%f!<%6$N(B + $B@\B3$r5v2D$9$k$h$&$K@_Dj$5$l$F$$$J$1$l$P$J$i$J$$!%$3$N%f!<(B + $B%6$O(BBugzilla$B%F!<%V%k$K%"%/%;%9$7!$JQ99$G$-$k8"8B$,$J$1$l$P(B + $B$J$i$J$$!%$3$N9`L\$N%G%U%)%k%HCM$O(BMySQL$B%G!<%?%Y!<%9$G$N(B + Bugzilla$B%f!<%6$NI8=`L>(B\texttt{bugs}$B$G$"$k!%(B + +%\item[\rcitem{bugzilla}{password}] The MySQL password for the user you +% configured above. This is stored as plain text, so you should make +% sure that unauthorised users cannot read the \hgrc\ file where you +% store this information. + \item[\rcitem{bugzilla}{password}] $B>e5-$N%f!<%6$N(BMySQL$B%Q%9%o!<%I!%J?J8$G(B + $BJ]B8$5$l$k$?$a!$8"8B$N$J$$%f!<%6$,$3$N(B\hgrc\ $B%U%!%$%k$r3N<B(B + $B$KFI$a$J$$$h$&$K$7$F$*$/I,MW$,$"$k!%(B + +%\item[\rcitem{bugzilla}{db}] The name of the Bugzilla database on the +% MySQL server. The default value of this item is \texttt{bugs}, +% which is the standard name of the MySQL database where Bugzilla +% stores its data. + \item[\rcitem{bugzilla}{db}] MySQL$B%5!<%P>e$N(BBugzilla$B%G!<%?%Y!<%9$NL>A0!%(B + $B$3$N9`L\$N%G%U%)%k%HCM$O(B\texttt{bugs}$B$3$N9`L\$N%G%U%)%k%HCM(B + $B$O(BBugzilla$B$,%G!<%?$rJ]B8$9$k(BMySQL$B%G!<%?%Y!<%9$NI8=`L>(B + \texttt{bugs}$B$G$"$k!%(B + +%\item[\rcitem{bugzilla}{notify}] If you want Bugzilla to send out a +% notification email to subscribers after this hook has added a +% comment to a bug, you will need this hook to run a command whenever +% it updates the database. The command to run depends on where you + +% have installed Bugzilla, but it will typically look something like +% this, if you have Bugzilla installed in +% \dirname{/var/www/html/bugzilla}: +% \begin{codesample4} +% cd /var/www/html/bugzilla && ./processmail %s nobody@nowhere.com +% \end{codesample4} +% The Bugzilla \texttt{processmail} program expects to be given a +% bug~ID (the hook replaces ``\texttt{\%s}'' with the bug~ID) and an +% email address. It also expects to be able to write to some files in +% the directory that it runs in. If Bugzilla and this hook are not +% installed on the same machine, you will need to find a way to run +% \texttt{processmail} on the server where Bugzilla is installed. +\item[\rcitem{bugzilla}{notify}] $B%U%C%/$+$i%P%0$K%3%a%s%H$,DI2C$5$l$?;~!$(B + Bugzilla$B$+$i9VFI<T$KDLCN%a!<%k(B + $B$,Aw$i$l$k$h$&$K$7$?$$>l9g$O!$%U%C%/$,%G!<%?%Y!<%9$r99?7$7(B + $B$?>l9g$O>o$K%3%^%s%I$,<B9T$5$l$k$h$&$K@_Dj$7$J$1$l$P$J$i$J(B + $B$$!%<B9T$9$k%3%^%s%I$O!$(BBugzilla$B$r$I$3$K%$%s%9%H!<%k$7$?$+$K(B + $B0MB8$9$k!%(BBugzilla$B$r(B\dirname{/var/www/html/bugzilla}$B$K%$%s(B + $B%9%H!<%k$7$?>l9g!$E57?E*$J%3%^%s%I$O<!$N$h$&$K$J$k!'(B + \begin{codesample4} + cd /var/www/html/bugzilla && ./processmail %s nobody@nowhere.com + \end{codesample4} +Bugzilla \texttt{processmail}$B%W%m%0%i%`$O(Bbug~ID ($B%U%C%/$,(B +``\texttt{\%s}''$B$r(Bbug~ID$B$KCV49$9$k!%(B)$B$H(Bemail$B%"%I%l%9$r<h$k!%$3$N%W%m%0%i(B +$B%`$O$^$?<B9T$5$l$k%G%#%l%/%H%jFb$G$$$/$D$+$N%U%!%$%k$X=q$-9~$_$rI,MW$H$9(B +$B$k!%(BBugzilla$B$H%U%C%/$,F1$8%^%7%s>e$K%$%s%9%H!<%k$5$l$F$$$J$$>l9g!$(B +Bugzilla$B$,%$%s%9%H!<%k$5$l$?%5!<%P>e$G(B\texttt{processmail}$B$r<B9T$9$kJ}K!(B +$B$r8+$D$1$kI,MW$,$"$k!%(B +\end{itemize} + +%\subsubsection{Mapping committer names to Bugzilla user names} +\subsubsection{$B%3%_%C%H<T$NL>A0$r(BBugzilla$B$N%f!<%6L>$X%^%C%W$9$k(B} + +%By default, the \hgext{bugzilla} hook tries to use the email address +%of a changeset's committer as the Bugzilla user name with which to +%update a bug. If this does not suit your needs, you can map committer +%email addresses to Bugzilla user names using a \rcsection{usermap} +%section. + +$B%G%U%)%k%H$G$O(B\hgext{bugzilla}$B%U%C%/$O%P%0$r99?7$9$k(BBugzilla$B%f!<%6L>$H$7(B +$B$F%A%'%s%8%;%C%H$N%3%_%C%?$N(Bemail$B%"%I%l%9$r;H$*$&$H$9$k!%(B +$B$3$N5sF0$,K>$^$7$/$J$$>l9g$O!$(B\rcsection{usermap}$B%;%/%7%g%s$r$;$C$F$$$9$k(B +$B$3$H$G%3%_%C%?$N(Bemail$B%"%I%l%9$r(BBugzilla$B$N%f!<%6L>$K%^%C%W$9$k$3$H$,$G$-$k!%(B + +%Each item in the \rcsection{usermap} section contains an email address +%on the left, and a Bugzilla user name on the right. +%\begin{codesample2} +% [usermap] +% jane.user@example.com = jane +%\end{codesample2} +%You can either keep the \rcsection{usermap} data in a normal \hgrc, or +%tell the \hgext{bugzilla} hook to read the information from an +%external \filename{usermap} file. In the latter case, you can store +%\filename{usermap} data by itself in (for example) a user-modifiable +%repository. This makes it possible to let your users maintain their +%own \rcitem{bugzilla}{usermap} entries. The main \hgrc\ file might +%look like this: +%\begin{codesample2} +% # regular hgrc file refers to external usermap file +% [bugzilla] +% usermap = /home/hg/repos/userdata/bugzilla-usermap.conf +%\end{codesample2} +%While the \filename{usermap} file that it refers to might look like +%this: +%\begin{codesample2} +% # bugzilla-usermap.conf - inside a hg repository +% [usermap] +% stephanie@example.com = steph +%\end{codesample2} + +\rcsection{usermap}$B%;%/%7%g%s$N3F!9$N9`L\$O!$:8JU$K(Bemail$B%"%I%l%9!$1&JU$K(B +Bugzilla$B%f!<%6L>$r;}$D!%(B +\begin{codesample2} + [usermap] + jane.user@example.com = jane +\end{codesample2} +\rcsection{usermap}$B%G!<%?$rDL>o$N(B \hgrc $B%U%!%$%k$KJ]B8$9$k$3$H$b(B +\hgext{bugzilla}$B%U%C%/$K30It$N(B\filename{usermap}$B%U%!%$%k$rFI$`$h$&$K;X<((B +$B$9$k$3$H$b$G$-$k!%8e<T$N>l9g!$Nc$($P(B\filename{usermap}$B%G!<%?$r%f!<%6$,JQ(B +$B992DG=$J%j%]%8%H%j$KCV$/$3$H$b2DG=$G$"$k!%$3$l$O%f!<%6$K(B +\rcitem{bugzilla}{usermap}$B%(%s%H%j$N4IM}$rG$$;$k$3$H$K$J$k!%%a%$%s$N(B +\hgrc\ $B%U%!%$%k$O<!$N$h$&$K$J$k!%!'(B +\begin{codesample2} + # regular hgrc file refers to external usermap file + [bugzilla] + usermap = /home/hg/repos/userdata/bugzilla-usermap.conf +\end{codesample2} + +%\subsubsection{Configuring the text that gets added to a bug} +\subsubsection{$B%P%0$KDI2C$5$l$?J8;zNs$r@_Dj$9$k(B} + +You can configure the text that this hook adds as a comment; you +specify it in the form of a Mercurial template. Several \hgrc\ +entries (still in the \rcsection{bugzilla} section) control this +behaviour. +\begin{itemize} +\item[\texttt{strip}] The number of leading path elements to strip + from a repository's path name to construct a partial path for a URL. + For example, if the repositories on your server live under + \dirname{/home/hg/repos}, and you have a repository whose path is + \dirname{/home/hg/repos/app/tests}, then setting \texttt{strip} to + \texttt{4} will give a partial path of \dirname{app/tests}. The + hook will make this partial path available when expanding a + template, as \texttt{webroot}. +\item[\texttt{template}] The text of the template to use. In addition + to the usual changeset-related variables, this template can use + \texttt{hgweb} (the value of the \texttt{hgweb} configuration item + above) and \texttt{webroot} (the path constructed using + \texttt{strip} above). +\end{itemize} + +In addition, you can add a \rcitem{web}{baseurl} item to the +\rcsection{web} section of your \hgrc. The \hgext{bugzilla} hook will +make this available when expanding a template, as the base string to +use when constructing a URL that will let users browse from a Bugzilla +comment to view a changeset. Example: +\begin{codesample2} + [web] + baseurl = http://hg.domain.com/ +\end{codesample2} + +Here is an example set of \hgext{bugzilla} hook config information. +\begin{codesample2} + [bugzilla] + host = bugzilla.example.com + password = mypassword + version = 2.16 + # server-side repos live in /home/hg/repos, so strip 4 leading + # separators + strip = 4 + hgweb = http://hg.example.com/ + usermap = /home/hg/repos/notify/bugzilla.conf + template = Changeset \{node|short\}, made by \{author\} in the \{webroot\} + repo, refers to this bug.\\nFor complete details, see + \{hgweb\}\{webroot\}?cmd=changeset;node=\{node|short\}\\nChangeset + description:\\n\\t\{desc|tabindent\} +\end{codesample2} + +%\subsubsection{Testing and troubleshooting} +\subsubsection{$B%F%9%H$HLdBj2r7h(B} + +The most common problems with configuring the \hgext{bugzilla} hook +relate to running Bugzilla's \filename{processmail} script and mapping +committer names to user names. + +Recall from section~\ref{sec:hook:bugzilla:config} above that the user +that runs the Mercurial process on the server is also the one that +will run the \filename{processmail} script. The +\filename{processmail} script sometimes causes Bugzilla to write to +files in its configuration directory, and Bugzilla's configuration +files are usually owned by the user that your web server runs under. + +You can cause \filename{processmail} to be run with the suitable +user's identity using the \command{sudo} command. Here is an example +entry for a \filename{sudoers} file. +\begin{codesample2} + hg_user = (httpd_user) NOPASSWD: /var/www/html/bugzilla/processmail-wrapper %s +\end{codesample2} +This allows the \texttt{hg\_user} user to run a +\filename{processmail-wrapper} program under the identity of +\texttt{httpd\_user}. + +This indirection through a wrapper script is necessary, because +\filename{processmail} expects to be run with its current directory +set to wherever you installed Bugzilla; you can't specify that kind of +constraint in a \filename{sudoers} file. The contents of the wrapper +script are simple: +\begin{codesample2} + #!/bin/sh + cd `dirname $0` && ./processmail "$1" nobody@example.com +\end{codesample2} +It doesn't seem to matter what email address you pass to +\filename{processmail}. + +If your \rcsection{usermap} is not set up correctly, users will see an +error message from the \hgext{bugzilla} hook when they push changes +to the server. The error message will look like this: +\begin{codesample2} + cannot find bugzilla user id for john.q.public@example.com +\end{codesample2} +What this means is that the committer's address, +\texttt{john.q.public@example.com}, is not a valid Bugzilla user name, +nor does it have an entry in your \rcsection{usermap} that maps it to +a valid Bugzilla user name. + +%\subsection{\hgext{notify}---send email notifications} +\subsection{\hgext{notify}---$B%a!<%k$GDLCN$r9T$&(B} + +Although Mercurial's built-in web server provides RSS feeds of changes +in every repository, many people prefer to receive change +notifications via email. The \hgext{notify} hook lets you send out +notifications to a set of email addresses whenever changesets arrive +that those subscribers are interested in. + +As with the \hgext{bugzilla} hook, the \hgext{notify} hook is +template-driven, so you can customise the contents of the notification +messages that it sends. + +By default, the \hgext{notify} hook includes a diff of every changeset +that it sends out; you can limit the size of the diff, or turn this +feature off entirely. It is useful for letting subscribers review +changes immediately, rather than clicking to follow a URL. + +%\subsubsection{Configuring the \hgext{notify} hook} +\subsubsection{\hgext{notify}$B%U%C%/$N@_Dj(B} + +You can set up the \hgext{notify} hook to send one email message per +incoming changeset, or one per incoming group of changesets (all those +that arrived in a single pull or push). +\begin{codesample2} + [hooks] + # send one email per group of changes + changegroup.notify = python:hgext.notify.hook + # send one email per change + incoming.notify = python:hgext.notify.hook +\end{codesample2} + +Configuration information for this hook lives in the +\rcsection{notify} section of a \hgrc\ file. +\begin{itemize} +\item[\rcitem{notify}{test}] By default, this hook does not send out + email at all; instead, it prints the message that it \emph{would} + send. Set this item to \texttt{false} to allow email to be sent. + The reason that sending of email is turned off by default is that it + takes several tries to configure this extension exactly as you would + like, and it would be bad form to spam subscribers with a number of + ``broken'' notifications while you debug your configuration. +\item[\rcitem{notify}{config}] The path to a configuration file that + contains subscription information. This is kept separate from the + main \hgrc\ so that you can maintain it in a repository of its own. + People can then clone that repository, update their subscriptions, + and push the changes back to your server. +\item[\rcitem{notify}{strip}] The number of leading path separator + characters to strip from a repository's path, when deciding whether + a repository has subscribers. For example, if the repositories on + your server live in \dirname{/home/hg/repos}, and \hgext{notify} is + considering a repository named \dirname{/home/hg/repos/shared/test}, + setting \rcitem{notify}{strip} to \texttt{4} will cause + \hgext{notify} to trim the path it considers down to + \dirname{shared/test}, and it will match subscribers against that. +\item[\rcitem{notify}{template}] The template text to use when sending + messages. This specifies both the contents of the message header + and its body. +\item[\rcitem{notify}{maxdiff}] The maximum number of lines of diff + data to append to the end of a message. If a diff is longer than + this, it is truncated. By default, this is set to 300. Set this to + \texttt{0} to omit diffs from notification emails. +\item[\rcitem{notify}{sources}] A list of sources of changesets to + consider. This lets you limit \hgext{notify} to only sending out + email about changes that remote users pushed into this repository + via a server, for example. See section~\ref{sec:hook:sources} for + the sources you can specify here. +\end{itemize} + +If you set the \rcitem{web}{baseurl} item in the \rcsection{web} +section, you can use it in a template; it will be available as +\texttt{webroot}. + +Here is an example set of \hgext{notify} configuration information. +\begin{codesample2} + [notify] + # really send email + test = false + # subscriber data lives in the notify repo + config = /home/hg/repos/notify/notify.conf + # repos live in /home/hg/repos on server, so strip 4 "/" chars + strip = 4 + template = X-Hg-Repo: \{webroot\} + Subject: \{webroot\}: \{desc|firstline|strip\} + From: \{author\} + + changeset \{node|short\} in \{root\} + details: \{baseurl\}\{webroot\}?cmd=changeset;node=\{node|short\} + description: + \{desc|tabindent|strip\} + + [web] + baseurl = http://hg.example.com/ +\end{codesample2} + +This will produce a message that looks like the following: +\begin{codesample2} + X-Hg-Repo: tests/slave + Subject: tests/slave: Handle error case when slave has no buffers + Date: Wed, 2 Aug 2006 15:25:46 -0700 (PDT) + + changeset 3cba9bfe74b5 in /home/hg/repos/tests/slave + details: http://hg.example.com/tests/slave?cmd=changeset;node=3cba9bfe74b5 + description: + Handle error case when slave has no buffers + diffs (54 lines): + + diff -r 9d95df7cf2ad -r 3cba9bfe74b5 include/tests.h + --- a/include/tests.h Wed Aug 02 15:19:52 2006 -0700 + +++ b/include/tests.h Wed Aug 02 15:25:26 2006 -0700 + @@ -212,6 +212,15 @@ static __inline__ void test_headers(void *h) + [...snip...] +\end{codesample2} + +%\subsubsection{Testing and troubleshooting} +\subsubsection{$B%F%9%H$HLdBj2r7h(B} + +Do not forget that by default, the \hgext{notify} extension \emph{will + not send any mail} until you explicitly configure it to do so, by +setting \rcitem{notify}{test} to \texttt{false}. Until you do that, +it simply prints the message it \emph{would} send. + +%\section{Information for writers of hooks} +\section{$B%U%C%/:n@=<T$X$N>pJs(B} +\label{sec:hook:ref} + +%\subsection{In-process hook execution} +\subsection{$B%W%m%;%9Fb%U%C%/$N<B9T(B} + +An in-process hook is called with arguments of the following form: +\begin{codesample2} + def myhook(ui, repo, **kwargs): + pass +\end{codesample2} +The \texttt{ui} parameter is a \pymodclass{mercurial.ui}{ui} object. +The \texttt{repo} parameter is a +\pymodclass{mercurial.localrepo}{localrepository} object. The +names and values of the \texttt{**kwargs} parameters depend on the +hook being invoked, with the following common features: +\begin{itemize} +\item If a parameter is named \texttt{node} or + \texttt{parent\emph{N}}, it will contain a hexadecimal changeset ID. + The empty string is used to represent ``null changeset ID'' instead + of a string of zeroes. +\item If a parameter is named \texttt{url}, it will contain the URL of + a remote repository, if that can be determined. +\item Boolean-valued parameters are represented as Python + \texttt{bool} objects. +\end{itemize} + +An in-process hook is called without a change to the process's working +directory (unlike external hooks, which are run in the root of the +repository). It must not change the process's working directory, or +it will cause any calls it makes into the Mercurial API to fail. + +If a hook returns a boolean ``false'' value, it is considered to have +succeeded. If it returns a boolean ``true'' value or raises an +exception, it is considered to have failed. A useful way to think of +the calling convention is ``tell me if you fail''. + +Note that changeset IDs are passed into Python hooks as hexadecimal +strings, not the binary hashes that Mercurial's APIs normally use. To +convert a hash from hex to binary, use the +\pymodfunc{mercurial.node}{bin} function. + +%\subsection{External hook execution} +\subsection{$B%U%C%/$N30It<B9T(B} + +An external hook is passed to the shell of the user running Mercurial. +Features of that shell, such as variable substitution and command +redirection, are available. The hook is run in the root directory of +the repository (unlike in-process hooks, which are run in the same +directory that Mercurial was run in). + +Hook parameters are passed to the hook as environment variables. Each +environment variable's name is converted in upper case and prefixed +with the string ``\texttt{HG\_}''. For example, if the name of a +parameter is ``\texttt{node}'', the name of the environment variable +representing that parameter will be ``\texttt{HG\_NODE}''. + +A boolean parameter is represented as the string ``\texttt{1}'' for +``true'', ``\texttt{0}'' for ``false''. If an environment variable is +named \envar{HG\_NODE}, \envar{HG\_PARENT1} or \envar{HG\_PARENT2}, it +contains a changeset ID represented as a hexadecimal string. The +empty string is used to represent ``null changeset ID'' instead of a +string of zeroes. If an environment variable is named +\envar{HG\_URL}, it will contain the URL of a remote repository, if +that can be determined. + +If a hook exits with a status of zero, it is considered to have +succeeded. If it exits with a non-zero status, it is considered to +have failed. + +%\subsection{Finding out where changesets come from} +\subsection{$B%A%'%s%8%;%C%H$N=P=h$rD4$Y$k(B} + +A hook that involves the transfer of changesets between a local +repository and another may be able to find out information about the +``far side''. Mercurial knows \emph{how} changes are being +transferred, and in many cases \emph{where} they are being transferred +to or from. + +%\subsubsection{Sources of changesets} +\subsubsection{$B%A%'%s%8%;%C%H$N=P=h(B} +\label{sec:hook:sources} + +Mercurial will tell a hook what means are, or were, used to transfer +changesets between repositories. This is provided by Mercurial in a +Python parameter named \texttt{source}, or an environment variable named +\envar{HG\_SOURCE}. + +\begin{itemize} +\item[\texttt{serve}] Changesets are transferred to or from a remote + repository over http or ssh. +\item[\texttt{pull}] Changesets are being transferred via a pull from + one repository into another. +\item[\texttt{push}] Changesets are being transferred via a push from + one repository into another. +\item[\texttt{bundle}] Changesets are being transferred to or from a + bundle. +\end{itemize} + +%\subsubsection{Where changes are going---remote repository URLs} +\subsubsection{$BJQ99$N9T$-@h(B---$B%j%b!<%H%j%]%8%H%j$N(BURL} +\label{sec:hook:url} + +When possible, Mercurial will tell a hook the location of the ``far +side'' of an activity that transfers changeset data between +repositories. This is provided by Mercurial in a Python parameter +named \texttt{url}, or an environment variable named \envar{HG\_URL}. + +This information is not always known. If a hook is invoked in a +repository that is being served via http or ssh, Mercurial cannot tell +where the remote repository is, but it may know where the client is +connecting from. In such cases, the URL will take one of the +following forms: +\begin{itemize} +\item \texttt{remote:ssh:\emph{ip-address}}---remote ssh client, at + the given IP address. +\item \texttt{remote:http:\emph{ip-address}}---remote http client, at + the given IP address. If the client is using SSL, this will be of + the form \texttt{remote:https:\emph{ip-address}}. +\item Empty---no information could be discovered about the remote + client. +\end{itemize} + +%\section{Hook reference} +\section{$B%U%C%/;2>H(B} + +%\subsection{\hook{changegroup}---after remote changesets added} +\subsection{\hook{changegroup}---$B%j%b!<%H%A%'%s%8%;%C%H$,DI2C$5$l$?8e(B} +\label{sec:hook:changegroup} + +This hook is run after a group of pre-existing changesets has been +added to the repository, for example via a \hgcmd{pull} or +\hgcmd{unbundle}. This hook is run once per operation that added one +or more changesets. This is in contrast to the \hook{incoming} hook, +which is run once per changeset, regardless of whether the changesets +arrive in a group. + +Some possible uses for this hook include kicking off an automated +build or test of the added changesets, updating a bug database, or +notifying subscribers that a repository contains new changes. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{node}] A changeset ID. The changeset ID of the first + changeset in the group that was added. All changesets between this + and \index{tags!\texttt{tip}}\texttt{tip}, inclusive, were added by + a single \hgcmd{pull}, \hgcmd{push} or \hgcmd{unbundle}. +\item[\texttt{source}] A string. The source of these changes. See + section~\ref{sec:hook:sources} for details. +\item[\texttt{url}] A URL. The location of the remote repository, if + known. See section~\ref{sec:hook:url} for more information. +\end{itemize} + +See also: \hook{incoming} (section~\ref{sec:hook:incoming}), +\hook{prechangegroup} (section~\ref{sec:hook:prechangegroup}), +\hook{pretxnchangegroup} (section~\ref{sec:hook:pretxnchangegroup}) + +%\subsection{\hook{commit}---after a new changeset is created} +\subsection{\hook{commit}---$B?7$7$$%A%'%s%8%;%C%H$,:n@.$5$l$?8e(B} +\label{sec:hook:commit} + +This hook is run after a new changeset has been created. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{node}] A changeset ID. The changeset ID of the newly + committed changeset. +\item[\texttt{parent1}] A changeset ID. The changeset ID of the first + parent of the newly committed changeset. +\item[\texttt{parent2}] A changeset ID. The changeset ID of the second + parent of the newly committed changeset. +\end{itemize} + +See also: \hook{precommit} (section~\ref{sec:hook:precommit}), +\hook{pretxncommit} (section~\ref{sec:hook:pretxncommit}) + +%\subsection{\hook{incoming}---after one remote changeset is added} +\subsection{\hook{incoming}---$B%j%b!<%H%A%'%s%8%;%C%H$,DI2C$5$l$?8e(B} +\label{sec:hook:incoming} + +This hook is run after a pre-existing changeset has been added to the +repository, for example via a \hgcmd{push}. If a group of changesets +was added in a single operation, this hook is called once for each +added changeset. + +You can use this hook for the same purposes as the \hook{changegroup} +hook (section~\ref{sec:hook:changegroup}); it's simply more convenient +sometimes to run a hook once per group of changesets, while other +times it's handier once per changeset. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{node}] A changeset ID. The ID of the newly added + changeset. +\item[\texttt{source}] A string. The source of these changes. See + section~\ref{sec:hook:sources} for details. +\item[\texttt{url}] A URL. The location of the remote repository, if + known. See section~\ref{sec:hook:url} for more information. +\end{itemize} + +See also: \hook{changegroup} (section~\ref{sec:hook:changegroup}) \hook{prechangegroup} (section~\ref{sec:hook:prechangegroup}), \hook{pretxnchangegroup} (section~\ref{sec:hook:pretxnchangegroup}) + +%\subsection{\hook{outgoing}---after changesets are propagated} +\subsection{\hook{outgoing}---$B%A%'%s%8%;%C%H$,GH5Z$7$?8e(B} +\label{sec:hook:outgoing} + +This hook is run after a group of changesets has been propagated out +of this repository, for example by a \hgcmd{push} or \hgcmd{bundle} +command. + +One possible use for this hook is to notify administrators that +changes have been pulled. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{node}] A changeset ID. The changeset ID of the first + changeset of the group that was sent. +\item[\texttt{source}] A string. The source of the of the operation + (see section~\ref{sec:hook:sources}). If a remote client pulled + changes from this repository, \texttt{source} will be + \texttt{serve}. If the client that obtained changes from this + repository was local, \texttt{source} will be \texttt{bundle}, + \texttt{pull}, or \texttt{push}, depending on the operation the + client performed. +\item[\texttt{url}] A URL. The location of the remote repository, if + known. See section~\ref{sec:hook:url} for more information. +\end{itemize} + +See also: \hook{preoutgoing} (section~\ref{sec:hook:preoutgoing}) + +%\subsection{\hook{prechangegroup}---before starting to add remote +%changesets} +\subsection{\hook{prechangegroup}---$B%j%b!<%H%A%'%s%8%;%C%H$,$,DI2C$5$l$k(B + $BA0(B} +\label{sec:hook:prechangegroup} + +This controlling hook is run before Mercurial begins to add a group of +changesets from another repository. + +This hook does not have any information about the changesets to be +added, because it is run before transmission of those changesets is +allowed to begin. If this hook fails, the changesets will not be +transmitted. + +One use for this hook is to prevent external changes from being added +to a repository. For example, you could use this to ``freeze'' a +server-hosted branch temporarily or permanently so that users cannot +push to it, while still allowing a local administrator to modify the +repository. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{source}] A string. The source of these changes. See + section~\ref{sec:hook:sources} for details. +\item[\texttt{url}] A URL. The location of the remote repository, if + known. See section~\ref{sec:hook:url} for more information. +\end{itemize} + +See also: \hook{changegroup} (section~\ref{sec:hook:changegroup}), +\hook{incoming} (section~\ref{sec:hook:incoming}), , +\hook{pretxnchangegroup} (section~\ref{sec:hook:pretxnchangegroup}) + +%\subsection{\hook{precommit}---before starting to commit a changeset} +\subsection{\hook{precommit}---$B%A%'%s%8%;%C%H$r%3%_%C%H$9$kA0(B} +\label{sec:hook:precommit} + +This hook is run before Mercurial begins to commit a new changeset. +It is run before Mercurial has any of the metadata for the commit, +such as the files to be committed, the commit message, or the commit +date. + +One use for this hook is to disable the ability to commit new +changesets, while still allowing incoming changesets. Another is to +run a build or test, and only allow the commit to begin if the build +or test succeeds. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{parent1}] A changeset ID. The changeset ID of the first + parent of the working directory. +\item[\texttt{parent2}] A changeset ID. The changeset ID of the second + parent of the working directory. +\end{itemize} +If the commit proceeds, the parents of the working directory will +become the parents of the new changeset. + +See also: \hook{commit} (section~\ref{sec:hook:commit}), +\hook{pretxncommit} (section~\ref{sec:hook:pretxncommit}) + +%\subsection{\hook{preoutgoing}---before starting to propagate +%changesets} +\subsection{\hook{preoutgoing}---$B%A%'%s%8%;%C%H$rGH5Z$5$;$kA0$K(B} +\label{sec:hook:preoutgoing} + +This hook is invoked before Mercurial knows the identities of the +changesets to be transmitted. + +One use for this hook is to prevent changes from being transmitted to +another repository. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{source}] A string. The source of the operation that is + attempting to obtain changes from this repository (see + section~\ref{sec:hook:sources}). See the documentation for the + \texttt{source} parameter to the \hook{outgoing} hook, in + section~\ref{sec:hook:outgoing}, for possible values of this + parameter. +\item[\texttt{url}] A URL. The location of the remote repository, if + known. See section~\ref{sec:hook:url} for more information. +\end{itemize} + +See also: \hook{outgoing} (section~\ref{sec:hook:outgoing}) + +%\subsection{\hook{pretag}---before tagging a changeset} +\subsection{\hook{pretag}---$B%A%'%s%8%;%C%H$K%?%0$r$D$1$kA0$K(B} +\label{sec:hook:pretag} + +This controlling hook is run before a tag is created. If the hook +succeeds, creation of the tag proceeds. If the hook fails, the tag is +not created. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{local}] A boolean. Whether the tag is local to this + repository instance (i.e.~stored in \sfilename{.hg/localtags}) or + managed by Mercurial (stored in \sfilename{.hgtags}). +\item[\texttt{node}] A changeset ID. The ID of the changeset to be tagged. +\item[\texttt{tag}] A string. The name of the tag to be created. +\end{itemize} + +If the tag to be created is revision-controlled, the \hook{precommit} +and \hook{pretxncommit} hooks (sections~\ref{sec:hook:commit} +and~\ref{sec:hook:pretxncommit}) will also be run. + +See also: \hook{tag} (section~\ref{sec:hook:tag}) + +%\subsection{\hook{pretxnchangegroup}---before completing addition of +%remote changesets} +\subsection{\hook{pretxnchangegroup}---$B%j%b!<%H%A%'%s%8%;%C%H$NDI2C$r40(B + $BN;$9$kA0$K(B} +\label{sec:hook:pretxnchangegroup} + +This controlling hook is run before a transaction---that manages the +addition of a group of new changesets from outside the +repository---completes. If the hook succeeds, the transaction +completes, and all of the changesets become permanent within this +repository. If the hook fails, the transaction is rolled back, and +the data for the changesets is erased. + +This hook can access the metadata associated with the almost-added +changesets, but it should not do anything permanent with this data. +It must also not modify the working directory. + +While this hook is running, if other Mercurial processes access this +repository, they will be able to see the almost-added changesets as if +they are permanent. This may lead to race conditions if you do not +take steps to avoid them. + +This hook can be used to automatically vet a group of changesets. If +the hook fails, all of the changesets are ``rejected'' when the +transaction rolls back. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{node}] A changeset ID. The changeset ID of the first + changeset in the group that was added. All changesets between this + and \index{tags!\texttt{tip}}\texttt{tip}, inclusive, were added by + a single \hgcmd{pull}, \hgcmd{push} or \hgcmd{unbundle}. +\item[\texttt{source}] A string. The source of these changes. See + section~\ref{sec:hook:sources} for details. +\item[\texttt{url}] A URL. The location of the remote repository, if + known. See section~\ref{sec:hook:url} for more information. +\end{itemize} + +See also: \hook{changegroup} (section~\ref{sec:hook:changegroup}), +\hook{incoming} (section~\ref{sec:hook:incoming}), +\hook{prechangegroup} (section~\ref{sec:hook:prechangegroup}) + +%\subsection{\hook{pretxncommit}---before completing commit of new +%changeset} +\subsection{\hook{pretxncommit}---$B?7$7$$%A%'%s%8%;%C%H$N%3%_%C%H$r40N;$9(B + $B$kA0$K(B} +\label{sec:hook:pretxncommit} + +This controlling hook is run before a transaction---that manages a new +commit---completes. If the hook succeeds, the transaction completes +and the changeset becomes permanent within this repository. If the +hook fails, the transaction is rolled back, and the commit data is +erased. + +This hook can access the metadata associated with the almost-new +changeset, but it should not do anything permanent with this data. It +must also not modify the working directory. + +While this hook is running, if other Mercurial processes access this +repository, they will be able to see the almost-new changeset as if it +is permanent. This may lead to race conditions if you do not take +steps to avoid them. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{node}] A changeset ID. The changeset ID of the newly + committed changeset. +\item[\texttt{parent1}] A changeset ID. The changeset ID of the first + parent of the newly committed changeset. +\item[\texttt{parent2}] A changeset ID. The changeset ID of the second + parent of the newly committed changeset. +\end{itemize} + +See also: \hook{precommit} (section~\ref{sec:hook:precommit}) + +%\subsection{\hook{preupdate}---before updating or merging working +%directory} +\subsection{\hook{preupdate}---$B%o!<%-%s%0%G%#%l%/%H%j$N%"%C%W%G!<%H$^$?(B + $B$O%^!<%8$NA0$K(B} +\label{sec:hook:preupdate} + +This controlling hook is run before an update or merge of the working +directory begins. It is run only if Mercurial's normal pre-update +checks determine that the update or merge can proceed. If the hook +succeeds, the update or merge may proceed; if it fails, the update or +merge does not start. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{parent1}] A changeset ID. The ID of the parent that the + working directory is to be updated to. If the working directory is + being merged, it will not change this parent. +\item[\texttt{parent2}] A changeset ID. Only set if the working + directory is being merged. The ID of the revision that the working + directory is being merged with. +\end{itemize} + +See also: \hook{update} (section~\ref{sec:hook:update}) + +%\subsection{\hook{tag}---after tagging a changeset} +\subsection{\hook{tag}---$B%A%'%s%8%;%C%H$K%?%0IU$1$7$?8e$K(B} +\label{sec:hook:tag} + +This hook is run after a tag has been created. + +Parameters to this hook: +\begin{itemize} +\item[\texttt{local}] A boolean. Whether the new tag is local to this + repository instance (i.e.~stored in \sfilename{.hg/localtags}) or + managed by Mercurial (stored in \sfilename{.hgtags}). +\item[\texttt{node}] A changeset ID. The ID of the changeset that was + tagged. +\item[\texttt{tag}] A string. The name of the tag that was created. +\end{itemize} + +If the created tag is revision-controlled, the \hook{commit} hook +(section~\ref{sec:hook:commit}) is run before this hook. + +See also: \hook{pretag} (section~\ref{sec:hook:pretag}) + +%\subsection{\hook{update}---after updating or merging working +%directory} +\subsection{\hook{update}---$B%o!<%-%s%0%G%#%l%/%H%j$r99?7$^$?$O%^!<%8$7$?(B + $B8e$K(B} +\label{sec:hook:update} + +This hook is run after an update or merge of the working directory +completes. Since a merge can fail (if the external \command{hgmerge} +command fails to resolve conflicts in a file), this hook communicates +whether the update or merge completed cleanly. + +\begin{itemize} +\item[\texttt{error}] A boolean. Indicates whether the update or + merge completed successfully. +\item[\texttt{parent1}] A changeset ID. The ID of the parent that the + working directory was updated to. If the working directory was + merged, it will not have changed this parent. +\item[\texttt{parent2}] A changeset ID. Only set if the working + directory was merged. The ID of the revision that the working + directory was merged with. +\end{itemize} + +See also: \hook{preupdate} (section~\ref{sec:hook:preupdate}) + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/htlatex.book Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,16 @@ +#!/bin/bash +# +# This script is horrible. It's essentially a hacked copy of +# /usr/bin/htlatex from Fedora Core 6. I apologise for any lasting +# pain reading it causes. + +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 + +(cd $4 && bibtex hgbook) +(cd $4 && makeindex hgbook) + +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 + +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 + +echo status $$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/intro.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1011 @@ +%\chapter{Introduction} +\chapter{$BF3F~(B} +\label{chap:intro} + +%\section{About revision control} +\section{$B%j%S%8%g%s%3%s%H%m!<%k(B} + +%Revision control is the process of managing multiple versions of a +%piece of information. In its simplest form, this is something that +%many people do by hand: every time you modify a file, save it under a +%new name that contains a number, each one higher than the number of +%the preceding version. + +$B%j%S%8%g%s%3%s%H%m!<%k$H$O!$J#?t$N%P!<%8%g%s$N>pJs$r$r4IM}$9$k%W%m%;%9$G(B +$B$"$k!%:G$bC1=c$JJ}K!$O!$%U%!%$%k$rJQ99$7$?$i!$$=$l$^$G$N%P!<%8%g%s$h$j$b(B +$BBg$-$J?t;z$r4^$`?7$?$JL>A0$G%;!<%V$r9T$&$J$I$NJ}K!$GA4$F<j$G9T$&$3$H$G$"(B +$B$k!%(B + +%Manually managing multiple versions of even a single file is an +%error-prone task, though, so software tools to help automate this +%process have long been available. The earliest automated revision +%control tools were intended to help a single user to manage revisions +%of a single file. Over the past few decades, the scope of revision +%control tools has expanded greatly; they now manage multiple files, +%and help multiple people to work together. The best modern revision +%control tools have no problem coping with thousands of people working +%together on projects that consist of hundreds of thousands of files. + +$B$?$C$?0l$D$N%U%!%$%k$KBP$7$F$b!$J#?t$N%P!<%8%g%s$r<j$G4IM}$9$k$3$H$O4V0c(B +$B$$$r5/$3$70W$$:n6H$G!$$3$N%W%m%;%9$r<+F02=$9$k%=%U%H%&%'%"%D!<%k$,$+$J$j(B +$B$N@N$+$iDs6!$5$l$F$-$?!%:G=i$N<+F02=$5$l$?%j%S%8%g%s%3%s%H%m!<%k%D!<%k(B +$B$O!$0l?M$N%f!<%6$rBP>]$H$7$F!$(B1$B$D$N%U%!%$%k$N%j%S%8%g%s$r4IM}$9$k$?$a$K:n(B +$B$i$l$?!%?t==G/$,7P$A!$%j%S%8%g%s%3%s%H%m!<%k$N<h$j07$&%9%3!<%W$OBg$$$K3H(B +$BBg$7$?!%:#$G$OJ#?t?M$K$h$kJ#?t%U%!%$%k$NJT=8$r$b4IM}$9$k$3$H$,$G$-$k!%8=(B +$BBe$N:G9b$N%j%S%8%g%s4IM}%D!<%k$O?t@i?M$K$h$k!$?t==K|8D$N%U%!%$%k$rMJ$9$k(B +$B%W%m%8%'%/%H$K$bBP1~$9$k!%(B + +%\subsection{Why use revision control?} +\subsection{$B$J$<%j%S%8%g%s%3%s%H%m!<%k$r;H$&$N$+(B?} + +%There are a number of reasons why you or your team might want to use +%an automated revision control tool for a project. +$B%W%m%8%'%/%H$N$?$a$K<+F02=$5$l$?%j%S%8%g%s%3%s%H%m!<%k%D!<%k$r;H$*$&$H9M(B +$B$($kM}M3$O?tB?$/$"$k!%(B +\begin{itemize} +%\item It will track the history and evolution of your project, so you +% don't have to. For every change, you'll have a log of \emph{who} +% made it; \emph{why} they made it; \emph{when} they made it; and +% \emph{what} the change was. + \item $B%j%S%8%g%s4IM}%D!<%k$O!$%W%m%8%'%/%H$NMzNr$H?J2=$r5-O?$9$k$?$a!$<+(B + $BJ,<+?H$G5-O?$9$kI,MW$,$J$$!%A4$F$NJQ99$KBP$7$F(B\emph{$BC/$,(B}\emph{$B2?(B + $B$N$?$a$K(B}\emph{$B$$$D(B}\emph{$B2?$r(B}$BJQ99$7$?$N$+$,5-O?$5$l$k!%(B +%\item When you're working with other people, revision control software +% makes it easier for you to collaborate. For example, when people +% more or less simultaneously make potentially incompatible changes, +% the software will help you to identify and resolve those conflicts. + \item $BB>$N?M$H:n6H$7$F$$$k;~!$%j%S%8%g%s%3%s%H%m!<%k%=%U%H%&%'%"$O6&F1(B + $B:n6H$r=u$1$k!%Nc$($P!$?M!9$,F1;~$K8_49@-$N$J$$JQ99$r9T$C$?>l9g!$(B + $B%=%U%H%&%'%"$O%3%s%U%j%/%H$rFCDj$7!$2D7h$9$k$3$H$r=u$1$k!%(B +%\item It can help you to recover from mistakes. If you make a change +% that later turns out to be in error, you can revert to an earlier +% version of one or more files. In fact, a \emph{really} good +% revision control tool will even help you to efficiently figure out +% exactly when a problem was introduced (see +% section~\ref{sec:undo:bisect} for details). + \item $B%j%S%8%g%s4IM}%D!<%k$OHH$7$?%_%9$+$i$N2sI|$r=u$1$k!%2C$($?JQ99$,8e(B +$B$G4V0c$$$G$"$C$?$HJ,$+$C$?;~!$(B1$B$D$^$?$OJ#?t$N%U%!%$%k$X$NJQ99$rGK4~$9$k$3(B +$B$H$,$G$-$k!%<B:]$N$H$3$m!$(B\emph{$B??$K(B}$BM%$l$?%j%S%8%g%s%3%s%H%m!<%k%D!<%k$O(B +$BJ6$l9~$s$@LdBj$rFCDj$9$k$N$r;Y1g$9$k5!G=$r;}$D!%!J>\:Y$K$D$$$F(B +$B$O(B~\ref{sec:undo:bisect}$B@a$r;2>H!%!K(B +%\item It will help you to work simultaneously on, and manage the drift +% between, multiple versions of your project. + \item $B%j%S%8%g%s4IM}%D!<%k$O!$%W%m%8%'%/%H$NJ#?t$N%P!<%8%g%s$G$NF1;~:n(B + $B6H$d!$%j%S%8%g%s4V$N0\9T$r;Y1g$9$k!%(B +\end{itemize} +%Most of these reasons are equally valid---at least in theory---whether +%you're working on a project by yourself, or with a hundred other +%people. +$B$3$l$i$NM}M3$NB?$/$O<+J,<+?H$N%W%m%8%'%/%H$G:n6H$7$F$$$F$b!$(B100$B?M$N6&F1:n(B +$B6H<T$H:n6H$7$F$$$F$b>/$J$/$H$bM}O@E*$K$OEy$7$/M-0U$G$"$k!%(B + +%A key question about the practicality of revision control at these two +%different scales (``lone hacker'' and ``huge team'') is how its +%\emph{benefits} compare to its \emph{costs}. A revision control tool +%that's difficult to understand or use is going to impose a high cost. + +$B%j%S%8%g%s%3%s%H%m!<%k$N<BMQ@-$K4X$9$k80$K$J$k<ALd$O!$$3$l$i$N(B2$B$D$N0[$J$C(B +$B$?%9%1!<%k!J(B``$B0l?M$N%O%C%+!<(B''$B%l%Y%k$+$i(B``$BBg5,LO%A!<%`(B''$B%l%Y%k$^$G!K$K$*(B +$B$$$F!$%3%9%H$KBP$7$F$I$l$@$1Mx1W$,$"$k$N$+$H$$$&$3$H$G$"$k!%M}2r$d;HMQ$,(B +$B:$Fq$J%j%S%8%g%s%3%s%H%m!<%k%D!<%k$O9b$$%3%9%H$r2!$7$D$1$k!%(B + +%A five-hundred-person project is likely to collapse under its own +%weight almost immediately without a revision control tool and process. +%In this case, the cost of using revision control might hardly seem +%worth considering, since \emph{without} it, failure is almost +%guaranteed. + +500$B?M$+$i$J$k%W%m%8%'%/%H$G$O!$%j%S%8%g%s%3%s%H%m!<%k%D!<%k$J$7$G$OKX$s$I(B +$BN)$A9T$+$J$$!%$3$N>l9g!$%j%S%8%g%s%3%s%H%m!<%k$J$7$G$O<:GT$9$k$3$H$,KX$s(B +$B$IL@Gr$J$?$a!$%j%S%8%g%s%3%s%H%m!<%k$r9T$&%3%9%H$rJ'$&$3$H$OFC$KLdBj$H$O(B +$B$J$i$J$$!%(B%xxx + +%On the other hand, a one-person ``quick hack'' might seem like a poor +%place to use a revision control tool, because surely the cost of using +%one must be close to the overall cost of the project. Right? + +$B0lJ}!$(B1$B?M$N3+H/<T$K$h$k(B``$B%/%$%C%/%O%C%/(B''$B$O%j%S%8%g%s%3%s%H%m!<%k%D!<%k(B +$B$r;H$&$K$O$"$^$j$U$5$o$7$/$J$$!%$J$<$J$i!$%D!<%k$r;H$&%3%9%H$,$[$\%W%m%8%'(B +$B%/%H$N%3%9%H$=$N$b$N$G$"$k$+$i$@!%$3$l$O@5$7$$$@$m$&$+!)(B + +%Mercurial uniquely supports \emph{both} of these scales of +%development. You can learn the basics in just a few minutes, and due +%to its low overhead, you can apply revision control to the smallest of +%projects with ease. Its simplicity means you won't have a lot of +%abstruse concepts or command sequences competing for mental space with +%whatever you're \emph{really} trying to do. At the same time, +%Mercurial's high performance and peer-to-peer nature let you scale +%painlessly to handle large projects. + +Mercurial$B$O$3$l$i$N3+H/%9%1!<%k$NN>J}$r%5%]!<%H$7$F$$$k!%4pACE*$J;HMQK!$O(B +$B?tJ,$G3X$V$3$H$,$G$-!$%j%S%8%g%s%3%s%H%m!<%k$r:G>.5,LO$N%W%m%8%'%/%H$K4J(B +$BC1$K<h$jF~$l$k$3$H$,$G$-$k!%C1=c$G$"$k$?$a!$Fq2r$J%3%s%;%W%H$d%3%^%s%I%7!<(B +$B%1%s%9$K0U<1$NB?$/$r@j$a$i$l!$K\Ev$K$d$j$?$$$3$H$,AB$+$K$J$k$3$H$b$J$$!%(B +$B$^$?F1;~$K(BMercurial$B$N@-G=$N9b$5$d!$%T%"%D!<%T%"$N@-<A$N$?$a$K!$Bg5,LO%W%m(B +$B%8%'%/%H$K$b6lO+$9$k;v$J$/%9%1!<%k$9$k$3$H$,$G$-$k!%(B + +%No revision control tool can rescue a poorly run project, but a good +%choice of tools can make a huge difference to the fluidity with which +%you can work on a project. + +$B$*AFKv$J%W%m%8%'%/%H$r5_:Q$9$k$h$&$J%j%S%8%g%s%3%s%H%m!<%k$OB8:_$7$J$$(B +$B$,!$NI$$%D!<%k$NA*Br$O!$:n6H$9$k%W%m%8%'%/%H$N7x<B$5$KBg$-$J:9$r$b$?$i$9!%(B + +%\subsection{The many names of revision control} +\subsection{$BMM!9$J%j%S%8%g%s%3%s%H%m!<%k(B} + +%Revision control is a diverse field, so much so that it doesn't +%actually have a single name or acronym. Here are a few of the more +%common names and acronyms you'll encounter: +$B%j%S%8%g%s%3%s%H%m!<%k$OBg$-$JI}$r$b$DJ,Ln$G$"$j!$$=$N$?$aB?$/$N8F$SL>$H(B +$B$=$NC;=L7A$,CN$i$l$F$$$k!'(B +\begin{itemize} +\item $B%j%S%8%g%s%3%s%H%m!<%k(B (Revision control (RCS)) +\item $B%=%U%H%&%'%"@_Dj%^%M%8%a%s%H$^$?$O@_Dj%^%M%8%a%s%H(B (Software configuration management (SCM), or configuration management) +\item $B%=!<%9%3!<%I%^%M%8%a%s%H(B (Source code management) +\item $B%=!<%9%3!<%I%3%s%H%m!<%k$^$?$O%=!<%9%3%s%H%m!<%k(B (Source code control, or source control) +\item $B%P!<%8%g%s%3%s%H%m!<%k(B (Version control (VCS)) +\end{itemize} +%Some people claim that these terms actually have different meanings, +%but in practice they overlap so much that there's no agreed or even +%useful way to tease them apart. +$B$3$l$i$NMQ8l$O3F!90c$&0UL#$r;}$D$N$@$H<gD%$9$k?M!9$b$$$k!%$7$+$7<B<AE*$K(B +$B$O$3$l$i$O8_$$$KBg$-$/=E$J$C$F$*$j!$$o$6$o$66hJL$9$k$3$H$O0lHLE*$G$J$/!$(B +$B$^$?M-MQ$G$b$J$$!%(B + +%\section{A short history of revision control} +\section{$B%j%S%8%g%s%3%s%H%m!<%k$NNr;K(B} + +%The best known of the old-time revision control tools is SCCS (Source +%Code Control System), which Marc Rochkind wrote at Bell Labs, in the +%early 1970s. SCCS operated on individual files, and required every +%person working on a project to have access to a shared workspace on a +%single system. Only one person could modify a file at any time; +%arbitration for access to files was via locks. It was common for +%people to lock files, and later forget to unlock them, preventing +%anyone else from modifying those files without the help of an +%administrator. + +$B:G$bCN$i$l$F$$$k8E$$%j%S%8%g%s%3%s%H%m!<%k%D!<%k$O!$(BMarc Rochkind$B$,(B1970$BG/(B +$BBe=iF,$K(BBell$B8&5f=j$G=q$$$?(BSCCS (Source Code Control System)$B$G$"$k!%(B SCCS +$B$O8D!9$N%U%!%$%k$KBP$7$FF0:n$7!$%W%m%8%'%/%H$N6&F1:n6H<T$K$OF10l%^%7%s>e(B +$B$N6&M-%o!<%/%9%Z!<%9$X$N%"%/%;%9$,I,MW$G$"$C$?!%%U%!%$%k$X$N%"%/%;%9$ND4(B +$BDd$O%m%C%/$K$h$C$F9T$o$l!$$"$k%U%!%$%k$rJQ99$G$-$k$N$O>o$K0l?M$N%f!<%6$@(B +$B$1$G$"$C$?!%%U%!%$%k$r%m%C%/$7$?8e!$%m%C%/$N2r=|$rK:$l$k$3$H$OF|>oE*$K$"(B +$B$j!$$3$&$J$k$H4IM}<T$N=u$1$J$7$KB>$N3+H/<T$,%U%!%$%k$rJQ99$9$k$3$H$O$G$-(B +$B$J$+$C$?!%(B + +%Walter Tichy developed a free alternative to SCCS in the early 1980s; +%he called his program RCS (Revison Control System). Like SCCS, RCS +%required developers to work in a single shared workspace, and to lock +%files to prevent multiple people from modifying them simultaneously. + +Walter Tichy$B$O!$(B1980$BG/Be=iF,$K(BSCCS$B$NBeBX$H$J$k%U%j!<$N%P!<%8%g%s%3%s%H%m!<(B +$B%k%D!<%k$r3+H/$7$?!%H`$O<+$i$N%7%9%F%`$r(BRCS (Revison Control System)$B$H8F(B +$B$s$@!%(BSCCS$BF1MM!$(BRCS$B$O3+H/<T$?$A$KC10l$N6&M-%o!<%/%9%Z!<%9$H!$%U%!%$%k$rF1(B +$B;~$KJ#?t?M$,JQ99$9$k$3$H$N$J$$$h$&$K%m%C%/$rMW5a$7$?!%(B + +%Later in the 1980s, Dick Grune used RCS as a building block for a set +%of shell scripts he initially called cmt, but then renamed to CVS +%(Concurrent Versions System). The big innovation of CVS was that it +%let developers work simultaneously and somewhat independently in their +%own personal workspaces. The personal workspaces prevented developers +%from stepping on each other's toes all the time, as was common with +%SCCS and RCS. Each developer had a copy of every project file, and +%could modify their copies independently. They had to merge their +%edits prior to committing changes to the central repository. + +1980$BG/Be8eH>$K(BDick Grune$B$O(BRCS$B$r8F$S=P$9%7%'%k%9%/%j%W%H$K$h$k%P!<%8%g%s4I(B +$BM}%7%9%F%`$r:n$C$?!%=i4|$K(Bcmt$B$H8F$P$l$?$3$N%7%9%F%`$O!$8e$K(BCVS +(Concurrent Versions System)$B$H2~L>$5$l$?!%(B CVS$B$NBg$-$J3W?7$O!$3+H/<TC#$K(B +$BF1;~$K8DJL$N%o!<%/%9%Z!<%9$G:n6H$9$k$3$H$r5v$7$?$3$H$G$"$k!%%o!<%/%9%Z!<(B +$B%9$r8DJL$K$7$?$3$H$G!$3+H/<T$O(BSCCS$B$d(BRCS$B$GNI$/$"$C$?$h$&$K!$B>$N3+H/<T$N:n(B +$B6H$rK8$2$k$3$H$,$J$/$J$C$?!%$3$N%b%G%k$G$O!$Cf1{$N%j%]%8%H%j$KJQ99$r%3%_%C(B +$B%H$9$kA0$K!$JQ997k2L$r%^!<%8$9$kI,MW$,$"$C$?!%(B + +%Brian Berliner took Grune's original scripts and rewrote them in~C, +%releasing in 1989 the code that has since developed into the modern +%version of CVS. CVS subsequently acquired the ability to operate over +%a network connection, giving it a client/server architecture. CVS's +%architecture is centralised; only the server has a copy of the history +%of the project. Client workspaces just contain copies of recent +%versions of the project's files, and a little metadata to tell them +%where the server is. CVS has been enormously successful; it is +%probably the world's most widely used revision control system. + +Brian Berliner$B$O(BGrune$B$N%*%j%8%J%k%9%/%j%W%H$r<u$17Q$$$G!$$=$l$r(BC$B$G=q$-D>(B +$B$7!$8=:_$N(BCVS$B$X$H7R$,$k%3!<%I$r(B1989$BG/$K%j%j!<%9$7$?!%$=$N8e!$(BCVS$B$O%M%C%H(B +$B%o!<%/$r7PM3$7$?F0:n$d!$%/%i%$%"%s%H%5!<%P%"!<%-%F%/%A%c$rHw$($F$$$C(B +$B$?!%(BCVS$B$N%"!<%-%F%/%A%c$OCf1{=8Cf7?$G!$%5!<%P$N$_$,%W%m%8%'%/%H$NMzNr$rJ](B +$BB8$9$k!%%/%i%$%"%s%H$N%o!<%/%9%Z!<%9$O%W%m%8%'%/%H$N:G?7%P!<%8%g%s$N%U%!(B +$B%$%k$N%3%T!<$G$"$j!$%5!<%P$N=j:_$r<($96O$+$J%a%?%G!<%?$,IU2C$5$l$F$$$?!%(B +CVS$B$OBg@.8y$r<}$a!$$*$=$i$/@$3&$G:G$b9-$/MQ$$$i$l$?%j%S%8%g%s%3%s%H%m!<%k(B +$B%7%9%F%`$H$J$C$?!%(B + +%In the early 1990s, Sun Microsystems developed an early distributed +%revision control system, called TeamWare. A TeamWare workspace +%contains a complete copy of the project's history. TeamWare has no +%notion of a central repository. (CVS relied upon RCS for its history +%storage; TeamWare used SCCS.) + +1990$BG/Be=iF,!$(BSun Microsystems$B$O(BTeamWare$B$H8F$P$l$k=i4|$NJ,;6%j%S%8%g%s%3(B +$B%s%H%m!<%k%7%9%F%`$r3+H/$7$?!%(BTeamWare$B%o!<%/%9%Z!<%9$O%W%m%8%'%/%H$NMzNr(B +$B$N40A4$J%3%T!<$r;}$C$F$$$?!%(BTeamWare$B$K$OCf1{%j%]%8%H%j$H$$$&35G0$O$J$+$C(B +$B$?!%!J(BCVS$B$,MzNr$N5-O?$K(BRCS$B$r;H$C$F$$$?$h$&$K!$(BTeamWare$B$O(BSCCS$B$rMQ$$$F$$(B +$B$?!%!K(B + +%As the 1990s progressed, awareness grew of a number of problems with +%CVS. It records simultaneous changes to multiple files individually, +%instead of grouping them together as a single logically atomic +%operation. It does not manage its file hierarchy well; it is easy to +%make a mess of a repository by renaming files and directories. Worse, +%its source code is difficult to read and maintain, which made the +%``pain level'' of fixing these architectural problems prohibitive. + +1990$BG/BeCf:"$K$J$k$H!$(BCVS$B$NLdBj$,9-$/CN$i$l$k$h$&$K$J$C$F$-$?!%(B CVS$B$O0lEY(B +$B$KJ#?t$N%U%!%$%k$KBP$7$F9T$o$l$kJQ99$rO@M}E*$K%"%H%_%C%/$JA`:n$H$7$F%0%k!<(B +$B%W2=$9$k$N$G$O$J$/!$%U%!%$%kKh$K8DJL$K5-O?$7$F$$$?!%(BCVS$B$N%U%!%$%k%R%(%i%k(B +$B%-!<$N4IM}$OIT==J,$G!$%U%!%$%k$d%G%#%l%/%H%j$r%j%M!<%`$9$k$H4JC1$K%j%]%8(B +$B%H%j$,:.Mp$7$?!%$5$i$K0-$$$3$H$K!$(BCVS$B$N%=!<%9%3!<%I$OFI$_$K$/$/!$%a%s%F%J(B +$B%s%9$bFq$7$+$C$?$?$a!$%"!<%-%F%/%A%c$NLdBj$r2r7h$9$k$N$OIT2DG=$J%l%Y%k$H(B +$B8@$($?!%(B + +%In 2001, Jim Blandy and Karl Fogel, two developers who had worked on +%CVS, started a project to replace it with a tool that would have a +%better architecture and cleaner code. The result, Subversion, does +%not stray from CVS's centralised client/server model, but it adds +%multi-file atomic commits, better namespace management, and a number +%of other features that make it a generally better tool than CVS. +%Since its initial release, it has rapidly grown in popularity. + +2001$BG/!$(BCVS$B$r3+H/$7$F$$$?(BJim Blandy$B$H(BKarl Fogel$B$N(B2$B?M$N3+H/<T$,(BCVS$B$rCV$-49(B +$B$($k!$$h$jM%$l$?%"!<%-%F%/%A%c$H4qNo$J%3!<%I$r;}$D%D!<%k$N%W%m%8%'%/%H$r(B +$B;O$a$?!%$=$N@.2LJ*$G$"$k(BSubversion$B$O(BCVS$B$N=8Cf7?%/%i%$%"%s%H%5!<%P%b%G%k$r(B +$B2~$a$k$3$H$O$7$J$+$C$?$,!$J#?t%U%!%$%k$N%"%H%_%C%/$J%3%_%C%H$rDI2C$7!$L>(B +$BA06u4V$N4IM}$b2~NI$7$F$$$?!%$^$?(BCVS$B$h$j$bM%$l$??tB?$/$N5!G=$bDI2C$5$l$?!%(B +Subversion$B$O:G=i$N%j%j!<%9$+$i5^B.$K?M5$$r3MF@$7$F$$$C$?!%(B + +%More or less simultaneously, Graydon Hoare began working on an +%ambitious distributed revision control system that he named Monotone. +%While Monotone addresses many of CVS's design flaws and has a +%peer-to-peer architecture, it goes beyond earlier (and subsequent) +%revision control tools in a number of innovative ways. It uses +%cryptographic hashes as identifiers, and has an integral notion of +%``trust'' for code from different sources. + +$B$[$\;~$rF1$8$/$7$F!$(BGraydon Hoare$B$O(BMonotone$B$H8F$P$l$kLn?4E*$JJ,;6%j%S%8%g(B +$B%s%3%s%H%m!<%k%7%9%F%`$N3+H/$r;O$a$?!%(BMonotone$B$O(BCVS$B$N?tB?$/$N@_7W>e$N`laS(B +$B$r=$@5$7!$%T%"%D!<%T%"%"!<%-%F%/%A%c$r;}$C$F$$$k!%(B Monotone$B$O=i4|$N!J$"$k(B +$B$$$O8eB3$N!K%j%S%8%g%s%3%s%H%m!<%k%D!<%k$h$j$b@h?JE*$J5!G=$r;}$C$F$$(B +$B$k!%(BMonotone$B$O0E9f2=$5$l$?%O%C%7%e$r<1JL;R$H$7$F;HMQ$7!$MM!9$J=P=h$N%3!<(B +$B%I$KBP$7$F(B``$B?.Mj@-(B''$B$N35G0$r;}$C$F$$$?!%(B + +%Mercurial began life in 2005. While a few aspects of its design are +%influenced by Monotone, Mercurial focuses on ease of use, high +%performance, and scalability to very large projects. + +Mercurial$B$O(B2005$BG/$KCB@8$7$?!%%G%6%$%s$N$$$/$D$+$NLL$O(BMonotone$B$K1F6A$r<u$1(B +$B$F$$$k$,!$(BMercurial$B$O;H$$$d$9$5!$9b@-G=!$Bg5,LO%W%m%8%'%/%H$X$N%9%1!<%i%S(B +$B%j%F%#$K%U%)!<%+%9$7$F$$$k!%(B + +%\section{Trends in revision control} +\section{$B%j%S%8%g%s%3%s%H%m!<%k$N%H%l%s%I(B} + +%There has been an unmistakable trend in the development and use of +%revision control tools over the past four decades, as people have +%become familiar with the capabilities of their tools and constrained +%by their limitations. + +$B%j%S%8%g%s%3%s%H%m!<%k%D!<%k$N3+H/$H;HMQ$K$*$$$F!$2a5n(B20$BG/4V%D!<%k$K?F$7(B +$B$_!$%D!<%k$N@)8B$rCN$k$K=>$C$F!$J6$l$b$J$$%H%l%s%I$,B8:_$7$F$$$k!%(B + +%The first generation began by managing single files on individual +%computers. Although these tools represented a huge advance over +%ad-hoc manual revision control, their locking model and reliance on a +%single computer limited them to small, tightly-knit teams. + +$BBh0l@$Be$N%D!<%k$OC10l$N%U%!%$%k$r8DJL$N%3%s%T%e!<%?$N>e$G4IM}$7$?!%%"%I(B +$B%[%C%/$J<jF0$K$h$k%j%S%8%g%s%3%s%H%m!<%k$HHf$Y$FBgI}$J?JJb$,$"$C$?$,!$%m%C(B +$B%/%b%G%k$HC10l%3%s%T%e!<%?$X$N0MB8$N$?$a!$MxMQ$O>.5,LO$G6[L)$J%A!<%`$K8B(B +$B$i$l$?!%(B + +%The second generation loosened these constraints by moving to +%network-centered architectures, and managing entire projects at a +%time. As projects grew larger, they ran into new problems. With +%clients needing to talk to servers very frequently, server scaling +%became an issue for large projects. An unreliable network connection +%could prevent remote users from being able to talk to the server at +%all. As open source projects started making read-only access +%available anonymously to anyone, people without commit privileges +%found that they could not use the tools to interact with a project in +%a natural way, as they could not record their changes. + +$BBhFs@$Be$N%D!<%k$O!$%M%C%H%o!<%/Cf?4$N%"!<%-%F%/%A%c$K0\9T$9$k$3$H$G!$$=(B +$B$l$^$G$N@)8B$r4KOB$7!$%W%m%8%'%/%HA4BN$rF1;~$K4IM}$7$?!%%W%m%8%'%/%H$,Bg(B +$B$-$/@.D9$9$k$H!$?7$?$JLdBj$KD>LL$7$?!%%/%i%$%"%s%H$,%5!<%P$KIQHK$KDL?.$9(B +$B$k$?$a!$Bg5,LO%W%m%8%'%/%H$G$O%5!<%P$N5,LO$,LdBj$K$J$C$?!%?.Mj@-$N$J$$%M%C(B +$B%H%o!<%/@\B3$O%j%b!<%H%f!<%6$,%5!<%P$HDL?.$9$k$N$rK8$2$?!%%*!<%W%s%=!<%9(B +$B%W%m%8%'%/%H$,%3%_%C%H8"$N$J$$%f!<%6$K$bF?L>$NFI$_=P$7@lMQ%"%/%;%9$rDs6!(B +$B$9$k$h$&$K$J$k$H!$%D!<%k$OH`$i$N9T$C$?JQ99$r5-O?$G$-$J$$$?$a!$%W%m%8%'%/(B +$B%H$H$d$j$H$j$r9T$&<+A3$J<jCJ$H$O8@$($J$$$3$H$,$o$+$C$?!%(B + +%The current generation of revision control tools is peer-to-peer in +%nature. All of these systems have dropped the dependency on a single +%central server, and allow people to distribute their revision control +%data to where it's actually needed. Collaboration over the Internet +%has moved from constrained by technology to a matter of choice and +%consensus. Modern tools can operate offline indefinitely and +%autonomously, with a network connection only needed when syncing +%changes with another repository. + +$B8=9T@$Be$N%j%S%8%g%s%3%s%H%m!<%k%D!<%k$O!$%T%"%D!<%T%"$G$"$k!%$3$l$i$N%7(B +$B%9%F%`$NA4$F$,C10l$NCf1{%5!<%P$X0MB8$7$J$/$J$C$F$*$j!$%j%S%8%g%s%3%s%H%m!<(B +$B%k%G!<%?$rI,MW$J$H$3$m$XJ,;6$5$;$k$3$H$,$G$-$k$h$&$K$J$C$F$$$k!%%$%s%?!<(B +$B%M%C%H$rDL$8$?6&F1:n6H$O5;=QE*@)Ls$+$iN%$l$F!$A*Br$H9g0U$K$h$C$F9T$o$l$k(B +$B$h$&$K$J$C$?!%8=Be$N%D!<%k$O%*%U%i%$%s$N$^$^$G$b!$<+N'E*$K$bF0:n$9$k$h$&(B +$B$K$J$C$F$$$k!%%M%C%H%o!<%/@\B3$OJQ99$rJL$N%j%]%8%H%j$HF14|$5$;$k;~$K$N$_(B +$BI,MW$G$"$k!%(B + +%\section{A few of the advantages of distributed revision control} +\section{$BJ,;6%j%S%8%g%s%3%s%H%m!<%k$NMxE@(B} + +%Even though distributed revision control tools have for several years +%been as robust and usable as their previous-generation counterparts, +%people using older tools have not yet necessarily woken up to their +%advantages. There are a number of ways in which distributed tools +%shine relative to centralised ones. + +$BJ,;6%j%S%8%g%s%3%s%H%m!<%k%D!<%k$O$b$&?tG/$bA0$+$iA0@$Be$N%D!<%k$HF1MM$K(B +$B7xO4$+$DM-MQ$J$b$N$HG'$a$i$l$F$$$k$K$b$+$+$o$i$:!$8E$$%D!<%k$N%f!<%6$?$A(B +$B$O$=$NMxE@$rCN$i$J$$!%J,;6%D!<%k$,Cf1{=8Cf%D!<%k$h$j$bM%$l$$$F$$$kE@$OB?!9(B +$B$"$k!%(B + +%For an individual developer, distributed tools are almost always much +%faster than centralised tools. This is for a simple reason: a +%centralised tool needs to talk over the network for many common +%operations, because most metadata is stored in a single copy on the +%central server. A distributed tool stores all of its metadata +%locally. All else being equal, talking over the network adds overhead +%to a centralised tool. Don't underestimate the value of a snappy, +%responsive tool: you're going to spend a lot of time interacting with +%your revision control software. + +$B8D?M$N3+H/<T$K$H$C$F$O!$J,;6%D!<%k$O$[$H$s$I$N>l9g!$Cf1{=8Cf%D!<%k$h$j$b(B +$B9bB.$G$"$k!%$=$NM}M3$O!$Cf1{=8Cf%D!<%k$G$O$[$H$s$I$N%a%?%G!<%?$OCf1{%5!<(B +$B%P$GC10l%3%T!<$H$7$FJ]4I$5$l$F$*$j!$DL>o$N%*%Z%l!<%7%g%s$NB?$/$r%M%C%H%o!<(B +$B%/$r7PM3$7$F9T$&I,MW$,$"$k$+$i$@!%J,;6%D!<%k$OA4$F$N%a%?%G!<%?$r%m!<%+%k(B +$B$KJ]B8$9$k!%$=$NB>$bF1MM$G!$Cf1{=8Cf%D!<%k$O%M%C%H%o!<%/1[$7$NDL?.$K$h$C(B +$B$F%*!<%P%X%C%I$r@8$8$k!%3+H/Cf!$%j%S%8%g%s%3%s%H%m!<%k%=%U%H%&%'%"$NA`:n(B +$B$r4vEY$H$J$/9T$&$3$H$r9M$($l$P!$%D!<%k$N6O$+$J%*!<%P%X%C%I$G$b2a>.I>2A$9(B +$B$Y$-$G$O$J$$!%(B + +%Distributed tools are indifferent to the vagaries of your server +%infrastructure, again because they replicate metadata to so many +%locations. If you use a centralised system and your server catches +%fire, you'd better hope that your backup media are reliable, and that +%your last backup was recent and actually worked. With a distributed +%tool, you have many backups available on every contributor's computer. + +$BJ,;6%D!<%k$O%a%?%G!<%?$rMM!9$J>l=j$KJ#@=$9$k$?$a!$%5!<%P%$%s%U%i%9%H%i%/(B +$B%A%c$N>c32$K4X$o$j$J$/F0:n$9$k!%$b$7Cf1{=8Cf%7%9%F%`$r;H$C$F$$$F!$%5!<%P(B +$B$,2P:R$K$"$C$?$H$7$?$i!$?.Mj$G$-$k%P%C%/%"%C%W%a%G%#%"$K:G6a:n@.$7$?%P%C(B +$B%/%"%C%W%3%T!<$,;D$C$F$*$j!$$=$l$,$^$H$b$K5!G=$9$k$3$H$r5'$k$3$H$K$J$k!%(B +$BJ,;6%D!<%k$G$O!$6(NO<T$N%3%s%T%e!<%?$NCf$K?tB?$/$N%P%C%/%"%C%W$,;D$5$l$F(B +$B$$$k!%(B + +%The reliability of your network will affect distributed tools far less +%than it will centralised tools. You can't even use a centralised tool +%without a network connection, except for a few highly constrained +%commands. With a distributed tool, if your network connection goes +%down while you're working, you may not even notice. The only thing +%you won't be able to do is talk to repositories on other computers, +%something that is relatively rare compared with local operations. If +%you have a far-flung team of collaborators, this may be significant. + +$BJ,;6%D!<%k$G$O!$%M%C%H%o!<%/$N?.Mj@-$NM?$($k1F6A$O=8Cf%D!<%k$KHf$Y$FMZ$+(B +$B$K>.$5$$!%=8Cf%D!<%k$O!$$$$/$D$+$NBg$-$J@)8B$N$"$k%3%^%s%I$r=|$$$F%M%C%H(B +$B%o!<%/@\B3$J$7$K;HMQ$G$-$J$$!%J,;6%D!<%k$G$O:n6HCf$K%M%C%H%o!<%/@\B3$,CG(B +$B$?$l$?$H$7$F$b$=$l$K5$$E$/$3$H$9$i$J$$$@$m$&!%B>$N%3%s%T%e!<%?$N%j%]%8%H(B +$B%j$H$NDL?.$r9T$&F0:n$N$_$,1F6A$r<u$1$k!%$3$N$h$&$JF0:n$O%m!<%+%k$G$NF0:n(B +$B$h$jAjBPE*$K>/$J$$$O$:$@!%$3$l$,=EBg$JLdBj$H$J$k$N$O!$9-HO0O$K$o$?$k%A!<(B +$B%`$G:n6H$r$7$F$$$k>l9g$G$"$m$&!%(B + +%\subsection{Advantages for open source projects} +\subsection{$B%*!<%W%s%=!<%9%W%m%8%'%/%H$G$NMxE@(B} + +%If you take a shine to an open source project and decide that you +%would like to start hacking on it, and that project uses a distributed +%revision control tool, you are at once a peer with the people who +%consider themselves the ``core'' of that project. If they publish +%their repositories, you can immediately copy their project history, +%start making changes, and record your work, using the same tools in +%the same ways as insiders. By contrast, with a centralised tool, you +%must use the software in a ``read only'' mode unless someone grants +%you permission to commit changes to their central server. Until then, +%you won't be able to record changes, and your local modifications will +%be at risk of corruption any time you try to update your client's view +%of the repository. + +$B%*!<%W%s%=!<%9%W%m%8%'%/%H$,9%$-$K$J$j!$:n6H$r;O$a$h$&$H$9$k$H$-!$%W%m%8%'(B +$B%/%H$,J,;6%j%S%8%g%s%3%s%H%m!<%k%D!<%k$r;H$C$F$$$l$P!$$?$@$A$K%W%m%8%'%/(B +$B%H$N%3%"%a%s%P!<$NCg4V$H$J$k!%H`$i$,%j%]%8%H%j$r8x3+$7$F$$$l$P!$D>$A$K%W(B +$B%m%8%'%/%HMzNr$r%3%T!<$7!$JQ99$r9T$$!$FbIt$N%a%s%P!<$,;H$C$F$$$k$N$HA4$/(B +$BF1$8%D!<%k$rMQ$$$F:n6H7k2L$r5-O?$9$k$3$H$,$G$-$k!%BP>NE*$K%a%s%P!<$,Cf1{(B +$B=8Cf7?$N%D!<%k$r;H$C$F$$$k>l9g!$C/$+$,$"$J$?$KJQ99$rCf1{$N%5!<%P$K%3%_%C(B +$B%H$9$k5v2D$rM?$($J$$8B$j!$%D!<%k$r%j!<%I%*%s%j!<%b!<%I$G;HMQ$9$k$3$H$K$J(B +$B$k!%$=$l$^$G$OJQ99$r5-O?$9$k$3$H$O$G$-$:!$$"$J$?$N%m!<%+%k$JJQ99$O%j%]%8(B +$B%H%j$N%/%i%$%"%s%H%3%T!<$r99?7$9$k$?$S$KGK2u$5$l$k%j%9%/$rH<$&!%(B + +%\subsubsection{The forking non-problem} +\subsubsection{$B%U%)!<%/$7$F$bLdBj$J$7(B} + +%It has been suggested that distributed revision control tools pose +%some sort of risk to open source projects because they make it easy to +%``fork'' the development of a project. A fork happens when there are +%differences in opinion or attitude between groups of developers that +%cause them to decide that they can't work together any longer. Each +%side takes a more or less complete copy of the project's source code, +%and goes off in its own direction. + +$B%*!<%W%s%=!<%9%W%m%8%'%/%H$GJ,;6%j%S%8%g%s%3%s%H%m!<%k%D!<%k$rMQ$$$k$3$H(B +$B$O!$%W%m%8%'%/%H$N3+H/$r%U%)!<%/$5$;$k%j%9%/$,$"$k$H8@$o$l$F$$$k!%0U8+$N(B +$BAj0c$d!$3+H/<T$N%0%k!<%W4V$G$NBVEY$N0c$$$+$i!$H`$i$,$=$l0J>e6&$K:n6H$rB3(B +$B$1$k$3$H$,$G$-$J$$$H7hCG$9$k$3$H$G%U%)!<%/$O5/$3$k!%APJ}$N?X1D$O%W%m%8%'(B +$B%/%H$N%=!<%9%3!<%I$N$[$\40A4$J%3%T!<$+$i$=$l$>$l$NJ}8~$KJL$l$F$$$/!%(B + +%Sometimes the camps in a fork decide to reconcile their differences. +%With a centralised revision control system, the \emph{technical} +%process of reconciliation is painful, and has to be performed largely +%by hand. You have to decide whose revision history is going to +%``win'', and graft the other team's changes into the tree somehow. +%This usually loses some or all of one side's revision history. + +$B;~$K$O%U%)!<%/$7$??X1D$,!$8_$$$N%3!<%I$N:90[$r2r>C$9$k$3$H$b$"$k!%Cf1{=8(B +$BCf%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$G$O!$:90[$r(B\emph{$B5;=QE*$K(B}$B2r7h$9$k2aDx$K(B +$B:$Fq$rH<$$!$B?$/$N>l9g!$<jF0$G2r>C$9$kI,MW$,$"$k!%$I$N%j%S%8%g%sMzNr$r;D(B +$B$9$N$+7h$a!$$[$+$N%A!<%`$K$h$kJQ99$r%D%j!<$X$J$s$i$+$NJ}K!$G7Q$.LZ$9$kI,(B +$BMW$,$"$k!%$3$NA`:n$G$O!$DL>o!$0lJ}$N%j%S%8%g%sMzNr$N0lIt$^$?$OA4BN$r<:$&(B +$B$3$H$K$J$k!%(B + +%What distributed tools do with respect to forking is they make forking +%the \emph{only} way to develop a project. Every single change that +%you make is potentially a fork point. The great strength of this +%approach is that a distributed revision control tool has to be really +%good at \emph{merging} forks, because forks are absolutely +%fundamental: they happen all the time. + +%$BJ,;6%D!<%k$O!$%U%)!<%/$rC1$K%W%m%8%'%/%H$r?J$a$k$?$a$N0l$D$NJ}K!$H$7$F07(B +%$B$&!%$9$Y$F$NJQ99$O@x:_E*$K%U%)!<%/%]%$%s%H$K$J$j$&$k!%$3$N%"%W%m!<%A$NM%(B +%$B0LE@$O!$J,;6%j%S%8%g%s%3%s%H%m!<%k%D!<%k$O%U%)!<%/4V$N(B\emph{$B%^!<%8(B}$B$K6K$a(B +%$B$FM%$l$F$$$k$3$H$@!%%U%)!<%/$O@dBPE*$K4pACE*$J$3$H$G$"$k!'$3$l$O>o$K5/$3(B +%$B$k!%(B + +$BJ,;6%D!<%k$O!$%U%)!<%/$r%W%m%8%'%/%H$r?J$a$k$?$a$N0l$D$NJ}K!$H$7$F07$&$K(B +$B$9$.$J$$!%9T$C$?JQ99$9$Y$F$O@x:_E*$K%U%)!<%/%]%$%s%H$K$J$j$&$k!%J,;6%j%S(B +$B%8%g%s%3%s%H%m!<%k%D!<%k$G$O!$%U%)!<%/$OF|>oE*$K5/$-!$$3$l$r<h$j07$&$3$H(B +$B$OF0:n$N:,K\$G$"$k!%$=$N$?$a%U%)!<%/4V$N(B\emph{$B%^!<%8(B}$B$K$O6K$a$FM%$l$F$*(B +$B$j!$$3$l$,J,;6%D!<%k$K$h$k%"%W%m!<%A$NBg$-$JMxE@$H$J$C$F$$$k!%(B + +%If every piece of work that everybody does, all the time, is framed in +%terms of forking and merging, then what the open source world refers +%to as a ``fork'' becomes \emph{purely} a social issue. If anything, +%distributed tools \emph{lower} the likelihood of a fork: + +$B3F?M$,>o$K9T$&:n6H$NCGJR$,%U%)!<%/$H%^!<%8$K0LCVIU$1$i$l$k$J$i$P!$%*!<%W(B +$B%s%=!<%93&$O(B``$B%U%)!<%/(B''$B$r(B\emph{$B=c?h$K(B}$B<R2qE*$J;v>]$H$7$F07$&$@$m$&!%$$$:(B +$B$l$K$;$hJ,;6%D!<%k$O%U%)!<%/$N38A3@-$r(B\emph{$B2<$2$k(B}$B!'(B + +%\begin{itemize} +%\item They eliminate the social distinction that centralised tools +% impose: that between insiders (people with commit access) and +% outsiders (people without). +%\item They make it easier to reconcile after a social fork, because +% all that's involved from the perspective of the revision control +% software is just another merge. +%\end{itemize} +\begin{itemize} + \item $BCf1{=8CfE*$J%D!<%k$,2]$9!$%3%_%C%H8"$r;}$C$?FbIt$N?M4V$H;}$?$J$$30(B + $BIt$N?M4V$N<R2qE*$J6hJL$r<h$j5n$k(B + \item $B%j%S%8%g%s%3%s%H%m!<%k%=%U%H%&%'%"$N4QE@$+$i$9$k$H!$F1$8%^!<%8$G$"(B + $B$k$?$a!$<R2qE*$J%U%)!<%/$N8e$K:90[$r2r>C$9$k$N$rMF0W$K$9$k!%(B +\end{itemize} + + +%Some people resist distributed tools because they want to retain tight +%control over their projects, and they believe that centralised tools +%give them this control. However, if you're of this belief, and you +%publish your CVS or Subversion repositories publically, there are +%plenty of tools available that can pull out your entire project's +%history (albeit slowly) and recreate it somewhere that you don't +%control. So while your control in this case is illusory, you are +%forgoing the ability to fluidly collaborate with whatever people feel +%compelled to mirror and fork your history. + +$B%W%m%8%'%/%H$r873J$K%3%s%H%m!<%k$7$?$$$?$a$KJ,;6%D!<%k$K93$&?M!9$b$$$k!%(B +$BH`$i$OCf1{=8Cf%D!<%k$,$3$N$h$&$J%3%s%H%m!<%k$rM?$($k$H9M$($F$$$k!%$7$+$7(B +$B$=$&;W$C$F$$$F$b!$(BCVS$B$d(BSubversion$B%j%]%8%H%j$r8x3+$9$l$P!$(B $B!J;~4V$O$+$+$C(B +$B$F$b!K%W%m%8%'%/%H$NMzNrA4BN$r<hF@$7$F!$%3%s%H%m!<%k$N<j$N5Z$P$J$$$I$3$+(B +$B$G$=$l$r:F8=$9$kJ}K!$O$$$/$i$G$b$"$k!%7k6I!$MzNr$r%_%i!<$7!$%U%)!<%/$9$k(B +$B$h$&$JN.F0E*$J6(NO$rGS=|$9$k$h$&$J%3%s%H%m!<%k$OHs8=<BE*$G$"$k!%(B + +%\subsection{Advantages for commercial projects} +\subsection{$B>&MQ%W%m%8%'%/%H$G$NMxE@(B} + +%Many commercial projects are undertaken by teams that are scattered +%across the globe. Contributors who are far from a central server will +%see slower command execution and perhaps less reliability. Commercial +%revision control systems attempt to ameliorate these problems with +%remote-site replication add-ons that are typically expensive to buy +%and cantankerous to administer. A distributed system doesn't suffer +%from these problems in the first place. Better yet, you can easily +%set up multiple authoritative servers, say one per site, so that +%there's no redundant communication between repositories over expensive +%long-haul network links. + +$B>&MQ%W%m%8%'%/%H$NB?$/$OCOM}E*$K9-$,$C$?%A!<%`$K$h$C$F3+H/$5$l$F$$$k!%Cf(B +$B1{%5!<%P$O!$1s$/N%$l$?6(NO<T$+$i$O%3%^%s%I<B9T$,CY$+$C$?$j!$?.Mj@-$,Dc$+$C(B +$B$?$j$9$k$h$&$K8+$($k!%>&MQ%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$O$3$NLdBj$N2r7h(B +$B$K%j%b!<%H%5%$%H$NJ#@=$r:n@.$9$k%"%I%*%s$rDs6!$7$F$$$k!%$3$l$i$NB?$/$O9b(B +$B2A$@$C$?$j!$4IM}$,J#;($@$H$$$&LdBj$r;}$C$F$$$k!%J,;6%7%9%F%`$K$O$=$b$=$b(B +$B$3$l$i$NLdBj$,$J$$!%$5$i$K9%$^$7$$$3$H$K!$J#?t$N%5%$%HKh$K@5<0$J%5!<%P$r(B +$B4JC1$K@_Dj$9$k$3$H$,$G$-!$9b2A$JD95wN%$N%M%C%H%o!<%/%j%s%/>e$K>iD9$JDL?.(B +$B$r9T$&$3$H$,$J$$!%(B + +%Centralised revision control systems tend to have relatively low +%scalability. It's not unusual for an expensive centralised system to +%fall over under the combined load of just a few dozen concurrent +%users. Once again, the typical response tends to be an expensive and +%clunky replication facility. Since the load on a central server---if +%you have one at all---is many times lower with a distributed +%tool (because all of the data is replicated everywhere), a single +%cheap server can handle the needs of a much larger team, and +%replication to balance load becomes a simple matter of scripting. + +$BCf1{=8Cf7?$N%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$N%9%1!<%i%S%j%F%#$OAjBPE*$K>.(B +$B$5$/!$?t==?M$N%f!<%6$NF1;~%"%/%;%9$K$h$kIi2Y$GCf1{$N9b2A$J%7%9%F%`$,Dd;_(B +$B$9$k$3$H$bDA$7$/$J$$!%$7$+$7!$$3$l$K9b2A$GJ#;($JJ#@=5!G=$rDI2C$9$k$3$H$,(B +$B$h$/9T$o$F$7$^$&!%$?$@0l$D$NCf1{%5!<%P$N$_$r;}$D>l9g$G$b!$J,;6%D!<%k$rMQ(B +$B$$$k$3$H$G!J%G!<%?$O$9$Y$F$"$i$f$k$H$3$m$KJ#@=$5$l$k$?$a!KCf1{%5!<%P$NIi(B +$B2Y$O?tJ,$N0l$KM^$($i$l$k!%$3$N$?$aC10l$N0B2A$J%5!<%P$GBg$-$J%A!<%`$N<{MW(B +$B$rK~$?$9$3$H$,$G$-!$Ii2YJ,;6$N$?$a$N%G!<%?$NJ#@=$b%9%/%j%W%H$@$1$G<B8=$G(B +$B$-$k!%(B + +%If you have an employee in the field, troubleshooting a problem at a +%customer's site, they'll benefit from distributed revision control. +%The tool will let them generate custom builds, try different fixes in +%isolation from each other, and search efficiently through history for +%the sources of bugs and regressions in the customer's environment, all +%without needing to connect to your company's network. + +$B8\5R$NB&$G$3$NNN0h$NLdBj2r7h$r9T$&=>6H0w$,$$$l$P!$J,;6%j%S%8%g%s%3%s%H%m!<(B +$B%k$NMx1W$rF@$k$3$H$,$G$-$k!%%D!<%k$r;H$&$3$H$G!$%+%9%?%`%S%k%I!$8_$$$KFH(B +$BN)$7$?=$@5$N%F%9%H!$%W%m%8%'%/%H$NMzNr$+$i%P%0$d%j%0%l%C%7%g%s$N860x$NC5(B +$B:w$J$I$r8\5R$N4D6-$G%M%C%H%o!<%/$K@\B3$9$kI,MW$J$/<B8=$G$-$k!%(B + +%\section{Why choose Mercurial?} +\section{Mercurial$B$rA*$VM}M3(B} + +%Mercurial has a unique set of properties that make it a particularly +%good choice as a revision control system. +Mercurial$B$O!$%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$H$7$FA*Br$9$k$N$K$U$5$o$7$$(B +$B%f%K!<%/$J@-<A$r;}$C$F$$$k!%(B +\begin{itemize} +%\item It is easy to learn and use. +%\item It is lightweight. +%\item It scales excellently. +%\item It is easy to customise. +\item $B3X=,$HMxMQ$,4JC1(B +\item $B7ZNL$G$"$k(B +\item $B6K$a$FNI9%$K%9%1!<%k$9$k(B +\item $B%+%9%?%^%$%:$,MF0W$G$"$k(B +\end{itemize} + +%If you are at all familiar with revision control systems, you should +%be able to get up and running with Mercurial in less than five +%minutes. Even if not, it will take no more than a few minutes +%longer. Mercurial's command and feature sets are generally uniform +%and consistent, so you can keep track of a few general rules instead +%of a host of exceptions. + +$BFI<T$,%j%S%8%g%s%3%s%H%m!<%k$K47$l$F$$$k$N$G$"$l$P!$(B Mercurial$B$r(B5$BJ,0JFb$K(B +$B;H$$;O$a$k$3$H$,$G$-$k$@$m$&!%(B $B2>$K(B5$BJ,$,L5M}$G$b!$$"$H?tJ,$b$"$l$P==J,$K(B +$B0c$$$J$$!%(B Mercurial$B$N%3%^%s%I$H5!G=%;%C%H$OA4BN$K6Q0l$G0l4S@-$,$"$k$N(B +$B$G!$B??t$NNc30$r3P$($k$N$G$O$J$/!$6&DL$9$k%k!<%k$5$(3P$($F$*$1$P$h$$!%(B + +%On a small project, you can start working with Mercurial in moments. +%Creating new changes and branches; transferring changes around +%(whether locally or over a network); and history and status operations +%are all fast. Mercurial attempts to stay nimble and largely out of +%your way by combining low cognitive overhead with blazingly fast +%operations. + +$B>.$5$J%W%m%8%'%/%H$G$O!$$9$0$K(BMercurial$B$r;H$$;O$a$k$3$H$,$G$-$k!%?7$7$$JQ(B +$B99$H%V%i%s%A$r:n$j!$!J%m!<%+%k$d%M%C%H%o!<%/1[$7$K!KJQ99$rE>Aw$7!$MzNr$H(B +$B>uBV$K4X$9$kF0:n$O$9$Y$F9bB.$G$"$k!%(B Mercurial$B$N8D!9$NF0:n$O6K$a$F9bB.$G(B +$B$"$j!$A4BN$H$7$F$bAGAa$/!$%*!<%P%X%C%I$,$[$H$s$ICN3P$G$-$J$$$h$&$JF0:n$r(B +$B$9$k$h$&$K$J$C$F$$$k!%(B + +%The usefulness of Mercurial is not limited to small projects: it is +%used by projects with hundreds to thousands of contributors, each +%containing tens of thousands of files and hundreds of megabytes of +%source code. + +Mercurial$B$NM-MQ@-$O!$>.$5$J%W%m%8%'%/%H$K8B$i$J$$!%(BMercurial$B$O?tI4?M$+$i(B +$B?t@i?M$N9W8%<T$rMJ$7!$?tK|$N%U%!%$%k$+$i$J$k?tI4%a%,%P%$%H$K$b5Z$V%=!<%9(B +$B%3!<%I$+$i$J$k%W%m%8%'%/%H$G$bM-8z$G$"$k!%(B + +%If the core functionality of Mercurial is not enough for you, it's +%easy to build on. Mercurial is well suited to scripting tasks, and +%its clean internals and implementation in Python make it easy to add +%features in the form of extensions. There are a number of popular and +%useful extensions already available, ranging from helping to identify +%bugs to improving performance. + +Mercurial$B$N3K$K$J$k5!G=$,==J,$G$J$+$C$?>l9g!$3HD%$9$k$3$H$O$?$d$9$$!%(B +Mercurial$B$O%9%/%j%W%H$H$h$/Fk@w$`!%$^$?@0$C$?FbIt9=B$$H(BPython$B$K$h$k<BAu$N(B +$B$?$a!$3HD%$N7A$G?7$7$$5!G=$rDI2C$9$k$N$,MF0W$G$"$k!%%P%0$N<1JL$r=u$1$k$b(B +$B$N$+$i!$@-G=$r2~A1$9$k$b$N$^$G!$?M5$$N9b$$M-MQ$J3HD%$,$9$G$K?tB?$/B8:_$7(B +$B$F$$$k!%(B + +%\section{Mercurial compared with other tools} +\section{Mercurial$B$HB>$N%D!<%k$NHf3S(B} + +%Before you read on, please understand that this section necessarily +%reflects my own experiences, interests, and (dare I say it) biases. I +%have used every one of the revision control tools listed below, in +%most cases for several years at a time. + +$B$3$N@a$rFI$`A0$K!$$3$l$OI.<T<+?H$NBN83$H6=L#!$$=$7$F!J4:$($F8@$($P!K%P%$(B +$B%"%9$,$+$+$C$F$$$k$3$H$rM}2r$7$FM_$7$$!%I.<T$O2<5-$N%j%S%8%g%s%3%s%H%m!<(B +$B%k%D!<%k$N$9$Y$F$r;HMQ$7$?$3$H$,$"$j!$$=$N;HMQ4|4V$OB?$/$N>l9g?tG/$K5Z$V!%(B + +\subsection{Subversion} + +%Subversion is a popular revision control tool, developed to replace +%CVS. It has a centralised client/server architecture. + +Subversion$B$O!$(BCVS$B$rCV$-49$($k$Y$/3+H/$5$l$?!$?M5$$N9b$$%j%S%8%g%s%3%s%H%m!<(B +$B%k%D!<%k$G$"$k!%$3$l$bCf1{=8Cf7?$N%/%i%$%"%s%H%5!<%P%"!<%-%F%/%A%c$r;}$D!%(B + +%Subversion and Mercurial have similarly named commands for performing +%the same operations, so if you're familiar with one, it is easy to +%learn to use the other. Both tools are portable to all popular +%operating systems. + +Subversion$B$H(BMercurial$B$G$O!$F1$8F0:n$N$?$a$N%3%^%s%I$KF1MM$NL>A0$,IU$1$i$l(B +$B$F$$$k$?$a!$$I$A$i$+$K47$l$F$$$l$P$b$&0lJ}$r3X$V$N$O$?$d$9$$!%$I$A$i$N%D!<(B +$B%k$b$9$Y$F$N?M5$$N9b$$%*%Z%l!<%F%#%s%0%7%9%F%`$K0\?"$5$l$F$$$k!%(B + +%Subversion lacks a history-aware merge capability, forcing its users +%to manually track exactly which revisions have been merged between +%branches. If users fail to do this, or make mistakes, they face the +%prospect of manually resolving merges with unnecessary conflicts. +%Subversion also fails to merge changes when files or directories are +%renamed. Subversion's poor merge support is its single biggest +%weakness. + +Subversion$B$OMzNr$r9MN8$7$?%^!<%8$N5!G=$r7g$$$F$*$j!$@53N$K$I$N%j%S%8%g%s(B +$B$,%V%i%s%A4V$G%^!<%8$5$l$?$N$+%f!<%6<+?H$,%H%i%C%/$9$kI,MW$,$"$k!#%f!<%6(B +$B$,DI$$@Z$l$J$+$C$?>l9g$d4V0c$$$rHH$7$?>l9g!$I,MW$N$J$$%3%s%U%j%/%H$r<jF0(B +$B$G2r7h$9$k$3$H$K$J$k!%(BSubversion$B$O%U%!%$%k$d%G%#%l%/%H%j$,%j%M!<%`$5$l$F(B +$B$$$?>l9g$b%^!<%8$K<:GT$9$k!%%^!<%8%5%]!<%H$N<e$5$O(BSubversion$B$N:GBg$N<eE@(B +$B$N0l$D$G$"$k!%(B + +%Mercurial has a substantial performance advantage over Subversion on +%every revision control operation I have benchmarked. I have measured +%its advantage as ranging from a factor of two to a factor of six when +%compared with Subversion~1.4.3's \emph{ra\_local} file store, which is +%the fastest access method available. In more realistic deployments +%involving a network-based store, Subversion will be at a substantially +%larger disadvantage. Because many Subversion commands must talk to +%the server and Subversion does not have useful replication facilities, +%server capacity and network bandwidth become bottlenecks for modestly +%large projects. + +Mercurial$B$OI.<T$,%Y%s%A%^!<%/$r9T$C$?A4$F$N%j%S%8%g%s%3%s%H%m!<%kA`:n$K$*(B +$B$$$F(BSubversion$B$h$j$bL@3N$J@-G=>e$NM%0L@-$r;}$C$F$$$k!%I.<T$O(B2$B$+$i(B6$B$^$G$N(B +$BHO0O$GM%0L@-$r(BSubversion~1.4.3$B$GMxMQ2DG=$JCf$G:G$b9bB.$J(B\emph{ra\_$B%m!<%+(B +$B%k(B}$B%U%!%$%kJ]B8$HHf3S$7$?!%$h$j8=<BE*$JMxMQ$G$O%M%C%H%o!<%/$rMxMQ$7$?%U%!(B +$B%$%k%5!<%S%9$rMQ$$$k$3$H$K$J$j!$(BSubversion$B$G$OL@3N$KBg$-$JITMx$,$"$k!%B?(B +$B$/$N(BSubversion$B%3%^%s%I$O%5!<%P$HDL?.$9$kI,MW$,$"$j!$(BSubversion$B$O<BMQE*$J(B +$BJ#@=5!9=$r;}$?$J$$$?$a!$0lDj0J>e$N5,LO$N%W%m%8%'%/%H$G$O!$%5!<%P%-%c%Q%7(B +$B%F%#$H%M%C%H%o!<%/$N%P%s%II}$,%\%H%k%M%C%/$H$J$k$+$i$G$"$k!%(B + +%Additionally, Subversion incurs substantial storage overhead to avoid +%network transactions for a few common operations, such as finding +%modified files (\texttt{status}) and displaying modifications against +%the current revision (\texttt{diff}). As a result, a Subversion +%working copy is often the same size as, or larger than, a Mercurial +%repository and working directory, even though the Mercurial repository +%contains a complete history of the project. + +$B$5$i$K!$(BSubversion$B$O99?7$5$l$?%U%!%$%k$NC5:w(B(\texttt{status})$B$H!$8=:_$N%j(B +$B%S%8%g%s$KBP$9$k:9J,$N$rI=<((B(\texttt{diff})$B$J$I$N$$$/$D$+$NA`:n$G%M%C%H%o!<(B +$B%/%H%i%s%6%/%7%g%s$rHr$1$k$?$a$KL@3N$J%9%H%l!<%8%*!<%P%X%C%I$r$b$?$i$9!%(B +$B7k2L$H$7$F!$(BSubversion$B$N%o!<%-%s%0%3%T!<$O!$%W%m%8%'%/%H$N40A4$JMzNr$r4^(B +$B$`(BMercurial$B$N%j%]%8%H%j5Z$S%o!<%-%s%0%G%#%l%/%H%j$HF1$8$+$h$jBg$-$J%5%$%:(B +$B$H$J$C$F$7$^$&!%(B + +%Subversion is widely supported by third party tools. Mercurial +%currently lags considerably in this area. This gap is closing, +%however, and indeed some of Mercurial's GUI tools now outshine their +%Subversion equivalents. Like Mercurial, Subversion has an excellent +%user manual. + +Subversion$B$K$OB?$/$N%5!<%I%Q!<%F%#%D!<%k$,$"$k!%(BMercurial$B$O$3$NE@$G$+$J$j(B +$BCY$l$F$$$k!%%.%c%C%W$O=L$^$j$D$D$"$k$,!$(BMercurial$B$N(BGUI$B%D!<%k$N$$$/$D$+(B +$B$O!$BP1~$9$k(BSubversion$BMQ$N$b$N$h$j$b=($G$F$$$k!%(BSubversion$B$K$O(BMercurial$B$H(B +$BF1MM$KM%$l$?%f!<%6%^%K%e%"%k$,$"$k!%(B + +%Because Subversion doesn't store revision history on the client, it is +%well suited to managing projects that deal with lots of large, opaque +%binary files. If you check in fifty revisions to an incompressible +%10MB file, Subversion's client-side space usage stays constant. The +%space used by any distributed SCM will grow rapidly in proportion to +%the number of revisions, because the differences between each revision +%are large. + +Subversion$B$O%j%S%8%g%s$NMzNr$r%/%i%$%"%s%HFb$K;}$?$J$$$?$a!$%5%$%:$,Bg$-(B +$B$/FbMF$NL@$i$+$G$J$$B??t$N%P%$%J%j%U%!%$%k$r<h$j07$&$N$K$O8~$$$F$$$k!%(B +$B05=L$N8z$+$J$$(B10MB$B$N%U%!%$%k$KBP$7$F(B50$B%j%S%8%g%s$r%A%'%C%/%$%s$9$k>l(B +$B9g!$(BSubversion$B$N%/%i%$%"%s%HB&$N%9%H%l!<%8$N;HMQNL$O0lDj$G$"$k!%(B +$BJ,;6(BSCM$B$G$O!$%9%H%l!<%8;HMQNL$O3F!9$N%j%S%8%g%s4V$G$N:9J,$,Bg$-$$$?$a!$%j(B +$B%S%8%g%s?t$KHfNc$7$F$9$0$KA}$($F$7$^$&!%(B + +%In addition, it's often difficult or, more usually, impossible to +%merge different versions of a binary file. Subversion's ability to +%let a user lock a file, so that they temporarily have the exclusive +%right to commit changes to it, can be a significant advantage to a +%project where binary files are widely used. + +$B2C$($F!$0[$J$k%P!<%8%g%s$N%P%$%J%j%U%!%$%k$r%^!<%8$9$k$N$OIT2DG=$G$"$C$?(B +$B$j!$:$Fq$G$"$C$?$j$9$k!%(B Subversion$B$G$O%U%!%$%k%m%C%/5!G=$K$h$C$F%f!<%6$,(B +$B0l;~E*$K%U%!%$%k$X$NJQ99$r%3%_%C%H$9$kGSB>E*$J8"Mx$rF@$k$3$H$,$G$-$k!%$3(B +$B$l$O%P%$%J%j%U%!%$%k$r9-HF$K;H$&%W%m%8%'%/%H$G$OBg$-$JMxE@$K$J$jF@$k!%(B + +%Mercurial can import revision history from a Subversion repository. +%It can also export revision history to a Subversion repository. This +%makes it easy to ``test the waters'' and use Mercurial and Subversion +%in parallel before deciding to switch. History conversion is +%incremental, so you can perform an initial conversion, then small +%additional conversions afterwards to bring in new changes. + +Mercurial$B$O(BSubversion$B%j%]%8%H%j$+$i%j%S%8%g%sMzNr$r%$%s%]!<%H$9$k$3$H$,$G(B +$B$-$k!%$^$?!$%j%S%8%g%sMzNr$r(BSubversion$B%j%]%8%H%j$K%(%/%9%]!<%H$9$k$3$H$b(B +$B2DG=$@!%$3$N$?$a!$0\9T$r7h$a$kA0$K(BMercurial$B$r;n$7$?$j!$(BMercurial$B$r(B +Subversion$B$HJB9T$7$FMxMQ$9$k$3$H$,MF0W$G$"$k!%(B +$BMzNr$NJQ49$OA2?JE*$K9T$($k$?$a!$:G=i$KJQ49$r9T$C$?8e!$?7$?$JJQ99$r<h$j9~(B +$B$`$?$a$KDI2C$NJQ49$r9T$&$3$H$,$G$-$k!%(B + +\subsection{Git} + +%Git is a distributed revision control tool that was developed for +%managing the Linux kernel source tree. Like Mercurial, its early +%design was somewhat influenced by Monotone. + +Git$B$O(BLinux$B%+!<%M%k$N%=!<%9%D%j!<$r07$&$?$a$K3+H/$5$l$?J,;6%j%S%8%g%s%3%s(B +$B%H%m!<%k%D!<%k$G$"$k!%(B Mercurial$BF1MM!$$=$N=i4|$N%G%6%$%s$OB?>/(BMonotone$B$K(B +$B1F6A$r<u$1$F$$$k!%(B + +%Git has a very large command set, with version~1.5.0 providing~139 +%individual commands. It has something of a reputation for being +%difficult to learn. Compared to Git, Mercurial has a strong focus on +%simplicity. + +Git$B$OHs>o$KBg5,LO$J%3%^%s%I%;%C%H$r;}$C$F$$$k!%(Bversion~1.5.0$B$G$O(B~139$B$K$b(B +$B5Z$V%3%^%s%I$,MQ0U$5$l$F$$$k!%$3$N$?$a!$(BGit$B$O$7$P$7$P=,F@$7$E$i$$$H$$$&(B +$BI>H=$5$l$F$$$k!%(BMercurial$B$O(BGit$B$HHf$Y$k$H4J7i$5$K6/$/%U%)!<%+%9$7$F$$$k!%(B + +%In terms of performance, Git is extremely fast. In several cases, it +%is faster than Mercurial, at least on Linux, while Mercurial performs +%better on other operations. However, on Windows, the performance and +%general level of support that Git provides is, at the time of writing, +%far behind that of Mercurial. + +$B@-G=$K4X$7$F$O!$(BGit$B$O6K$a$F9bB.$G$"$k!%(BLinux$B4D6-$G$N%F%9%H$G$O!$$$$/$D$+(B +$B$NA`:n$O(BGit$B$O(BMercurial$B$h$j$b9bB.$G$"$C$?!%$7$+$7(BWindows$B4D6-$G$O!$$3$NK\$N(B +$B<9I.;~E@$G$O!$@-G=$d(BGit$B$NDs6!$9$k5!G=$O(BMercurial$B$KBg$-$/Nt$C$?!%(B + +%While a Mercurial repository needs no maintenance, a Git repository +%requires frequent manual ``repacks'' of its metadata. Without these, +%performance degrades, while space usage grows rapidly. A server that +%contains many Git repositories that are not rigorously and frequently +%repacked will become heavily disk-bound during backups, and there have +%been instances of daily backups taking far longer than~24 hours as a +%result. A freshly packed Git repository is slightly smaller than a +%Mercurial repository, but an unpacked repository is several orders of +%magnitude larger. + +Mercurial$B%j%]%8%H%j$O%a%s%F%J%s%9$rI,MW$H$7$J$$$,!$(BGit$B%j%]%8%H%j$O$7$P$7(B +$B$P<jF0$G%a%?%G!<%?$N(B``repacks''$B$,I,MW$H$J$k!%$3$l$r9T$o$J$$>l9g!$@-G=$ONt(B +$B2=$7!$I,MW$J5-21NN0h$b5^B.$K3HBg$9$k!%(BGit$B%j%]%8%H%j$r5,B'@5$7$/IQHK$K(B +repack$B$7$J$$%5!<%P$G$O%P%C%/%"%C%W$N:]$K%G%#%9%/;HMQ$,6K$a$FB?$/$J$j!$7k(B +$B2L$H$7$FKhF|$N%P%C%/%"%C%W$K(B~24$B;~4V0J>e$rHq$d$9$3$H$K$J$k!%(B +$B?75,$K(Bpack$B$5$l$?(BGit$B%j%]%8%H%j$O(BMercurial$B%j%]%8%H%j$h$j$d$d>.$5$$(B +$B$,!$(Bunpack$B>uBV$N(BGit$B%j%]%8%H%j$O?tCJBg$-$/$J$k!%(B + +%The core of Git is written in C. Many Git commands are implemented as +%shell or Perl scripts, and the quality of these scripts varies widely. +%I have encountered several instances where scripts charged along +%blindly in the presence of errors that should have been fatal. + +Git$B$N%3%"$O(BC$B$G=q$+$l$F$$$k!%(BGit$B%3%^%s%I$NB?$/$O%7%'%k$d(BPerl$B$N%9%/%j%W%H$H(B +$B$7$F<BAu$5$l$F$*$j!$$=$l$i$N%9%/%j%W%H$NIJ<A$OMM!9$G$"$k!%?tEY$K$o$?$C$F(B +$BCWL?E*$J%(%i!<$,$"$k$K$b$+$+$o$i$:!$%9%/%j%W%H$,LULGK!$KF0:n$9$k$3$H$rBN(B +$B83$7$?!%(B + +%Mercurial can import revision history from a Git repository. + +Mercurial$B$O(BGit$B%j%]%8%H%j$+$i%j%S%8%g%sMzNr$r%$%s%]!<%H$9$k$3$H$,$G$-$k!%(B + +\subsection{CVS} + +%CVS is probably the most widely used revision control tool in the +%world. Due to its age and internal untidiness, it has been only +%lightly maintained for many years. + +CVS$B$O$*$=$i$/@$3&Cf$G:G$b9-HO$K;HMQ$5$l$F$$$k%j%S%8%g%s%3%s%H%m!<%k%D!<(B +$B%k$G$"$m$&!%$=$N8E$5$HFbIt$NMp;($5$N$?$a!$D9$i$/7Z$$%a%s%F%J%s%9$N$_$,9T(B +$B$o$l$F$-$?!%(B + +%It has a centralised client/server architecture. It does not group +%related file changes into atomic commits, making it easy for people to +%``break the build'': one person can successfully commit part of a +%change and then be blocked by the need for a merge, causing other +%people to see only a portion of the work they intended to do. This +%also affects how you work with project history. If you want to see +%all of the modifications someone made as part of a task, you will need +%to manually inspect the descriptions and timestamps of the changes +%made to each file involved (if you even know what those files were). + +CVS$B$O=8Cf7?$N%/%i%$%"%s%H%5!<%P%"!<%-%F%/%A%c$r;}$D!%(BCVS$B$O!$4XO"$7$?%U%!(B +$B%$%kJQ99$r%0%k!<%W2=$7!$%"%H%_%C%/$K%3%_%C%H$9$k$3$H$,$G$-$J$$!%$3$N$?$a(B +$B%f!<%6$,%3%_%C%H$K$h$C$F%S%k%I$rGK2u$9$k$3$H$,5/$3$k!%C/$+$,JQ99$N0lIt$r(B +$B@.8yN"$K%3%_%C%H$7$?$b$N$N!$;D$j$NItJ,$O%^!<%8$,I,MW$J$?$a%V%m%C%/$5$l$F(B +$B$$$k>l9g!$B>$N%f!<%6$OI,MW$JJQ99$N0lIt$7$+8+$k$3$H$,$G$-$J$$!%F1$8$3$H$O(B +$B%W%m%8%'%/%H$NMzNr$KBP$7$F$b5/$3$k!%C/$+$N:n6H$K4X78$9$kJQ99$9$Y$F$r;2>H(B +$B$7$?$$>l9g!$!J$I$N%U%!%$%k$,2?$J$N$+CN$C$F$$$l$P!K4XO"$9$k3F%U%!%$%k$K$D(B +$B$$$F!$JQ99$N@bL@$H%?%$%`%9%?%s%W$r<+NO$GD4$Y$FJQ99$rFCDj$9$kI,MW$,$"$k!%(B + +%CVS has a muddled notion of tags and branches that I will not attempt +%to even describe. It does not support renaming of files or +%directories well, making it easy to corrupt a repository. It has +%almost no internal consistency checking capabilities, so it is usually +%not even possible to tell whether or how a repository is corrupt. I +%would not recommend CVS for any project, existing or new. + +CVS$B$N%?%0$H%V%i%s%A$O8l$k5$$5$(5/$-$J$$$h$&$J:.Mp$7$?7A<0$r;}$C$F$$$k!%$-(B +$B$A$s$H$7$?%U%!%$%k$d%G%#%l%/%H%j$N%j%M!<%`$r%5%]!<%H$7$J$$$?$a!$%j%]%8%H(B +$B%j$,4JC1$K2u$l$F$7$^$&!%(B cvs$B$OFbIt$G0l4S@-$r%A%'%C%/$9$k5!G=$,$J$/!$%j%](B +$B%8%H%j$NGKB;$rCN$i$;$k$3$H$b$G$-$J$$!%I.<T$O4{B8$^$?$O?75,$rLd$o$:!$$I$N(B +$B$h$&$J%W%m%8%'%/%H$G$"$C$F$b(BCVS$B$N;HMQ$OA&$a$J$$!%(B + +%Mercurial can import CVS revision history. However, there are a few +%caveats that apply; these are true of every other revision control +%tool's CVS importer, too. Due to CVS's lack of atomic changes and +%unversioned filesystem hierarchy, it is not possible to reconstruct +%CVS history completely accurately; some guesswork is involved, and +%renames will usually not show up. Because a lot of advanced CVS +%administration has to be done by hand and is hence error-prone, it's +%common for CVS importers to run into multiple problems with corrupted +%repositories (completely bogus revision timestamps and files that have +%remained locked for over a decade are just two of the less interesting +%problems I can recall from personal experience). + +Mercurial$B$O(BCVS$B$N%j%S%8%g%sMzNr$r%$%s%]!<%H$9$k$3$H$,$G$-$k!%$7$+$7B>$N%j(B +$B%S%8%g%s%3%s%H%m!<%k%D!<%k$N(BCVS$B%$%s%]!<%?!<F1MM$$$/$D$+$N@)8B$b$"$k!%(B +CVS$B$K$O%"%H%_%C%/%A%'%s%8$,$J$/!$%U%!%$%k%7%9%F%`3,AX$r%P!<%8%g%s4IM}$9(B +$B$kG=NO$b$J$$$?$a!$(BCVS$B$NMzNr$r40A4$+$D@53N$K:F8=$9$k$3$H$O$G$-$J$$!%:F8=(B +$B$K$O$$$/$D$+$N?dB,$,F~$j!$%j%M!<%`$ODL>o:F8=$5$l$J$$!%(B +CVS$B$G$O9bEY$J4IM}$NB?$/$,<jF0$G9T$o$l$k$?$a!$4V0c$$$,5/$3$j$d$9$/!$GKB;$7(B +$B$?%j%]%8%H%j$G(BCVS$B%$%s%]!<%?!<$,F1;~$KJ#?t$NLdBj$K8+Iq$o$l$k$3$H$,$h$/$"(B +$B$k!%!JI.<T$NITL{2w$JBN83$G$O!$(B10$BG/0J>e$K$o$?$C$F%m%C%/$5$l$?$^$^$N40A4$K(B +$BL50UL#$J%j%S%8%g%s%?%$%`%9%?%s%W$d%U%!%$%k$r8+$?$3$H$,$"$k!%!K(B + +%Mercurial can import revision history from a CVS repository. + +Mercurial$B$O(BCVS$B%j%]%8%H%j$+$i%j%S%8%g%sMzNr$r%$%s%]!<%H$9$k$3$H$,$G$-$k!%(B + +%\subsection{Commercial tools} +\subsection{$B>&MQ%D!<%k(B} + +%Perforce has a centralised client/server architecture, with no +%client-side caching of any data. Unlike modern revision control +%tools, Perforce requires that a user run a command to inform the +%server about every file they intend to edit. + +Perforce$B$O=8Cf7?$N%/%i%$%"%s%H!&%5!<%P%"!<%-%F%/%A%c$r;}$A!$$$$+$J$k%G!<(B +$B%?$b%/%i%$%"%s%HB&$G%-%c%C%7%e$7$J$$!%8=:_$N%j%S%8%g%s%3%s%H%m!<%k%D!<%k(B +$B$H$3$H$J$j!$(BPerforce$B$G$O%f!<%6$,$I$N%U%!%$%k$rJT=8$9$k$N$+%5!<%P$KCN$i$;(B +$B$k%3%^%s%I$r<B9T$9$kI,MW$,$"$k!%(B + +%The performance of Perforce is quite good for small teams, but it +%falls off rapidly as the number of users grows beyond a few dozen. +%Modestly large Perforce installations require the deployment of +%proxies to cope with the load their users generate. + +Perforce$B$N@-G=$O!$>.5,LO$J%A!<%`$G$N:n6H$K$*$$$F$O$+$J$jNI$$!%$7$+$7%f!<(B +$B%6?t$,?t%@!<%90J>e$KA}2C$9$k$K=>$C$F!$5^7c$K0-$/$J$C$F$$$/!%$+$J$jBg5,LO(B +$B$J(BPerforce$B4D6-$G$O!$%f!<%6$NA`:n$K$h$kIi2Y$r7Z8:$9$k$?$a$N%W%m%-%7!<$,I,(B +$BMW$K$J$k!%(B + +%\subsection{Choosing a revision control tool} +\subsection{$B%j%S%8%g%s%3%s%H%m!<%k%D!<%k$rA*$V(B} + +%With the exception of CVS, all of the tools listed above have unique +%strengths that suit them to particular styles of work. There is no +%single revision control tool that is best in all situations. + +CVS$B$r=|$$$F!$>e5-$N%D!<%k$OFCDj$N:n6H%9%?%$%k$K9g$C$?8GM-$N6/$_$r;}$C$F$$(B +$B$k!%$9$Y$F$N>u67$G%Y%9%H$G$"$k%D!<%k$H$$$&$b$N$OB8:_$7$J$$!%(B + +%As an example, Subversion is a good choice for working with frequently +%edited binary files, due to its centralised nature and support for +%file locking. If you're averse to the command line, it currently has +%better GUI support than other free revision control tools. However, +%its poor merging is a substantial liability for busy projects with +%overlapping development. + +$BNc$($P!$IQHK$KJQ99$5$l$k%P%$%J%j%U%!%$%k$r07$&>l9g$O(BSubverrsion$B$rA*$V$N$,(B +$BNI$$!%(BSubversion$B$N=8Cf7?$N@-<A$H%U%!%$%k%m%C%/$N%5%]!<%H$O%P%$%J%j%U%!%$(B +$B%k$N<h$j07$$$KE,$7$F$$$k!%%3%^%s%I%i%$%s$,7y$$$J$i$P!$B>$N%U%j!<%j%S%8%g(B +$B%s4IM}%D!<%k$h$j$bM%$l$?(BGUI$B%5%]!<%H$,$"$k!%$7$+$7%^!<%85!9=$N<e$5$OF1;~$K(B +$BJB9T$7$?3+H/$G$O>/$J$+$i$LLdBj$H$J$j$&$k!%(B + +%I personally find Mercurial's properties of simplicity, performance, +%and good merge support to be a compelling combination that has served +%me well for several years. + +$B8D?ME*$K$O!$?tG/$K$o$?$C$F!$(BMercurial$B$N4J7i$5!$@-G=!$M%$l$?%^!<%8%5%]!<%H(B +$B$O!$>h$j49$($k$KCM$9$kAH9g$;$@$H46$8$F$$$k!%(B + +%\section{Switching from another tool to Mercurial} +\section{$BB>$N%D!<%k$+$i(BMercurial$B$X$N0\9T(B} + +%Mercurial is bundled with an extension named \hgext{convert}, which +%can incrementally import revision history from several other revision +%control tools. By ``incremental'', I mean that you can convert all of +%a project's history to date in one go, then rerun the conversion later +%to obtain new changes that happened after the initial conversion. + +Mercurial$B$K$O(B\hgext{convert}$B$H$$$&3HD%$,F1:-$5$l$F$$$k!%$3$N3HD%$O%j%S%8%g(B +$B%sMzNr$rB>$N%j%S%8%g%s%3%s%H%m!<%k%D!<%k$+$i%$%s%/%j%a%s%?%k$K%$%s%]!<%H(B +$B$9$k!%!V%$%s%/%j%a%s%?%k!W$H$$$&$N$O!$$^$:%W%m%8%'%/%H$NMzNr$9$Y$F$rJQ49(B +$B$7$?8e$G!$85$N%j%]%8%H%j$K5/$-$?JQ99$r$5$i$KJQ49$7$F<h$j9~$a$k$H$$$&0UL#(B +$B$G$"$k!%(B + +%The revision control tools supported by \hgext{convert} are as +%follows: + +\hgext{convert}$B$O<!$N%j%S%8%g%s%3%s%H%m!<%k%D!<%k$r%5%]!<%H$9$k(B: +\begin{itemize} +\item Subversion +\item CVS +\item Git +\item Darcs +\end{itemize} + +%In addition, \hgext{convert} can export changes from Mercurial to +%Subversion. This makes it possible to try Subversion and Mercurial in +%parallel before committing to a switchover, without risking the loss +%of any work. + +$B2C$($F!$(B\hgext{convert}$B$O(BMercurial$B$+$i(BSubversion$B$KJQ99$r%(%/%9%]!<%H$9$k(B +$B$3$H$,$G$-$k!%$3$l$K$h$j!$(BSubversion$B$+$i(BMercurial$B$K@ZBX$($kA0$K!$9T$C$?:n(B +$B6H$N7k2L$r<:$&$3$H$J$/!$N><T$rJB9T$7$F;n$9$3$H$,$G$-$k!%(B + +%The \hgxcmd{conver}{convert} command is easy to use. Simply point it +%at the path or URL of the source repository, optionally give it the +%name of the destination repository, and it will start working. After +%the initial conversion, just run the same command again to import new +%changes. + +\hgxcmd{conver}{convert}$B%3%^%s%I$r;H$&$N$O$?$d$9$$!%C1$K%=!<%9%j%]%8%H%j(B +$B$N%Q%9$d(BURL$B$rEO$9$@$1$G!$;HMQ2DG=$J%j%]%8%H%j$r:n@.$9$k!%$^$?!$%*%W%7%g%s(B +$B$GJQ498e$N%j%]%8%H%j$NL>A0$rEO$9$3$H$b$G$-$k!%:G=i$NJQ498e!$F1$8%3%^%s%I(B +$B$r:F$S<B9T$9$k$H?7$7$$JQ99$r<h$j9~$`$3$H$,$G$-$k!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/license.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,138 @@ +\chapter{Open Publication License} +\label{cha:opl} + +Version 1.0, 8 June 1999 + +\section{Requirements on both unmodified and modified versions} + +The Open Publication works may be reproduced and distributed in whole +or in part, in any medium physical or electronic, provided that the +terms of this license are adhered to, and that this license or an +incorporation of it by reference (with any options elected by the +author(s) and/or publisher) is displayed in the reproduction. + +Proper form for an incorporation by reference is as follows: + +\begin{quote} + Copyright (c) \emph{year} by \emph{author's name or designee}. This + material may be distributed only subject to the terms and conditions + set forth in the Open Publication License, v\emph{x.y} or later (the + latest version is presently available at + \url{http://www.opencontent.org/openpub/}). +\end{quote} + +The reference must be immediately followed with any options elected by +the author(s) and/or publisher of the document (see +section~\ref{sec:opl:options}). + +Commercial redistribution of Open Publication-licensed material is +permitted. + +Any publication in standard (paper) book form shall require the +citation of the original publisher and author. The publisher and +author's names shall appear on all outer surfaces of the book. On all +outer surfaces of the book the original publisher's name shall be as +large as the title of the work and cited as possessive with respect to +the title. + +\section{Copyright} + +The copyright to each Open Publication is owned by its author(s) or +designee. + +\section{Scope of license} + +The following license terms apply to all Open Publication works, +unless otherwise explicitly stated in the document. + +Mere aggregation of Open Publication works or a portion of an Open +Publication work with other works or programs on the same media shall +not cause this license to apply to those other works. The aggregate +work shall contain a notice specifying the inclusion of the Open +Publication material and appropriate copyright notice. + +\textbf{Severability}. If any part of this license is found to be +unenforceable in any jurisdiction, the remaining portions of the +license remain in force. + +\textbf{No warranty}. Open Publication works are licensed and provided +``as is'' without warranty of any kind, express or implied, including, +but not limited to, the implied warranties of merchantability and +fitness for a particular purpose or a warranty of non-infringement. + +\section{Requirements on modified works} + +All modified versions of documents covered by this license, including +translations, anthologies, compilations and partial documents, must +meet the following requirements: + +\begin{enumerate} +\item The modified version must be labeled as such. +\item The person making the modifications must be identified and the + modifications dated. +\item Acknowledgement of the original author and publisher if + applicable must be retained according to normal academic citation + practices. +\item The location of the original unmodified document must be + identified. +\item The original author's (or authors') name(s) may not be used to + assert or imply endorsement of the resulting document without the + original author's (or authors') permission. +\end{enumerate} + +\section{Good-practice recommendations} + +In addition to the requirements of this license, it is requested from +and strongly recommended of redistributors that: + +\begin{enumerate} +\item If you are distributing Open Publication works on hardcopy or + CD-ROM, you provide email notification to the authors of your intent + to redistribute at least thirty days before your manuscript or media + freeze, to give the authors time to provide updated documents. This + notification should describe modifications, if any, made to the + document. +\item All substantive modifications (including deletions) be either + clearly marked up in the document or else described in an attachment + to the document. +\item Finally, while it is not mandatory under this license, it is + considered good form to offer a free copy of any hardcopy and CD-ROM + expression of an Open Publication-licensed work to its author(s). +\end{enumerate} + +\section{License options} +\label{sec:opl:options} + +The author(s) and/or publisher of an Open Publication-licensed +document may elect certain options by appending language to the +reference to or copy of the license. These options are considered part +of the license instance and must be included with the license (or its +incorporation by reference) in derived works. + +\begin{enumerate}[A] +\item To prohibit distribution of substantively modified versions + without the explicit permission of the author(s). ``Substantive + modification'' is defined as a change to the semantic content of the + document, and excludes mere changes in format or typographical + corrections. + + To accomplish this, add the phrase ``Distribution of substantively + modified versions of this document is prohibited without the + explicit permission of the copyright holder.'' to the license + reference or copy. + +\item To prohibit any publication of this work or derivative works in + whole or in part in standard (paper) book form for commercial + purposes is prohibited unless prior permission is obtained from the + copyright holder. + + To accomplish this, add the phrase ``Distribution of the work or + derivative of the work in any standard (paper) book form is + prohibited unless prior permission is obtained from the copyright + holder.'' to the license reference or copy. +\end{enumerate} + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/metadata.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,328 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docname="metadata.svg" + sodipodi:docbase="/home/bos/hg/hgbook/en"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path2944" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4" + inkscape:cx="232.14286" + inkscape:cy="490.68696" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="181" + inkscape:window-y="58" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + 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" + d="M 326.94646,467.18359 L 326.94646,510.98123" + id="path1910" + inkscape:connector-type="polyline" + inkscape:connection-end="#rect2962" + inkscape:connection-start="#rect2764" /> + <path + 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" + d="M 326.94646,531.98123 L 326.94646,591.77887" + id="path1912" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect2962" + inkscape:connection-end="#rect3000" /> + <path + 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" + d="M 316.1622,531.98123 L 192.30212,652.57648" + id="path1916" + inkscape:connector-type="polyline" + inkscape:connection-end="#rect3038" + inkscape:connection-start="#rect2962" /> + <path + 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" + d="M 254.23217,467.18359 L 254.23216,510.98123" + id="path3088" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect1872" + inkscape:connection-end="#rect2960" /> + <path + 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" + d="M 254.23215,531.98123 L 254.23215,591.77887" + id="path3090" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect2960" + inkscape:connection-end="#rect2998" /> + <path + 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" + d="M 248.84002,531.98123 L 186.90999,652.57648" + id="path3092" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect2960" + inkscape:connection-end="#rect3038" /> + <rect + 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" + id="rect1872" + width="51.42857" + height="20" + x="228.51788" + y="446.68359" /> + <rect + 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" + id="rect2764" + width="51.42857" + height="20" + x="301.23218" + y="446.68359" /> + <rect + 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" + id="rect2766" + width="51.42857" + height="20" + x="155.80359" + y="446.68359" /> + <rect + 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" + id="rect2768" + width="51.42857" + height="20" + x="83.089294" + y="446.68359" /> + <path + 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" + d="M 135.01786,456.68359 L 155.30359,456.68359" + id="path2770" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect2768" + inkscape:connection-end="#rect2766" /> + <path + 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" + d="M 207.73216,456.68359 L 228.01788,456.68359" + id="path2772" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect2766" + inkscape:connection-end="#rect1872" /> + <path + 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" + d="M 280.44645,456.68359 L 300.73218,456.68359" + id="path2774" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect1872" + inkscape:connection-end="#rect2764" /> + <path + 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" + d="M 62.303571,456.68359 L 82.589294,456.68359" + id="path2778" + inkscape:connector-type="polyline" + inkscape:connection-end="#rect2768" /> + <rect + 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" + id="rect2960" + width="51.42857" + height="20" + x="228.51787" + y="511.48123" /> + <rect + 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" + id="rect2962" + width="51.42857" + height="20" + x="301.23218" + y="511.48123" /> + <rect + 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" + id="rect2964" + width="51.42857" + height="20" + x="155.80357" + y="511.48123" /> + <rect + 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" + id="rect2966" + width="51.42857" + height="20" + x="83.089287" + y="511.48123" /> + <path + 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" + d="M 135.01786,521.48121 L 155.30359,521.48121" + id="path2968" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 207.73216,521.48121 L 228.01788,521.48121" + id="path2970" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 280.44645,521.48121 L 300.73218,521.48121" + id="path2972" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 62.30358,521.48121 L 82.5893,521.48121" + id="path2974" + inkscape:connector-type="polyline" /> + <rect + 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" + id="rect2998" + width="51.42857" + height="20" + x="228.51787" + y="592.27887" /> + <rect + 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" + id="rect3000" + width="51.42857" + height="20" + x="301.23218" + y="592.27887" /> + <rect + 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" + id="rect3002" + width="51.42857" + height="20" + x="155.80357" + y="592.27887" /> + <rect + 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" + id="rect3004" + width="51.42857" + height="20" + x="83.089287" + y="592.27887" /> + <path + 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" + d="M 135.01786,602.27884 L 155.30359,602.27884" + id="path3006" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 207.73216,602.27884 L 228.01788,602.27884" + id="path3008" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 280.44645,602.27884 L 300.73218,602.27884" + id="path3010" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 62.30358,602.27884 L 82.5893,602.27884" + id="path3012" + inkscape:connector-type="polyline" /> + <rect + 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" + id="rect3034" + width="51.42857" + height="20" + x="228.51787" + y="653.07648" /> + <rect + 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" + id="rect3038" + width="51.42857" + height="20" + x="155.80357" + y="653.07648" /> + <rect + 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" + id="rect3040" + width="51.42857" + height="20" + x="83.089287" + y="653.07648" /> + <path + 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" + d="M 135.01786,663.07646 L 155.30359,663.07646" + id="path3042" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 207.73216,663.07646 L 228.01788,663.07646" + id="path3044" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 62.30358,663.07646 L 82.5893,663.07646" + id="path3048" + inkscape:connector-type="polyline" /> + <text + xml:space="preserve" + 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" + x="82.072548" + y="432.64789" + id="text3094"><tspan + sodipodi:role="line" + id="tspan3096" + x="82.072548" + y="432.64789">Changelog</tspan></text> + <text + xml:space="preserve" + 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" + x="82.306923" + y="498.97327" + id="text3098"><tspan + sodipodi:role="line" + id="tspan3100" + x="82.306923" + y="498.97327">Manifest</tspan></text> + <text + xml:space="preserve" + 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" + x="82.14286" + y="580.08569" + id="text3102"><tspan + sodipodi:role="line" + id="tspan3104" + x="82.14286" + y="580.08569">Filelogs</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/mq-collab.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,701 @@ +%\chapter{Advanced uses of Mercurial Queues} +\chapter{Mercurial Queues$B$N9bEY$J;H$$J}(B} +\label{chap:mq-collab} + +%While it's easy to pick up straightforward uses of Mercurial Queues, +%use of a little discipline and some of MQ's less frequently used +%capabilities makes it possible to work in complicated development +%environments. + +Mercurial Queues$B$NC1=c$J;H$$J}$r<h$j>e$2$?0lJ}!$>/!9$NE}@)$H(BMQ$B$N$"$^$jMQ(B +$B$$$i$l$J$$5!G=$rMQ$$$k$3$H$GJ#;($J3+H/4D6-$G$N:n6H$,2DG=$H$J$k!%(B + +%In this chapter, I will use as an example a technique I have used to +%manage the development of an Infiniband device driver for the Linux +%kernel. The driver in question is large (at least as drivers go), +%with 25,000 lines of code spread across 35 source files. It is +%maintained by a small team of developers. + +$B$3$N>O$G$O!$(BLinux$B%+!<%M%kMQ(BInfiniband$B%G%P%$%9%I%i%$%P$N3+H/$r4IM}$9$k$N$K(B +$BMQ$$$?%F%/%K%C%/$rNc$H$7$FMQ$$$k!%$3$N%I%i%$%P$O!J%I%i%$%P$H$7$F$O!KBg5,(B +$BLO$G!$(B35$B$N%=!<%9%U%!%$%k$K$o$?$k(B25000$B9T$+$i$J$k!%$3$N%=!<%9$O>.5,LO$J3+H/(B +$B<T$N%A!<%`$K$h$C$F$$;~4IM}$5$l$F$$$k!%(B + +%While much of the material in this chapter is specific to Linux, the +%same principles apply to any code base for which you're not the +%primary owner, and upon which you need to do a lot of development. + +$B$3$N>O$G$NAG:`$O(BLinux$B$KFC2=$7$F$$$k$,!$F1$886B'$O$$$+$J$k%3!<%I%Y!<%9$KBP(B +$B$7$F$bE,MQ2DG=$G!$<+J,<+?H$G=jM-$7$F$$$J$$$,!$B?$/$N3+H/$r9T$&I,MW$N$"$k(B +$B%3!<%I$J$I$K$bE,MQ$G$-$k!%(B + + +%\section{The problem of many targets} +\section{$B%?!<%2%C%H$,J#?t$"$k$H$$$&LdBj(B} + +%The Linux kernel changes rapidly, and has never been internally +%stable; developers frequently make drastic changes between releases. +%This means that a version of the driver that works well with a +%particular released version of the kernel will not even \emph{compile} +%correctly against, typically, any other version. + +Linux$B%+!<%M%k$O5^B.$KJQ2=$7!$$=$NFbIt$O7h$7$F0lDj$G$O$J$$!%3+H/<T$?$A$OIQ(B +$BHK$K%j%j!<%94V$G7`E*$JJQ99$r9T$&!%$3$N$?$a!$FCDj$N%j%j!<%9%P!<%8%g%s$GNI(B +$B$/F0$$$?%I%i%$%P$,!$Nc$($PJL$N%P!<%8%g%s$G$O@5$7$/%3%s%Q%$%k$9$k$3$H$9$i(B +$B$G$-$J$/$J$k$H$$$&$3$H$r0UL#$9$k!%(B + +%To maintain a driver, we have to keep a number of distinct versions of +%Linux in mind. + +$B%I%i%$%P$r0];}$9$k$?$a$K!$3+H/<T$O$$$/$D$b$NJL$N%P!<%8%g%s$N(BLinux$B$rA[Dj(B +$B$7$J$1$l$P$J$i$J$$!%(B +\begin{itemize} +%\item One target is the main Linux kernel development tree. + +% Maintenance of the code is in this case partly shared by other +% developers in the kernel community, who make ``drive-by'' +% modifications to the driver as they develop and refine kernel +% subsystems. +\item $B0l$D$N%?!<%2%C%H$O(BLinux$B%+!<%M%k$N3+H/%D%j!<$G$"$k!%$3$N>l9g!$%3!<%I(B + $B$N0];}4IM}$O%+!<%M%k%3%_%e%K%F%#$NB>$N3+H/<T!J$3$l$O%+!<%M%k$N%5%V(B + $B%7%9%F%`$r2~NI$9$k$?$a$K%I%i%$%P$r(B``$BDI$$N)$F$k(B''$BJQ99$r9T$&3+H/<T$G(B + $B$"$k!K$HItJ,E*$K6&M-$5$l$F$$$k!%(B +%\item We also maintain a number of ``backports'' to older versions of +% the Linux kernel, to support the needs of customers who are running +% older Linux distributions that do not incorporate our drivers. (To +% \emph{backport} a piece of code is to modify it to work in an older +% version of its target environment than the version it was developed +% for.) +\item $B3+H/<T$O2f!9$N%I%i%$%P$,AH$_9~$^$l$F$$$J$$8E$$(BLinux$B%G%#%9%H%j%S%e!<(B + $B%7%g%s$r;H$C$F$$$k8\5R$r%5%]!<%H$9$k$?$a$K!$8E$$%P!<%8%g%s$N(BLinux$B%+!<(B + $B%M%k$X$N(B``$B%P%C%/%]!<%H(B''$B$rJz$($F$$$k!%%3!<%I$N0lIt$r(B\emph{$B%P%C%/%]!<(B + $B%H(B}$B$9$k$3$H$O!$%I%i%$%P$,3+H/$5$l$?%P!<%8%g%s$h$j$b8E$$%P!<%8%g%s(B + $B$N4D6-$GF0$/$h$&$K$9$k$3$H$r0UL#$9$k!%(B +%\item Finally, we make software releases on a schedule that is +% necessarily not aligned with those used by Linux distributors and +% kernel developers, so that we can deliver new features to customers +% without forcing them to upgrade their entire kernels or +% distributions. +\item $B:G=*E*$K(BLinux$B%G%#%9%H%j%S%e!<%?$d%+!<%M%k3+H/<T$rBT$?$;$k$3$H$J$/%9(B +$B%1%8%e!<%kDL$j$K%=%U%H%&%'%"$r%j%j!<%9$9$k$3$H$,I,MW$G$"$j!$$3$l$K$h$C$F(B +$B8\5R$K%+!<%M%k$d%G%#%9%H%j%S%e!<%7%g%sA4BN$r%"%C%W%0%l!<%I$5$;$k$3$H$J$/(B +$B?75!G=$r8\5R$KFO$1$i$l$k!%(B +\end{itemize} + +%\subsection{Tempting approaches that don't work well} +\subsection{$B$d$C$F$7$^$$$,$A$J4V0c$C$?J}K!(B} + +%There are two ``standard'' ways to maintain a piece of software that +%has to target many different environments. + +$B$5$^$6$^$J4D6-$r%?!<%2%C%H$K$7$?%=%U%H%&%'%"$r4IM}$9$k(B2$B$D$NI8=`E*$JJ}K!(B +$B$,$"$k!%(B + +%The first is to maintain a number of branches, each intended for a +%single target. The trouble with this approach is that you must +%maintain iron discipline in the flow of changes between repositories. +%A new feature or bug fix must start life in a ``pristine'' repository, +%then percolate out to every backport repository. Backport changes are +%more limited in the branches they should propagate to; a backport +%change that is applied to a branch where it doesn't belong will +%probably stop the driver from compiling. + +$BBh(B1$B$NJ}K!$O!$C10l$N%?!<%2%C%H8~$1$NJ#?t$N%V%i%s%A$r0];}$9$k$3$H$G$"$k!%$3(B +$B$NJ}K!$NLdBjE@$O!$%j%]%8%H%j4V$G$NJQ99$NN.$l$K$D$$$F873J$J5,N'$r0];}$7$J(B +$B$1$l$P$J$i$J$$$3$H$G$"$k!%?75!G=$d%P%0=$@5$O!$$-$l$$$J>uBV$N%j%]%8%H%j$G(B +$B3+;O$7!$%P%C%/%]!<%H%j%]%8%H%j$K?;F)$9$kI,MW$,$"$k!%%P%C%/%]!<%HJQ99$OGH(B +$B5Z$9$Y$-%V%i%s%AFb$K8BDj$5$l$F$$$J$1$l$P$J$i$J$$!%I,MW$N$J$$%V%i%s%A$X$N(B +$B%P%C%/%]!<%H$NGH5Z$O$*$=$i$/%I%i%$%P$r%3%s%Q%$%kITG=$K$7$F$7$^$&$@$m$&!%(B + +%The second is to maintain a single source tree filled with conditional +%statements that turn chunks of code on or off depending on the +%intended target. Because these ``ifdefs'' are not allowed in the +%Linux kernel tree, a manual or automatic process must be followed to +%strip them out and yield a clean tree. A code base maintained in this +%fashion rapidly becomes a rat's nest of conditional blocks that are +%difficult to understand and maintain. + +$BBh(B2$B$NJ}K!$O!$%A%c%s%/$d%3!<%I$r!$L\E*$H$9$k%?!<%2%C%HKh$K(Bon/off$B$9$k>r7oJ8(B +$B$rDI2C$7$?C10l$N%=!<%9%D%j!<$r0];}$9$kJ}K!$G$"$k!%$3$l$i$N(B``ifdef''$B$O(B +linux$B%+!<%M%k%D%j!<$G$O5v$5$l$F$$$J$$$?$a!$<jF0$^$?$O<+F0$G$3$l$i$N%3!<%I(B +$B$r=|5n$7!$%/%j!<%s$J%D%j!<$r:n$k%W%m%;%9$,I,MW$K$J$k!%$3$N$h$&$J$d$jJ}$G(B +$B4IM}$5$l$?%3!<%I%Y!<%9$O$9$0$K>r7o@a$NAc7"$H2=$7!"M}2r$d4IM}$NK8$2$H$J$k!#(B + +%Neither of these approaches is well suited to a situation where you +%don't ``own'' the canonical copy of a source tree. In the case of a + +%Linux driver that is distributed with the standard kernel, Linus's +%tree contains the copy of the code that will be treated by the world +%as canonical. The upstream version of ``my'' driver can be modified +%by people I don't know, without me even finding out about it until +%after the changes show up in Linus's tree. + +$B$"$J$?$,@5<0$J%=!<%9%D%j!<$r=jM-$7$F$$$k$N$G$J$1$l$P!"$3$l$i$N$d$jJ}$N$I(B +$B$A$i$b$=$0$o$J$$$@$m$&!#I8=`$N(Blinux$B%+!<%M%k$KF1:-$5$l$F$$$k%I%i%$%P$N>l(B +$B9g!$(BLinus$B$N%D%j!<$O@$3&Cf$G@5<0$J%3!<%I$H$7$F07$o$l$k%3%T!<$r4^$s$G$$$k!%(B +``$B;d(B''$B$N%I%i%$%P$N>eN.HG$O!$CN$i$J$$?M$K$h$C$FJQ99$5$lF@$k$7!$<+J,$NJQ99(B +$B$,(BLinus$B$N%D%j!<$KF~$C$?$"$H$G$5$($bJQ99$5$lF@$k!%(B + +%These approaches have the added weakness of making it difficult to +%generate well-formed patches to submit upstream. + +$B$3$l$i$N%"%W%m!<%A$O!$$&$^$/=q$+$l$?%Q%C%A$r>eN.$XDs=P$9$k$3$H$r:$Fq$K$7(B +$B$F$7$^$&!%(B + +%In principle, Mercurial Queues seems like a good candidate to manage a +%development scenario such as the above. While this is indeed the +%case, MQ contains a few added features that make the job more +%pleasant. + +Mercurial Queues$B$O>e5-$N$h$&$J3+H/%7%J%j%*$r4IM}$9$k$h$$8uJd$N0l$D$G$"$k(B +$B$H$$$($k!%$3$N$h$&$J>l9g$N$?$a$K(BMQ$B$K$O:n6H$r$h$j2wE,$K$9$k$$$/$D$+$N5!G=(B +$B$,$"$k!%(B + +%\section{Conditionally applying patches with guards} +\section{$B%,!<%I$r;H$C$?%Q%C%A$N>r7oE*$JE,MQ(B} + +%Perhaps the best way to maintain sanity with so many targets is to be +%able to choose specific patches to apply for a given situation. MQ +%provides a feature called ``guards'' (which originates with quilt's +%\texttt{guards} command) that does just this. To start off, let's +%create a simple repository for experimenting in. +%\interaction{mq.guards.init} +%This gives us a tiny repository that contains two patches that don't +%have any dependencies on each other, because they touch different files. + +$BB?$/$N%?!<%2%C%H$rBP>]$H$7$J$,$i@5>o$KJ]$D0lHVNI$$J}J}$O!$>u67$K1~$8$FFC(B +$BDj$N%Q%C%A$rA*$Y$k$h$&$K$9$k$3$H$G$"$k!%(BMQ$B$O$3$NL\E*$N$?$a$K(Bquilt$B$N(B +\texttt{guards}$B%3%^%s%I$KN`;w$7$?(B``guards''$B$H8F$P$l$k5!G=$rDs6!$7$F$$$k!%(B +$B3+;O$KEv$?$C$F!$<B83$N$?$a$KC1=c$J%j%]%8%H%j$r:n@.$9$k!%(B +\interaction{mq.guards.init} +$B>.$5$J%j%]%8%H%j$r:n$j!$JL!9$N%U%!%$%k$rA`:n$9$k8_$$$K0MB8@-$N$J$$(B2$B$D$N%Q%C(B +$B%A$rCV$/!%(B + +%The idea behind conditional application is that you can ``tag'' a +%patch with a \emph{guard}, which is simply a text string of your +%choosing, then tell MQ to select specific guards to use when applying +%patches. MQ will then either apply, or skip over, a guarded patch, +%depending on the guards that you have selected. + +$B>r7oIU$-$G%Q%C%A%Q%C%A$NE,MQ$r%3%s%H%m!<%k$9$kJ}K!$NGX8e$K$"$k$N(B +$B$O!$(B\emph{guard}$B$K$h$C$F%Q%C%A$KIU$1$i$l$?(B``$B%?%0(B''$B$G$"$k!%%?%0$O<+M3$KA*(B +$B$s$@C1=c$J%F%-%9%H$G!$(BMQ$B$,%Q%C%A$rE,MQ$9$k$H$-$KMQ$$$kFCDj$N%,!<%I$r;XDj(B +$B$9$k!%(BMQ$B$O%,!<%I%Q%C%A$NE,MQ$^$?$O%9%-%C%W$r!$;XDj$5$l$?%,!<%I$K$h$C$F7h(B +$BDj$9$k!%(B + +%A patch can have an arbitrary number of guards; +%each one is \emph{positive} (``apply this patch if this guard is +%selected'') or \emph{negative} (``skip this patch if this guard is +%selected''). A patch with no guards is always applied. + +$B%Q%C%A$OG$0U$N?t$N%,!<%I$r;}$D$3$H$,$G$-$k!%3F!9$N%,!<%I(B +$B$O!$(B\emph{positive}$B!J$3$N%,!<%I$,A*Br$5$l$F$$$k$H$-$K$3$N%Q%C%A$rE,MQ!K$^(B +$B$?$O(B\emph{negative}$B!J$3$N%,!<%I$,A*Br$5$l$F$$$k$H$-$K$3$N%Q%C%A$r%9%-%C(B +$B%W!K$G$"$k!%%,!<%I$r;}$?$J$$%Q%C%A$O>o$KE,MQ$5$l$k!%(B + +%\section{Controlling the guards on a patch} +\section{$B%Q%C%AFb$N%,!<%I$rA`:n$9$k(B} + +%The \hgxcmd{mq}{qguard} command lets you determine which guards should +%apply to a patch, or display the guards that are already in effect. +%Without any arguments, it displays the guards on the current topmost +%patch. +%\interaction{mq.guards.qguard} +%To set a positive guard on a patch, prefix the name of the guard with +%a ``\texttt{+}''. +%\interaction{mq.guards.qguard.pos} +%To set a negative guard on a patch, prefix the name of the guard with +%a ``\texttt{-}''. +%\interaction{mq.guards.qguard.neg} + +\hgxcmd{mq}{qguard}$B%3%^%s%I$G$I$N%,!<%I$,%Q%C%A$KE,MQ$5$l$k$+$r;XDj$7$?(B +$B$j!$$9$G$KM-8z$K$J$C$F$$$k%,!<%I$rI=<($5$;$k$3$H$,$G$-$k!%0z?t$J$7$G$3$N(B +$B%3%^%s%I$r;H$&$H!$8=:_$N:G>e0L$N%Q%C%A$N%,!<%I$rI=<($9$k!%(B +\interaction{mq.guards.qguard} +$B%Q%C%A$K%]%8%F%#%V%,!<%I$r@_Dj$9$k$K$O!$%,!<%IL>$NA0$K(B``\texttt{+}''$B$r$D(B +$B$1$k!%(B +\interaction{mq.guards.qguard.pos} +$B%Q%C%A$K%M%,%F%#%V%,!<%I$r@_Dj$9$k$K$O!$%,!<%IL>$NA0$K(B``\texttt{-}''$B$r$D(B +$B$1$k!%(B +\interaction{mq.guards.qguard.neg} + +%\begin{note} +% The \hgxcmd{mq}{qguard} command \emph{sets} the guards on a patch; it +% doesn't \emph{modify} them. What this means is that if you run +% \hgcmdargs{qguard}{+a +b} on a patch, then \hgcmdargs{qguard}{+c} on +% the same patch, the \emph{only} guard that will be set on it +% afterwards is \texttt{+c}. +%\end{note} + +\begin{note} + \hgxcmd{mq}{qguard} $B%3%^%s%I$O%Q%C%A$K%,!<%I$r(B\emph{$B@_Dj$9$k(B}$B$,%Q%C%A<+(B + $BBN$r(B\emph{$BJQ99$7$J$$(B}$BE@$KCm0U$5$l$?$$!%%Q%C%A$KBP$7$F(B + \hgcmdargs{qguard}{+a +b}$B$r<B9T$7!$F1$8%Q%C%A$K(B\hgcmdargs{qguard}{+c}$B$r(B + $B<B9T$9$k$H!$$3$N%Q%C%A$X$N%,!<%I$O(B\texttt{+c}$B$N$_$K$J$k!%(B +\end{note} + +%Mercurial stores guards in the \sfilename{series} file; the form in +%which they are stored is easy both to understand and to edit by hand. +%(In other words, you don't have to use the \hgxcmd{mq}{qguard} command if +%you don't want to; it's okay to simply edit the \sfilename{series} +%file.) +%\interaction{mq.guards.series} + +Mercurial$B$O%,!<%I$r(B\sfilename{series}$B%U%!%$%k$KJ]B8$9$k!%=q<0$OM}2r$7$d(B +$B$9$/!$<j$GJQ99$9$k$N$b4JC1$G$"$k!%!J$D$^$j!$(B\hgxcmd{mq}{qguard}$B%3%^%s%I(B +$B$r;H$$$?$/$J$1$l$P!$D>@\(B\sfilename{series}$B$rJT=8$7$F:Q$^$9$3$H$b$G$-$k!%!K(B +\interaction{mq.guards.series} + +%\section{Selecting the guards to use} +\section{$B;HMQ$9$k%,!<%I$rA*$V(B} + +%The \hgxcmd{mq}{qselect} command determines which guards are active at a +%given time. The effect of this is to determine which patches MQ will +%apply the next time you run \hgxcmd{mq}{qpush}. It has no other effect; in +%particular, it doesn't do anything to patches that are already +%applied. + +\hgxcmd{mq}{qselect}$B%3%^%s%I$r<B9T$9$k$3$H$G!$$=$N;~E@$G%"%/%F%#%V$J%,!<(B +$B%I$r;XDj$9$k$3$H$,$G$-$k!%$3$N%3%^%s%I$K$h$C$F!$<!$K(B\hgxcmd{mq}{qpush}$B$,(B +$B<B9T$5$l$?$H$-$K$I$N%Q%C%A$,(BMQ$B$K$h$C$FE,MQ$5$l$k$+$,;XDj$5$l$k!%$=$l0J30(B +$B$N8z2L$O$J$/!$FC$K$9$G$KE,MQ$5$l$F$$$k%Q%C%A$KBP$7$F$O2?$b9T$o$J$$!%(B + +%With no arguments, the \hgxcmd{mq}{qselect} command lists the guards +%currently in effect, one per line of output. Each argument is treated +%as the name of a guard to apply. +%\interaction{mq.guards.qselect.foo} +%In case you're interested, the currently selected guards are stored in +%the \sfilename{guards} file. +%\interaction{mq.guards.qselect.cat} +%We can see the effect the selected guards have when we run +%\hgxcmd{mq}{qpush}. +%\interaction{mq.guards.qselect.qpush} + +$B0z?t$J$7$G(B\hgxcmd{mq}{qselect}$B%3%^%s%I$r<B9T$9$k$H!$8=:_M-8z$J%,!<%I$N%j(B +$B%9%H$r(B1$B9T$K(B1$B$D$:$DI=<($9$k!%3F!9$N0z?t$OE,MQ$5$l$k%,!<%I$NL>A0$H$7$F2r<a(B +$B$5$l$k!%(B +\interaction{mq.guards.qselect.foo} +$B8=:_A*Br$5$l$F$$$k%,!<%I$K6=L#$,$"$k>l9g!$$3$l$O(B\sfilename{guards}$B%U%!%$(B +$B%k$KJ]B8$5$l$F$$$k!%(B +\interaction{mq.guards.qselect.cat} +$BA*Br$5$l$?%,!<%I$N8z2L$O(B\hgxcmd{mq}{qpush}$B$N<B9T;~$K8+$k$3$H$,$G$-$k!%(B +\interaction{mq.guards.qselect.qpush} + +%A guard cannot start with a ``\texttt{+}'' or ``\texttt{-}'' +%character. The name of a guard must not contain white space, but most +%othter characters are acceptable. If you try to use a guard with an +%invalid name, MQ will complain: +%\interaction{mq.guards.qselect.error} +%Changing the selected guards changes the patches that are applied. +%\interaction{mq.guards.qselect.quux} +%You can see in the example below that negative guards take precedence +%over positive guards. +%\interaction{mq.guards.qselect.foobar} + +$B%,!<%I$r(B``\texttt{+}''$B$d(B``\texttt{-}''$B$NJ8;z$G;O$a$k$3$H$O$G$-$J$$!%%,!<(B +$B%IL>$O6uGr$r4^$s$G$O$J$i$J$$$,!$$=$NB>$NKX$s$I$NJ8;z$r4^$`$3$H$,$G$-$k!%(B +$B$b$7;HMQIT2D$NJ8;z$r4^$`>l9g$O!"(BMQ$B$,7Y9p$rI=<($9$k!#(B +\interaction{mq.guards.qselect.error} +$BA*Br$5$l$?%,!<%I$rJQ99$9$k$3$H$O!"E,MQ$5$l$k%Q%C%A$NJQ99$r0UL#$9$k!#(B +\interaction{mq.guards.qselect.quux} +$B2<$NNc$G%M%,%F%#%V%,!<%I$,%]%8%F%#%V%,!<%I$h$j$bM%@hEY$r;}$D$3$H$,$o$+$k!#(B +\interaction{mq.guards.qselect.foobar} + +%\section{MQ's rules for applying patches} +\section{MQ$B$N%Q%C%AE,MQ%k!<%k(B} + +%The rules that MQ uses when deciding whether to apply a patch +%are as follows. +MQ$B$,E,MQ$9$k%Q%C%A$r7hDj$9$k5,B'$O2<5-$N$H$*$j$G$"$k!#(B +%\begin{itemize} +%\item A patch that has no guards is always applied. +%\item If the patch has any negative guard that matches any currently +% selected guard, the patch is skipped. +%\item If the patch has any positive guard that matches any currently +% selected guard, the patch is applied. +%\item If the patch has positive or negative guards, but none matches +% any currently selected guard, the patch is skipped. +%\end{itemize} +\begin{itemize} +\item $B%,!<%I$N$J$$%Q%C%A$O>o$KE,MQ$9$k(B +\item $B%Q%C%A$K8=:_A*Br$5$l$F$$$k%,!<%I$K%^%C%A$9$k%M%,%F%#%V%,!<%I$,$"$l(B + $B$P!"$=$N%Q%C%A$r%9%-%C%W$9$k(B +\item $B%Q%C%A$K8=:_A*Br$5$l$F$$$k%,!<%I$K%^%C%A$9$k%]%8%F%#%V%,!<%I$,$"$l(B + $B$P!"$=$N%Q%C%A$rE,MQ$9$k(B +\item $B%Q%C%A$,%]%8%F%#%V!&%M%,%F%#%V$$$:$l$+$N%,!<%I$r;}$D$,!"8=:_A*Br$5(B + $B$l$F$$$k%,!<%I$H%^%C%A$9$k$b$N$,$J$1$l$P!"$=$N%Q%C%A$r%9%-%C%W$9$k(B +\end{itemize} + +%\section{Trimming the work environment} +\section{$B:n6H4D6-$r=L>.$9$k(B} + +%In working on the device driver I mentioned earlier, I don't apply the +%patches to a normal Linux kernel tree. Instead, I use a repository +%that contains only a snapshot of the source files and headers that are +%relevant to Infiniband development. This repository is~1\% the size +%of a kernel repository, so it's easier to work with. + +$B0JA08@5Z$7$?%G%P%$%9%I%i%$%P$G$N:n6H$G$O!"(BLinux$B%+!<%M%k%D%j!<$K%Q%C%A$rE,(B +$BMQ$7$F$$$J$+$C$?!%$=$NBe$o$j!$(BInfiniband$B%I%i%$%P$N3+H/$K4XO"$7$?%=!<%9$H(B +$B%X%C%@%U%!%$%k$@$1$r;}$D%j%]%8%H%j$rMQ$$$?!%$3$N%j%]%8%H%j$O%+!<%M%k%j%](B +$B%8%H%j$N(B~1\%$B$[$I$N%5%$%:$G!$:n6H$,MF0W$G$"$k!%(B + +%I then choose a ``base'' version on top of which the patches are +%applied. This is a snapshot of the Linux kernel tree as of a revision +%of my choosing. When I take the snapshot, I record the changeset ID +%from the kernel repository in the commit message. Since the snapshot +%preserves the ``shape'' and content of the relevant parts of the +%kernel tree, I can apply my patches on top of either my tiny +%repository or a normal kernel tree. + +$B$3$3$G%Q%C%A$rE,MQ$9$k$?$a$N(B``base''$B%P!<%8%g%s$rA*$V!%$3$l$OG$0U$KA*$s$@(B +Linux$B%+!<%M%k%D%j!<$N%9%J%C%W%7%g%C%H$G!$:n@.$9$k:]!$%+!<%M%k%j%]%8%H%j$N(B +$B%A%'%s%8%;%C%H(BID$B$r%3%_%C%H%a%C%;!<%8$K5-O?$7$F$*$/!%%9%J%C%W%7%g%C%H$O%+!<(B +$B%M%k%D%j!<$N4XO"$9$kItJ,$N867?$rJ]$C$F$$$k$?$a!$<+J,$N%Q%C%A$r3+H/MQ$N8D(B +$BJL$N%j%]%8%H%j$KE,MQ$9$k$N$HF1MM$KDL>o$N%+!<%M%k%D%j!<$KE,MQ$9$k$3$H$,$G(B +$B$-$k!%(B + +%Normally, the base tree atop which the patches apply should be a +%snapshot of a very recent upstream tree. This best facilitates the +%development of patches that can easily be submitted upstream with few +%or no modifications. + +$BDL>o!$%Q%C%A$,E,MQ$5$l$k%Y!<%9%D%j!<$O>eN.$N%D%j!<$N$4$/:G6a$N%9%J%C%W(B +$B%7%g%C%H$G$"$k$Y$-$@!%$3$&$9$k$3$H$G!$3+H/$7$?%Q%C%A$r=$@5$9$k$3$H$J$/!$(B +$B$"$k$$$O$4$/6O$+$J=$@5$N$_$G!$>eN.$XDs=P$9$k$3$H$,2DG=$K$J$k!%(B + +%\section{Dividing up the \sfilename{series} file} +\section{\sfilename{series}$B%U%!%$%k$rJ,3d$9$k(B} + +%I categorise the patches in the \sfilename{series} file into a number +%of logical groups. Each section of like patches begins with a block +%of comments that describes the purpose of the patches that follow. + +$BI.<T$O(B\sfilename{series}$B%U%!%$%k$N%Q%C%A$r$$$/$D$+$NO@M}E*$J%0%k!<%W$K%+(B +$B%F%4%i%$%:$7$F$$$k!%%Q%C%A$N$=$l$>$l$N%;%/%7%g%s$O$"$H$KB3$/%Q%C%A$,2?$G(B +$B$"$k$+@bL@$9$k%3%a%s%H%V%m%C%/$G;O$^$C$F$$$k!%(B + +%The sequence of patch groups that I maintain follows. The ordering of +%these groups is important; I'll describe why after I introduce the +%groups. +$B$=$N8e$K%a%s%F%J%s%9$7$F$$$k%Q%C%A%0%k!<%W$,O"$J$k!%%0%k!<%W$r@0M}$9$k$3(B +$B$H$O=EMW$G$"$k!%$^$:%0%k!<%W$K$D$$$F@bL@$7$?8e!$$3$NM}M3$K?($l$k!%(B + +\begin{itemize} +%\item The ``accepted'' group. Patches that the development team has +% submitted to the maintainer of the Infiniband subsystem, and which +% he has accepted, but which are not present in the snapshot that the +% tiny repository is based on. These are ``read only'' patches, +% present only to transform the tree into a similar state as it is in +% the upstream maintainer's repository. +\item ``accepted''$B%0%k!<%W!%3+H/%A!<%`$,(BInfiniband$B%5%V%7%9%F%`$N%a%s%F%J(B + $B$KDs=P$7!$<uM}$5$l$?$,!$>.%j%]%8%H%j$N%Y!<%9$H$J$C$F$$$k%9%J%C%W(B + $B%7%g%C%H$K$O$^$@<h$j9~$^$l$F$$$J$$$b$N!%$3$l$i$O%D%j!<$r>eN.%a%s%F(B + $B%J$N%j%]%8%H%j$HF1MM$N>uBV$K$9$k$?$a$KB8:_$9$k(B``$BFI$_=P$7$N$_(B''$B$N%Q%C(B + $B%A$G$"$k!%(B +%\item The ``rework'' group. Patches that I have submitted, but that +% the upstream maintainer has requested modifications to before he +% will accept them. +\item ``rework''$B%0%k!<%W!%Ds=P$7$?$,>eN.%a%s%F%J$,<uM}$K@h$@$C$FJQ99$rMW(B + $B5a$7$?$b$N!%(B +%\item The ``pending'' group. Patches that I have not yet submitted to +% the upstream maintainer, but which we have finished working on. +% These will be ``read only'' for a while. If the upstream maintainer +% accepts them upon submission, I'll move them to the end of the +% ``accepted'' group. If he requests that I modify any, I'll move +% them to the beginning of the ``rework'' group. +\item ``pending''$B%0%k!<%W!%>eN.%a%s%F%J$K$O$^$@Ds=P$7$F$$$J$$$,!$<j85$G(B + $B$N:n6H$O40N;$7$?$b$N!%$3$l$i$O$7$P$i$/$N4V(B``read only''$B$K$J$C$F$*(B + $B$j!$>eN.$N%a%s%F%J$XDs=P$7$F<uM}$5$l$?;~$O(B``accepted''$B%0%k!<%W$X0\(B + $BF0$5$l$k!%%a%s%F%J$,JQ99$rMW5a$7$?>l9g$O(B``rework''$B%0%k!<%W$X0\F0$5(B + $B$l$k!%(B +%\item The ``in progress'' group. Patches that are actively being +% developed, and should not be submitted anywhere yet. +\item ``in progress''$B%0%k!<%W!%$3$N%0%k!<%W$K$O!$%"%/%F%#%V$K3+H/$5(B + $B$l$F$*$j!$$^$@$I$3$X$bDs=P$5$l$k$Y$-$G$O$J$$%Q%C%A$,4^$^$l$k!%(B +%\item The ``backport'' group. Patches that adapt the source tree to +% older versions of the kernel tree. +\item ``backport''$B%0%k!<%W!%%=!<%9$r8E$$%P!<%8%g%s$N%+!<%M%k%D%j!<$XE,9g(B + $B$5$;$k%Q%C%A$+$i$J$k!%(B +%\item The ``do not ship'' group. Patches that for some reason should +% never be submitted upstream. For example, one such patch might +% change embedded driver identification strings to make it easier to +% distinguish, in the field, between an out-of-tree version of the +% driver and a version shipped by a distribution vendor. +\item ``do not ship''$B%0%k!<%W!%$J$s$i$+$NM}M3$K$h$C$F7h$7$F>eN.$XDs=P$5$l(B + $B$k$Y$-$G$J$$%Q%C%A$+$i$J$k!%Nc$($P!$%D%j!<30$N%I%i%$%P$H%Y%s%@$K$h$C(B + $B$FG[I[$5$l$F$$$k%I%i%$%P$r<1JL$7$d$9$/$9$k$?$a$K%I%i%$%P$N<1JLJ8;z(B + $BNs$rJQ99$9$k$h$&$J%Q%C%A$,3:Ev$9$k!%(B +\end{itemize} + +%Now to return to the reasons for ordering groups of patches in this +%way. We would like the lowest patches in the stack to be as stable as +%possible, so that we will not need to rework higher patches due to +%changes in context. Putting patches that will never be changed first +%in the \sfilename{series} file serves this purpose. + +$B%Q%C%A$r$3$N$h$&$JJ}K!$G@0M}$9$kM}M3$N@bL@$XLa$m$&!%0lHL$K!$%Q%C%A%9%?%C(B +$B%/$NDl$K$"$k%Q%C%A$O$J$k$Y$/0BDj$G$"$C$FM_$7$$$H;W$&$b$N$@!%$=$&$G$"$l(B +$B$P!$%Q%C%A$N%3%s%F%-%9%H$GJQ99$K$h$k:F:n6H$r$;$:$K:Q$`!%(B +\sfilename{series}$B$K:G=i$KDI2C$9$k%Q%C%A$O7h$7$FJQ99$5$l$J$$$b$N$K$9$k$H(B +$B$h$$!%(B + +%We would also like the patches that we know we'll need to modify to be +%applied on top of a source tree that resembles the upstream tree as +%closely as possible. This is why we keep accepted patches around for +%a while. + +$B$^$?!$E,MQ$N$?$a$KJQ99$7$J$1$l$P$J$i$J$$%Q%C%A$K$D$$$F$O!$$G$-$k$@$1>eN.(B +$B$N%D%j!<$K6a$$%=!<%9%D%j!<$KE,MQ$G$-$k$h$&$K$J$C$F$$$FM_$7$$$H9M$($k!%$3(B +$B$l$,<uM}$5$l$?%Q%C%A$r$7$P$i$/$N4VJ];}$7$F$$$kM}M3$G$"$k!%(B + +%The ``backport'' and ``do not ship'' patches float at the end of the +%\sfilename{series} file. The backport patches must be applied on top +%of all other patches, and the ``do not ship'' patches might as well +%stay out of harm's way. + +``backport''$B$H(B``do not ship''$B%Q%C%A$O(B\sfilename{series}$B%U%!%$%k$NKvHx$KCV(B +$B$+$l$k!%(B``backport''$B%Q%C%A$OB>$N%Q%C%A$9$Y$F$N>e$+$iE,MQ$5$l$J$1$l$P$J$i(B +$B$J$$$7!$(B``do not ship''$B%Q%C%A$O0BA4$J$H$3$m$KCV$+$l$F$$$J$1$l$P$J$i$J$$!%(B + +%\section{Maintaining the patch series} +\section{$B%Q%C%A%7%j!<%:$r4IM}$9$k(B} + +%In my work, I use a number of guards to control which patches are to +%be applied. + +$B$3$N:n6H$G$O!$$I$N%Q%C%A$,E,MQ$5$l$k$+@)8f$9$k$?$a$K$$$/$D$+$N%,!<%I$rMQ(B +$B$$$F$$$k!%(B + +\begin{itemize} +%\item ``Accepted'' patches are guarded with \texttt{accepted}. I +% enable this guard most of the time. When I'm applying the patches +% on top of a tree where the patches are already present, I can turn +% this patch off, and the patches that follow it will apply cleanly. + +\item ``Accepted''$B%Q%C%A$O(B\texttt{accepted}$B$K$h$C$F%,!<%I$5$l$F$$$k!%I.<T(B +$B$O$3$N%,!<%I$r$[$\$$$D$bM-8z$K$7$F$$$k!%$9$G$K%Q%C%A$,B8:_$7$F$$$k%D%j!<(B +$B$N>e$K?7$?$J%Q%C%A$rE,MQ$9$k;~$O!$$3$N%Q%C%A$r%*%U$K$7$F!$8eB3$N%Q%C%A$,(B +$B%/%j!<%s$KE,MQ$5$l$k$h$&$K$9$k$3$H$,$G$-$k!%(B + +%\item Patches that are ``finished'', but not yet submitted, have no +% guards. If I'm applying the patch stack to a copy of the upstream +% tree, I don't need to enable any guards in order to get a reasonably +% safe source tree. + +\item $B40@.$5$l$F$$$k$b$N$N!$$^$@Ds=P$5$l$F$$$J$$%Q%C%A$O%,!<%I$r;}$?$J(B + $B$$!%$3$N%Q%C%A%9%?%C%/$r>eN.%D%j!<$N%3%T!<$KE,MQ$9$k>l9g!$%,!<%I$r(B + $BA4$/;H$o$:$K==J,0BA4$J%=!<%9%D%j!<$rF@$k$3$H$,$G$-$k!%(B + +%\item Those patches that need reworking before being resubmitted are +% guarded with \texttt{rework}. + + \item $B:FDs=P$N$?$a$K:n6H$,I,MW$J%Q%C%A$K$O(B\texttt{rework}$B%,!<%I$rMQ$$$k!%(B + +%\item For those patches that are still under development, I use +% \texttt{devel}. + + \item $B3+H/Cf$N%Q%C%A$K$O(B\texttt{devel}$B%,!<%I$rMQ$$$F$$$k!%(B + +%\item A backport patch may have several guards, one for each version +% of the kernel to which it applies. For example, a patch that +% backports a piece of code to~2.6.9 will have a~\texttt{2.6.9} guard. + + \item $B%P%C%/%]!<%H%Q%C%A$O%Q%C%A$,E,MQ$5$l$k%+!<%M%k$N%P!<%8%g%s$=$l$>$l(B + $B$KBP$7$F%,!<%I$r;}$D$3$H$,$"$k!%Nc$($P!$$"$k%3!<%I$r(B~2.6.9$B$K%P%C%/(B + $B%]!<%H$9$k%Q%C%A$O(B~\texttt{2.6.9}$B$H$$$&%,!<%I$r;}$D!%(B +\end{itemize} +%This variety of guards gives me considerable flexibility in +%determining what kind of source tree I want to end up with. For most +%situations, the selection of appropriate guards is automated during +%the build process, but I can manually tune the guards to use for less +%common circumstances. + +$BB?$/$N%,!<%I$rMQ$$$k$3$H$K$h$C$F!$=@Fp$K:n6HBP>]$N%=!<%9%D%j!<$rA*$V$3$H(B +$B$,$G$-$k!%%S%k%I=hM}Cf$K@5$7$$%,!<%I$r<+F0E*$KA*Br$G$-$k$3$H$,$[$H$s$I$@(B +$B$,!$FC<l$J>u67$N$?$a$K<j$GA*$V$3$H$b2DG=$G$"$k!%(B + +%\subsection{The art of writing backport patches} +\subsection{$B%P%C%/%]!<%H%Q%C%A$r=q$/5;=Q(B} + +%Using MQ, writing a backport patch is a simple process. All such a +%patch has to do is modify a piece of code that uses a kernel feature +%not present in the older version of the kernel, so that the driver +%continues to work correctly under that older version. + +MQ$B$r;H$C$F%P%C%/%]!<%H%Q%C%A$r=q$/$N$OC1=c$J:n6H$G$"$k!%$=$N$h$&$J%Q%C%A(B +$B$,$9$Y$-$3$H$O!$8E$$%P!<%8%g%s$N%+!<%M%k$KHw$o$C$F$$$J$$5!G=$r;H$&%3!<%I(B +$B$rJQ99$7!$8E$$%P!<%8%g%s$N%+!<%M%k$G$b@5$7$/5!G=$7B3$1$k$h$&$K$9$k$3$H$@(B +$B$1$G$"$k!%(B + +%A useful goal when writing a good backport patch is to make your code +%look as if it was written for the older version of the kernel you're +%targeting. The less obtrusive the patch, the easier it will be to +%understand and maintain. If you're writing a collection of backport +%patches to avoid the ``rat's nest'' effect of lots of +%\texttt{\#ifdef}s (hunks of source code that are only used +%conditionally) in your code, don't introduce version-dependent +%\texttt{\#ifdef}s into the patches. Instead, write several patches, +%each of which makes unconditional changes, and control their +%application using guards. + +$B$h$$%P%C%/%]!<%H%Q%C%A$H$O!$$=$N%Q%C%A$K$h$C$F$"$?$+$b%3!<%I$,%?!<%2%C%H(B +$B$N8E$$%P!<%8%g%s$N%+!<%M%k$K8~$1$F=q$+$l$?$h$&$J>uBV$K$J$k$b$N$G$"$k!%(B +$BL5M}$N$J$$%Q%C%A$OM}2r$7$d$9$/!$%a%s%F%J%s%9$bMF0W$G$"$k!%(B +$B%P%C%/%]!<%H%Q%C%A$r$$$/$D$b=q$$$F$$$k$J$i$P!$%3!<%IFb$NBgNL$N(B +\texttt{\#ifdef}$B$G>r7oE*%3%s%Q%$%k$5$l$k%3!<%I$K$h$k:.Mp$rHr$1$k$Y$-$G$"(B +$B$k!%$=$N$?$a$K%P!<%8%g%s$K0MB8$7$?(B\texttt{\#ifdef}$B$G$O$J$/!$%,!<%I$K$h$C(B +$B$F@)8f$5$l$k>r7o%3%s%Q%$%k$K$h$i$J$$JQ99$r2C$($k$Y$-$G$"$k!%(B + +%There are two reasons to divide backport patches into a distinct +%group, away from the ``regular'' patches whose effects they modify. +%The first is that intermingling the two makes it more difficult to use +%a tool like the \hgext{patchbomb} extension to automate the process of +%submitting the patches to an upstream maintainer. The second is that +%a backport patch could perturb the context in which a subsequent +%regular patch is applied, making it impossible to apply the regular +%patch cleanly \emph{without} the earlier backport patch already being +%applied. + +$B%P%C%/%]!<%H%Q%C%A$rDL>o$NJQ99$r2C$($k%Q%C%A$HJL$N%0%k!<%W$KJ,3d$9$kM}M3(B +$B$,(B2$B$D$"$k!%Bh0l$NM}M3$O!$(B2$B$D$r:.$<9g$o$;$k$3$H$G!$>eN.$N%a%s%F%J$X%Q%C%A(B +$B$rDs=P$9$k$?$a$K(B\hgext{patchbomb}$B%(%/%9%F%s%7%g%s$N$h$&$J%D!<%k$r;H$&$N$,(B +$BFq$7$/$J$k$3$H$G$"$k!%BhFs$NM}M3$O!$%P%C%/%]!<%H%Q%C%A$O!$8eB3$NDL>o%Q%C(B +$B%A$NE,MQ$5$l$k%3%s%F%-%9%H$rMp$9$3$H$,$"$j!$$=$N$h$&$J>l9g!$DL>o%Q%C%A$O(B +$B%P%C%/%]!<%H%Q%C%A$J$7$K@5$7$/E,MQ$9$k$3$H$,IT2DG=$K$J$C$F$7$^$&!%(B + +%\section{Useful tips for developing with MQ} +\section{MQ$B$K$h$k3+H/$N(Btips} + +%\subsection{Organising patches in directories} +\subsection{$B%G%#%l%/%H%jFb$G%Q%C%A$r4IM}$9$k(B} + +%If you're working on a substantial project with MQ, it's not difficult +%to accumulate a large number of patches. For example, I have one +%patch repository that contains over 250 patches. + +MQ$B$rMQ$$$FHf3SE*Bg5,LO$J%W%m%8%'%/%H$G:n6H$7$F$$$k>l9g!$BgNL$N%Q%C%A$,C_(B +$B@Q$9$k$3$H$,>/$J$/$J$$!%Nc$($PI.<T$N$H$3$m$K$O!$(B250$B0J>e$N%Q%C%A$r4^$`%Q%C(B +$B%A%j%]%8%H%j$,$"$k!%(B + +%If you can group these patches into separate logical categories, you +%can if you like store them in different directories; MQ has no +%problems with patch names that contain path separators. + +$B$b$7$3$l$i$N%Q%C%A$rO@M}E*$J%+%F%4%j$KJ,3d$9$k$3$H$,$G$-!$JL!9$N%G%#%l%/(B +$B%H%j$K<}MF$7$?$$$H9M$($k$J$i$P!$%Q%C%AL>$K%Q%9%;%Q%l!<%?$r4^$a$F$b(BMQ$B$OLd(B +$BBj$J$/<h$j07$&$3$H$,$G$-$k!%(B + +%\subsection{Viewing the history of a patch} +\subsection{$B%Q%C%A$N%R%9%H%j$r8+$k(B} +\label{mq-collab:tips:interdiff} + +%If you're developing a set of patches over a long time, it's a good +%idea to maintain them in a repository, as discussed in +%section~\ref{sec:mq:repo}. If you do so, you'll quickly discover that +%using the \hgcmd{diff} command to look at the history of changes to a +%patch is unworkable. This is in part because you're looking at the +%second derivative of the real code (a diff of a diff), but also +%because MQ adds noise to the process by modifying time stamps and +%directory names when it updates a patch. + +$BD9$$4|4V$K$o$?$C$FB?$/$N%Q%C%A$r:n$C$F$-$?$N$J$i!$(B~\ref{sec:mq:repo}$B@a$G(B +$B5DO@$7$F$-$?$h$&$K$=$l$i$r%j%]%8%H%j$G4IM}$9$k$N$ONI$$9M$($G$"$k!%$=$&$7(B +$B$?>l9g!$$9$0$K(B\hgcmd{diff}$B%3%^%s%I$G$O%Q%C%A$N%R%9%H%j$r8+$k$3$H$K;H$($J(B +$B$$$3$H$K5$$E$/$@$m$&!%$3$l$O<B:]$N%3!<%I$NFs<!E*$JGI@8J*!J(Bdiff$B$N(Bdiff$B!K$r(B +$B8+$F$$$k$3$H$H!$(BMQ$B$,%Q%C%A$r99?7$9$k;~$K%?%$%`%9%?%s%W$H%G%#%l%/%H%jL>$r(B +$BJQ99$9$k$3$H$G!$%W%m%;%9$K%N%$%:$r2C$($F$$$k$?$a$G$G$"$k!%(B + +%However, you can use the \hgext{extdiff} extension, which is bundled +%with Mercurial, to turn a diff of two versions of a patch into +%something readable. To do this, you will need a third-party package +%called \package{patchutils}~\cite{web:patchutils}. This provides a +%command named \command{interdiff}, which shows the differences between +%two diffs as a diff. Used on two versions of the same diff, it +%generates a diff that represents the diff from the first to the second +%version. + +$B$7$+$7(BMercurial$B$KF1:-$5$l$F$$$k(B\hgext{extdiff}$B%(%/%9%F%s%7%g%s$r;H$$!$(B2$B$D(B +$B$N%P!<%8%g%s$N%Q%C%A4V$G0UL#$N$"$k:9J,$r<h$k$3$H$,$G$-$k!%$3$N$?$a$K(B +\package{patchutils}~\cite{web:patchutils}$B$r;H$&I,MW$,$"$k!%$3$N%Q%C%1!<(B +$B%8$O(B2$B$D$N(Bdiff$B%U%!%$%k4V$N:9J,$r(Bdiff$B$H$7$FI=<($9$k(B\command{interdiff}$B$H$$(B +$B$&%3%^%s%I$rDs6!$7$F$$$k!%F1$8(Bdiff$B$N0[$J$k%P!<%8%g%s4V$G;HMQ$9$l$P!$A08e(B +$B$N(Bdiff$B$N4V$N(Bdiff$B$r@8@.$9$k!%(B + +%You can enable the \hgext{extdiff} extension in the usual way, by +%adding a line to the \rcsection{extensions} section of your \hgrc. +\hgrc $B%U%!%$%k$N(B \rcsection{extensions} $B%;%/%7%g%s$K<!$N9T$rDI2C$9$kDL>o$N(B +$BJ}K!$G(B\hgext{extdiff}$B$rM-8z$K$G$-$k!%(B +\begin{codesample2} + [extensions] + extdiff = +\end{codesample2} +%The \command{interdiff} command expects to be passed the names of two +%files, but the \hgext{extdiff} extension passes the program it runs a +%pair of directories, each of which can contain an arbitrary number of +%files. We thus need a small program that will run \command{interdiff} +%on each pair of files in these two directories. This program is +%available as \sfilename{hg-interdiff} in the \dirname{examples} +%directory of the source code repository that accompanies this book. +%\excode{hg-interdiff} + +\command{interdiff}$B%3%^%s%I$O(B2$B$D$N%U%!%$%kL>$rEO$5$l$k$3$H$rA[Dj$7$F$$$k(B +$B$,!$(B\hgext{extdiff}$B3HD%$O!$(B2$B$D$N%G%#%l%/%H%j$r0z?t$H$7$F<h$k%3%^%s%I$r5/(B +$BF0$9$k!%=>$C$F$3$l$i$N(B2$B$D$N%G%#%l%/%H%j$N3F!9$N%U%!%$%k$KBP$7$F(B +\command{interdiff}$B$r5/F0$9$k>.$5$J%W%m%0%i%`$,I,MW$K$J$k!%$3$NK\$N%=!<%9(B +$B%3!<%I%j%]%8%H%j%G%#%l%/%H%jFb$N(B\dirname{examples}$B%G%#%l%/%H%j$K$"$k(B +\sfilename{hg-interdiff}$B$H$$$&%W%m%0%i%`$,$=$l$@!%(B +\excode{hg-interdiff} + +%With the \sfilename{hg-interdiff} program in your shell's search path, +%you can run it as follows, from inside an MQ patch directory: +$B%7%'%k%5!<%A%Q%9$NCf$K(B\sfilename{hg-interdiff}$B$,$"$l$P!$(B MQ$B%Q%C%A%G%#%l%/(B +$B%H%j$NCf$+$i<!$N$h$&$K5/F0$G$-$k!%(B + +\begin{codesample2} + hg extdiff -p hg-interdiff -r A:B my-change.patch +\end{codesample2} +%Since you'll probably want to use this long-winded command a lot, you +%can get \hgext{hgext} to make it available as a normal Mercurial +%command, again by editing your \hgrc. +$B$3$ND9$$%3%^%s%I$OIQHK$K;H$&$3$H$K$J$k$@$m$&!%$=$3$G(B \hgrc $B$rJT=8(B +$B$7!$(B\hgext{hgext}$B$GDL>o$N(BMercurial$B%3%^%s%I$N$h$&$K;H$($k$h$&$K$9$k!%(B +\begin{codesample2} + [extdiff] + cmd.interdiff = hg-interdiff +\end{codesample2} +%This directs \hgext{hgext} to make an \texttt{interdiff} command +%available, so you can now shorten the previous invocation of +%\hgxcmd{extdiff}{extdiff} to something a little more wieldy. +$B$3$l$O(B\hgext{hgext}$B$K(B\texttt{interdiff}$B%3%^%s%I$,MxMQ2DG=$G$"$k$3$H$r;X(B +$B<($9$k$?$a!$0JA0$N(B\hgxcmd{extdiff}{extdiff}$B$N5/F0$r<c434JC1$K$G$-$k!%(B +\begin{codesample2} + hg interdiff -r A:B my-change.patch +\end{codesample2} + +\begin{note} +% The \command{interdiff} command works well only if the underlying +% files against which versions of a patch are generated remain the +% same. If you create a patch, modify the underlying files, and then +% regenerate the patch, \command{interdiff} may not produce useful +% output. + +\command{interdiff}$B%3%^%s%I$O!$%Q%C%A$N%P!<%8%g%s$,@8@.$5$l$?85$N%U%!%$%k(B +$B$,F10l$KJ]$?$l$F$$$k>l9g$K8B$C$F@5$7$/F0$/!%%Q%C%A$r:n@.$7$F$+$i85$N%U%!(B +$B%$%k$rJQ99$7!$%Q%C%A$r:F@8@.$7$?>l9g$O(B\command{interdiff}$B$OM-MQ$J:9J,$r=P(B +$BNO$7$J$$$+$b$7$l$J$$!%(B + +\end{note} + +%The \hgext{extdiff} extension is useful for more than merely improving +%the presentation of MQ~patches. To read more about it, go to +%section~\ref{sec:hgext:extdiff}. + +\hgext{extdiff}$B%(%/%9%F%s%7%g%s$O(BMQ$B%Q%C%A$NI=8=$r2~A1$9$k0J>e$N$3$H$r$9(B +$B$k!%$3$N%(%/%9%F%s%7%g%s$K$D$$$F99$KCN$j$?$$;~$O(B\ref{sec:hgext:extdiff}$B%;(B +$B%/%7%g%s$r;2>H$5$l$?$$!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/mq-ref.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,633 @@ +%\chapter{Mercurial Queues reference} +\chapter{Mercurial Queues $B%j%U%!%l%s%9(B} +\label{chap:mqref} + +%\section{MQ command reference} +\section{MQ $B%3%^%s%I%j%U%!%l%s%9(B} +\label{sec:mqref:cmdref} + +%For an overview of the commands provided by MQ, use the command +%\hgcmdargs{help}{mq}. + +MQ$B$K$h$C$FDs6!$5$l$k%3%^%s%I$N35MW$K$D$$$F$O(B\hgcmdargs{help}{mq}$B$rMxMQ$5(B +$B$l$?$$!%(B + +%\subsection{\hgxcmd{mq}{qapplied}---print applied patches} +\subsection{\hgxcmd{mq}{qapplied}---$BE,MQ$5$l$?%Q%C%A$NI=<((B} + +%The \hgxcmd{mq}{qapplied} command prints the current stack of applied +%patches. Patches are printed in oldest-to-newest order, so the last +%patch in the list is the ``top'' patch. + +\hgxcmd{mq}{qapplied}$B%3%^%s%I$O!$E,MQ$5$l$?%Q%C%A$N8=:_$N%9%?%C%/$rI=<((B +$B$9$k!%%Q%C%A$O8E$$$b$N$+$i?7$7$$$b$N$N=g$KI=<($5$l$k!%$=$N$?$a!$%j%9%H$N(B +$B:G8e$N%Q%C%A$O(B``top''$B%Q%C%A$H$J$k!%(B + +%\subsection{\hgxcmd{mq}{qcommit}---commit changes in the queue +%repository} +\subsection{\hgxcmd{mq}{qcommit}---$B%-%e!<$NCf$NJQ99$r%3%_%C%H$9$k(B} + +%The \hgxcmd{mq}{qcommit} command commits any outstanding changes in the +%\sdirname{.hg/patches} repository. This command only works if the +%\sdirname{.hg/patches} directory is a repository, i.e.~you created the +%directory using \hgcmdargs{qinit}{\hgxopt{mq}{qinit}{-c}} or ran +%\hgcmd{init} in the directory after running \hgxcmd{mq}{qinit}. + +\hgxcmd{mq}{qcommit}$B%3%^%s%I$O!$(B\sdirname{.hg/patches}$B%G%#%l%/%H%j$K$"$k(B +$BFM=P$7$?JQ99$r%3%_%C%H$9$k!%$3$N%3%^%s%I$O(B\sdirname{.hg/patches}$B%G%#%l%/(B +$B%H%j$,%j%]%8%H%j$N>l9g$K$N$_F0:n$9$k!%Nc$($P(B +\hgcmdargs{qinit}{\hgxopt{mq}{qinit}{-c}}$B%3%^%s%I$K$h$C$F%G%#%l%/%H%j$r:n$C(B +$B$?$j!$(B\hgxcmd{mq}{qinit}$B%3%^%s%I$N8e$K(B\hgcmd{init}$B$r<B9T$7$?>l9g$,AjEv$9(B +$B$k!%(B + +%This command is shorthand for \hgcmdargs{commit}{--cwd .hg/patches}. + +$B$3$N%3%^%s%I$O(B\hgcmdargs{commit}{--cwd .hg/patches}$B$NC;=L7A$G$"$k!%(B + +%\subsection{\hgxcmd{mq}{qdelete}---delete a patch from the +% \sfilename{series} file} +\subsection{\hgxcmd{mq}{qdelete}---\sfilename{series}$B%U%!%$%k$+$i%Q%C%A(B + $B$r>C5n$9$k(B} + +%The \hgxcmd{mq}{qdelete} command removes the entry for a patch from the +%\sfilename{series} file in the \sdirname{.hg/patches} directory. It +%does not pop the patch if the patch is already applied. By default, +%it does not delete the patch file; use the \hgxopt{mq}{qdel}{-f} option to +%do that. + +\hgxcmd{mq}{qdelete}$B%3%^%s%I$O(B\sdirname{.hg/patches}$B%G%#%l%/%H%j$N(B +\sfilename{series}$B%U%!%$%k$+$i%Q%C%A$r>C5n$9$k!%%Q%C%A$,4{$KE,MQ$5$l$F$$(B +$B$k>l9g$O%Q%C%A$r%]%C%W$7$J$$!%%G%U%)%k%H$G$O%Q%C%A%U%!%$%k$r>C5n$7$J$$$?(B +$B$a!$$=$NMQES$G$O(B\hgxopt{mq}{qdel}{-f}$B%*%W%7%g%s$r;H$&!%(B + +%Options: +$B%*%W%7%g%s(B: +\begin{itemize} +%\item[\hgxopt{mq}{qdel}{-f}] Delete the patch file. +\item[\hgxopt{mq}{qdel}{-f}] $B%Q%C%A$r>C5n$9$k!%(B +\end{itemize} + +%\subsection{\hgxcmd{mq}{qdiff}---print a diff of the topmost applied +%patch} +\subsection{\hgxcmd{mq}{qdiff}---$B:G>e0L$NE,MQ$5$l$?%Q%C%A$N(Bdiff$B$r=PNO$9(B + $B$k(B} + +%The \hgxcmd{mq}{qdiff} command prints a diff of the topmost applied patch. +%It is equivalent to \hgcmdargs{diff}{-r-2:-1}. + +\hgxcmd{mq}{qdiff}$B%3%^%s%I$O:G>e0L$NE,MQ$5$l$?%Q%C%A$N(Bdiff$B$r=PNO$9$k!%$3(B +$B$l$O(B\hgcmdargs{diff}{-r-2:-1}$B$HEy2A$G$"$k!%(B + +%\subsection{\hgxcmd{mq}{qfold}---merge (``fold'') several patches into +%one} +\subsection{\hgxcmd{mq}{qfold}---$B$$$/$D$+$N%Q%C%A$r0l$D$K%^!<%8(B($B$^$?$O(B``fold'')$B$9$k(B} + +%The \hgxcmd{mq}{qfold} command merges multiple patches into the topmost +%applied patch, so that the topmost applied patch makes the union of +%all of the changes in the patches in question. + +\hgxcmd{mq}{qfold}$B%3%^%s%I$OJ#?t$N%Q%C%A$rE,MQ$5$l$?:F>e0L$N%Q%C%A$K%^!<(B +$B%8$9$k!%:F>e0L$N%Q%C%A$O4X?4$N$"$k%Q%C%AA4$F$NJQ99$N=89g$K$J$k!%(B + +%The patches to fold must not be applied; \hgxcmd{mq}{qfold} will exit with +%an error if any is. The order in which patches are folded is +%significant; \hgcmdargs{qfold}{a b} means ``apply the current topmost +%patch, followed by \texttt{a}, followed by \texttt{b}''. + +fold$B$9$k%Q%C%A$OE,MQ$5$l$F$$$F$O$J$i$J$$!%(B\hgxcmd{mq}{qfold}$B$O!$$I$l$+$,(B +$BE,MQ$5$l$F$$$k>l9g$O%(%i!<$rJV$7$F=*N;$9$k!%(Bfold$B$5$l$k%Q%C%A$N=g=x$O=EMW(B +$B$G!$(B\hgcmdargs{qfold}{a b}$B$O!$(B``\texttt{a}, \texttt{b}$B$,B3$$$F$$$k8=:_$N(B +$B:F>e0L$N%Q%C%A$rE,MQ$9$k(B''$B$H$$$&0UL#$K$J$k!%(B + +%The comments from the folded patches are appended to the comments of +%the destination patch, with each block of comments separated by three +%asterisk (``\texttt{*}'') characters. Use the \hgxopt{mq}{qfold}{-e} +%option to edit the commit message for the combined patch/changeset +%after the folding has completed. + +$B%U%)!<%k%I$5$l$?%Q%C%A$N%3%a%s%H$O!$L\E*$N%Q%C%A$N%3%a%s%H$KDI2C$5$l$k!%(B +$B3F!9$N%3%a%s%H%V%m%C%/$O(B3$B$D$N%"%9%?%j%9%/$K$h$C$FJ,N%$5$l$F$$$k!%(B +\hgxopt{mq}{qfold}{-e}$B%*%W%7%g%s$K$h$C$F!$%U%)!<%k%I$,40N;$7$?8e$K7k9g$7(B +$B$?%Q%C%A!?%A%'%s%8%;%C%H$N%3%_%C%H%a%C%;!<%8$rJT=8$9$k$3$H$,$G$-$k!%(B + +%Options: +$B%*%W%7%g%s(B: +\begin{itemize} +%\item[\hgxopt{mq}{qfold}{-e}] Edit the commit message and patch description +% for the newly folded patch. +\item[\hgxopt{mq}{qfold}{-e}] $B?7$?$K%U%)!<%k%I$5$l$k%Q%C%A$N%3%_%C%H%a%C(B + $B%;!<%8$H%Q%C%A$N@bL@$rJT=8$9$k!%(B +%\item[\hgxopt{mq}{qfold}{-l}] Use the contents of the given file as the new +% commit message and patch description for the folded patch. +\item[\hgxopt{mq}{qfold}{-l}] $B%U%)!<%k%I$5$l$?%Q%C%A$N?7$7$$%3%_%C%H%a%C(B + $B%;!<%85Z$S%Q%C%A$N@bL@$H$7$F!$M?$($i$l$?%U%!(B + $B%$%k$r;HMQ$9$k!%(B +%\item[\hgxopt{mq}{qfold}{-m}] Use the given text as the new commit message +% and patch description for the folded patch. +\item[\hgxopt{mq}{qfold}{-m}] $B%U%)!<%k%I$5$l$?%Q%C%A$N?7$7$$%3%_%C%H%a%C(B + $B%;!<%85Z$S%Q%C%A$N@bL@$H$7$F!$M?$($i$l$?%F(B + $B%-%9%H$rMQ$$$k!%(B +\end{itemize} + +%\subsection{\hgxcmd{mq}{qheader}---display the header/description of a patch} +\subsection{\hgxcmd{mq}{qheader}---$B%Q%C%A$N%X%C%@!?@bL@$rI=<((B} + +%The \hgxcmd{mq}{qheader} command prints the header, or description, of a +%patch. By default, it prints the header of the topmost applied patch. +%Given an argument, it prints the header of the named patch. + +\hgxcmd{mq}{qheader}$B%3%^%s%I$O%Q%C%A$N%X%C%@$^$?$O@bL@$rI=<($9$k!%%G%U%)(B +$B%k%H$G$O:F>e0L$KE,MQ$5$l$?%Q%C%A$N%X%C%@$rI=<($9$k!%0z?t$,EO$5$l$k$H!$;X(B +$BDj$5$l$?%Q%C%A$N%X%C%@$rI=<($9$k(B + +%\subsection{\hgxcmd{mq}{qimport}---import a third-party patch into the +%queue} +\subsection{\hgxcmd{mq}{qimport}---$B%5!<%I%Q!<%F%#$N%Q%C%A$r%-%e!<$X%$%s(B + $B%]!<%H$9$k(B} + +%The \hgxcmd{mq}{qimport} command adds an entry for an external patch to the +%\sfilename{series} file, and copies the patch into the +%\sdirname{.hg/patches} directory. It adds the entry immediately after +%the topmost applied patch, but does not push the patch. + +\hgxcmd{mq}{qimport}$B%3%^%s%I$O!$(B\sfilename{series}$B%U%!%$%k$K30It$N%Q%C%A(B +$B$N$?$a$N%(%s%H%j$rDI2C$7!$%Q%C%A$r(B\sdirname{.hg/patches}$B%G%#%l%/%H%j$K%3(B +$B%T!<$9$k!%DI2C$O:F>e0L$NE,MQ:Q$_%Q%C%A$ND>8e$K9T$o$l!$%Q%C%A$N%W%C%7%e$O(B +$B9T$o$J$$!%(B + +%If the \sdirname{.hg/patches} directory is a repository, +%\hgxcmd{mq}{qimport} automatically does an \hgcmd{add} of the imported +%patch. + +\sdirname{.hg/patches}$B%G%#%l%/%H%j$,%j%]%8%H%j$N>l(B +$B9g!$(B\hgxcmd{mq}{qimport}$B$O<+F0E*$K%$%s%]!<%H$5$l$?%Q%C%A$KBP$7$F(B +\hgcmd{add}$B$r9T$&!%(B + +%\subsection{\hgxcmd{mq}{qinit}---prepare a repository to work with MQ} +\subsection{\hgxcmd{mq}{qinit}---MQ$B$G;HMQ$9$k%j%]%8%H%j$rMQ0U$9$k(B} + +%The \hgxcmd{mq}{qinit} command prepares a repository to work with MQ. It +%creates a directory called \sdirname{.hg/patches}. + +\hgxcmd{mq}{qinit}$B%3%^%s%I$O(BMQ$B$G;HMQ$9$k%j%]%8%H%j$rMQ0U$9(B +$B$k!%(B\sdirname{.hg/patches}$B$H$$$&%G%#%l%/%H%j$,:n$i$l$k!%(B + +%Options: +$B%*%W%7%g%s(B: +\begin{itemize} +%\item[\hgxopt{mq}{qinit}{-c}] Create \sdirname{.hg/patches} as a repository +% in its own right. Also creates a \sfilename{.hgignore} file that +% will ignore the \sfilename{status} file. +\item[\hgxopt{mq}{qinit}{-c}] \sdirname{.hg/patches}$B$r%j%]%8%H%j$H$7$F!$(B + $B%3%^%s%I<B9T;~$N8"8B$G:n@.$9$k!%F1;~$K(B + \sfilename{status}$B%U%!%$%k$rL5;k$9$k$?$a$K(B + \sfilename{.hgignore}$B%U%!%$%k$r:n@.$9$k!%(B +\end{itemize} + +%When the \sdirname{.hg/patches} directory is a repository, the +%\hgxcmd{mq}{qimport} and \hgxcmd{mq}{qnew} commands automatically \hgcmd{add} +%new patches. + +\sdirname{.hg/patches}$B%G%#%l%/%H%j$,%j%]%8%H%j$N>l(B +$B9g!$(B\hgxcmd{mq}{qimport}$B%3%^%s%I$H(B\hgxcmd{mq}{qnew}$B%3%^%s%I$O?7$7$$%Q%C(B +$B%A$r<+F0E*$K(B\hgcmd{add}$B$9$k!%(B + +%\subsection{\hgxcmd{mq}{qnew}---create a new patch} +\subsection{\hgxcmd{mq}{qnew}---$B?7$7$$%Q%C%A$r:n@.$9$k(B} + +%The \hgxcmd{mq}{qnew} command creates a new patch. It takes one mandatory +%argument, the name to use for the patch file. The newly created patch +%is created empty by default. It is added to the \sfilename{series} +%file after the current topmost applied patch, and is immediately +%pushed on top of that patch. + +\hgxcmd{mq}{qnew}$B%3%^%s%I$O?7$7$$%Q%C%A$r:n@.$9$k!%$3$N%3%^%s%I$OI,?\$N0z(B +$B?t$H$7$F%Q%C%A%U%!%$%k$H$7$F;HMQ$9$kL>A0$r<h$k!%?75,$K:n@.$5$l$?%Q%C%A(B +$B$O!$%G%U%)%k%H$G$O6u$G$"$j!$(B\sfilename{series}$B%U%!%$%k$K!$8=:_$N:F>e0L$N(B +$BE,MQ$5$l$?%Q%C%A$ND>8e$KDI2C$5$l!$D>$A$K$=$N%Q%C%A$N>e$K%W%C%7%e$5$l$k!%(B + +%If \hgxcmd{mq}{qnew} finds modified files in the working directory, it will +%refuse to create a new patch unless the \hgxopt{mq}{qnew}{-f} option is +%used (see below). This behaviour allows you to \hgxcmd{mq}{qrefresh} your +%topmost applied patch before you apply a new patch on top of it. + +\hgxcmd{mq}{qnew}$B$O!$%o!<%-%s%0%G%#%l%/%H%j$+$iJQ99$5$l$?%U%!%$%k$r8+$D$1(B +$B$k$H!$(B\hgxopt{mq}{qnew}{-f}$B%*%W%7%g%s!J2<5-$r;2>H!K$,;H$o$l$J$$8B$j?7$7$$(B +$B%Q%C%A$N:n@.$r5qH]$9$k!%$3$N5sF0$N$?$a!$:F>e0L$NE,MQ$5$l$?%Q%C%A$N>e$K?7(B +$B$?$J%Q%C%A$rE,MQ$9$kA0$K!$(B\hgxcmd{mq}{qrefresh}$B$9$k$3$H$,$G$-$k!%(B + +%Options: +$B%*%W%7%g%s(B: +\begin{itemize} +%\item[\hgxopt{mq}{qnew}{-f}] Create a new patch if the contents of the +% working directory are modified. Any outstanding modifications are +% added to the newly created patch, so after this command completes, +% the working directory will no longer be modified. +\item[\hgxopt{mq}{qnew}{-f}] $B%+%l%s%H%G%#%l%/%H%j$NFbMF$,99?7$5$l$F$$$k(B + $B>l9g!$?7$7$$%Q%C%A$r:n@.$9$k!%8IN)$7$?JQ2&(B + $B$O?75,$K:n@.$7$?%Q%C%A$KDI2C$5$l!$$3$N%3%^(B + $B%s%I$,=*N;$9$k$H%o!<%-%s%0%G%#%l%/%H%j$OJQ(B + $B99$J$7$N>uBV$K$J$k!%(B +%\item[\hgxopt{mq}{qnew}{-m}] Use the given text as the commit message. +% This text will be stored at the beginning of the patch file, before +% the patch data. +\item[\hgxopt{mq}{qnew}{-m}] $BM?$($i$l$?%F%-%9%H$r%3%_%C%H%a%C%;!<%8$H$7(B + $B$FMQ$$$k!%$3$N%F%-%9%H$O%Q%C%A%U%!%$%k$N@h(B + $BF,$G%G!<%?$NA0$K5-O?$5$l$k!%(B +\end{itemize} + +%\subsection{\hgxcmd{mq}{qnext}---print the name of the next patch} +\subsection{\hgxcmd{mq}{qnext}---$B<!$N%Q%C%A$NL>A0$rI=<($9$k(B} + +%The \hgxcmd{mq}{qnext} command prints the name of the next patch in +%the \sfilename{series} file after the topmost applied patch. This +%patch will become the topmost applied patch if you run \hgxcmd{mq}{qpush}. + +\hgxcmd{mq}{qnext}$B%3%^%s%I$O(B\sfilename{series}$B%U%!%$%k$N<!$N%Q%C%A$NL>A0(B +$B$rI=<($9$k!%$3$N%Q%C%A$O!$(B\hgxcmd{mq}{qpush}$B$r<B9T$9$k$H:G>e0L$NE,MQ:Q$_(B +$B%Q%C%A$H$J$k(B + +%\subsection{\hgxcmd{mq}{qpop}---pop patches off the stack} +\subsection{\hgxcmd{mq}{qpop}---$B%9%?%C%/$+$i%Q%C%A$r%]%C%W$9$k(B} + +%The \hgxcmd{mq}{qpop} command removes applied patches from the top of the +%stack of applied patches. By default, it removes only one patch. + +\hgxcmd{mq}{qpop}$B%3%^%s%I$OE,MQ$5$l$?%Q%C%A$N%9%?%C%/$N%H%C%W$+$i%Q%C%A(B +$B$r=|5n$9$k!%%G%U%)%k%H$G$O%Q%C%A$r(B1$B$D=|5n$9$k!%(B + +%This command removes the changesets that represent the popped patches +%from the repository, and updates the working directory to undo the +%effects of the patches. + +$B$3$N%3%^%s%I$O%j%]%8%H%j$+$i%]%C%W$5$l$?%Q%C%A$rI=$9%A%'%s%8%;%C%H$r=|5n(B +$B$7!$%o!<%-%s%0%G%#%l%/%H%j$r%Q%C%A$N8z2L$r=|5n$9$k$h$&$K99?7$9$k!%(B + +%This command takes an optional argument, which it uses as the name or +%index of the patch to pop to. If given a name, it will pop patches +%until the named patch is the topmost applied patch. If given a +%number, \hgxcmd{mq}{qpop} treats the number as an index into the entries in +%the series file, counting from zero (empty lines and lines containing +%only comments do not count).It pops patches until the patch +%identified by the given index is the topmost applied patch. + +$B$3$N%3%^%s%I$O%]%C%W$9$k%Q%C%A$NL>A0$d%$%s%G%C%/%9$H$7$F;H$&$?$a$K!$%*%W(B +$B%7%g%s$N0z?t$r<h$k!%$3$N%3%^%s%I$O!$L>A0$,M?$($i$l$k$HL>A0$NIU$1$i$l$?%Q%C(B +$B%A$,:G>e0L$NE,MQ:Q$_%Q%C%A$H$J$k$^$G%Q%C%A$r%]%C%W$9$k!%HV9f$,M?$($i$l$?(B +$B>l9g!$(B\hgxcmd{mq}{qpop}$B$OHV9f$r0lO"$N%U%!%$%k$NCf$N%(%s%H%j$X$N%<%m$+$i?t(B +$B$(;O$a$k!J6u9T$H%3%a%s%H9T$O?t$($J$$!K%$%s%G%C%/%9$H$7$F<h$j07$&!%$3$N%3(B +$B%^%s%I$OM?$($?%$%s%G%C%/%9$N%Q%C%A$,:G>e0L$NE,MQ:Q$_%Q%C%A$H$J$k$^$G%Q%C(B +$B%A$r%]%C%W$7B3$1$k!%(B + +%The \hgxcmd{mq}{qpop} command does not read or write patches or the +%\sfilename{series} file. It is thus safe to \hgxcmd{mq}{qpop} a patch +%that you have removed from the \sfilename{series} file, or a patch that +%you have renamed or deleted entirely. In the latter two cases, use the +%name of the patch as it was when you applied it. + +\hgxcmd{mq}{qpop}$B%3%^%s%I$O%Q%C%A$d(B\sfilename{$B%7%j!<%:(B}$B%U%!%$%k$rFI$_=q$-(B +$B$7$J$$!%$=$N$?$a$9$G$K(B\sfilename{series}$B%U%!%$%k$+$i:o=|$7$?%Q%C%A$d!$40(B +$BA4$K>C5n$7$?%Q%C%A$r(B\hgxcmd{mq}{qpop}$B$7$F$b0BA4$G$"$k!%(B +$B8e$+$i=R$Y$?(B2$B$D$N%1!<%9$G$O!$%Q%C%A$rE,MQ$7$?;~$NL>A0;HMQ$9$k!%(B + +%By default, the \hgxcmd{mq}{qpop} command will not pop any patches if the +%working directory has been modified. You can override this behaviour +%using the \hgxopt{mq}{qpop}{-f} option, which reverts all modifications in +%the working directory. + +$B%G%U%)%k%H$G$O(B\hgxcmd{mq}{qpop}$B%3%^%s%I$O!$%o!<%-%s%0%G%#%l%/%H%j$,JQ99(B +$B$5$l$F$$$k>l9g$O$$$+$J$k%Q%C%A$b%]%C%W$7$J$$!%$3$N5sF0$O(B +\hgxopt{mq}{qpop}{-f}$B%*%W%7%g%s$K$h$C$F%*!<%P%i%$%I2DG=$G!$$3$l$K$h$j!$(B +$B%o!<%-%s%0%G%#%l%/%H%j$N$9$Y$F$NJQ99$,<h$j>C$5$l$k!%(B + + +%Options: +$B%*%W%7%g%s(B: +\begin{itemize} +%\item[\hgxopt{mq}{qpop}{-a}] Pop all applied patches. This returns the +% repository to its state before you applied any patches. +\item[\hgxopt{mq}{qpop}{-a}] $BE,MQ$5$l$?$9$Y$F$N%Q%C%A$r%]%C%W$9$k!%$3$N(B + $B%3%^%s%I$O%Q%C%A$rE,MQ$9$kA0$N>uBV$X%j%]%8(B + $B%H%j$rLa$9!%(B +%\item[\hgxopt{mq}{qpop}{-f}] Forcibly revert any modifications to the +% working directory when popping. +\item[\hgxopt{mq}{qpop}{-f}] $B%]%C%W;~$K%o!<%-%s%0%G%#%l%/%H%j$X$N$"$i$f$k(B + $B99?7$r6/@)E*$KLa$9!%(B + +%\item[\hgxopt{mq}{qpop}{-n}] Pop a patch from the named queue. +\item[\hgxopt{mq}{qpop}{-n}] $BL>A0IU$1$5$l$?%-%e!<$+$i%Q%C%A$r(B1$B$D%]%C%W$9(B + $B$k!%(B +\end{itemize} + +%The \hgxcmd{mq}{qpop} command removes one line from the end of the +%\sfilename{status} file for each patch that it pops. + +\hgxcmd{mq}{qpop}$B%3%^%s%I$O(B\sfilename{status}$B%U%!%$%k$NKvHx$+$i!$%]%C%W(B +$B$5$l$?%Q%C%A$KBP1~$9$k9T$r(B1$B9T<h$j=|$/!%(B + +%\subsection{\hgxcmd{mq}{qprev}---print the name of the previous patch} +\subsection{\hgxcmd{mq}{qprev}---$B0JA0$N%Q%C%A$NL>A0$rI=<($9$k(B} + +%The \hgxcmd{mq}{qprev} command prints the name of the patch in the +%\sfilename{series} file that comes before the topmost applied patch. +%This will become the topmost applied patch if you run \hgxcmd{mq}{qpop}. + +\hgxcmd{mq}{qprev}$B%3%^%s%I$O!$(B\sfilename{series}$B%U%!%$%kFb$K$"$k!$:G>e0L(B +$B$NE,MQ:Q$_%Q%C%A$NA0%Q%C%A$NL>A0$rI=<($9$k!%$3$N%Q%C%A$O(B +\hgxcmd{mq}{qpop}$B$r<B9T$9$k$H!$:G>e0L$N%Q%C%A$H$J$k!%(B + +%\subsection{\hgxcmd{mq}{qpush}---push patches onto the stack} +\subsection{\hgxcmd{mq}{qpush}---$B%Q%C%A$r%9%?%C%/$K%W%C%7%e$9$k(B} +\label{sec:mqref:cmd:qpush} + +%The \hgxcmd{mq}{qpush} command adds patches onto the applied stack. By +%default, it adds only one patch. + +\hgxcmd{mq}{qpush}$B%3%^%s%I$O%Q%C%A$rE,MQ:Q$_%9%?%C%/$N>e$KDI2C$9$k!%%G%U%)(B +$B%k%H$G$O!$$3$N%3%^%s%I$O%Q%C%A$r0l$D$@$1DI2C$9$k!%(B + +%This command creates a new changeset to represent each applied patch, +%and updates the working directory to apply the effects of the patches. + +$B$3$N%3%^%s%I$OE,MQ$5$l$?%Q%C%A$R$H$D$R$H$D$K$D$$$F?7$?$J%A%'%s%8%;%C%H$r(B +$B:n@.$7!$%o!<%-%s%0%G%#%l%/%H%j$K%Q%C%A$N1F6A$rE,MQ$9$k$h$&JQ99$r2C$($k!%(B + +%The default data used when creating a changeset are as follows: +$B%A%'%s%8%;%C%H$r:n@.$9$k;~$KMQ$$$i$l$k%G%U%)%k%H%G!<%?$O<!$NDL$j$G$"$k(B: +\begin{itemize} +%\item The commit date and time zone are the current date and time +% zone. Because these data are used to compute the identity of a +% changeset, this means that if you \hgxcmd{mq}{qpop} a patch and +% \hgxcmd{mq}{qpush} it again, the changeset that you push will have a +% different identity than the changeset you popped. +\item $B%3%_%C%H$NF|;~$H%?%$%`%>!<%s$K$O!$8=:_$NF|;~$H%?%$%`%>!<%s$,MQ$$$i(B + $B$l$k!%$3$l$i$N%G!<%?$O%A%'%s%8%;%C%H$N%"%$%G%s%F%#%F%#$r7W;;$9$k$N(B + $B$KMQ$$$i$l$k$?$a!$%Q%C%A$r(B\hgxcmd{mq}{qpop}$B$7$?8e!$:F$S(B + \hgxcmd{mq}{qpush}$B$9$k$H!$(Bpush$B$K$h$k%A%'%s%8%;%C%H$O(Bpop$B$7$?;~$H0[(B + $B$J$k%"%$%G%s%F%#%F%#$r;}$D!%(B +%\item The author is the same as the default used by the \hgcmd{commit} +% command. + \item $B%*!<%5!<$O(B\hgcmd{commit}$B%3%^%s%IMQ$$$i$l$k%G%U%)%k%HCM$,MQ$$$i$l(B + $B$k!%(B +%\item The commit message is any text from the patch file that comes +% before the first diff header. If there is no such text, a default +% commit message is used that identifies the name of the patch. + \item $B%3%_%C%H%a%C%;!<%8$O!$%Q%C%A%U%!%$%k$N:G=i$N(Bdiff$B%X%C%@$NA0$N$"$i$f(B + $B$k%F%-%9%H$G$"$k!%$=$N$h$&$J%F%-%9%H$,B8:_$7$J$$>l9g!$%Q%C%A$NL>A0(B + $B$r<1JL$9$k$N$K%G%U%)%k%H$N%3%_%C%H%a%C%;!<%8$,;H$o$l$k!%(B +\end{itemize} +%If a patch contains a Mercurial patch header (XXX add link), the +%information in the patch header overrides these defaults. +$B%Q%C%A$,(BMercurial$B$N%Q%C%A%X%C%@(B(XXX add link)$B$r4^$`>l9g!$%Q%C%A%X%C%@$N(B +$B>pJs$,$3$l$i$N%G%U%)%k%HCM$r%*!<%P%i%$%I$9$k!%(B + +%Options: +$B%*%W%7%g%s(B: +\begin{itemize} +%\item[\hgxopt{mq}{qpush}{-a}] Push all unapplied patches from the +% \sfilename{series} file until there are none left to push. +\item[\hgxopt{mq}{qpush}{-a}] \sfilename{series}$B%U%!%$%k$N$9$Y$F$NL$E,MQ(B + $B%Q%C%A$r$9$Y$F%W%C%7%e$9$k(B +%\item[\hgxopt{mq}{qpush}{-l}] Add the name of the patch to the end +% of the commit message. +\item[\hgxopt{mq}{qpush}{-l}] $B%Q%C%A$NL>A0$r%3%_%C%H%a%C%;!<%8$N:G8e$KDI(B + $B2C$9$k!%(B +%\item[\hgxopt{mq}{qpush}{-m}] If a patch fails to apply cleanly, use the +% entry for the patch in another saved queue to compute the parameters +% for a three-way merge, and perform a three-way merge using the +% normal Mercurial merge machinery. Use the resolution of the merge +% as the new patch content. +\item[\hgxopt{mq}{qpush}{-m}] $B@5>o$K%Q%C%A$,E,MQ$G$-$J$+$C$?>l9g!$(B $B%Q%C%A(B +$B$r(B3$B%&%'%$%^!<%8$9$k$?$a$N%Q%i%a!<%?$r!$(B $B%-%e!<$K%;!<%V$5$l$?B>$N%(%s%H%j!<(B + $B$+$i7W;;$7!$DL>o$N(BMercurial$B$N%^!<%85!9=$r(B + $BMQ$$$F(B3$B%&%'%$%^!<%8$r9T$&!%(B +%\item[\hgxopt{mq}{qpush}{-n}] Use the named queue if merging while pushing. +\item[\hgxopt{mq}{qpush}{-n}] $B%W%C%7%eCf$N%^!<%8$KL>A0$D$-%-%e!<$rMQ$$$k!%(B +\end{itemize} + +%The \hgxcmd{mq}{qpush} command reads, but does not modify, the +%\sfilename{series} file. It appends one line to the \hgcmd{status} +%file for each patch that it pushes. +\hgxcmd{mq}{qpush}$B%3%^%s%I$O(B\sfilename{series}$B%U%!%$%k$rFI$`$,JQ99$O9T$o(B +$B$J$$!%$3$N%3%^%s%I$O%W%C%7%e$9$k3F!9$N%Q%C%A$rI=$99T$r(B\hgcmd{status}$B%U%!(B +$B%$%k$KDI2C$9$k!%(B + +%\subsection{\hgxcmd{mq}{qrefresh}---update the topmost applied patch} +\subsection{\hgxcmd{mq}{qrefresh}---$B:F>e0L$NE,MQ:Q$_%Q%C%A$r99?7$9$k(B} + +%The \hgxcmd{mq}{qrefresh} command updates the topmost applied patch. It +%modifies the patch, removes the old changeset that represented the +%patch, and creates a new changeset to represent the modified patch. + +\hgxcmd{mq}{qrefresh}$B%3%^%s%I$O:G>e0L$NE,MQ:Q$_%Q%C%A$r99?7$9$k!%$3$N%3%^(B +$B%s%I$O%Q%C%A$rJQ99$7!$%Q%C%A$rI=$98E$$%A%'%s%8%;%C%H$r=|5n$7!$JQ99$5$l$?(B +$B%Q%C%A$rI=$9?7$?$J%A%'%s%8%;%C%H$r@8@.$9$k!%(B + +%The \hgxcmd{mq}{qrefresh} command looks for the following +%modifications: +\hgxcmd{mq}{qrefresh}$B%3%^%s%I$O!$0J2<$N$h$&$JJQ99$rC5$9!%(B +\begin{itemize} +%\item Changes to the commit message, i.e.~the text before the first +% diff header in the patch file, are reflected in the new changeset +% that represents the patch. +\item $B%3%_%C%H%a%C%;!<%8$X$NJQ99!%Nc$($P(B~$B%Q%C%A%U%!%$%k$NCf$N:G=i$N(Bdiff$B%X%C(B + $B%@$NA0$N%F%-%9%H$O!$%Q%C%A$rI=$9?7$7$$%A%'%s%8%;%C%H$KH?1G$5$l$k!%(B +%\item Modifications to tracked files in the working directory are +% added to the patch. +\item $B%o!<%-%s%0%G%#%l%/%H%j$NCf$N4IM}$5$l$F$$$k%U%!%$%k$X$NJQ99$O%Q%C%A(B + $B$XDI2C$5$l$k!%(B +%\item Changes to the files tracked using \hgcmd{add}, \hgcmd{copy}, +% \hgcmd{remove}, or \hgcmd{rename}. Added files and copy and rename +% destinations are added to the patch, while removed files and rename +% sources are removed. +\item $B%3%^%s%I(B\hgcmd{add}, \hgcmd{copy}, \hgcmd{remove}, \hgcmd{rename}$B$G(B + $B4IM}$5$l$F$$$k%U%!%$%k$X$NJQ99!%DI2C$5$l$?%U%!%$%k!$%3%T!<!&%j%M!<(B + $B%`@h$NL>A0$O%Q%C%A$KDI2C$5$l!$:o=|$5$l$?%U%!%$%k$H%j%M!<%`85$NL>A0(B + $B$O%Q%C%A$+$i:o=|$5$l$k!%(B +\end{itemize} + +%Even if \hgxcmd{mq}{qrefresh} detects no changes, it still recreates the +%changeset that represents the patch. This causes the identity of the +%changeset to differ from the previous changeset that identified the +%patch. +\hgxcmd{mq}{qrefresh}$B$O!$JQ99$r8!CN$7$J$+$C$?$H$7$F$b!$%Q%C%A$rI=$9?7$?$J(B +$B%A%'%s%8%;%C%H$r:F@8@.$9$k!%$3$l$K$h$j!$%A%'%s%8%;%C%H$N%"%$%G%s%F%#%F%#(B +$B$O!$%Q%C%A$rI=$7$F$$$?0JA0$N%A%'%s%8%;%C%H$N$b$N$H$OJL$N$b$N$K$J$k!%(B + +%Options: +$B%*%W%7%g%s!'(B +\begin{itemize} +%\item[\hgxopt{mq}{qrefresh}{-e}] Modify the commit and patch description, +% using the preferred text editor. +\item[\hgxopt{mq}{qrefresh}{-e}] $B%3%_%C%H$H%Q%C%A$N@bL@$r9%$_$N%(%G%#%?(B + $B$GJQ99$9$k!%(B +%\item[\hgxopt{mq}{qrefresh}{-m}] Modify the commit message and patch +% description, using the given text. +\item[\hgxopt{mq}{qrefresh}{-m}] $B%3%_%C%H%a%C%;!<%8$H%Q%C%A$N@bL@$r!$M?(B + $B$($i$l$?%F%-%9%H$G9T$&!%(B +%\item[\hgxopt{mq}{qrefresh}{-l}] Modify the commit message and patch +% description, using text from the given file. +\item[\hgxopt{mq}{qrefresh}{-l}] $B%3%_%C%H%a%C%;!<%8$H%Q%C%A$N@bL@$rM?$((B + $B$i$l$?%U%!%$%k$K$h$C$F9T$&!%(B +\end{itemize} + +%\subsection{\hgxcmd{mq}{qrename}---rename a patch} +\subsection{\hgxcmd{mq}{qrename}---$B%Q%C%A$N%j%M!<%`(B} + +%The \hgxcmd{mq}{qrename} command renames a patch, and changes the entry for +%the patch in the \sfilename{series} file. +\hgxcmd{mq}{qrename}$B%3%^%s%I$O%Q%C%A$r%j%M!<%`$7!$(B\sfilename{series}$B%U%!(B +$B%$%kCf$N$3$N%Q%C%A$N%(%s%H%j$rJQ99$9$k!%(B + +%With a single argument, \hgxcmd{mq}{qrename} renames the topmost applied +%patch. With two arguments, it renames its first argument to its +%second. +$B0z?t(B1$B$D$rM?$($?>l9g!$(B\hgxcmd{mq}{qrename}$B$O:G>e0L$NE,MQ:Q$_%Q%C%A$r%j%M!<(B +$B%`$9$k!%0z?t(B2$B$D$N>l9g!$(B1$BHVL\$N0z?t$N%Q%C%A$r(B2$BHVL\$N0z?t$NL>A0$K%j%M!<%`(B +$B$9$k!%(B + +%\subsection{\hgxcmd{mq}{qrestore}---restore saved queue state} +\subsection{\hgxcmd{mq}{qrestore}---$B%;!<%V$5$l$?%-%e!<>uBV$KI|85$9$k(B} + +%XXX No idea what this does. +XXX $B$3$N%3%^%s%I$,2?$r$9$k$+ITL@(B + +%\subsection{\hgxcmd{mq}{qsave}---save current queue state} +\subsection{\hgxcmd{mq}{qsave}---$B8=:_$N%-%e!<>uBV$r%;!<%V$9$k(B} + +%XXX Likewise. +XXX $BF1>e(B + +%\subsection{\hgxcmd{mq}{qseries}---print the entire patch series} +\subsection{\hgxcmd{mq}{qseries}---$B%Q%C%A7ONs$rA4$FI=<((B} + +%The \hgxcmd{mq}{qseries} command prints the entire patch series from the +%\sfilename{series} file. It prints only patch names, not empty lines +%or comments. It prints in order from first to be applied to last. + +\hgxcmd{mq}{qseries}$B%3%^%s%I$O!$(B\sfilename{series}$B%U%!%$%k$K4^$^$l$k%Q%C(B +$B%A7ONsA4$F$rI=<($9$k!%$3$N%3%^%s%I$O%Q%C%AL>$@$1$rI=<($7!$6u9T$d%3%a%s%H(B +$B$OI=<($7$J$$!%:G=i$KE,MQ$5$l$?%Q%C%A$+$i:G8e$KE,MQ$5$l$?%Q%C%A$N=g$KI=<((B +$B$9$k!%(B + +%\subsection{\hgxcmd{mq}{qtop}---print the name of the current patch} +\subsection{\hgxcmd{mq}{qtop}---$B8=:_$N%Q%C%A$NL>A0$rI=<((B} + +%The \hgxcmd{mq}{qtop} prints the name of the topmost currently applied +%patch. +\hgxcmd{mq}{qtop}$B%3%^%s%I$O8=:_$N:G>e0L$NE,MQ:Q$_%Q%C%A$NL>A0$rI=<($9$k!%(B + +%\subsection{\hgxcmd{mq}{qunapplied}---print patches not yet applied} +\subsection{\hgxcmd{mq}{qunapplied}---$BL$E,MQ$N%Q%C%A$rI=<((B} + +%The \hgxcmd{mq}{qunapplied} command prints the names of patches from the +%\sfilename{series} file that are not yet applied. It prints them in +%order from the next patch that will be pushed to the last. + +\hgxcmd{mq}{qunapplied}$B%3%^%s%I$O(B\sfilename{series}$B%U%!%$%k$K4^$^$l$k$9$Y(B +$B$F$NL$E,MQ$N%Q%C%A$NL>A0$rI=<($9$k!%$3$N%3%^%s%I$O<!$KKvHx$K%W%C%7%e$5$l(B +$B$k%Q%C%A$+$i=g$KI=<($9$k!%(B + + +%\subsection{\hgcmd{strip}---remove a revision and descendants} +\subsection{\hgcmd{strip}---$B%j%S%8%g%s$H$=$N;RB9$r:o=|(B} + +%The \hgcmd{strip} command removes a revision, and all of its +%descendants, from the repository. It undoes the effects of the +%removed revisions from the repository, and updates the working +%directory to the first parent of the removed revision. + +\hgcmd{strip}$B%3%^%s%I$O%j%]%8%H%j$+$i(B1$B$D$N%j%S%8%g%s$H$=$N;RB9$r:o=|$9$k!%(B +$B$3$N%3%^%s%I$O:o=|$5$l$?%j%S%8%g%s$N1F6A$r%j%]%8%H%j$+$i<h$j=|$-!$%o!<%-(B +$B%s%0%G%#%l%/%H%j$r:o=|$5$l$?%j%S%8%g%s$N?F$N>uBV$K99?7$9$k!%(B + +%The \hgcmd{strip} command saves a backup of the removed changesets in +%a bundle, so that they can be reapplied if removed in error. +\hgcmd{strip}$B%3%^%s%I$O!$:o=|$5$l$?%A%'%s%8%;%C%H$N%P%C%/%"%C%W0l<0$rJ](B +$BB8$9$k$N$G!$8m$C$F:o=|$7$?>l9g$J$I$K$O:FE,MQ$9$k$3$H$,$G$-$k!%(B + +%Options: +$B%*%W%7%g%s!'(B +\begin{itemize} +%\item[\hgopt{strip}{-b}] Save unrelated changesets that are intermixed +% with the stripped changesets in the backup bundle. +\item[\hgopt{strip}{-b}] $B=|5n$7$?%A%'%s%8%;%C%H$H:.8r$7$?L54X78$N%A%'%s%8(B + $B%;%C%H$r%P%C%/%"%C%W%P%s%I%k$KJ]B8$9$k(B +%\item[\hgopt{strip}{-f}] If a branch has multiple heads, remove all +% heads. XXX This should be renamed, and use \texttt{-f} to strip revs +% when there are pending changes. +\item[\hgopt{strip}{-f}] $B%V%i%s%A$,J#?t$N%X%C%I$r;}$C$F$$$k>l9g!$$9$Y$F$N(B + $B%X%C%I$r>C5n$9$k!%(BXXX $B$3$N%*%W%7%g%s$O%j%M!<%`$5(B + $B$l$k$Y$-$G!$(B\texttt{-f}$B$O%Z%s%G%#%s%0>uBV$NJQ99(B + $B$,$"$k>l9g$K%j%S%8%g%s$r=|5n$9$k$N$KMQ$$$i$l$k$Y(B + $B$-$G$"$k!%(B +%\item[\hgopt{strip}{-n}] Do not save a backup bundle. +\item[\hgopt{strip}{-n}] $B%P%C%/%"%C%W%P%s%I%k$rJ]B8$7$J$$!%(B +\end{itemize} + +%\section{MQ file reference} +\section{MQ $B%U%!%$%k%j%U%!%l%s%9(B} + +%\subsection{The \sfilename{series} file} +\subsection{\sfilename{series}$B%U%!%$%k(B} + +%The \sfilename{series} file contains a list of the names of all +%patches that MQ can apply. It is represented as a list of names, with +%one name saved per line. Leading and trailing white space in each +%line are ignored. + +\sfilename{series}$B%U%!%$%k$O(BMQ$B$,E,MQ$G$-$k$9$Y$F$N%Q%C%A$NL>A0$rJ];}$7$F(B +$B$$$k!%$3$l$OL>A0$N%j%9%H$H$7$FI=8=$5$l$F$*$j!$(B1$B9T$K(B1$B$D$:$D%Q%C%AL>$r4^(B +$B$`!%A08e$N6uGr$OL5;k$5$l$k!%(B + +%Lines may contain comments. A comment begins with the ``\texttt{\#}'' +%character, and extends to the end of the line. Empty lines, and lines +%that contain only comments, are ignored. + +$B9T$K$O%3%a%s%H$r4^$a$F$bNI$$!%%3%a%s%H$O(B``\texttt{\#}''$BJ8;z$G;O$^$j!$9T(B +$BKv$^$GB3$/!%6u9T$H%3%a%s%H$N$_$N9T$OL5;k$5$l$k!%(B + +%You will often need to edit the \sfilename{series} file by hand, hence +%the support for comments and empty lines noted above. For example, +%you can comment out a patch temporarily, and \hgxcmd{mq}{qpush} will skip +%over that patch when applying patches. You can also change the order +%in which patches are applied by reordering their entries in the +%\sfilename{series} file. + +$B%3%a%s%H$H6u9T$N$?$a$K(B\sfilename{series}$B$r<j$GJT=8$9$kI,MW$,@8$8$k$3$H$,(B +$B$"$k!%Nc$($P!$$"$k%Q%C%A$r0l;~E*$K%3%a%s%H%"%&%H$7$F!$(B\hgxcmd{mq}{qpush} +$B$,%Q%C%AE,MQ;~$K$=$N%Q%C%A$r%9%-%C%W$9$k$h$&$K$9$k$J$I$,9M$($i$l$k!%$^(B +$B$?!$%Q%C%A$NE,MQ$5$l$k=gHV$r(B\sfilename{series}$B$rJT=8$9$k$3$H$K$h$C$FJQ99(B +$B$9$k$3$H$b$G$-$k!%(B + +%Placing the \sfilename{series} file under revision control is also +%supported; it is a good idea to place all of the patches that it +%refers to under revision control, as well. If you create a patch +%directory using the \hgxopt{mq}{qinit}{-c} option to \hgxcmd{mq}{qinit}, this +%will be done for you automatically. + +\sfilename{series}$B%U%!%$%k$r%j%S%8%g%s%3%s%H%m!<%k$N2<$KCV$/$3$H$b%5%]!<(B +$B%H$5$l$F$$$k!%$3$N%U%!%$%k$,;2>H$9$k$9$Y$F$N%Q%C%A$r%j%S%8%g%s%3%s%H%m!<(B +$B%k2<$K$*$/$3$H$ONI$$9M$($G$"$k!%(B\hgxcmd{mq}{qinit}$B%3%^%s%I$K(B +\hgxopt{mq}{qinit}{-c}$B%*%W%7%g%s$rEO$7$F;H$$!$D>@\%Q%C%A$r@8@.$7$?>l9g(B +$B$O!$<+F0E*$K$3$N$h$&$J>uBV$K$J$k!%(B + +%\subsection{The \sfilename{status} file} +\subsection{\sfilename{status}$B%U%!%$%k(B} + +%The \sfilename{status} file contains the names and changeset hashes of +%all patches that MQ currently has applied. Unlike the +%\sfilename{series} file, this file is not intended for editing. You +%should not place this file under revision control, or modify it in any +%way. It is used by MQ strictly for internal book-keeping. + +\sfilename{status}$B%U%!%$%k$O(BMQ$B$,8=:_E,MQ$7$F$$$k$9$Y$F$N%Q%C%A$NL>A0$H%A%'(B +$B%s%8%;%C%H%O%C%7%e$r;}$D!%(B\sfilename{series}$B%U%!%$%k$H0c$C$F!$$3$N%U%!%$(B +$B%k$OJT=8$5$l$k$3$H$r0U?^$7$F$$$J$$!%$3$N%U%!%$%k$O%j%S%8%g%s4IM}$7$?$j!$(B +$BJT=8$7$?$j$9$Y$-$G$O$J$$!%$3$l$O(BMQ$B$K$h$C$FFbIt$N4IM}$KMQ$$$i$l$k$Y$-$b$N(B +$B$G$"$k!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/mq-stack.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,270 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.43" + sodipodi:docname="mq-stack.svg" + sodipodi:docbase="/home/bos/hg/hgbook/en"> + <defs + id="defs4" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4142136" + inkscape:cx="299.33323" + inkscape:cy="815.646" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="1014" + inkscape:window-height="689" + inkscape:window-x="0" + inkscape:window-y="25" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + 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" + id="rect1307" + width="202.93683" + height="24.243662" + x="230.01944" + y="221.70146" /> + <text + xml:space="preserve" + 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" + x="237.89606" + y="237.13383" + id="text1309"><tspan + sodipodi:role="line" + id="tspan1311" + x="237.89606" + y="237.13383">prevent-compiler-reorder.patch</tspan></text> + <rect + 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" + id="rect1320" + width="202.93683" + height="24.243662" + x="230.01936" + y="251.34325" /> + <text + xml:space="preserve" + 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" + x="237.89598" + y="266.77563" + id="text1322"><tspan + sodipodi:role="line" + id="tspan1324" + x="237.89598" + y="266.77563">namespace-cleanup.patch</tspan></text> + <rect + 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" + id="rect2217" + width="202.93683" + height="24.243662" + x="230.01936" + y="280.98505" /> + <text + xml:space="preserve" + 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" + x="237.89598" + y="296.41742" + id="text2219"><tspan + sodipodi:role="line" + id="tspan2221" + x="237.89598" + y="296.41742">powerpc-port-fixes.patch</tspan></text> + <rect + 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" + id="rect3114" + width="202.93683" + height="24.243662" + x="230.01936" + y="310.6268" /> + <text + xml:space="preserve" + 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" + x="237.89598" + y="326.05917" + id="text3116"><tspan + sodipodi:role="line" + id="tspan3118" + x="237.89598" + y="326.05917">report-devinfo-correctly.patch</tspan></text> + <text + xml:space="preserve" + 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" + x="200.01021" + y="191.68094" + id="text3170" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan3172" + x="200.01021" + y="191.68094" + 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> + <text + xml:space="preserve" + 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" + x="255.26627" + y="248.79449" + id="text3190" + sodipodi:linespacing="125%" + transform="scale(0.786716,1.271107)"><tspan + sodipodi:role="line" + id="tspan3192" + x="255.26627" + y="248.79449" + 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> + <text + xml:space="preserve" + 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" + x="195.86807" + y="173.17117" + id="text4085" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4087" + x="195.86807" + y="173.17117" + 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 + sodipodi:role="line" + x="195.86807" + y="188.17117" + id="tspan4089" + 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> + <text + xml:space="preserve" + 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" + x="195.0712" + y="288.91745" + id="text4091" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4093" + x="195.0712" + y="288.91745" + 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 + sodipodi:role="line" + x="195.0712" + y="303.91745" + id="tspan4111" + 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> + <text + xml:space="preserve" + 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" + x="195.0712" + y="229.28813" + id="text4095" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan4097" + x="195.0712" + y="229.28813" + 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 + sodipodi:role="line" + x="195.0712" + y="244.28813" + id="tspan4109" + 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> + <text + xml:space="preserve" + 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" + x="450.4975" + y="238.29692" + id="text4137"><tspan + sodipodi:role="line" + id="tspan4139" + x="450.4975" + y="238.29692">201ad3209902</tspan></text> + <text + xml:space="preserve" + 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" + x="450.05804" + y="267.93872" + id="text4141"><tspan + sodipodi:role="line" + id="tspan4143" + x="450.05804" + y="267.93872">126b84e593ae</tspan></text> + <text + xml:space="preserve" + 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" + x="450.6557" + y="297.58051" + id="text4145"><tspan + sodipodi:role="line" + id="tspan4147" + x="450.6557" + y="297.58051">a655daf15409</tspan></text> + <text + xml:space="preserve" + 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" + x="450.71429" + y="327.22226" + id="text4149"><tspan + sodipodi:role="line" + id="tspan4151" + x="450.71429" + y="327.22226">e50d59aaea3a</tspan></text> + <rect + 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" + id="rect3106" + width="202.93683" + height="24.243662" + x="230.01936" + y="150.41792" /> + <text + xml:space="preserve" + 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" + x="237.89598" + y="165.8503" + id="text3108"><tspan + sodipodi:role="line" + id="tspan3110" + x="237.89598" + y="165.8503">forbid-illegal-params.patch</tspan></text> + <rect + 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" + id="rect2241" + width="202.93683" + height="24.243662" + x="230.16466" + y="180.05968" /> + <text + xml:space="preserve" + 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" + x="238.04128" + y="195.49205" + id="text2243"><tspan + sodipodi:role="line" + id="tspan2245" + x="238.04128" + y="195.49205">fix-memory-leak.patch</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/mq.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1862 @@ +%\chapter{Managing change with Mercurial Queues} +\chapter{Mercurial Queues$B$GJQ99$r4IM}$9$k(B} +\label{chap:mq} + +%\section{The patch management problem} +\section{$B%Q%C%A4IM}$NLdBj(B} +\label{sec:mq:patch-mgmt} + +%Here is a common scenario: you need to install a software package from +%source, but you find a bug that you must fix in the source before you +%can start using the package. You make your changes, forget about the +%package for a while, and a few months later you need to upgrade to a +%newer version of the package. If the newer version of the package +%still has the bug, you must extract your fix from the older source +%tree and apply it against the newer version. This is a tedious task, +%and it's easy to make mistakes. + +$B$h$/$"$k%7%J%j%*!'%=!<%9$+$i%=%U%H%&%'%"%Q%C%1!<%8$r%$%s%9%H!<%k$9$kI,MW(B +$B$,$"$k!%$7$+$7%Q%C%1!<%8$r;H$&A0$K%=!<%9$+$iD>$9$Y$-%P%0$r8+$D$1$?!%JQ99(B +$B$r2C$($F!$;C$/%Q%C%1!<%8$N$3$H$OK:$l$F$$$k!%?t%v7n8e!$?7$7$$%P!<%8%g%s$r(B +$B%$%s%9%H!<%k$9$k$3$H$K$J$C$?!%$b$7?7$7$$%P!<%8%g%s$,!$0MA3$H$7$F$=$N%P%0(B +$B$r;}$C$F$$$?>l9g!$=$@5$r8E$$%=!<%9$+$iCj=P$7$F!$?7$7$$%P!<%8%g%s$KE,MQ$7(B +$B$J$1$l$P$J$i$J$$!%$3$l$OB`6~$G$7$+$b4V0c$$$d$9$$;E;v$@!%(B + +%This is a simple case of the ``patch management'' problem. You have +%an ``upstream'' source tree that you can't change; you need to make +%some local changes on top of the upstream tree; and you'd like to be +%able to keep those changes separate, so that you can apply them to +%newer versions of the upstream source. + +$B$3$l$,%Q%C%A4IM}LdBj$N%7%s%W%k$JNc$G$"$k!%$b$7$"$J$?$,JQ99$G$-$J$$>eN.$N(B +$B%=!<%9%D%j!<$,$"$l$P!$%"%C%W%9%H%j!<%`$N%D%j!<$N>e$G%m!<%+%k$JJQ99$r$7$J(B +$B$1$l$P$J$i$J$$!%$"$J$?$O%"%C%W%9%H%j!<%`%=!<%9$KE,MQ$G$-$k$h$&$K$-$C$H$3(B +$B$NJQ99$rJ,N%$7$F$*$-$?$$$H;W$&$O$:$@!%(B + +%The patch management problem arises in many situations. Probably the +%most visible is that a user of an open source software project will +%contribute a bug fix or new feature to the project's maintainers in the +%form of a patch. + +$B%Q%C%A4IM}LdBj$O$$$m$$$m$J>u67$G5/$3$k!%$*$=$i$/:G$bL@$i$+$J$N$O!$%*!<%W(B +$B%s%=!<%9%=%U%H%&%'%"%W%m%8%'%/%H$N%f!<%6$,!$%W%m%8%'%/%H$N%a%s%F%J$K%P%0(B +$B%U%#%C%/%9$d?75!G=$r%Q%C%A$N7A$G9W8%$9$k$3$H$G$"$m$&!%(B + +%Distributors of operating systems that include open source software +%often need to make changes to the packages they distribute so that +%they will build properly in their environments. + +$B%*!<%W%s%=%U%H%&%'%"$r4^$`%*%Z%l!<%F%#%s%0%7%9%F%`$NG[I[<T$O!$G[I[$9$k%Q%C(B +$B%1!<%8$,H`$i$N4D6-$G@5$7$/%S%k%I$G$-$k$h$&$K%Q%C%1!<%8$XJQ99$r2C$($k$3$H(B +$B$,B?$$!%(B + +%When you have few changes to maintain, it is easy to manage a single +%patch using the standard \command{diff} and \command{patch} programs +%(see section~\ref{sec:mq:patch} for a discussion of these tools). Once +%the number of changes grows, it starts to make sense to maintain patches +%as discrete ``chunks of work,'' so that for example a single patch will +%contain only one bug fix (the patch might modify several files, but it's +%doing ``only one thing''), and you may have a number of such patches for +%different bugs you need fixed and local changes you require. In this +%situation, if you submit a bug fix patch to the upstream maintainers of +%a package and they include your fix in a subsequent release, you can +%simply drop that single patch when you're updating to the newer release. + +$B$b$7%a%s%F%J%s%9$7$F$$$kJQ99$,$4$/$o$:$+$J$i!$I8=`$N(B\command{diff}$B%3%^%s(B +$B%I$H(B\command{patch}$B%3%^%s%I$r;H$C$FC10l$N%Q%C%A$r4IM}$9$k$N$,4JC1$@!%!J$3(B +$B$l$i$N%D!<%k$K$D$$$F$O(B~\ref{sec:mq:patch}$B$N@a$r;2>H!%!KJQ99$N?t$,A}$($F$/(B +$B$k$H!$C10l$N%P%0%U%#%C%/%9$r4^$`8D!9$N%Q%C%A$r0l2t$N=89g$H$7$F4IM}$9$k$3(B +$B$H$,8=<BL#$rBS$S$F$/$k!%!J3F!9$N%Q%C%A$OJ#?t$N%U%!%$%k$rJQ99$9$k$+$b$7$l(B +$B$J$$$,!$L\E*$O(B1$B$D$-$j$G$"$k!%!K=$@5$7$?$$%P%0$,$$$/$D$b$"$C$?$j!$%m!<%+%k(B +$B$G$NMM!9$JJQ99$NI,MW$N$?$a!$?tB?$/$N$=$N$h$&$J%Q%C%A$r;}$D$3$H$K$J$k$+$b(B +$B$7$l$J$$!%$3$N>u67$G!$%"%C%W%9%H%j!<%`$N%a%s%F%J$K%P%0=$@5%Q%C%A$rAw$j!$(B +$BH`$i$,$"$J$?$N=$@5$r8e$N%j%j!<%9$K<h$j9~$a$P!$<j85$G?7$7$$%j%j!<%9$K@ZBX(B +$B$($?;~$K$OC1=c$K$=$N%Q%C%A$rGK4~$9$l$PNI$$!%(B + +%Maintaining a single patch against an upstream tree is a little +%tedious and error-prone, but not difficult. However, the complexity +%of the problem grows rapidly as the number of patches you have to +%maintain increases.With more than a tiny number of patches in hand, +%understanding which ones you have applied and maintaining them moves +%from messy to overwhelming. + +$BC10l$N%Q%C%A$r%"%C%W%9%H%j!<%`$N%D%j!<$KBP$7$F%a%s%F%J%s%9$9$k$3$H$O$d$d(B +$BLLE]$G!$4V0c$$$N85$K$J$j$,$A$G$"$k$,!$Fq$7$/$O$J$$!%$7$+$7!$%a%s%F%J%s%9(B +$B$9$k%Q%C%A$N?t$,A}$($k$K=>$C$FLdBj$NJ#;($5$,5^B.$KA}$7$F$$$/!%%Q%C%A$N?t(B +$B$,$"$kDxEY0J>eB?$/$J$k$H!$$I$N%Q%C%A$rE,MQ$7$?$+!$$I$N%Q%C%A$r4IM}$7$F$$(B +$B$k$N$+$NM}2r$,!$Lq2p$H$$$&>uBV$+$i05E]$5$l$k$F$$$k>uBV$K$J$k!%(B + +%Fortunately, Mercurial includes a powerful extension, Mercurial Queues +%(or simply ``MQ''), that massively simplifies the patch management +%problem. + +$B9,$$$K$b!$(BMercurial$B$O(BMercurial Queues$B!J$"$k$$$OC1$K(BMQ$B!K$H$$$&6/NO$J%(%/%9(B +$B%F%s%7%g%s$r$b$C$F$*$j!$%Q%C%A4IM}$NLdBj$rBgI}$KC1=c2=$9$k!%(B + + +%\section{The prehistory of Mercurial Queues} +\section{Mercurial Queues$BA0;K(B} +\label{sec:mq:history} + +%During the late 1990s, several Linux kernel developers started to +%maintain ``patch series'' that modified the behaviour of the Linux +%kernel. Some of these series were focused on stability, some on +%feature coverage, and others were more speculative. + +1990$BG/Be$N=*$o$j:"!$(BLinux$B%+!<%M%k$N3+H/<TC#$O!$(BLinux$B%+!<%M%k$r2~A1$9$k0l(B +$BO"$N%Q%C%A$N4IM}$r;O$a$?!%$=$l$i$N$&$A!$$"$k$b$N$O0BDj@-$K!$JL$N$b$N$OFC(B +$BDj$N5!G=$K!$$^$?JL$N$b$N$OLn?4E*$JFbMF$KFC2=$7$F$$$?!%(B + +%The sizes of these patch series grew rapidly. In 2002, Andrew Morton +%published some shell scripts he had been using to automate the task of +%managing his patch queues. Andrew was successfully using these +%scripts to manage hundreds (sometimes thousands) of patches on top of +%the Linux kernel. + +$B$3$l$i$N%Q%C%A%7%j!<%:$N%5%$%:$O$O$9$0$KKD$l>e$,$C$?!%(B2002$BG/$K(BAndrew +Morton$B$OH`$N%Q%C%A%-%e!<$N4IM}$r<+F02=$9$k$$$/$D$+$N%7%'%k%9%/%j%W%H$r8x(B +$BI=$7$?!%(BAndrew$B$O?tI4$+$i?t@i$N(BLinux$B%+!<%M%k%Q%C%A$r$3$l$i$N%9%/%j%W%H$G(B +$B4IM}$9$k$3$H$,$G$-$F$$$?!%(B + +%\subsection{A patchwork quilt} +\subsection{patchwork quilt} +\label{sec:mq:quilt} + +%In early 2003, Andreas Gruenbacher and Martin Quinson borrowed the +%approach of Andrew's scripts and published a tool called ``patchwork +%quilt''~\cite{web:quilt}, or simply ``quilt'' +%(see~\cite{gruenbacher:2005} for a paper describing it). Because +%quilt substantially automated patch management, it rapidly gained a +%large following among open source software developers. + +2003$BG/$N;O$a!$(BAndreas Gruenbacher$B$H(BMartin Quinson$B$O(BAndrew$B$N%9%/%j%W%H$N$d(B +$B$jJ}$r??;w$F!$(B``patchwork quilt''~\cite{web:quilt}$B$"$k$$$OC1$K(B``quilt''$B$H(B +$B8F$P$l$k%D!<%k$r%j%j!<%9$7$?!%!J>\$7$/$OO@J8(B~\cite{gruenbacher:2005}$B$r;2(B +$B>H$N$3$H!%!K(Bquilt$B$O==J,$K<+F02=$5$l$?%Q%C%A4IM}$rDs6!$7$F$$$?$N$G!$%=%U%H(B +$B%&%'%"3+H/<T$NBg$-$J;Y;}$r5^B.$K3MF@$7$F$$$C$?!%(B + +%Quilt manages a \emph{stack of patches} on top of a directory tree. +%To begin, you tell quilt to manage a directory tree, and tell it which +%files you want to manage; it stores away the names and contents of +%those files. To fix a bug, you create a new patch (using a single +%command), edit the files you need to fix, then ``refresh'' the patch. + +quilt$B$O%G%#%l%/%H%j%D%j!<>e$G(B\emph{$B%Q%C%A$N%9%?%C%/(B}$B$r4IM}$9$k!%%Q%C%A$N(B +$B4IM}$r;O$a$k$K$O!$(Bquilt$B$K4IM}$9$Y$-%G%#%l%/%H%j%D%j!<$H!$4IM}BP>]$N%U%!%$(B +$B%k$r;XDj$9$k!%(Bquilt$B$O$3$l$i$N%U%!%$%k$NL>A0$HCf?H$rJ]B8$9$k!%%P%0$r=$@5(B +$B$9$k>l9g$O!$$^$:?7$7$$%Q%C%A$r!J%3%^%s%I(B1$B$D$G!K:n@.$7!$I,MW$J%U%!%$%k$K(B +$B=$@5$r2C$($?8e!$%Q%C%A$r(B``$B%j%U%l%C%7%e(B''$B$9$l$P$h$$!%(B + +%The refresh step causes quilt to scan the directory tree; it updates +%the patch with all of the changes you have made. You can create +%another patch on top of the first, which will track the changes +%required to modify the tree from ``tree with one patch applied'' to +%``tree with two patches applied''. + +$B%j%U%l%C%7%e$G$O!$(Bquilt$B$O%G%#%l%/%H%j%D%j!<$r%9%-%c%s$7!$JQ99A4$F$rH?1G$5(B +$B$;$F%Q%C%A$r99?7$9$k!%(B``$B$"$k%Q%C%A$,E,MQ$5$l$?>uBV$N%D%j!<(B''$B$+$i(B``2$B$D$N%Q%C(B +$B%A$,E,MQ$5$l$?%D%j!<(B''$B$X99?7$9$k$N$KI,MW$JJQ99$rDI@W$7!$JL$N%Q%C%A$r:n$k(B +$B$3$H$b$G$-$k!%(B + +%You can \emph{change} which patches are applied to the tree. If you +%``pop'' a patch, the changes made by that patch will vanish from the +%directory tree. Quilt remembers which patches you have popped, +%though, so you can ``push'' a popped patch again, and the directory +%tree will be restored to contain the modifications in the patch.Most +%importantly, you can run the ``refresh'' command at any time, and the +%topmost applied patch will be updated. This means that you can, at +%any time, change both which patches are applied and what +%modifications those patches make. + +$B%f!<%6$O$I$N%Q%C%A$,%D%j!<$KE,MQ$5$l$k$+$r(B\emph{$BJQ99(B}$B$G$-$k!%$"$k%Q%C%A$r(B +$B%]%C%W$9$k$H!$$3$N%Q%C%A$K$h$kJQ99$O%D%j!<$+$i>CLG$9$k!%(Bquilt$B$O$I$N%Q%C%A(B +$B$r%]%C%W$7$?$+5-21$7$F$*$j!$0lEY%]%C%W$7$?%U%!%$%k$r:F$S%W%C%7%e$7!$%G%#(B +$B%l%/%H%j%D%j!<$r%Q%C%A$K$h$kJQ99$,$J$5$l$?>uBV$KLa$9$3$H$,$G$-$k!%:G$b=E(B +$BMW$J$3$H$O!$$$$D$G$b(B``refresh''$B%3%^%s%I$r<B9T$7$F0lHV?7$7$/E,MQ$5$l$?%Q%C(B +$B%A$r99?7$G$-$k$3$H$G$"$k!%$3$l$O$9$J$o$A!$%Q%C%A$NE,MQ$5$l$?>uBV$H!$%Q%C(B +$B%A$=$l<+BN$r$$$D$G$b99?7$G$-$k$H$$$&$3$H$G$"$k!%(B + +%Quilt knows nothing about revision control tools, so it works equally +%well on top of an unpacked tarball or a Subversion working copy. + +quilt$B$O%j%S%8%g%s4IM}%D!<%k$K$D$$$F$OA4$/4XCN$7$J$$$?$a!$E83+$5$l$?(Btar$B%\!<(B +$B%k>e$G$b!$(BSubversion$B$N%o!<%-%s%0%3%T!<>e$G$bF1MM$KF0:n$9$k!%(B + +%\subsection{From patchwork quilt to Mercurial Queues} +\subsection{patchwork quilt$B$+$i(BMercurial Queues$B$X(B} +\label{sec:mq:quilt-mq} + +%In mid-2005, Chris Mason took the features of quilt and wrote an +%extension that he called Mercurial Queues, which added quilt-like +%behaviour to Mercurial. + +2005$BG/$NCf:"(BChris Mason$B$O!$(Bquilt$B$N5!G=$r<h$jF~$l$F!$(BMercurial$B$K(Bquilt$B$N$h(B +$B$&$JF0:n$rDI2C$9$k(BMercurial Queues$B$H$$$&%(%/%9%F%s%7%g%s$r=q$$$?!%(B + +%The key difference between quilt and MQ is that quilt knows nothing +%about revision control systems, while MQ is \emph{integrated} into +%Mercurial. Each patch that you push is represented as a Mercurial +%changeset. Pop a patch, and the changeset goes away. + +quilt$B$H(BMQ$B$N0c$$$O!$(Bquilt$B$O%j%S%8%g%s4IM}%7%9%F%`$K$D$$$F2?$b4XCN$7$J$$$N(B +$B$KBP$7$F!$(BMQ$B$O(BMercurial$B$KE}9g$5$l$F$$$k$3$H$G$"$k!%%W%C%7%e$7$?8D!9$N%Q%C(B +$B%A$O(BMercurial$B$N%A%'%s%8%;%C%H$H$7$FI=8=$5$l$k!%%Q%C%A$r%]%C%W$9$k$H!$%A%'(B +$B%s%8%;%C%H$O>C$($F$J$/$J$k!%(B + +%Because quilt does not care about revision control tools, it is still +%a tremendously useful piece of software to know about for situations +%where you cannot use Mercurial and MQ. + +quilt$B$O%j%S%8%g%s4IM}%D!<%k$HL54X78$KMxMQ2DG=$J$?$a!$(BMercurial$B$H(BMQ$B$,;H$((B +$B$J$$>u67$G$O0MA3$H$7$FHs>o$KM-1W$J%D!<%k$G$"$k$3$H$O5-21$KN1$a$F$*$/$Y$-(B +$B$G$"$k!%(B + +%\section{The huge advantage of MQ} +\section{MQ$B$NBg$-$JMxE@(B} + +%I cannot overstate the value that MQ offers through the unification of +%patches and revision control. + +MQ$B$,%Q%C%A$H%j%S%8%g%s%3%s%H%m!<%k$NE}9g$K$h$C$F$b$?$i$92ACM$r8XD%$9$k$o(B +$B$1$K$O$$$+$J$$!%(B + +%A major reason that patches have persisted in the free software and +%open source world---in spite of the availability of increasingly +%capable revision control tools over the years---is the \emph{agility} +%they offer. + +$B;~$rDI$&Kh$K%j%S%8%g%s%3%s%H%m!<%k%D!<%k$NMxMQ$,9-$,$C$F$$$k$K$b$+$+$o$i(B +$B$:!$%U%j!<%=%U%H$H%*!<%W%s%=!<%9$N@$3&$K%Q%C%A$,B8:_$9$kBg$-$JM}M3$O$=$N(B +\emph{$B5!IR$5(B}$B$K$"$k!%(B + +%Traditional revision control tools make a permanent, irreversible +%record of everything that you do. While this has great value, it's +%also somewhat stifling. If you want to perform a wild-eyed +%experiment, you have to be careful in how you go about it, or you risk +%leaving unneeded---or worse, misleading or destabilising---traces of +%your missteps and errors in the permanent revision record. + +$BEAE}E*$J%j%S%8%g%s%3%s%H%m!<%k%D!<%k$O!$9T$J$C$?A`:n$N1J5WE*$GIT2D5UE*$J(B +$B5-O?$r;D$9!%$3$l$K$OBg$-$J2ACM$,$"$k0lJ}$G!$5g6~$K46$8$k$3$H$b$"$k!%$b$7(B +$B2a7c$J<B83$r$9$k$N$G$"$l$P!$$I$N$h$&$K?J$a$k$+?5=E$K$9$kI,MW$,$"$k!%$5$b(B +$B$J$1$l$P!$ITMW$J!$$"$k$$$O8m2r$r>7$$$?$j!$0BDj@-$rB;$J$&%H%l!<%9$H%(%i!<(B +$B$r1J5WE*$J%j%S%8%g%sMzNr$K;D$9$3$H$K$J$k!%(B + +%By contrast, MQ's marriage of distributed revision control with +%patches makes it much easier to isolate your work. Your patches live +%on top of normal revision history, and you can make them disappear or +%reappear at will. If you don't like a patch, you can drop it. If a +%patch isn't quite as you want it to be, simply fix it---as many times +%as you need to, until you have refined it into the form you desire. + +$BBP>NE*$K!$(BMQ$B$K$h$kJ,;6%j%S%8%g%s%3%s%H%m!<%k$H%Q%C%A$N7k9g$O!$:n6H$r3VN%(B +$B$9$k$3$H$rMZ$+$KMF0W$K$9$k!%%Q%C%A$ODL>o$N%j%S%8%g%sMzNr$N>e$K>h$C$F$*$j!$(B +$BK>$`$h$&$K>CLG$5$;$?$j:F8=$5$;$k$3$H$,$G$-$k!%%Q%C%A$r5$$KF~$i$J$1$l$P!$(B +$B$3$l$r4~5Q$9$k$3$H$b$G$-$k!%%Q%C%A$,$"$J$?$NK>$`$h$&$J$b$N$G$J$1$l$P!$4u(B +$BK>DL$j$K$J$k$^$G2?EY$G$b4JC1$K=$@5$9$k$3$H$,$G$-$k!%(B + +%As an example, the integration of patches with revision control makes +%understanding patches and debugging their effects---and their +%interplay with the code they're based on---\emph{enormously} easier. +%Since every applied patch has an associated changeset, you can use +%\hgcmdargs{log}{\emph{filename}} to see which changesets and patches +%affected a file. You can use the \hgext{bisect} command to +%binary-search through all changesets and applied patches to see where +%a bug got introduced or fixed. You can use the \hgcmd{annotate} +%command to see which changeset or patch modified a particular line of +%a source file. And so on. + +$BNc$($P!$%j%S%8%g%s%3%s%H%m!<%k$X$N%Q%C%A$NE}9g$O!$%Q%C%A$rM}2r$7!$$=$N1F(B +$B6A!$0M$C$FN)$D%Y!<%9%3!<%I$H$NAj8_:nMQ$r%G%P%C%0$9$k$3$H$r2DG=$K$9$k!%E,(B +$BMQ$5$l$?%Q%C%A$O!$4XO"$E$1$i$l$?%A%'%s%8%;%C%H$r;}$D$?$a!$(B +\hgcmdargs{log}{\emph{filename}}$B$K$h$C$F$I$N%A%'%s%8%;%C%H$H%Q%C%A$,%U%!(B +$B%$%k$K1F6A$rM?$($F$$$k$+D4$Y$k$3$H$,$G$-$k!%(B\hgext{bisect}$B%3%^%s%I$GA4$F(B +$B$N%A%'%s%8%;%C%H$HE,MQ$5$l$?%Q%C%A$KBP$7$F%P%$%J%j%5!<%A$r9T$J$$!$$I$3$G(B +$B%P%0$,:.F~$7$?$+!$$"$k$$$O=$@5$5$l$?$+$rD4$Y$k$3$H$,$G$-$k!%(B +\hgcmd{annotate}$B%3%^%s%I$G$I$N%A%'%s%8%;%C%H$+%Q%C%A$,%=!<%9%U%!%$%k$NFC(B +$BDj$N9T$rJQ99$7$?$+8+$k$3$H$,$G$-$k!%(B + + +%\section{Understanding patches} +\section{$B%Q%C%A$H$O2?$+(B} +\label{sec:mq:patch} + +%Because MQ doesn't hide its patch-oriented nature, it is helpful to +%understand what patches are, and a little about the tools that work +%with them. + +MQ$B$O%Q%C%A;X8~$G$"$k@-<A$r1#JC$7$F$$$J$$$N$G!$%Q%C%A$,2?$G$"$k$+!$%D!<%k(B +$B$,%Q%C%A$r$I$&07$&$+$rM}2r$9$k$N$O$?$d$9$$!%(B + +%The traditional Unix \command{diff} command compares two files, and +%prints a list of differences between them. The \command{patch} command +%understands these differences as \emph{modifications} to make to a +%file. Take a look at figure~\ref{ex:mq:diff} for a simple example of +%these commands in action. + +Unix$B$NEAE}E*$J(B\command{diff}$B%3%^%s%I$O(B2$B$D$N%U%!%$%k$rHf3S$7!$:9J,$N%j%9(B +$B%H$r=PNO$9$k!%(B\command{patch}$B%3%^%s%I$O$3$N:9J,$rJQ99$H2r<a$7!$%U%!%$%k(B +$B$K5Z$\$9!%?^(B~\ref{ex:mq:diff}$B$K$3$l$i$N%3%^%s%I$NF0:n$r<($9!%(B + +\begin{figure}[ht] + \interaction{mq.dodiff.diff} +% \caption{Simple uses of the \command{diff} and \command{patch} + % commands} + \caption{\command{diff}$B%3%^%s%I$H(B\command{patch}$B%3%^%s%I$NC1=c$J;HMQNc(B} + \label{ex:mq:diff} +\end{figure} + +%The type of file that \command{diff} generates (and \command{patch} +%takes as input) is called a ``patch'' or a ``diff''; there is no +%difference between a patch and a diff. (We'll use the term ``patch'', +%since it's more commonly used.) + +\command{diff}$B$,@8@.$9$k!J$^$?(B\command{patch}$B$,F~NO$K<h$k!K%U%!%$%k$N<o(B +$BN`$O(B``patch''$B$^$?$O(B``diff''$B$H8F$P$l!$$3$l$i$N4V$K$O0c$$$O$J$$!%!J0J2<$G(B +$B$O!$$h$jB?$/;H$o$l$F$$$k(B``patch''$B$H$$$&8@MU$r;H$&$3$H$K$9$k!%!K(B + +%A patch file can start with arbitrary text; the \command{patch} +%command ignores this text, but MQ uses it as the commit message when +%creating changesets. To find the beginning of the patch content, +%\command{patch} searches for the first line that starts with the +%string ``\texttt{diff~-}''. + +$B%Q%C%A%U%!%$%k$OG$0U$N%F%-%9%H$G;O$^$k!%(B\command{patch}$B%3%^%s%I$O$3$N%F(B +$B%-%9%H$rL5;k$9$k$,!$(BMQ$B$O%A%'%s%8%;%C%H$r:n$k:]$N%3%_%C%H%a%C%;!<%8$H$7$F(B +$BMxMQ$9$k!%%Q%C%AFbMF$N@hF,$r8+$D$1$k$?$a$K(B\command{patch}$B$O(B +``\texttt{diff~-}''$B$G;O$^$k:G=i$N9T$r%5!<%A$9$k!%(B + +%MQ works with \emph{unified} diffs (\command{patch} can accept several +%other diff formats, but MQ doesn't). A unified diff contains two +%kinds of header. The \emph{file header} describes the file being +%modified; it contains the name of the file to modify. When +%\command{patch} sees a new file header, it looks for a file with that +%name to start modifying. + +MQ\emph{unified} diffs$B7A<0$r;H$&!%!J(B\command{patch}$B%3%^%s%I$O$3$l0J30$K2?(B +$B<oN`$+$N(Bdiff$B%U%)!<%^%C%H$r<u$1IU$1$k$,!$(BMQ$B$G$OMxMQ$G$-$J$$!%!K(Bunified +diff$B$O(B2$B<oN`$N%X%C%@$r;}$D!%(B\emph{file $B%X%C%@(B}$B$OJQ99$5$l$F$$$k%U%!%$%k$r5-(B +$B=R$9$k!%(B\command{patch}$B%3%^%s%I$O!$?7$7$$%U%!%$%k%X%C%@$r8+$D$1$k$H!$$=$3(B +$B$K5-=R$5$l$F$$$k%U%!%$%kL>$r;}$D%U%!%$%k$rC5$9!%(B + +%After the file header comes a series of \emph{hunks}. Each hunk starts +%with a header; this identifies the range of line numbers within the file +%that the hunk should modify. Following the header, a hunk starts and +%ends with a few (usually three) lines of text from the unmodified file; +%these are called the \emph{context} for the hunk.If +%there's only a small amount of context between successive hunks, +%\command{diff} doesn't print a new hunk header; it just runs the hunks +%together, with a few lines of context between modifications. + +$B%U%!%$%k%X%C%@$N8e$K$O0lO"$N(B\emph{hunks}$B$,B3$/!%3F!9$N(Bhunk$B$O%X%C%@$G;O$^(B +$B$k!%$3$N%X%C%@$O%U%!%$%kFb$G(Bhunk$B$,2~JQ$9$Y$-9THV9f$NHO0O$r<1JL$9$k$N$K;H(B +$B$o$l$k!%%X%C%@$KB3$-!$(Bhunk$B$O?t9T!JDL>o(B3$B!K$N2~JQ$5$l$F$$$J$$%U%!%$%k$+$i$N(B +$B9T$,$"$k!%$3$l$i$O(Bhunk$B$N(B\emph{$B%3%s%F%-%9%H(B}$B$H8F$P$l$k!%$b$7O"B3$9$k(Bhunk$B$N(B +$B4V$K%3%s%F%-%9%H$,>/$7$7$+$J$1$l$P!$(B\command{diff}$B$O?7$?$J(Bhunk$B%X%C%@$r=P(B +$BNO$;$:!$3F!9$N(Bhunk$B$H4V$N%3%s%F%-%9%H$r9g$o$;$F=PNO$9$k!%(B + +%Each line of context begins with a space character. Within the hunk, +%a line that begins with ``\texttt{-}'' means ``remove this line,'' +%while a line that begins with ``\texttt{+}'' means ``insert this +%line.'' For example, a line that is modified is represented by one +%deletion and one insertion. + +$B%3%s%F%-%9%H$N3F9T$O!$6uGrJ8;z$G;O$^$k!%(Bhunk$BFb$G$O9T$O(B``\texttt{-}''$B$G;O(B +$B$^$k!%$3$l$O(B``$B$3$N9T$r:o=|$;$h(B''$B$r0UL#$9$k!%(B +$B0lJ}!$(B``\texttt{+}''$B$G;O$^$k9T$O!$(B``$B$3$N9T$rA^F~$;$h(B''$B$r0UL#$9$k!%Nc$r5s(B +$B$2$k$H!$JQ99$5$l$?9T$O(B1$B$D$N:o=|$H(B1$B$D$NA^F~$GI=$5$l$k!%(B + +%We will return to some of the more subtle aspects of patches later (in +%section~\ref{sec:mq:adv-patch}), but you should have enough information +%now to use MQ. + +$B%Q%C%A$N:3:Y$JE@$K$D$$$F$O8e$G!J(B~\ref{sec:mq:adv-patch}$B!K$^$??($l$k$,!$(B +$B$3$l$^$G$G!$(BMQ$B$r;H$&$N$K==J,$J>pJs$O=R$Y$?!%(B + +%\section{Getting started with Mercurial Queues} +\section{Mercurial Queues$B$r;H$C$F$_$k(B} +\label{sec:mq:start} + +%Because MQ is implemented as an extension, you must explicitly enable +%before you can use it. (You don't need to download anything; MQ ships +%with the standard Mercurial distribution.) To enable MQ, edit your +%\tildefile{.hgrc} file, and add the lines in figure~\ref{ex:mq:config}. + +MQ$B$O%(%/%9%F%s%7%g%s$H$7$F<BAu$5$l$F$$$k$N$G!$;H$&A0$KL@<(E*$KM-8z$K$9$k(B +$BI,MW$,$"$k!%!J2?$b%@%&%s%m!<%I$9$kI,MW$O$J$$!%(BMQ$B$ODL>o$N(BMercurial$B$KF1:-$5(B +$B$l$F$$$k!K(BMQ$B$rM-8z$K$9$k$K$O(B\tildefile{.hgrc}$B%U%!%$%k$rJT=8$7!$(B +$B?^(B~\ref{ex:mq:config}$B$N$h$&$K@_Dj$rDI2C$9$k!%(B + +\begin{figure}[ht] + \begin{codesample4} + [extensions] + hgext.mq = + \end{codesample4} + \label{ex:mq:config} +% \caption{Contents to add to \tildefile{.hgrc} to enable the MQ + % extension} + \caption{MQ$B%(%/%9%F%s%7%g%s$rM-8z$K$9$k$?$a$K(B\tildefile{.hgrc}$B$KDI2C$9$kFbMF(B} +\end{figure} + +%Once the extension is enabled, it will make a number of new commands +%available. To verify that the extension is working, you can use +%\hgcmd{help} to see if the \hgxcmd{mq}{qinit} command is now available; see +%the example in figure~\ref{ex:mq:enabled}. + +$B%(%/%9%F%s%7%g%s$,M-8z2=$5$l$k$H0lO"$N%3%^%s%I$,MxMQ2DG=$K$J$k!%%(%/%9%F(B +$B%s%7%g%s$,M-8z$G$"$k$3$H$r3NG'$9$k$?$a$K$O!$(B\hgcmd{help}$B$G(B +\hgxcmd{mq}{qinit}$B$,$"$k$3$H$r3NG'$9$k!%?^(B~\ref{ex:mq:enabled}$B$NNc$r;2>H(B +$B$5$l$?$$!%(B + +\begin{figure}[ht] + \interaction{mq.qinit-help.help} +% \caption{How to verify that MQ is enabled} + \caption{MQ$B$,M-8z$G$"$k$3$H$N3NG'K!(B} + \label{ex:mq:enabled} +\end{figure} + +%You can use MQ with \emph{any} Mercurial repository, and its commands +%only operate within that repository. To get started, simply prepare +%the repository using the \hgxcmd{mq}{qinit} command (see +%figure~\ref{ex:mq:qinit}). This command creates an empty directory +%called \sdirname{.hg/patches}, where MQ will keep its metadata. As +%with many Mercurial commands, the \hgxcmd{mq}{qinit} command prints nothing +%if it succeeds. + +MQ$B$O(B\emph{$B$"$i$f$k(B}Mercurial$B%j%]%8%H%j$G;H$&$3$H$,$G$-!$$=$N%3%^%s%I$O3F!9(B +$B$N%j%]%8%H%j$NCf$K$@$1:nMQ$9$k!%;O$a$k$?$a$K(B\hgxcmd{mq}{qinit}$B%3%^%s%I$G(B +$B%j%]%8%H%j$rMQ0U$9$k!%!J?^(B~\ref{ex:mq:qinit}$B$r;2>H!K(B $B$3$N%3%^%s%I$O(BMQ$B$,%a(B +$B%?%G!<%?$rJ]B8$9$k$?$a$N(B\sdirname{.hg/patches}$B$H$$$&L>A0$N6u$N%G%#%l%/%H(B +$B%j$r:n@.$9$k!%B>$N(BMercurial$B%3%^%s%I$HF1MM$K!$(B\hgxcmd{mq}{qinit}$B%3%^%s%I(B +$B$b@.8y$9$k$H2?$bI=<($7$J$$!%(B + +\begin{figure}[ht] + \interaction{mq.tutorial.qinit} +% \caption{Preparing a repository for use with MQ} + \caption{MQ$B$r;H$&$?$a$K%j%]%8%H%j$r=`Hw$9$k(B} + \label{ex:mq:qinit} +\end{figure} + +\begin{figure}[ht] + \interaction{mq.tutorial.qnew} +% \caption{Creating a new patch} + \caption{$B?7$7$$%Q%C%A$N:n@.(B} + \label{ex:mq:qnew} +\end{figure} + +%\subsection{Creating a new patch} +\subsection{$B?7$7$$%Q%C%A$N:n@.(B} + +%To begin work on a new patch, use the \hgxcmd{mq}{qnew} command. This +%command takes one argument, the name of the patch to create. MQ will +%use this as the name of an actual file in the \sdirname{.hg/patches} +%directory, as you can see in figure~\ref{ex:mq:qnew}. + +$B?7$7$$%Q%C%A$r07$&;~$O(B\hgxcmd{mq}{qnew}$B%3%^%s%I$r;H$&!%$3$N%3%^%s%I$O:n@.(B +$B$5$l$k%Q%C%A$NL>A0$H$7$F0z?t$r(B1$B$D<h$k!%?^(B~\ref{ex:mq:qnew}$B$N$h$&$K!$(BMQ$B$O(B +$B$3$l$r(B\sdirname{.hg/patches} $B%G%#%l%/%H%jFb$N<B:]$N%U%!%$%kL>$H$7$FMxMQ$9(B +$B$k!%(B + +%Also newly present in the \sdirname{.hg/patches} directory are two +%other files, \sfilename{series} and \sfilename{status}. The +%\sfilename{series} file lists all of the patches that MQ knows about +%for this repository, with one patch per line.Mercurial uses the +%\sfilename{status} file for internal book-keeping; it tracks all of the +%patches that MQ has \emph{applied} in this repository. + +\sdirname{.hg/patches}$B%G%#%l%/%H%j$NCf$K$O!$(B\sfilename{series}$B$H(B +\sfilename{status}$B$H$$$&(B2$B$D$N%U%!%$%k$b?7$7$/:n$i$l$k!%(B +\sfilename{series}$B$U$!$$$k$O(BMQ$B$,4XCN$9$k!$$3$N%j%]%8%H%jFb$NA4$F$N%Q%C%A(B +$B$N%j%9%H$,$"$j!$0l9T$K0l$D$N%Q%C%A$,5-=R$5$l$F$$$k!%(BMercurial$B$O(B +\sfilename{status}$B%U%!%$%k$rFbIt$N4IM}$KMQ$$$k!%$3$N%U%!%$%k$O%j%]%8%H%j(B +$BFb$G(BMQ$B$,E,MQ$7$?A4$F$N%Q%C%A$,5-O?$5$l$F$$$k!%(B + +%\begin{note} +% You may sometimes want to edit the \sfilename{series} file by hand; +% for example, to change the sequence in which some patches are +% applied. However, manually editing the \sfilename{status} file is +% almost always a bad idea, as it's easy to corrupt MQ's idea of what +% is happening. +%\end{note} + +\begin{note} + $BNc$($P!$J#?t$N%Q%C%A$,E,MQ$5$l$k<j=g$rJQ99$9$k$J$I$NL\E*$G(B + \sfilename{series}$B%U%!%$%k$r<j$GJT=8$7$?$/$J$k$3$H$,$"$k$+$b$7$l$J$$!%(B + $B$7$+$7(B\sfilename{status}$B$r<j$GJT=8$9$k$N$O$[$H$s$I$N>l9gNI$/$J$$9M$($G!$(B + MQ$B$N>uBVDI@W$r4JC1$K68$o$;$F$7$^$&!%(B +\end{note} + +%Once you have created your new patch, you can edit files in the +%working directory as you usually would. All of the normal Mercurial +%commands, such as \hgcmd{diff} and \hgcmd{annotate}, work exactly as +%they did before. + +$B?7$7$$%Q%C%A$r:n$C$?8e!$%o!<%-%s%0%G%#%l%/%H%jFb$N%U%!%$%k$rDL>oDL$jJT=8(B +$B$9$k$3$H$,$G$-$k!%(B\hgcmd{diff}$B$d(B\hgcmd{annotate}$B$N$h$&$JA4$F$NDL>o$N(B +Mercurial$B%3%^%s%I$,A4$/F1$8$h$&$K;H$($k!%(B + +%\subsection{Refreshing a patch} +\subsection{$B%Q%C%A$N%j%U%l%C%7%e(B} + +%When you reach a point where you want to save your work, use the +%\hgxcmd{mq}{qrefresh} command (figure~\ref{ex:mq:qnew}) to update the patch +%you are working on. This command folds the changes you have made in +%the working directory into your patch, and updates its corresponding +%changeset to contain those changes. + +$B:n6HFbMF$r%;!<%V$9$k%]%$%s%H$K:9$7$+$+$C$?$i!$(B\hgxcmd{mq}{qrefresh}$B%3%^(B +$B%s%I$r;H$C$F!J?^(B~\ref{ex:mq:qnew}$B!K:n6HCf$N%Q%C%A$r99?7$9$k!%$3$N%3%^%s(B +$B%I$O%o!<%-%s%0%G%#%l%/%H%j$N:9J,$r%Q%C%A$K<h$j9~$_!$%A%'%s%8%;%C%H$,JQ99(B +$B$r4^$`$h$&$K99?7$9$k!%(B + +\begin{figure}[ht] + \interaction{mq.tutorial.qrefresh} +% \caption{Refreshing a patch} + \caption{$B%Q%C%A$N%j%U%l%C%7%e(B} + \label{ex:mq:qrefresh} +\end{figure} + +%You can run \hgxcmd{mq}{qrefresh} as often as you like, so it's a good way +%to ``checkpoint'' your work. Refresh your patch at an opportune +%time; try an experiment; and if the experiment doesn't work out, +%\hgcmd{revert} your modifications back to the last time you refreshed. + +\hgxcmd{mq}{qrefresh}$B$O$$$D$G$b9%$-$J;~$K<B9T$G$-!$:n6H$N>uBVJ]B8$r$9$k(B +$B$N$K$b;H$($k!%%Q%C%A$N%j%U%l%C%7%e$OET9g$N$h$$;~$K9T$($P$h$$!%<B83E*$J%3!<(B +$B%I$rF0$+$9>l9g!$;vA0$K%j%U%l%C%7%e$r$7$F$*$1$P!$<B83$N7k2L%3!<%I$,F0$+$J(B +$B$/$F$b!$(B\hgcmd{revert}$B$9$l$P!$JQ99$O85$KLa$k!%(B + +\begin{figure}[ht] + \interaction{mq.tutorial.qrefresh2} +% \caption{Refresh a patch many times to accumulate changes} + \caption{$B%Q%C%A$N%j%U%l%C%7%e$GJQ99$rC_@Q$9$k(B} + \label{ex:mq:qrefresh2} +\end{figure} + +%\subsection{Stacking and tracking patches} +\subsection{$B%Q%C%A$N%9%?%C%/$HDI@W(B} + +%Once you have finished working on a patch, or need to work on another, +%you can use the \hgxcmd{mq}{qnew} command again to create a new patch. +%Mercurial will apply this patch on top of your existing patch. See +%figure~\ref{ex:mq:qnew2} for an example. Notice that the patch +%contains the changes in our prior patch as part of its context (you +%can see this more clearly in the output of \hgcmd{annotate}). + +$B%Q%C%A$X$N:n6H$,=*N;$7$?$j!$B>$N:n6H$r$r$9$kI,MW$,$"$k>l9g!$(B +\hgxcmd{mq}{qnew}$B%3%^%s%I$r<B9T$7!$?7$7$$%Q%C%A$r:n$k$3$H$,$G$-$k!%(B +Mercurial$B$O$3$N%Q%C%A$r4{B8$N%Q%C%A$N>e$+$iE,MQ$9$k!%?^(B~\ref{ex:mq:qnew2}$B$r(B +$B;2>H$N$3$H!%%Q%C%A$O@h9T$9$k%Q%C%A$NJQ99$r%3%s%F%-%9%H$H$7$F;}$D!%!J(B\hgcmd{annotate} +$B$N=PNO$G$h$jL@NF$K3NG'$9$k$3$H$,$G$-$k!%!K(B + +\begin{figure}[ht] + \interaction{mq.tutorial.qnew2} +% \caption{Stacking a second patch on top of the first} + \caption{$B:G=i$N%Q%C%A$N>e$K(B2$BHVL\$N%Q%C%A$r%9%?%C%/$9$k(B} + \label{ex:mq:qnew2} +\end{figure} + +%So far, with the exception of \hgxcmd{mq}{qnew} and +%\hgxcmd{mq}{qrefresh}, we've been careful to only use regular Mercurial +%commands. However, MQ provides many commands that are easier to use +%when you are thinking about patches, as illustrated in +%figure~\ref{ex:mq:qseries}: + +$B$3$l$^$G$O(B\hgxcmd{mq}{qnew}$B$H(B\hgxcmd{mq}{qrefresh}$B$r=|$$$F!$DL>o$N(B +Mercurial$B%3%^%s%I$N$_$r;H$&$h$&$KCm0U$7$F$-$?!%$7$+$7(BMQ$B$O%Q%C%A$r07$&>l(B +$B9g!$?^(B~\ref{ex:mq:qseries}$B$K<($9$h$&$J$h$j4JC1$J%3%^%s%I$rMQ0U$7$F$$$k!%(B + +%\begin{itemize} +%\item The \hgxcmd{mq}{qseries} command lists every patch that MQ knows +% about in this repository, from oldest to newest (most recently +% \emph{created}). +%\item The \hgxcmd{mq}{qapplied} command lists every patch that MQ has +% \emph{applied} in this repository, again from oldest to newest (most +% recently applied). +%\end{itemize} + +\begin{itemize} +\item \hgxcmd{mq}{qseries}$B%3%^%s%I$O(BMQ$B$,4XCN$9$k%j%]%8%H%jFb$N%Q%C%AA4$F(B + $B$r8E$$$b$N$+$i?7$7$/(B\emph{$B:n@.$5$l$?(B}$B$b$N$N=g$K%j%9%HI=<($9$k!%(B +\item \hgxcmd{mq}{qapplied}$B%3%^%s%I$O(BMQ$B$,(B\emph{$BE,MQ$7$?(B}$B%j%]%8%H%jFb$N(B + $B%Q%C%AA4$F$r$d$O$j8E$$$b$N$+$i?7$7$/(B\emph{$B:n@.$5$l$?(B}$B$b$N$N=g$K%j%9%HI=<($9$k!%(B +\end{itemize} + +\begin{figure}[ht] + \interaction{mq.tutorial.qseries} +% \caption{Understanding the patch stack with \hgxcmd{mq}{qseries} and +% \hgxcmd{mq}{qapplied}} + \caption{\hgxcmd{mq}{qseries}$B$H(B\hgxcmd{mq}{qapplied}$B$G%Q%C%A%9%?%C%/$r(B + $BD4$Y$k(B} + \label{ex:mq:qseries} +\end{figure} + + +%\subsection{Manipulating the patch stack} +\subsection{$B%Q%C%A%9%?%C%/$NA`:n(B} + +%The previous discussion implied that there must be a difference +%between ``known'' and ``applied'' patches, and there is. MQ can +%manage a patch without it being applied in the repository. + +$B$3$l$^$G$N5DO@$O(B``known''$B$H(B``applied''$B%Q%C%A$K0c$$$,$"$k$3$H$r0EL[$K2>Dj(B +$B$7$F$$$?!%(BMQ$B$O:90[$N$J$$%Q%C%A$r%j%]%8%H%j$KBP$7$FE,MQ$9$k$3$H$b$G$-$k!%(B + +%An \emph{applied} patch has a corresponding changeset in the +%repository, and the effects of the patch and changeset are visible in +%the working directory. You can undo the application of a patch using +%the \hgxcmd{mq}{qpop} command. MQ still \emph{knows about}, or manages, a +%popped patch, but the patch no longer has a corresponding changeset in +%the repository, and the working directory does not contain the changes +%made by the patch. Figure~\ref{fig:mq:stack} illustrates the +%difference between applied and tracked patches. + +\emph{$BE,MQ$5$l$?(B}$B%Q%C%A$O%j%]%8%H%jFb$KBP1~$9$k%A%'%s%8%;%C%H$r;}$A!$%Q%C(B +$B%A$N8z2L$H%A%'%s%8%;%C%H$O%o!<%-%s%0%G%#%l%/%H%jFb$G8+$k$3$H$,$G$-$k!%%Q%C(B +$B%A$NE,MQ$O(B\hgxcmd{mq}{qpop}$B%3%^%s%I$G<h$j>C$9$3$H$,$G$-$k!%%]%C%W$5$l$?%Q%C(B +$B%A$OBP1~$9$k%A%'%s%8%;%C%H$r;}$?$:!$JQ99$b%o!<%-%s%0%G%#%l%/%H%j$K;D$C$F(B +$B$$$J$$$,!$(BMQ$B$O%]%C%W$5$l$?%Q%C%A$r0MA3$H$7$F5-21$7!$4IM}$7$F$$$k!%(B +$B?^(B~\ref{fig:mq:stack}$B$OE,MQ$5$l$?%Q%C%A$H4IM}$5$l$F$$$k%Q%C%A$N0c$$$r<((B +$B$9!%(B + +\begin{figure}[ht] + \centering + \grafix{mq-stack} +% \caption{Applied and unapplied patches in the MQ patch stack} + \caption{MQ$B%Q%C%A%9%?%C%/$NCf$NE,MQ$5$l$?%Q%C%A$HE,MQ$5$l$J$$%Q%C%A(B} + \label{fig:mq:stack} +\end{figure} + +%You can reapply an unapplied, or popped, patch using the \hgxcmd{mq}{qpush} +%command. This creates a new changeset to correspond to the patch, and +%the patch's changes once again become present in the working +%directory. See figure~\ref{ex:mq:qpop} for examples of \hgxcmd{mq}{qpop} +%and \hgxcmd{mq}{qpush} in action. Notice that once we have popped a patch +%or two patches, the output of \hgxcmd{mq}{qseries} remains the same, while +%that of \hgxcmd{mq}{qapplied} has changed. + +$BE,MQ$r30$7$?%Q%C%A$d%]%C%W$7$?%Q%C%A$r(B\hgxcmd{mq}{qpush}$B%3%^%s%I$G:FE,MQ(B +$B$9$k$3$H$,$G$-$k!%$3$N%3%^%s%I$O!$%Q%C%A$KBP1~$7$??7$7$$%A%'%s%8%;%C%H$r(B +$B:n$j!$%Q%C%A$K$h$kJQ99$O$b$&0lEY%o!<%-%s%0%G%#%l%/%H%j$K8=$l$k!%(B +\hgxcmd{mq}{qpop}$B$H(B\hgxcmd{mq}{qpush}$B$N;HMQNc$r?^(B~\ref{ex:mq:qpop}$B$K<($9!%(B +1$B$D$^$?$OJ#?t$N%Q%C%A$r%]%C%W$9$k$H(B\hgxcmd{mq}{qapplied}$B$N=PNO$OJQ2=$9$k(B +$B$,!$(B\hgxcmd{mq}{qseries}$B$N=PNO$OF1$8$^$^;D$k$N$KCm0U$5$l$?$$!%(B + +\begin{figure}[ht] + \interaction{mq.tutorial.qpop} +% \caption{Modifying the stack of applied patches} + \caption{$BE,MQ$5$l$?%Q%C%A$N%9%?%C%/$rJQ99$9$k(B} + \label{ex:mq:qpop} +\end{figure} + +%\subsection{Pushing and popping many patches} +\subsection{$B%Q%C%A$N%W%C%7%e$H%]%C%W(B} + +%While \hgxcmd{mq}{qpush} and \hgxcmd{mq}{qpop} each operate on a single patch at +%a time by default, you can push and pop many patches in one go. The +%\hgxopt{mq}{qpush}{-a} option to \hgxcmd{mq}{qpush} causes it to push all +%unapplied patches, while the \hgxopt{mq}{qpop}{-a} option to \hgxcmd{mq}{qpop} +%causes it to pop all applied patches. (For some more ways to push and +%pop many patches, see section~\ref{sec:mq:perf} below.) + +\hgxcmd{mq}{qpush}$B$H(B\hgxcmd{mq}{qpop}$B$O0lEY$K3F!9$N%Q%C%A0l$D$:$D$rA`:n$9(B +$B$k!J$3$l$O%G%U%)%k%HF0:n$G$"$k!K0lJ}!$J#?t$N%Q%C%A$r0lEY$K%]%C%W!&%W%C%7%e(B +$B$9$kA`:n$b$"$k!%(B\hgxcmd{mq}{qpush}$B%3%^%s%I$N(B\hgxopt{mq}{qpush}{-a}$B%*%W%7%g(B +$B%s$O!$L$E,MQ$N%Q%C%AA4BN$r%W%C%7%e$7!$(B\hgxcmd{mq}{qpop}$B%3%^%s%I$N(B +\hgxopt{mq}{qpop}{-a} $B%*%W%7%g%s$OE,MQ:Q$_$N%Q%C%AA4BN$r%]%C%W$9$k!%(B +$B!JB>$NJ#?t$N%Q%C%A$rF1;~$K%W%C%7%e!&%]%C%W$9$kJ}K!$K$D$$$F$O2<(B +$B$N(B~\ref{sec:mq:perf}$B$r;2>H$N$3$H!K(B + +\begin{figure}[ht] + \interaction{mq.tutorial.qpush-a} +% \caption{Pushing all unapplied patches} + \caption{$BE,MQ$5$l$F$$$J$$%Q%C%A$rA4$F%W%C%7%e$9$k(B} + \label{ex:mq:qpush-a} +\end{figure} + +%\subsection{Safety checks, and overriding them} +\subsection{$B0BA4@-%A%'%C%/$H%*!<%P%i%$%I(B} + +%Several MQ commands check the working directory before they do +%anything, and fail if they find any modifications. They do this to +%ensure that you won't lose any changes that you have made, but not yet +%incorporated into a patch.Figure~\ref{ex:mq:add} illustrates this; +%the \hgxcmd{mq}{qnew} command will not create a new patch if there are +%outstanding changes, caused in this case by the \hgcmd{add} of +%\filename{file3}. + +$B$$$/$D$+$N(BMQ$B%3%^%s%I$O!$<B9T;~$K$^$:%o!<%-%s%0%G%#%l%/%H%j$r%A%'%C%/$7!$(B +$BJQ99$,$J$5$l$F$$$?$i=*N;$9$k$h$&$K$J$C$F$$$k!%$3$l$O!$%f!<%6$N$^$@%Q%C%A(B +$B$K<h$j9~$^$l$F$$$J$$JQ99$,<:$o$l$J$$$h$&$K$9$k$?$a$G$"$k!%(B +$B?^(B~\ref{ex:mq:add}$B$O$3$l$r@bL@$7$?$b$N$G!$(B\hgxcmd{mq}{qnew}$B%3%^%s%I$O8IN)(B +$B$7$?JQ99$,$"$k;~$K?7$?$J%Q%C%A$r@8@.$7$J$$!%$3$NNc$G$O!$JQ99$O(B +\hgcmd{add}$B$K$h$k(B\filename{file3}$B$NDI2C$K$h$C$F@8$^$l$F$$$k!%(B + +\begin{figure}[ht] + \interaction{mq.tutorial.add} +% \caption{Forcibly creating a patch} + \caption{$B%Q%C%A$N6/@)E*$J@8@.(B} + \label{ex:mq:add} +\end{figure} + +%Commands that check the working directory all take an ``I know what +%I'm doing'' option, which is always named \option{-f}. The exact +%meaning of \option{-f} depends on the command. For example, +%\hgcmdargs{qnew}{\hgxopt{mq}{qnew}{-f}} will incorporate any outstanding +%changes into the new patch it creates, but +%\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-f}} will revert modifications to any +%files affected by the patch that it is popping. Be sure to read the +%documentation for a command's \option{-f} option before you use it! + +$B%o!<%-%s%0%G%#%l%/%H%j$N%A%'%C%/$r9T$J$&%3%^%s%I$OA4$F!$>e5i<T8~$1$N6/@)(B +$B%*%W%7%g%s(B\option{-f}$B$r;}$C$F$$$k!%(B\option{-f}$B$N87L)$J0UL#$O!$%3%^%s%I$K(B +$B$h$C$F0[$J$k!%Nc$($P(B\hgcmdargs{qnew}{\hgxopt{mq}{qnew}{-f}}$B$O8IN)$7$?JQ(B +$B99$r?7$7$$%Q%C%A$K<h$j9~$`$H$$$&0UL#$@$,!$(B +\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-f}}$B$O!$%]%C%W$9$k%Q%C%A$K$h$k$"$i$f(B +$B$k%U%!%$%k$X$NJQ99$r<h$j>C$9$H$$$&0UL#$K$J$k!%(B\option{-f}$B%*%W%7%g%s$r;H(B +$B$&;~$OI,$:;vA0$K%3%^%s%I$N%I%-%e%a%s%H$rFI$s$G3NG'$9$k$h$&$K$7$FM_$7$$!%(B + +%\subsection{Working on several patches at once} +\subsection{$BJ#?t$N%Q%C%A$r0lEY$K07$&(B} + +%The \hgxcmd{mq}{qrefresh} command always refreshes the \emph{topmost} +%applied patch. This means that you can suspend work on one patch (by +%refreshing it), pop or push to make a different patch the top, and +%work on \emph{that} patch for a while. + +\hgxcmd{mq}{qrefresh}$B%3%^%s%I$O(B\emph{$B:G$b>e(B}$B$KE,MQ$5$l$?%Q%C%A$KBP$7$F%j(B +$B%U%l%C%7%e$r9T$J$&!%$3$l$O%j%U%l%C%7%e$K$h$C$F(B1$B$D$N%Q%C%A$K8=:_$N:n6H$r%5(B +$B%9%Z%s%I$7$?$j!$JL$N%H%C%W%Q%C%A$d0l;~E*$K:n6H$9$k$?$a%Q%C%A$r:n$k$?$a$K(B +$B%]%C%W$d%W%C%7%e$,$G$-$k$H$$$&$3$H$r0UL#$9$k!%(B + +%Here's an example that illustrates how you can use this ability. +%Let's say you're developing a new feature as two patches. The first +%is a change to the core of your software, and the second---layered on +%top of the first---changes the user interface to use the code you just +%added to the core. If you notice a bug in the core while you're +%working on the UI patch, it's easy to fix the core. Simply +%\hgxcmd{mq}{qrefresh} the UI patch to save your in-progress changes, and +%\hgxcmd{mq}{qpop} down to the core patch. Fix the core bug, +%\hgxcmd{mq}{qrefresh} the core patch, and \hgxcmd{mq}{qpush} back to the UI +%patch to continue where you left off. + +$B$3$N5!G=$N;H$$J}$r<($9Nc$r<($9!%(B2$B$D$N%Q%C%A$H$7$F?7$7$$5!G=$r3+H/$7$F$$$k(B +$B$H$9$k!%:G=i$N$b$N$O$"$J$?$N%=%U%H%&%'%"$N%3%"$rJQ99$7!$(B2$BHVL\$N$b$N$O(B1$BHV(B +$BL\$N$b$N$N>e$KE83+$9$k!$:#DI2C$7$?%3%"$N%3!<%I$r;H$C$?%f!<%6%$%s%?%U%'!<(B +$B%9$@$H$9$k!%(BUI$B%Q%C%A$G:n6HCf$K%3%"$N%P%0$K5$IU$$$?$H$9$k$H!$4JC1$K%3%"$N(B +$B=$@5$O9T$J$($k!%C1=c$K(B\hgxcmd{mq}{qrefresh}$B$K$h$C$F?J9TCf$N(BUI$B%Q%C%A$r%;!<(B +$B%V$7!$(B\hgxcmd{mq}{qpop}$B$K$h$C$F%3%"%Q%C%A$XAL$k!%%3%"$N%P%0$r=$@5$7$?8e(B +$B$K(B\hgxcmd{mq}{qrefresh}$B$r%3%"%Q%C%A$K$D$$$F9T$J$$!$(B\hgxcmd{mq}{qpush}$B$G(B +UI$B%Q%C%A$KLa$C$F:n6H$rB3$1$k!%(B + +%\section{More about patches} +\section{$B$5$i$K%Q%C%A$K$D$$$F(B} +\label{sec:mq:adv-patch} + +%MQ uses the GNU \command{patch} command to apply patches, so it's +%helpful to know a few more detailed aspects of how \command{patch} +%works, and about patches themselves. + +MQ$B$O%Q%C%A$NE,MQ$K(BGNU$B$N(B\command{patch}$B%3%^%s%I$rMQ$$$k!%$=$N$?$a!$(B +\command{patch}$B$NF0:n$H%Q%C%A<+BN$K$D$$$F$h$j>\$7$/CN$C$F$*$/$3$H$OM-MQ(B +$B$G$"$k!%(B + +%\subsection{The strip count} +\subsection{$B%9%H%j%C%W%+%&%s%H(B} + +%If you look at the file headers in a patch, you will notice that the +%pathnames usually have an extra component on the front that isn't +%present in the actual path name. This is a holdover from the way that +%people used to generate patches (people still do this, but it's +%somewhat rare with modern revision control tools). + +$B%Q%C%A$N%U%!%$%k%X%C%@$r8+$k$H!$%Q%9%M!<%`$N:G=i$KDI2C$NItJ,$,$D$$$F$$$k(B +$B$N$K5$$E$/$O$:$@!%$3$l$O<B:]$N%Q%9%M!<%`$K$OB8:_$7$J$$$b$N$G!$%Q%C%A$r@8(B +$B@.$9$k;~$N=,47$+$i$N0dJ*$G$"$k!%!JB?$/$N?M$,$$$^$@$3$NJ}K!$r;H$C$F$$$k$,!$(B +$B6aBeE*$J%j%S%8%g%s%3%s%H%m!<%k%D!<%k$G$O$[$H$s$I8+$i$l$J$$!%!K(B + +%Alice would unpack a tarball, edit her files, then decide that she +%wanted to create a patch. So she'd rename her working directory, +%unpack the tarball again (hence the need for the rename), and use the +%\cmdopt{diff}{-r} and \cmdopt{diff}{-N} options to \command{diff} to +%recursively generate a patch between the unmodified directory and the +%modified one. +%The result would be that the name of the unmodified +%directory would be at the front of the left-hand path in every file +%header, and the name of the modified directory would be at the front +%of the right-hand path. + +$B%"%j%9$,(Btar$B%\!<%k$r2rE`$7!$%U%!%$%k$rJT=8$7!$%Q%C%A$r:n$j$?$$$H;W$C$F$$$k(B +$B$H$9$k!%H`=w$O%o!<%-%s%0%G%#%l%/%H%j$r%j%M!<%`$7$F(Btar$B%\!<%k$r$b$&0lEY2rE`(B +$B$7!J$3$N$?$a$K%j%M!<%`$,I,MW$@$C$?!K!$(B\command{diff}$B$K(B\cmdopt{diff}{-r}$B$H(B +\cmdopt{diff}{-N}$B%*%W%7%g%s$r$D$1$F!$85$N$^$^$N%G%#%l%/%H%j$HJQ99$7$?%G%#(B +$B%l%/%H%j$N4V$G:F5"E*$K%Q%C%A$r@8@.$9$k$@$m$&!%@8@.$5$l$?%Q%C%A$G$O!$A4$F(B +$B$N%U%!%$%k%X%C%@$G85$N$^$^$N%G%#%l%/%H%j$NL>A0$,:8B&$N%Q%9$N@hF,$K!$JQ99(B +$B$5$l$?%G%#%l%/%H%j$NL>A0$,1&B&$N%Q%9$N@hF,$K8=$l$k!%(B + +%Since someone receiving a patch from the Alices of the net would be +%unlikely to have unmodified and modified directories with exactly the +%same names, the \command{patch} command has a \cmdopt{patch}{-p} +%option that indicates the number of leading path name components to +%strip when trying to apply a patch. This number is called the +%\emph{strip count}. + +$B%M%C%H>e$N%"%j%9$?$A$+$i%Q%C%A$r<u$1<h$C$??M$O!$JQ99$J$7$N%G%#%l%/%H%j$H(B +$BJQ99$5$l$?%G%#%l%/%H%j$NN>J}$r%"%j%9$HF1$8L>A0$G;}$C$F$$$k2DG=@-$O$^$:$J(B +$B$$!%(B\command{patch}$B%3%^%s%I$K$O(B\cmdopt{patch}{-p}$B%*%W%7%g%s$,$"$j!$%Q%C(B +$B%A$rE,MQ$9$k;~$K%Q%9$NMWAG$r@hF,$+$i$$$/$D:o$k$+$r;XDj$G$-$k!%$3$N?t$O(B +\emph{$B%9%H%j%C%W%+%&%s%H(B}$B$H8F$P$l$k!%(B + +%An option of ``\texttt{-p1}'' means ``use a strip count of one''. If +%\command{patch} sees a file name \filename{foo/bar/baz} in a file +%header, it will strip \filename{foo} and try to patch a file named +%\filename{bar/baz}. (Strictly speaking, the strip count refers to the +%number of \emph{path separators} (and the components that go with them +%) to strip. A strip count of one will turn \filename{foo/bar} into +%\filename{bar}, but \filename{/foo/bar} (notice the extra leading +%slash) into \filename{foo/bar}.) + +$B%*%W%7%g%s(B``\texttt{-p1}''$B$O(B``$B%9%H%j%C%W%+%&%s%H(B1$B$r;H$&(B''$B$H$$$&0UL#$G$"(B +$B$k!%$b$7(B\command{patch}$B$,%U%!%$%k%X%C%@$K(B\filename{foo/bar/baz}$B$r8+$D$1(B +$B$?;~$O!$(B\filename{foo}$B$rMn$7$F(B\filename{bar/baz}$B$H$$$&L>A0$N%U%!%$%k$K%Q%C(B +$B%A$r;n$_$k!%!J87L)$K8@$&$H%9%H%j%C%W%+%&%s%H$O(B\emph{$B%Q%9%;%Q%l!<%?(B}$B$N?t(B +$B$r;2>H$7$F$$$k!J7k2L$H$7$FMWAG$b;2>H$5$l$k!K%9%H%j%C%W%+%&%s%H(B1$B$O(B +\filename{foo/bar}$B$r(B\filename{bar}$B$KJQ$($k!%$^$?(B\filename{/foo/bar}$B!JA0(B +$B$KCV$+$l$?%9%i%C%7%e$KCm0U!K$O(B\filename{foo/bar}$B$H$J$k!%!K(B + +%The ``standard'' strip count for patches is one; almost all patches +%contain one leading path name component that needs to be stripped. +%Mercurial's \hgcmd{diff} command generates path names in this form, +%and the \hgcmd{import} command and MQ expect patches to have a strip +%count of one. + +$B%Q%C%A$X$N(B``$BI8=`E*$J(B''$B%9%H%j%C%W%+%&%s%H$O(B1$B$G$"$k!%$[$H$s$IA4$F$N%Q%C%A(B +$B$O<h$j=|$/$Y$-%Q%9MWAG$r0l$D;}$C$F$$$k!%(BMercurial$B$N(B\hgcmd{diff}$B%3%^%s%I(B +$B$O%Q%9L>$r$3$N7A<0$G@8@.$7!$(B\hgcmd{import}$B%3%^%s%I$H(BMQ$B$O%9%H%j%C%W%+%&%s(B +$B%H(B1$B$rA0Ds$H$7$F$$$k!%(B + +%If you receive a patch from someone that you want to add to your patch +%queue, and the patch needs a strip count other than one, you cannot +%just \hgxcmd{mq}{qimport} the patch, because \hgxcmd{mq}{qimport} does not yet +%have a \texttt{-p} option (see~\bug{311}). Your best bet is to +%\hgxcmd{mq}{qnew} a patch of your own, then use \cmdargs{patch}{-p\emph{N}} +%to apply their patch, followed by \hgcmd{addremove} to pick up any +%files added or removed by the patch, followed by \hgxcmd{mq}{qrefresh}. +%This complexity may become unnecessary; see~\bug{311} for details. + +$BC/$+$+$i%Q%C%A$r<u$1<h$j!$%Q%C%A%-%e!<$KDI2C$9$k$H$-!$%9%H%j%C%W%+%&%s%H(B +$B$,(B1$B0J30$G$"$l$PC1$K(B\hgxcmd{mq}{qimport}$B$9$k$3$H$O$G$-$J$$!%$3$l$O(B +\hgxcmd{mq}{qimport}$B%3%^%s%I$,$^$@(B\texttt{-p}$B%*%W%7%g%s$r;}$C$F$$$J$$$?$a(B +$B$@!J(B\bug{311}$B$r;2>H!K!%:G$b>e<j$/$$$-$=$&$JJ}K!$O!$(B\hgxcmd{mq}{qnew}$B$G?7(B +$B$?$K%Q%C%A$r:n$j!$(B\cmdargs{patch}{-p\emph{N}}$B$r<B9T$7$F<u$1<h$C$?%Q%C%A$r(B +$BE,MQ$7$?8e!$%Q%C%A$K$h$C$FDI2C$5$l$?$j:o=|$5$l$?%U%!%$%k$r(B +\hgcmd{addremove}$B$K$h$C$F%T%C%/%"%C%W$7!$(B\hgxcmd{mq}{qrefresh}$B$r<B9T$9$k(B +$B$3$H$G$"$k!%$3$NJ#;($J<j=g$O>-MhE*$K$OI,MW$J$/$J$k$O$:$@!J(B\bug{311}$B$r;2(B +$B>H!K!%(B + +%\subsection{Strategies for applying a patch} +\subsection{$B%Q%C%AE,MQ$N$?$a$N@oN,(B} + +%When \command{patch} applies a hunk, it tries a handful of +%successively less accurate strategies to try to make the hunk apply. +%This falling-back technique often makes it possible to take a patch +%that was generated against an old version of a file, and apply it +%against a newer version of that file. + +\command{patch}$B$,(Bhunk$B$rE,MQ$9$k$H$-!$$$$/$D$+$N$"$^$j@53N$G$J$$@oN,$rB3$1(B +$B$FMQ$$$k!%$3$N%U%)!<%k%P%C%/<jK!$K$h$C$F!$8E$$%P!<%8%g%s$N%U%!%$%k$KBP$7(B +$B$F:n@.$7$?%Q%C%A$r?7$7$$%U%!%$%k$KE,MQ$9$k$3$H$5$($7$P$7$P2DG=$H$J$k!%(B + +%First, \command{patch} tries an exact match, where the line numbers, +%the context, and the text to be modified must apply exactly. If it +%cannot make an exact match, it tries to find an exact match for the +%context, without honouring the line numbering information. If this +%succeeds, it prints a line of output saying that the hunk was applied, +%but at some \emph{offset} from the original line number. + +$B:G=i$K!$(B\command{patch}$B$O9THV9f!$%3%s%F%-%9%H!$JQ99$5$l$k%F%-%9%H$N@53N$J(B +$B%^%C%A$r;n$_$k!%@53N$J%^%C%A$,$G$-$J$$>l9g!$9THV9f$rL5;k$7$F%3%s%F%-%9%H(B +$B$N@53N$J%^%C%A$r;n$_$k!%$3$l$,@.8y$9$l$P!$(Bhunk$B$,E,MQ$5$l$?$,!$(B\emph{$B%*%U(B +$B%;%C%H(B}$B$,@8$8$?$H$$$&%a%C%;!<%8$rI=<($9$k!%(B + +%If a context-only match fails, \command{patch} removes the first and +%last lines of the context, and tries a \emph{reduced} context-only +%match. If the hunk with reduced context succeeds, it prints a message +%saying that it applied the hunk with a \emph{fuzz factor} (the number +%after the fuzz factor indicates how many lines of context +%\command{patch} had to trim before the patch applied). + +$B%3%s%F%-%9%H$N$_$N%^%C%A$,<:GT$9$k$H!$(B\command{patch}$B$O%3%s%F%-%9%H$N:G=i(B +$B$H:G8e$N9T$r:o$j!$%3%s%F%-%9%H$N(B\emph{$B=L>.(B}$B%^%C%A$r;n$_$k!%=L>.%3%s%F%-%9(B +$B%H$K$h$k(Bhunk$B$,@.8y$9$k$H!$(Bhunk$B$,E,MQ$5$l$?$3$H$H(B\emph{fuzz $B%U%!%/%?!<(B}$B$r(B +$B4^$`%a%C%;!<%8$rI=<($9$k!%!J(Bfuzz$B%U%!%/%?!<$N8e$m$N?t;z$O!$(B +\command{patch}$B%3%^%s%I$,!$%Q%C%A$rE,MQ$9$kA0$K%3%s%F%-%9%H$N2?9T$r:o=|$9(B +$B$kI,MW$,$"$C$?$N$+$r<($9!%!K(B + +%When neither of these techniques works, \command{patch} prints a message +%saying that the hunk in question was rejected. It saves rejected hunks +%(also simply called ``rejects'') to a file with the same name, and an +%added \sfilename{.rej} extension. It also saves an unmodified copy of +%the file with a \sfilename{.orig} extension; the copy of the file +%without any extensions will contain any changes made by hunks that +%\emph{did} apply cleanly. If you have a patch that modifies +%\filename{foo} with six hunks, and one of them fails to apply, you will +%have: an unmodified \filename{foo.orig}, a \filename{foo.rej} containing +%one hunk, and \filename{foo}, containing the changes made by the five +%successful five hunks. + +$B$I$A$i$b>e<j$/$$$+$J$+$C$?>l9g!$(B\command{patch}$B$O(Bhunk$B$,%j%8%'%/%H$5$l$?$H(B +$B$$$&%a%C%;!<%8$rI=<($9$k!%%3%^%s%I$O%j%8%'%/%H$5$l$?(Bhunk$B!J$"$k$$$OC1$K(B +``rejects''$B!K$rF1L>$G3HD%;R(B\sfilename{.rej}$B$N%U%!%$%k$K%;!<%V$9$k!%%3%^%s(B +$B%I$OF1;~$KL5JQ99$N%U%!%$%k$r(B\sfilename{.orig}$B$H$$$&3HD%;R$G%;!<%V$9$k!#3H(B +$BD%;R$N$J$$%U%!%$%k$N%3%T!<$O!$(Bhunk$B$+$i%/%j!<%s$KE,MQ$5$l$?JQ99$rA4$F4^$`!%(B +\filename{foo}$B$H$$$&%U%!%$%k$rJQ99$9$k(B6$B$D$N(Bhunk$B$r4^$`%Q%C%A%U%!%$%k$,$"$j!$(B +$B$=$NFb$N(B1$B$D$,E,MQ$G$-$J$+$C$?$H$9$k$H!$L5JQ99$N%U%!%$%k(B +\filename{foo.orig}$B!$(Bhunk1$B$D$r4^$`%U%!%$%k(B\filename{foo.rej}$B!$@5$7$/E,MQ(B +$B$5$l$?(B5$B$D$N(Bhunk$B$r4^$`%U%!%$%k(B\filename{foo}$B$,@8@.$5$l$k!%(B + +%\subsection{Some quirks of patch representation} +\subsection{$B%Q%C%AI=8=$N4qL/$JE@(B} + +%There are a few useful things to know about how \command{patch} works +%with files. +%\begin{itemize} +%\item This should already be obvious, but \command{patch} cannot +% handle binary files. +%\item Neither does it care about the executable bit; it creates new +% files as readable, but not executable. +%\item \command{patch} treats the removal of a file as a diff between +% the file to be removed and the empty file. So your idea of ``I +% deleted this file'' looks like ``every line of this file was +% deleted'' in a patch. +%\item It treats the addition of a file as a diff between the empty +% file and the file to be added. So in a patch, your idea of ``I +% added this file'' looks like ``every line of this file was added''. +%\item It treats a renamed file as the removal of the old name, and the +% addition of the new name. This means that renamed files have a big +% footprint in patches. (Note also that Mercurial does not currently +% try to infer when files have been renamed or copied in a patch.) +%\item \command{patch} cannot represent empty files, so you cannot use +% a patch to represent the notion ``I added this empty file to the +% tree''. +%\end{itemize} + +\command{patch}$B$,%U%!%$%k$K$I$N$h$&$K:nMQ$9$k$+!$M-MQ$JE@$r$$$/$D$+=R$Y(B +$B$k!%(B +\begin{itemize} + \item $B$9$G$KL@Gr$@$,!$(B\command{patch}$B$O%P%$%J%j%U%!%$%k$r07$&$3$H$O$G$-(B + $B$J$$!%(B + \item $B<B9T%S%C%H$r9MN8$7$J$$$@$1$G$J$/!$?7$7$$%U%!%$%k$rFI$_<h$j2DG=B0(B + $B@-$G:n@.$7!$<B9T2DG=B0@-$OIU$1$J$$!%(B + \item \command{patch}$B%3%^%s%I$O%U%!%$%k$N:o=|$r:o=|$5$l$k%U%!%$%k$HCf?H(B + $B$,$+$i$N%U%!%$%k$H$N:9J,$H$7$F07$&!%=>$C$F!$%U%!%$%k$r:o=|$9$k$H$$(B + $B$&$3$H$O!$%Q%C%A%U%!%$%k$NCf$G$O%U%!%$%k$NCf$NA4$F$N9T$r:o=|$9$k$3(B + $B$H$HEy2A$G$"$k!%(B + \item \command{patch}$B%3%^%s%I$O%U%!%$%k$NDI2C$r6u$N%U%!%$%k$HDI2C$5$l$k(B + $B%U%!%$%k$N:9J,$H$7$F07$&!%=>$C$F%U%!%$%k$NDI2C$O%Q%C%A%U%!%$%k$NCf(B + $B$G$O%U%!%$%k$KA4$F$N9T$rDI2C$9$k$3$H$HEy2A$G$"$k!%(B + \item \command{patch}$B%3%^%s%I$OL>A0$NJQ99$5$l$?%U%!%$%k$r5lL>$N%U%!%$%k(B + $B$N:o=|$H?7$7$$%U%!%$%k$NDI2C$H$7$F07$&!%=>$C$FL>A0$NJQ99$5$l$?%U%!(B + $B%$%k$O%Q%C%AFb$GBg$-$J%U%C%H%W%j%s%H$r@j$a$k!%!J(BMercurial$B$O8=:_$N(B + $B$H$3$m!$%Q%C%AFb$G%U%!%$%k$,%j%M!<%`$5$l$?$N$+!$%3%T!<$5$l$?$N$+(B + $B$r4XCN$7$J$$!K(B + \item \command{patch}$B%3%^%s%I$OCf?H$N6u$N%U%!%$%k$rI=8=$G$-$J$$!%=>$C$F(B + $B%Q%C%A%U%!%$%k$r!V6u$N%U%!%$%k$r%D%j!<$KDI2C$9$k!W$H$$$&MQES$K;H(B + $B$&$3$H$O$G$-$J$$!%(B +\end{itemize} + +%\subsection{Beware the fuzz} +\subsection{$B[#Kf$JE@$K$D$$$F(B} + +%While applying a hunk at an offset, or with a fuzz factor, will often +%be completely successful, these inexact techniques naturally leave +%open the possibility of corrupting the patched file. The most common +%cases typically involve applying a patch twice, or at an incorrect +%location in the file. If \command{patch} or \hgxcmd{mq}{qpush} ever +%mentions an offset or fuzz factor, you should make sure that the +%modified files are correct afterwards. + +$B$"$k%*%U%;%C%H$d(Bfuzz factor$B$N0LCV$X$N(Bhunk$B$NE,MQ$O!$B?$/$N>l9gLdBj$J$/@.8y(B +$B$9$k$,!$IT@53N$J%^%C%A$rMQ$$$?>l9g!$%Q%C%A$rE,MQ$7$?%U%!%$%k$r2u$7$F$$$k(B +$B2DG=@-$,;D$k!%:G$b$h$/$"$k$N$O!$%Q%C%A$rFsEYE,MQ$7$?$j!$%U%!%$%k$N4V0c$C(B +$B$?>l=j$KE,MQ$7$F$7$^$&$3$H$@!%(B\command{patch}$B$^$?$O(B\hgxcmd{mq}{qpush}$B$,%*(B +$B%U%;%C%H$+(Bfuzz$B%U%!%/%?!<$rI=<($7$F$$$k9g!$JQ99$5$l$?%U%!%$%k$,@5>o$G$"$k(B +$B$+3NG'$9$kI,MW$,$"$k!%(B + +%It's often a good idea to refresh a patch that has applied with an +%offset or fuzz factor; refreshing the patch generates new context +%information that will make it apply cleanly. I say ``often,'' not +%``always,'' because sometimes refreshing a patch will make it fail to +%apply against a different revision of the underlying files. In some +%cases, such as when you're maintaining a patch that must sit on top of +%multiple versions of a source tree, it's acceptable to have a patch +%apply with some fuzz, provided you've verified the results of the +%patching process in such cases. + +$B%*%U%;%C%H$d(Bfuzz factor$B$N=P$?%Q%C%A$r%j%U%l%C%7%e$9$k$N$OB?$/$N>l9gNI$$9M(B +$B$($G$"$k!%%Q%C%A$r%j%U%l%C%7%e$9$k$H!$?7$7$$%3%s%F%-%9%H>pJs$,@8@.$5$l!$(B +$B%Q%C%A$,%/%j!<%s$KE,MQ$G$-$k$h$&$K$J$k!%!V>o$K!W$G$O$J$J$/!VB?$/$N>l9g!W(B +$B$HCG$C$?$N$O!$%Q%C%A$r%j%U%l%C%7%e$9$k$3$H$G!$85$N%U%!%$%k$N0[$J$C$?%j%S(B +$B%8%g%s$G%Q%C%A$,E,MQ$G$-$J$/$J$k$3$H$,$"$k$+$i$@!%J#?t$N%P!<%8%g%s$N%=!<(B +$B%9%D%j!<$N>e$GE,MQ2DG=$J%Q%C%A$r4IM}$7$J$1$l$P$J$i$J$$$h$&$J>l9g$J$I$O!$(B +$B%Q%C%A$N7k2L$r8!>Z$7$F$"$k$N$G$"$l$P(Bfuzz$B$N=P$k%Q%C%A$b5vMF$5$lF@$k!%(B + +%\subsection{Handling rejection} +\subsection{$B%j%8%'%/%H$N<h$j07$$(B} + +%If \hgxcmd{mq}{qpush} fails to apply a patch, it will print an error +%message and exit. If it has left \sfilename{.rej} files behind, it is +%usually best to fix up the rejected hunks before you push more patches +%or do any further work. + +\hgxcmd{mq}{qpush}$B$O%Q%C%A$NE,MQ$K<:GT$7$?>l9g!$%(%i!<%a%C%;!<%8$rI=<($7(B +$B$F=*N;$9$k!%(B\sfilename{.rej}$B%U%!%$%k$,:n$i$l$F$$$k>l9g$O!$DL>o!$$5$i$J$k(B +$B%Q%C%A$NDI2C$d?7$7$$:n6H$NA0$K%j%8%'%/%H$5$l$?(Bhunk$B$K$D$$$F=$@5$r9T$&$Y$-(B +$B$G$"$k!%(B + +%If your patch \emph{used to} apply cleanly, and no longer does because +%you've changed the underlying code that your patches are based on, +%Mercurial Queues can help; see section~\ref{sec:mq:merge} for details. + +$B$=$l$^$G%Q%C%A$,%/%j!<%s$KE,MQ$5$l$F$*$j!$%Q%C%A$NBP>]$K$J$C$F$$$k%3!<%I(B +$B$KJQ99$r2C$($?$?$a$KE,MQ$G$-$J$/$J$C$?$N$J$i!$(BMercurial Queues$B$N;Y1g$r<u(B +$B$1$k$3$H$,$G$-$k!%>\$7$$>pJs$O%;%/%7%g%s(B~\ref{sec:mq:merge}$B$r8+$FM_$7$$!%(B + +%Unfortunately, there aren't any great techniques for dealing with +%rejected hunks. Most often, you'll need to view the \sfilename{.rej} +%file and edit the target file, applying the rejected hunks by hand. + +$B;DG0$J$3$H$K!$%j%8%'%/%H$5$l$?(Bhunk$B$r<h$j07$&7h$^$C$?NI$$J}K!$OB8:_$7$J(B +$B$$!%BgDq$N>l9g!$(B\sfilename{.rej}$B%U%!%$%k$r8+$F%?!<%2%C%H%U%!%$%k$rJT=8(B +$B$7!$%j%8%'%/%H$5$l$?(Bhunk$B$r<j$GE,MQ$9$k$3$H$K$J$k!%(B + +%If you're feeling adventurous, Neil Brown, a Linux kernel hacker, +%wrote a tool called \command{wiggle}~\cite{web:wiggle}, which is more +%vigorous than \command{patch} in its attempts to make a patch apply. + +$BKA81$,9%$-$J$i!$(BLinux kerner$B%O%C%+!<$N(BNeil Brown$B$,=q$$$?(B +\command{wiggle}~\cite{web:wiggle}$B$r;n$7$F$_$k$HNI$$!%$3$N%3%^%s%I$O(B +\command{patch}$B$h$j$b@:NOE*$K%Q%C%A$NE,MQ$r;n$_$k!%(B + +%Another Linux kernel hacker, Chris Mason (the author of Mercurial +%Queues), wrote a similar tool called +%\command{mpatch}~\cite{web:mpatch}, which takes a simple approach to +%automating the application of hunks rejected by \command{patch}. The +%\command{mpatch} command can help with four common reasons that a hunk +%may be rejected: + +$BJL$N(BLinux kerner$B%O%C%+!<(B Chris Mason$B!J(BMercurial Queues$B$N:n<T$G$b$"$k!%!K(B +$B$O(B\command{mpatch}~\cite{web:mpatch}$B$H$$$&%D!<%k$r=q$$$?!%$3$N%3%^%s%I$O(B +\command{patch}$B%3%^%s%I$G%j%8%'%/%H$5$l$?(Bhunk$B$NE,MQ$r<+F02=$9(B +$B$k!%(B\command{mpatch}$B%3%^%s%I$O!$(Bhunk$B$,%j%8%'%/%H$5$l$k<g$J860x(B4$B$D$KBP1~(B +$B$9$k(B: + +\begin{itemize} +%\item The context in the middle of a hunk has changed. +\item hunk$B$NCf$N%3%s%F%-%9%H$,JQ99$5$l$?(B +%\item A hunk is missing some context at the beginning or end. +\item hunk$B$N3+;OIt!&=*C<It$G%3%s%F%-%9%H$,8+$D$1$i$l$J$$(B +%\item A large hunk might apply better---either entirely or in +% part---if it was broken up into smaller hunks. +\item $BBg$-$J(Bhunk$B$O$b$C$H>e<j$KE,MQ$G$-$kH&$@(B---hunk$B$r>.$5$J(Bhunk$B$KJ,3d$7(B + $B$FE,MQ$9$k(B +%\item A hunk removes lines with slightly different content than those +% currently present in the file. +\item hunk$BFb$N9T$,8=:_%U%!%$%k$K$"$k9T$H<c430c$C$F$$$k>l9g!$$=$N9T$r:o=|(B + $B$9$k(B +\end{itemize} + +%If you use \command{wiggle} or \command{mpatch}, you should be doubly +%careful to check your results when you're done. In fact, +%\command{mpatch} enforces this method of double-checking the tool's +%output, by automatically dropping you into a merge program when it has +%done its job, so that you can verify its work and finish off any +%remaining merges. + +\command{wiggle}$B$^$?$O(B\command{mpatch}$B$r;HMQ$7$?>l9g$O!$7k2L$K:Y?4$NCm0U(B +$B$,I,MW$G$"$k!%<B:]$K$O(B\command{mpatch}$B$O%D!<%k$N=PNO$GFs=E%A%'%C%/$r6/@)(B +$B$7!$F0:n$,=*$k$H<+F0E*$K%^!<%8%W%m%0%i%`$r5/F0$9$k!%$3$l$K$h$C$F:n6H$r3N(B +$BG'$7!$%^!<%8$r40N;$9$k$3$H$,$G$-$k!%(B + +%\section{Getting the best performance out of MQ} +\section{MQ$B$r:GBg8B$K3hMQ$9$k(B} +\label{sec:mq:perf} + +%MQ is very efficient at handling a large number of patches. I ran +%some performance experiments in mid-2006 for a talk that I gave at the +%2006 EuroPython conference~\cite{web:europython}. I used as my data +%set the Linux 2.6.17-mm1 patch series, which consists of 1,738 +%patches. I applied these on top of a Linux kernel repository +%containing all 27,472 revisions between Linux 2.6.12-rc2 and Linux +%2.6.17. + +MQ$B$O$H$F$b8zN(E*$KBgNL$N%Q%C%A$r=hM}$9$k$3$H$,$G$-$k!%I.<T$O(B2006$BG/$NCf:"!$(B +2006 EuroPython conference~\cite{web:europython}$B$G$N9V1i$N$?$a$K@-G=B,Dj(B +$B$r9T$C$?!%B,Dj$KMQ$$$?%G!<%?$O(BLinux 2.6.17-mm1$B$N%Q%C%A%7%j!<%:$G!$(B1,738 +$B$N%Q%C%A$r4^$`!%$3$N%Q%C%A$r(BLinux kernel$B%j%]%8%H%j$KE,MQ$7$?!%%j%]%8%H%j(B +$B$O(BLinux 2.6.12-rc2$B$+$i(BLinux 2.6.17$B$^$G$N(B27,472$B$N%j%S%8%g%s$r4^$s$G$$$k!%(B + +%On my old, slow laptop, I was able to +%\hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-a}} all 1,738 patches in 3.5 minutes, +%and \hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a}} them all in 30 seconds. (On a +%newer laptop, the time to push all patches dropped to two minutes.) I +%could \hgxcmd{mq}{qrefresh} one of the biggest patches (which made 22,779 +%lines of changes to 287 files) in 6.6 seconds. + +$BI.<T$N8E$/CY$$%i%C%W%H%C%W$G!$(B\hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-a}}$B$G(B +1738$B$N%Q%C%A$9$Y$F$r=hM}$9$k$N$K(B +3.5$BJ,!$(B\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a}}$B$r9T$&$N$K(B30$BIC$rMW$7$?!%(B($B?7(B +$B$7$$%i%C%W%H%C%W$G$O%W%C%7%e$N=jMW;~4V$O(B2$BJ,$G$"$C$?!%(B)$B:GBg$N%Q%C%A(B +(22.778$B9T$G!$(B287$B$N%U%!%$%k$rJQ99$9$k(B)$B$K(B\hgxcmd{mq}{qrefresh}$B$r9T$C$?$H$3(B +$B$m!$(B6.6$BIC$rMW$7$?!%(B + +%Clearly, MQ is well suited to working in large trees, but there are a +%few tricks you can use to get the best performance of it. + +MQ$B$,5pBg$J%D%j!<$G$N:n6H$KE,$7$F$$$k$N$OL@$i$+$@$,!$$5$i$K:G9b$N@-G=$r0z(B +$B$-=P$9$?$a$K$$$/$D$+$N%H%j%C%/$,;H$($k!%(B + +%First of all, try to ``batch'' operations together. Every time you +%run \hgxcmd{mq}{qpush} or \hgxcmd{mq}{qpop}, these commands scan the working +%directory once to make sure you haven't made some changes and then +%forgotten to run \hgxcmd{mq}{qrefresh}. On a small tree, the time that +%this scan takes is unnoticeable. However, on a medium-sized tree +%(containing tens of thousands of files), it can take a second or more. + +$B$^$:Bh0l$K!$(B``batch''$B%*%Z%l!<%7%g%s$rJ;MQ$9$k$3$H$,$G$-(B +$B$k!%(B\hgxcmd{mq}{qpush}$B$^$?$O(B\hgxcmd{mq}{qpop}$B$O!$%o!<%-%s%0%G%#%l%/%H%j$K(B +$BJQ99$r2C$($?$N$K(B\hgxcmd{mq}{qrefresh}$B$N<B9T$rK:$l$F$$$J$$$+$I$&$+D4$Y$k$?(B +$B$a!$<B9T;~$K>o$K%o!<%-%s%0%G%#%l%/%H%j$r%9%-%c%s$9$k!%>.5,LO$J%D%j!<$G$O(B +$B5$$E$+$J$$DxEY$N;~4V$7$+$+$+$i$J$$$,!$(B($B?tK|$N%U%!%$%k$r;}$D$h$&$J(B)$BCf5,LO(B +$B$N$G$O?tIC$N;~4V$rMW$9$k!%(B + +%The \hgxcmd{mq}{qpush} and \hgxcmd{mq}{qpop} commands allow you to push and pop +%multiple patches at a time. You can identify the ``destination +%patch'' that you want to end up at. When you \hgxcmd{mq}{qpush} with a +%destination specified, it will push patches until that patch is at the +%top of the applied stack. When you \hgxcmd{mq}{qpop} to a destination, MQ +%will pop patches until the destination patch is at the top. + +\hgxcmd{mq}{qpush}$B%3%^%s%I$H(B\hgxcmd{mq}{qpop}$B%3%^%s%I$OJ#?t$N%U%!%$%k$rF1(B +$B;~$K(Bpush$B$^$?$O(Bpop$B$9$k$3$H$,$G$-$k!%:G=*L\E*$N%Q%C%A$,$"$k$J$i(B +$B$P!$(B\hgxcmd{mq}{qpush}$B$KL\E*$N%Q%C%A$r;XDj$7$F<B9T$9$k$3$H$G!$;XDj$7$?%Q%C(B +$B%A$,:F>e0L$K$J$k$^$G%Q%C%A$r(Bpush$B$9$k!%F1MM$K(B\hgxcmd{mq}{qpop}$B$KL\E*$N%Q%C(B +$B%A$r;XDj$9$l$P!$;XDj$7$?%Q%C%A$,:F>e0L$K$J$k$^$G%Q%C%A$r(Bpop$B$9$k!%(B + +%You can identify a destination patch using either the name of the +%patch, or by number. If you use numeric addressing, patches are +%counted from zero; this means that the first patch is zero, the second +%is one, and so on. + +$BL\E*$N%Q%C%A$OL>A0$G$bHV9f$G$b;XDj2DG=$G$"$k!%HV9f$,MQ$$$i$l$k>l9g$O!$%Q%C(B +$B%A$O(B0$B$+$i%+%&%s%H$5$l$k!%$D$^$j:G=i$N%Q%C%A$O(B0$B$H$J$j!$(B2$BHVL\$O(B1$B!$$H$$$&Iw(B +$B$K$J$k!%(B + +%\section{Updating your patches when the underlying code changes} +\section{$BBP>]%3!<%I$NJQ2=$K9g$o$;$F%Q%C%A$r99?7$9$k(B} +\label{sec:mq:merge} + +%It's common to have a stack of patches on top of an underlying +%repository that you don't modify directly. If you're working on +%changes to third-party code, or on a feature that is taking longer to +%develop than the rate of change of the code beneath, you will often +%need to sync up with the underlying code, and fix up any hunks in your +%patches that no longer apply. This is called \emph{rebasing} your +%patch series. + +$BD>@\JQ99$7$J$$%j%]%8%H%j$N>e$K%Q%C%A$N%9%?%C%/$r4IM}$9$k$3$H$O$h$/9T$o$l(B +$B$k!%%5!<%I%Q!<%F%#$N%3!<%I$rJQ99$9$k:n6H$r$7$F$$$k>l9g$d!$85$K$J$k%3!<%I(B +$B$NJQ99IQEY$KHf$Y$FD9$$;~4V$,$+$+$k5!G=$r3+H/$7$F$$$k>l9g!$$7$P$7$P85$N%3!<(B +$B%I$NF14|$r9T$$!$%Q%C%A$NCf$N$b$O$dE,MQ$G$-$J$/$J$C$?(Bhunk$B$r=$@5$9$k$3$H$K(B +$B$J$k$@$m$&!%$3$l$O%Q%C%A$N(B\emph{rebasing}$B$H8F$P$l$k!%(B + +%The simplest way to do this is to \hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a}} +%your patches, then \hgcmd{pull} changes into the underlying +%repository, and finally \hgcmdargs{qpush}{\hgxopt{mq}{qpop}{-a}} your +%patches again. MQ will stop pushing any time it runs across a patch +%that fails to apply during conflicts, allowing you to fix your +%conflicts, \hgxcmd{mq}{qrefresh} the affected patch, and continue pushing +%until you have fixed your entire stack. + +$B$3$l$r9T$&:G$b4JC1$JJ}K!$O!$%Q%C%A$KBP$7$F(B +\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a}}$B$r9T$$!$2<0L$N%j%]%8%H%j$K(B +\hgcmd{pull}$B$r9T$&!%$=$7$F:G8e$K%Q%C%A$K:F$S(B +\hgcmdargs{qpush}{\hgxopt{mq}{qpop}{-a}}$B$r9T$&!%(B MQ$B$O%Q%C%AE,MQCf$K%3%s%U(B +$B%j%/%H$,$"$k$H!$$$$D$G$b%W%C%7%e$rDd;_$7!$(B\hgxcmd{mq}{qrefresh}$B$K$h$C$F%3(B +$B%s%U%j%/%H$r=$@5$9$k5!2q$rM?$($k!%$=$N8e$K$9$Y$F$N%Q%C%A%9%?%C%/$rE,MQ$9(B +$B$k$^$G%W%C%7%e$rB3$1$k!%(B + +%This approach is easy to use and works well if you don't expect +%changes to the underlying code to affect how well your patches apply. +%If your patch stack touches code that is modified frequently or +%invasively in the underlying repository, however, fixing up rejected +%hunks by hand quickly becomes tiresome. + +$B$3$N%"%W%m!<%A$O4JC1$G!$%Q%C%A$NE,MQ$5$l$k2<0L$N%3!<%I$X$NJQ99$,$J$1$l$P(B +$B$&$^$/F/$/!%$7$+$7!$%Q%C%A%9%?%C%/$,!$IQHK$K99?7$5$l$?$j!$2<0L%j%]%8%H%j(B +$B$X?/F~E*$K99?7$5$l$?$j$9$k%3!<%I$K?($l$F$$$k>l9g$O%j%8%'%/%H$5$l$?%3!<%I(B +$B$N=$@5$OLLE]$J$b$N$K$J$k!%(B + +%It's possible to partially automate the rebasing process. If your +%patches apply cleanly against some revision of the underlying repo, MQ +%can use this information to help you to resolve conflicts between your +%patches and a different revision. + +rebase$B%W%m%;%9$rItJ,E*$K<+F02=$9$k$3$H$O2DG=$G$"$k!%%Q%C%A$,2<0L$N%j%]%8(B +$B%H%j$N$$$:$l$+$N%P!<%8%g%s$K%/%j!<%s$KE,MQ$G$-$k$N$G$"$l$P!$(BMQ$B$O$3$N>pJs(B +$B$r;H$C$F%Q%C%A$H$=$NB>$N%j%S%8%g%s$H$N4V$N%3%s%U%j%/%H$r2r>C$9$k$N$r1g=u(B +$B$9$k!%(B + +%The process is a little involved. +$B$3$N%W%m%;%9$O$d$d9~$_F~$C$F$$$k!%(B +\begin{enumerate} +%\item To begin, \hgcmdargs{qpush}{-a} all of your patches on top of +% the revision where you know that they apply cleanly. +\item $B:G=i$K!$%Q%C%A$,%/%j!<%s$KE,MQ$G$-$k%j%S%8%g%s$N>e$G!$$9$Y$F$N%Q%C(B + $B%A$KBP$7$F(B\hgcmdargs{qpush}{-a}$B$r9T$&!%(B + +%\item Save a backup copy of your patch directory using +% \hgcmdargs{qsave}{\hgxopt{mq}{qsave}{-e} \hgxopt{mq}{qsave}{-c}}. +% This prints +% the name of the directory that it has saved the patches in. It will +% save the patches to a directory called +% \sdirname{.hg/patches.\emph{N}}, where \texttt{\emph{N}} is a small +% integer. It also commits a ``save changeset'' on top of your + +% applied patches; this is for internal book-keeping, and records the +% states of the \sfilename{series} and \sfilename{status} files. + +\item $B%Q%C%A%G%#%l%/%H%j$r%;!<%V$r(B + \hgcmdargs{qsave}{\hgxopt{mq}{qsave}{-e} \hgxopt{mq}{qsave}{-c}}$B$r(B + $BMQ$$$F9T$&!%%Q%C%A$r%;!<%V$7$?%G%#%l%/%H%jL>$,I=<($5$l$k!%$3$N%3%^(B + $B%s%I$O!$(B\sdirname{.hg/patches.\emph{N}}$B$H$$$&%G%#%l%/%H%j$K%;!<%V$r(B + $B9T$&!%$3$3$G(B\texttt{\emph{N}}$B$O>.$5$$@0?t$G$"$k!%$3$N%3%^%s%I$O(B``$B%;!<(B + $B%V%A%'%s%8%;%C%H(B''$B$rE,MQ$5$l$?%Q%C%A$N>e$K%3%_%C%H$9$k!%$3$l$OFbIt(B + $BE*$J4IM}$H!$(B\sfilename{series}$B%U%!%$%k5Z$S(B\sfilename{status}$B%U%!%$(B + $B%k$N>uBV$r5-O?$9$k$?$a$G$"$k!%(B + +%\item Use \hgcmd{pull} to bring new changes into the underlying +% repository. (Don't run \hgcmdargs{pull}{-u}; see below for why.) + +\item \hgcmd{pull}$B%3%^%s%I$r;H$C$F?7$?$JJQ99$r2<0L$N%j%]%8%H%j$K<h$j9~(B + $B$`!%(B(\hgcmdargs{pull}{-u}$B$r<B9T$7$F$O$$$1$J$$!%M}M3$K$D$$$F$O2<5-(B + $B$r;2>H!%(B) + +%\item Update to the new tip revision, using +% \hgcmdargs{update}{\hgopt{update}{-C}} to override the patches you +% have pushed. + +\item \hgcmdargs{update}{\hgopt{update}{-C}}$B$rMQ$$$F!$(Bpush$B$7$?%Q%C%A$r%*!<(B + $B%P%i%$%I$7$F?7$?$J(Btip$B%j%S%8%g%s$X$N%"%C%W%G!<%H$r9T$&!%(B + +%\item Merge all patches using \hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-m} +% \hgxopt{mq}{qpush}{-a}}. The \hgxopt{mq}{qpush}{-m} option to \hgxcmd{mq}{qpush} +% tells MQ to perform a three-way merge if the patch fails to apply. + +\item \hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-m} \hgxopt{mq}{qpush}{-a}}$B$r(B + $BMQ$$$F$9$Y$F$N%Q%C%A$N%^!<%8$r9T$&!%(B\hgxopt{mq}{qpush}{-m}$B%*%W%7%g(B + $B%s$r(B\hgxcmd{mq}{qpush}$B$KIU$1$k$H!$(BMQ$B$O%Q%C%A$NE,MQ$K<:GT$7$?>l(B + $B9g!$(B3$B%&%'%$%^!<%8$r9T$&!%(B + +\end{enumerate} + +%During the \hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-m}}, each patch in the +%\sfilename{series} file is applied normally. If a patch applies with +%fuzz or rejects, MQ looks at the queue you \hgxcmd{mq}{qsave}d, and +%performs a three-way merge with the corresponding changeset. This +%merge uses Mercurial's normal merge machinery, so it may pop up a GUI +%merge tool to help you to resolve problems. + +\hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-m}}$B%3%^%s%I$N<B9T(B +$BCf!$(B\sfilename{series}$BFb$N%Q%C%A$ODL>oDL$jE,MQ$5$l$k!%$b$7%Q%C%A$,(Bfuzz$B$d(B +reject$B$r=P$7$?>l9g!$(BMQ$B$O(B\hgxcmd{mq}{qsave}$B$7$?%-%e!<$r;2>H$7!$BP1~$9$k%A%'(B +$B%s%8%;%C%H$H$N4V$G(B3$B%&%'%$%^!<%8$r9T$&!%%^!<%8$O(BMercurial$B$NDL>o$N5!9=$r;H$C(B +$B$F9T$o$l$k$?$a!$@_Dj$K$h$C$FLdBj$r2r7h$9$k$?$a$N(BGUI$B%^!<%8%D!<%k$J$I$,5/F0(B +$B$9$k!%(B + +%When you finish resolving the effects of a patch, MQ refreshes your +%patch based on the result of the merge. + +$B%Q%C%A$N1F6A$N2r7h$r=*$($?;~!$(BMQ$B$O%^!<%8$N7k2L$rF'$^$($F%Q%C%A$N%j%U%l%C(B +$B%7%e$r9T$&!%(B + +%At the end of this process, your repository will have one extra head +%from the old patch queue, and a copy of the old patch queue will be in +%\sdirname{.hg/patches.\emph{N}}. You can remove the extra head using + +%\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a} \hgxopt{mq}{qpop}{-n} patches.\emph{N}} +%or \hgcmd{strip}. You can delete \sdirname{.hg/patches.\emph{N}} once +%you are sure that you no longer need it as a backup. + +$B$3$N%W%m%;%9$N:G8e$K%j%]%8%H%j$K$O8E$$%Q%C%A%-%e!<$KM3Mh$9$k0l$DM>J,$J(B +head$B$,$G$-!$8E$$%Q%C%A%-%e!<$,(B\sdirname{.hg/patches.\emph{N}}$B$K%3%T!<$5$l(B +$B$k!%$3$N(Bhead$B$O(B\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a} +\hgxopt{mq}{qpop}{-n} patches.\emph{N}}$B$^$?$O(B\hgcmd{strip}$B$K$h$C$F>C5n$G(B +$B$-$k!%%P%C%/%"%C%W$,ITMW$J$3$H$,J,$+$l$P!$(B\sdirname{.hg/patches.\emph{N}}$B$r(B +$B>C5n$7$F$b9=$o$J$$!%(B + +%\section{Identifying patches} +\section{$B%Q%C%A$N<1JL(B} + +%MQ commands that work with patches let you refer to a patch either by +%using its name or by a number. By name is obvious enough; pass the +%name \filename{foo.patch} to \hgxcmd{mq}{qpush}, for example, and it will +%push patches until \filename{foo.patch} is applied. + +$B%Q%C%A$r07$&(BMQ$B%3%^%s%I$O!$%Q%C%A$r%Q%C%AL>$^$?$OHV9f$G;2>H$9$k!%L>A0$N>l(B +$B9g$ONc$($P%U%!%$%kL>(B\filename{foo.patch}$B$r(B\hgxcmd{mq}{qpush}$B$KEO$9!%$3$N(B +$B>l9g!$%3%^%s%I$O(B\filename{foo.patch}$B$^$G$N%U%!%$%k$r%W%C%7%e$9$k!%(B + +%As a shortcut, you can refer to a patch using both a name and a +%numeric offset; \texttt{foo.patch-2} means ``two patches before +%\texttt{foo.patch}'', while \texttt{bar.patch+4} means ``four patches +%after \texttt{bar.patch}''. + +$B%7%g!<%H%+%C%H$H$7$F!$%Q%C%A$KL>A0$H?t;z$K$h$k%*%U%;%C%HN>J}$rMQ$$$F;2>H(B +$B$9$k$3$H$,$G$-$k!%(B\texttt{foo.patch-2}$B$O(B``\texttt{foo.patch}$B$N(B2$B$DA0$N%Q%C(B +$B%A(B''$B$H2r<a$5$l$k!%$^$?!$(B\texttt{bar.patch+4}$B$O(B``\texttt{bar.patch}$B$N(B4$B$D(B +$B8e$N%Q%C%A(B''$B$H2r<a$5$l$k!%(B + +%Referring to a patch by index isn't much different. The first patch +%printed in the output of \hgxcmd{mq}{qseries} is patch zero (yes, it's one +%of those start-at-zero counting systems); the second is patch one; and +%so on + +$B%$%s%G%C%/%9$,$"$^$j0c$o$J$$%Q%C%A$N;2>H!%(B\hgxcmd{mq}{qseries}$B$G:G=i$KI=(B +$B<($5$l$k%Q%C%A$O%Q%C%A(B0($B$3$l$b(B0$B$+$i?t$(;O$a$k(B)$B$G!$(B2$BHVL\$O%Q%C%A(B1$B$N$h$&$K(B +$BB3$/!%(B + +%MQ also makes it easy to work with patches when you are using normal +%Mercurial commands. Every command that accepts a changeset ID will +%also accept the name of an applied patch. MQ augments the tags +%normally in the repository with an eponymous one for each applied +%patch. In addition, the special tags \index{tags!special tag +% names!\texttt{qbase}}\texttt{qbase} and \index{tags!special tag +% names!\texttt{qtip}}\texttt{qtip} identify the ``bottom-most'' and +%topmost applied patches, respectively. + +MQ$B$O!$DL>o$N(BMercurial$B%3%^%s%I$r;H$&;~$N$b4JC1$K$7$F$$$k!%A4$F$N%3%^%s%I$O(B +$B%A%'%s%8%;%C%H(BID$B$HE,MQ$5$l$?%Q%C%A$NHV9f$r<u$1IU$1$k!%(BMQ$B$O!$%j%]%8%H%j$K(B +$BE,MQ$5$l$?%Q%C%A$NL>A0$N$D$$$?%?%0$r<u$1IU$1$k!%$5$i$K!$:G2<0L$NE,MQ$5$l(B +$B$?%Q%C%A$rI=$9FCJL$J%?%0(B\index{tags!special tag +names!\texttt{qbase}}\texttt{qbase}$B$H!$:G>e0L$rI=$9FCJL$J%?%0(B +\index{tags!special tag names!\texttt{qtip}}\texttt{qtip}$B$b<u$1IU$1$k!%(B + +%These additions to Mercurial's normal tagging capabilities make +%dealing with patches even more of a breeze. + +Mercurial$B$NDL>o$N%?%05!G=$X$N$3$l$i$NDI2C$O!$%Q%C%A$N<h$j07$$$K$*$$$FBg$-(B +$B$J0UL#$r;}$D!%(B + +\begin{itemize} +%\item Want to patchbomb a mailing list with your latest series of +% changes? +\item $B0lO"$N:G?7$NJQ99$r%Q%C%AGzCF$H$7$F%a!<%j%s%0%j%9%H$X$KEj$29~$_$?$$(B + $B$@$m$&$+!)(B + \begin{codesample4} + hg email qbase:qtip + \end{codesample4} +% (Don't know what ``patchbombing'' is? See +% section~\ref{sec:hgext:patchbomb}.) +(``patchbombing''$B$,2?$+J,$+$i$J$1$l$P(Bsection~\ref{sec:hgext:patchbomb}$B$r(B + $B;2>H$N$3$H!%(B) +%\item Need to see all of the patches since \texttt{foo.patch} that +% have touched files in a subdirectory of your tree? + \item $B%D%j!<Cf$N%5%V%G%#%l%/%H%j$K4^$^$l$k%U%!%$%k$K?($l$?(B + \texttt{foo.patch}$B0J9_$N%Q%C%A$rA4$F8+$?$$$+!)(B + \begin{codesample4} + hg log -r foo.patch:qtip \emph{subdir} + \end{codesample4} +\end{itemize} + +%Because MQ makes the names of patches available to the rest of +%Mercurial through its normal internal tag machinery, you don't need to +%type in the entire name of a patch when you want to identify it by +%name. + +MQ$B$G$N%Q%C%A$NL>>N$O!$FbIt$N%?%05!9=$rMQ$$$F$$$k$?$a!$(BMercurial$B$NB>$NItJ,(B +$B$G$bMxMQ2DG=$G$"$k!%L>>N$r;XDj$9$k;~!$L>>NA4$F$rF~NO$9$kI,MW$O$J$$!%(B + +\begin{figure}[ht] + \interaction{mq.id.output} +% \caption{Using MQ's tag features to work with patches} + \caption{$B%Q%C%A$r07$&$?$a(BMQ$B$N%?%05!G=$rMxMQ$9$k(B} + \label{ex:mq:id} +\end{figure} + +%Another nice consequence of representing patch names as tags is that +%when you run the \hgcmd{log} command, it will display a patch's name +%as a tag, simply as part of its normal output. This makes it easy to +%visually distinguish applied patches from underlying ``normal'' +%revisions. Figure~\ref{ex:mq:id} shows a few normal Mercurial +%commands in use with applied patches. + +$B%Q%C%AL>$r%?%0$H$7$F<h$j07$&$3$H$N$b$&0l$D$NMxE@$O!$(B\hgcmd{log}$B%3%^%s%I(B +$B$r<B9T$7$?;~!$DL>o=PNO$N0lIt$K%Q%C%AL>$r%?%0$H$7$FI=<($9$kE@$G$"$k!%$3$N(B +$B$?$a!$E,MQ$7$?%Q%C%A$O2<0L$N(B``$BDL>o$N(B''$B%j%S%8%g%s$H;k3PE*$K6hJL$70W$/$J$k!%(B +$B?^(B~\ref{ex:mq:id}$B$K$$$/$D$+$NDL>o$N(BMercurial$B%3%^%s%I$rE,MQ:Q$_%Q%C%A$H6&(B +$B$K;HMQ$7$?>l9g$r<($9!%(B + +%\section{Useful things to know about} +\section{$BCN$C$F$*$/$Y$-$$$/$D$+$NE@(B} + +%There are a number of aspects of MQ usage that don't fit tidily into +%sections of their own, but that are good to know. Here they are, in +%one place. + +MQ$B$N;HMQK!$K$O8DJL$K<h$j>e$2$k$[$I$G$O$J$$$,!$CN$C$F$*$/$HNI$$$$$/$D$+$N(B +$BE@$,$"$k!%$3$3$G$O$=$l$i$r$^$H$a$F<h$j>e$2$k!%(B + +\begin{itemize} +%\item Normally, when you \hgxcmd{mq}{qpop} a patch and \hgxcmd{mq}{qpush} it +% again, the changeset that represents the patch after the pop/push +% will have a \emph{different identity} than the changeset that +% represented the hash beforehand. See +% section~\ref{sec:mqref:cmd:qpush} for information as to why this is. +\item $B%Q%C%A$r(B\hgxcmd{mq}{qpop}$B$7$?8e$G:F$S(B\hgxcmd{mq}{qpush}$B$9$k(B + $B$H!$(Bpop/push$B$7$?8e$N%A%'%s%8%;%C%H$O!$0JA0$N%A%'%s%8%;%C%H$H0[$J$k(B + $B%"%$%G%s%F%#%F%#$r;}$A!$%O%C%7%eCM$,0[$J$k!%$3$NM}M3$K$D$$$F$O%;%/(B + $B%7%g%s(B~\ref{sec:mqref:cmd:qpush}$B$r;2>H$5$l$?$$!%(B +%\item It's not a good idea to \hgcmd{merge} changes from another +% branch with a patch changeset, at least if you want to maintain the +% ``patchiness'' of that changeset and changesets below it on the +% patch stack. If you try to do this, it will appear to succeed, but +% MQ will become confused. +\item \hgcmd{merge}$B$,B>$N%V%i%s%A$N%Q%C%A%A%'%s%8%;%C%H$r%^!<%8$9$k$3$H(B + $B$O!$$=$N%A%'%s%8%;%C%H$H%Q%C%A%9%?%C%/$K@Q$_9~$^$l$?B>$N%A%'%s%8%;%C(B + $B%H$H$N4V$G0l4S@-$r0];}$7$h$&$H$9$k$N$G$"$l$PHr$1$k$Y$-$G$"$k!%$3$l(B + $B$r;n$_$?>l9g!$0l8+@.8y$7$?$h$&$K8+$($F$b(BMQ$B$O:.Mp>uBV$K4Y$C$F$7$^(B + $B$&!%(B +\end{itemize} + +%\section{Managing patches in a repository} +\section{$B%j%]%8%H%jFb$G$N%Q%C%A$N4IM}(B} +\label{sec:mq:repo} + +%Because MQ's \sdirname{.hg/patches} directory resides outside a +%Mercurial repository's working directory, the ``underlying'' Mercurial +%repository knows nothing about the management or presence of patches. + +MQ$B$N(B\sdirname{.hg/patches}$B%G%#%l%/%H%j$O(BMercurial$B%j%]%8%H%j$N%o!<%-%s%0(B +$B%G%#%l%/%H%j$N30$K$"$k$N$G!$(B``$B2<0L$N(B''Mercurial$B%j%]%8%H%j$O%Q%C%A$N4IM}(B +$B$d!$$=$NB;0&;yBP$K$D$$$F2?$bCN$i$J$$!%(B + +%This presents the interesting possibility of managing the contents of +%the patch directory as a Mercurial repository in its own right. This +%can be a useful way to work. For example, you can work on a patch for +%a while, \hgxcmd{mq}{qrefresh} it, then \hgcmd{commit} the current state of +%the patch. This lets you ``roll back'' to that version of the patch +%later on. + +$B$3$N$3$H$+$i!$%Q%C%A%G%#%l%/%H%j$N4IM}$rFHN)$7$?(BMercurial$B%j%]%8%H%j$H$7$F(B +$B9T$&$3$H$,$G$-$k$N$G$O$J$$$+$H$$$&6=L#$,@8$^$l$k!%<B:]$3$NJ}K!$OM-8z$JJ}(B +$BK!$H$J$jF@$k!%Nc$($P!$$7$P$i$/$N4V(B1$B$D$N%Q%C%A$K$D$$$F:n6H$r9T$C$?8e(B +$B$G!$(B\hgxcmd{mq}{qrefresh}$B$r9T$$!$%Q%C%A$N8=:_$N>uBV$r(B\hgcmd{commit}$B$9$k(B +$B$3$H$,$G$-$k!%$3$l$K$h$C$F!$8e$G$3$N%Q%C%A$r(B``$B%m!<%k%P%C%/(B''$B$9$k$3$H$,2D(B +$BG=$H$J$k!%(B + +%You can then share different versions of the same patch stack among +%multiple underlying repositories. I use this when I am developing a +%Linux kernel feature. I have a pristine copy of my kernel sources for +%each of several CPU architectures, and a cloned repository under each +%that contains the patches I am working on. When I want to test a +%change on a different architecture, I push my current patches to the +%patch repository associated with that kernel tree, pop and push all of +%my patches, and build and test that kernel. + +$BJ#?t$N2<0L%j%]%8%H%j$N4V$G!$F1$8%Q%C%A%9%?%C%/$N0[$J$k%P!<%8%g%s$r6&M-$9(B +$B$k$3$H$,$G$-$k!%I.<T$O$3$l$r(BLinux$B%+!<%M%k$N5!G=$r3+H/$9$k;~$KMxMQ$7$F$$(B +$B$k!%$$$/$D$+$N(BCPU$B%"!<%-%F%/%A%c$N3F!9$KBP$7$F$^$C$5$i$J%+!<%M%k%=!<%9$N%j(B +$B%]%8%H%j$rMQ0U$7!$:n6HCf$N%Q%C%A$r4^$`%j%]%8%H%j$r$=$l$i$N4V$G%/%m!<%s$7(B +$B$F$$$k!%JQ99$r0[$J$k%"!<%-%F%/%A%c$G%F%9%H$7$?$$;~$O!$8=:_$N%Q%C%A$r$=$N(B +$B%"!<%-%F%/%A%cMQ$N%+!<%M%k%D%j!<$H7k$SIU$$$?%Q%C%A$N%j%]%8%H%j$X%W%C%7%e(B +$B$7!$$9$Y$F$N%Q%C%A$r(Bpop$B!$(Bpush$B$7$F%+!<%M%k$N%S%k%I$H%F%9%H$r9T$C$F$$$k!%(B + +%Managing patches in a repository makes it possible for multiple +%developers to work on the same patch series without colliding with +%each other, all on top of an underlying source base that they may or +%may not control. + +$B%j%]%8%H%jFb$G%Q%C%A$r4IM}$9$k$H!$J#?t$N3+H/<T$,F1$8%Q%C%A%7%j!<%:$N>e$G(B +$B>WFM$9$k$3$H$J$/:n6H$G$-$k$h$&$K$J$k!%$3$l$OH`$i$,2<0L$N%=!<%9%Y!<%9$r%3(B +$B%s%H%m!<%k$G$-$k$+H]$+$K4X$o$j$,$J$$!%(B + +%\subsection{MQ support for patch repositories} +\subsection{MQ$B$K$h$k%Q%C%A%j%]%8%H%j%5%]!<%H(B} + +%MQ helps you to work with the \sdirname{.hg/patches} directory as a +%repository; when you prepare a repository for working with patches +%using \hgxcmd{mq}{qinit}, you can pass the \hgxopt{mq}{qinit}{-c} option to +%create the \sdirname{.hg/patches} directory as a Mercurial repository. + +MQ$B$O(B\sdirname{.hg/patches}$B%G%#%l%/%H%j$r%j%]%8%H%j$H$7$F;H$$$J$,$i:n6H$9(B +$B$k$3$H$r%5%]!<%H$7$F$$$k!%%Q%C%A$r07$&:n6HMQ$N%j%]%8%H%j$r(B +\hgxcmd{mq}{qinit}$B$G:n@.$9$k;~!$(B\hgxopt{mq}{qinit}{-c}$B$rEO$7$F(B +\sdirname{.hg/patches}$B%G%#%l%/%H%j$r(BMercurial$B%j%]%8%H%j$K$9$k$3$H$,$G$-$k!%(B + +\begin{note} +% If you forget to use the \hgxopt{mq}{qinit}{-c} option, you can simply go +% into the \sdirname{.hg/patches} directory at any time and run +% \hgcmd{init}. Don't forget to add an entry for the +% \sfilename{status} file to the \sfilename{.hgignore} file, though +% (\hgcmdargs{qinit}{\hgxopt{mq}{qinit}{-c}} does this for you +% automatically); you \emph{really} don't want to manage the +% \sfilename{status} file. + + \hgxopt{mq}{qinit}{-c}$B%*%W%7%g%s$rK:$l$?>l9g$O$$$D$G$b(B + \sdirname{.hg/patches}$B$KF~$C$F(B\hgcmd{init}$B$r<B9T$9$l$P$h(B + $B$$!%(B\sfilename{status}$B%U%!%$%k$r(B\sfilename{.hgignore}$B%U%!%$%k$KDI2C$9$k(B + $B$N$rK:$l$J$$$3$H!%(B(\hgcmdargs{qinit}{\hgxopt{mq}{qinit}{-c}}$B$O$3$l$r<+F0(B + $BE*$K9T$&!%!K(B\sfilename{status}$B$r%P!<%8%g%s4IM}$9$kI,MW$O(B\emph{$BA4$/$J$$(B}$B!%(B +\end{note} + +%As a convenience, if MQ notices that the \dirname{.hg/patches} +%directory is a repository, it will automatically \hgcmd{add} every +%patch that you create and import. + +\dirname{.hg/patches}$B$,%j%]%8%H%j$N;~$O!$(BMQ$B$OJXMx$N$?$a$K$3$l$^$G:n@.$7!$(B +$B%$%s%]!<%H$7$?$9$Y$F$N%Q%C%A$r<+F0E*$K(B\hgcmd{add}$B$9$k!%(B + +%MQ provides a shortcut command, \hgxcmd{mq}{qcommit}, that runs +%\hgcmd{commit} in the \sdirname{.hg/patches} directory. This saves +%some bothersome typing. + +MQ$B$O%7%g!<%H%+%C%H%3%^%s%I(B\hgxcmd{mq}{qcommit}$B$r;}$D!%$3$N%3%^%s%I$O(B +\hgcmd{commit}$B%3%^%s%I$r(B\sdirname{.hg/patches}$B%G%#%l%/%H%j$NCf$G<B9T$9(B +$B$k!%$3$l$K$h$C$FHK;($JF~NO$r>J$/$3$H$,$G$-$k!%(B + +%Finally, as a convenience to manage the patch directory, you can +%define the alias \command{mq} on Unix systems. For example, on Linux +%systems using the \command{bash} shell, you can include the following +%snippet in your \tildefile{.bashrc}. + +$B%Q%C%A%G%#%l%/%H%j$N4IM}$N$?$a$K(BUNIX$B4D6-$J$i(B\command{mq}$B$H$$$&%(%$%j%"%9(B +$B$r:n$C$F$*$/$HJXMx$@!%(BLinux$B$G$O(B\command{bash}$B%7%'%k$N@_Dj%U%!%$%k(B +\tildefile{.bashrc}$B$K$3$l$rDj5A$7$F$*$/!%(B + +\begin{codesample2} + alias mq=`hg -R \$(hg root)/.hg/patches' +\end{codesample2} + +%You can then issue commands of the form \cmdargs{mq}{pull} from +%the main repository. + +$B%a%$%s%j%]%8%H%j$+$i(B\cmdargs{mq}{pull}$B$r<B9T$9$k$3$H$,$G$-$k(B + +%\subsection{A few things to watch out for} +\subsection{$BCm0U$7$F$*$/$Y$-$$$/$D$+$NE@(B} + +%MQ's support for working with a repository full of patches is limited +%in a few small respects. + +MQ$B$,BgNL$N%Q%C%A$N$"$k%j%]%8%H%j$r07$&:]$K!$$$$/$D$+$N>.$5$JE@$+$i@)8B$,(B +$B$"$k!%(B + +%MQ cannot automatically detect changes that you make to the patch +%directory. If you \hgcmd{pull}, manually edit, or \hgcmd{update} +%changes to patches or the \sfilename{series} file, you will have to +%\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a}} and then +%\hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-a}} in the underlying repository to +%see those changes show up there. If you forget to do this, you can +%confuse MQ's idea of which patches are applied. + +MQ$B$O!$%Q%C%A%G%#%l%/%H%j$KBP$7$F9T$o$l$?JQ99$r<+F0E*$K8!=P$9$k$3$H$O$G$-(B +$B$J$$!%%Q%C%A%U%!%$%k$d(B\sfilename{series}$B$KBP$7$F(B\hgcmd{pull}$B$r9T$C$?$j!$(B +$B<j$GJT=8$7$?$j!$(B\hgcmd{update}$B$r9T$C$?>l9g(B +$B$O!$2<0L$N%j%]%8%H%j$KBP$7$F(B\hgcmdargs{qpop}{\hgxopt{mq}{qpop}{-a}}$B$H(B +\hgcmdargs{qpush}{\hgxopt{mq}{qpush}{-a}}$B$r9T$$!$JQ99$rCN$i$;$kI,MW$,$"(B +$B$k!%$3$l$rK:$l$k$H(BMQ$B$O$I$N%Q%C%A$,E,MQ$5$l$?$N$+GD0.$G$-$J$/$J$C$F$7$^$&!%(B + + +%\section{Third party tools for working with patches} +\section{$B%Q%C%A8~$1%5!<%I%Q!<%F%#%D!<%k(B} +\label{sec:mq:tools} + +%Once you've been working with patches for a while, you'll find +%yourself hungry for tools that will help you to understand and +%manipulate the patches you're dealing with. + +$B$7$P$i$/%Q%C%A$r;H$C$?:n6H$r$7$F$$$k$H!$%Q%C%A$r<h$j07$&=u$1$H$J$k$h$&$J(B +$B%D!<%k$,M_$7$/$J$k$K0c$$$J$$!%(B + +%The \command{diffstat} command~\cite{web:diffstat} generates a +%histogram of the modifications made to each file in a patch. It +%provides a good way to ``get a sense of'' a patch---which files it +%affects, and how much change it introduces to each file and as a +%whole. (I find that it's a good idea to use \command{diffstat}'s +%\cmdopt{diffstat}{-p} option as a matter of course, as otherwise it +%will try to do clever things with prefixes of file names that +%inevitably confuse at least me.) + +\command{diffstat}$B%3%^%s%I(B~\cite{web:diffstat}$B$O%Q%C%AFb$N$=$l$>$l$N%U%!(B +$B%$%k$X$NJQ99$N%R%9%H%0%i%`$r@8@.$9$k!%$3$l$O!$%Q%C%A$,1F6A$r5Z$\$9%U%!%$(B +$B%k$rGD0.$7$?$j!$A4BN$G$=$l$>$l$N%U%!%$%k$X$I$NDxEYJQ99$r2C$($k$N$+GD0.$9(B +$B$k$N$KLrN)$D!%(B $B!J(B\command{diffstat}$B%3%^%s%I$N(B\cmdopt{diffstat}{-p}$B%*%W%7%g(B +$B%s$rMQ$$$k$N$OL^O@NI$$9M$($G$"$k!%$5$b$J$1$l$P%3%^%s%I$O%U%!%$%kL>$N(B +prefix$B$KBP$7$F(B``$B8-$$(B''$B$3$H$r$7$G$+$9$?$a!$>/$J$/$H$bI.<T$O:.Mp$rHr$1$i$l(B +$B$J$+$C$?!%!K(B + + +\begin{figure}[ht] + \interaction{mq.tools.tools} +% \caption{The \command{diffstat}, \command{filterdiff}, and + % \command{lsdiff} commands} + \caption{\command{diffstat}, \command{filterdiff}, $B$*$h$S(B + \command{lsdiff} $B%3%^%s%I(B} + \label{ex:mq:tools} +\end{figure} + +%The \package{patchutils} package~\cite{web:patchutils} is invaluable. +%It provides a set of small utilities that follow the ``Unix +%philosophy;'' each does one useful thing with a patch. The +%\package{patchutils} command I use most is \command{filterdiff}, which +%extracts subsets from a patch file. For example, given a patch that + +%modifies hundreds of files across dozens of directories, a single +%invocation of \command{filterdiff} can generate a smaller patch that +%only touches files whose names match a particular glob pattern. See +%section~\ref{mq-collab:tips:interdiff} for another example. + +\package{patchutils}$B%Q%C%1!<%8(B~\cite{web:patchutils}$B$OHs>o$KM-MQ$G$"$k!%(B +$B$3$N%Q%C%1!<%8$O(B``UNIX$BE/3X(B''$B$K=>$C$?>.$5$J%f!<%F%#%j%F%#$+$i$J$j!$3F!9$N(B +$B%f!<%F%#%j%F%#$O%Q%C%A$KBP$7$FM-MQ$JC15!G=$rDs6!$9(B +$B$k!%(B\package{patchutils}$B$NCf$GI.<T$,:G$bNI$/;H$&%3%^%s%I$O(B +\command{filterdiff}$B$G!$$3$l$O%Q%C%A%U%!%$%k$+$i%Q%C%A$NItJ,=89g$r<h$j=P(B +$B$9!%Nc$($P!$(B10$B0J>e$N%G%#%l%/%H%j$K8Y$C$F?tI4$N%U%!%$%k$KJQ99$r9T$&$h$&$J(B +$B%Q%C%A$,$"$k$H$7$F!$$?$@0l2s$N(B\command{filterdiff}$B$N<B9T$GFCDj$N%Q%?!<%s(B +$B$K%^%C%A$7$?%U%!%$%k$N$_$rJQ99$9$k$h$j>.$5$J%Q%C%A$r@8@.$9$k$3$H$,$G$-(B +$B$k!%$=$N$[$+$NNc$O(B\ref{mq-collab:tips:interdiff}$B$r8+$h!%(B + + +%\section{Good ways to work with patches} +\section{$B9%$^$7$$%Q%C%A<h$j07$$J}K!(B} + +%Whether you are working on a patch series to submit to a free software +%or open source project, or a series that you intend to treat as a +%sequence of regular changesets when you're done, you can use some +%simple techniques to keep your work well organised. + +$B%U%j!<%=%U%H$d%*!<%W%s%=!<%9%W%m%8%'%/%H$KDs=P$9$k$?$a$N%Q%C%A%7%j!<%:$K(B +$BBP$7$F:n6H$7$F$$$k$H$-$d!$:n6H$,=*$C$?$H$-$KDL>o$N%A%'%s%8%;%C%H$H$7$F<h(B +$B$j9~$^$l$kM=Dj$N%Q%C%A%7%j!<%:$KBP$7$F$@9T$7$F$$$k$H$-$O!$:n6H$r$&$^$/7O(B +$BE}$E$1$k$?$a$NC1=c$J%F%/%K%C%/$,$"$k!%(B + +%Give your patches descriptive names. A good name for a patch might be +%\filename{rework-device-alloc.patch}, because it will immediately give +%you a hint what the purpose of the patch is. Long names shouldn't be a +%problem; you won't be typing the names often, but you \emph{will} be +%running commands like \hgxcmd{mq}{qapplied} and \hgxcmd{mq}{qtop} over +%and over. Good naming becomes especially important when you have a +%number of patches to work with, or if you are juggling a number of +%different tasks and your patches only get a fraction of your attention. + +$B%Q%C%A$K5-=RE*$JL>A0$rM?$($k!%%Q%C%A$KM?$($k$Y$-NI$$L>A0$O(B +\filename{rework-device-alloc.patch}$B$N$h$&$J$b$N$G$"$k!%M}M3$OB(:B$K%Q%C(B +$B%A$NL\E*$N%R%s%H$rM?$($k$+$i$G$"$k!%D9$$L>A0$OLdBj$K$O$J$i$J$$!%$J$<$J$i(B +$BL>A0$r%?%$%W$9$k$3$H$OLGB?$K$J$/!$Be$o$j$K(B\hgxcmd{mq}{qapplied}$B$d(B +\hgxcmd{mq}{qtop}$B$N$h$&$J%3%^%s%I$r7+$jJV$7<B9T$9$k$3$H$K$J$k$+$i$G$"$k!%(B +$BB??t$N%Q%C%A$KBP$7$F:n6H$r$7$F$$$k$H$-$O!$NI$$L>A0$rIU$1$k$3$H$OFC$K=EMW(B +$B$H$J$k!%$=$&$7$J$$$H!$$b$7$"$J$?$,$?$/$5$s$NJL$N%?%9%/$rJz$($F$$$k$J$i(B +$B$P!$%Q%C%A$N6hJL$O$D$+$J$/$J$C$F$7$^$&!%(B + +%Be aware of what patch you're working on. Use the \hgxcmd{mq}{qtop} +%command and skim over the text of your patches frequently---for +%example, using \hgcmdargs{tip}{\hgopt{tip}{-p}}---to be sure of where +%you stand. I have several times worked on and \hgxcmd{mq}{qrefresh}ed a +%patch other than the one I intended, and it's often tricky to migrate +%changes into the right patch after making them in the wrong one. + +$B$I$N%Q%C%A$K$D$$$F:n6H$7$F$$$k$N$+GD0.$7$F$*$/$Y$-$G$"(B +$B$k!%(B\hgxcmd{mq}{qtop}$B%3%^%s%I$r;H$$!$%Q%C%A$rIQHK$K%A%'%C%/$9$Y$-$G$"$k!%(B +$B$^$?!$Nc$($P(B\hgcmdargs{tip}{\hgopt{tip}{-p}}$B$r;H$C$F!$$$$^$I$3$K$$$k$N$+(B +$B$rD4$Y$k$3$H$bI,MW$G$"$k!%0U?^$7$F$$$k%Q%C%A0J30$N%Q%C%A$K$D$$$F(B +\hgxcmd{mq}{qrefresh}$B$r9T$$!$4V0c$C$?%Q%C%A$K2C$($i$l$?JQ99$r@5$7$$%Q%C%A(B +$B$K0\F0$5$;$?!%(B + +%For this reason, it is very much worth investing a little time to +%learn how to use some of the third-party tools I described in +%section~\ref{sec:mq:tools}, particularly \command{diffstat} and +%\command{filterdiff}. The former will give you a quick idea of what +%changes your patch is making, while the latter makes it easy to splice +%hunks selectively out of one patch and into another. + +$B$3$N$?$a!$%;%/%7%g%s(B~\ref{sec:mq:tools}$B$G=R$Y$?%5!<%I%Q!<%F%#@=$N$$$/$D$+(B +$B$N%D!<%k!$FC$K(B\command{diffstat}$B$H(B\command{filterdiff}$B$N;H$$J}$r3X$V$N$O(B +$B$H$F$b0UL#$,$"$k!%A0<T$O!$$"$J$?$N%Q%C%A$,$I$N$h$&$JJQ99$r2C$($k$N$+B(:B(B +$B$KCN$k$3$H$,$G$-!$0lJ}$G8e<T$O%Q%C%A$NCf$N(Bhunk$B$rJL$N%Q%C%A$XA^F~$9$k$N$r(B +$BMF0W$K$9$k!%(B + + +%\section{MQ cookbook} +\section{MQ$B%/%C%/%V%C%/(B} + +%\subsection{Manage ``trivial'' patches} +\subsection{``$B%H%j%S%"%k(B''$B$J%Q%C%A$N4IM}(B} + +%Because the overhead of dropping files into a new Mercurial repository +%is so low, it makes a lot of sense to manage patches this way even if +%you simply want to make a few changes to a source tarball that you +%downloaded. + +$B%U%!%$%k$r(BMercurial$B%j%]%8%H%j$KDI2C$9$k%*!<%P%X%C%I$O>.$5$$!%$3$N$?$a!$$?(B +$B$H$(%=!<%9$N(Btar$B%"!<%+%$%V$X>/?t$NJQ99$r2C$($k$@$1$@$H$7$F$b!$%Q%C%A$r%j%](B +$B%8%H%j$G4IM}$9$k$N$ONI$$J}K!$G$"$k!%(B + +%Begin by downloading and unpacking the source tarball, +%and turning it into a Mercurial repository. +%\interaction{mq.tarball.download} + +$B%=!<%9(Btarball$B$r%@%&%s%m!<%I$7$FE83+$7!$$3$l$r(BMercurial$B%j%]%8%H%j$KJQ49$9(B +$B$k!%(B +\interaction{mq.tarball.download} + +%Continue by creating a patch stack and making your changes. +%\interaction{mq.tarball.qinit} + +$B?7$?$J%Q%C%A%9%?%C%/$r:n$j!$JQ99$r9T$&!%(B +\interaction{mq.tarball.qinit} + +%Let's say a few weeks or months pass, and your package author releases +%a new version. First, bring their changes into the repository. +%\interaction{mq.tarball.newsource} +%The pipeline starting with \hgcmd{locate} above deletes all files in +%the working directory, so that \hgcmd{commit}'s +%\hgopt{commit}{--addremove} option can actually tell which files have +%really been removed in the newer version of the source. + +$B?t=54V$+$i?t%+7n7P$C$?;~!$%Q%C%1!<%8$N:n<T$,?7$7$$%P!<%8%g%s$r%j%j!<%9$7(B +$B$?$H$7$h$&!%$=$N>l9g!$$^$:?7$7$$%P!<%8%g%s$H$N:9J,$r%j%]%8%H%j$K<h$j9~$`!%(B +\interaction{mq.tarball.newsource} +\hgcmd{locate}$B$N=PNO$r%Q%$%W$G7R$$$G%o!<%-%s%0%G%#%l%/%H%j$N$9$Y$F$N%U%!(B +$B%$%k$r>C5n$7!$(B\hgcmd{commit}$B%3%^%s%I$N(B\hgopt{commit}{--addremove}$B%*%W%7%g(B +$B%s$r;H$C$F<B:]$K$I$N%U%!%$%k$,?7$7$$%P!<%8%g%s$N%=!<%9$G:o=|$5$l$?$N$+;X(B +$BDj$9$k!%(B + +%Finally, you can apply your patches on top of the new tree. +%\interaction{mq.tarball.repush} + +$B:G8e$K%Q%C%A$r?7$7$$%D%j!<$KE,MQ$9$k!%(B +\interaction{mq.tarball.repush} + +%\subsection{Combining entire patches} +\subsection{$B%Q%C%AF1;N$r7k9g$9$k(B} +\label{sec:mq:combine} + +%MQ provides a command, \hgxcmd{mq}{qfold} that lets you combine entire +%patches. This ``folds'' the patches you name, in the order you name +%them, into the topmost applied patch, and concatenates their +%descriptions onto the end of its description. The patches that you +%fold must be unapplied before you fold them. + +MQ$B$K$O%Q%C%AA4BN$r7k9g$9$k(B\hgxcmd{mq}{qfold}$B$H$$$&%3%^%s%I$,$"$k!%$3$N%3(B +$B%^%s%I$OL>A0$r$D$1$?%Q%C%A$rL>IU$1$?=gHV$G:F>e0L$NE,MQ:Q$_%Q%C%A$K>v$_9~(B +$B$`!%3F!9$N%Q%C%A$N@bL@$O7k9g$5$l$F%Q%C%A$N@bL@$NKvHx$KDI2C$5$l$k!%>v$_9~(B +$B$`%Q%C%A$O$9$G$KE,MQ$5$l$F$$$F$O$J$i$J$$!%(B + +%The order in which you fold patches matters. If your topmost applied +%patch is \texttt{foo}, and you \hgxcmd{mq}{qfold} \texttt{bar} and +%\texttt{quux} into it, you will end up with a patch that has the same +%effect as if you applied first \texttt{foo}, then \texttt{bar}, +%followed by \texttt{quux}. + +$B%Q%C%A$r>v$_9~$`=gHV$O=EMW$G$"$k!%:#!$:F>e0L$NE,MQ:Q$_%Q%C%A$,(B +\texttt{foo}$B$@$H$7$F!$(B\hgxcmd{mq}{qfold} \texttt{bar}$B$H(B\texttt{quux}$B$r9T(B +$B$&$H!$%Q%C%A$O(B\texttt{foo}, then \texttt{bar}, \texttt{quux}$B$N=gHV$G%Q%C(B +$B%A$rE,MQ$7$?$N$HF1$88z2L$r;}$D$3$H$K$J$k!%(B + +%\subsection{Merging part of one patch into another} +\subsection{$B%Q%C%A$N0lItJ,$rJL$N%Q%C%A$X%^!<%8$9$k(B} + +%Merging \emph{part} of one patch into another is more difficult than +%combining entire patches. + +$B%Q%C%A$N(B\emph{$B0lIt(B}$B$rJL$N%Q%C%A$X%^!<%8$9$k$3$H$O!$%Q%C%A$r7k9g$9$k$h$j$O(B +$BFq$7$$!%(B + +%If you want to move changes to entire files, you can use +%\command{filterdiff}'s \cmdopt{filterdiff}{-i} and +%\cmdopt{filterdiff}{-x} options to choose the modifications to snip +%out of one patch, concatenating its output onto the end of the patch +%you want to merge into.You usually won't need to modify the patch +%you've merged the changes from. Instead, MQ will report some rejected +%hunks when you \hgxcmd{mq}{qpush} it (from the hunks you moved into the +%other patch), and you can simply \hgxcmd{mq}{qrefresh} the patch to drop +%the duplicate hunks. + +$BJQ99$r%U%!%$%k$N=89gA4BN$K0\F0$9$k>l9g!$(B\command{filterdiff}$B$K(B +\cmdopt{filterdiff}{-i}$B$H(B\cmdopt{filterdiff}{-x}$B$rIU$1!$(B +$B0l$D$N%Q%C%A$+$i<h$k5n$kJQ99!$%Q%C%A$NKvHx$K7k9g$9$kJQ99$rA*$V!%(B +$BDL>o$N>l9g!$JQ99$r<h$j=P$7$?%Q%C%A$rJQ99$9$kI,MW$O$J$$!%$=$NBe$o$j!$(BMQ$B$O(B +($BB>$N%Q%C%A$K0\F0$7$?(Bhunk$B$+$i(B)\hgxcmd{mq}{qpush}$B$7$?;~$K%j%8%'%/%H$5$l$?(B +hunk$B$rJs9p$9$k!%(B + +%If you have a patch that has multiple hunks modifying a file, and you +%only want to move a few of those hunks, the job becomes more messy, +%but you can still partly automate it. Use \cmdargs{lsdiff}{-nvv} to +%print some metadata about the patch. +%\interaction{mq.tools.lsdiff} + +$B%Q%C%A$K0l$D$N%U%!%$%k$rJQ99$9$kJ#?t$N(Bhunk$B$,$"$j!$$=$NCf$N0lIt$r0\F0$7$?(B +$B$$>l9g$O!$:n6H$O$b$C$H$d$d$3$7$$$b$N$K$J$k$,!$0MA3$H$7$F0lIt$O<+F02=$9$k(B +$B$3$H$,$G$-$k!%(B\cmdargs{lsdiff}{-nvv}$B%3%^%s%I$G%Q%C%A$N%a%?%G!<%?$rI=<($9(B +$B$k!%(B\interaction{mq.tools.lsdiff} + +%This command prints three different kinds of number: +$B$3$N%3%^%s%I$O(B3$B$D$N0[$J$kHV9f$r=PNO$9$k(B: +\begin{itemize} +%\item (in the first column) a \emph{file number} to identify each file +% modified in the patch; +\item ($B:G=i$NNs(B) $B$3$N%Q%C%A$GJQ99$5$l$k%U%!%$%k$r<1JL$9$k$?$a$N(B\emph{$B%U%!(B + $B%$%kHV9f(B} +%\item (on the next line, indented) the line number within a modified +% file where a hunk starts; and +\item ($B<!$N9T$G%$%s%G%s%H$5$l$F$$$k(B) $BJQ99$5$l$?%U%!%$%k$NCf$G(Bhun$B$,;O$^$k(B + $B9THV9f(B +%\item (on the same line) a \emph{hunk number} to identify that hunk. +\item ($B$=$l$HF1$89T(B) $BEv3:(Bhunk$B$r<1JL$9$k(B\emph{hunk$BHV9f(B} +\end{itemize} + +%You'll have to use some visual inspection, and reading of the patch, +%to identify the file and hunk numbers you'll want, but you can then +%pass them to to \command{filterdiff}'s \cmdopt{filterdiff}{--files} +%and \cmdopt{filterdiff}{--hunks} options, to select exactly the file +%and hunk you want to extract. + +$BI,MW$J%U%!%$%k$H(Bhunk$BHV9f$r8+$D$1$k$?$a$K!$%Q%C%A$rFI$`$J$I$7$FL\;k$G3NG'(B +$B$9$kI,MW$,$"$k!%$=$NHV9f$O!$(Bextract$B$9$k%U%!%$%k$H(Bhunk$B$rA*$V$?$a$K(B +\command{filterdiff}$B%3%^%s%I$N(B\cmdopt{filterdiff}{--files}$B$H(B +\cmdopt{filterdiff}{--hunks}$B%*%W%7%g%s$G;H$($k!%(B + +%Once you have this hunk, you can concatenate it onto the end of your +%destination patch and continue with the remainder of +%section~\ref{sec:mq:combine}. + +$B$3$N(Bhunk$B$,$G$-$?$i!$L\E*$N%Q%C%A$NKvHx$K7k9g$7!$%;%/%7%g%s$N;D$j$NItJ,$r(B +$BB3$1$k$3$H$,$G$-$k(B~\ref{sec:mq:combine}$B!%(B + +%\section{Differences between quilt and MQ} +\section{quilt$B$H(BMQ$B$N0c$$(B} + +%If you are already familiar with quilt, MQ provides a similar command +%set. There are a few differences in the way that it works. + +$B$9$G$K(Bquilt$B$KFk@w$s$G$$$k%f!<%6$N$?$a$K!$(BMQ$B$OF1MM$N%3%^%s%I%;%C%H$rMQ0U(B +$B$7$F$$$k!%%3%^%s%I$N5sF0$K$O2?E@$+0c$$$,$"$k!%(B + +%You will already have noticed that most quilt commands have MQ +%counterparts that simply begin with a ``\texttt{q}''. The exceptions +%are quilt's \texttt{add} and \texttt{remove} commands, the +%counterparts for which are the normal Mercurial \hgcmd{add} and +%\hgcmd{remove} commands. There is no MQ equivalent of the quilt +%\texttt{edit} command. + +$B$9$G$K$[$H$s$I$N(Bquilt$B%3%^%s%I$K$O!$BP1~$9$k(B``\texttt{q}''$B$G;O$^$k(BMQ$B%3%^%s(B +$B%I$,$"$k$3$H$K5$$E$$$F$$$k$3$H$H;W$&!%Nc30$O!$(Bquilt$B$N(B\texttt{add}$B%3%^%s%I(B +$B$H(B\texttt{remove}$B%3%^%s%I$G!$$3$l$i$K$O$=$l$>$lDL>o$N(BMercurial$B%3%^%s%I$N(B +\hgcmd{add}$B$H(B\hgcmd{remove}$B$,BP1~$9$k!%$^$?!$(Bquilt$B$N(B\texttt{edit}$B%3%^%s%I(B +$B$KBP1~$9$k(BMQ$B%3%^%s%I$O$J$$!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/preface.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,116 @@ +%\chapter*{Preface} +\chapter*{$B$^$($,$-(B} +\addcontentsline{toc}{chapter}{Preface} +\label{chap:preface} + +%Distributed revision control is a relatively new territory, and has +%thus far grown due to people's willingness to strike out into +%ill-charted territory. + +$BJ,;6%j%S%8%g%s%3%s%H%m!<%k$OHf3SE*?7$7$$NN0h$G$"$j!$$3$l$^$G$N4V0c$C$?NN(B +$B0h$+$iH4$1=P$=$&$H$$$&?M!9$N0U;V$G5^B.$KH/E8$7$F$$$k!%(B + +%I am writing a book about distributed revision control because I +%believe that it is an important subject that deserves a field guide. +%I chose to write about Mercurial because it is the easiest tool to +%learn the terrain with, and yet it scales to the demands of real, +%challenging environments where many other revision control tools fail. + +$BI.<T$,J,;6%j%S%8%g%s%3%s%H%m!<%k$K$D$$$F$NK\$r=q$$$F$$$k$N$O!$$3$l$,%U%#!<(B +$B%k%I%,%$%I$rI,MW$H$9$k=EMW$J2]Bj$@$H;W$C$?$+$i$@!%(BMercurial$B$K$D$$$F=q$3$&(B +$B$HA*$s$@$N$O!$$3$l$,A4BN$r3X$V$N$,:G$b4JC1$J%D!<%k$G!$$7$+$bB>$N%j%S%8%g(B +$B%s%3%s%H%m!<%k%D!<%k$,1}!9$K$7$F<:GT$7$F$$$k!$<B:]$ND)@oE*$J4D6-$N5a$a$K(B +$B9g$o$;$F%9%1!<%k$9$k%D!<%k$@$+$i$@!%(B + + +%\section{This book is a work in progress} +\section{$B$3$NK\$O<9I.Cf$G$"$k(B} + +%I am releasing this book while I am still writing it, in the hope that +%it will prove useful to others. I also hope that readers will +%contribute as they see fit. + +$B$3$NK\$O$^$@<9I.Cf$G$"$k$,!$$3$l$,FI<T$K$H$C$FM-MQ$G$"$k$H?.$8$F8x3+$9$k(B +$B$3$H$K$7$?!%$^$?!$FI<T$+$i$bH`$i$N5a$a$K9g$o$;$F9W8%$,$"$k$3$H$r4|BT$7$F(B +$B$$$k!%(B + +%\section{About the examples in this book} +\section{$B$3$NK\$NNc$K$D$$$F(B} + +%This book takes an unusual approach to code samples. Every example is +%``live''---each one is actually the result of a shell script that +%executes the Mercurial commands you see. Every time an image of the +%book is built from its sources, all the example scripts are +%automatically run, and their current results compared against their +%expected results. + +$B$3$NK\$O%3!<%I%5%s%W%k$KIaDL$H0c$&%"%W%m!<%A$r<h$C$F$$$k!%A4$F$NNc$O(B``$B@8(B +$B$-$F$$$k(B''---$BA4$F$NNc$O(BMercurial$B%3%^%s%I$r5/F0$9$k%7%'%k%9%/%j%W%H$N7k2L(B +$B$G$"$k!%$3$NK\$G$O!$2hA|$,%=!<%9$+$i@8@.$5$l$kEY$K!$%9%/%j%W%H$,<+F0E*$K(B +$B5/F0$9$k!%8=:_$N7k2L$O4|BT$5$l$k7k2L$HHf3S$5$l$k!%(B + +%The advantage of this approach is that the examples are always accurate; +%they describe \emph{exactly} the behaviour of the version of Mercurial +%that's mentioned at the front of the book. If I update the version of +%Mercurial that I'm documenting, and the output of some command changes, +%the build fails. + +$B$3$N%"%W%m!<%A$NMxE@$O!$Nc$,>o$K@53N$G$"$k$3$H$G!$5-=R$OK\$NI=;f$G8@5Z$7(B +$B$F$$$k(BMercurial$B$N%P!<%8%g%s$G$N5sF0$H(B\emph{$B87L)$K(B}$B0lCW$9$k!%(B +$BI.<T$,(BMercurial$B$N%P!<%8%g%s$r99?7$7!$%3%^%s%I$N=PNO$,JQ$o$k$H%S%k%I$O<:(B +$BGT$9$k!%(B + +%There is a small disadvantage to this approach, which is that the dates +%and times you'll see in examples tend to be ``squashed'' together in a +%way that they wouldn't be if the same commands were being typed by a +%human. Where a human can issue no more than one command every few +%seconds, with any resulting timestamps correspondingly spread out, my +%automated example scripts run many commands in one second. + +$B$3$N%"%W%m!<%A$N>.$5$J7gE@$O!$Nc$NCf$G8+$i$l$kF|IU$H;~9o$,?M4V$,%?%$%W$7(B +$B$F$$$l$PM-$jF@$J$$$[$I(B``$B=8$^$C$F(B''$B$7$^$C$F$$$k$3$H$@!%?M4V$G$"$l$P!$(B1$B$D$N(B +$B%3%^%s%I$r<B9T$9$k$N$K?tIC$O$+$+$j!$%?%$%`%9%?%s%W$O9-$$HO0O$K3H$,$k$O$:(B +$B$N$H$3$m$,!$$3$NK\$GNc$r:n@.$9$k%9%/%j%W%H$G$O!$(B1$BIC$KB?$/$N%3%^%s%I$r<B9T(B +$B$7$F$7$^$&!%(B + +%As an instance of this, several consecutive commits in an example can +%show up as having occurred during the same second. You can see this +%occur in the \hgext{bisect} example in section~\ref{sec:undo:bisect}, +%for instance. + +$B$3$N$?$a!$Nc$NCf$K8=$l$kO"B3$7$?%3%_%C%H$O!$F1$8IC$K5/$-$?$h$&$K$J$C$F$$(B +$B$k!%Nc$($P!$(B~\ref{sec:undo:bisect}$B$N@a$N(B\hgext{bisect}$B$NNc$G$3$l$,8+$i$l(B +$B$k!%(B + +%So when you're reading examples, don't place too much weight on the +%dates or times you see in the output of commands. But \emph{do} be +%confident that the behaviour you're seeing is consistent and +%reproducible. + +$B=>$C$F!$Nc$rFI$`;~$K$O!$F|IU$H;~9o$K$"$^$j94$i$J$$$h$&$K$7$F$$$?$@$-$?$$!%(B +$B$7$+$7!$$=$3$G8+$i$l$k$U$k$^$$$O@53N$G$"$j!$:F8=2DG=$G$"$k$3$H$O4V0c$$$N(B +$B$J$$$b$N$G$"$k!%(B + + +%\section{Colophon---this book is Free} +\section{$BGXI=;f(B---$B$3$NK\$OL5NA$G$"$k(B} + +%This book is licensed under the Open Publication License, and is +%produced entirely using Free Software tools. It is typeset with +%\LaTeX{}; illustrations are drawn and rendered with +%\href{http://www.inkscape.org/}{Inkscape}. + +$B$3$NK\$O(BOpen Publication License$B$N2<$G%i%$%;%s%9$5$l!$A4BN$KEO$C$F%U%j!<(B +$B%=%U%H%&%'%"%D!<%k$r;H$C$F:n$i$l$F$$$k!%AHHG$O(B\LaTeX{}$B$r;H$C$F9T$o$l!$?^(B +$BHG$O(B\href{http://www.inkscape.org/}{Inkscape}$B$r;H$C$F9T$o$l$F$$$k!%(B + +%The complete source code for this book is published as a Mercurial +%repository, at \url{http://hg.serpentine.com/mercurial/book}. + +$B$3$NK\$N40A4$J%=!<%9$O!$(B\url{http://hg.serpentine.com/mercurial/book}$B$K(B +$B$F(BMercurial$B%j%]%8%H%j$H$7$F8x3+$5$l$F$$$k!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/revlog.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1155 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docbase="/home/bos/hg/hgbook/en" + sodipodi:docname="revlog.svg"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path4852" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + <linearGradient + id="linearGradient3092"> + <stop + style="stop-color:#44436f;stop-opacity:1;" + offset="0" + id="stop3094" /> + <stop + style="stop-color:#abade5;stop-opacity:1;" + offset="1" + id="stop3096" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient3118" + gradientUnits="userSpaceOnUse" + x1="176.16635" + y1="405.21934" + x2="417.11935" + y2="405.21934" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient3120" + gradientUnits="userSpaceOnUse" + x1="176.16635" + y1="405.21934" + x2="417.11935" + y2="405.21934" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient3129" + gradientUnits="userSpaceOnUse" + x1="176.16635" + y1="405.21934" + x2="417.11935" + y2="405.21934" + gradientTransform="translate(-0.928574,-1.428574)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient3133" + gradientUnits="userSpaceOnUse" + x1="176.16635" + y1="405.21934" + x2="417.11935" + y2="405.21934" + gradientTransform="translate(-0.928574,-1.428574)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient3708" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.423343,0,0,0.423343,138.874,-67.01732)" + x1="175.23776" + y1="509.98154" + x2="416.29077" + y2="297.49997" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient5164" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.423343,0,0,0.423343,198.249,247.4358)" + x1="175.23776" + y1="509.98154" + x2="416.29077" + y2="297.49997" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient5584" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.423343,0,0,0.423343,143.9081,371.2915)" + x1="175.23776" + y1="509.98154" + x2="416.29077" + y2="297.49997" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient5784" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.423343,0,0,0.423343,76.37397,152.137)" + x1="175.23776" + y1="509.98154" + x2="416.29077" + y2="297.49997" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient5786" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.423343,0,0,0.423343,198.249,152.137)" + x1="175.23776" + y1="509.98154" + x2="416.29077" + y2="297.49997" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient5895" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.423343,0,0,0.423343,198.0215,261.7142)" + x1="175.23776" + y1="509.98154" + x2="416.29077" + y2="297.49997" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3092" + id="linearGradient5958" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.423343,0,0,0.423343,137.1978,42.55987)" + x1="175.23776" + y1="509.98154" + x2="416.29077" + y2="297.49997" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.64" + inkscape:cx="566.02368" + inkscape:cy="688.16826" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="29" + inkscape:window-y="79" + inkscape:connector-spacing="11" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + y="168.74846" + x="211.58516" + height="89.506805" + width="101.60232" + id="rect3068" + 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" /> + <g + id="g3215" + transform="matrix(0.423343,0,0,0.423343,137.1977,42.55985)"> + <rect + y="447.71451" + x="299.67859" + height="48.571426" + width="103.14286" + id="rect2899" + 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" /> + <text + id="text2903" + y="464.8139" + x="308.89639" + 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" + xml:space="preserve"><tspan + y="464.8139" + x="308.89639" + sodipodi:role="line" + id="tspan2905">Second parent</tspan></text> + <text + id="text2907" + y="485.50256" + x="308.20175" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="485.50256" + x="308.20175" + id="tspan2909" + sodipodi:role="line">32bf9a5f22c0</tspan></text> + </g> + <g + id="g3250" + transform="matrix(0.423343,0,0,0.423343,137.1977,42.55986)"> + <rect + y="311.28598" + x="188.6071" + height="48.571426" + width="103.14286" + id="rect2936" + 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" /> + <text + id="text2940" + y="328.38538" + x="197.82495" + 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" + xml:space="preserve"><tspan + y="328.38538" + x="197.82495" + sodipodi:role="line" + id="tspan2942">Revision hash</tspan></text> + <text + id="text2944" + y="349.07404" + x="197.13031" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="349.07404" + x="197.13031" + id="tspan2946" + sodipodi:role="line">34b8b7a15ea1</tspan></text> + </g> + <g + id="g3243" + transform="matrix(0.423343,0,0,0.423343,137.6664,43.91853)"> + <rect + y="363.07654" + x="187.5" + height="75" + width="213.85715" + id="rect2950" + 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" /> + <text + id="text2958" + y="400.86459" + x="196.02321" + 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" + xml:space="preserve"><tspan + style="fill:black;fill-opacity:1;font-family:Courier" + y="400.86459" + x="196.02321" + id="tspan2960" + sodipodi:role="line">...</tspan></text> + <text + id="text2954" + y="380.17593" + x="196.71785" + 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" + xml:space="preserve"><tspan + y="380.17593" + x="196.71785" + sodipodi:role="line" + id="tspan2956" + style="fill:black;fill-opacity:1">Revision data (delta or snapshot)</tspan></text> + </g> + <g + id="g5529" + transform="translate(-6.710312,-8.165836e-6)"> + <rect + 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" + id="rect3509" + width="101.60232" + height="89.506805" + x="218.29547" + y="497.4801" /> + <g + transform="matrix(0.423343,0,0,0.423343,143.908,371.2915)" + id="g3513"> + <g + id="g3515"> + <rect + y="447.72418" + x="188.6071" + height="48.571426" + width="103.14286" + id="rect3517" + 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" /> + <text + id="text3519" + y="464.82358" + x="197.82495" + 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" + xml:space="preserve"><tspan + y="464.82358" + x="197.82495" + sodipodi:role="line" + id="tspan3521">First parent</tspan></text> + <text + id="text3523" + y="485.51224" + x="197.13031" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="485.51224" + x="197.13031" + id="tspan3525" + sodipodi:role="line">000000000000</tspan></text> + </g> + <g + id="g3527"> + <rect + y="447.71451" + x="299.67859" + height="48.571426" + width="103.14286" + id="rect3529" + 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" /> + <text + id="text3531" + y="464.8139" + x="308.89639" + 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" + xml:space="preserve"><tspan + y="464.8139" + x="308.89639" + sodipodi:role="line" + id="tspan3533">Second parent</tspan></text> + <text + id="text3535" + y="485.50256" + x="308.20175" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="485.50256" + x="308.20175" + id="tspan3537" + sodipodi:role="line">000000000000</tspan></text> + </g> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,143.908,371.2915)" + id="g3539"> + <rect + 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" + id="rect3541" + width="103.14286" + height="48.571426" + x="188.6071" + y="311.28598" /> + <text + xml:space="preserve" + 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" + x="197.82495" + y="328.38538" + id="text3543"><tspan + id="tspan3545" + sodipodi:role="line" + x="197.82495" + y="328.38538">Revision hash</tspan></text> + <text + xml:space="preserve" + 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" + x="197.13031" + y="349.07404" + id="text3547"><tspan + sodipodi:role="line" + id="tspan3549" + x="197.13031" + y="349.07404" + style="font-family:Courier">ff9dc8bc2a8b</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,144.3767,372.6502)" + id="g3551"> + <rect + 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" + id="rect3553" + width="213.85715" + height="75" + x="187.5" + y="363.07654" /> + <text + xml:space="preserve" + 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" + x="196.02321" + y="400.86459" + id="text3555"><tspan + sodipodi:role="line" + id="tspan3557" + x="196.02321" + y="400.86459" + style="fill:black;fill-opacity:1;font-family:Courier">...</tspan></text> + <text + xml:space="preserve" + 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" + x="196.71785" + y="380.17593" + id="text3559"><tspan + style="fill:black;fill-opacity:1" + id="tspan3561" + sodipodi:role="line" + x="196.71785" + y="380.17593">Revision data (delta or snapshot)</tspan></text> + </g> + </g> + <g + id="g4868" + transform="translate(-1.676208,-2.342463e-5)"> + <rect + 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" + id="rect3567" + width="101.60232" + height="89.506805" + x="213.26137" + y="59.171272" /> + <g + transform="matrix(0.423343,0,0,0.423343,138.8739,-67.01734)" + id="g3573"> + <rect + 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" + id="rect3575" + width="103.14286" + height="48.571426" + x="188.6071" + y="447.72418" /> + <text + xml:space="preserve" + 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" + x="197.82495" + y="464.82358" + id="text3577"><tspan + id="tspan3579" + sodipodi:role="line" + x="197.82495" + y="464.82358">First parent</tspan></text> + <text + xml:space="preserve" + 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" + x="197.13031" + y="485.51224" + id="text3581"><tspan + sodipodi:role="line" + id="tspan3583" + x="197.13031" + y="485.51224" + style="font-family:Courier">34b8b7a15ea1</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,138.8739,-67.01734)" + id="g3585"> + <rect + 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" + id="rect3587" + width="103.14286" + height="48.571426" + x="299.67859" + y="447.71451" /> + <text + xml:space="preserve" + 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" + x="308.89639" + y="464.8139" + id="text3589"><tspan + id="tspan3591" + sodipodi:role="line" + x="308.89639" + y="464.8139">Second parent</tspan></text> + <text + xml:space="preserve" + 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" + x="308.20175" + y="485.50256" + id="text3593"><tspan + sodipodi:role="line" + id="tspan3595" + x="308.20175" + y="485.50256" + style="font-family:Courier">000000000000</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,138.8739,-67.01733)" + id="g3597"> + <rect + 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" + id="rect3599" + width="103.14286" + height="48.571426" + x="188.6071" + y="311.28598" /> + <text + xml:space="preserve" + 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" + x="197.82495" + y="328.38538" + id="text3601"><tspan + id="tspan3603" + sodipodi:role="line" + x="197.82495" + y="328.38538">Revision hash</tspan></text> + <text + xml:space="preserve" + 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" + x="197.13031" + y="349.07404" + id="text3605"><tspan + sodipodi:role="line" + id="tspan3607" + x="197.13031" + y="349.07404" + style="font-family:Courier">1b67dc96f27a</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,139.3426,-65.65866)" + id="g3609"> + <rect + 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" + id="rect3611" + width="213.85715" + height="75" + x="187.5" + y="363.07654" /> + <text + xml:space="preserve" + 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" + x="196.02321" + y="400.86459" + id="text3613"><tspan + sodipodi:role="line" + id="tspan3615" + x="196.02321" + y="400.86459" + style="fill:black;fill-opacity:1;font-family:Courier">...</tspan></text> + <text + xml:space="preserve" + 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" + x="196.71785" + y="380.17593" + id="text3617"><tspan + style="fill:black;fill-opacity:1" + id="tspan3619" + sodipodi:role="line" + x="196.71785" + y="380.17593">Revision data (delta or snapshot)</tspan></text> + </g> + </g> + <path + 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)" + d="M 240.78255,143.08593 L 241.42595,171.75349" + id="path3801" + inkscape:connector-type="polyline" + inkscape:connection-start="#g3573" + inkscape:connection-end="#g3250" /> + <g + id="g5677"> + <rect + 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" + id="rect3393" + width="101.60232" + height="89.506805" + x="150.76137" + y="278.32565" /> + <g + transform="matrix(0.423343,0,0,0.423343,76.37397,152.137)" + id="g3399"> + <rect + 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" + id="rect3401" + width="103.14286" + height="48.571426" + x="188.6071" + y="447.72418" /> + <text + xml:space="preserve" + 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" + x="197.82495" + y="464.82358" + id="text3403"><tspan + id="tspan3405" + sodipodi:role="line" + x="197.82495" + y="464.82358">First parent</tspan></text> + <text + xml:space="preserve" + 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" + x="197.13031" + y="485.51224" + id="text3407"><tspan + sodipodi:role="line" + id="tspan3409" + x="197.13031" + y="485.51224" + style="font-family:Courier">ff9dc8bc2a8b</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,76.37397,152.137)" + id="g3411"> + <rect + 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" + id="rect3413" + width="103.14286" + height="48.571426" + x="299.67859" + y="447.71451" /> + <text + xml:space="preserve" + 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" + x="308.89639" + y="464.8139" + id="text3415"><tspan + id="tspan3417" + sodipodi:role="line" + x="308.89639" + y="464.8139">Second parent</tspan></text> + <text + xml:space="preserve" + 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" + x="308.20175" + y="485.50256" + id="text3419"><tspan + sodipodi:role="line" + id="tspan3421" + x="308.20175" + y="485.50256" + style="font-family:Courier">000000000000</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,76.37397,152.137)" + id="g3423"> + <rect + 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" + id="rect3425" + width="103.14286" + height="48.571426" + x="188.6071" + y="311.28598" /> + <text + xml:space="preserve" + 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" + x="197.82495" + y="328.38538" + id="text3427"><tspan + id="tspan3429" + sodipodi:role="line" + x="197.82495" + y="328.38538">Revision hash</tspan></text> + <text + xml:space="preserve" + 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" + x="197.13031" + y="349.07404" + id="text3431"><tspan + sodipodi:role="line" + id="tspan3433" + x="197.13031" + y="349.07404" + style="font-family:Courier">5b80c922ebdd</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,76.84265,153.4957)" + id="g3435"> + <rect + 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" + id="rect3437" + width="213.85715" + height="75" + x="187.5" + y="363.07654" /> + <text + xml:space="preserve" + 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" + x="196.02321" + y="400.86459" + id="text3439"><tspan + sodipodi:role="line" + id="tspan3441" + x="196.02321" + y="400.86459" + style="fill:black;fill-opacity:1;font-family:Courier">...</tspan></text> + <text + xml:space="preserve" + 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" + x="196.71785" + y="380.17593" + id="text3443"><tspan + style="fill:black;fill-opacity:1" + id="tspan3445" + sodipodi:role="line" + x="196.71785" + y="380.17593">Revision data (delta or snapshot)</tspan></text> + </g> + </g> + <g + id="g5646" + transform="translate(-0.227432,0)"> + <rect + 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" + id="rect3451" + width="101.60232" + height="89.506805" + x="272.63638" + y="278.32565" /> + <g + transform="matrix(0.423343,0,0,0.423343,198.2489,152.137)" + id="g3457"> + <rect + 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" + id="rect3459" + width="103.14286" + height="48.571426" + x="188.6071" + y="447.72418" /> + <text + xml:space="preserve" + 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" + x="197.82495" + y="464.82358" + id="text3461"><tspan + id="tspan3463" + sodipodi:role="line" + x="197.82495" + y="464.82358">First parent</tspan></text> + <text + xml:space="preserve" + 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" + x="197.13031" + y="485.51224" + id="text3465"><tspan + sodipodi:role="line" + id="tspan3467" + x="197.13031" + y="485.51224" + style="font-family:Courier">ecacb6b4c9fd</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,198.2489,152.137)" + id="g3469"> + <rect + 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" + id="rect3471" + width="103.14286" + height="48.571426" + x="299.67859" + y="447.71451" /> + <text + xml:space="preserve" + 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" + x="308.89639" + y="464.8139" + id="text3473"><tspan + id="tspan3475" + sodipodi:role="line" + x="308.89639" + y="464.8139">Second parent</tspan></text> + <text + xml:space="preserve" + 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" + x="308.20175" + y="485.50256" + id="text3477"><tspan + sodipodi:role="line" + id="tspan3479" + x="308.20175" + y="485.50256" + style="font-family:Courier">000000000000</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,198.2489,152.137)" + id="g3481"> + <rect + 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" + id="rect3483" + width="103.14286" + height="48.571426" + x="188.6071" + y="311.28598" /> + <text + xml:space="preserve" + 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" + x="197.82495" + y="328.38538" + id="text3485"><tspan + id="tspan3487" + sodipodi:role="line" + x="197.82495" + y="328.38538">Revision hash</tspan></text> + <text + xml:space="preserve" + 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" + x="197.13031" + y="349.07404" + id="text3489"><tspan + sodipodi:role="line" + id="tspan3491" + x="197.13031" + y="349.07404" + style="font-family:Courier">32bf9a5f22c0</tspan></text> + </g> + <g + transform="matrix(0.423343,0,0,0.423343,198.7176,153.4957)" + id="g3493"> + <rect + 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" + id="rect3495" + width="213.85715" + height="75" + x="187.5" + y="363.07654" /> + <text + xml:space="preserve" + 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" + x="196.02321" + y="400.86459" + id="text3497"><tspan + sodipodi:role="line" + id="tspan3499" + x="196.02321" + y="400.86459" + style="fill:black;fill-opacity:1;font-family:Courier">...</tspan></text> + <text + xml:space="preserve" + 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" + x="196.71785" + y="380.17593" + id="text3501"><tspan + style="fill:black;fill-opacity:1" + id="tspan3503" + sodipodi:role="line" + x="196.71785" + y="380.17593">Revision data (delta or snapshot)</tspan></text> + </g> + </g> + <rect + y="387.90286" + x="272.40894" + height="89.506805" + width="101.60232" + id="rect5081" + 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" /> + <g + id="g5087" + transform="matrix(0.423343,0,0,0.423343,198.0214,261.7142)"> + <rect + y="447.72418" + x="188.6071" + height="48.571426" + width="103.14286" + id="rect5089" + 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" /> + <text + id="text5091" + y="464.82358" + x="197.82495" + 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" + xml:space="preserve"><tspan + y="464.82358" + x="197.82495" + sodipodi:role="line" + id="tspan5093">First parent</tspan></text> + <text + id="text5095" + y="485.51224" + x="197.13031" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="485.51224" + x="197.13031" + id="tspan5097" + sodipodi:role="line">ff9dc8bc2a8b</tspan></text> + </g> + <g + id="g5099" + transform="matrix(0.423343,0,0,0.423343,198.0214,261.7142)"> + <rect + y="447.71451" + x="299.67859" + height="48.571426" + width="103.14286" + id="rect5101" + 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" /> + <text + id="text5103" + y="464.8139" + x="308.89639" + 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" + xml:space="preserve"><tspan + y="464.8139" + x="308.89639" + sodipodi:role="line" + id="tspan5105">Second parent</tspan></text> + <text + id="text5107" + y="485.50256" + x="308.20175" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="485.50256" + x="308.20175" + id="tspan5109" + sodipodi:role="line">000000000000</tspan></text> + </g> + <g + id="g5111" + transform="matrix(0.423343,0,0,0.423343,198.0214,261.7142)"> + <rect + y="311.28598" + x="188.6071" + height="48.571426" + width="103.14286" + id="rect5113" + 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" /> + <text + id="text5115" + y="328.38538" + x="197.82495" + 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" + xml:space="preserve"><tspan + y="328.38538" + x="197.82495" + sodipodi:role="line" + id="tspan5117">Revision hash</tspan></text> + <text + id="text5119" + y="349.07404" + x="197.13031" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="349.07404" + x="197.13031" + id="tspan5121" + sodipodi:role="line">ecacb6b4c9fd</tspan></text> + </g> + <g + id="g5123" + transform="matrix(0.423343,0,0,0.423343,198.4901,263.0729)"> + <rect + y="363.07654" + x="187.5" + height="75" + width="213.85715" + id="rect5125" + 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" /> + <text + id="text5127" + y="400.86459" + x="196.02321" + 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" + xml:space="preserve"><tspan + style="fill:black;fill-opacity:1;font-family:Courier" + y="400.86459" + x="196.02321" + id="tspan5129" + sodipodi:role="line">...</tspan></text> + <text + id="text5131" + y="380.17593" + x="196.71785" + 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" + xml:space="preserve"><tspan + y="380.17593" + x="196.71785" + sodipodi:role="line" + id="tspan5133" + style="fill:black;fill-opacity:1">Revision data (delta or snapshot)</tspan></text> + </g> + <path + 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" + d="M 299.69935,362.24027 L 299.69931,393.49494" + id="path5203" + inkscape:connector-type="polyline" + inkscape:connection-start="#g3457" + inkscape:connection-end="#g5111" /> + <path + 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" + d="M 182.35357,362.22647 L 241.2842,503.07224" + id="path5271" + inkscape:connector-type="polyline" + inkscape:connection-start="#g3399" + inkscape:connection-end="#g3539" /> + <path + 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" + d="M 287.63109,471.81747 L 250.9438,503.07223" + id="path5285" + inkscape:connector-type="polyline" + inkscape:connection-start="#g5087" + inkscape:connection-end="#g3539" /> + <path + 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)" + d="M 290.80419,250.07192 L 297.80065,283.90394" + id="path5077" + inkscape:connector-type="polyline" + inkscape:connection-start="#g3215" + inkscape:connection-end="#g3481" /> + <path + 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)" + d="M 229.63373,250.07601 L 190.07484,283.90394" + id="path5075" + inkscape:connector-type="polyline" + inkscape:connection-end="#g3423" /> + <text + xml:space="preserve" + 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" + x="131.5625" + y="100.79968" + id="text5897"><tspan + sodipodi:role="line" + id="tspan5899" + x="131.5625" + y="100.79968" + style="text-align:end;text-anchor:end">Head revision</tspan><tspan + sodipodi:role="line" + x="131.5625" + y="115.79968" + id="tspan5901" + style="text-align:end;text-anchor:end">(no children)</tspan></text> + <text + xml:space="preserve" + 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" + x="131.5625" + y="207.04968" + id="text5903"><tspan + sodipodi:role="line" + id="tspan5905" + x="131.5625" + y="207.04968" + style="text-align:end;text-anchor:end">Merge revision</tspan><tspan + sodipodi:role="line" + x="131.5625" + y="222.04968" + id="tspan5907" + style="text-align:end;text-anchor:end">(two parents)</tspan></text> + <text + xml:space="preserve" + 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" + x="131.92578" + y="451.58093" + id="text5909"><tspan + sodipodi:role="line" + id="tspan5911" + x="131.92578" + y="451.58093" + style="text-align:end;text-anchor:end">Branches</tspan><tspan + sodipodi:role="line" + x="131.92578" + y="466.58093" + id="tspan5913" + style="text-align:end;text-anchor:end">(two revisions,</tspan><tspan + sodipodi:role="line" + x="131.92578" + y="481.58093" + id="tspan5915" + style="text-align:end;text-anchor:end">same parent)</tspan></text> + <path + 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" + d="M 111.71875,433.61218 L 154.7268,368.52294" + id="path5917" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 134.375,464.86218 L 277.86691,440.37816" + id="path5919" + inkscape:connector-type="polyline" + inkscape:connection-end="#g5123" /> + <text + xml:space="preserve" + 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" + x="131.5625" + y="536.73718" + id="text5927"><tspan + sodipodi:role="line" + id="tspan5929" + x="131.5625" + y="536.73718">First revision</tspan><tspan + sodipodi:role="line" + x="131.5625" + y="551.73718" + id="tspan5931">(both parents null)</tspan></text> + <rect + 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" + id="rect2830" + width="43.664806" + height="20.562374" + x="217.0432" + y="232.10075" /> + <text + xml:space="preserve" + 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" + x="220.94551" + y="239.33966" + id="text2832"><tspan + id="tspan2836" + sodipodi:role="line" + x="220.94551" + y="239.33966">First parent</tspan></text> + <text + xml:space="preserve" + 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" + x="220.65144" + y="248.09805" + id="text2879"><tspan + sodipodi:role="line" + id="tspan2881" + x="220.65144" + y="248.09805" + style="font-family:Courier">5b80c922ebdd</tspan></text> + <path + 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" + d="M 139.84375,107.83093 L 210.15625,107.83093" + id="path5965" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 137.5,213.29968 L 210.49036,214.09055" + id="path5967" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 136.34375,544.54968 L 206.65625,544.54968" + id="path5969" + inkscape:connector-type="polyline" + inkscape:transform-center-y="-171.09375" + inkscape:transform-center-x="53.90625" /> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/snapshot.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,202 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2807" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docbase="/home/bos/hg/hgbook/en" + sodipodi:docname="snapshots.svg"> + <defs + id="defs2809" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4" + inkscape:cx="252.04111" + inkscape:cy="605.75448" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="906" + inkscape:window-height="721" + inkscape:window-x="0" + inkscape:window-y="25" /> + <metadata + id="metadata2812"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + 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" + id="rect2817" + width="118.18347" + height="245.32632" + x="243.05112" + y="315.4133" + inkscape:transform-center-x="136.84403" + inkscape:transform-center-y="-66.529183" /> + <rect + y="315.04153" + x="46.965065" + height="97.803009" + width="108.92702" + id="rect2815" + 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" /> + <g + id="g3814"> + <rect + y="348.94302" + x="59.285713" + height="30" + width="84.285713" + id="rect2819" + 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" + ry="0" /> + <text + id="text2821" + y="368.02701" + x="72.717636" + 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" + xml:space="preserve"><tspan + y="368.02701" + x="72.717636" + id="tspan2823" + sodipodi:role="line">Index, rev 7</tspan></text> + </g> + <text + id="text3722" + y="301.29074" + x="46.187778" + 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" + xml:space="preserve"><tspan + y="301.29074" + x="46.187778" + id="tspan3724" + sodipodi:role="line">Revlog index (.i file)</tspan></text> + <text + id="text3726" + y="301.29074" + x="241.90207" + 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" + xml:space="preserve"><tspan + y="301.29074" + x="241.90207" + id="tspan3728" + sodipodi:role="line">Revlog data (.d file)</tspan></text> + <path + style="fill:#c695ff;fill-opacity:0.60109288;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + 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 " + id="path3839" + sodipodi:nodetypes="ccccc" /> + <rect + 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" + id="rect3752" + width="92.720184" + height="67.005905" + x="255.42564" + y="368.64264" /> + <text + xml:space="preserve" + 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" + x="264.45859" + y="387.30099" + id="text3754"><tspan + sodipodi:role="line" + id="tspan3756" + x="264.45859" + y="387.30099">Snapshot, rev 4</tspan></text> + <rect + 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" + id="rect3761" + width="93.49366" + height="29.922237" + x="255.03891" + y="442.04395" /> + <text + xml:space="preserve" + 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" + x="263.2662" + y="460.17206" + id="text3763"><tspan + sodipodi:role="line" + id="tspan3765" + x="263.2662" + y="460.17206">Delta, rev 4 to 5</tspan></text> + <rect + 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" + id="rect3774" + width="93.49366" + height="29.922237" + x="255.03891" + y="477.97485" /> + <text + xml:space="preserve" + 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" + x="263.2662" + y="496.10297" + id="text3776"><tspan + sodipodi:role="line" + id="tspan3778" + x="263.2662" + y="496.10297">Delta, rev 5 to 6</tspan></text> + <rect + 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" + id="rect3782" + width="93.49366" + height="29.922237" + x="255.03891" + y="513.90576" /> + <text + xml:space="preserve" + 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" + x="263.2662" + y="532.03387" + id="text3784"><tspan + sodipodi:role="line" + id="tspan3786" + x="263.2662" + y="532.03387">Delta, rev 6 to 7</tspan></text> + <rect + 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" + id="rect3889" + width="93.49366" + height="29.922237" + x="255.03891" + y="332.32489" /> + <text + xml:space="preserve" + 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" + x="263.2662" + y="350.453" + id="text3891"><tspan + sodipodi:role="line" + id="tspan3893" + x="263.2662" + y="350.453">Delta, rev 2 to 3</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/srcinstall.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,96 @@ +%\chapter{Installing Mercurial from source} +\chapter{$B%=!<%9$+$i(BMercurial$B$r%$%s%9%H!<%k$9$k(B} +\label{chap:srcinstall} + +%\section{On a Unix-like system} +\section{Unix$B7O%7%9%F%`$G$N%$%s%9%H!<%k(B} +\label{sec:srcinstall:unixlike} + +%If you are using a Unix-like system that has a sufficiently recent +%version of Python (2.3~or newer) available, it is easy to install +%Mercurial from source. +%\begin{enumerate} +%\item Download a recent source tarball from +% \url{http://www.selenic.com/mercurial/download}. +%\item Unpack the tarball: +% \begin{codesample4} +% gzip -dc mercurial-\emph{version}.tar.gz | tar xf - +% \end{codesample4} +%\item Go into the source directory and run the installer script. This +% will build Mercurial and install it in your home directory. +% \begin{codesample4} +% cd mercurial-\emph{version} +% python setup.py install --force --home=\$HOME +% \end{codesample4} +%\end{enumerate} +%Once the install finishes, Mercurial will be in the \texttt{bin} +%subdirectory of your home directory. Don't forget to make sure that +%this directory is present in your shell's search path. + +Python (2.3~$B0\9T(B)$B$N%$%s%9%H!<%k$5$l$F$$$k!$==J,?7$7$$(BUnix$B7O$N%7%9%F%`$G(B +$B$O!$(BMercurial$B$N%=!<%9$+$i$N%$%s%9%H!<%k$O4JC1$G$"$k!%(B +\begin{enumerate} +\item \url{http://www.selenic.com/mercurial/download}$B$+$i?7$7$$%=!<%9$N(B + tarball$B$r%@%&%s%m!<%I$9$k(B +\item tarball$B$r2rE`$9$k(B: + \begin{codesample4} + gzip -dc mercurial-\emph{version}.tar.gz | tar xf - + \end{codesample4} +\item $B%=!<%9%G%#%l%/%H%j$KF~$C$F!$%$%s%9%H!<%i%9%/%j%W%H$r<B9T$9$k!%(B + Mercurial$B$,%S%k%I$5$l!$%f!<%6%[!<%`%G%#%l%/%H%j$K%$%s%9%H!<%k$5$l(B + $B$k!%(B + \begin{codesample4} + cd mercurial-\emph{version} + python setup.py install --force --home=\$HOME + \end{codesample4} +\end{enumerate} +$B%$%s%9%H!<%k$r9T$J$&$H!$(BMercurial$B$O%f!<%6%[!<%`%G%#%l%/%H%jFb$N(B +\texttt{bin}$B%5%V%G%#%l%/%H%j$K<}$a$i$l$k!%$3$N%G%#%l%/%H%j$,%7%'%k$N%3%^(B +$B%s%I%5!<%A%Q%9$K$"$k$N$r3NG'$9$k$3$H!%(B + +%You will probably need to set the \envar{PYTHONPATH} environment +%variable so that the Mercurial executable can find the rest of the +%Mercurial packages. For example, on my laptop, I have set it to +%\texttt{/home/bos/lib/python}. The exact path that you will need to +%use depends on how Python was built for your system, but should be +%easy to figure out. If you're uncertain, look through the output of +%the installer script above, and see where the contents of the +%\texttt{mercurial} directory were installed to. + +Mercurial$B$N<B9T%U%!%$%k$,B>$N(BMercurial$B%Q%C%1!<%8$rH/8+$G$-$k$h$&$K!$$*$=(B +$B$i$/4D6-JQ?t(B\envar{PYTHONPATH}$B$r@_Dj$9$k$3$H$,I,MW$K$J$k!%Nc$($P!$I.<T$N(B +$B%i%C%W%H%C%W$G$O$3$l$r(B\texttt{/home/bos/lib/python}$B$K@_Dj$7$F$$$k!%(B +$B<B:]$N@5$7$$%Q%9$O$I$N$h$&$K(BPython$B$r%S%k%I$7$?$+$K$h$k$,!$$3$l$r8+$D$1=P(B +$B$9$N$O4JC1$JH&$@!%$b$7ITL@$G$"$l$P!$A0=R$N%$%s%9%H!<%i%9%/%j%W%H$N=PNO$+(B +$B$i!$(B\texttt{mercurial}$B%G%#%l%/%H%j$NCf?H$,$I$3$K%$%s%9%H!<%k$5$l$?$+$r8+(B +$B$l$PNI$$!%(B + +%\section{On Windows} +\section{Windows$B$G$N%$%s%9%H!<%k(B} + +%Building and installing Mercurial on Windows requires a variety of +%tools, a fair amount of technical knowledge, and considerable +%patience. I very much \emph{do not recommend} this route if you are a +%``casual user''. Unless you intend to hack on Mercurial, I strongly +%suggest that you use a binary package instead. + +Mercurial$B$r(BWindows$B>e$G%=!<%9$+$i%S%k%I$7%$%s%9%H!<%k$9$k$?$a$K$O!$B?$/$N(B +$B%D!<%k$,I,MW$G!$$=$l$J$j$N5;=QE*CN<1$,I,MW$G$"$j!$:$Fq$G$"$k!%$b$7%+%8%e(B +$B%"%k$J%f!<%6$G$"$l$P!$$3$N$d$jJ}$O$*$9$9$a$7$J$$!%(BMercurial$B<+BN$r%O%C%/$7(B +$B$?$$$N$G$J$1$l$P!$%P%$%J%j%Q%C%1!<%8$r$*$9$9$a$9$k!%(B + +%If you are intent on building Mercurial from source on Windows, follow +%the ``hard way'' directions on the Mercurial wiki at +%\url{http://www.selenic.com/mercurial/wiki/index.cgi/WindowsInstall}, +%and expect the process to involve a lot of fiddly work. + +$B$b$7(BMercurial$B$r(BWindows$B>e$G%=!<%9$+$i%S%k%I$7$?$$$N$G$"$l$P!$(BMercurial +wiki +\url{http://www.selenic.com/mercurial/wiki/index.cgi/WindowsInstall} $B$N(B +``hard way''$B$N@bL@$K=>$C$F9T$J$&!%$3$NJ}K!$G$OB?$/$NLLE]$J:n6H$,BT$A9=$((B +$B$F$$$k$3$H$r3P8g$9$kI,MW$,$"$k!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/template.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,867 @@ +%\chapter{Customising the output of Mercurial} +\chapter{Mercurial$B$N=PNO$N%+%9%?%^%$%:(B} +\label{chap:template} + +%Mercurial provides a powerful mechanism to let you control how it +%displays information. The mechanism is based on templates. You can +%use templates to generate specific output for a single command, or to +%customise the entire appearance of the built-in web interface. + +Mercurial$B$K$O>pJs$NI=<($r%3%s%H%m!<%k$9$k$?$a$N6/NO$J5!9=$,$"$k!%$3$N5!9=(B +$B$O%F%s%W%l!<%H$r%Y!<%9$H$7$F$$$k!%%F%s%W%l!<%H$K$h$C$F$"$k%3%^%s%I$+$iFC(B +$BJL$N=PNO$r9T$C$?$j!$FbB"$N%&%'%V%$%s%?%U%'!<%9$N8+$?L\$r%+%9%?%^%$%:$9$k(B +$B$3$H$,$G$-$k!%(B + +%\section{Using precanned output styles} +\section{$BMQ0U$5$l$?=PNO%9%?%$%k$NMxMQ(B} +\label{sec:style} + +%Packaged with Mercurial are some output styles that you can use +%immediately. A style is simply a precanned template that someone +%wrote and installed somewhere that Mercurial can find. + +$B$9$0$K;H$&$3$H$N$G$-$k$$$/$D$+$N%9%?%$%k$,(BMercurial$B$KF1:-$5$l$F$$$k!%%9%?(B +$B%$%k$H$O4L5M$5$l$?%F%s%W%l!<%H$G$"$j!$(B Mercurial$B$N%$%s%9%H!<%k$5$l$?$I$3(B +$B$+$N%^%7%s$GC/$+$,=q$$$F%$%s%9%H!<%k$7$?$b$N$G$"$k!%(B + +%Before we take a look at Mercurial's bundled styles, let's review its +%normal output. + +Mercurial$BF1:-$N%9%?%$%k$r8+$kA0$K!$DL>o$N=PNO$r8+$F$_$h$&!%(B + +\interaction{template.simple.normal} + +%This is somewhat informative, but it takes up a lot of space---five +%lines of output per changeset. The \texttt{compact} style reduces +%this to three lines, presented in a sparse manner. + +$B$3$N=PNO$K$OM-1W$J>pJs$,4^$^$l$F$$$k$,!$(B1$B$D$N%A%'%s%8%;%C%HKh$K(B5$B9T$r;H$&(B +$B$J$I!$B?$/$N%9%Z!<%9$rHq$d$9!%(B\texttt{compact}$B%9%?%$%k$OAB$i$JJ}K!$r;H$&(B +$B$3$H$G$3$l$r(B3$B9T$K8:$i$9!%(B + +\interaction{template.simple.compact} + +%The \texttt{changelog} style hints at the expressive power of +%Mercurial's templating engine. This style attempts to follow the GNU +%Project's changelog guidelines\cite{web:changelog}. + +\texttt{changelog}$B%9%?%$%k$O(BMercurial$B$N%F%s%W%l!<%H%(%s%8%s$N0RNO$rCN$k$$(B +$B$$Nc$G$"$k!%$3$N%9%?%$%k$O(BGNU$B%W%m%8%'%/%H$N(Bchangelog$B%,%$%I%i%$%s(B +\cite{web:changelog}$B$K=>$*$&$H$9$k!%(B + +\interaction{template.simple.changelog} + +%You will not be shocked to learn that Mercurial's default output style +%is named \texttt{default}. + +Mercurial$B$N%G%U%)%k%H=PNO%9%?%$%k$,(B\texttt{default}$B$HL>IU$1$i$l$F$$$k$N(B +$B$O6C$/$KCM$7$J$$!%(B + +%\subsection{Setting a default style} +\subsection{$B%G%U%)%k%H%9%?%$%k$N@_Dj(B} + +%You can modify the output style that Mercurial will use for every +%command by editing your \hgrc file, naming the style you would +%prefer to use. + +Mercurial$B$NA4$F$N%3%^%s%I$GMQ$$$i$l$k=PNO%9%?%$%k$O(B \hgrc $B%U%!%$%k$rJT=8(B +$B$9$k$3$H$G@_Dj$G$-!$9%$-$JL>A0$rIU$1$k$3$H$,$G$-$k!%(B + +\begin{codesample2} + [ui] + style = compact +\end{codesample2} + +%If you write a style of your own, you can use it by either providing +%the path to your style file, or copying your style file into a +%location where Mercurial can find it (typically the \texttt{templates} +%subdirectory of your Mercurial install directory). + +$B<+J,$G%9%?%$%k$r=q$$$?$H$-$O!$%9%?%$%k%U%!%$%k$N%Q%9$rDI2C$7$?$j!$%U%!%$(B +$B%k$r(BMercurial$B$,H/8+$G$-$k>l=j(B($BE57?E*$K$O!$(BMercurial$B$N%$%s%9%H!<%k%G%#%l%/(B +$B%H%j$N(B\texttt{templates}$B%5%V%G%#%l%/%H%j(B)$B$K%3%T!<$9$k$3$H$GMxMQ2DG=$K$J(B +$B$k!%(B + +%\section{Commands that support styles and templates} +\section{$B%9%?%$%k$H%F%s%W%l!<%H$r%5%]!<%H$9$k%3%^%s%I(B} + +%All of Mercurial's ``\texttt{log}-like'' commands let you use styles +%and templates: \hgcmd{incoming}, \hgcmd{log}, \hgcmd{outgoing}, and +%\hgcmd{tip}. + +Mercurial$B$N(B``\texttt{log}$B7O(B''$B$NA4$F$N%3%^%s%I(B: \hgcmd{incoming}, +\hgcmd{log}, \hgcmd{outgoing}, $B$*$h$S(B\hgcmd{tip}$B$O%9%?%$%k$H%F%s%W%l!<%H(B +$B$rMxMQ$7$F$$$k!%(B + +%As I write this manual, these are so far the only commands that +%support styles and templates. Since these are the most important +%commands that need customisable output, there has been little pressure +%from the Mercurial user community to add style and template support to +%other commands. + +$B$3$N%^%K%e%"%k$G=q$$$F$$$k$h$&$K!$$3$l$^$G$N$H$3$m!$$3$l$i$N%3%^%s%I$@$1(B +$B$,%9%?%$%k$H%F%s%W%l!<%H$r%5%]!<%H$7$F$$$k!%$3$l$i$,%+%9%?%^%$%:2DG=$J=P(B +$BNO$,I,MW$J:G$b=EMW$J%3%^%s%I$G$"$k$?$a!$(B Mercurial$B$N%f!<%6%3%_%e%K%F%#$+(B +$B$iB>$N%3%^%s%I$K%9%?%$%k$H%F%s%W%l!<%H%5%]!<%H$rE,MQ$+$N$&$K$;$h$H$$$&%W(B +$B%l%C%7%c!<$O$[$H$s$I$J$$!%(B + +%\section{The basics of templating} +\section{$B%F%s%W%l!<%H$N4pK\(B} + +%At its simplest, a Mercurial template is a piece of text. Some of the +%text never changes, while other parts are \emph{expanded}, or replaced +%with new text, when necessary. + +$B:G$bC1=c$J(BMercurial$B%F%s%W%l!<%H$O%F%-%9%HJR$G$"$k!%%F%-%9%H$N$"$kItJ,$OIT(B +$BJQ$G!$B>$NItJ,$OI,MW$K1~$8$F(B\emph{$BE83+(B}$B$5$l$k$?$j?7$7$$%F%-%9%H$KCV49$5$l(B +$B$k!%(B + +%Before we continue, let's look again at a simple example of +%Mercurial's normal output. + +$B$5$i$KB3$1$kA0$K(BMercurial$BI8=`=PNO$NNc$r$b$&0lEY8+$F$_$h$&!%(B + +\interaction{template.simple.normal} + +%Now, let's run the same command, but using a template to change its +%output. + +$B$3$3$GF1$8%3%^%s%I$r=PNO$rJQ2=$5$;$k$?$a$K%F%s%W%l!<%H$r;H$C$F$_$h$&!%(B + +\interaction{template.simple.simplest} + +%The example above illustrates the simplest possible template; it's +%just a piece of static text, printed once for each changeset. The +%\hgopt{log}{--template} option to the \hgcmd{log} command tells +%Mercurial to use the given text as the template when printing each +%changeset. + +$B>e$NNc$O:G$bC1=c$J%F%s%W%l!<%H$r<($7$?(B; $B@EE*$J%F%-%9%H$@$1$+$i$J$j!$3F%A%'(B +$B%s%8%;%C%H$K$D$$$F0lEY$@$1=PNO$r9T$&!%(B\hgcmd{log}$B%3%^%s%I$K(B +\hgopt{log}{--template}$B%*%W%7%g%s$r;H$&$H(BMercurial$B$O3F!9$N%A%'%s%8%;%C%H(B +$B$r=PNO$9$k$H$-$K!$M?$($i$l$?%F%-%9%H$r%F%s%W%l!<%H$H$7$FMQ$$$k!%(B + +%Notice that the template string above ends with the text +%``\Verb+\n+''. This is an \emph{escape sequence}, telling Mercurial +%to print a newline at the end of each template item. If you omit this +%newline, Mercurial will run each piece of output together. See +%section~\ref{sec:template:escape} for more details of escape sequences. + +$B%F%s%W%l!<%HJ8;zNs$O(B``\Verb+\n+''$B$G=*$k$3$H$KCm0U!%$3$l$O(BMercurial$B$K%F%s(B +$B%W%l!<%H$N3FMWAG$NKvHx$K2~9T$r=PNO$9$k$h$&;X<($9$k(B\emph{$B%(%9%1!<%W%7!<%1(B +$B%s%9(B}$B$G$"$k!%$3$N2~9T$r>JN,$9$k$H(BMercurial$B$O3FMWAG$r7R$2$F=PNO$9$k!%%(%9(B +$B%1!<%W%7!<%1%s%9$N$h$j>\:Y$J@bL@$K$D$$$F$O(B~\ref{sec:template:escape}$B@a$r(B +$B;2>H$N$3$H!%(B + +%A template that prints a fixed string of text all the time isn't very +%useful; let's try something a bit more complex. + +$B>o$K8GDjJ8;zNs$r=PNO$9$k%F%s%W%l!<%H$O$"$^$jM-MQ$G$"$k$H$O8@$($J$$!%$b$&(B +$B>/$79~$_F~$C$?%F%s%W%l!<%H$r;n$=$&!%(B + +\interaction{template.simple.simplesub} + +%As you can see, the string ``\Verb+{desc}+'' in the template has been +%replaced in the output with the description of each changeset. Every +%time Mercurial finds text enclosed in curly braces (``\texttt{\{}'' +%and ``\texttt{\}}''), it will try to replace the braces and text with +%the expansion of whatever is inside. To print a literal curly brace, +%you must escape it, as described in section~\ref{sec:template:escape}. + +$B%F%s%W%l!<%HFb$N(B``\Verb+{desc}+''$B$H$$$&J8;zNs$O=PNO$G$O!$3F!9$N%A%'%s%8%;%C(B +$B%H$N@bL@$KCV49$5$l$k!%(BMercurial$B$OCf3g8L(B(``\texttt{\{}''$B$H(B +``\texttt{\}}'')$B$G0O$^$l$?%F%-%9%H$r8+$D$1$k$HCf3g8L$H%F%-%9%H$rFbIt$N%F(B +$B%-%9%H$rE83+$7$?$b$N$KCV49$7$h$&$H;n$_$k!%J8;z$H$7$FCf3g8L$r0u;z$7$?$$>l(B +$B9g$O(B~\ref{sec:template:escape}$B@a$G<($9$h$&$K%(%9%1!<%W$9$kI,MW$,$"$k!%(B + +%\section{Common template keywords} +\section{$B%F%s%W%l!<%H$N6&DL%-!<%o!<%I(B} +\label{sec:template:keyword} + +%You can start writing simple templates immediately using the keywords +%below. + +$BC1=c$J%F%s%W%l!<%H$O0J2<$N$h$&$J%-!<%o!<%I$r;H$C$FD>$A$K=q$/$3$H$,$G$-$k!%(B + +\begin{itemize} +%\item[\tplkword{author}] String. The unmodified author of the changeset. +\item[\tplkword{author}] $BJ8;zNs!%%A%'%s%8%;%C%H$NCx<T!%(B +%\item[\tplkword{branches}] String. The name of the branch on which +% the changeset was committed. Will be empty if the branch name was +% \texttt{default}. +\item[\tplkword{branches}] $BJ8;zNs!%%A%'%s%8%;%C%H$,%3%_%C%H$5$l$?%V%i%s(B + $B%A$NL>A0!%%V%i%s%AL>$,(B\texttt{default}$B$N>l9g$O(B + $B6uMs$H$J$k!%(B +%\item[\tplkword{date}] Date information. The date when the changeset +% was committed. This is \emph{not} human-readable; you must pass it +% through a filter that will render it appropriately. See +% section~\ref{sec:template:filter} for more information on filters. +% The date is expressed as a pair of numbers. The first number is a +% Unix UTC timestamp (seconds since January 1, 1970); the second is +% the offset of the committer's timezone from UTC, in seconds. +\item[\tplkword{date}] $BF|;~>pJs!%%A%'%s%8%;%C%H$,%3%_%C%H$5$l$?F|;~!%$3$l(B + $B$O?M4V$N2DFI$J7A<0$G$O(B\emph{$B$J$$(B}$B!%I,$:E,@Z$J%U%#(B + $B%k%?$r8F$S=P$7$FJQ49$9$kI,MW$,$"$k!%%U%#%k%?$K4X(B + $B$9$k$h$j>\:Y$J@bL@$O(B~\ref{sec:template:filter} + $B@a$r;2>H$N$3$H!%F|;~$O(B2$B$D$N?t;z$NAH$_9g$o$;$GI=(B + $B$5$l$k!%:G=i$N?t;z$O(BUTC$B$G$N(BUnix$B%?%$%`%9%?%s%W(B + (1970$BG/(B1$B7n(B1$BF|$+$i$NIC?t(B)$B$G!$(B2$BHVL\$N?t;z$O%3%_%C(B + $B%?$N%?%$%`%>!<%s$N(BUTC$B$+$i$N;~:9$rIC?t$GI=$7$?$b(B + $B$N$G$"$k!%(B +%\item[\tplkword{desc}] String. The text of the changeset description. +\item[\tplkword{desc}] $BJ8;zNs!%%A%'%s%8%;%C%H$N@bL@J8!%(B + +%\item[\tplkword{files}] List of strings. All files modified, added, or +% removed by this changeset. +\item[\tplkword{files}] $BJ8;zNs$N%j%9%H!%$3$N%A%'%s%8%;%C%H$GJQ99!$DI2C!$(B + $B:o=|$5$l$?A4$F$N%U%!%$%k$NL>A0!%(B + +%\item[\tplkword{file\_adds}] List of strings. Files added by this +% changeset. +\item[\tplkword{file\_adds}] $BJ8;zNs$N%j%9%H!%$3$N%A%'%s%8%;%C%H$GDI2C$5(B + $B$l$?%U%!%$%k$NL>A0!%(B + +%\item[\tplkword{file\_dels}] List of strings. Files removed by this +% changeset. +\item[\tplkword{file\_dels}] $BJ8;zNs$N%j%9%H!%$3$N%A%'%s%8%;%C%H$G:o=|$5(B + $B$l$?%U%!%$%k$NL>A0!%(B + +%\item[\tplkword{node}] String. The changeset identification hash, as a +% 40-character hexadecimal string. +\item[\tplkword{node}] $BJ8;zNs!%%A%'%s%8%;%C%H$N<1JL%O%C%7%e$r(B40$BJ8;z$N(B16 + $B?J?t$G<($7$?$b$N!%(B + +%\item[\tplkword{parents}] List of strings. The parents of the +% changeset. +\item[\tplkword{parents}] $BJ8;zNs$N%j%9%H!%%A%'%s%8%;%C%H$N?F!%(B + +%\item[\tplkword{rev}] Integer. The repository-local changeset revision +% number. +\item[\tplkword{rev}] $B@0?t!%%j%]%8%H%j%m!<%+%k$N%A%'%s%8%;%C%H%j%S%8%g%s(B + $BHV9f!%(B + +%\item[\tplkword{tags}] List of strings. Any tags associated with the +% changeset. +\item[\tplkword{tags}] $BJ8;zNs$N%j%9%H!%%A%'%s%8%;%C%H$K4XO"$E$1$i$l$?G$(B + $B0U$N%?%0!%(B +\end{itemize} + +%A few simple experiments will show us what to expect when we use these +%keywords; you can see the results in +%figure~\ref{fig:template:keywords}. + +$B$$$/$D$+;n$7$F$_$l$P$3$l$i$N%-!<%o!<%I$K$I$N$h$&$J8z2L$,$"$k$N$+$rCN$k$3(B +$B$H$,$G$-$k!%7k2L$r?^(B~\ref{fig:template:keywords}$B$K<($9!%(B + +\begin{figure} + \interaction{template.simple.keywords} +% \caption{Template keywords in use} + \caption{$B%F%s%W%l!<%H%-!<%o!<%I$N;HMQ(B} + \label{fig:template:keywords} +\end{figure} + +%As we noted above, the date keyword does not produce human-readable +%output, so we must treat it specially. This involves using a +%\emph{filter}, about which more in section~\ref{sec:template:filter}. + +$B4{$K=R$Y$?$h$&$K!$(Bdate$B%-!<%o!<%I$O2DFI$J=PNO$r9T$o$J$$$?$a!$FCJL$J<h$j07(B +$B$$$,I,MW$G$"$k!%$=$NL\E*$G(B\emph{filter}$B$r;HMQ$9$k$,!$$h$j>\:Y$K(B +$B$O(B~\ref{sec:template:filter}$B@a$G<h$j07$&!%(B + +\interaction{template.simple.datekeyword} + +%\section{Escape sequences} +\section{$B%(%9%1!<%W%7!<%1%s%9(B} +\label{sec:template:escape} + +%Mercurial's templating engine recognises the most commonly used escape +%sequences in strings. When it sees a backslash (``\Verb+\+'') +%character, it looks at the following character and substitutes the two +%characters with a single replacement, as described below. + +Mercurial$B$N%F%s%W%l!<%H%(%s%8%s$OJ8;zNs$G:G$b$h$/;HMQ$5$l$k%(%9%1!<%W%7!<(B +$B%1%s%9$rG'<1$9$k!%%(%s%8%s$O%P%C%/%9%i%C%7%e(B(``\Verb+\+'')$B$r8+$D$1$k$H8e(B +$BB3$NJ8;z$r4^$`(B2$BJ8;z$r0J2<$N$h$&$J(B1$BJ8;z$GCV49$9$k!%(B + +\begin{itemize} +%\item[\Verb+\textbackslash\textbackslash+] Backslash, ``\Verb+\+'', +% ASCII~134. +%\item[\Verb+\textbackslash n+] Newline, ASCII~12. +%\item[\Verb+\textbackslash r+] Carriage return, ASCII~15. +%\item[\Verb+\textbackslash t+] Tab, ASCII~11. +%\item[\Verb+\textbackslash v+] Vertical tab, ASCII~13. +%\item[\Verb+\textbackslash \{+] Open curly brace, ``\Verb+{+'', ASCII~173. +%\item[\Verb+\textbackslash \}+] Close curly brace, ``\Verb+}+'', ASCII~175. +\item[\Verb+\textbackslash\textbackslash+] $B%P%C%/%9%i%C%7%e(B, ``\Verb+\+'', + ASCII~134. +\item[\Verb+\textbackslash n+] $B2~9T(B, ASCII~12. +\item[\Verb+\textbackslash r+] $BI|5"(B, ASCII~15. +\item[\Verb+\textbackslash t+] $B%?%V(B, ASCII~11. +\item[\Verb+\textbackslash v+] $B?bD>%?%V(B, ASCII~13. +\item[\Verb+\textbackslash \{+] $B3+$-Cf3g8L(B, ``\Verb+{+'', ASCII~173. +\item[\Verb+\textbackslash \}+] $BJD$8Cf3g8L(B, ``\Verb+}+'', ASCII~175. +\end{itemize} + +%As indicated above, if you want the expansion of a template to contain +%a literal ``\Verb+\+'', ``\Verb+{+'', or ``\Verb+{+'' character, you +%must escape it. + +$B>e$K<($7$?$h$&$K!$%F%s%W%l!<%H$NE83+$N:]$KJ8;z(B +``\Verb+\+'', ``\Verb+{+'', $B$^$?$O(B``\Verb+{+''$B$rF~$l$?$$>l9g$O%(%9%1!<%W(B +$B$9$k$3$H$,I,MW$G$"$k!%(B + +%\section{Filtering keywords to change their results} +\section{$B7k2L$r2~JQ$9$k%U%#%k%?%-!<%o!<%I(B} +\label{sec:template:filter} + +%Some of the results of template expansion are not immediately easy to +%use. Mercurial lets you specify an optional chain of \emph{filters} +%to modify the result of expanding a keyword. You have already seen a +%common filter, \tplkwfilt{date}{isodate}, in action above, to make a +%date readable. + +$B%F%s%W%l!<%HE83+$N7k2L$N$&$A!$$$$/$D$+$O$?$d$9$/MxMQ$G$-$k$b$N$G$O$J$$!%(B +Mercurial$B$OE83+$5$l$k%-!<%o!<%I$rJQ99$9$k$?$a$N0lO"$N(B\emph{filters}$B%*%W%7%g(B +$B%s$rDs6!$7$F$$$k!%F|;~$r2DFI$K$9$k$?$a$K$h$/MQ$$$i$l$k(B +\tplkwfilt{date}{isodate}$B%U%#%k%?$NF0:nNc$K$D$$$F$O4{$K8+$F$-$?!%(B + +%Below is a list of the most commonly used filters that Mercurial +%supports. While some filters can be applied to any text, others can +%only be used in specific circumstances. The name of each filter is +%followed first by an indication of where it can be used, then a +%description of its effect. + +$B0J2<$K<($9$N$O(BMercurial$B$,%5%]!<%H$9$k%U%#%k%?$NCf$G:G$b$h$/;H$o$l$k$b$N$G(B +$B$"$k!%$$$/$D$+$N%U%#%k%?$OG$0U$NJ8;zNs$KBP$7$FE,MQ2DG=$J0lJ}!$B>$N$b$N$O(B +$BFCDj$N>u67$K$*$$$F$N$_MxMQ2DG=$G$"$k!%3F!9$N%U%#%k%?$NL>A0$O!$MxMQ2DG=$J(B +$B>u67$r<($9I=<($G;O$^$j!$F@$i$l$k8z2L$N@bL@$,B3$/!%(B + +\begin{itemize} +%\item[\tplfilter{addbreaks}] Any text. Add an XHTML ``\Verb+<br/>+'' +% tag before the end of every line except the last. For example, +% ``\Verb+foo\nbar+'' becomes ``\Verb+foo<br/>\nbar+''. + +\item[\tplfilter{addbreaks}] $BG$0U$N%F%-%9%H!%(BXHTML$B%?%0(B``\Verb+<br/>+'' +$B$r:G=*9T0J30$N3F9T$NKvHx$KDI2C$9$k!%Nc$($P(B``\Verb+foo\nbar+''$B$O(B + ``\Verb+foo<br/>\nbar+''$B$H$J$k!%(B + +%\item[\tplkwfilt{date}{age}] \tplkword{date} keyword. Render the +% age of the date, relative to the current time. Yields a string like +% ``\Verb+10 minutes+''. + +\item[\tplkwfilt{date}{age}] \tplkword{date}$B%-!<%o!<%I!%F|;~$N7P2a;~4V$r(B + $B8=:_$r5/E@$K@07A$9$k!%7k2L$O(B + ``\Verb+10 minutes+''$B$N$h$&$K$J$k(B + +%\item[\tplfilter{basename}] Any text, but most useful for the +% \tplkword{files} keyword and its relatives. Treat the text as a +% path, and return the basename. For example, ``\Verb+foo/bar/baz+'' +% becomes ``\Verb+baz+''. + +\item[\tplfilter{basename}] $BG$0U$N%F%-%9%H$@$,!$(B\tplkword{files}$B%-!<%o!<(B + $B%I$d$=$N4XO"%-!<%o!<%I$KBP$7$F:G$bM-MQ$G$"(B + $B$k!%%F%-%9%H$r%Q%9$H$7$F07$$!$%Y!<%9%M!<%`$r(B + $BJV$9!%Nc$($P(B``\Verb+foo/bar/baz+''$B$O(B + ``\Verb+baz+''$B$H$J$k!%(B + +%\item[\tplkwfilt{date}{date}] \tplkword{date} keyword. Render a date +% in a similar format to the Unix \tplkword{date} command, but with +% timezone included. Yields a string like +% ``\Verb+Mon Sep 04 15:13:13 2006 -0700+''. + +\item[\tplkwfilt{date}{date}] \tplkword{date}$B%-!<%o!<%I!%F|;~$r(BUnix$B$N(B + \tplkword{date}$B%3%^%s%I$N=PNO$K%?%$%`%>!<%s(B + $B>pJs$rDI2C$7$?7A<0$K@07A$9$k!%7k2L$O(B + ``\Verb+Mon Sep 04 15:13:13 2006 -0700+''$B$N(B + $B$h$&$K$J$k!%(B + +%\item[\tplkwfilt{author}{domain}] Any text, but most useful for the +% \tplkword{author} keyword. Finds the first string that looks like +% an email address, and extract just the domain component. For +% example, ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' becomes +% ``\Verb+serpentine.com+''. + +\item[\tplkwfilt{author}{domain}] $BG$0U$N%F%-%9%H!%(B\tplkword{author}$B%-!<%o!<(B + $B%I$G$N;HMQ$K:G$bM-MQ!%:G=i$K8=$l$k(Bemail$B%"%I(B + $B%l%97A<0$NJ8;zNs$r8+$D$1!$%I%a%$%sItJ,$@$1$r(B + $BH4$-=P$9!%Nc$($P(B + ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' + $B$O(B``\Verb+serpentine.com+''$B$H$J$k!%(B + +%\item[\tplkwfilt{author}{email}] Any text, but most useful for the +% \tplkword{author} keyword. Extract the first string that looks like +% an email address. For example, +% ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' becomes +% ``\Verb+bos@serpentine.com+''. + +\item[\tplkwfilt{author}{email}] $BG$0U$N%F%-%9%H!%(B\tplkword{author}$B%-!<%o!<(B + $B%I$G:G$bM-MQ!%:G=i$K8=$l$k(Bemail$B%"%I%l%97A<0(B + $B$NJ8;zNs$rH4$-=P$9!%Nc$($P(B + ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' + $B$O(B``\Verb+bos@serpentine.com+''$B$H$J$k!%(B + +%\item[\tplfilter{escape}] Any text. Replace the special XML/XHTML +% characters ``\Verb+&+'', ``\Verb+<+'' and ``\Verb+>+'' with +% XML entities. + +\item[\tplfilter{escape}] $BG$0U$N%F%-%9%H!%(BXML/XHTML$BJ8;z(B + ``\Verb+&+'', ``\Verb+<+''$B$*$h$S(B + ``\Verb+>+''$B$r(BXML$B%(%s%F%#%F%#$GCV49$9$k!%(B + +%\item[\tplfilter{fill68}] Any text. Wrap the text to fit in 68 +% columns. This is useful before you pass text through the +% \tplfilter{tabindent} filter, and still want it to fit in an +% 80-column fixed-font window. + +\item[\tplfilter{fill68}] $BG$0U$N%F%-%9%H!%%F%-%9%H$r(B68$B7e$K<}$^$k$h$&$K@0(B + $B7A$9$k!%$3$l$O(B80$B7e$K8GDj$5$l$?C<Kv$G$NI=<(MQ(B + $B$K(B\tplfilter{tabindent}$B%U%#%k%?$r;H$&:]$KJX(B + $BMx$G$"$k!%(B + +%\item[\tplfilter{fill76}] Any text. Wrap the text to fit in 76 +% columns. + +\item[\tplfilter{fill76}] $BG$0U$N%F%-%9%H!%(B76$B7e$K<}$^$k$h$&$K@07A$9$k!%(B + +%\item[\tplfilter{firstline}] Any text. Yield the first line of text, +% without any trailing newlines. + +\item[\tplfilter{firstline}] $BG$0U$N%F%-%9%H:G=i$N9T$@$1$r=PNO$7!$8eB3$N(B + $B9T$O0l@Z=PNO$7$J$$!%(B + +%\item[\tplkwfilt{date}{hgdate}] \tplkword{date} keyword. Render the +% date as a pair of readable numbers. Yields a string like +% ``\Verb+1157407993 25200+''. + +\item[\tplkwfilt{date}{hgdate}] \tplkword{date}$B%-!<%o!<%I!%F|;~$r2DFI$J(B + $B?t;z$N%Z%"$K@07A$9$k!%(B``\Verb+115740799325200+''$B$N$h$&$JJ8;zNs$r=PNO$9$k!%(B + +%\item[\tplkwfilt{date}{isodate}] \tplkword{date} keyword. Render the +% date as a text string in ISO~8601 format. Yields a string like +% ``\Verb+2006-09-04 15:13:13 -0700+''. + +\item[\tplkwfilt{date}{isodate}] \tplkword{date}$B%-!<%o!<%I!%F|;~$r(B + ISO~8601$B%U%)!<%^%C%H$K@07A$9$k!%=PNO$O(B + ``\Verb+2006-09-04 15:13:13 -0700+''$B$N$h$&$K(B + $B$J$k!%(B + +%\item[\tplfilter{obfuscate}] Any text, but most useful for the +% \tplkword{author} keyword. Yield the input text rendered as a +% sequence of XML entities. This helps to defeat some particularly +% stupid screen-scraping email harvesting spambots. + +\item[\tplfilter{obfuscate}]$BG$0U$N%F%-%9%H!%(B\tplkword{author}$B%-!<%o!<%I$H(B + $BJ;$;$FMxMQ$9$k>l9g:G$bM-MQ!%F~NO$5$l$?%F%-%9(B + $B%H$r(BXML$B%(%s%F%#%F%#$N%7!<%1%s%9$H$7$F=PNO$9(B + $B$k!%$3$l$O2hLL$r%9%/%l%$%T%s%0$9$k4VH4$1$J%9(B + $B%Q%`%\%C%H$rHr$1$kF/$-$,$"$k!%(B + +%\item[\tplkwfilt{author}{person}] Any text, but most useful for the +% \tplkword{author} keyword. Yield the text before an email address. +% For example, ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' +% becomes ``\Verb+Bryan O'Sullivan+''. + +\item[\tplkwfilt{author}{person}] $BG$0U$N%F%-%9%H!%(B\tplkword{author}$B%-!<(B + $B%o!<%I$H9g$o$;$F;H$&>l9g$b$C$H$bM-MQ!%(Bemail$B%"%I%l%9$NA0$N%F(B + $B%-%9%H$rCj=P$9$k!%Nc$($P(B``\Verb+Bryan O'Sullivan <bos@serpentine.com>+''$B$O(B``\Verb+Bryan O'Sullivan+''$B$H$J$k!%(B + +%\item[\tplkwfilt{date}{rfc822date}] \tplkword{date} keyword. Render a +% date using the same format used in email headers. Yields a string +% like ``\Verb+Mon, 04 Sep 2006 15:13:13 -0700+''. + +\item[\tplkwfilt{date}{rfc822date}] \tplkword{date}$B%-!<%o!<%I!%F|;~$r(B + email$B%X%C%@$HF1$87A<0$G@07A$9$k!%(B``\Verb+Mon, 04 Sep 2006 15:13:13 -0700+''$B$N$h$&$JJ8;zNs$r@8@.$9$k!%(B + +%\item[\tplkwfilt{node}{short}] Changeset hash. Yield the short form +% of a changeset hash, i.e.~a 12-byte hexadecimal string. + +\item[\tplkwfilt{node}{short}] $B%A%'%s%8%;%C%H%O%C%7%e!%C;7A<0$N%A%'%s%8(B + $B%;%C%H%O%C%7%e!$$9$J$o$A(B12$B%P%$%H$N(B16$B?J?tJ8;zNs$r@8@.$9$k!%(B + +%\item[\tplkwfilt{date}{shortdate}] \tplkword{date} keyword. Render +% the year, month, and day of the date. Yields a string like +% ``\Verb+2006-09-04+''. + +\item[\tplkwfilt{date}{shortdate}] \tplkword{date}$B%-!<%o!<%I!%G/7nF|$r@0(B + $B7A$9$k!%(B``\Verb+2006-09-04+''$B$N$h$&$JJ8;zNs$r@8@.$9$k!%(B + +%\item[\tplfilter{strip}] Any text. Strip all leading and trailing +% whitespace from the string. + +\item[\tplfilter{strip}] $BG$0U$N%F%-%9%H!%J8;zNs$NA08e$N6uGrItJ,$r=|5n$9(B + $B$k!%(B + +%\item[\tplfilter{tabindent}] Any text. Yield the text, with every line +% except the first starting with a tab character. + +\item[\tplfilter{tabindent}] $BG$0U$N%F%-%9%H!%%?%VJ8;z$G;O$^$i$J$$9T$9$Y(B + $B$F$r=PNO$9$k!%(B + +%\item[\tplfilter{urlescape}] Any text. Escape all characters that are +% considered ``special'' by URL parsers. For example, \Verb+foo bar+ +% becomes \Verb+foo%20bar+. + +\item[\tplfilter{urlescape}] $BG$0U$N%F%-%9%H!%(BURL$B%Q!<%5$+$i8+$F(B``$BFCJL(B''$B$J(B + $BJ8;z$N%(%9%1!<%W$r9T$&!%Nc$($P(B \Verb+foo bar+ $B$O(B + \Verb+foo\%20bar+ $B$H$J$k!%(B + +%\item[\tplkwfilt{author}{user}] Any text, but most useful for the +% \tplkword{author} keyword. Return the ``user'' portion of an email +% address. For example, +% ``\Verb+Bryan O'Sullivan <bos@serpentine.com>+'' becomes +% ``\Verb+bos+''. + +\item[\tplkwfilt{author}{user}] $BG$0U$N%F%-%9%H!%(B\tplkword{author}$B%-!<%o!<(B + $B%I$H6&$K;H$C$?>l9g$K:G$bM-MQ!%(Bemail$B%"%I%l%9$+$i%f!<%6L>$NIt(B + $BJ,$rH4$-=P$9!%Nc$($P(B``\Verb+Bryan O'Sullivan <bos@serpentine.com>+''$B$O(B``\Verb+bos+''$B$H$J$k!%(B +\end{itemize} + +\begin{figure} + \interaction{template.simple.manyfilters} +% \caption{Template filters in action} + \caption{$B%F%s%W%l!<%H%U%#%k%?$NF0:n(B} + \label{fig:template:filters} +\end{figure} + +\begin{note} +% If you try to apply a filter to a piece of data that it cannot +% process, Mercurial will fail and print a Python exception. For +% example, trying to run the output of the \tplkword{desc} keyword +% into the \tplkwfilt{date}{isodate} filter is not a good idea. +$B%U%#%k%?$rE,MQITG=$J%G!<%?$KBP$7$F;H$*$&$H$9$k$H(BMercurial$B$O%(%i!<$r5/$3(B + $B$7!$(BPython$B$+$i$NNc30$r=PNO$9$k!%Nc$($P(B\tplkword{desc}$B%-!<%o!<%I$N=PNO$K(B + \tplkwfilt{date}{isodate}$B%U%#%k%?$rE,MQ$9$k$N$O$$$$9M$($H$O8@$($J$$!%(B + +\end{note} + +%\subsection{Combining filters} +\subsection{$BAH$_9g$o$;%U%#%k%?(B} + +%It is easy to combine filters to yield output in the form you would +%like. The following chain of filters tidies up a description, then +%makes sure that it fits cleanly into 68 columns, then indents it by a +%further 8~characters (at least on Unix-like systems, where a tab is +%conventionally 8~characters wide). + +$BK>$_$N=PNO$r$($k$?$a$KJ#?t$N%U%#%k%?$rAH$_9g$o$;$k$N$O$?$d$9$$!%0J2<$N0l(B +$BO"$N%U%#%k%?$O@bL@J8$r@0M}$7!$$-$l$$$K(B68$B7e$K<}$^$k$h$&$K@07A$7!$(B8$BJ8;z$N(B +$B%$%s%G%s%H$r9T$&!%!J(BUNIX$B%7%9%F%`$G$O%?%V$O=,47E*$K(B8$B7eJ,$NI}$r;}$D!%!K(B + +\interaction{template.simple.combine} + +%Note the use of ``\Verb+\t+'' (a tab character) in the template to +%force the first line to be indented; this is necessary since +%\tplkword{tabindent} indents all lines \emph{except} the first. + +$B%F%s%W%l!<%H$G:G=i$N9T$r%$%s%G%s%H$9$k$?$a$K$O(B``\Verb+\t+''$B!J%?%VJ8;z!K$r(B +$B;H$&I,MW$,$"$k!%$J$<$J$i(B\tplkword{tabindent}$B$O:G=i$N9T(B\emph{$B0J30(B}$B$N%$%s(B +$B%G%s%H$r9T$&$+$i$G$"$k!%(B + +%Keep in mind that the order of filters in a chain is significant. The +%first filter is applied to the result of the keyword; the second to +%the result of the first filter; and so on. For example, using +%\Verb+fill68|tabindent+ gives very different results from +%\Verb+tabindent|fill68+. + +$B%U%#%k%?$rAH$_9g$o$;$k;~%U%#%k%?$N=g=x$,=EMW$G$"$k$3$H$rF,$KCV$$$F$*$/I,(B +$BMW$,$"$k!%:G=i$N%U%#%k%?$O%-!<%o!<%I$N7k2L$KBP$7$FE,MQ$5$l!$(B2$BHVL\$N%U%#%k(B +$B%?$O:G=i$N%U%#%k%?$N7k2L$KBP$7$FE,MQ$5$l$k!%Nc$r5s$2$k(B +$B$H!$(B\Verb+fill68|tabindent+ $B$H(B \Verb+tabindent|fill68+ $B$N7k2L$OA4$/0c$&(B +$B$b$N$G$"$k!%(B + +%\section{From templates to styles} +\section{$B%F%s%W%l!<%H$+$i%9%?%$%k$X(B} + +%A command line template provides a quick and simple way to format some +%output. Templates can become verbose, though, and it's useful to be +%able to give a template a name. A style file is a template with a +%name, stored in a file. + +$B%3%^%s%I%i%$%s%F%s%W%l!<%H$O=PNO$r%U%)!<%^%C%H$9$k$?$a$NAGAa$/C1=c$JJ}K!(B +$B$rDs6!$9$k!%%F%s%W%l!<%H$O%a%C%;!<%8$rB?$/=PNO$9$k$h$&$K$b$G$-$k$,!$%F%s(B +$B%W%l!<%H$KL>A0$rIU$1$k$N$OM-1W$G$"$k!%%9%?%$%k%U%!%$%k$O!$%U%!%$%k$KJ]B8(B +$B$5$l$?L>A0$rIU$1$i$l$?%F%s%W%l!<%H$G$"$k!%(B + +%More than that, using a style file unlocks the power of Mercurial's +%templating engine in ways that are not possible using the command line +%\hgopt{log}{--template} option. + +$B$5$i$K!$%9%?%$%k%U%!%$%k$r;H$&$3$H$G!$(BMercurial$B$N%F%s%W%l!<%H%(%s%8%s$N%3(B +$B%^%s%I%i%$%s(B\hgopt{log}{--template}$B%*%W%7%g%s$+$i$G$OMxMQ$G$-$J$$NO$r:GBg(B +$B8B$K0z$-=P$9$3$H$,$G$-$k!%(B + +%\subsection{The simplest of style files} +\subsection{$B:G$bC1=c$J%9%?%$%k%U%!%$%k(B} + +%Our simple style file contains just one line: + +$B%5%s%W%k%9%?%$%k%U%!%$%k$O$?$@$N(B1$B9T$+$i$J$k(B: + +\interaction{template.simple.rev} + +%This tells Mercurial, ``if you're printing a changeset, use the text +%on the right as the template''. + +$B$3$l$O(BMercurial$B$K(B``$B%A%'%s%8%;%C%H$r=PNO$9$k;~$O1&$N%F%-%9%H$r%F%s%W%l!<%H(B +$B$H$7$F;H$((B''$B$H$$$&;X<($rM?$($k!%(B + +%\subsection{Style file syntax} +\subsection{$B%9%?%$%k%U%!%$%k$NJ8K!(B} + +%The syntax rules for a style file are simple. + +$B%9%?%$%k%U%!%$%k$NJ8K!5,B'$OC1=c$G$"$k!%(B + +\begin{itemize} +%\item The file is processed one line at a time. +\item $B%U%!%$%k$O0lEY$K(B1$B9T$:$D=hM}$5$l$k(B + +%\item Leading and trailing white space are ignored. +\item $BA08e$N6uGr$OL5;k$5$l$k(B + +%\item Empty lines are skipped. +\item $B6u9T$O%9%-%C%W$5$l$k(B + +%\item If a line starts with either of the characters ``\texttt{\#}'' or +% ``\texttt{;}'', the entire line is treated as a comment, and skipped +% as if empty. +\item $B9T$,(B``\texttt{\#}''$B$^$?$O(B``\texttt{;}''$B$G;O$^$k>l9g$O!$9TA4BN$,%3(B + $B%a%s%H$H$7$F07$o$l!$6uGr$HF1MM$K%9%-%C%W$5$l$k!%(B + +%\item A line starts with a keyword. This must start with an +% alphabetic character or underscore, and can subsequently contain any +% alphanumeric character or underscore. (In regexp notation, a +% keyword must match \Verb+[A-Za-z_][A-Za-z0-9_]*+.) +\item $B9T$O%-!<%o!<%I$G;O$^$k!%I,$:%"%k%U%!%Y%C%H$+%"%s%@!<%9%3%"$G;O$^$k(B + $BI,MW$,$"$j!$8eB3$NJ8;z$O%"%k%U%!%Y%C%H!$?t;z!$%"%s%@!<%9%3%"$N$$$:(B + $B$l$+$G$"$C$F$h$$!%!J@55,I=8=$G$O(B\Verb+[A-Za-z_][A-Za-z0-9_]*+$B$H%^%C(B + $B%A$9$k!K(B + +%\item The next element must be an ``\texttt{=}'' character, which can +% be preceded or followed by an arbitrary amount of white space. +\item $B<!$NMWAG$OJ8;z(B``\texttt{=}''$B$G!$A08e$K6uGr$,F~$C$F$bNI$$!%(B + +%\item If the rest of the line starts and ends with matching quote +% characters (either single or double quote), it is treated as a +% template body. +\item $B?t$ND`$j9g$C$?%7%s%0%k%/%)!<%H$^$?$O%@%V%k%/%)!<%H$G3g$i$l$kItJ,$,(B + $BB3$/>l9g$O$3$l$,%F%s%W%l!<%H%\%G%#$H$7$F07$o$l$k!%(B + +%\item If the rest of the line \emph{does not} start with a quote +% character, it is treated as the name of a file; the contents of this +% file will be read and used as a template body. +\item $BB3$/ItJ,$,%/%)!<%HJ8;z$G;O$^$i$J$$>l9g$O%U%!%$%kL>$H$7$F07$o$l!$%U%!(B + $B%$%k$NFbMF$,%F%s%W%l!<%H%\%G%#$H$7$F;H$o$l$k!%(B + +\end{itemize} + +%\section{Style files by example} +\section{$B%9%?%$%k%U%!%$%k$NNc(B} + +%To illustrate how to write a style file, we will construct a few by +%example. Rather than provide a complete style file and walk through +%it, we'll mirror the usual process of developing a style file by +%starting with something very simple, and walking through a series of +%successively more complete examples. + +$B%9%?%$%k%U%!%$%k$N=q$-J}$r@bL@$9$k$?$a$K$$$/$D$+$NNcBj$r5s$2$F$_$k!%40A4(B +$B$J%9%?%$%k%U%!%$%k$rMQ0U$7$F$3$l$r@bL@$9$k$N$G$O$J$/!$$H$F$bC1=c$JNc$+$i(B +$B;O$a$F!$$@$s$@$s$HJ#;($JNc$K?J$`$3$H$G%9%?%$%k%U%!%$%k$NDL>o$N3+H/%W%m%;(B +$B%9$rLOJo$7$F$_$k!%(B + +%\subsection{Identifying mistakes in style files} +\subsection{$B%9%?%$%k%U%!%$%k$G$N8m$j$rFCDj$9$k(B} + +%If Mercurial encounters a problem in a style file you are working on, +%it prints a terse error message that, once you figure out what it +%means, is actually quite useful. + +Mercurial$B$,%9%?%$%k%U%!%$%k$GLdBj$KD>LL$9$k$H!$4J7i$J%(%i!<%a%C%;!<%8$rI=(B +$B<($9$k!%$3$N%a%C%;!<%8$O$=$N0UL#$9$k$H$3$m$,J,$+$C$F$$$l$P$H$F$bM-1W$G$"(B +$B$k!%(B + +\interaction{template.svnstyle.syntax.input} + +%Notice that \filename{broken.style} attempts to define a +%\texttt{changeset} keyword, but forgets to give any content for it. +%When instructed to use this style file, Mercurial promptly complains. + +\filename{broken.style}$B$G(B\texttt{changeset}$B%-!<%o!<%I$rDj5A$7$h$&$H$7$F$$(B +$B$k$,!$Dj5A$NFbMF$,A4$/M?$($i$l$F$$$J$$!%$3$N%9%?%$%k%U%!%$%k$r;H$*$&$H$9(B +$B$k$H!$(BMercurial$B$O$9$0$5$^%(%i!<$rI=<($9$k!%(B + +\interaction{template.svnstyle.syntax.error} + +%This error message looks intimidating, but it is not too hard to +%follow. + +$B$3$N%(%i!<%a%C%;!<%8$O62$m$7$2$@$,!$BP1~$9$k$N$O$5$[$IFq$7$/$J$$!%(B + +\begin{itemize} +%\item The first component is simply Mercurial's way of saying ``I am +% giving up''. + \item $B:G=i$NItJ,$O(B``$B%.%V%"%C%W(B''$B$N(BMercurial$BE*$JI=8=$G$"$k!%(B + \begin{codesample4} + \textbf{abort:} broken.style:1: parse error + \end{codesample4} + +%\item Next comes the name of the style file that contains the error. +\item $B<!$K%(%i!<$N$"$k%9%?%$%k%U%!%$%kL>$,I=<($5$l$k(B + \begin{codesample4} + abort: \textbf{broken.style}:1: parse error + \end{codesample4} + +%\item Following the file name is the line number where the error was +% encountered. + \item $B%U%!%$%kL>$N8e$K%(%i!<$N5/$-$?9THV9f$,B3$/!%(B + \begin{codesample4} + abort: broken.style:\textbf{1}: parse error + \end{codesample4} + +%\item Finally, a description of what went wrong. + \item $B:G8e$KLdBjE@$N@bL@$,I=<($5$l$k(B + \begin{codesample4} + abort: broken.style:1: \textbf{parse error} + \end{codesample4} +% The description of the problem is not always clear (as in this +% case), but even when it is cryptic, it is almost always trivial to +% visually inspect the offending line in the style file and see what +% is wrong. +$BLdBj$N@bL@$O>o$KL@2w$G$"$k$H$O8B$i$J$$!%!J$3$NNc$N$h$&$K!%!K$7$+$7Ff$a$$(B + $B$F$$$?$H$7$F$b!$KX$s$I$N>l9g!$%9%?%$%k%U%!%$%k$NLdBj$N$"$k9T$r8+(B + $B$k$H!$$4$/:3:Y$JLdBj$K$9$.$J$$$b$N$G$"$k!%(B +\end{itemize} + +%\subsection{Uniquely identifying a repository} +\subsection{$B%j%]%8%H%j$NFCDj(B} + +%If you would like to be able to identify a Mercurial repository +%``fairly uniquely'' using a short string as an identifier, you can +%use the first revision in the repository. +%\interaction{template.svnstyle.id} + +%This is not guaranteed to be unique, but it is nevertheless useful in +%many cases. + +$BC;$$J8;zNs$r<1JL;R$K;H$C$F(BMercurial$B%j%]%8%H%j$rFCDj$7$?$$>l9g$O(B +$B%j%]%8%H%jFb$N:G=i$N%j%S%8%g%s$r;H$&$3$H$,$G$-$k!%(B +\interaction{template.svnstyle.id} +$B$3$l$O%f%K!<%/$G$"$k$3$H$,J]>Z$5$l$F$$$k$o$1$G$O$J$$$,!$B?$/$N>l9g$KM-MQ(B +$B$G$"$k$3$H$O$$$&$^$G$b$J$$!%(B + +\begin{itemize} +%\item It will not work in a completely empty repository, because such +% a repository does not have a revision~zero. + \item $B40A4$K6u$N%j%]%8%H%j$G$O$3$NJ}K!$O;H$($J$$!%6u$N%j%]%8%H%j$K$O%j(B + $B%S%8%g%s(B~$B%<%m$9$iB8:_$7$J$$$?$a$G$"$k!%(B + +%\item Neither will it work in the (extremely rare) case where a +% repository is a merge of two or more formerly independent +% repositories, and you still have those repositories around. + \item $BFHN)$7$?J#?t$N%j%]%8%H%j$r%^!<%8$7$F%j%]%8%H%j$r:n@.$7!$$3$l$i$N(B + $B%j%]%8%H%j$,0MA3$H$7$FB8:_$9$k$J$I$N!J$-$o$a$F5)$J!K>l9g$O$3$NJ}(B + $BK!$O;H$($J$$!%(B +\end{itemize} +%Here are some uses to which you could put this identifier: +$B$3$N<1JL;R$N;HMQNc$r<($9(B: +\begin{itemize} +%\item As a key into a table for a database that manages repositories +% on a server. + \item $B%5!<%P>e$G%j%]%8%H%j$r4IM}$9$k%G!<%?%Y!<%9MQ$N%F!<%V%k$X$N%-!<$H$7$F!%(B + +%\item As half of a \{\emph{repository~ID}, \emph{revision~ID}\} tuple. +% Save this information away when you run an automated build or other +% activity, so that you can ``replay'' the build later if necessary. + \item \{\emph{repository~ID}, \emph{revision~ID}\}$B%?%W%k$NH>J,$H$7$F!%<+(B +$BF0%S%k%I$d$=$NB>$NA`:n$r9T$&$H$-$K$3$N>pJs$r%;!<%V$7$F$*$-!$8e$G%S%k%I$r(B +$B:F8=$9$k$3$H$,I,MW$H$J$C$?$i(B``$B%j%W%l%$(B''$B$r9T$($k$h$&$K$9$k!%(B + +\end{itemize} + +%\subsection{Mimicking Subversion's output} +\subsection{Subversion$B=PNO$NLOJo(B} + +%Let's try to emulate the default output format used by another +%revision control tool, Subversion. +%\interaction{template.svnstyle.short} + +$BJL$N%P!<%8%g%s4IM}%D!<%k$G$"$k(BSubversion$B$N=PNO$r%(%_%e%l!<%H$7$F$_$h$&!%(B +\interaction{template.svnstyle.short} + +%Since Subversion's output style is fairly simple, it is easy to +%copy-and-paste a hunk of its output into a file, and replace the text +%produced above by Subversion with the template values we'd like to see +%expanded. + +Subversion$B$N=PNO%9%?%$%k$O$+$J$jC1=c$J$N$G!$=PNO$+$i%U%!%$%k$X(Bhunk$B$r%3%T!<(B +$B!u%Z!<%9%H$7!$(BSubversion$B$,@8@.$7$?%F%-%9%H$r%F%s%W%l!<%H$K$h$C$FCV49$9$k(B +$B$N$O4JC1$G$"$k!%(B +\interaction{template.svnstyle.template} + +%There are a few small ways in which this template deviates from the +%output produced by Subversion. + +$B%F%s%W%l!<%H$K$h$k=PNO$,(BSubversion$B$,@8@.$9$k=PNO$H0[$J$k(B2, 3$B$NNc$,$"$k!%(B + +\begin{itemize} +%\item Subversion prints a ``readable'' date (the ``\texttt{Wed, 27 Sep +% 2006}'' in the example output above) in parentheses. Mercurial's +% templating engine does not provide a way to display a date in this +% format without also printing the time and time zone. + \item Subversion$B$OCf3g8L$G0O$^$l$?(B``$B2DFI$J(B''$BF|;~$r=PNO$9$k!%!J>e$NNc$G$O(B + ``\texttt{Wed, 27 Sep 2006}''$B!%!K(B Mercurial$B$N%F%s%W%l!<%H%(%s%8%s(B + $B$O$3$N%U%)!<%^%C%H$G;~9o$H%?%$%`%>!<%s$r4^$^$J$$7A$GF|;~$r=PNO$9$k(B + $B$3$H$,$G$-$J$$!%(B + +%\item We emulate Subversion's printing of ``separator'' lines full of +% ``\texttt{-}'' characters by ending the template with such a line. +% We use the templating engine's \tplkword{header} keyword to print a +% separator line as the first line of output (see below), thus +% achieving similar output to Subversion. + \item Subversion$B$N(B``$B%;%Q%l!<%?(B''$B9T$N=PNO$r%F%s%W%l!<%H$r9TI}0lGU$N(B + ``\texttt{-}''$BJ8;z$G=*$($k$3$H$G%(%_%e%l!<%H$7$F$$$k!%%F%s%W%l!<%H(B + $B%(%s%8%s$N(B\tplkword{header}$B%-!<%o!<%I$r;H$C$F%;%Q%l!<%?9T$r=PNO$N(B + $B:G=i$N9T$H$7$F=PNO$9$k!%!J2<5-$r;2>H!%!K$3$l$K$h$C$F(BSubversion$B$H;w(B + $BDL$C$?=PNO$r9T$C$F$$$k!%(B + +%\item Subversion's output includes a count in the header of the number +% of lines in the commit message. We cannot replicate this in +% Mercurial; the templating engine does not currently provide a filter +% that counts the number of items it is passed. + \item Subversion$B$N=PNO$O%X%C%@Fb$K%3%_%C%H%a%C%;!<%8$N9T?t$N%+%&%s%H$r(B + $B4^$s$G$$$k!%(BMercurial$B$G$O$3$l$r:F8=$9$k$3$H$O$G$-$J$$!%%F%s%W%l!<(B + $B%H%(%s%8%s$O8=>u$G$OEO$5$l$?%"%$%F%`$r?t$($k%U%#%k%?$r:n$k$3$H$,(B + $B$G$-$J$$!%(B +\end{itemize} +%It took me no more than a minute or two of work to replace literal +%text from an example of Subversion's output with some keywords and +%filters to give the template above. The style file simply refers to +%the template. + +Subversion$B$N=PNO$r;29M$K!$%F%-%9%H$rCV49$9$k%-!<%o!<%I!$%F%s%W%l!<%H$NF~$C(B +$B$?%U%#%k%?$r=`Hw$9$k$N$K$O$[$s$N#1!$#2J,$7$+$+$+$i$J$+$C$?!%%9%?%$%k%U%!(B +$B%$%k$OC1=c$K%F%s%W%l!<%H$r;2>H$9$k$N$_$G$"$k(B + +\interaction{template.svnstyle.style} + +%We could have included the text of the template file directly in the +%style file by enclosing it in quotes and replacing the newlines with +%``\texttt{\\n}'' sequences, but it would have made the style file too +%difficult to read. Readability is a good guide when you're trying to +%decide whether some text belongs in a style file, or in a template +%file that the style file points to. If the style file will look too +%big or cluttered if you insert a literal piece of text, drop it into a +%template instead. + +$B%F%s%W%l!<%H%U%!%$%k$N%F%-%9%H$r%/%)!<%H$G3g$j!$2~9T$r(B``\texttt{\\n}''$B$G(B +$B%(%9%1!<%W$9$k$3$H$G%9%?%$%k%U%!%$%k$KD>@\DI2C$9$k$3$H$b2DG=$G$O$"$k!%$7(B +$B$+$7$=$&$7$?>l9g!$%9%?%$%k%U%!%$%k$,$[$H$s$IFI$a$J$$$[$IJ#;($K$J$C$F$7$^(B +$B$&$@$m$&!%%F%-%9%H$r%9%?%$%k%U%!%$%k$KF~$l$k$+!$%9%?%$%k%U%!%$%k$+$i8F$P(B +$B$l$k%F%s%W%l!<%H%U%!%$%k$KF~$l$k$+$O!$2DFI@-$r9MN8$7$F7hDj$9$Y$-$G$"$k!%(B +$B$b$7%F%-%9%H$rDI2C$7$?$3$H$G%9%?%$%k%U%!%$%k$,Bg$-$/$J$j2a$.$?$j!$Mp;($K(B +$B$J$C$?$j$7$?>l9g$O!$%F%s%W%l!<%H$X$N0\F0$r9MN8$9$k$H$h$$!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/todo.txt Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,22 @@ + translate proofread +00book.tex 100% +branch.tex 100% +collab.tex 100% +concepts.tex +daily.tex 100% +filenames.tex 100% +hg_id.tex noneed +hgext.tex 100% +hook.tex 50% +intro.tex 100% +license.tex +mq-collab.tex 100% +mq-ref.tex 100% +mq.tex 100% +preface.tex 100% +srcinstall.tex 100% +template.tex 100% +tour-basic.tex +tour-merge.tex 100% +undo.tex 100% +cmdref.tex 100%
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/tour-basic.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,617 @@ +\chapter{A tour of Mercurial: the basics} +\label{chap:tour-basic} + +\section{Installing Mercurial on your system} +\label{sec:tour:install} + +Prebuilt binary packages of Mercurial are available for every popular +operating system. These make it easy to start using Mercurial on your +computer immediately. + +\subsection{Linux} + +Because each Linux distribution has its own packaging tools, policies, +and rate of development, it's difficult to give a comprehensive set of +instructions on how to install Mercurial binaries. The version of +Mercurial that you will end up with can vary depending on how active +the person is who maintains the package for your distribution. + +To keep things simple, I will focus on installing Mercurial from the +command line under the most popular Linux distributions. Most of +these distributions provide graphical package managers that will let +you install Mercurial with a single click; the package name to look +for is \texttt{mercurial}. + +\begin{itemize} +\item[Debian] + \begin{codesample4} + apt-get install mercurial + \end{codesample4} + +\item[Fedora Core] + \begin{codesample4} + yum install mercurial + \end{codesample4} + +\item[Gentoo] + \begin{codesample4} + emerge mercurial + \end{codesample4} + +\item[OpenSUSE] + \begin{codesample4} + yum install mercurial + \end{codesample4} + +\item[Ubuntu] Ubuntu's Mercurial package is based on Debian's. To + install it, run the following command. + \begin{codesample4} + apt-get install mercurial + \end{codesample4} + The Ubuntu package for Mercurial tends to lag behind the Debian + version by a considerable time margin (at the time of writing, seven + months), which in some cases will mean that on Ubuntu, you may run + into problems that have since been fixed in the Debian package. +\end{itemize} + +\subsection{Solaris} + +XXX. + +\subsection{Mac OS X} + +Lee Cantey publishes an installer of Mercurial for Mac OS~X at +\url{http://mercurial.berkwood.com}. This package works on both +Intel-~and Power-based Macs. Before you can use it, you must install +a compatible version of Universal MacPython~\cite{web:macpython}. This +is easy to do; simply follow the instructions on Lee's site. + +\subsection{Windows} + +Lee Cantey also publishes an installer of Mercurial for Windows at +\url{http://mercurial.berkwood.com}. This package has no external +dependencies; it ``just works''. + +\begin{note} + The Windows version of Mercurial does not automatically convert line + endings between Windows and Unix styles. If you want to share work + with Unix users, you must do a little additional configuration + work. XXX Flesh this out. +\end{note} + +\section{Getting started} + +To begin, we'll use the \hgcmd{version} command to find out whether +Mercurial is actually installed properly. The actual version +information that it prints isn't so important; it's whether it prints +anything at all that we care about. +\interaction{tour.version} + +\subsection{Built-in help} + +Mercurial provides a built-in help system. This is invaluable for those +times when you find yourself stuck trying to remember how to run a +command. If you are completely stuck, simply run \hgcmd{help}; it +will print a brief list of commands, along with a description of what +each does. If you ask for help on a specific command (as below), it +prints more detailed information. +\interaction{tour.help} +For a more impressive level of detail (which you won't usually need) +run \hgcmdargs{help}{\hggopt{-v}}. The \hggopt{-v} option is short +for \hggopt{--verbose}, and tells Mercurial to print more information +than it usually would. + +\section{Working with a repository} + +In Mercurial, everything happens inside a \emph{repository}. The +repository for a project contains all of the files that ``belong to'' +that project, along with a historical record of the project's files. + +There's nothing particularly magical about a repository; it is simply +a directory tree in your filesystem that Mercurial treats as special. +You can rename or delete a repository any time you like, using either the +command line or your file browser. + +\subsection{Making a local copy of a repository} + +\emph{Copying} a repository is just a little bit special. While you +could use a normal file copying command to make a copy of a +repository, it's best to use a built-in command that Mercurial +provides. This command is called \hgcmd{clone}, because it creates an +identical copy of an existing repository. +\interaction{tour.clone} +If our clone succeeded, we should now have a local directory called +\dirname{hello}. This directory will contain some files. +\interaction{tour.ls} +These files have the same contents and history in our repository as +they do in the repository we cloned. + +Every Mercurial repository is complete, self-contained, and +independent. It contains its own private copy of a project's files +and history. A cloned repository remembers the location of the +repository it was cloned from, but it does not communicate with that +repository, or any other, unless you tell it to. + +What this means for now is that we're free to experiment with our +repository, safe in the knowledge that it's a private ``sandbox'' that +won't affect anyone else. + +\subsection{What's in a repository?} + +When we take a more detailed look inside a repository, we can see that +it contains a directory named \dirname{.hg}. This is where Mercurial +keeps all of its metadata for the repository. +\interaction{tour.ls-a} + +The contents of the \dirname{.hg} directory and its subdirectories are +private to Mercurial. Every other file and directory in the +repository is yours to do with as you please. + +To introduce a little terminology, the \dirname{.hg} directory is the +``real'' repository, and all of the files and directories that coexist +with it are said to live in the \emph{working directory}. An easy way +to remember the distinction is that the \emph{repository} contains the +\emph{history} of your project, while the \emph{working directory} +contains a \emph{snapshot} of your project at a particular point in +history. + +\section{A tour through history} + +One of the first things we might want to do with a new, unfamiliar +repository is understand its history. The \hgcmd{log} command gives +us a view of history. +\interaction{tour.log} +By default, this command prints a brief paragraph of output for each +change to the project that was recorded. In Mercurial terminology, we +call each of these recorded events a \emph{changeset}, because it can +contain a record of changes to several files. + +The fields in a record of output from \hgcmd{log} are as follows. +\begin{itemize} +\item[\texttt{changeset}] This field has the format of a number, + followed by a colon, followed by a hexadecimal string. These are + \emph{identifiers} for the changeset. There are two identifiers + because the number is shorter and easier to type than the hex + string. +\item[\texttt{user}] The identity of the person who created the + changeset. This is a free-form field, but it most often contains a + person's name and email address. +\item[\texttt{date}] The date and time on which the changeset was + created, and the timezone in which it was created. (The date and + time are local to that timezone; they display what time and date it + was for the person who created the changeset.) +\item[\texttt{summary}] The first line of the text message that the + creator of the changeset entered to describe the changeset. +\end{itemize} +The default output printed by \hgcmd{log} is purely a summary; it is +missing a lot of detail. + +Figure~\ref{fig:tour-basic:history} provides a graphical representation of +the history of the \dirname{hello} repository, to make it a little +easier to see which direction history is ``flowing'' in. We'll be +returning to this figure several times in this chapter and the chapter +that follows. + +\begin{figure}[ht] + \centering + \grafix{tour-history} + \caption{Graphical history of the \dirname{hello} repository} + \label{fig:tour-basic:history} +\end{figure} + +\subsection{Changesets, revisions, and talking to other + people} + +As English is a notoriously sloppy language, and computer science has +a hallowed history of terminological confusion (why use one term when +four will do?), revision control has a variety of words and phrases +that mean the same thing. If you are talking about Mercurial history +with other people, you will find that the word ``changeset'' is often +compressed to ``change'' or (when written) ``cset'', and sometimes a +changeset is referred to as a ``revision'' or a ``rev''. + +While it doesn't matter what \emph{word} you use to refer to the +concept of ``a~changeset'', the \emph{identifier} that you use to +refer to ``a~\emph{specific} changeset'' is of great importance. +Recall that the \texttt{changeset} field in the output from +\hgcmd{log} identifies a changeset using both a number and a +hexadecimal string. +\begin{itemize} +\item The revision number is \emph{only valid in that repository}, +\item while the hex string is the \emph{permanent, unchanging + identifier} that will always identify that exact changeset in + \emph{every} copy of the repository. +\end{itemize} +This distinction is important. If you send someone an email talking +about ``revision~33'', there's a high likelihood that their +revision~33 will \emph{not be the same} as yours. The reason for this +is that a revision number depends on the order in which changes +arrived in a repository, and there is no guarantee that the same +changes will happen in the same order in different repositories. +Three changes $a,b,c$ can easily appear in one repository as $0,1,2$, +while in another as $1,0,2$. + +Mercurial uses revision numbers purely as a convenient shorthand. If +you need to discuss a changeset with someone, or make a record of a +changeset for some other reason (for example, in a bug report), use +the hexadecimal identifier. + +\subsection{Viewing specific revisions} + +To narrow the output of \hgcmd{log} down to a single revision, use the +\hgopt{log}{-r} (or \hgopt{log}{--rev}) option. You can use either a +revision number or a long-form changeset identifier, and you can +provide as many revisions as you want. \interaction{tour.log-r} + +If you want to see the history of several revisions without having to +list each one, you can use \emph{range notation}; this lets you +express the idea ``I want all revisions between $a$ and $b$, +inclusive''. +\interaction{tour.log.range} +Mercurial also honours the order in which you specify revisions, so +\hgcmdargs{log}{-r 2:4} prints $2,3,4$ while \hgcmdargs{log}{-r 4:2} +prints $4,3,2$. + +\subsection{More detailed information} + +While the summary information printed by \hgcmd{log} is useful if you +already know what you're looking for, you may need to see a complete +description of the change, or a list of the files changed, if you're +trying to decide whether a changeset is the one you're looking for. +The \hgcmd{log} command's \hggopt{-v} (or \hggopt{--verbose}) +option gives you this extra detail. +\interaction{tour.log-v} + +If you want to see both the description and content of a change, add +the \hgopt{log}{-p} (or \hgopt{log}{--patch}) option. This displays +the content of a change as a \emph{unified diff} (if you've never seen +a unified diff before, see section~\ref{sec:mq:patch} for an overview). +\interaction{tour.log-vp} + +\section{All about command options} + +Let's take a brief break from exploring Mercurial commands to discuss +a pattern in the way that they work; you may find this useful to keep +in mind as we continue our tour. + +Mercurial has a consistent and straightforward approach to dealing +with the options that you can pass to commands. It follows the +conventions for options that are common to modern Linux and Unix +systems. +\begin{itemize} +\item Every option has a long name. For example, as we've already + seen, the \hgcmd{log} command accepts a \hgopt{log}{--rev} option. +\item Most options have short names, too. Instead of + \hgopt{log}{--rev}, we can use \hgopt{log}{-r}. (The reason that + some options don't have short names is that the options in question + are rarely used.) +\item Long options start with two dashes (e.g.~\hgopt{log}{--rev}), + while short options start with one (e.g.~\hgopt{log}{-r}). +\item Option naming and usage is consistent across commands. For + example, every command that lets you specify a changeset~ID or + revision number accepts both \hgopt{log}{-r} and \hgopt{log}{--rev} + arguments. +\end{itemize} +In the examples throughout this book, I use short options instead of +long. This just reflects my own preference, so don't read anything +significant into it. + +Most commands that print output of some kind will print more output +when passed a \hggopt{-v} (or \hggopt{--verbose}) option, and less +when passed \hggopt{-q} (or \hggopt{--quiet}). + +\section{Making and reviewing changes} + +Now that we have a grasp of viewing history in Mercurial, let's take a +look at making some changes and examining them. + +The first thing we'll do is isolate our experiment in a repository of +its own. We use the \hgcmd{clone} command, but we don't need to +clone a copy of the remote repository. Since we already have a copy +of it locally, we can just clone that instead. This is much faster +than cloning over the network, and cloning a local repository uses +less disk space in most cases, too. +\interaction{tour.reclone} +As an aside, it's often good practice to keep a ``pristine'' copy of a +remote repository around, which you can then make temporary clones of +to create sandboxes for each task you want to work on. This lets you +work on multiple tasks in parallel, each isolated from the others +until it's complete and you're ready to integrate it back. Because +local clones are so cheap, there's almost no overhead to cloning and +destroying repositories whenever you want. + +In our \dirname{my-hello} repository, we have a file +\filename{hello.c} that contains the classic ``hello, world'' program. +Let's use the ancient and venerable \command{sed} command to edit this +file so that it prints a second line of output. (I'm only using +\command{sed} to do this because it's easy to write a scripted example +this way. Since you're not under the same constraint, you probably +won't want to use \command{sed}; simply use your preferred text editor to +do the same thing.) +\interaction{tour.sed} + +Mercurial's \hgcmd{status} command will tell us what Mercurial knows +about the files in the repository. +\interaction{tour.status} +The \hgcmd{status} command prints no output for some files, but a line +starting with ``\texttt{M}'' for \filename{hello.c}. Unless you tell +it to, \hgcmd{status} will not print any output for files that have +not been modified. + +The ``\texttt{M}'' indicates that Mercurial has noticed that we +modified \filename{hello.c}. We didn't need to \emph{inform} +Mercurial that we were going to modify the file before we started, or +that we had modified the file after we were done; it was able to +figure this out itself. + +It's a little bit helpful to know that we've modified +\filename{hello.c}, but we might prefer to know exactly \emph{what} +changes we've made to it. To do this, we use the \hgcmd{diff} +command. +\interaction{tour.diff} + +\section{Recording changes in a new changeset} + +We can modify files, build and test our changes, and use +\hgcmd{status} and \hgcmd{diff} to review our changes, until we're +satisfied with what we've done and arrive at a natural stopping point +where we want to record our work in a new changeset. + +The \hgcmd{commit} command lets us create a new changeset; we'll +usually refer to this as ``making a commit'' or ``committing''. + +\subsection{Setting up a username} + +When you try to run \hgcmd{commit} for the first time, it is not +guaranteed to succeed. Mercurial records your name and address with +each change that you commit, so that you and others will later be able +to tell who made each change. Mercurial tries to automatically figure +out a sensible username to commit the change with. It will attempt +each of the following methods, in order: +\begin{enumerate} +\item If you specify a \hgopt{commit}{-u} option to the \hgcmd{commit} + command on the command line, followed by a username, this is always + given the highest precedence. +\item If you have set the \envar{HGUSER} environment variable, this is + checked next. +\item If you create a file in your home directory called + \sfilename{.hgrc}, with a \rcitem{ui}{username} entry, that will be + used next. To see what the contents of this file should look like, + refer to section~\ref{sec:tour-basic:username} below. +\item If you have set the \envar{EMAIL} environment variable, this + will be used next. +\item Mercurial will query your system to find out your local user + name and host name, and construct a username from these components. + Since this often results in a username that is not very useful, it + will print a warning if it has to do this. +\end{enumerate} +If all of these mechanisms fail, Mercurial will fail, printing an +error message. In this case, it will not let you commit until you set +up a username. + +You should think of the \envar{HGUSER} environment variable and the +\hgopt{commit}{-u} option to the \hgcmd{commit} command as ways to +\emph{override} Mercurial's default selection of username. For normal +use, the simplest and most robust way to set a username for yourself +is by creating a \sfilename{.hgrc} file; see below for details. + +\subsubsection{Creating a Mercurial configuration file} +\label{sec:tour-basic:username} + +To set a user name, use your favourite editor to create a file called +\sfilename{.hgrc} in your home directory. Mercurial will use this +file to look up your personalised configuration settings. The initial +contents of your \sfilename{.hgrc} should look like this. +\begin{codesample2} + # This is a Mercurial configuration file. + [ui] + username = Firstname Lastname <email.address@domain.net> +\end{codesample2} +The ``\texttt{[ui]}'' line begins a \emph{section} of the config file, +so you can read the ``\texttt{username = ...}'' line as meaning ``set +the value of the \texttt{username} item in the \texttt{ui} section''. +A section continues until a new section begins, or the end of the +file. Mercurial ignores empty lines and treats any text from +``\texttt{\#}'' to the end of a line as a comment. + +\subsubsection{Choosing a user name} + +You can use any text you like as the value of the \texttt{username} +config item, since this information is for reading by other people, +but for interpreting by Mercurial. The convention that most people +follow is to use their name and email address, as in the example +above. + +\begin{note} + Mercurial's built-in web server obfuscates email addresses, to make + it more difficult for the email harvesting tools that spammers use. + This reduces the likelihood that you'll start receiving more junk + email if you publish a Mercurial repository on the web. +\end{note} + +\subsection{Writing a commit message} + +When we commit a change, Mercurial drops us into a text editor, to +enter a message that will describe the modifications we've made in +this changeset. This is called the \emph{commit message}. It will be +a record for readers of what we did and why, and it will be printed by +\hgcmd{log} after we've finished committing. +\interaction{tour.commit} + +The editor that the \hgcmd{commit} command drops us into will contain +an empty line, followed by a number of lines starting with +``\texttt{HG:}''. +\begin{codesample2} + \emph{empty line} + HG: changed hello.c +\end{codesample2} +Mercurial ignores the lines that start with ``\texttt{HG:}''; it uses +them only to tell us which files it's recording changes to. Modifying +or deleting these lines has no effect. + +\subsection{Writing a good commit message} + +Since \hgcmd{log} only prints the first line of a commit message by +default, it's best to write a commit message whose first line stands +alone. Here's a real example of a commit message that \emph{doesn't} +follow this guideline, and hence has a summary that is not readable. +\begin{codesample2} + changeset: 73:584af0e231be + user: Censored Person <censored.person@example.org> + date: Tue Sep 26 21:37:07 2006 -0700 + summary: include buildmeister/commondefs. Add an exports and install +\end{codesample2} + +As far as the remainder of the contents of the commit message are +concerned, there are no hard-and-fast rules. Mercurial itself doesn't +interpret or care about the contents of the commit message, though +your project may have policies that dictate a certain kind of +formatting. + +My personal preference is for short, but informative, commit messages +that tell me something that I can't figure out with a quick glance at +the output of \hgcmdargs{log}{--patch}. + +\subsection{Aborting a commit} + +If you decide that you don't want to commit while in the middle of +editing a commit message, simply exit from your editor without saving +the file that it's editing. This will cause nothing to happen to +either the repository or the working directory. + +If we run the \hgcmd{commit} command without any arguments, it records +all of the changes we've made, as reported by \hgcmd{status} and +\hgcmd{diff}. + +\subsection{Admiring our new handiwork} + +Once we've finished the commit, we can use the \hgcmd{tip} command to +display the changeset we just created. This command produces output +that is identical to \hgcmd{log}, but it only displays the newest +revision in the repository. +\interaction{tour.tip} +We refer to the newest revision in the repository as the tip revision, +or simply the tip. + +\section{Sharing changes} + +We mentioned earlier that repositories in Mercurial are +self-contained. This means that the changeset we just created exists +only in our \dirname{my-hello} repository. Let's look at a few ways +that we can propagate this change into other repositories. + +\subsection{Pulling changes from another repository} +\label{sec:tour:pull} + +To get started, let's clone our original \dirname{hello} repository, +which does not contain the change we just committed. We'll call our +temporary repository \dirname{hello-pull}. +\interaction{tour.clone-pull} + +We'll use the \hgcmd{pull} command to bring changes from +\dirname{my-hello} into \dirname{hello-pull}. However, blindly +pulling unknown changes into a repository is a somewhat scary +prospect. Mercurial provides the \hgcmd{incoming} command to tell us +what changes the \hgcmd{pull} command \emph{would} pull into the +repository, without actually pulling the changes in. +\interaction{tour.incoming} +(Of course, someone could cause more changesets to appear in the +repository that we ran \hgcmd{incoming} in, before we get a chance to +\hgcmd{pull} the changes, so that we could end up pulling changes that we +didn't expect.) + +Bringing changes into a repository is a simple matter of running the +\hgcmd{pull} command, and telling it which repository to pull from. +\interaction{tour.pull} +As you can see from the before-and-after output of \hgcmd{tip}, we +have successfully pulled changes into our repository. There remains +one step before we can see these changes in the working directory. + +\subsection{Updating the working directory} + +We have so far glossed over the relationship between a repository and +its working directory. The \hgcmd{pull} command that we ran in +section~\ref{sec:tour:pull} brought changes into the repository, but +if we check, there's no sign of those changes in the working +directory. This is because \hgcmd{pull} does not (by default) touch +the working directory. Instead, we use the \hgcmd{update} command to +do this. +\interaction{tour.update} + +It might seem a bit strange that \hgcmd{pull} doesn't update the +working directory automatically. There's actually a good reason for +this: you can use \hgcmd{update} to update the working directory to +the state it was in at \emph{any revision} in the history of the +repository. If you had the working directory updated to an old +revision---to hunt down the origin of a bug, say---and ran a +\hgcmd{pull} which automatically updated the working directory to a +new revision, you might not be terribly happy. + +However, since pull-then-update is such a common thing to do, +Mercurial lets you combine the two by passing the \hgopt{pull}{-u} +option to \hgcmd{pull}. +\begin{codesample2} + hg pull -u +\end{codesample2} +If you look back at the output of \hgcmd{pull} in +section~\ref{sec:tour:pull} when we ran it without \hgopt{pull}{-u}, +you can see that it printed a helpful reminder that we'd have to take +an explicit step to update the working directory: +\begin{codesample2} + (run 'hg update' to get a working copy) +\end{codesample2} + +To find out what revision the working directory is at, use the +\hgcmd{parents} command. +\interaction{tour.parents} +If you look back at figure~\ref{fig:tour-basic:history}, you'll see +arrows connecting each changeset. The node that the arrow leads +\emph{from} in each case is a parent, and the node that the arrow +leads \emph{to} is its child. The working directory has a parent in +just the same way; this is the changeset that the working directory +currently contains. + +To update the working directory to a particular revision, give a +revision number or changeset~ID to the \hgcmd{update} command. +\interaction{tour.older} +If you omit an explicit revision, \hgcmd{update} will update to the +tip revision, as shown by the second call to \hgcmd{update} in the +example above. + +\subsection{Pushing changes to another repository} + +Mercurial lets us push changes to another repository, from the +repository we're currently visiting. As with the example of +\hgcmd{pull} above, we'll create a temporary repository to push our +changes into. +\interaction{tour.clone-push} +The \hgcmd{outgoing} command tells us what changes would be pushed +into another repository. +\interaction{tour.outgoing} +And the \hgcmd{push} command does the actual push. +\interaction{tour.push} +As with \hgcmd{pull}, the \hgcmd{push} command does not update the +working directory in the repository that it's pushing changes into. +(Unlike \hgcmd{pull}, \hgcmd{push} does not provide a \texttt{-u} +option that updates the other repository's working directory.) + +What happens if we try to pull or push changes and the receiving +repository already has those changes? Nothing too exciting. +\interaction{tour.push.nothing} + +\subsection{Sharing changes over a network} + +The commands we have covered in the previous few sections are not +limited to working with local repositories. Each works in exactly the +same fashion over a network connection; simply pass in a URL instead +of a local path. +\interaction{tour.outgoing.net} +In this example, we can see what changes we could push to the remote +repository, but the repository is understandably not set up to let +anonymous users push to it. +\interaction{tour.push.net} + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/tour-history.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,289 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docname="tour-history.svg"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mstart" + style="overflow:visible"> + <path + id="path2973" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.4) translate(10,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path3066" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4" + inkscape:cx="232.14286" + inkscape:cy="672.75296" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="5" + inkscape:window-y="49" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + 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" + id="rect1878" + width="94.285713" + height="20.714285" + x="138" + y="479.50504" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="493.12619" + id="text1872"><tspan + sodipodi:role="line" + id="tspan1874" + x="162.09892" + y="493.12619" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan1876">0</tspan>: 0a04</tspan></text> + <rect + 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" + id="rect2800" + width="94.285713" + height="20.714285" + x="138" + y="432.63004" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="446.25119" + id="text2794"><tspan + sodipodi:role="line" + id="tspan2796" + x="162.09892" + y="446.25119" + style="font-family:Courier"><tspan + id="tspan2868" + style="font-weight:bold">1</tspan>: 82e5</tspan></text> + <rect + 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" + id="rect2810" + width="94.285713" + height="20.714285" + x="138" + y="385.75504" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="399.37619" + id="text2804"><tspan + sodipodi:role="line" + id="tspan2806" + x="162.09892" + y="399.37619" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2866">2</tspan>: 057d</tspan></text> + <rect + 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" + id="rect2820" + width="94.285713" + height="20.714285" + x="138" + y="338.88007" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="352.50122" + id="text2814"><tspan + sodipodi:role="line" + id="tspan2816" + x="162.09892" + y="352.50122" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2864">3</tspan>: ff5d</tspan></text> + <rect + 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" + id="rect2830" + width="94.285713" + height="20.714285" + x="138" + y="292.00504" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="305.62619" + id="text2824"><tspan + sodipodi:role="line" + id="tspan2826" + x="162.09892" + y="305.62619" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2862">4</tspan>: b57f</tspan></text> + <text + xml:space="preserve" + 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" + x="173.57143" + y="443.79074" + id="text2832"><tspan + sodipodi:role="line" + id="tspan2834" + x="173.57143" + y="443.79074" /></text> + <path + 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)" + d="M 185.14286,478.50504 L 185.14286,454.34432" + id="path2894" + inkscape:connector-type="polyline" /> + <path + 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)" + d="M 185.14286,431.63004 L 185.14286,407.46932" + id="path2896" + inkscape:connector-type="polyline" /> + <path + 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)" + d="M 185.14286,384.75504 L 185.14286,360.59435" + id="path2898" + inkscape:connector-type="polyline" /> + <path + 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)" + d="M 185.14286,337.88007 L 185.14286,313.71932" + id="path2900" + inkscape:connector-type="polyline" /> + <text + xml:space="preserve" + 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" + x="244.60992" + y="305.245" + id="text1902"><tspan + sodipodi:role="line" + id="tspan1904" + x="244.60992" + y="305.245">(newest)</tspan></text> + <text + xml:space="preserve" + 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" + x="244.60992" + y="492.745" + id="text1906"><tspan + sodipodi:role="line" + id="tspan1908" + x="244.60992" + y="492.745">(oldest)</tspan></text> + <rect + 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" + id="rect1907" + width="94.285713" + height="20.714285" + x="309.28571" + y="324.86218" /> + <text + xml:space="preserve" + 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" + x="333.38464" + y="338.48334" + id="text1909"><tspan + sodipodi:role="line" + id="tspan1911" + x="333.38464" + y="338.48334" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan1913">4</tspan>: b57f</tspan></text> + <path + 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" + d="M 332.14286,375.21932 L 335.71429,347.36218" + id="path2802" /> + <path + 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" + d="M 372.69968,375.21932 L 369.12825,347.36218" + id="path2986" /> + <text + xml:space="preserve" + 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" + x="335.14285" + y="387.21933" + id="text2988"><tspan + sodipodi:role="line" + x="335.14285" + y="387.21933" + id="tspan3020" + style="text-align:end;text-anchor:end">revision</tspan><tspan + sodipodi:role="line" + x="335.14285" + y="402.21933" + id="tspan3014" + style="text-align:end;text-anchor:end">number</tspan></text> + <text + xml:space="preserve" + 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" + x="368.71429" + y="387.21933" + id="text2994"><tspan + sodipodi:role="line" + id="tspan2996" + x="368.71429" + y="387.21933">changeset</tspan><tspan + sodipodi:role="line" + x="368.71429" + y="402.21933" + id="tspan2998">identifier</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/tour-merge-conflict.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,210 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docname="tour-merge-conflict.svg"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path3053" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4" + inkscape:cx="164.78349" + inkscape:cy="590.07679" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="5" + inkscape:window-y="49" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="g1988" + transform="translate(84.85711,0)"> + <g + id="g1876"> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + 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 " + id="path1872" + sodipodi:nodetypes="cccccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 191.55484,563.36862 L 191.6923,560.98794 L 192.69126,552.44884 L 203.80416,551.31242" + id="path1874" + sodipodi:nodetypes="cccc" /> + </g> + <flowRoot + style="font-size:8px;font-family:Times New Roman" + id="flowRoot1898" + xml:space="preserve"><flowRegion + id="flowRegion1900"><rect + style="font-size:8px;font-family:Times New Roman" + y="464.50504" + x="122.85714" + height="93.571426" + width="76.428574" + id="rect1902" /></flowRegion><flowPara + id="flowPara1904">Greetings!</flowPara><flowPara + id="flowPara1906" /><flowPara + 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> + <g + id="g1966" + transform="translate(82,0.35715)"> + <g + transform="translate(-77.85718,-140.0714)" + id="g1910"> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + 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 " + id="path1912" + sodipodi:nodetypes="cccccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 191.55484,563.36862 L 191.6923,560.98794 L 192.69126,552.44884 L 203.80416,551.31242" + id="path1914" + sodipodi:nodetypes="cccc" /> + </g> + <flowRoot + transform="translate(-77.85718,-140.0714)" + style="font-size:8px;font-family:Times New Roman" + id="flowRoot1916" + xml:space="preserve"><flowRegion + id="flowRegion1918"><rect + style="font-size:8px;font-family:Times New Roman" + y="464.50504" + x="122.85714" + height="93.571426" + width="76.428574" + id="rect1920" /></flowRegion><flowPara + id="flowPara1922">Greetings!</flowPara><flowPara + id="flowPara1924" /><flowPara + id="flowPara1926">I am <flowSpan + style="font-style:italic;fill:red" + 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> + <g + id="g1977" + transform="translate(81.99999,-0.35715)"> + <g + transform="translate(83.57141,-139.3571)" + id="g1932"> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + 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 " + id="path1934" + sodipodi:nodetypes="cccccc" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 191.55484,563.36862 L 191.6923,560.98794 L 192.69126,552.44884 L 203.80416,551.31242" + id="path1936" + sodipodi:nodetypes="cccc" /> + </g> + <flowRoot + transform="translate(83.57141,-139.3571)" + style="font-size:8px;font-family:Times New Roman" + id="flowRoot1938" + xml:space="preserve"><flowRegion + id="flowRegion1940"><rect + style="font-size:8px;font-family:Times New Roman" + y="464.50504" + x="122.85714" + height="93.571426" + width="76.428574" + id="rect1942" /></flowRegion><flowPara + id="flowPara1944">Greetings!</flowPara><flowPara + id="flowPara1946" /><flowPara + id="flowPara1948">I am <flowSpan + style="font-style:italic;fill:red" + 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> + <path + 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" + d="M 215.502,457.71933 L 196.35507,424.5765" + id="path1999" + inkscape:connector-type="polyline" + inkscape:connection-start="#g1988" + inkscape:connection-end="#g1966" /> + <path + 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" + d="M 277.06936,457.71933 L 296.21629,424.5765" + id="path2001" + inkscape:connector-type="polyline" + inkscape:connection-start="#g1988" + inkscape:connection-end="#g1977" /> + <text + xml:space="preserve" + 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" + x="302.42859" + y="515.08905" + id="text1905"><tspan + sodipodi:role="line" + id="tspan1907" + x="302.42859" + y="515.08905">Base version</tspan></text> + <text + xml:space="preserve" + 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" + x="45.57143" + y="374.1619" + id="text1917"><tspan + sodipodi:role="line" + id="tspan1919" + x="45.57143" + y="374.1619">Our changes</tspan></text> + <text + xml:space="preserve" + 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" + x="385.71429" + y="374.1619" + id="text1921"><tspan + sodipodi:role="line" + id="tspan1923" + x="385.71429" + y="374.1619">Their changes</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/tour-merge-merge.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,380 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docname="tour-merge-merge.svg"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mstart" + style="overflow:visible"> + <path + id="path2973" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.4) translate(10,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path3066" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4" + inkscape:cx="247.53795" + inkscape:cy="871.05738" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="38" + inkscape:window-y="95" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + 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" + id="rect2995" + width="94.285713" + height="20.714285" + x="532.85718" + y="203.0479" /> + <text + xml:space="preserve" + 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" + x="173.57143" + y="443.79074" + id="text2832"><tspan + sodipodi:role="line" + id="tspan2834" + x="173.57143" + y="443.79074" /></text> + <rect + 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" + id="rect2830" + width="94.285713" + height="20.714285" + x="138" + y="297.76227" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="311.38342" + id="text2824"><tspan + sodipodi:role="line" + id="tspan2826" + x="162.09892" + y="311.38342" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2862">4</tspan>: b57f</tspan></text> + <path + 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" + d="M 185.14286,343.63731 L 185.14286,319.47656" + id="path2900" + inkscape:connector-type="polyline" /> + <rect + 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" + id="rect2863" + width="94.285713" + height="20.714285" + x="91.428574" + y="250.47656" /> + <text + xml:space="preserve" + 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" + x="116.09886" + y="264.56592" + id="text1965" + transform="scale(1.000002,0.999998)"><tspan + sodipodi:role="line" + id="tspan1967" + x="116.09886" + y="264.56592" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan1973">5</tspan>: ae13</tspan></text> + <path + 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" + d="M 173.95727,296.76228 L 149.75702,272.19085" + id="path1971" + inkscape:connector-type="polyline" + inkscape:connection-end="#rect2863" + inkscape:connection-start="#rect2830" /> + <rect + 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" + id="rect2911" + width="94.285995" + height="20.714283" + x="186.71414" + y="204.40514" /> + <text + xml:space="preserve" + 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" + x="210.81311" + y="218.02673" + id="text2913" + transform="scale(1.000002,0.999998)"><tspan + sodipodi:role="line" + id="tspan2915" + x="210.81311" + y="218.02673" + style="font-family:Courier"><tspan + id="tspan1966" + style="font-weight:bold">6</tspan>: d2b5</tspan></text> + <path + 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" + d="M 191.06908,296.76228 L 227.93092,226.11942" + id="path2919" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect2830" /> + <text + xml:space="preserve" + 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" + x="295.28571" + y="217.56711" + id="text2871"><tspan + sodipodi:role="line" + id="tspan2873" + x="295.28571" + y="217.56711">tip (and head)</tspan></text> + <text + xml:space="preserve" + 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" + x="76" + y="264.91769" + id="text2875"><tspan + sodipodi:role="line" + id="tspan2877" + x="76" + y="264.91769" + style="text-align:end;text-anchor:end">head</tspan></text> + <rect + 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" + id="rect1913" + width="94.285713" + height="20.714285" + x="138" + y="156.90514" /> + <path + 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" + d="M 144.22399,249.47657 L 179.49029,178.61943" + id="path1915" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect2863" + inkscape:connection-end="#rect1913" /> + <path + 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" + d="M 222.20966,203.40514 L 196.79033,178.61943" + id="path1917" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect2911" + inkscape:connection-end="#rect1913" /> + <text + xml:space="preserve" + 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" + x="166.16823" + y="168.52228" + id="text2806"><tspan + sodipodi:role="line" + id="tspan2808" + x="166.16823" + y="168.52228" + style="font-family:Courier">merge</tspan></text> + <text + xml:space="preserve" + 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" + x="246" + y="162.63338" + id="text2810"><tspan + sodipodi:role="line" + id="tspan2812" + x="246" + y="162.63338">working directory</tspan><tspan + sodipodi:role="line" + x="246" + y="177.63338" + id="tspan2814">during merge</tspan></text> + <rect + 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" + id="rect2816" + width="94.285713" + height="20.714285" + x="483.14636" + y="297.76227" /> + <text + xml:space="preserve" + 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" + x="507.24527" + y="311.38342" + id="text2818"><tspan + sodipodi:role="line" + id="tspan2820" + x="507.24527" + y="311.38342" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2822">4</tspan>: b57f</tspan></text> + <path + 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" + d="M 530.28921,343.6373 L 530.28921,319.47655" + id="path2824" + inkscape:connector-type="polyline" /> + <rect + 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" + id="rect2826" + width="94.285713" + height="20.714285" + x="436.57492" + y="250.47656" /> + <text + xml:space="preserve" + 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" + x="461.24484" + y="264.56613" + id="text2828" + transform="scale(1.000002,0.999998)"><tspan + sodipodi:role="line" + id="tspan2830" + x="461.24484" + y="264.56613" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2832">5</tspan>: ae13</tspan></text> + <path + 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" + d="M 519.10362,296.76227 L 494.90337,272.19084" + id="path2834" + inkscape:connector-type="polyline" /> + <rect + 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" + id="rect2836" + width="94.285995" + height="20.714283" + x="483.14001" + y="156.548" /> + <text + xml:space="preserve" + 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" + x="555.95911" + y="218.02698" + id="text2838" + transform="scale(1.000002,0.999998)"><tspan + sodipodi:role="line" + id="tspan2840" + x="555.95911" + y="218.02698" + style="font-family:Courier"><tspan + id="tspan2842" + style="font-weight:bold">6</tspan>: d2b5</tspan></text> + <path + 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" + d="M 536.21543,296.76227 L 574.03453,224.76218" + id="path2844" + inkscape:connector-type="polyline" /> + <text + xml:space="preserve" + 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" + x="594.43207" + y="169.78796" + id="text2846"><tspan + sodipodi:role="line" + id="tspan2848" + x="594.43207" + y="169.78796">tip</tspan></text> + <path + 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" + d="M 489.37034,249.47656 L 524.65575,178.26229" + id="path2856" + inkscape:connector-type="polyline" + inkscape:connection-end="#rect2836" /> + <path + 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" + d="M 567.85714,202.0479 L 542.42591,178.26229" + id="path2858" + inkscape:connector-type="polyline" + inkscape:connection-end="#rect2836" + inkscape:connection-start="#rect2995" /> + <text + xml:space="preserve" + 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" + x="504.54507" + y="170.39714" + id="text2860"><tspan + sodipodi:role="line" + id="tspan2863" + x="504.54507" + y="170.39714" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2997">7</tspan>: dba3</tspan></text> + <text + xml:space="preserve" + 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" + x="90.323105" + y="120.21933" + id="text2929"><tspan + sodipodi:role="line" + id="tspan2931" + x="90.323105" + y="120.21933" + style="font-weight:bold">Working directory during merge</tspan></text> + <text + xml:space="preserve" + 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" + x="435.35226" + y="120.21933" + id="text2937"><tspan + sodipodi:role="line" + id="tspan2939" + x="435.35226" + y="120.21933" + style="font-weight:bold">Repository after merge committed</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/tour-merge-pull.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docname="tour-merge-pull.svg" + sodipodi:docbase="/home/bos/hg/hgbook/en"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mstart" + style="overflow:visible"> + <path + id="path2973" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.4) translate(10,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path3066" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4" + inkscape:cx="233.63208" + inkscape:cy="832.54381" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="237" + inkscape:window-y="103" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <text + xml:space="preserve" + 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" + x="173.57143" + y="443.79074" + id="text2832"><tspan + sodipodi:role="line" + id="tspan2834" + x="173.57143" + y="443.79074" /></text> + <rect + 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" + id="rect1878" + width="94.285713" + height="20.714285" + x="138" + y="479.50504" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="493.12619" + id="text1872"><tspan + sodipodi:role="line" + id="tspan1874" + x="162.09892" + y="493.12619" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan1876">0</tspan>: 0a04</tspan></text> + <rect + 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" + id="rect2800" + width="94.285713" + height="20.714285" + x="138" + y="432.63004" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="446.25119" + id="text2794"><tspan + sodipodi:role="line" + id="tspan2796" + x="162.09892" + y="446.25119" + style="font-family:Courier"><tspan + id="tspan2868" + style="font-weight:bold">1</tspan>: 82e5</tspan></text> + <rect + 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" + id="rect2810" + width="94.285713" + height="20.714285" + x="138" + y="385.75504" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="399.37619" + id="text2804"><tspan + sodipodi:role="line" + id="tspan2806" + x="162.09892" + y="399.37619" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2866">2</tspan>: 057d</tspan></text> + <rect + 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" + id="rect2820" + width="94.285713" + height="20.714285" + x="138" + y="338.88007" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="352.50122" + id="text2814"><tspan + sodipodi:role="line" + id="tspan2816" + x="162.09892" + y="352.50122" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2864">3</tspan>: ff5d</tspan></text> + <rect + 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" + id="rect2830" + width="94.285713" + height="20.714285" + x="138" + y="292.00504" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="305.62619" + id="text2824"><tspan + sodipodi:role="line" + id="tspan2826" + x="162.09892" + y="305.62619" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2862">4</tspan>: b57f</tspan></text> + <path + 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" + d="M 185.14286,478.50504 L 185.14286,454.34432" + id="path2894" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 185.14286,431.63004 L 185.14286,407.46932" + id="path2896" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 185.14286,384.75504 L 185.14286,360.59435" + id="path2898" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 185.14286,337.88007 L 185.14286,313.71932" + id="path2900" + inkscape:connector-type="polyline" /> + <rect + 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" + id="rect2863" + width="94.285713" + height="20.714285" + x="91.428574" + y="244.71933" /> + <text + xml:space="preserve" + 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" + x="116.09886" + y="258.80865" + id="text1965" + transform="scale(1.000002,0.999998)"><tspan + sodipodi:role="line" + id="tspan1967" + x="116.09886" + y="258.80865" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan1973">5</tspan>: ae13</tspan></text> + <path + 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" + d="M 173.95727,291.00504 L 149.75702,266.43361" + id="path1971" + inkscape:connector-type="polyline" + inkscape:connection-end="#rect2863" + inkscape:connection-start="#rect2830" /> + <rect + 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" + id="rect2911" + width="94.285995" + height="20.714283" + x="186.71414" + y="198.6479" /> + <text + xml:space="preserve" + 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" + x="210.81311" + y="212.26949" + id="text2913" + transform="scale(1.000002,0.999998)"><tspan + sodipodi:role="line" + id="tspan2915" + x="210.81311" + y="212.26949" + style="font-family:Courier"><tspan + id="tspan1966" + style="font-weight:bold">6</tspan>: d2b5</tspan></text> + <path + 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" + d="M 191.06908,291.00504 L 227.93092,220.36218" + id="path2919" + inkscape:connector-type="polyline" + inkscape:connection-start="#rect2830" /> + <text + xml:space="preserve" + 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" + x="295.28571" + y="211.80988" + id="text2871"><tspan + sodipodi:role="line" + id="tspan2873" + x="295.28571" + y="211.80988">tip (and head)</tspan></text> + <text + xml:space="preserve" + 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" + x="76" + y="259.16046" + id="text2875"><tspan + sodipodi:role="line" + id="tspan2877" + x="76" + y="259.16046" + style="text-align:end;text-anchor:end">head</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/tour-merge-sep-repos.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,466 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docname="tour-merge-sep-repos.svg"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mstart" + style="overflow:visible"> + <path + id="path2973" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.4) translate(10,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path3066" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4" + inkscape:cx="307.20351" + inkscape:cy="716.87911" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="5" + inkscape:window-y="49" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <text + xml:space="preserve" + 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" + x="173.57143" + y="443.79074" + id="text2832"><tspan + sodipodi:role="line" + id="tspan2834" + x="173.57143" + y="443.79074" /></text> + <rect + 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" + id="rect1878" + width="94.285713" + height="20.714285" + x="138" + y="479.50504" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="493.12619" + id="text1872"><tspan + sodipodi:role="line" + id="tspan1874" + x="162.09892" + y="493.12619" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan1876">0</tspan>: 0a04</tspan></text> + <rect + 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" + id="rect2800" + width="94.285713" + height="20.714285" + x="138" + y="432.63004" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="446.25119" + id="text2794"><tspan + sodipodi:role="line" + id="tspan2796" + x="162.09892" + y="446.25119" + style="font-family:Courier"><tspan + id="tspan2868" + style="font-weight:bold">1</tspan>: 82e5</tspan></text> + <rect + 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" + id="rect2810" + width="94.285713" + height="20.714285" + x="138" + y="385.75504" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="399.37619" + id="text2804"><tspan + sodipodi:role="line" + id="tspan2806" + x="162.09892" + y="399.37619" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2866">2</tspan>: 057d</tspan></text> + <rect + 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" + id="rect2820" + width="94.285713" + height="20.714285" + x="138" + y="338.88007" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="352.50122" + id="text2814"><tspan + sodipodi:role="line" + id="tspan2816" + x="162.09892" + y="352.50122" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2864">3</tspan>: ff5d</tspan></text> + <rect + 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" + id="rect2830" + width="94.285713" + height="20.714285" + x="138" + y="292.00504" /> + <text + xml:space="preserve" + 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" + x="162.09892" + y="305.62619" + id="text2824"><tspan + sodipodi:role="line" + id="tspan2826" + x="162.09892" + y="305.62619" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2862">4</tspan>: b57f</tspan></text> + <path + 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" + d="M 185.14286,478.50504 L 185.14286,454.34432" + id="path2894" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 185.14286,431.63004 L 185.14286,407.46932" + id="path2896" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 185.14286,384.75504 L 185.14286,360.59435" + id="path2898" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 185.14286,337.88007 L 185.14286,313.71932" + id="path2900" + inkscape:connector-type="polyline" /> + <rect + 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" + id="rect1963" + width="94.285995" + height="20.714283" + x="138" + y="245.18723" /> + <text + xml:space="preserve" + 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" + x="162.09877" + y="258.80865" + id="text1965" + transform="scale(1.000002,0.999998)"><tspan + sodipodi:role="line" + id="tspan1967" + x="162.09877" + y="258.80865" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan1973">5</tspan>: ae13</tspan></text> + <path + 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" + d="M 185.143,291.06218 L 185.143,266.90143" + id="path1971" + inkscape:connector-type="polyline" /> + <text + xml:space="preserve" + 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" + x="136.90039" + y="232.25546" + id="text2921"><tspan + sodipodi:role="line" + id="tspan2923" + x="136.90039" + y="232.25546">my-hello</tspan></text> + <rect + 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" + id="rect2863" + width="94.285713" + height="20.714285" + x="370.71414" + y="479.49289" /> + <text + xml:space="preserve" + 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" + x="394.81305" + y="493.11404" + id="text2865"><tspan + sodipodi:role="line" + id="tspan2867" + x="394.81305" + y="493.11404" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2869">0</tspan>: 0a04</tspan></text> + <rect + 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" + id="rect2871" + width="94.285713" + height="20.714285" + x="370.71414" + y="432.61789" /> + <text + xml:space="preserve" + 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" + x="394.81305" + y="446.23904" + id="text2873"><tspan + sodipodi:role="line" + id="tspan2875" + x="394.81305" + y="446.23904" + style="font-family:Courier"><tspan + id="tspan2877" + style="font-weight:bold">1</tspan>: 82e5</tspan></text> + <rect + 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" + id="rect2879" + width="94.285713" + height="20.714285" + x="370.71414" + y="385.74289" /> + <text + xml:space="preserve" + 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" + x="394.81305" + y="399.36404" + id="text2881"><tspan + sodipodi:role="line" + id="tspan2883" + x="394.81305" + y="399.36404" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2885">2</tspan>: 057d</tspan></text> + <rect + 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" + id="rect2887" + width="94.285713" + height="20.714285" + x="370.71414" + y="338.86792" /> + <text + xml:space="preserve" + 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" + x="394.81305" + y="352.48907" + id="text2889"><tspan + sodipodi:role="line" + id="tspan2891" + x="394.81305" + y="352.48907" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2893">3</tspan>: ff5d</tspan></text> + <rect + 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" + id="rect2895" + width="94.285713" + height="20.714285" + x="370.71414" + y="291.99289" /> + <text + xml:space="preserve" + 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" + x="394.81305" + y="305.61404" + id="text2897"><tspan + sodipodi:role="line" + id="tspan2899" + x="394.81305" + y="305.61404" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2901">4</tspan>: b57f</tspan></text> + <path + 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" + d="M 417.85701,478.4929 L 417.85701,454.33218" + id="path2903" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 417.85701,431.6179 L 417.85701,407.45718" + id="path2905" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 417.85701,384.7429 L 417.85701,360.58221" + id="path2907" + inkscape:connector-type="polyline" /> + <path + 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" + d="M 417.85701,337.86793 L 417.85701,313.70718" + id="path2909" + inkscape:connector-type="polyline" /> + <rect + 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" + id="rect2911" + width="94.285995" + height="20.714283" + x="370.71414" + y="245.17511" /> + <text + xml:space="preserve" + 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" + x="394.81274" + y="258.79678" + id="text2913" + transform="scale(1.000002,0.999998)"><tspan + sodipodi:role="line" + id="tspan2915" + x="394.81274" + y="258.79678" + style="font-family:Courier"><tspan + style="font-weight:bold" + id="tspan2917">5</tspan>: d2b5</tspan></text> + <path + 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" + d="M 417.85715,291.05004 L 417.85715,266.88929" + id="path2919" + inkscape:connector-type="polyline" /> + <text + xml:space="preserve" + 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" + x="369.61453" + y="232.25546" + id="text2925"><tspan + sodipodi:role="line" + id="tspan2927" + x="369.61453" + y="232.25546">my-new-hello</tspan></text> + <text + xml:space="preserve" + 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" + x="300.54352" + y="252.12723" + id="text2933"><tspan + sodipodi:role="line" + id="tspan2935" + x="300.54352" + y="252.12723" + style="text-align:center;text-anchor:middle">newest changes</tspan><tspan + sodipodi:role="line" + x="300.54352" + y="267.12723" + style="text-align:center;text-anchor:middle" + id="tspan3132">differ</tspan></text> + <text + xml:space="preserve" + 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" + x="262.15436" + y="398.37112" + id="text2929"><tspan + sodipodi:role="line" + x="262.15436" + y="398.37112" + id="tspan3013" + style="text-align:start;text-anchor:start">common history</tspan></text> + <g + id="g3107" + transform="translate(0,0.855744)"> + <path + id="path3101" + d="M 300.35713,381.29075 L 300.35713,304.50504" + 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" /> + <path + id="path3105" + d="M 291.07142,301.64789 L 309.28571,301.64789" + 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" /> + </g> + <path + 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" + d="M 300.53571,486.38926 L 300.53571,409.60355" + id="path3113" /> + <path + 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" + d="M 291.25,488.49641 L 309.46429,488.49641" + id="path3115" /> + <text + xml:space="preserve" + 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" + x="480.71429" + y="250.91507" + id="text1949"><tspan + sodipodi:role="line" + id="tspan1951" + x="480.71429" + y="250.91507" + style="text-align:start;text-anchor:start">head revision</tspan><tspan + sodipodi:role="line" + x="480.71429" + y="265.91507" + id="tspan1953" + style="text-align:start;text-anchor:start">(has no children)</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/tour-merge.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,489 @@ +%\chapter{A tour of Mercurial: merging work} +\chapter{Mercurial$B%D%"!<(B: $B%^!<%8(B} +\label{chap:tour-merge} + +%We've now covered cloning a repository, making changes in a +%repository, and pulling or pushing changes from one repository into +%another. Our next step is \emph{merging} changes from separate +%repositories. + +$B2f!9$O4{$K%j%]%8%H%j$N%/%m!<%s!$%j%]%8%H%j$KBP$9$kJQ99!$(B1$B$D$N%j%]%8%H%j$+(B +$B$i$N(Bpull$B$HJL$N(B1$B$D$N%j%]%8%H%j$KBP$9$k(Bpush$B$r9T$C$?!%<!$N%9%F%C%W$OJL$N%j%](B +$B%8%H%j$+$iJQ99$r(B\emph{$B%^!<%8(B}$B$9$k$3$H$G$"$k!%(B + +%\section{Merging streams of work} +\section{$BJ#?t$N:n6H7k2L$r%^!<%8$9$k(B} + +%Merging is a fundamental part of working with a distributed revision +%control tool. + +$B%^!<%8$OJ,;6%j%S%8%g%s%3%s%H%m!<%k%D!<%k$G$N:n6H$K$*$$$FIT2D7g$NItJ,$G$"(B +$B$k!%(B + +\begin{itemize} +%\item Alice and Bob each have a personal copy of a repository for a + +% project they're collaborating on. Alice fixes a bug in her +% repository; Bob adds a new feature in his. They want the shared +% repository to contain both the bug fix and the new feature. + \item $B%"%j%9$H%\%V$O6&F1:n6H$7$F$$$k%W%m%8%'%/%H$N%j%]%8%H%j%3%T!<$r3F!9(B +$B;}$C$F$$$k!%%"%j%9$O<+J,$N%j%]%8%H%j$G%P%0$r=$@5$7!$%\%V$OH`$N%j%]%8%H%j(B +$B$G?75!G=$rDI2C$7$?!%H`$i$O%P%0=$@5$H?75!G=$NN>J}$r;}$D%j%]%8%H%j$r6&M-$7(B +$B$?$$$H9M$($F$$$k!%(B + +%\item I frequently work on several different tasks for a single +% project at once, each safely isolated in its own repository. +% Working this way means that I often need to merge one piece of my +% own work with another. + \item $B;d$O0l$D$N%W%m%8%'%/%H$NJL!9$N%?%9%/$KBP$7$FF1;~$K:n6H$r9T$&$3$H$r(B + $B$h$/9T$C$F$$$k!%$3$N$h$&$J:n6H%9%?%$%k$G$O!$<+J,$N:n6H$N0l$D$+$iJL(B + $B$N:n6H$N0l$D$X7k2L$r%^!<%8$7$?$$$H;W$&$3$H$,$7$P$7$P$"$k!%(B + +\end{itemize} + +%Because merging is such a common thing to need to do, Mercurial makes +%it easy. Let's walk through the process. We'll begin by cloning yet +%another repository (see how often they spring up?) and making a change +%in it. + +$B>e$G=R$Y$?$h$&$K%^!<%8$r9T$$$?$$>u67$O$H$F$bB?$$$?$a!$(B Mercurial$B$G$O%^!<(B +$B%8$r4JC1$K9T$($k$h$&$K$J$C$F$$$k!%$^$:JL$N%j%]%8%H%j$r%/%m!<%s$7!$JQ99$r(B +$B2C$($k$H$3$m$+$i;O$a$h$&!%(B +\interaction{tour.merge.clone} + +%We should now have two copies of \filename{hello.c} with different +%contents. The histories of the two repositories have also diverged, +%as illustrated in figure~\ref{fig:tour-merge:sep-repos}. + +$B:#!$FbMF$N0[$J$C$?(B2$B$D$N(B\filename{hello.c}$B$,$"$k!%(B 2$B$D$N%j%]%8%H%j$NMzNr$O(B +$B?^(B~\ref{fig:tour-merge:sep-repos}$B$K<($9$h$&$KJ,$+$l$F$$$k!%(B +\interaction{tour.merge.cat} + +\begin{figure}[ht] + \centering + \grafix{tour-merge-sep-repos} +% \caption{Divergent recent histories of the \dirname{my-hello} and +% \dirname{my-new-hello} repositories} + \caption{\dirname{my-hello}$B%j%]%8%H%j$H(B\dirname{my-new-hello}$B%j%]%8%H(B + $B%j$NMzNr$N:90[(B} + \label{fig:tour-merge:sep-repos} +\end{figure} + +%We already know that pulling changes from our \dirname{my-hello} +%repository will have no effect on the working directory. +$B4{$K(B\dirname{my-hello}$B%j%]%8%H%j$+$i$N(Bpull$B$O%o!<%-%s%0%G%#%l%/%H%j$K2?$N(B +$B1F6A$bM?$($J$$$3$H$r3X$s$@!%(B +\interaction{tour.merge.pull} +%However, the \hgcmd{pull} command says something about ``heads''. +$B$7$+$7(B\hgcmd{pull}$B%3%^%s%I$O(B``heads''$B$K$D$$$F%a%C%;!<%8$rI=<($9$k!%(B + +%\subsection{Head changesets} +\subsection{Head$B%A%'%s%8%;%C%H(B} + +%A head is a change that has no descendants, or children, as they're +%also known. The tip revision is thus a head, because the newest +%revision in a repository doesn't have any children, but a repository +%can contain more than one head. +head$B$O;RB9$d;R$r;}$?$J$$JQ99$G$"$k!%%j%]%8%H%j$N:G?7$N%j%S%8%g%s$O;R$r;}(B +$B$?$J$$$?$a!$(Btip$B%j%S%8%g%s$O$9$J$o$A(Bhead$B$G$"$k!%0lJ}$G%j%]%8%H%j$OJ#?t$N(B +head$B$r;}$AF@$k!%(B + +\begin{figure}[ht] + \centering + \grafix{tour-merge-pull} +% \caption{Repository contents after pulling from \dirname{my-hello} into +% \dirname{my-new-hello}} + \caption{\dirname{my-hello}$B$+$i(B\dirname{my-new-hello}$B$X(Bpull$B$7$?$"$H$N(B + $B%j%]%8%H%j$NFbMF(B} + \label{fig:tour-merge:pull} +\end{figure} + +%In figure~\ref{fig:tour-merge:pull}, you can see the effect of the +%pull from \dirname{my-hello} into \dirname{my-new-hello}. The history +%that was already present in \dirname{my-new-hello} is untouched, but a +%new revision has been added. By referring to +%figure~\ref{fig:tour-merge:sep-repos}, we can see that the +%\emph{changeset ID} remains the same in the new repository, but the +%\emph{revision number} has changed. (This, incidentally, is a fine +%example of why it's not safe to use revision numbers when discussing +%changesets.) We can view the heads in a repository using the +%\hgcmd{heads} command. +%\interaction{tour.merge.heads} + +$B?^(B~\ref{fig:tour-merge:pull}$B$K(B\dirname{my-hello}$B$+$i(B +\dirname{my-new-hello}$B$X(Bpull$B$r9T$C$?8z2L$r<($9!%(B \dirname{my-new-hello}$B$K(B +$B4{$KB8:_$7$?MzNr$OJQ99$5$l$:!$?7$?$K%j%S%8%g%s$,DI2C$5$l$k!%(B +figure~\ref{fig:tour-merge:sep-repos}$B$r8+$k$H!$?7$7$$%j%]%8%H%j$K$b(B +\emph{changeset ID}$B$,;D$C$F$$$k$3$H!$(B\emph{$B%j%S%8%g%sHV9f(B}$B$,JQ99$5$l$F$$(B +$B$k$3$H$,J,$+$k!%(B $B!J$3$l$OF1;~$K%A%'%s%8%;%C%H$K$D$$$FO@$8$k:]$K%j%S%8%g%s(B +$BHV9f$rMQ$$$k$N$,0BA4$G$J$$$3$H$NNc$K$J$C$F$$$k!%!K%j%]%8%H%jFb$K$"$k(Bhead +$B$O(B\hgcmd{heads}$B$K$h$C$F8+$k$3$H$,$G$-$k!%(B +\interaction{tour.merge.heads} + +%\subsection{Performing the merge} +\subsection{$B%^!<%8$r<B9T$9$k(B} + +%What happens if we try to use the normal \hgcmd{update} command to +%update to the new tip? +%\interaction{tour.merge.update} + +$B?7$7$$(Btip$B$X99?7$9$k$?$a$K(B\hgcmd{update}$B$r;H$C$?>l9g2?$,5/$-$k$+!)(B +\interaction{tour.merge.update} + +%Mercurial is telling us that the \hgcmd{update} command won't do a +%merge; it won't update the working directory when it thinks we might +%be wanting to do a merge, unless we force it to do so. Instead, we +%use the \hgcmd{merge} command to merge the two heads. +%\interaction{tour.merge.merge} + +Mercurial$B$O(B\hgcmd{update}$B%3%^%s%I$,%^!<%8$r9T$o$J$$$H%a%C%;!<%8$rI=<($9(B +$B$k!%(B \hgcmd{update}$B%3%^%s%I$O!$%^!<%8$,I,MW$H9M$($i$l$k>l9g$O!$%f!<%6$,(B +$B!J%*%W%7%g%s$K$h$C$F!K6/@)$7$J$$8B$j%o!<%-%s%0%G%#%l%/%H%j$r99?7$7$J$$!%(B +$B0lJ}!$(B\hgcmd{merge}$B%3%^%s%I$O(B2$B$D$N%X%C%I$N%^!<%8$r9T$&!%(B +\interaction{tour.merge.merge} + +\begin{figure}[ht] + \centering + \grafix{tour-merge-merge} +% \caption{Working directory and repository during merge, and +% following commit} + \caption{$B%^!<%8Cf$N%o!<%-%s%0%G%#%l%/%H%j$H%j%]%8%H%j$*$h$S8eB3$N%3%_%C(B + $B%H(B} + \label{fig:tour-merge:merge} +\end{figure} + +%This updates the working directory so that it contains changes from +%\emph{both} heads, which is reflected in both the output of +%\hgcmd{parents} and the contents of \filename{hello.c}. +%\interaction{tour.merge.parents} + +$B$3$NA`:n$K$h$C$F(B\hgcmd{parents}$B$H(B\filename{hello.c}$B$N=PNO$NAPJ}$rH?1G$9$k(B +\emph{$BAPJ}$N(B}head$B$+$i$NJQ99$r4^$`$h$&$K%o!<%-%s%0%G%#%l%/%H%j$,99?7$5$l$k!%(B + +%\subsection{Committing the results of the merge} +\subsection{$B%^!<%87k2L$r%3%_%C%H$9$k(B} + +%Whenever we've done a merge, \hgcmd{parents} will display two parents +%until we \hgcmd{commit} the results of the merge. +%\interaction{tour.merge.commit} + +$B%^!<%8$r9T$&$H!$%^!<%8$N7k2L$r(B\hgcmd{commit}$B$9$k$^$G!$(B\hgcmd{parents}$B$O(B2 +$B$D$N%Z%"%l%s%H$rI=<($9$k!%(B +\interaction{tour.merge.commit} + +%We now have a new tip revision; notice that it has \emph{both} of +%our former heads as its parents. These are the same revisions that +%were previously displayed by \hgcmd{parents}. +%\interaction{tour.merge.tip} + +$B?7$7$$(Btip$B%j%S%8%g%s$O0JA0$N%X%C%I(B\emph{$BN>J}(B}$B$r?F$H$7$F;}$D!%$3$l$i$O(B +\hgcmd{parents}$B%3%^%s%I$GI=<($7$?$N$HF1$8%j%S%8%g%s$G$"$k!%(B +\interaction{tour.merge.tip} + +%In figure~\ref{fig:tour-merge:merge}, you can see a representation of +%what happens to the working directory during the merge, and how this +%affects the repository when the commit happens. During the merge, the +%working directory has two parent changesets, and these become the +%parents of the new changeset. + +$B?^(B~\ref{fig:tour-merge:merge}$B$G!$%^!<%8$N4V$K%o!<%-%s%0%G%#%l%/%H%j$K2?$,(B +$B5/$-!$%3%_%C%H$7$?;~$K%j%]%8%H%j$K$I$&1F6A$9$k$N$+$r8+$k$3$H$,$G$-$k!%(B +$B%^!<%8$N4V!$%o!<%-%s%0%G%#%l%/%H%j$O(B2$B$D$N?F%A%'%s%8%;%C%H$r;}$A!$$3$l$i$O(B +$B?7$7$$%A%'%s%8%;%C%H$NN>?F$H$J$k!%(B + +%\section{Merging conflicting changes} +\section{$B%3%s%U%j%/%H$N$"$kJQ99$r%^!<%8$9$k(B} + +%Most merges are simple affairs, but sometimes you'll find yourself +%merging changes where each modifies the same portions of the same +%files. Unless both modifications are identical, this results in a +%\emph{conflict}, where you have to decide how to reconcile the +%different changes into something coherent. + +$BBgH>$N%^!<%8$O%7%s%W%k$J$b$N$@$,!$>l9g$K$h$C$F$OF1$8%U%!%$%k$NF1$82U=j$r(B +$BJQ99$7$F$$$k%A%'%s%8%;%C%H$r%^!<%8$7$J$1$l$P$J$i$J$$$3$H$,$"$k!%J#?t$NJQ(B +$B99$,F1$8FbMF$G$J$$8B$j!$7k2L$O(B\emph{conflict}$B$H$J$k$?$a!$Aj0[$J$kJQ99$r@0(B +$B9g$5$;$k$h$&$K=$@5$9$kI,MW$,$"$k!%(B + +\begin{figure}[ht] + \centering + \grafix{tour-merge-conflict} +% \caption{Conflicting changes to a document} + \caption{$B%3%s%U%j%/%H$7$?%A%'%s%8%;%C%H(B} + \label{fig:tour-merge:conflict} +\end{figure} + +%Figure~\ref{fig:tour-merge:conflict} illustrates an instance of two +%conflicting changes to a document. We started with a single version +%of the file; then we made some changes; while someone else made +%different changes to the same text. Our task in resolving the +%conflicting changes is to decide what the file should look like. + +1$B$D$N%I%-%e%a%s%H$KBP$7$F(B2$B$D$N%A%'%s%8%;%C%H$,%3%s%U%j%/%H$7$?MM;R$r(B +$B?^(B~\ref{fig:tour-merge:conflict}$B$K<($9!%(B + +$B$3$3$G$O!$$"$k(B1$B$D$N%P!<%8%g%s$N%U%!%$%k$K$$$/$D$+$NJQ99$r2C$(!$F1;~$KJL$N(B +$B?M$,JL$NJQ99$rF1$8%F%-%9%H$KBP$7$F2C$($F$$$k!%%A%'%s%8%;%C%H$N%3%s%U%j%/(B +$B%H$r2r7h$9$k$?$a!$%U%!%$%k$,$I$&$"$k$Y$-$+$rL@$i$+$K$7$h$&!%(B + +%Mercurial doesn't have a built-in facility for handling conflicts. +%Instead, it runs an external program called \command{hgmerge}. This +%is a shell script that is bundled with Mercurial; you can change it to +%behave however you please. What it does by default is try to find one +%of several different merging tools that are likely to be installed on +%your system. It first tries a few fully automatic merging tools; if +%these don't succeed (because the resolution process requires human +%guidance) or aren't present, the script tries a few different +%graphical merging tools. + +Mercurial$B$OFbB"$N%3%s%U%j%/%H2r7h5!9=$r;}$?$J$$!%$=$NBe$o(B +$B$j!$(B\command{hgmerge}$B$H$$$&30It%3%^%s%I$r5/F0$9$k!%$3$l$O(BMercurial$B$KF1:-(B +$B$5$l$?%7%'%k%9%/%j%W%H$G!$5sF0$rJQ99$9$k$3$H$b2DG=$G$"$k!%(B +$B%G%U%)%k%H$G$3$N%3%^%s%I$,9T$&$3$H$O!$%7%9%F%`$K%$%s%9%H!<%k$5$l$F$$$k2D(B +$BG=@-$N9b$$$$$/$D$+$N0[$J$C$?%^!<%8%D!<%k$N(B1$B$D$rA\$7=P$9$3$H$G$"$k!%(B +$B:G=i$K(B2,3$B$NA4<+F0$N%^!<%8%D!<%k$r;n$9!%$3$l$G$&$^$/$$$+$J$$>l9g!J2r7h%W(B +$B%m%;%9$K?M$N%,%$%I$,I,MW$J$?$a!K$d%D!<%k$,B8:_$7$J$$>l9g!$%9%/%j%W%H$O(B +$BJL$N(B2,3$B$N%0%i%U%#%+%k%^!<%8%D!<%k$r;n$9!%(B + +%It's also possible to get Mercurial to run another program or script +%instead of \command{hgmerge}, by setting the \envar{HGMERGE} +%environment variable to the name of your preferred program. + +$B4D6-JQ?t(B\envar{HGMERGE}$B$K9%$_$N%W%m%0%i%`L>$r$r@_Dj$9$k$3$H$G!$(BMercurial +$B$,(B\command{hgmerge}$B0J30$N%9%/%j%W%H$r5/F0$9$k$h$&$K$9$k$3$H$b2DG=$G$"$k!%(B + +%\subsection{Using a graphical merge tool} +\subsection{$B%0%i%U%#%+%k%^!<%8%D!<%k$N;HMQ(B} + +%My preferred graphical merge tool is \command{kdiff3}, which I'll use +%to describe the features that are common to graphical file merging +%tools. You can see a screenshot of \command{kdiff3} in action in +%figure~\ref{fig:tour-merge:kdiff3}. The kind of merge it is +%performing is called a \emph{three-way merge}, because there are three +%different versions of the file of interest to us. The tool thus +%splits the upper portion of the window into three panes: + +$BI.<T$N9%$_$N%0%i%U%#%+%k%^!<%8%D!<%k$O(B\command{kdiff3}$B$J$N$G!$$3$l$r;H$C(B +$B$F%0%i%U%#%+%k%U%!%$%k%^!<%8%D!<%k$N5!G=$r@bL@$9$k!%(B +$B?^(B~\ref{fig:tour-merge:kdiff3}$B$K(B\command{kdiff3}$B$N<B:]$NF0:n$N%9%/%j!<%s(B +$B%7%g%C%H$r<($9!%:#CmL\$7$F$$$k%U%!%$%k$K$O(B3$B$D$N0[$J$C$?%P!<%8%g%s$,$"$k$?(B +$B$a!$$3$3$G<B9T$5$l$F$$$k$N$O(B\emph{3way$B%^!<%8(B}$B$G$"$k!%%D!<%k$O%&%#%s%I%&$N(B +$B>eIt$r(B3$B$D$N%Z!<%s$KJ,3d$7$F$$$k!%(B + +\begin{itemize} +%\item At the left is the \emph{base} version of the file, i.e.~the +% most recent version from which the two versions we're trying to +% merge are descended. + \item $B:8$K$"$k$N$O%U%!%$%k$N(B\emph{$B%Y!<%9(B}$B%P!<%8%g%s$G$"$k!%$3$l$O$3$l$+(B + $B$i%^!<%8$7$h$&$H$9$k(B2$B$D$N%P!<%8%g%s$N?F$H$J$k:G$b:G6a$N%P!<%8%g%s(B + $B$G$"$k!%(B + +%\item In the middle is ``our'' version of the file, with the contents +% that we modified. + \item $BCf1{$K$"$k$N$O2f!9$,JQ99$r2C$($?%P!<%8%g%s$G$"$k!%(B + +%\item On the right is ``their'' version of the file, the one that +% from the changeset that we're trying to merge with. + \item $B1&$K$"$k$N$OB>$N?M$,JQ99$r2C$($?%P!<%8%g%s$G!$$3$l$+$i%^!<%8$7$h(B + $B$&$H$9$k$b$N$G$"$k!%(B +\end{itemize} + +%In the pane below these is the current \emph{result} of the merge. +%Our task is to replace all of the red text, which indicates unresolved +%conflicts, with some sensible merger of the ``ours'' and ``theirs'' +%versions of the file. + +$B$3$N2<$N%Z!<%s$K$O%^!<%8$N(B\emph{$B7k2L(B}$B$,$"$k!%@V;z$N9T$O%3%s%U%j%/%H$r<($7(B +$B$F$*$j!$2f!9$N%P!<%8%g%s$HB>$N?M$N%P!<%8%g%s$rCm0U?<$/%^!<%8$7$?7k2L$rMQ(B +$B$$$F$3$l$i$r$9$Y$FCV$-49$($k!%(B + +%All four of these panes are \emph{locked together}; if we scroll +%vertically or horizontally in any of them, the others are updated to +%display the corresponding sections of their respective files. + +4$B$D$N%Z!<%s$9$Y$F$O(B\emph{$BF14|(B}$B$7$F$*$j!"$I$l$+$r?bD>$^$?$O?eJ?$K%9%/%m!<(B +$B%k$9$k$H!"B>$N(B3$B$D$bBP1~$9$k2U=j$rI=<($9$k$h$&$K99?7$5$l$k!#(B + +\begin{figure}[ht] + \centering + \grafix{kdiff3} +% \caption{Using \command{kdiff3} to merge versions of a file} + \caption{$B%U%!%$%k$NJ#?t%j%S%8%g%s$r(B\command{kdiff3}$B$r;H$C$F%^!<%8$9$k(B} + \label{fig:tour-merge:kdiff3} +\end{figure} + +%For each conflicting portion of the file, we can choose to resolve +%the conflict using some combination of text from the base version, +%ours, or theirs. We can also manually edit the merged file at any +%time, in case we need to make further modifications. + +$B%3%s%U%j%/%H$r2r7h$9$k$?$a$K!$%U%!%$%kCf$N%3%s%U%j%/%H$7$F$$$k$9$Y$F$NIt(B +$BJ,$KBP$7$F%Y!<%9%P!<%8%g%s!$2f!9$N%P!<%8%g%s!$JL$N?M!9$N%P!<%8%g%s$N%F%-(B +$B%9%H$rAH$_9g$o$;$FMQ$$$k!%$5$i$J$k=$@5$,I,MW$J>l9g$O!$%^!<%8$5$l$?%U%!%$(B +$B%k$r<jF0$GJT=8$9$k$3$H$b$G$-$k!%(B + +%There are \emph{many} file merging tools available, too many to cover +%here. They vary in which platforms they are available for, and in +%their particular strengths and weaknesses. Most are tuned for merging +%files containing plain text, while a few are aimed at specialised file +%formats (generally XML). + +\emph{$B?t!9$N(B}$B%^!<%8%D!<%k$,MxMQ2DG=$G$"$j!$$=$l$i$r%+%P!<$9$k$3$H$O$G$-$J(B +$B$$!%$=$l$i$O!$MxMQ2DG=$J%W%i%C%H%U%)!<%`$,0[$J$j!$$=$l$>$lD9=j$H<eE@$,0[(B +$B$J$k!%$[$H$s$I$,%W%l!<%s%F%-%9%H$r%^!<%8$9$k$h$&$K:n$i$l$F$$$k$,!$FCJL$J(B +$B%U%!%$%k%U%)!<%^%C%H!J(BXML$B!K$KFC2=$7$F$$$k$b$N$b$"$k!%(B + +%\subsection{A worked example} +\subsection{$B<B9TNc(B} + +%In this example, we will reproduce the file modification history of +%figure~\ref{fig:tour-merge:conflict} above. Let's begin by creating a +%repository with a base version of our document. +%\interaction{tour-merge-conflict.wife} +%We'll clone the repository and make a change to the file. +%\interaction{tour-merge-conflict.cousin} +%And another clone, to simulate someone else making a change to the +%file. (This hints at the idea that it's not all that unusual to merge +%with yourself when you isolate tasks in separate repositories, and +%indeed to find and resolve conflicts while doing so.) +%\interaction{tour-merge-conflict.son} +%Having created two different versions of the file, we'll set up an +%environment suitable for running our merge. +%\interaction{tour-merge-conflict.pull} + +$B$3$NNc$G$OA0=R$N?^(B~\ref{fig:tour-merge:conflict}$B$G$NJQ99MzNr$r:F8=$9$k!%(B +$BJ8=q$N%Y!<%9%P!<%8%g%s$r4^$`%j%]%8%H%j$r:n@.$9$k$3$H$+$i;O$a$k!%(B +\interaction{tour-merge-conflict.wife} +$B%j%]%8%H%j$r%3%T!<$7!$%U%!%$%k$KJQ99$r9T$&!%(B +\interaction{tour-merge-conflict.cousin} +$BJL$N?M$,JQ99$r9T$&$N$r%7%_%e%l!<%H$9$k$?$a$K$b$&0l$D$N%/%m!<%s$r:n@.$9(B +$B$k!%!JJL!9$N%j%]%8%H%j$K3VN%$7$F9T$C$?:n6H$N7k2L$r%^!<%8$7!$%3%s%U%j%/%H(B +$B$r2r>C$9$k$3$H$O>/$7$bDA$7$$$3$H$G$O$J$$$H$$$&;v$,$o$+$k$@$m$&!%(B $B!K(B +\interaction{tour-merge-conflict.son} +$B%U%!%$%k$K(B2$B$D$NJL$N%P!<%8%g%s$r:n$j!$%^!<%8$r9T$&$N$KE*2<4D6-$r@_Dj$9$k!%(B +\interaction{tour-merge-conflict.pull} + +%In this example, I won't use Mercurial's normal \command{hgmerge} +%program to do the merge, because it would drop my nice automated +%example-running tool into a graphical user interface. Instead, I'll +%set \envar{HGMERGE} to tell Mercurial to use the non-interactive +%\command{merge} command. This is bundled with many Unix-like systems. +%If you're following this example on your computer, don't bother +%setting \envar{HGMERGE}. +%\interaction{tour-merge-conflict.merge} +%Because \command{merge} can't resolve the conflicting changes, it +%leaves \emph{merge markers} inside the file that has conflicts, +%indicating which lines have conflicts, and whether they came from our +%version of the file or theirs. + +$B$3$NNc$G$O%^!<%8$K(BMercurial$B$NDL>o%3%^%s%I$G$"$k(B\command{hgmerge}$B$O;H$o$J(B +$B$$!%$3$N%3%^%s%I$O<+F02=$5$l$?%0%i%U%#%+%k%f!<%6%$%s%?!<%U%'%$%9$N%^!<%8(B +$B%D!<%k$r5/F0$7$F$7$^$&$+$i$G$"$k!%$=$NBe$o$j(B\envar{HGMERGE}$B$r@_Dj$7(B +$B$F!$(BMercurial$B$KHsBPOCE*$J(B\command{merge}$B%3%^%s%I$r5/F0$5$;$k!%$3$l$OB?$/(B +$B$N(BUnix$B7O%7%9%F%`$K%P%s%I%k$5$l$F$$$k%3%^%s%I$G$"$k!%$3$NNc$r<j85$N%^%7%s(B +$B$G<B9T$9$k;~$K$O(B\envar{HGMERGE}$B$r@_Dj$9$kI,MW$O$J$$!%(B +\interaction{tour-merge-conflict.merge} \command{merge}$B%3%^%s%I$O%A%'%s%8(B +$B%;%C%H$N%3%s%U%j%/%H$r2r7h$9$k$3$H$O$G$-$:!$(B\emph{merge markers}$B$r%3%s%U(B +$B%j%/%H$N$"$k%U%!%$%kFb$K;D$7!$$I$N9T$K%3%s%U%j%/%H$,$"$k$N$+!$%3%s%U%j%/(B +$B%H$,<j85$NJQ99$HB>$N?M$NJQ99$N$$$:$l$+$iMh$F$$$k$N$+$r<($9!%(B + +%Mercurial can tell from the way \command{merge} exits that it wasn't +%able to merge successfully, so it tells us what commands we'll need to +%run if we want to redo the merging operation. This could be useful +%if, for example, we were running a graphical merge tool and quit +%because we were confused or realised we had made a mistake. + +Mercurial$B$O(B\command{merge}$B%3%^%s%I$G@5$7$/%^!<%8$G$-$J$+$C$?>l9g!$$b$&0l(B +$BEY%^!<%8$r9T$&$?$a$K$I$N$h$&$K$9$l$P$$$$$N$+$rI=<($9$k!%$3$l$O!$%0%i%U%#(B +$B%+%k%^!<%8%D!<%k$N;HMQCf$K:.Mp$rMh$7$?$+4V0c$$$rHH$7$?$3$H$K5$IU$$$?$?$a(B +$B$K=*N;$7$?>l9g$J$I$KM-8z$G$"$m$&!%(B + +%If automatic or manual merges fail, there's nothing to prevent us from +%``fixing up'' the affected files ourselves, and committing the results +%of our merge: +%\interaction{tour-merge-conflict.commit} + +$B<+F0$^$?$O<jF0$K$h$k%^!<%8$,<:GT$7$?>l9g!$1F6A$r<u$1$k%U%!%$%k$r(B``$B=$@5(B'' +$B$7$F%^!<%8$N7k2L$r%3%_%C%H$7$J$1$l$P$J$i$J$$!%(B +\interaction{tour-merge-conflict.commit} + + +%\section{Simplifying the pull-merge-commit sequence} +\section{pull-merge-commit$B<j=g$r4JC1$K$9$k(B} +\label{sec:tour-merge:fetch} + +%The process of merging changes as outlined above is straightforward, +%but requires running three commands in sequence. +$BA0@a$G35MW$r=R$Y$?%A%'%s%8%;%C%H$N%^!<%8%W%m%;%9$OC1=c$J$b$N$@$C$?$,!$(B3 +$B$D$N%3%^%s%I$r=g$KMQ$$$kI,MW$,$"$C$?!%(B + +\begin{codesample2} + hg pull + hg merge + hg commit -m 'Merged remote changes' +\end{codesample2} +%In the case of the final commit, you also need to enter a commit +%message, which is almost always going to be a piece of uninteresting +%``boilerplate'' text. +$B:G8e$N%3%_%C%H$G$O!$$[$H$s$IB`6~$J%\%$%i!<%W%l!<%H%F%-%9%H$H8@$C$F$b$h$$(B +$B%3%_%C%H%a%C%;!<%8$NF~NO$bI,MW$G$"$C$?!%(B + +%It would be nice to reduce the number of steps needed, if this were +%possible. Indeed, Mercurial is distributed with an extension called +%\hgext{fetch} that does just this. + +$B2DG=$G$"$l$PI,MW$J%9%F%C%W?t$r>/$J$/$9$k$3$H$,$G$-$k$H$h$$!%<B$O(B +Mercurial$B$O(B\hgext{fetch}$B$H$$$&!$$^$5$K$3$N$3$H$r9T$&%(%/%9%F%s%7%g%s$rF1(B +$B:-$7$F$$$k!%(B + +%Mercurial provides a flexible extension mechanism that lets people +%extend its functionality, while keeping the core of Mercurial small +%and easy to deal with. Some extensions add new commands that you can +%use from the command line, while others work ``behind the scenes,'' +%for example adding capabilities to the server. + +Mercurial$B$O%3%"$r>.$5$/!$07$$$d$9$/J]$C$?$^$^5!G=$r3HD%$G$-$k=@Fp$J%(%96e(B +$B%F%s%7%g%s%a%+%K%:%`$rDs6!$7$F$$$k!%%3%^%s%I%i%$%s$+$iMxMQ$G$-$k?7$7$$%3(B +$B%^%s%I$rDI2C$9$k$h$&$J%(%/%9%F%s%7%g%s$b$"$l$P!$L\$K8+$($J$$$H$3$m$GNc$((B +$B$P%5!<%P$K5!G=$rDI2C$9$k$h$&$J$b$N$b$"$k!%(B + +%The \hgext{fetch} extension adds a new command called, not +%surprisingly, \hgcmd{fetch}. This extension acts as a combination of +%\hgcmd{pull}, \hgcmd{update} and \hgcmd{merge}. It begins by pulling +%changes from another repository into the current repository. If it +%finds that the changes added a new head to the repository, it begins a +%merge, then commits the result of the merge with an +%automatically-generated commit message. If no new heads were added, +%it updates the working directory to the new tip changeset. + +\hgext{fetch}$B%(%/%9%F%s%7%g%s$O$=$NL>$NDL$j$N?7$7$$%3%^%s%I(B\hgcmd{fetch} +$B$rDI2C$9$k!%$3$N%(%/%9%F%s%7%g%s$O(B\hgcmd{pull}$B$H(B\hgcmd{update}$B$*$h$S(B +\hgcmd{merge}$B$rAH$_9g$o$;$?F/$-$r$9$k!%$3$N%(%/%9%F%s%7%g%s$O$^$:B>$N%j%](B +$B%8%H%j$+$iJQ99$r(Bpull$B$7!$%j%]%8%H%j$K?7$7$$%X%C%I$,DI2C$5$l$?>l9g$O%^!<%8(B +$B$r9T$$!$%^!<%87k2L$r<+F0E*$K@8@.$5$l$?%3%_%C%H%a%C%;!<%8$H6&$K%3%_%C%H$9(B +$B$k!%?7$?$J%X%C%I$,DI2C$5$l$J$+$C$?>l9g$O?7$?$J(Btip$B%A%'%s%8%;%C%H$X%o!<%-%s(B +$B%0%G%#%l%/%H%j$r99?7$9$k!%(B + +%Enabling the \hgext{fetch} extension is easy. Edit your +%\sfilename{.hgrc}, and either go to the \rcsection{extensions} section +%or create an \rcsection{extensions} section. Then add a line that +%simply reads ``\Verb+fetch +''. +$B4JC1$K(B\hgext{fetch}$B%(%/%9%F%s%7%g%s$rM-8z$K$9$k$3$H$,$G$-(B +$B$k!%(B\sfilename{.hgrc}$B%U%!%$%k$N(B\rcsection{extensions}$B%;%/%7%g%s$rJT=8!JB8(B +$B:_$7$J$1$l$PDI2C$9$k!K$7!$(B``\Verb+fetch +''$B$H$$$&9T$rDI2C$9$l$P$h$$!%(B +\begin{codesample2} + [extensions] + fetch = +\end{codesample2} +%(Normally, on the right-hand side of the ``\texttt{=}'' would appear +%the location of the extension, but since the \hgext{fetch} extension +%is in the standard distribution, Mercurial knows where to search for +%it.) +$B!JDL>o!$1&JU$N(B``\texttt{=}''$B$O%(%/%9%F%s%7%g%s$NCV$+$l$?>l=j$rI=$9(B +$B$,!$(B\hgext{fetch}$B%(%/%9%F%s%7%g%s$OI8=`G[I[J*$K4^$^$l$k$?$a!$(BMercurial$B$O(B +$B$=$N=j:_$r$9$G$KCN$C$F$$$k!%!K(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/undo-manual-merge.dot Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,8 @@ +digraph undo_manual { + "first change" -> "second change"; + "second change" -> "third change"; + backout [label="back out\nsecond change", shape=box]; + "second change" -> backout; + "third change" -> "manual\nmerge"; + backout -> "manual\nmerge"; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/undo-manual.dot Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,6 @@ +digraph undo_manual { + "first change" -> "second change"; + "second change" -> "third change"; + backout [label="back out\nsecond change", shape=box]; + "second change" -> backout; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/undo-non-tip.dot Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,9 @@ +digraph undo_non_tip { + "first change" -> "second change"; + "second change" -> "third change"; + backout [label="back out\nsecond change", shape=box]; + "second change" -> backout; + merge [label="automated\nmerge", shape=box]; + "third change" -> merge; + backout -> merge; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/undo-simple.dot Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,4 @@ +digraph undo_simple { + "first change" -> "second change"; + "second change" -> "back out\nsecond change"; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/undo.tex Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,1396 @@ +%\chapter{Finding and fixing your mistakes} +\chapter{$B%_%9$NH/8+$H=$@5(B} +\label{chap:undo} + +%To err might be human, but to really handle the consequences well +%takes a top-notch revision control system. In this chapter, we'll +%discuss some of the techniques you can use when you find that a +%problem has crept into your project. Mercurial has some highly +%capable features that will help you to isolate the sources of +%problems, and to handle them appropriately. + +$B%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$K$O?M$NHH$7$?4V0c$$$r$&$^$/=hM}$9$k5!G=$,(B +$B5a$a$i$l$F$$$k!%$3$N>O$G$O!$%W%m%8%'%/%H$K5/$3$jF@$kLdBj$N2r7h$KMxMQ2DG=(B +$B$J%F%/%K%C%/$K$D$$$F=R$Y$k!%(BMercurial$B$K$OLdBj$N$"$k%=!<%9$r@Z$jJ,$1!$=hM}(B +$B$9$k6/NO$J5!G=$,$"$k!%(B + + +%\section{Erasing local history} +\section{$B%m!<%+%k%R%9%H%j!<$r>C5n$9$k(B} + +%\subsection{The accidental commit} +\subsection{$B%"%/%7%G%s%H$K$h$k%3%_%C%H(B} + +%I have the occasional but persistent problem of typing rather more +%quickly than I can think, which sometimes results in me committing a +%changeset that is either incomplete or plain wrong. In my case, the +%usual kind of incomplete changeset is one in which I've created a new +%source file, but forgotten to \hgcmd{add} it. A ``plain wrong'' +%changeset is not as common, but no less annoying. + +$BI.<T$K$O%?%$%T%s%0Cf$K9M$($k$h$j$b@h$K;X$,F0$$$F$7$^$&JJ$,0JA0$+$i$"$j!$(B +$B$?$^$K$3$l$,5/$-$k$H!$IT40A4$@$C$?$j4V0c$C$?FbMF$N%A%'%s%8%;%C%H$r%3%_%C(B +$B%H$7$F$7$^$&!%I.<T$N>l9g!$IT40A4$J%A%'%s%8%;%C%H$NE57?$O?7$7$$%=!<%9%U%!(B +$B%$%k$r:n@.$7$?$N$K(B\hgcmd{add}$B$rK:$l$k$3$H$G!$(B``$B4V0c$C$?FbMF(B''$B$N%3%_%C%H(B +$B$O$"$^$j5/$-$J$$$,!$$d$O$jF1$8$h$&$KLq2p$G$"$k!%(B + + +%\subsection{Rolling back a transaction} +\subsection{$B%H%i%s%6%/%7%g%s$N%m!<%k%P%C%/(B} +\label{sec:undo:rollback} + +%In section~\ref{sec:concepts:txn}, I mentioned that Mercurial treats +%each modification of a repository as a \emph{transaction}. Every time +%you commit a changeset or pull changes from another repository, +%Mercurial remembers what you did. You can undo, or \emph{roll back}, +%exactly one of these actions using the \hgcmd{rollback} command. (See +%section~\ref{sec:undo:rollback-after-push} for an important caveat +%about the use of this command.) + +\ref{sec:concepts:txn}$B@a$G!$(BMercurial$B$O%j%]%8%H%j$X$N8D!9$NJQ99$r(B\emph{$B%H(B +$B%i%s%6%/%7%g%s(B}$B$H$7$F07$&$H$$$&$3$H$r=R$Y$?!%(BMercurial$B$O!$JL$N%j%]%8%H%j(B +$B$X$N%A%'%s%8%;%C%H$N%3%_%C%H$dJQ99$N(Bpull$B$r5-21$7$F$$$k!%%f!<%6$O(Bundo$B$7$?(B +$B$j!$0l2s$K8B$j%"%/%7%g%s$r(B\hgcmd{rollback}$B%3%^%s%I$G(B\emph{$B%m!<%k%P%C%/(B}$B$9(B +$B$k$3$H$,$G$-$k!%(B($B$3$N%3%^%s%I$N=EMW$J@)Ls$K$D$$$F$O(B +\ref{sec:undo:rollback-after-push}$B$r;2>H$N$3$H!%(B) + + +%Here's a mistake that I often find myself making: committing a change +%in which I've created a new file, but forgotten to \hgcmd{add} it. +%\interaction{rollback.commit} +%Looking at the output of \hgcmd{status} after the commit immediately +%confirms the error. +%\interaction{rollback.status} +%The commit captured the changes to the file \filename{a}, but not the +%new file \filename{b}. If I were to push this changeset to a +%repository that I shared with a colleague, the chances are high that +%something in \filename{a} would refer to \filename{b}, which would not +%be present in their repository when they pulled my changes. I would +%thus become the object of some indignation. + +$BI.<T$,NI$/5/$3$9%_%9$O!$?7$7$$%U%!%$%k$r:n@.$7$?%A%'%s%8%;%C%H$r%3%_%C%H(B +$B$9$k;~$K(B\hgcmd{add}$B$N<B9T$rK:$l$k$b$N$G$"$k!%(B +\interaction{rollback.commit} +$B%3%_%C%H8e$N(B\hgcmd{status}$B$N=PNO$r8+$k$H!$D>$A$K%(%i!<$rI=<($7$F$$$k$3$H(B +$B$,$o$+$k!%(B +\interaction{rollback.status} +$B%3%_%C%H$O(B\filename{a}$B$X$NJQ99$r4^$s$G$$$k$,!$(B\filename{b}$B$X$NJQ99$O4^$s(B +$B$G$$$J$$!%$3$3$G;d$,F1N=$H6&M-$7$F$$$k%j%]%8%H%j$X%A%'%s%8%;%C%H$N%W%C%7%e(B +$B$r9T$J$C$?$H$7$?$i!$H`$i$,JQ99$r%W%k$7$?;~!$(B\filename{a}$B$NCf$N2?$+$,H`$i(B +$B$N%j%]%8%H%j$K4^$^$l$J$$(B\filename{b}$B$X$N;2>H$r9T$J$&2DG=@-$O9b$$!%$=$&$J$C(B +$B$?$iI.<T$OF1N=$NE\$j$rGc$&$3$H$K$J$k$@$m$&!%(B + +%However, luck is with me---I've caught my error before I pushed the +%changeset. I use the \hgcmd{rollback} command, and Mercurial makes +%that last changeset vanish. +%\interaction{rollback.rollback} +%Notice that the changeset is no longer present in the repository's +%history, and the working directory once again thinks that the file +%\filename{a} is modified.The commit and rollback have left the +%working directory exactly as it was prior to the commit; the changeset +%has been completely erased. I can now safely \hgcmd{add} the file +%\filename{b}, and rerun my commit. +%\interaction{rollback.add} + +$B$7$+$79%1?$K$b%A%'%s%8%;%C%H$r%W%C%7%e$9$kA0$K%(%i!<$K5$$E$$$?>l9g!$(B +\hgcmd{rollback}$B%3%^%s%I$r;HMQ$9$k$3$H$G(BMercurial$B$+$i:G8e$N99?7$r<h$j=|(B +$B$/$3$H$,$G$-$k!%(B +\interaction{rollback.rollback} +$B%A%'%s%8%;%C%H$O$j$]$8$H$j$NMzNr$K$b$O$dB8:_$;$:!$%o!<%-%s%0%G%#%l%/%H%j(B +$B$N(B\filename{a}$B$OJQ99$5$l$?$HG'<1$5$l$k!%%3%_%C%H$7$F%m!<%k%P%C%/$9$k$H!$(B +$B%o!<%-%s%0%G%#%l%/%H%j$O40A4$K%3%_%C%HA0$N>uBV$K$J$j!$%A%'%s%8%;%C%H$O40(B +$BA4$K>C5n$5$l$k!%$3$N>uBV$G0BA4$K(B\hgcmd{add} \filename{b}$B$7!$$b$&0lEY(B +commit$B$9$k$3$H$,$G$-$k!%(B +\interaction{rollback.rollback} + +%\subsection{The erroneous pull} +\subsection{$B8m$C$?%W%k(B} + +%It's common practice with Mercurial to maintain separate development +%branches of a project in different repositories. Your development +%team might have one shared repository for your project's ``0.9'' +%release, and another, containing different changes, for the ``1.0'' +%release. + +Mercurial$B$r;H$C$FJL!9$N3+H/%V%i%s%A$rJL!9$N%j%]%8%H%j$G4IM}$9$k$3$H$,$h$/(B +$B$"$k!%$"$J$?$N3+H/%A!<%`$O%W%m%8%'%/%H$N%j%j!<%9(B0.9$B$N$?$a$K(B1$B$D$N6&M-%j%](B +$B%8%H%j$r;}$A!$%j%j!<%9(B1.0$B$N$?$a$K0[$J$kJQ99$r;}$C$?$b$&0l$DJL$N%j%]%8%H(B +$B%j$r$b$C$F$$$k!%(B + +%Given this, you can imagine that the consequences could be messy if +%you had a local ``0.9'' repository, and accidentally pulled changes +%from the shared ``1.0'' repository into it. At worst, you could be +%paying insufficient attention, and push those changes into the shared +%``0.9'' tree, confusing your entire team (but don't worry, we'll +%return to this horror scenario later). However, it's more likely that +%you'll notice immediately, because Mercurial will display the URL it's +%pulling from, or you will see it pull a suspiciously large number of +%changes into the repository. + +$B$3$3$G$"$J$?$O8m$C$F%m!<%+%k$N(B0.9$B%j%]%8%H%j$K6&M-(B1.0$B%j%]%8%H%j$+$i%W%k$7(B +$B$?$H$9$k!%:G0-$N>l9g!$==J,Cm0U$;$:!$$3$l$r6&M-$N(B0.9$B%j%]%8%H%j$K=q$-La$7$F(B +$B$7$^$$!$3+H/%A!<%`A4BN$r:.Mp$5$;$F$7$^$&$3$H$,M-$jF@$k!%!J$3$N>l9g$I$&$9(B +$B$l$P$$$$$N$+$K$D$$$F$O8e=R$9$k!%!K$7$+$7(BMercurial$B$O%W%k85$N(BURL$B$H5?$$$r;}(B +$B$D$K==J,$J5pBg$JJQ99$rI=<($9$k$?$a!$B(:B$K5$$E$/2DG=@-$,9b$$!%(B + +%The \hgcmd{rollback} command will work nicely to expunge all of the +%changesets that you just pulled. Mercurial groups all changes from +%one \hgcmd{pull} into a single transaction, so one \hgcmd{rollback} is +%all you need to undo this mistake. + +\hgcmd{rollback}$B%3%^%s%I$r<B9T$9$l$P!$:#%W%k$7$?$P$+$j$N%A%'%s%8%;%C%H$r(B +$BA4$F>C5n$9$k$3$H$,$G$-$k!%(BMercurial$B$O0l2s(B\hgcmd{pull}$B$K$h$k%H%i%s%6%/%7%g(B +$B%s$G$b$?$i$5$l$?A4$F$N%A%'%s%8%;%C%H$r%0%k!<%W2=$7$F$$$k$N$G!$(B +\hgcmd{rollback}$B$r0lEY<B9T$9$k$@$1$G!$%_%9$rA4$F$d$jD>$9$3$H$,$G$-$k!%(B + + +%\subsection{Rolling back is useless once you've pushed} +\subsection{$B0lEY%W%C%7%e$7$?8e$G$O%m!<%k%P%C%/$G$-$J$$(B} +\label{sec:undo:rollback-after-push} + +%The value of the \hgcmd{rollback} command drops to zero once you've +%pushed your changes to another repository. Rolling back a change +%makes it disappear entirely, but \emph{only} in the repository in +%which you perform the \hgcmd{rollback}. Because a rollback eliminates +%history, there's no way for the disappearance of a change to propagate +%between repositories. + +$BB>$N%j%]%8%H%j$KJQ99$r%W%C%7%e$7$?8e$G$O(B\hgcmd{rollback}$B$N2ACM$O%<%m$G$"(B +$B$k!%JQ99$r%m!<%k%P%C%/$9$k$3$H$K$h$C$FJQ99$O40A4$K>CLG$9$k$,!$$=$l$O$"$J(B +$B$?$,(B\hgcmd{rollback}$B$r<B9T$7$?%j%]%8%H%j$K8B$C$F$N$3$H$G$"$k!%%m!<%k%P%C(B +$B%/$K$h$C$F!JJQ99$N!KMzNr<+BN$,$J$+$C$?$3$H$K$J$k$N$G!$JQ99$N>CLG$rB>$N%j(B +$B%]%8%H%j$KGH5Z$5$;$k<jCJ$O$J$$!%(B + +%If you've pushed a change to another repository---particularly if it's a +%shared repository---it has essentially ``escaped into the wild,'' and +%you'll have to recover from your mistake in a different way. What will +%happen if you push a changeset somewhere, then roll it back, then pull +%from the repository you pushed to, is that the changeset will reappear +%in your repository. + +$B$b$7$"$J$?$,B>$N%j%]%8%H%j!JFC$K6&M-%j%]%8%H%j!K$KJQ99$r%W%C%7%e$7$F$$$k(B +$B$N$J$i!$:$$C$?;vBV$,5/$3$C$F$*$j!$JL$NJ}K!$G%_%9$+$iI|5l$9$kI,MW$,$"$k!%(B +$B%A%'%s%8%;%C%H$r$I$3$+$X%W%C%7%e$7$?8e$G%m!<%k%P%C%/$7!$%W%C%7%e@h$N%j%](B +$B%8%H%j$+$i:F$S%W%k$7$?>l9g!$%A%'%s%8%;%C%H$,%m!<%+%k%j%]%8%H%j$K:F$S8=$l(B +$B$k!%(B + +%(If you absolutely know for sure that the change you want to roll back +%is the most recent change in the repository that you pushed to, +%\emph{and} you know that nobody else could have pulled it from that +%repository, you can roll back the changeset there, too, but you really +%should really not rely on this working reliably. If you do this, +%sooner or later a change really will make it into a repository that +%you don't directly control (or have forgotten about), and come back to +%bite you.) + +$B!J$b$7%m!<%k%P%C%/$7$?$$%A%'%s%8%;%C%H$,%W%C%7%e@h$N%j%]%8%H%j$G:G?7$G$"(B +$B$j!$$+$D!$C/$b$=$l$r%W%k$7$F$$$J$$$3$H$,3N<B$G$"$k>l9g$O!$%W%C%7%e@h$N%j(B +$B%]%8%H%j$G%m!<%k%P%C%/$9$k$3$H$,2DG=$@$,!$$3$NJ}K!$O3N<B$G$O$J$$$H$$$&$3(B +$B$H$r4N$KL?$8$F$*$/$Y$-$G$"$k!%$3$NJ}K!$OD>@\%3%s%H%m!<%k$G$-$J$+$C$?$j!$(B +$B$=$NJ}K!$rK:$l$F$7$^$C$?%j%]%8%H%j$X$NJQ99$N=$@5$K$O;H$($J$$!%!K(B + + +%\subsection{You can only roll back once} +\subsection{$B%m!<%k%P%C%/$O0l2s$N$_(B} + +%Mercurial stores exactly one transaction in its transaction log; that +%transaction is the most recent one that occurred in the repository. +%This means that you can only roll back one transaction. If you expect +%to be able to roll back one transaction, then its predecessor, this is +%not the behaviour you will get. +%\interaction{rollback.twice} +%Once you've rolled back one transaction in a repository, you can't +%roll back again in that repository until you perform another commit or +%pull. + +Mercurial$B$O%H%i%s%6%/%7%g%s%m%0$K$=$N%j%]%8%H%j$K5/$3$C$?:G$b?7$7$$%H%i%s(B +$B%6%/%7%g%s0l2sJ,$N$_$r5-O?$7$F$$$k!%%m!<%k%P%C%/0l2sKh$K0l$DA0$N%j%S%8%g(B +$B%s$KLa$k$o$1$G$O$J$$!%(B +\interaction{rollback.twice} +$B%j%]%8%H%j$J$$$G0lEY%m!<%k%P%C%/$7$?$i!$JL$N%3%_%C%H$r$9$k$+%W%k$r$9$k$^(B +$B$G%m!<%k%P%C%/$O$G$-$J$$!%(B + + +%\section{Reverting the mistaken change} +\section{$B4V0c$C$?JQ99$r85$KLa$9(B} + +%If you make a modification to a file, and decide that you really +%didn't want to change the file at all, and you haven't yet committed +%your changes, the \hgcmd{revert} command is the one you'll need. It +%looks at the changeset that's the parent of the working directory, and +%restores the contents of the file to their state as of that changeset. +%(That's a long-winded way of saying that, in the normal case, it +%undoes your modifications.) + +$B%U%!%$%k$KJQ99$r2C$($?8e$G!$JQ99$,I,MW$G$J$$$HJ,$+$j!$$^$@%3%_%C%H$5$l$F(B +$B$$$J$$;~$O(B\hgcmd{revert}$B%3%^%s%I$r;H$&$3$H$,$G$-$k!%$3$N%3%^%s%I$O%o!<%-(B +$B%s%0%G%#%l%/%H%j$N?F%A%'%s%8%;%C%H$r;2>H$7!$%U%!%$%k$NFbMF$r%A%'%s%8%;%C(B +$B%H$N>uBV$KLa$9!%!J$3$l$O$"$J$?$,2C$($?JQ99$r$/$I$/$I$7$/=R$Y$?$b$N$G$"(B +$B$k!%!K(B + +%Let's illustrate how the \hgcmd{revert} command works with yet another +%small example. We'll begin by modifying a file that Mercurial is +%already tracking. +%\interaction{daily.revert.modify} +%If we don't want that change, we can simply \hgcmd{revert} the file. +%\interaction{daily.revert.unmodify} +%The \hgcmd{revert} command provides us with an extra degree of safety +%by saving our modified file with a \filename{.orig} extension. +%\interaction{daily.revert.status} + +\hgcmd{revert}$B%3%^%s%I$,$I$N$h$&$KF0:n$9$k$+!$JL$N>.$5$JNc$G@bL@$9$k!%(B +$B$9$G$K(BMercurial$B$,4IM}$7$F$$$k%U%!%$%k$rJQ99$7$?$H$3$m$+$i;O$a$k!%(B +\interaction{daily.revert.modify} +$B$3$NJQ99$,I,MW$G$J$$>l9g!$C1$K%U%!%$%k$K(B\hgcmd{revert}$B$r<B9T$9$l$P$h$$!%(B +\interaction{daily.revert.unmodify} +\hgcmd{revert}$B%3%^%s%I$O0BA4$N$?$a(B\filename{.orig}$B$H$$$&%U%!%$%kL>$GJQ99(B +$B$r%;!<%V$9$k!%(B +\interaction{daily.revert.status} + +%Here is a summary of the cases that the \hgcmd{revert} command can +%deal with. We will describe each of these in more detail in the +%section that follows. +%\begin{itemize} +%\item If you modify a file, it will restore the file to its unmodified +% state. +%\item If you \hgcmd{add} a file, it will undo the ``added'' state of +% the file, but leave the file itself untouched. +%\item If you delete a file without telling Mercurial, it will restore +% the file to its unmodified contents. +%\item If you use the \hgcmd{remove} command to remove a file, it will +% undo the ``removed'' state of the file, and restore the file to its +% unmodified contents. +%\end{itemize} + +\hgcmd{revert}$B%3%^%s%I$,07$($k%1!<%9$K$D$$$F$^$H$a$k!%$h$j>\$7$$@bL@$O!$(B +$B8e$N@a$G9T$J$&!%(B + +\begin{itemize} +\item $B%U%!%$%k$rJQ99$7$?>l9g!$(B\hgcmd{revert}$B$O%U%!%$%k$rJQ99$5$l$kA0$N>u(B + $BBV$KLa$9!%(B + +\item \hgcmd{add}$B$r<B9T$7$?>l9g!$(B\hgcmd{revert}$B$O(Badd$B$r<h$j>C$9$,!$%U%!%$(B + $B%k<+BN$O$=$N$^$^<j$r?($l$:$K;D$9!%(B +\item Mercurial$B$rA`:n$;$:$K%U%!%$%k$r>C5n$7$F$$$?>l9g!$(B\hgcmd{revert}$B$O(B + $B%U%!%$%k$rJQ99A0$N>uBV$GI|85$9$k(B +\item \hgcmd{remove}$B%3%^%s%I$G%U%!%$%k$r>C5n$7$F$$$?>l9g!$JQ99A0$N>uBV$G(B + $B%U%!%$%k$rI|85$9$k!%(B +\end{itemize} + + +%\subsection{File management errors} +\subsection{$B%U%!%$%k4IM}$N%_%9(B} +\label{sec:undo:mgmt} + +%The \hgcmd{revert} command is useful for more than just modified +%files. It lets you reverse the results of all of Mercurial's file +%management commands---\hgcmd{add}, \hgcmd{remove}, and so on. + +\hgcmd{revert}$B%3%^%s%I$OC1$KJQ99$7$?%U%!%$%k$rLa$9$@$1$G$J$/!$(B +\hgcmd{add}$B!$(B\hgcmd{remove}$B$H$$$C$?(BMercurial$B$N%U%!%$%kA`:n%3%^%s%I$N7k2L(B +$B$r<h$j>C$9$3$H$,$G$-$k!%(B + +%If you \hgcmd{add} a file, then decide that in fact you don't want +%Mercurial to track it, use \hgcmd{revert} to undo the add. Don't +%worry; Mercurial will not modify the file in any way. It will just +%``unmark'' the file. +%\interaction{daily.revert.add} + +\hgcmd{add}$B$G%U%!%$%k$rDI2C$7$?8e$G!$(BMercurial$B$KDI@W$5$;$kI,MW$,$J$$$HJ,(B +$B$+$C$?;~!$(B\hgcmd{revert}$B$G(Badd$B$r<h$j>C$9$3$H$,$G$-$k!%(B\hgcmd{revert}$B$O%U%!(B +$B%$%k$N%^!<%/$r>C$9$@$1$G!$%U%!%$%k$NCf?H$O0l@ZJQ99$7$J$$$N$G?4G[$9$kI,MW(B +$B$O$J$$!%(B +\interaction{daily.revert.add} + +%Similarly, if you ask Mercurial to \hgcmd{remove} a file, you can use +%\hgcmd{revert} to restore it to the contents it had as of the parent +%of the working directory. +%\interaction{daily.revert.remove} +%This works just as well for a file that you deleted by hand, without +%telling Mercurial (recall that in Mercurial terminology, this kind of +%file is called ``missing''). +%\interaction{daily.revert.missing} + +$BF1MM$K!$(B\hgcmd{remove}$B%3%^%s%I$G%U%!%$%k$r>C5n$7$?;~!$(B\hgcmd{revert}$B%3%^(B +$B%s%I$G%o!<%-%s%0%G%#%l%/%H%j$N?F$NFbMF$K%U%!%$%k$rI|85$9$k$3$H$,$G$-$k!%(B +\interaction{daily.revert.remove} +$B$^$?(BMercurial$B$r;H$o$:$K<j$G>C$7$?%U%!%$%k$K$D$$$FF1$8A`:n$GI|85$9$k$3$H(B +$B$,$G$-$k!%!J(BMercurial$B$NMQ8l$G$3$l$r(Bmissing$B$H8F$s$G$$$?$3$H$r;W$$=P$7$FM_(B +$B$7$$!%!K(B +\interaction{daily.revert.missing} + +%If you revert a \hgcmd{copy}, the copied-to file remains in your +%working directory afterwards, untracked. Since a copy doesn't affect +%the copied-from file in any way, Mercurial doesn't do anything with +%the copied-from file. +%\interaction{daily.revert.copy} + +\hgcmd{copy}$B%3%^%s%I$r<h$j>C$7$?>l9g!$%3%T!<@h$N%U%!%$%k$O%o!<%-%s%0%G%#(B +$B%l%/%H%j$K;D$k$,(BMercurial$B$+$i$O4IM}$5$l$J$$!%%3%T!<A`:n<+BN%3%T!<85%U%!%$(B +$B%k$K1F6A$rM?$($J$$$?$a!$<h$j>C$7$K$h$C$F%3%T!<85%U%!%$%k$,1F6A$r<u$1$k$3(B +$B$H$b$J$$!%(B + + +%\subsubsection{A slightly special case: reverting a rename} +\subsubsection{$B$d$dFC<l$J%1!<%9!'%j%M!<%`$N<h$j>C$7(B} + +%If you \hgcmd{rename} a file, there is one small detail that +%you should remember. When you \hgcmd{revert} a rename, it's not +%enough to provide the name of the renamed-to file, as you can see +%here. +%As you can see from the output of \hgcmd{status}, the renamed-to file +%is no longer identified as added, but the renamed-\emph{from} file is +%still removed! This is counter-intuitive (at least to me), but at +%least it's easy to deal with. +%So remember, to revert a \hgcmd{rename}, you must provide \emph{both} +%the source and destination names. + +\hgcmd{rename}$B$7$?8e$G$O!$>/$7N10U$7$F$*$/$Y$-E@$,$"$k!%%j%M!<%`8e$K(B +\hgcmd{revert}$B$7$?>l9g!$$3$3$G@bL@$9$k$h$&$K!$%j%M!<%`$7$?%U%!%$%k$NL>A0(B +$B$r;XDj$9$k$@$1$G$OIT==J,$G$"$k!%(B +\interaction{daily.revert.rename} +\hgcmd{status}$B$N=PNO$+$iJ,$+$k$h$&$K!$%j%M!<%`@h$N%U%!%$%k$O$b$O$d(Badd$B$5(B +$B$l$?07$$$K$J$C$F$$$J$$!%$7$+$7%j%M!<%`(B\emph{$B85(B}$B$N%U%!%$%k$O$^$@>C5n$5$l(B +$B$?$^$^$K$J$C$F$$$k!%$3$l$O!J>/$J$/$H$bI.<T$K$H$C$F!KHsD>46E*$@$,!$<h$j07(B +$B$$$O4JC1$G$"$k!%(B +\interaction{daily.revert.rename-orig} +\hgcmd{rename}$B$r<h$j>C$9:]$K$O!$85$N%U%!%$%k$H%j%M!<%`8e$N%U%!%$%k(B +\emph{$BN>J}(B}$B$r;XDj$9$kI,MW$,$"$k!%(B + +%(By the way, if you rename a file, then modify the renamed-to file, +%then revert both components of the rename, when Mercurial restores the +%file that was removed as part of the rename, it will be unmodified. +%If you need the modifications in the renamed-to file to show up in the +%renamed-from file, don't forget to copy them over.) + +$B!J0lJ}!$%j%M!<%`$7$?8e$K%j%M!<%`@h$N%U%!%$%k$rJT=8$7!$%j%M!<%`$NA08e$N%U%!(B +$B%$%kL>$r;XDj$7$F<h$j>C$7$r9T$J$$!$(BMercurial$B$,%j%M!<%`$N:]$K>C5n$5$l$?%U%!(B +$B%$%k$r=$I|$9$k$H!$$3$N%U%!%$%k$OJT=8A0$N>uBV$K$J$C$F$$$k!%%j%M!<%`8e$N%U%!(B +$B%$%k$X$NJQ99$,%j%M!<%`A0$N%U%!%$%k$K;D$k$h$&$K$9$k$K$O!$%3%T!<$r:n$C$F$*(B +$B$/I,MW$,$"$k!%!K(B + +%These fiddly aspects of reverting a rename arguably constitute a small +%bug in Mercurial. + +$B%j%M!<%`$rI|85$9$k;~$K5/$3$kLq2p$4$H$O$*$=$i$/(BMercurial$B$N%P%0$H8@$($k$+(B +$B$b$7$l$J$$!%(B + + +%\section{Dealing with committed changes} +\section{$B%3%_%C%H$5$l$?JQ99$N07$$(B} + +%Consider a case where you have committed a change $a$, and another +%change $b$ on top of it; you then realise that change $a$ was +%incorrect. Mercurial lets you ``back out'' an entire changeset +%automatically, and building blocks that let you reverse part of a +%changeset by hand. + +$a$$B$r%3%_%C%H$7$?8e$GJL$N(B$b$$B$r%3%_%C%H$7!$$3$3$G(B$a$$B$O8m$j$G$"$k$3$H$K5$$E(B +$B$/$$$?>l9g$r9M$($k!%(BMercurial$B$O%A%'%s%8%;%C%HA4BN$H%A%'%s%8%;%C%H$N0lItJ,(B +$B$r<j$G%P%C%/%"%&%H$9$k$h$&$KB%$9!%(B + +%Before you read this section, here's something to keep in mind: the +%\hgcmd{backout} command undoes changes by \emph{adding} history, not +%by modifying or erasing it. It's the right tool to use if you're +%fixing bugs, but not if you're trying to undo some change that has +%catastrophic consequences. To deal with those, see +%section~\ref{sec:undo:aaaiiieee}. + +$B$3$N@a$rFI$`A0$K!$(B\hgcmd{backout}$B%3%^%s%I$OMzNr$K(B\emph{$BDI2C(B}$B$9$k$3$H$G<h(B +$B$j>C$7A`:n$r9T$J$&$3$H$r3P$($F$*$$$FM_$7$$!%JQ99$d>C5n$G$O$J$$!%%P%0$N=$(B +$B@5$N$?$a$KLrN)$D%D!<%k$@$,!$JQ99$N<h$j>C$7$N$?$a$KMQ$$$k$HGKLGE*$J7k2L$r(B +$B$b$?$i$9!%8e<T$NL\E*$N$?$a$K$O(B\ref{sec:undo:aaaiiieee}$B$r;2>H$N$3$H!%(B + +%\subsection{Backing out a changeset} +\subsection{$B%A%'%s%8%;%C%H$N%P%C%/%"%&%H(B} + +%The \hgcmd{backout} command lets you ``undo'' the effects of an entire +%changeset in an automated fashion. Because Mercurial's history is +%immutable, this command \emph{does not} get rid of the changeset you +%want to undo. Instead, it creates a new changeset that +%\emph{reverses} the effect of the to-be-undone changeset. + +\hgcmd{backout}$B%3%^%s%I$O%A%'%s%8%;%C%HA4BN$N:nMQ$rBG$A>C$9!%(BMercurial$B$N(B +$BMzNr$OITJQ$J$N$G!$$3$N%3%^%s%I$O<h$j>C$7$?$$%A%'%s%8%;%C%H$r<h$j=|$/$b$N(B +$B$G$O(B\emph{$B$J$$(B}$B!%$=$NBe$o$j!$<h$j=|$-$?$$%A%'%s%8%;%C%H$N(B\emph{$B5U(B}$B$NF/$-(B +$B$N?7$?$J%A%'%s%8%;%C%H$r$r@8@.$9$k!%(B + +%The operation of the \hgcmd{backout} command is a little intricate, so +%let's illustrate it with some examples. First, we'll create a +%repository with some simple changes. +%\interaction{backout.init} + +\hgcmd{backout}$B%3%^%s%I$NF0:n$O$d$dJ#;($J$N$G!$Nc$r5s$2$F@bL@$9$k$3$H$K(B +$B$9$k!%$^$:$$$/$D$+$NC1=c$JJQ99$N$"$k%j%]%8%H%j$r9M$($k!%(B +\interaction{backout.init} + +%The \hgcmd{backout} command takes a single changeset ID as its +%argument; this is the changeset to back out. Normally, +%\hgcmd{backout} will drop you into a text editor to write a commit +%message, so you can record why you're backing the change out. In this +%example, we provide a commit message on the command line using the +%\hgopt{backout}{-m} option. + +\hgcmd{backout}$B%3%^%s%I$O%P%C%/%"%&%H$9$Y$-%A%'%s%8%;%C%H$N(BID$B$r0l$D0z?t$K(B +$B<h$k!%(B\hgcmd{backout}$B$O%G%U%)%k%H$G%3%_%C%H%a%C%;!<%8F~NO$N$?$a$K%F%-%9%H(B +$B%(%G%#%?$r5/F0$9$k$N$G!%%P%C%/%"%&%H$NM}M3$r5-O?$7$F$*$/!%$3$NNc$G$O(B +\hgopt{backout}{-m}$B%*%W%7%g%s$r;H$C$F%3%_%C%H%a%C%;!<%8$r5-O?$7$F$$$k!%(B + + +%\subsection{Backing out the tip changeset} +\subsection{tip$B%A%'%s%8%;%C%H$r%P%C%/%"%&%H$9$k(B} + +%We're going to start by backing out the last changeset we committed. +%\interaction{backout.simple} +%You can see that the second line from \filename{myfile} is no longer +%present. Taking a look at the output of \hgcmd{log} gives us an idea +%of what the \hgcmd{backout} command has done. +%\interaction{backout.simple.log} +%Notice that the new changeset that \hgcmd{backout} has created is a +%child of the changeset we backed out. It's easier to see this in +%figure~\ref{fig:undo:backout}, which presents a graphical view of the +%change history. As you can see, the history is nice and linear. + +$B:G8e$K%3%_%C%H$7$?%A%'%s%8%;%C%H$r%P%C%/%"%&%H$9$k$3$H$+$i;O$a$k!%(B +\interaction{backout.simple} +\filename{myfile}$B$N(B2$B9TL\$,$J$/$J$C$F$$$k$N$,J,$+$k$H;W$&!%(B\hgcmd{log}$B$r(B +$B8+$F$_$k$H!$(B\hgcmd{backout}$B$,2?$r$7$?$N$+$,J,$+$k!%(B +\interaction{backout.simple.log} +\hgcmd{backout}$B$,@8@.$7$??7$7$$%A%'%s%8%;%C%H$O!$%P%C%/%"%&%H$7$?%A%'%s(B +$B%8%;%C%H$N;R$K$J$C$F$$$k!%(B\ref{fig:undo:backout}$B$O99?7MzNr$r?^<($7$?$b$N(B +$B$G!$M}2r$N=u$1$K$J$k$O$:$@!%?^$+$iJ,$+$k$h$&$KMzNr$O@~7A$G@09g$,<h$l$F$$$k!%(B + +\begin{figure}[htb] + \centering + \grafix{undo-simple} +% \caption{Backing out a change using the \hgcmd{backout} command} + \caption{\hgcmd{backout}$B%3%^%s%I$r;H$C$F99?7$r%P%C%/%"%&%H(B} + \label{fig:undo:backout} +\end{figure} + +%\subsection{Backing out a non-tip change} +\subsection{tip$B$G$J$$JQ99$r%P%C%/%"%&%H$9$k(B} + +%If you want to back out a change other than the last one you +%committed, pass the \hgopt{backout}{--merge} option to the +%\hgcmd{backout} command. +%\interaction{backout.non-tip.clone} +%This makes backing out any changeset a ``one-shot'' operation that's +%usually simple and fast. +%\interaction{backout.non-tip.backout} + +$B:G8e$N%3%_%C%H0J30$NJQ99$r%P%C%/%"%&%H$7$?$$;~$O!$(B +\hgcmd{backout}$B$K(B\hgopt{backout}{--merge}$B%*%W%7%g%s$rIU$1$k!%(B +\interaction{backout.non-tip.clone} +$B$3$N%*%W%7%g%s$O$I$s$J%A%'%s%8%;%C%H$G$b0l2s$NF0:n$G9T$J$&$3$H$,$G$-!$<j(B +$BAa$/4JC1$G$"$k!%(B +\interaction{backout.non-tip.backout} + +%If you take a look at the contents of \filename{myfile} after the +%backout finishes, you'll see that the first and third changes are +%present, but not the second. +%\interaction{backout.non-tip.cat} + +$B%P%C%/%"%&%H$,=*$C$?$"$H$G(B\filename{myfile}$B$NCf?H$r8+$k$H!$(B1$BHVL\$H(B3$BHVL\(B +$B$NJQ99$@$1$,;D$C$F$*$j!$(B2$BHVL\$NJQ99$,>C$($F$$$k$3$H$,$o$+$k!%(B +\interaction{backout.non-tip.cat} + +%As the graphical history in figure~\ref{fig:undo:backout-non-tip} +%illustrates, Mercurial actually commits \emph{two} changes in this +%kind of situation (the box-shaped nodes are the ones that Mercurial +%commits automatically). Before Mercurial begins the backout process, +%it first remembers what the current parent of the working directory +%is. It then backs out the target changeset, and commits that as a +%changeset. Finally, it merges back to the previous parent of the +%working directory, and commits the result of the merge. + +$B?^(B\ref{fig:undo:backout-non-tip}$B$G<($5$l$?MzNr$G!$(BMercurial$B$O(B2$B$D$N%3%_%C(B +$B%H$r9T$J$C$F$$$k!%!J?^Cf$GH"$G<($5$l$?@aE@$O(BMercurial$B$,<+F0E*$K%3%_%C%H$7(B +$B$?JQ99$G$"$k!%!K%P%C%/%"%&%H%W%m%;%9$NA0$K(BMercurial$B$O!$8=:_$N%o!<%-%s%0%G%#(B +$B%l%/%H%j$N?F$,2?$G$"$k$+$r5-21$9$k!%$=$7$F%?!<%2%C%H$N%A%'%s%8%;%C%H$r<h(B +$B$j=|$-!$$3$l$r%A%'%s%8%;%C%H$H$7$F%3%_%C%H$9$k!%:G8e$K%o!<%-%s%0%G%#%l%/(B +$B%H%j$NA0$N?F$X%^!<%8$r9T$J$$!$%^!<%8$N7k2L$r%3%_%C%H$9$k!%(B + +\begin{figure}[htb] + \centering + \grafix{undo-non-tip} +% \caption{Automated backout of a non-tip change using the + % \hgcmd{backout} command} + \caption{tip$B$G$J$$JQ99$r(B\hgcmd{backout}$B%3%^%s%I$G<+F0E*$K%P%C%/%"%&%H$9$k(B} + \label{fig:undo:backout-non-tip} +\end{figure} + +%The result is that you end up ``back where you were'', only with some +%extra history that undoes the effect of the changeset you wanted to +%back out. + +$B:G=*E*$K!$$$$/$i$+$NM>7W$JMzNr$r;D$7$D$D!$<h$j=|$-$?$+$C$?%A%'%s%8%;%C%H(B +$B$N1F6A$r=|5n$7$F!$K>$`>uBV$KLa$9$3$H$,$G$-$F$$$k!%(B + + +%\subsubsection{Always use the \hgopt{backout}{--merge} option} +\subsubsection{$B>o$K(B\hgopt{backout}{--merge}$B%*%W%7%g%s$r;H$&(B} + +%In fact, since the \hgopt{backout}{--merge} option will do the ``right +%thing'' whether or not the changeset you're backing out is the tip +%(i.e.~it won't try to merge if it's backing out the tip, since there's +%no need), you should \emph{always} use this option when you run the +%\hgcmd{backout} command. + +$B%P%C%/%"%&%H$7$h$&$H$9$k%A%'%s%8%;%C%H$,%A%C%W$+%A%C%W$G$J$$$+$K$+JQ$o$i(B +$B$:!$(B\hgcmd{backout}$B%3%^%s%I$r;H$*$&$H$9$k;~$O(B\emph{$B>o$K(B} +\hgopt{backout}{--merge}$B%*%W%7%g%s$r;H$&$Y$-$G$"$k!%BP>]$,%A%C%W$G$"$k>l(B +$B9g$OITMW$J%^!<%8$r;n$_$k$3$H$O$J$$$?$a!$>o$K$3$N%*%W%7%g%s$r;XDj$7$FLdBj(B +$B$J$$!%(B + + +%\subsection{Gaining more control of the backout process} +\subsection{$B%P%C%/%"%&%H%W%m%;%9$r$h$j:Y$+$/@)8f$9$k(B} + +%While I've recommended that you always use the +%\hgopt{backout}{--merge} option when backing out a change, the +%\hgcmd{backout} command lets you decide how to merge a backout +%changeset. Taking control of the backout process by hand is something +%you will rarely need to do, but it can be useful to understand what +%the \hgcmd{backout} command is doing for you automatically. To +%illustrate this, let's clone our first repository, but omit the +%backout change that it contains. + +$BJQ99$r%P%C%/%"%&%H$9$k:]!$>o$K(B\hgopt{backout}{--merge}$B%*%W%7%g%s$r;H$&$3(B +$B$H$r4+$a$?$,!$(B\hgcmd{backout}$B%3%^%s%I$G$O!$%P%C%/%"%&%H$9$k%A%'%s%8%;%C%H(B +$B$r$I$N$h$&$K%^!<%8$9$k$+;XDj$9$k$3$H$,$G$-$k!%%P%C%/%"%&%H%W%m%;%9$r<j$G(B +$B%3%s%H%m!<%k$9$kI,MW$O$[$H$s$I$J$$$O$:$@$,!$(B\hgcmd{backout}$B%3%^%s%I$,<+F0(B +$B$G$I$N$h$&$KF0:n$7$F$$$k$N$+M}2r$9$k$N$K$OLrN)$D$+$bCN$l$J$$!%F0:n$r@bL@(B +$B$9$k$?$a$K:G=i$N%j%]%8%H%j$N%/%m!<%s$r!$%P%C%/%"%&%H$r=|$$$F:n$C$F;O$a$k(B +$B$3$H$K$7$h$&!%(B + +%\interaction{backout.manual.clone} +%As with our earlier example, We'll commit a third changeset, then back +%out its parent, and see what happens. +%\interaction{backout.manual.backout} +%Our new changeset is again a descendant of the changeset we backout +%out; it's thus a new head, \emph{not} a descendant of the changeset +%that was the tip. The \hgcmd{backout} command was quite explicit in +%telling us this. +%\interaction{backout.manual.log} +% +%\interaction{backout.manual.clone} + +$BA0$K;H$C$?Nc$N$h$&$K!$(B3$BHVL\$N%A%'%s%8%;%C%H$r%3%_%C%H$7$?8e$G!$$=$N?F$r(B +$B%P%C%/%"%&%H$7$F2?$,5/$-$k$+8+$F$_$h$&!%(B +\interaction{backout.manual.backout} + +$BA0$NNc$HF1MM$K!$?7$7$$%A%'%s%8%;%C%H$O%P%C%/%"%&%H$7$?%A%'%s%8%;%C%H$N;R(B +$B$K$"$?$k!%$7$?$,$C$F?7$7$$%X%C%I$O%A%C%W$N;R$G$O(B\emph{$B$J$$(B}$B!%(B +\hgcmd{backout}$B%3%^%s%I$O$3$N?F;R4X78$K$D$$$F$+$J$j$O$C$-$j$HI=<($9$k!%(B +\interaction{backout.manual.log} + +\interaction{backout.manual.clone} + +%Again, it's easier to see what has happened by looking at a graph of +%the revision history, in figure~\ref{fig:undo:backout-manual}.This +%makes it clear that when we use \hgcmd{backout} to back out a change +%other than the tip, Mercurial adds a new head to the repository (the +%change it committed is box-shaped). + +$B$3$3$G$b%j%S%8%g%sMzNr$N%0%i%U(B\ref{fig:undo:backout-manual}$B$r8+$l$P!$2?$,(B +$B5/$-$F$$$k$N$+M}2r$7$d$9$$!%%A%C%W0J30$NJQ99$r%P%C%/%"%&%H$9$k$?$a$K(B +\hgcmd{backout}$B$r;H$C$?;~!$(BMercurial$B$,?7$7$$%X%C%I$r%j%]%8%H%j$KDI2C$9$k(B +$B$N$,$o$+$k!%!J;M3Q$G<($5$l$?%3%_%C%H!%!K(B + +\begin{figure}[htb] + \centering + \grafix{undo-manual} +% \caption{Backing out a change using the \hgcmd{backout} command} + \caption{\hgcmd{backout}$B%3%^%s%I$K$h$kJQ99$N%P%C%/%"%&%H(B} + \label{fig:undo:backout-manual} +\end{figure} + +%After the \hgcmd{backout} command has completed, it leaves the new +%``backout'' changeset as the parent of the working directory. +%\interaction{backout.manual.parents} +%Now we have two isolated sets of changes. +%\interaction{backout.manual.heads} + +\hgcmd{backout}$B%3%^%s%I$O!$40N;$7$?8e!$%P%C%/%"%&%H%A%'%s%8%;%C%H$r%o!<%-(B +$B%s%0%G%#%l%/%H%j$N?F$H$7$F;D$9!%(B +\interaction{backout.manual.parents} +$B$3$3$G(B2$B$D$N3VN%$5$l$?JQ99$N%;%C%H$,B8:_$9$k$3$H$K$J$k!%(B +\interaction{backout.manual.heads} + + +%Let's think about what we expect to see as the contents of +%\filename{myfile} now. The first change should be present, because +%we've never backed it out. The second change should be missing, as +%that's the change we backed out. Since the history graph shows the +%third change as a separate head, we \emph{don't} expect to see the +%third change present in \filename{myfile}. +%\interaction{backout.manual.cat} +%To get the third change back into the file, we just do a normal merge +%of our two heads. +%\interaction{backout.manual.merge} +%Afterwards, the graphical history of our repository looks like +%figure~\ref{fig:undo:backout-manual-merge}. + +$B:#$3$3$G(B\filename{myfile}$B$NFbMF$r8+$?$$$H$9$k!%:G=i$NJQ99$O%P%C%/%"%&%H$7(B +$B$F$$$J$$$N$GB8:_$7$F$$$k$O$:$G$"$k!%(B2$BHVL\$NJQ99$O%P%C%/%"%&%H$7$?$N$G>C(B +$B$($FL5$/$J$C$F$$$k$O$:$@!%(B3$BHVL\$NJQ99$OMzNr%0%i%U$GJ,N%$7$?%X%C%I$H$7$F(B +$BI=<($5$l$k$?$a!$(B3$BHVL\$NJQ99$,(B\filename{myfile}$B$K$"$k$H$O4|BT$7$F$$$J$$!%(B +\interaction{backout.manual.cat} +3$BHVL\$NJQ99$r%U%!%$%k$KH?1G$5$;$k$?$a$K$O!$(B2$B$D$N%X%C%I$r%^!<%8$7$F$d$l$P(B +$B$h$$!%(B +\interaction{backout.manual.merge} +$B$=$N8e$G$O%j%]%8%H%j$NMzNr$N%0%i%U$O?^(B +\ref{fig:undo:backout-manual-merge}$B$N$h$&$K$J$k(B + +\begin{figure}[htb] + \centering + \grafix{undo-manual-merge} +% \caption{Manually merging a backout change} + \caption{$B%P%C%/%"%&%H%A%'%s%8$N<jF0$K$h$k%^!<%8(B} + \label{fig:undo:backout-manual-merge} +\end{figure} + +%\subsection{Why \hgcmd{backout} works as it does} +\subsection{$B$J$<(B\hgcmd{backout}$B$O$3$N$h$&$KF0:n$9$k$N$+(B} + +%Here's a brief description of how the \hgcmd{backout} command works. +%\begin{enumerate} +%\item It ensures that the working directory is ``clean'', i.e.~that +% the output of \hgcmd{status} would be empty. +%\item It remembers the current parent of the working directory. Let's +% call this changeset \texttt{orig} +%\item It does the equivalent of a \hgcmd{update} to sync the working +% directory to the changeset you want to back out. Let's call this +% changeset \texttt{backout} +%\item It finds the parent of that changeset. Let's call that +% changeset \texttt{parent}. +%\item For each file that the \texttt{backout} changeset affected, it +% does the equivalent of a \hgcmdargs{revert}{-r parent} on that file, +% to restore it to the contents it had before that changeset was +% committed. +%\item It commits the result as a new changeset. This changeset has +% \texttt{backout} as its parent. +%\item If you specify \hgopt{backout}{--merge} on the command line, it +% merges with \texttt{orig}, and commits the result of the merge. +%\end{enumerate} + +\hgcmd{backout}$B$,$I$N$h$&$KF0:n$9$k$+407k$K@bL@$9$k$H0J2<$N$h$&$K$J$k!%(B +\begin{enumerate} + \item $B%o!<%-%s%0%G%#%l%/%H%j$,%/%j!<%s$G$"$k$3$H$r3NG'$9$k!%(Bi.e.\hgcmd{status} + $B$,6u$G$"$k$3$H$r3NG'$9$k(B + \item $B8=:_$N%o!<%-%s%0%G%#%l%/%H%j$N?F$r5-21$9$k$3$N%A%'%s%8%;%C%H$r(B + \texttt{orig}$B$H8F$V$3$H$K$9$k!%(B + \item $B%o!<%-%s%0%G%#%l%/%H%j$r!$%P%C%/%"%&%H$7$?%A%'%s%8%;%C%H$NFbMF$K(B + $B$9$k$?$a$K(B\hgcmd{update}$B$HEy2A$JF0:n$r9T$J$&!%$3$N%A%'%s%8%;%C%H(B + $B$r(B\texttt{backout}$B$H8F$V!%(B + \item $B$=$N%A%'%s%8%;%C%H$N?F$r8+$D$1=P$9$3$N%A%'%s%8%;%C%H$r(B + \texttt{parent}$B$H8F$V$3$H$K$9$k!%(B + \item \texttt{backout}$B%A%'%s%8%;%C%H$,1F6A$9$k3F!9$N%U%!%$%k$KBP$7$F!$(B + \hgcmdargs{revert}{-r parent}$B$HEy2A$JA`:n$r9T$$!$%A%'%s%8%;%C%H$,(B + $B%3%_%C%H$5$l$kA0$N>uBV$KLa$9!%(B + \item $B?7$7$$%A%'%s%8%;%C%H$N7k2L$r%3%_%C%H$9$k!%$3$N%A%'%s%8%;%C%H$O(B + \texttt{backout}$B$r?F$K;}$D!%(B + \item \hgopt{backout}{--merge}$B$r%3%^%s%I%i%$%s$+$iF~NO$7$?>l9g!$(B + \texttt{orig}$B$H$N%^!<%8$r9T$J$$!$7k2L$r%3%_%C%H$9$k!%(B +\end{enumerate} + +%An alternative way to implement the \hgcmd{backout} command would be +%to \hgcmd{export} the to-be-backed-out changeset as a diff, then use +%the \cmdopt{patch}{--reverse} option to the \command{patch} command to +%reverse the effect of the change without fiddling with the working +%directory. This sounds much simpler, but it would not work nearly as +%well. + +\hgcmd{backout}$B%3%^%s%I$r<BAu$9$kJL$NJ}K!$H$7$F!$(B\hgcmd{export}$B$G%P%C%/%"(B +$B%&%H$5$l$k$Y$-%A%'%s%8%;%C%H$r(Bdiff$B$H$7$F=PNO$7!$(B +\command{patch}$B$r(B\cmdopt{patch}{--reverse}$B%*%W%7%g%sIU$-$G8F$S!$%o!<%-%s(B +$B%0%G%#%l%/%H%j$NA`:n$r>JN,$7$F%j%P!<%9%Q%C%A$9$kJ}K!$,9M$($i$l$k!%(B +$B$3$NJ}K!$O$:$C$HC1=c$@$,!$$[$H$s$I$&$^$/F0$+$J$$!%(B + +%The reason that \hgcmd{backout} does an update, a commit, a merge, and +%another commit is to give the merge machinery the best chance to do a +%good job when dealing with all the changes \emph{between} the change +%you're backing out and the current tip. + +\hgcmd{backout}$B$,%"%C%W%G!<%H!$%3%_%C%H!$%^!<%8!$%3%_%C%H$r9T$J$&M}M3$O!$(B +$B%P%C%/%"%&%H$9$Y$-JQ99$H8=:_$N%A%C%W$N4V$G!$%^!<%85!9=$,:G$bNI$$7k2L$rF@(B +$B$i$l$k$h$&$K$9$k$?$a$G$"$k!%(B + +%If you're backing out a changeset that's~100 revisions back in your +%project's history, the chances that the \command{patch} command will +%be able to apply a reverse diff cleanly are not good,because +%intervening changes are likely to have ``broken the context'' that +%\command{patch} uses to determine whether it can apply a patch (if +%this sounds like gibberish, see \ref{sec:mq:patch} for a +%discussion of the \command{patch} command). +%Also, Mercurial's merge machinery will handle files and directories +%being renamed, permission changes, and modifications to binary files, +%none of which \command{patch} can deal with. + +$B$b$7%W%m%8%'%/%H$NMzNr$NCf$G(B100$B%j%S%8%g%s$bAL$k$h$&$J%A%'%s%8%;%C%H$r%P%C(B +$B%/%"%&%H$9$k$H$9$l$P!$(B\command{patch}$B$,(Bdiff$B$rE,MQ$G$-$k2DG=@-$OL@$i$+$KDc(B +$B$$!%4V$K$"$kJQ99$,!$(B\command{patch}$B%3%^%s%I$,%Q%C%AE,MQ$N2DH]$rH=CG$9$k$?(B +$B$a$NJ8L.$r2u$7$F$$$k2DG=@-$,9b$$$+$i$G$"$k!%!J$3$NOC$,J,$+$i$J$$>l9g$O(B +\ref{sec:mq:patch}$B$N(B\command{patch}$B%3%^%s%I$K4X$9$k5DO@$r;2>H$7$FM_$7$$!%!K(B +$B$^$?!$(BMercurial$B$N%^!<%85!9=$O!$(B\command{patch}$B%3%^%s%I$,07$($J$$%U%!%$%k(B +$B$H%G%#%l%/%H%j$N%j%M!<%`!$%Q!<%_%C%7%g%sJQ99!$%P%$%J%j%U%!%$%k$X$NJQ99$J(B +$B$I$r07$&$3$H$,$G$-$k!%(B + + +%\section{Changes that should never have been} +\section{$BB8:_$9$Y$-$G$J$$JQ99(B} +\label{sec:undo:aaaiiieee} + +%Most of the time, the \hgcmd{backout} command is exactly what you need +%if you want to undo the effects of a change. It leaves a permanent +%record of exactly what you did, both when committing the original +%changeset and when you cleaned up after it. + +$BBgDq$N>l9g!$(B\hgcmd{backout}$B$O$"$kJQ99$r<h$j>C$=$&$H$9$k:]$K;W$C$?$h$&$K5!(B +$BG=$9$k$O$:$G$"$k!%85!9$N%3%_%C%H$d$=$l$r<h$j=|$$$?;~$K2?$r$7$?$N$+1JB3E*(B +$B$J5-21$,;D$5$l$k!%(B + +%On rare occasions, though, you may find that you've committed a change +%that really should not be present in the repository at all. For +%example, it would be very unusual, and usually considered a mistake, +%to commit a software project's object files as well as its source +%files.Object files have almost no intrinsic value, and they're +%\emph{big}, so they increase the size of the repository and the amount +%of time it takes to clone or pull changes. + +$B$=$l$G$b$?$^$K%j%]%8%H%j$KA4$/;D$7$?$/$J$$JQ99$r%3%_%C%H$7$F$7$^$&$3$H$,(B +$B$"$k!%$?$H$($P!$Hs>o$KJQ$J%3%_%C%H$d!$DL>o%_%9$H9M$($i$l$k$h$&$J%3%_%C%H!$(B +$B%=!<%9$@$1$G$O$J$/%W%m%8%'%/%H$N%*%V%8%'%/%H%U%!%$%k$b%3%_%C%H$7$F$7$^$&(B +$B$J$I$,M-$jF@$k!%%*%V%8%'%/%H%U%!%$%k$O8GM-$NCM$r;}$AF@$:!$$+$D(B\emph{$BBg$-(B +$B$$(B}$B!%$=$N$?$a!$%j%]%8%H%j$N%5%$%:$rA}$d$7!$%/%m!<%s$d%W%k$KM>7W$J;~4V$,3](B +$B$+$k$h$&$K$J$k!%(B + +%Before I discuss the options that you have if you commit a ``brown +%paper bag'' change (the kind that's so bad that you want to pull a +%brown paper bag over your head), let me first discuss some approaches +%that probably won't work. + +$BCc?'$N;fB^%3%_%C%H!JCc?'$N;fB^$rF,$KHo$j$?$$$0$i$$%P%D$N0-$$%3%_%C%H!K$K(B +$B;H$($k%*%W%7%g%s$K$D$$$F5DO@$9$kA0$K!$$$$/$D$+$N$&$^$/9T$+$J$$%"%W%m!<%A(B +$B$r=R$Y$?$$!%(B + +%Since Mercurial treats history as accumulative---every change builds +%on top of all changes that preceded it---you generally can't just make +%disastrous changes disappear. The one exception is when you've just +%committed a change, and it hasn't been pushed or pulled into another +%repository. That's when you can safely use the \hgcmd{rollback} +%command, as I detailed in section~\ref{sec:undo:rollback}. + +Mercurial$B$OMzNr$rN_@QE*$J$b$N$H$7$F07$&!%A4$F$NJQ99$O$=$l$K@hN)$DA4$F$NJQ(B +$B99$N>e$K$J$j$?$C$F$$$k!%0lHLE*$K8@$C$FGK2uE*$JJQ99$r2sHr$9$k$3$H$O$G$-$J(B +$B$$!%$?$C$?0l$D$NNc30$O%3%_%C%H$r9T$J$C$?D>8e$G!$B>$N%j%]%8%H%j$K%W%C%7%e(B +$B$b%W%k$b$5$l$F$$$J$$>l9g$G$"$k!%$=$N>l9g!$(B\ref{sec:undo:rollback}$B$N%;%/%7%g(B +$B%s$G>\$7$/?($l$?$h$&$K!$0BA4$K(B\hgcmd{rollback}$B$r<B9T$9$k$3$H$,$G$-$k!%(B + +%After you've pushed a bad change to another repository, you \emph{could} +%still use \hgcmd{rollback} to make your local copy of the change +%disappear, but it won't have the consequences you want. The change will +%still be present in the remote repository, so it will reappear in your +%local repository the next time you pull. + +$B4V0c$C$?JQ99$rB>$N%j%]%8%H%j$K%W%C%7%e$7$?8e$G$b%m!<%+(B +$B%k%3%T!<$NJQ99$r<h$j>C$9$?$a$K0MA3$H$7$F(B\hgcmd{rollback}$B$r;H$&$3$H$,(B +\emph{$B$G$-$k(B}$B$,!$$3$l$O0U?^$7$?$h$&$J7k2L$K$O$J$i$J$$!%JQ99$O0MA3$H$7$F(B +$B%j%b!<%H$N%j%]%8%H%j$K$O$=$s$6$$$7$F$*$j!$<!$K%W%k$7$?;~$K$O%m!<%+%k%j%](B +$B%8%H%j$K$b8=$l$k!%(B + +%If a situation like this arises, and you know which repositories your +%bad change has propagated into, you can \emph{try} to get rid of the +%changee from \emph{every} one of those repositories. This is, of +%course, not a satisfactory solution: if you miss even a single +%repository while you're expunging, the change is still ``in the +%wild'', and could propagate further. + +$B$3$N$h$&$J>u67$K$J$C$?;~!$$b$7$I$N%j%]%8%H%j$K$3$N4V0c$C$?JQ99$,GH5Z$7$F(B +$B$$$k$N$+$,L@$i$+$G$"$l$P!$$=$l$i$N%j%]%8%H%j$N0l$D0l$D$+$i!$JQ99$r<h$j=|(B +$B$/$3$H$r;n$_$k$3$H$,$G$-$k!%$3$l$O$b$A$m$sK~B-$N$$$/2r7hK!$G$O$J$$!%$b$7(B +$B0l$D$G$b>C5n$rK:$l$l$P!$JQ99$OLnJ|$7$K$J$C$F$*$j!$$5$i$K3H$,$jF@$k!%(B + +%If you've committed one or more changes \emph{after} the change that +%you'd like to see disappear, your options are further reduced. +%Mercurial doesn't provide a way to ``punch a hole'' in history, +%leaving changesets intact. + +$B$b$7(B1$B$D0J>e$N?7$?$JJQ99$r!$>C$7$?$$$H;W$C$F$$$kJQ99$N8e$K%3%_%C%H$7$F$$(B +$B$?$H$9$l$P!$;H$($k%*%W%7%g%s$O$5$i$K>/$J$/$J$k!%(BMercurial$B$O%A%'%s%8%;%C(B +$B%H$r$=$N$^$^$KMzNr$K7j$r3+$1$k$h$&$JJ}K!$rDs6!$7$F$$$J$$!%(B + +%XXX This needs filling out. The \texttt{hg-replay} script in the +%\texttt{examples} directory works, but doesn't handle merge +%changesets. Kind of an important omission. + +XXX $BDI5-$NI,MW@-$"$j!%(B\texttt{examples}$B%G%#%l%/%H%jFb$N(B +\texttt{hg-replay}$B%9%/%j%W%H$O5!G=$9$k$,!$%A%'%s%8%;%C%H$N%^!<%8$r07$o$J(B +$B$$!%=EMW$J@)8B$G$"$k!%(B + + +%\subsection{Protect yourself from ``escaped'' changes} +\subsection{$B0oC&$7$?JQ99$+$i<+J,<+?H$r<i$k(B} + +%If you've committed some changes to your local repository and they've +%been pushed or pulled somewhere else, this isn't necessarily a +%disaster. You can protect yourself ahead of time against some classes +%of bad changeset. This is particularly easy if your team usually +%pulls changes from a central repository. + +$B%m!<%+%k%j%]%8%H%j$K$$$/$D$+$NJQ99$r%3%_%C%H$7!$$=$l$i$,JL$N=j$K%W%C%7%e(B +$B$^$?$O%W%k$5$l$F$$$F!$I,$:$7$bBg:R32$H$O8@$($J$$!%$"$J$?$O$$$/$D$+$N%/%i(B +$B%9$N4V0c$C$?JQ99$+$i<+J,<+?H$G$_$r<i$k$3$H$,$G$-$k!%$3$l$O$"$J$?$N%A!<%`(B +$B$,Cf1{$N%j%]%8%H%j$+$iJQ99$r%W%k$7$F$$$k>l9g$OFC$K4JC1$G$"$k!%(B + +%By configuring some hooks on that repository to validate incoming +%changesets (see chapter~\ref{chap:hook}), you can automatically +%prevent some kinds of bad changeset from being pushed to the central +%repository at all. With such a configuration in place, some kinds of +%bad changeset will naturally tend to ``die out'' because they can't +%propagate into the central repository. +%Better yet, this happens without any need for explicit intervention. + +$BCf1{%j%]%8%H%j$N>e$G!$JQ99E~Ce$K%U%C%/$r@_Dj$9$k!J(B\ref{chap:hook}$B$r;2>H!K(B +$B$3$H$G!$$"$k<o$N8m$C$?%A%'%s%8%;%C%H$,Cf1{%j%]%8%H%j$K%3%_%C%H$5$l$k$N$r(B +$B<+F0E*$KKI$0$3$H$,$G$-$k!%(B +$B$=$N$h$&$J@_Dj$r9T$&$3$H$G!$$"$k<o$N8m$C$?%A%'%s%8%;%C%H$O%;%s%H%i%k%j%](B +$B%8%H%j$KGH5Z$9$k$3$H$,$G$-$:!$;`LG$7$F$$$/798~$,$"$k!%$5$i$KNI$$$3$H$H$7(B +$B$F$O!$$3$l$OL@<(E*$K2pF~$;$:$KH/@8$5$;$k$3$H$,$G$-$k$3$H$,$"$k!%(B + +%For instance, an incoming change hook that verifies that a changeset +%will actually compile can prevent people from inadvertantly ``breaking +%the build''. + +$BNc$($P!$%A%'%s%8%;%C%H$r<B:]$K%3%s%Q%$%k$9$kJQ99E~Ce%U%C%/$O!$ITCm0U$K$h(B +$B$k%S%k%IITG=$rKI$0$3$H$,$G$-$k!%(B + +%\section{Finding the source of a bug} +\section{$B%P%0$N860x$r8+$D$1$k(B} +\label{sec:undo:bisect} + +%While it's all very well to be able to back out a changeset that +%introduced a bug, this requires that you know which changeset to back +%out. Mercurial provides an invaluable command, called +%\hgcmd{bisect}, that helps you to automate this process and accomplish +%it very efficiently. + +$B%P%0$rH/@8$5$;$?%A%'%s%8%;%C%H$r%P%C%/%"%&%H$9$k$?$a$K$O!$$I$N%A%'%s%8%;%C(B +$B%H$G%P%0$N:.F~$,5/$-$?$N$+$rCN$i$M$P$J$i$J$$!%(BMercurial$B$O(B\hgcmd{bisect} +$B$H$$$&M-MQ$J%3%^%s%I$rDs6!$7$F$*$j!$$3$l$K$h$C$F%A%'%s%8%;%C%H$NFCDj$r<+(B +$BF02=$7!$%P%C%/%"%&%H$r6K$a$F8z2LE*$K9T$&$3$H$,$G$-$k!%(B + +%The idea behind the \hgcmd{bisect} command is that a changeset has +%introduced some change of behaviour that you can identify with a +%simple binary test. You don't know which piece of code introduced the +%change, but you know how to test for the presence of the bug. The +%\hgcmd{bisect} command uses your test to direct its search for the +%changeset that introduced the code that caused the bug. + +\hgcmd{bisect}$B%3%^%s%I$NGX8e$K$O!$%A%'%s%8%;%C%H$K$h$C$FC1=c$J%P%$%J%j%F(B +$B%9%H$G==J,<1JL2DG=$J5sF0$NJQ2=$,@8$l$k$H$$$&9M$(J}$,$"$k!%$"$J$?$O$I$N%3!<(B +$B%I$,JQ2=$r0z$-5/$3$7$?$N$+$O$o$+$i$J$$$,!$%P%0$,5/$-$F$$$k$+$r%F%9%H$9$k(B +$BJ}K!$OCN$C$F$$$k!%(B\hgcmd{bisect}$B%3%^%s%I$O!$%F%9%H$K$h$C$F%P%0$r0z$-5/$3(B +$B$7$?%A%'%s%8%;%C%H$rFCDj$9$k!%(B + +%Here are a few scenarios to help you understand how you might apply +%this command. +%\begin{itemize} +%\item The most recent version of your software has a bug that you +% remember wasn't present a few weeks ago, but you don't know when it +% was introduced. Here, your binary test checks for the presence of +% that bug. +%\item You fixed a bug in a rush, and now it's time to close the entry +% in your team's bug database. The bug database requires a changeset +% ID when you close an entry, but you don't remember which changeset +% you fixed the bug in. Once again, your binary test checks for the +% presence of the bug. +%\item Your software works correctly, but runs~15\% slower than the +% last time you measured it. You want to know which changeset +% introduced the performance regression. In this case, your binary +% test measures the performance of your software, to see whether it's +% ``fast'' or ``slow''. +%\item The sizes of the components of your project that you ship +% exploded recently, and you suspect that something changed in the way +% you build your project. +%%\end{itemize} + +$B0J2<$O$3$N%3%^%s%I$r$I$N$h$&$KE,MQ$G$-$k$N$+M}2r$r=u$1$k%7%J%j%*$G$"$k!%(B +\begin{itemize} + \item $B%P%0$,5/$-$F$$$J$+$C$?:G$b?7$7$$%P!<%8%g%s$r3P$($F$$$k$,!$$I$N%P!<(B + $B%8%g%s$G%P%0$,:.F~$7$?$+J,$+$i$J$$!%$3$3$G%P%$%J%j%F%9%H$r9T$J$$!$(B + $B%P%0$NB8:_$rD4$Y$k!%(B + \item $B%P%0$rBg5^$.$G=$@5$7!$$"$J$?$N%A!<%`$N%P%0%G!<%?%Y!<%9$r%/%m!<%:(B + $B$9$k!%%P%0%G!<%?%Y!<%9$O$I$3$G%P%0$,=$@5$5$l$?$+$N%A%'%s%8%;%C%H(B + $B$N(BID$B$rI,MW$H$9$k$,!$$"$J$?$O$I$N%A%'%s%8%;%C%H$G=$@5$5$l$?$+5-21(B + $B$7$F$$$J$$!%$3$3$G$^$?%P%0$NB8:_$r%P%$%J%j%F%9%H$9$k!%(B + \item $B$"$J$?$N%=%U%H%&%'%"$O@5$7$/F0$$$?$,!$0JA0B,Dj$7$?;~$h$j$b(B15\%$BCY(B + $B$/$J$C$F$$$?!%$"$J$?$O$I$N%A%'%s%8%;%C%H$,$3$N@-G=Nt2=$r$b$?$i$7(B + $B$?$N$+CN$j$?$$!%$3$N>l9g!$%P%$%J%j%F%9%H$GB.EY$rB,Dj$9$k!%(B + \item $B=P2Y$9$k%W%m%8%'%/%H$N%3%s%]!<%M%s%H%5%$%:$,:G6aGzH/E*$KA}$($?!%(B + $B$"$J$?$O%W%m%8%'%/%H$N%S%k%I$NJ}K!$K$J$s$i$+$NJQ2=$,5/$-$?$N$G$O(B + $B$J$$$+$H5?$C$F$$$k!%(B +\end{itemize} + +%From these examples, it should be clear that the \hgcmd{bisect} +%command is not useful only for finding the sources of bugs. You can +%use it to find any ``emergent property'' of a repository (anything +%that you can't find from a simple text search of the files in the +%tree) for which you can write a binary test. + +$B$3$NNc$+$i!$(B\hgcmd{bisect}$B%3%^%s%I$O%P%0$N$"$j$+$rC5$9$N$KLrN)$D$N$G$O$J(B +$B$$$3$H$,J,$+$k$@$m$&!%$3$N%3%^%s%I$O%P%$%J%j%F%9%H$r9T$J$$F@$k%j%]%8%H%j(B +$B$G5/$-$?!JC1=c$K%D%j!<$r%F%-%9%H%5!<%A$7$?$N$G$OH/8+$G$-$J$$!KJQ2=A4$F$r(B +$BCN$k$N$K;H$&$3$H$,$G$-$k!%(B + +%We'll introduce a little bit of terminology here, just to make it +%clear which parts of the search process are your responsibility, and +%which are Mercurial's. A \emph{test} is something that \emph{you} run +%when \hgcmd{bisect} chooses a changeset.A \emph{probe} is what +%\hgcmd{bisect} runs to tell whether a revision is good. Finally, +%we'll use the word ``bisect'', as both a noun and a verb, to stand in +%for the phrase ``search using the \hgcmd{bisect} command''. + +$B$3$3$G%5!<%A$N$I$N%Q!<%H$,$"$J$?$N@UG$$KB0$7!$$I$N%Q!<%H$,(BMercurial$B$KB0$9(B +$B$k$N$+L@3N$K$9$k$?$a$K>/$7$P$+$jMQ8l$rF3F~$9$k!%(B\emph{test}$B$O(B\emph{$B$"$J(B +$B$?(B}$B$,(B\hgcmd{bisect}$B$r<B9T$9$k;~$KA*$s$@%A%'%s%8%;%C%H$G$"$k!%(B +\emph{probe}$B$O(B\hgcmd{bisect}$B$,%j%S%8%g%s$,NI$$$+H=Dj$9$k%j%S%8%g%s$G$"$k!%(B +``bisect''$B$H$$$&C18l$r(B``\hgcmd{bisect}$B%3%^%s%I$r;H$C$F%5!<%A$9$k(B''$B$H$$$&(B +$B$3$H$NF15A8l$H$7$FL>;l$HF0;lN>J}$GMQ$$$k!%(B + +%One simple way to automate the searching process would be simply to +%probe every changeset. However, this scales poorly.If it took ten +%minutes to test a single changeset, and you had 10,000 changesets in +%your repository, the exhaustive approach would take on average~35 +%\emph{days} to find the changeset that introduced a bug. Even if you +%knew that the bug was introduced by one of the last 500 changesets, +%and limited your search to those, you'd still be looking at over 40 +%hours to find the changeset that introduced your bug. + +$B%5!<%A%W%m%;%9$r<+F02=$9$k$?$s$s=_OBJ}K!$O!$A4$F$N%A%'%s%8%;%C%H$r(Bprobe +$B$9$k$3$H$G$"$k!%$7$+$7$3$l$OKX$s$I%9%1!<%k$7$J$$!%0l$D$N%A%'%s%8%;%C%H$N(B +$B%A%'%C%/$K(B10$BJ,$+$+$j!$%j%]%8%H%j$K%A%'%s%8%;%C%H$,(B10000$B$"$C$?$H$7$?$i!$iM(B +$BDY$7$N%"%W%m!<%A$O%P%0$rH/@8$5$;$?%A%'%s%8%;%C%H$NFCDj$KJ?6Q$G(B35$BF|$+$+$k!%(B +$B%P%0$,:G8e$N(B500$B%A%'%s%8%;%C%H$GH/@8$7$?$3$H$,J,$+$C$F$$$F!$%5!<%A$r$=$l$i(B +$B$N%A%'%s%8%;%C%H$K8BDj$7$?$H$7$F$b!$%P%0$r0z$-5/$3$7$?%A%'%s%8%;%C%H$NFC(B +$BDj$K(B40$B;~4V0J>e$+$+$k!%(B + +%What the \hgcmd{bisect} command does is use its knowledge of the +%``shape'' of your project's revision history to perform a search in +%time proportional to the \emph{logarithm} of the number of changesets +%to check (the kind of search it performs is called a dichotomic +%search). + +%With this approach, searching through 10,000 changesets will +%take less than three hours, even at ten minutes per test (the search +%will require about 14 tests). Limit your search to the last hundred +%changesets, and it will take only about an hour (roughly seven tests). + +\hgcmd{bisect}$B$O$"$J$?$N%W%m%8%'%/%H$N%j%S%8%g%sMzNr$N(B``$B%7%'%$%W(B''$B$NCN<1(B +$B$r!$%5!<%A$9$Y$-%A%'%s%8%;%C%H?t$N(B\emph{$BBP?t(B}$B$KHfNc$7$?;~4V$G%5!<%A$9$k$?(B +$B$a$K;H$&!%!JFsJ,8!:w$r9T$J$&!%!K$3$N%"%W%m!<%A$K$h$C$F(B10000$B%A%'%s%8%;%C%H(B +$B$N%5!<%A$O!$3F!9$N%5!<%A$,(B10$BJ,$+$+$C$?$H$7$F$b!$%F%9%H?t$O(B14$B$G(B3$B;~4V0J2<$G(B +$B=*N;$9$k!%:G8e$N(B100$B$N%A%'%s%8%;%C%H$K8B$C$F9T$J$C$?$H$9$k$H!$$*$h$=(B7$B2s$N(B +$B%F%9%H$G(B1$B;~4VDxEY$G=*N;$9$k!%(B + +%The \hgcmd{bisect} command is aware of the ``branchy'' nature of a +%Mercurial project's revision history, so it has no problems dealing +%with branches, merges, or multiple heads in a repoository. It can +%prune entire branches of history with a single probe, which is how it +%operates so efficiently. + +\hgcmd{bisect}$B%3%^%s%I$O!$(BMercurial$B%W%m%8%'%/%H$N%j%S%8%g%sMzNr$,;^J,$+$l(B +$B$7$,$A$J@-<A$r;}$D$3$H$rG0F,$K$*$$$F@_7W$5$l$F$*$j!$%j%]%8%H%j$K%V%i%s%A!$(B +$B%^!<%8!$J#?t$N%X%C%I$,$"$C$F$bLdBj$J$/<h$j07$($k!%0l2s$N(Bprobe$B$GMzNr$NCf(B +$B$N$"$kJ,;^A4$F$r4"$k$3$H$,$G$-$k$?$a!$6K$a$F8zN(E*$KF0:n$9$k!%(B + +%\subsection{Using the \hgcmd{bisect} command} +\subsection{\hgcmd{bisect}$B%3%^%s%I$r;H$&(B} + +%Here's an example of \hgcmd{bisect} in action. +\hgcmd{bisect}$B$NF0:n$rNc$G<($9!%(B + +%\begin{note} +% In versions 0.9.5 and earlier of Mercurial, \hgcmd{bisect} was not a +% core command: it was distributed with Mercurial as an extension. +% This section describes the built-in command, not the old extension. +%\end{note} + +\begin{note} + $B%P!<%8%g%s(B0.9.5$B0JA0$N(BMercurial$B$G$O!$(B\hgcmd{bisect}$B$O%3%"%3%^%s%I$G$O$J(B + $B$/!$(Bextension$B$H$7$F(BMercurial$B$KF1:-$5$l$F$$$?!%$3$N@a$O8E$$(Bextension$B$K$D(B + $B$$$F$G$O$J$/!$%S%k%H%$%s%3%^%s%I$H$7$F$N(B\hgcmd{bisect}$B$K$D$$$F=R$Y$F$$$k!%(B +\end{note} + +%Now let's create a repository, so that we can try out the +%\hgcmd{bisect} command in isolation. +%\interaction{bisect.init} +%We'll simulate a project that has a bug in it in a simple-minded way: +%create trivial changes in a loop, and nominate one specific change +%that will have the ``bug''. This loop creates 35 changesets, each +%adding a single file to the repository. We'll represent our ``bug'' +%with a file that contains the text ``i have a gub''. +%\interaction{bisect.commits} + +$BFHN)$7$F(B\hgcmd{bisect}$B$r;n$;$k$h$&$K%j%]%8%H%j$r:n@.$9$k!%(B +\interaction{bisect.init} +$BC1=c$J%P%0$N$"$k%W%m%8%'%/%H$r%7%_%e%l!<%H$9$k!%%P%0$O7+JV$7A`:n$N4V$K<+(B +$BL@$JJQ99$r9T$$!$FCDj$N(B1$B$D$NJQ99$r%P%0$r;}$D$H;XL>$9$k!%$3$N%k!<%W$O(B35 +$B$N%A%'%s%8%;%C%H$r:n$j!$3F!9!$(B1$B$D$N%U%!%$%k$r%j%]%8%H%j$KDI2C$9$k!%%P%0(B +$B$O(B``i have a gub''$B$H$$$&J8;zNs$r;}$D%U%!%$%k$GI=8=$9$k!%(B +\interaction{bisect.commits} + +%The next thing that we'd like to do is figure out how to use the +%\hgcmd{bisect} command. We can use Mercurial's normal built-in help +%mechanism for this. +%\interaction{bisect.help} + +$B<!$K(B\hgcmd{bisect}$B$N;H$$J}$r@bL@$7$?$$!%(BMercurial$B$N%S%k%H%$%s$N%X%k%W$,(B +$B;H$($k!%(B +\interaction{bisect.help} + +%The \hgcmd{bisect} command works in steps. Each step proceeds as follows. +%\begin{enumerate} +%\item You run your binary test. +% \begin{itemize} +% \item If the test succeeded, you tell \hgcmd{bisect} by running the +% \hgcmdargs{bisect}{good} command. +% \item If it failed, run the \hgcmdargs{bisect}{--bad} command. +% \end{itemize} +%\item The command uses your information to decide which changeset to +% test next. +%\item It updates the working directory to that changeset, and the +% process begins again. +%\end{enumerate} +%The process ends when \hgcmd{bisect} identifies a unique changeset +%that marks the point where your test transitioned from ``succeeding'' +%to ``failing''. + +\hgcmd{bisect}$B%3%^%s%I$OCJ3,$rF'$s$GF0:n$9$k!%3FCJ3,$O0J2<$N$h$&$K?J$`!%(B +\begin{enumerate} +\item $B%P%$%J%j%F%9%H$r<B9T$9$k(B + \begin{itemize} + \item $B%F%9%H$,@.8y$7$?>l9g!$(B\hgcmd{bisect}$B$r0z?t(B\hgcmdargs{bisect}{good} + $B$rIU$1$F<B9T$9$k!%(B + \item $B%F%9%H$,<:GT$7$?>l9g$O(B\hgcmdargs{bisect}{--bad}$B%3%^%s%I$r<B9T$9(B + $B$k!%(B + \end{itemize} + \item $B%3%^%s%I$O0z?t$GEO$5$l$?>pJs$r;H$C$F<!$K$I$N%A%'%s%8%;%C%H$r%F%9(B + $B%H$9$Y$-$+7hDj$9$k!%(B + \item $B%3%^%s%I$O%o!<%-%s%0%G%#%l%/%H%j$r$=$N%A%'%s%8%;%C%H$K99?7$9$k!%(B + $B%W%m%;%9$r:F3+$9$k!%(B +\end{enumerate} +\hgcmd{bisect}$B$N%W%m%;%9$O!$%F%9%H$,@.8y$+$i<:GT$XJQ2=$7$?%A%'%s%8%;%C%H(B +$B$rFCDj$G$-$k$H=*N;$9$k!%(B + +%To start the search, we must run the \hgcmdargs{bisect}{--reset} command. +%\interaction{bisect.search.init} + +$B%5!<%A$r;O$a$k$K$O(B\hgcmdargs{bisect}{--reset}$B$r<B9T$9$k!%(B +\interaction{bisect.search.init} + +%In our case, the binary test we use is simple: we check to see if any +%file in the repository contains the string ``i have a gub''. If it +%does, this changeset contains the change that ``caused the bug''. By +%convention, a changeset that has the property we're searching for is +%``bad'', while one that doesn't is ``good''. + +$B$3$N%1!<%9$G$O!$%P%$%J%j%F%9%H$OC1=c$G!$%j%]%8%H%jFb$K(B``i have a gub''$B$r(B +$B4^$`%U%!%$%k$,$"$k$+$I$&$+$r%A%'%C%/$9$k$@$1$G$"$k!%$b$7$3$l$,$"$l$P!$$=(B +$B$N%A%'%s%8%;%C%H$,%P%0$r0z$-5/$3$7$F$$$kJQ99$r4^$s$G$$$k$H$$$&$3$H$K$J$k!%(B +$B47Nc$K=>$C$F!$C5$7$F$$$k%A%'%s%8%;%C%H$r(B``bad''$B!$$=$l0J30$r(B``good''$B$H8F(B +$B$V$3$H$K$9$k!%(B + +%Most of the time, the revision to which the working directory is +%synced (usually the tip) already exhibits the problem introduced by +%the buggy change, so we'll mark it as ``bad''. +%\interaction{bisect.search.bad-init} + +$BBgDq$N>l9g!$%o!<%-%s%0%G%#%l%/%H%j$,F14|$7$F$$$k%j%S%8%g%s!JDL>o$O(Btip$B$N(B +$B$O$:$@!K$O!$%P%0$N$"$kJQ99$K$h$C$F0z$-5/$3$5$l$?LdBj$r<($7$F$$$k$N$G!$$3(B +$B$N%j%S%8%g%s$r(B``bad''$B$H%^!<%/$9$k!%(B +\interaction{bisect.search.bad-init} + +%Our next task is to nominate a changeset that we know \emph{doesn't} +%have the bug; the \hgcmd{bisect} command will ``bracket'' its search +%between the first pair of good and bad changesets. In our case, we +%know that revision~10 didn't have the bug. (I'll have more words +%about choosing the first ``good'' changeset later.) +%\interaction{bisect.search.good-init} + +$B<!$K%P%0$r(B\emph{$B4^$^$J$$(B}$B%j%S%8%g%s$r;XL>$9$k!%(B\hgcmd{bisect}$B%3%^%s%I$O(B +$B:G=i$N(B``good''$B%A%'%s%8%;%C%H$H(B``bad''$B%A%'%s%8%;%C%H$r%V%i%1%C%H$9$k!%$3(B +$B$NNc$G$O!$%j%S%8%g%s(B~10$B$O%P%0$r;}$?$J$$$HJ,$+$C$F$$$k!%!J:G=i$N(B``good'' +$B%A%'%s%8%;%C%H$NA*$SJ}$K$D$$$F$O8e=R$9$k!%!K(B +\interaction{bisect.search.good-init} + +%Notice that this command printed some output. +%\begin{itemize} +%\item It told us how many changesets it must consider before it can +% identify the one that introduced the bug, and how many tests that +% will require. +%\item It updated the working directory to the next changeset to test, +% and told us which changeset it's testing. +%\end{itemize} + +$B%3%^%s%I$+$i=PNO$,$"$k$3$H$KCm0U!%(B +\begin{itemize} + \item $B%P%0$NF~$C$?%A%'%s%8%;%C%H$rFCDj$9$k$^$G$K9MN8$9$Y$-%A%'%s%8%;%C%H(B + $B$N8D?t$H!$I,MW$J8!::$N2s?t$rI=<($9$k!%(B + \item $B%o!<%-%s%0%G%#%l%/%H%j$r<!$N%F%9%H$9$Y$-%A%'%s%8%;%C%H$K99?7$7!$(B + $B$I$N%A%'%s%8%;%C%H$r%F%9%H$7$F$$$k$N$+$rI=<($9$k!%(B +\end{itemize} + +%We now run our test in the working directory. We use the +%\command{grep} command to see if our ``bad'' file is present in the +%working directory. If it is, this revision is bad; if not, this +%revision is good. +%\interaction{bisect.search.step1} + +$B$3$3$G%o!<%-%s%0%G%#%l%/%H%j$G%F%9%H$r9T$&$3$H$,$G$-$k!%(B\command{grep}$B%3(B +$B%^%s%I$r;H$C$F(B``bad''$B%U%!%$%k$,%o!<%-%s%0%G%#%l%/%H%j$K$"$k$+$I$&$+$r%A%'%C(B +$B%/$9$k!%$b$7B8:_$9$l$P!$%j%S%8%g%s$O(Bbad$B$G!$B8:_$7$J$1$l$P%j%S%8%g%s$O(B +good$B$H$$$&$3$H$K$J$k!%(B +\interaction{bisect.search.step1} + +%This test looks like a perfect candidate for automation, so let's turn +%it into a shell function. +%\interaction{bisect.search.mytest} +%We can now run an entire test step with a single command, +%\texttt{mytest}. +%\interaction{bisect.search.step2} +%A few more invocations of our canned test step command, and we're +%done. +%\interaction{bisect.search.rest} + +$B$3$N%F%9%H$O40A4$K<+F02=$G$-$k!%%7%'%k4X?t$K$7$F$_$h$&!%(B +\interaction{bisect.search.mytest} +$B%F%9%HA4BN$r0l$D$N(B\texttt{mytest}$B%3%^%s%I$H$7$F<B9T$G$-$k$h$&$K$J$C$?!%(B +\interaction{bisect.search.step2} +$B$3$N%Q%C%/$5$l$?%F%9%H%3%^%s%I$r5/F0$9$k$@$1$G%F%9%H$,40N;$9$k!%(B +\interaction{bisect.search.rest} + +%Even though we had~40 changesets to search through, the \hgcmd{bisect} +%command let us find the changeset that introduced our ``bug'' with +%only five tests. Because the number of tests that the \hgcmd{bisect} +%command grows logarithmically with the number of changesets to +%search, the advantage that it has over the ``brute force'' search +%approach increases with every changeset you add. + +40$B8D$N%A%'%s%8%;%C%H$,$"$k$K$b$+$+$o$i$:!$(B\hgcmd{bisect}$B%3%^%s%I$O%P%0$r(B +$B$b$?$i$7$?%A%'%s%8%;%C%H$r(B5$B2s$N%F%9%H$GH/8+$9$k$3$H$,$G$-$?!%(B +\hgcmd{bisect}$B$N%F%9%H2s?t$OC5:w$9$Y$-%A%'%s%8%;%C%H?t$,A}$($k$K=>$C$F!$(B +$BBP?tE($KA}$($k$,!$iMDY$7C5:w$KBP$9$kM%0L@-$O!$%A%'%s%8%;%C%H$,A}2C$9$k$K(B +$B=>$C$FA}2C$9$k!%(B + + +%\subsection{Cleaning up after your search} +\subsection{$B%5!<%A8e$N%/%j!<%s%"%C%W(B} + +%When you're finished using the \hgcmd{bisect} command in a +%repository, you can use the \hgcmdargs{bisect}{reset} command to drop +%the information it was using to drive your search. The command +%doesn't use much space, so it doesn't matter if you forget to run this +%command. However, \hgcmd{bisect} won't let you start a new search in +%that repository until you do a \hgcmdargs{bisect}{reset}. +%\interaction{bisect.search.reset} + +$B%j%]%8%H%jFb$G(B\hgcmd{bisect}$B%3%^%s%I$r;H$$=*$C$?8e$K(B +\hgcmdargs{bisect}{reset}$B%3%^%s%I$GC5:w$K;H$C$?>pJs$r>C5n$9$k$3$H$,$G$-(B +$B$k!%%3%^%s%I$OBg$-$J%9%Z!<%9$r;H$&$o$1$G$O$J$$$N$G!$$3$N%3%^%s%I$r<B9T$9(B +$B$k$N$rK:$l$F$bFC$KLdBj$O$J$$!%$7$+$7(B\hgcmd{bisect}$B$O(B +\hgcmdargs{bisect}{reset}$B$,<B9T$5$l$k$^$G!$$=$N%j%]%8%H%jFb$G?7$?$JC5:w(B +$B$r;O$a$k$3$H$O$G$-$J$$!%(B +\interaction{bisect.search.reset} + +%\section{Tips for finding bugs effectively} +\section{$B8zN(E*$J%P%0$NH/8+K!(B} + +%\subsection{Give consistent input} +\subsection{$B0l4S$7$?F~NO$r9T$&(B} + +%The \hgcmd{bisect} command requires that you correctly report the +%result of every test you perform. If you tell it that a test failed +%when it really succeeded, it \emph{might} be able to detect the +%inconsistency. If it can identify an inconsistency in your reports, +%it will tell you that a particular changeset is both good and bad. +%However, it can't do this perfectly; it's about as likely to report +%the wrong changeset as the source of the bug. + +\hgcmd{bisect}$B%3%^%s%I$O3F%F%9%H$G@5$7$/7k2L$rF~NO$9$k$3$H$,I,MW$G$"$k!%(B +$B$b$7%F%9%H$K@.8y$7$?$N$K<:GT$HF~NO$9$k$P!$ITDj$J>uBV$r8!CN$9$k$+$b$7$l$J(B +$B$$!%F~NO$NCf$GITDj$rFCDj$G$-$l$P!$%3%^%s%I$OFCDj$N%A%'%s%8%;%C%H$,(Bgood$B$+(B +$B$D(Bbad$B$G$"$k$HI=<($9$k!%$7$+$740`z$K$3$l$r9T$&$3$H$OIT2DG=$G!$4V0c$C$?%A%'(B +$B%s%8%;%C%H$r%P%0$N860x$@$HJs9p$9$k2DG=@-$,9b$$!%(B + +%\subsection{Automate as much as possible} +\subsection{$B$G$-$k8B$j<+F02=$9$k(B} + +%When I started using the \hgcmd{bisect} command, I tried a few times +%to run my tests by hand, on the command line. This is an approach +%that I, at least, am not suited to. After a few tries, I found that I +%was making enough mistakes that I was having to restart my searches +%several times before finally getting correct results. + +\hgcmd{bisect}$B%3%^%s%I$r;H$$$O$8$a$?;~!$?t2s!$%3%^%s%I%i%$%s$+$i<j$G%F%9(B +$B%H$r<B9T$7$?!%$3$NJ}K!$OE,$7$?J}K!$G$O$J$$!%?t2s$N%F%9%H$N8e$G!$:G=*E*$J(B +$B7k2L$rF@$k$?$a$K%5!<%A$r$d$j$J$*$5$J$1$l$P$J$i$J$$$3$H$K5$$E$/$3$H$,2?EY(B +$B$+$"$C$?!%(B + +%My initial problems with driving the \hgcmd{bisect} command by hand +%occurred even with simple searches on small repositories; if the +%problem you're looking for is more subtle, or the number of tests that +%\hgcmd{bisect} must perform increases, the likelihood of operator +%error ruining the search is much higher. Once I started automating my +%tests, I had much better results. + +\hgcmd{bisect}$B%3%^%s%I$r<j$G<B9T$7$F$$$?;~$N:G=i$NLdBj$O!$>.$5$J%j%]%8%H(B +$B%j$G$NC1=c$J%5!<%A$G$b5/$3$C$?!%$b$7LdBj$,$b$C$HNt0-$G!$(B\hgcmd{bisect}$B$,(B +$B<B9T$7$J$1$l$P$J$i$J$$%F%9%H$N?t$,A}$($l$P!$%*%Z%l!<%?$N%(%i!<$,5/$3$k2D(B +$BG=@-$O$:$C$H9b$/$J$k!%0lEY%F%9%H$r<+F02=$7$F$+$i$O!$$:$C$H$h$$7k2L$,F@$i(B +$B$l$k$h$&$K$J$C$?!%(B + +%The key to automated testing is twofold: +%\begin{itemize} +%\item always test for the same symptom, and +%\item always feed consistent input to the \hgcmd{bisect} command. +%\end{itemize} +%In my tutorial example above, the \command{grep} command tests for the +%symptom, and the \texttt{if} statement takes the result of this check +%and ensures that we always feed the same input to the \hgcmd{bisect} +%command. The \texttt{mytest} function marries these together in a +%reproducible way, so that every test is uniform and consistent. + +$B%F%9%H$r<+F02=$9$k%-!<$O(B2$B$D$"$k!%(B +\begin{itemize} + \item $B>o$KF1$8C{8u$r%F%9%H$9$k!%$=$7$F(B + \item $B>o$K(B\hgcmd{bisect}$B%3%^%s%I$K0l4S$7$?F~NO$r9T$&!%(B +\end{itemize} +$B>e$N%A%e!<%H%j%"%kNc$G$O(B\command{grep}$B%3%^%s%I$,C{8u$r%F%9%H$7$F$*$j!$(B +\texttt{if}$BJ8$,$3$N%A%'%C%/$N7k2L$r<h$j!$>o$KF1$8F~NO$,(B\hgcmd{bisect}$B%3(B +$B%^%s%I$K$J$5$l$k$h$&$K$J$C$F$$$?!%(B\texttt{mytest}$B4X?t$O!$:F8=2DG=$JJ}K!(B +$B$G!$$3$l$i$r7k$S$D$1!$$3$3$N%F%9%H$,0lMM$G0l4S$9$k$h$&$K$J$C$F$$$?!%(B + + +%\subsection{Check your results} +\subsection{$B7k2L$r%A%'%C%/$9$k(B} + +%Because the output of a \hgcmd{bisect} search is only as good as the +%input you give it, don't take the changeset it reports as the +%absolute truth. A simple way to cross-check its report is to manually +%run your test at each of the following changesets: +%\begin{itemize} +%\item The changeset that it reports as the first bad revision. Your +% test should still report this as bad. +%\item The parent of that changeset (either parent, if it's a merge). +% Your test should report this changeset as good. +%\item A child of that changeset. Your test should report this +% changeset as bad. +%\end{itemize} + +\hgcmd{bisect}$B%5!<%A$N=PNO$O!$%f!<%6$NF~NO$,@5$7$$>l9g$K8B$C$F@5$7$$$N$G!$(B +$B%3%^%s%I$,Js9p$9$k%A%'%s%8%;%C%H$r@dBP$K@5$7$$$H9M$($F$O$$$1$J$$!%Js9p$N(B +$B%/%m%9%A%'%C%/$r9T$&C1=c$JJ}K!$O!$0J2<$N%A%'%s%8%;%C%H$KBP$7$F!$<jF0$G%F(B +$B%9%H$r9T$&$3$H$G$"$k!%(B +\begin{itemize} + \item $B:G=i$N(Bbad$B%j%S%8%g%s$H$7$FJs9p$5$l$k%A%'%s%8%;%C%H!%$3$l$K$D$$$F%F(B + $B%9%H$O(Bbad$B$H$J$kH&$G$"$k(B + \item $B$=$N%A%'%s%8%;%C%H$N?F!J%^!<%8$5$l$F$$$k$J$iN>J}$N?F!K!%%F%9%H$O(B + good$B$K$J$kH&$G$"$k(B + \item $B:G=i$N(Bbad$B%j%S%8%g%s$H$7$FJs9p$5$l$k%A%'%s%8%;%C%H$N;R!%%F%9%H$O(B + bad$B$H$J$kH&$G$"$k(B +\end{itemize} + +%\subsection{Beware interference between bugs} +\subsection{$B%P%0F1;N$NAj8_43>D$KN10U$9$k(B} + +%It's possible that your search for one bug could be disrupted by the +%presence of another. For example, let's say your software crashes at +%revision 100, and worked correctly at revision 50. Unknown to you, +%someone else introduced a different crashing bug at revision 60, and +%fixed it at revision 80. This could distort your results in one of +%several ways. + +$B0l$D$N%P%0$KBP$9$k%5!<%A$,$=$NB>$N%P%0$NB8:_$G:.Mp$5$;$i$l$k$3$H$,M-$jF@(B +$B$k!%Nc$($P%=%U%H%&%'%"$,%j%S%8%g%s(B100$B$G%/%i%C%7%e$7!$%j%S%8%g%s(B50$B$GF0:n(B +$B$7$?$H$9$k!%$"$J$?$K$OL$CN$@$,!$C/$+JL$N?M$,%j%S%8%g%s(B60$B$GB>$N%/%i%C%7%e(B +$B$9$k%P%0$r;}$A9~$_!$%j%S%8%g%s(B80$B$G=$@5$7$?$H$9$k!%$3$l$O7k2L$rJ#?t$NJ}8~(B +$B$XY`6J$2F@$k!%(B + +%It is possible that this other bug completely ``masks'' yours, which +%is to say that it occurs before your bug has a chance to manifest +%itself.If you can't avoid that other bug (for example, it prevents +%your project from building), and so can't tell whether your bug is +%present in a particular changeset, the \hgcmd{bisect} command cannot +%help you directly. Instead, you can mark a changeset as untested by +%running \hgcmdargs{bisect}{--skip}. + +$B$3$NJL$N%P%0$,DI$$$+$1$F$$$k%P%0$r40A4$K%^%9%/$7$F$7$^$&$3$H$bM-$jF@$k!%(B +$BDI$$$+$1$F$$$k%P%0$,L@$i$+$K$J$kA0$K$3$l$,5/$-$k$3$H$bM-$jF@$k!%B>$N%P%0(B +$B$,KI$.@Z$l$J$$$J$i!$%P%0$,FCDj$N%A%'%s%8%;%C%H$K4^$^$l$k$H8@$&$3$H$b$G$-(B +$B$J$$!%(B\hgcmd{bisect}$B%3%^%s%I$OD>@\$"$J$?$r=u$1$k$3$H$,$G$-$J$$!%$=$NBe$o(B +$B$j!$$"$k%A%'%s%8%;%C%H$r(B\hgcmdargs{bisect}{--skip}$B$K$h$C$FL$%F%9%H$H%^!<(B +$B%/$9$k$3$H$,$G$-$k!%(B + + +%A different problem could arise if your test for a bug's presence is +%not specific enough. If you check for ``my program crashes'', then +%both your crashing bug and an unrelated crashing bug that masks it +%will look like the same thing, and mislead \hgcmd{bisect}. + +$B%P%0$N%F%9%H$,==J,$K>\:Y$G$J$+$C$?>l9g!$JL$NLdBj$,5/$3$jF@$k!%%W%m%0%i%`(B +$B$,%/%i%C%7%e$9$k$+$I$&$+$r%A%'%C%/$7$F$$$k;~!$DI@W$7$F$$$k%/%i%C%7%e%P%0(B +$B$H!$$=$l$H$OL54X78$J%/%i%C%7%e%P%0$,:.:_$F$$$k$H$3$l$i$OF1$8$K8+$($F$7$^(B +$B$$!$7k2LE*$K%A%'%C%/$r%^%9%/$7$F$7$^$$!$(B\hgcmd{bisect}$B$r%_%9%j!<%I$9$k!%(B + + +%Another useful situation in which to use \hgcmdargs{bisect}{--skip} is +%if you can't test a revision because your project was in a broken and +%hence untestable state at that revision, perhaps because someone +%checked in a change that prevented the project from building. + +\hgcmdargs{bisect}{--skip}$B$N;HMQ$,M-MQ$J$b$&0l$DJL$N>u67$O!$C/$+$,%S%k%I(B +$B$G$-$J$/$J$k$h$&$JJQ99$r%A%'%C%/%$%s$7$?$?$a$K!$;n$=$&$H$7$F$$$k%j%S%8%g(B +$B%s$,%S%k%I$G$-$:!$$=$N%j%S%8%g%s$r%F%9%H$G$-$J$$$h$&$J>l9g$G$"$k!%(B + + +%\subsection{Bracket your search lazily} +\subsection{$BC5:w$rBUBF$K%V%i%1%C%H$9$k(B} + +%Choosing the first ``good'' and ``bad'' changesets that will mark the +%end points of your search is often easy,but it bears a little +%discussion nevertheless. From the perspective of \hgcmd{bisect}, the +%``newest'' changeset is conventionally ``bad'', and the older +%changeset is ``good''. + +$B:G=i$N(Bgood$B$H(Bbad$B%A%'%s%8%;%C%H$NAH$rA*$S!$%5!<%AHO0O$r;XDj$9$k$N$OB?$/$N(B +$B>l9g4JC1$@$,!$<c43$N5DO@$NM>CO$,$"$k!%(B\hgcmd{bisect}$B$+$i8+$?;~!$:G?7$N%A%'(B +$B%s%8%;%C%H$O(Bbad$B$G!$8E$$%A%'%s%8%;%C%H$O(Bgood$B$H$J$k!%(B + +%If you're having trouble remembering when a suitable ``good'' change +%was, so that you can tell \hgcmd{bisect}, you could do worse than +%testing changesets at random. Just remember to eliminate contenders +%that can't possibly exhibit the bug (perhaps because the feature with +%the bug isn't present yet) and those where another problem masks the +%bug (as I discussed above). + +$BE,@Z$J(Bgood$B%A%'%s%8%;%C%H$r3P$($F$$$J$$;~!$(B\hgcmd{bisect}$B$K$=$l$r;XDj$9$k(B +$B$H!$%i%s%@%`$KA*$V$h$j$b0-$$C5:w$r9T$&2DG=@-$,$"$k!%%P%0$r<($5$J$$!J$*$=(B +$B$i$/%P%0$N$"$k5!G=$,<BAu$5$l$F$$$J$$!K%A%'%s%8%;%C%H$H!$B>$NLdBj$,DI@WCf(B +$B$N%P%0$r%^%9%/$7$F$7$^$&$h$&$J%A%'%s%8%;%C%H$N$_$r>C5n$9$k$3$H$r3P$($F$*(B +$B$/$Y$-$@!%(B + +%Even if you end up ``early'' by thousands of changesets or months of +%history, you will only add a handful of tests to the total number that +%\hgcmd{bisect} must perform, thanks to its logarithmic behaviour. + +\hgcmd{bisect}$B$,9T$o$J$1$l$P$J$i$J$$%F%9%H$N2s?t$O!$BP>]$H$9$k%A%'%s%8%;%C(B +$B%H$NBP?t$KHfNc$9$k$?$a!$?t%u7n$K5Z$VMzNr$NCf$N?t@i$N%A%'%s%8%;%C%H$NCf$K(B +$BBP$7$F$b>/?t$N%F%9%H$rDI2C$9$k$@$1$G:Q$`!%(B + + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/wdir-after-commit.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,394 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg5971" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docbase="/home/bos/hg/hgbook/en" + sodipodi:docname="wdir-after-commit.svg"> + <defs + id="defs5973"> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6445" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mstart" + style="overflow:visible"> + <path + id="path4855" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.4) translate(10,0)" /> + </marker> + <linearGradient + id="linearGradient6049"> + <stop + style="stop-color:#686868;stop-opacity:1;" + offset="0" + id="stop6051" /> + <stop + style="stop-color:#f0f0f0;stop-opacity:1;" + offset="1" + id="stop6053" /> + </linearGradient> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path4852" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6083" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6142" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-42.00893,-30.49544)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6193" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6216" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-6.0462,-0.664361)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6232" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,222.8399,50.85693)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6772" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,222.8399,50.85693)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.90509668" + inkscape:cx="390.0539" + inkscape:cy="690.49342" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showguides="true" + inkscape:guide-bbox="true" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="0" + inkscape:window-y="25"> + <sodipodi:guide + orientation="vertical" + position="-1.4285714" + id="guide6022" /> + </sodipodi:namedview> + <metadata + id="metadata5976"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + y="245.98355" + x="328.23956" + height="258.57144" + width="174.28572" + id="rect6047" + 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" /> + <g + id="g6261" + transform="translate(234,0)"> + <rect + y="258.7149" + x="114.11369" + height="44.537449" + width="134.53746" + id="rect5983" + 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" /> + <text + id="text5985" + y="284.47562" + x="138.7962" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="284.47562" + x="138.7962" + id="tspan5987" + sodipodi:role="line">dfbbb33f3fa3</tspan></text> + </g> + <rect + 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" + id="rect5996" + width="134.53746" + height="44.537449" + x="348.11371" + y="320.38159" /> + <text + xml:space="preserve" + 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" + x="372.7962" + y="346.1423" + id="text5998"><tspan + sodipodi:role="line" + id="tspan6000" + x="372.7962" + y="346.1423" + style="font-family:Courier">e7639888bb2f</tspan></text> + <rect + 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" + id="rect6004" + width="134.53746" + height="44.537449" + x="348.11371" + y="382.04825" /> + <text + xml:space="preserve" + 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" + x="370.65421" + y="407.80896" + id="text6006"><tspan + sodipodi:role="line" + id="tspan6008" + x="370.65421" + y="407.80896" + style="font-family:Courier">7b064d8bac5e</tspan></text> + <path + inkscape:connector-type="polyline" + id="path6018" + d="M 415.38242,303.62646 L 415.38242,320.00744" + 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" /> + <path + inkscape:connection-end="#rect6004" + inkscape:connector-type="polyline" + id="path6020" + d="M 415.38242,365.29315 L 415.38243,381.67412" + 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" /> + <rect + 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" + id="rect6039" + width="134.53746" + height="44.537449" + x="348.11359" + y="443.71487" /> + <text + xml:space="preserve" + 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" + x="372.79706" + y="469.47556" + id="text6041"><tspan + sodipodi:role="line" + id="tspan6043" + x="372.79706" + y="469.47556" + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> + <path + inkscape:connection-end="#rect6039" + inkscape:connector-type="polyline" + id="path6045" + d="M 415.38238,426.95981 L 415.38235,443.34087" + 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" /> + <text + xml:space="preserve" + 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" + x="327.66046" + y="231.36218" + id="text6102"><tspan + sodipodi:role="line" + id="tspan6104" + x="327.66046" + y="231.36218">History in repository</tspan></text> + <rect + y="245.94225" + x="557.28418" + height="204.51619" + width="174.36833" + id="rect6140" + 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" /> + <g + id="g6130" + transform="translate(262.3254,24.38544)"> + <rect + 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" + id="rect6106" + width="134.53746" + height="44.537449" + x="314.87415" + y="257.95059" /> + <text + xml:space="preserve" + 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" + x="339.55664" + y="283.7113" + id="text6108"><tspan + sodipodi:role="line" + id="tspan6110" + x="339.55664" + y="283.7113" + style="font-family:Courier">dfbbb33f3fa3</tspan></text> + </g> + <g + id="g6135" + transform="translate(263.0396,49.83106)"> + <rect + inkscape:transform-center-y="102.85714" + inkscape:transform-center-x="129.28571" + 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" + id="rect6112" + width="134.53746" + height="44.537449" + x="314.15985" + y="326.52203" /> + <text + inkscape:transform-center-y="102.7311" + inkscape:transform-center-x="128.69672" + xml:space="preserve" + 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" + x="338.84335" + y="352.28271" + id="text6114"><tspan + sodipodi:role="line" + id="tspan6116" + x="338.84335" + y="352.28271" + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> + </g> + <text + xml:space="preserve" + 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" + x="576.63208" + y="270.479" + id="text6118"><tspan + sodipodi:role="line" + id="tspan6120" + x="576.63208" + y="270.479">First parent</tspan></text> + <text + xml:space="preserve" + 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" + x="576.07544" + y="364.49615" + id="text6122"><tspan + sodipodi:role="line" + id="tspan6124" + x="576.07544" + y="364.49615">Second parent</tspan></text> + <text + xml:space="preserve" + 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" + x="556.61743" + y="231.36218" + id="text6195"><tspan + sodipodi:role="line" + id="tspan6197" + x="556.61743" + y="231.36218">Parents of working directory</tspan></text> + <path + 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" + d="M 576.82542,297.63008 L 483.02528,287.95831" + id="path6266" + inkscape:connector-type="polyline" + inkscape:connection-start="#g6130" + inkscape:connection-end="#g6261" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 665.12232,418.17579 L 665.12232,418.17579" + id="path6270" + inkscape:connector-type="polyline" /> + <text + xml:space="preserve" + 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" + x="316.86407" + y="275.6496" + id="text6573"><tspan + sodipodi:role="line" + id="tspan6575" + x="316.86407" + y="275.6496" + style="text-align:end;text-anchor:end">New</tspan><tspan + sodipodi:role="line" + x="316.86407" + y="290.6496" + id="tspan6577" + style="text-align:end;text-anchor:end">changeset</tspan></text> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/wdir-branch.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,418 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg5971" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docbase="/home/bos/hg/hgbook/en" + sodipodi:docname="wdir-branch.svg"> + <defs + id="defs5973"> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mstart" + style="overflow:visible"> + <path + id="path4855" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.4) translate(10,0)" /> + </marker> + <linearGradient + id="linearGradient6049"> + <stop + style="stop-color:#686868;stop-opacity:1;" + offset="0" + id="stop6051" /> + <stop + style="stop-color:#f0f0f0;stop-opacity:1;" + offset="1" + id="stop6053" /> + </linearGradient> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path4852" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6083" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6142" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-42.00893,-30.49544)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6193" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6216" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6232" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000473,0,0,0.790947,-11.16012,50.85693)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6445" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6974" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.911882,0,0,0.789965,-574.7896,51.22599)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6996" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000473,0,0,0.790947,112.8399,50.85693)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.90509668" + inkscape:cx="345.85973" + inkscape:cy="690.49342" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showguides="true" + inkscape:guide-bbox="true" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="0" + inkscape:window-y="25"> + <sodipodi:guide + orientation="vertical" + position="-1.4285714" + id="guide6022" /> + </sodipodi:namedview> + <metadata + id="metadata5976"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + y="246.06918" + x="64.325172" + height="204.26233" + width="333.2135" + id="rect6047" + 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" /> + <g + id="g1935"> + <rect + y="266.24374" + x="84.113708" + height="44.537449" + width="134.53746" + id="rect5996" + 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" /> + <text + id="text5998" + y="292.00446" + x="108.7962" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="292.00446" + x="108.7962" + id="tspan6000" + sodipodi:role="line">e7639888bb2f</tspan></text> + </g> + <g + id="g6976" + transform="translate(70,0)"> + <rect + y="327.9104" + x="40.113693" + height="44.537449" + width="134.53746" + id="rect6004" + 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" /> + <text + id="text6006" + y="353.67111" + x="62.654205" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="353.67111" + x="62.654205" + id="tspan6008" + sodipodi:role="line">7b064d8bac5e</tspan></text> + </g> + <path + inkscape:connector-type="polyline" + id="path6020" + d="M 160.92915,311.15532 L 167.83571,327.53627" + 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" + inkscape:connection-end="#g6976" + inkscape:connection-start="#g1935" /> + <rect + 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" + id="rect6039" + width="134.53746" + height="44.537449" + x="110.11359" + y="389.57703" /> + <text + xml:space="preserve" + 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" + x="134.79706" + y="415.33771" + id="text6041"><tspan + sodipodi:role="line" + id="tspan6043" + x="134.79706" + y="415.33771" + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> + <path + inkscape:connection-end="#rect6039" + inkscape:connector-type="polyline" + id="path6045" + d="M 177.38238,372.82195 L 177.38235,389.20303" + 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" /> + <rect + y="245.94225" + x="447.28412" + height="204.51619" + width="174.36833" + id="rect6140" + 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" /> + <g + id="g6130" + transform="translate(152.3254,24.38544)"> + <rect + 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" + id="rect6106" + width="134.53746" + height="44.537449" + x="314.87415" + y="257.95059" /> + <text + xml:space="preserve" + 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" + x="339.55664" + y="283.7113" + id="text6108"><tspan + sodipodi:role="line" + id="tspan6110" + x="339.55664" + y="283.7113" + style="font-family:Courier">ffb20e1701ea</tspan></text> + </g> + <g + id="g6135" + transform="translate(153.0396,49.83106)"> + <rect + inkscape:transform-center-y="102.85714" + inkscape:transform-center-x="129.28571" + 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" + id="rect6112" + width="134.53746" + height="44.537449" + x="314.15985" + y="326.52203" /> + <text + inkscape:transform-center-y="102.7311" + inkscape:transform-center-x="128.69672" + xml:space="preserve" + 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" + x="338.84335" + y="352.28271" + id="text6114"><tspan + sodipodi:role="line" + id="tspan6116" + x="338.84335" + y="352.28271" + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> + </g> + <text + xml:space="preserve" + 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" + x="466.63208" + y="270.479" + id="text6118"><tspan + sodipodi:role="line" + id="tspan6120" + x="466.63208" + y="270.479">First parent</tspan></text> + <text + xml:space="preserve" + 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" + x="466.07544" + y="364.49615" + id="text6122"><tspan + sodipodi:role="line" + id="tspan6124" + x="466.07544" + y="364.49615">Second parent</tspan></text> + <text + xml:space="preserve" + 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" + x="446.61743" + y="231.36218" + id="text6195"><tspan + sodipodi:role="line" + id="tspan6197" + x="446.61743" + y="231.36218">Parents of working directory</tspan></text> + <path + 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" + d="M 466.82542,300.21999 L 377.00207,294.39744" + id="path6266" + inkscape:connector-type="polyline" + inkscape:connection-start="#g6130" + inkscape:connection-end="#rect1925" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 665.12232,418.17579 L 665.12232,418.17579" + id="path6270" + inkscape:connector-type="polyline" /> + <g + id="g2845"> + <rect + y="266.24374" + x="242.09048" + height="44.537449" + width="134.53746" + id="rect1925" + 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" /> + <text + id="text1927" + y="292.00446" + x="266.77298" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="292.00446" + x="266.77298" + id="tspan1929" + sodipodi:role="line">ffb20e1701ea</tspan></text> + </g> + <path + inkscape:connector-type="polyline" + id="path1933" + d="M 260.89978,311.15532 L 225.84185,327.53627" + 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" + inkscape:connection-end="#g6976" /> + <text + xml:space="preserve" + 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" + x="109.45568" + y="231.4554" + id="text2837"><tspan + sodipodi:role="line" + id="tspan2839" + x="109.45568" + y="231.4554">Pre-existing head</tspan></text> + <text + xml:space="preserve" + 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" + x="237.54184" + y="231.4554" + id="text2841"><tspan + sodipodi:role="line" + id="tspan2843" + x="237.54184" + y="231.4554">Newly created head (and tip)</tspan></text> + <path + 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)" + d="M 148.05048,235.87482 L 149.94915,265.86962" + id="path2850" + inkscape:connector-type="polyline" + inkscape:connection-end="#g1935" /> + <path + 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)" + d="M 303.83495,238.08453 L 306.87874,265.86962" + id="path2852" + inkscape:connector-type="polyline" + inkscape:connection-end="#g2845" /> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/wdir-merge.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,425 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg5971" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docbase="/home/bos/hg/hgbook/en" + sodipodi:docname="wdir-merge.svg"> + <defs + id="defs5973"> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mstart" + style="overflow:visible"> + <path + id="path4855" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.4) translate(10,0)" /> + </marker> + <linearGradient + id="linearGradient6049"> + <stop + style="stop-color:#686868;stop-opacity:1;" + offset="0" + id="stop6051" /> + <stop + style="stop-color:#f0f0f0;stop-opacity:1;" + offset="1" + id="stop6053" /> + </linearGradient> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path4852" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6083" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6142" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-42.00893,-30.49544)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6193" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6216" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6232" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000473,0,0,0.790947,-11.16012,50.85693)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6445" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6974" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.911882,0,0,0.789965,-574.7896,51.22599)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6996" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000473,0,0,0.790947,112.8399,50.85693)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.28" + inkscape:cx="345.85973" + inkscape:cy="690.49342" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showguides="true" + inkscape:guide-bbox="true" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="0" + inkscape:window-y="25"> + <sodipodi:guide + orientation="vertical" + position="-1.4285714" + id="guide6022" /> + </sodipodi:namedview> + <metadata + id="metadata5976"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + y="246.06918" + x="64.325172" + height="204.26233" + width="333.2135" + id="rect6047" + 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" /> + <g + id="g6976" + transform="translate(70,0)"> + <rect + y="327.9104" + x="40.113693" + height="44.537449" + width="134.53746" + id="rect6004" + 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" /> + <text + id="text6006" + y="353.67111" + x="62.654205" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="353.67111" + x="62.654205" + id="tspan6008" + sodipodi:role="line">7b064d8bac5e</tspan></text> + </g> + <path + inkscape:connector-type="polyline" + id="path6020" + d="M 160.92915,311.15532 L 167.83571,327.53627" + 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" + inkscape:connection-end="#g6976" + inkscape:connection-start="#g1935" /> + <rect + 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" + id="rect6039" + width="134.53746" + height="44.537449" + x="110.11359" + y="389.57703" /> + <text + xml:space="preserve" + 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" + x="134.79706" + y="415.33771" + id="text6041"><tspan + sodipodi:role="line" + id="tspan6043" + x="134.79706" + y="415.33771" + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> + <path + inkscape:connection-end="#rect6039" + inkscape:connector-type="polyline" + id="path6045" + d="M 177.38238,372.82195 L 177.38235,389.20303" + 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" /> + <rect + y="245.94225" + x="447.28412" + height="204.51619" + width="174.36833" + id="rect6140" + 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" /> + <g + id="g6130" + transform="translate(152.3254,24.38544)"> + <rect + 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" + id="rect6106" + width="134.53746" + height="44.537449" + x="314.87415" + y="257.95059" /> + <text + xml:space="preserve" + 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" + x="339.55664" + y="283.7113" + id="text6108"><tspan + sodipodi:role="line" + id="tspan6110" + x="339.55664" + y="283.7113" + style="font-family:Courier">ffb20e1701ea</tspan></text> + </g> + <g + id="g6135" + transform="translate(153.0396,49.83106)"> + <rect + inkscape:transform-center-y="102.85714" + inkscape:transform-center-x="129.28571" + 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" + id="rect6112" + width="134.53746" + height="44.537449" + x="314.15985" + y="326.52203" /> + <text + inkscape:transform-center-y="102.7311" + inkscape:transform-center-x="128.69672" + xml:space="preserve" + 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" + x="338.84335" + y="352.28271" + id="text6114"><tspan + sodipodi:role="line" + id="tspan6116" + x="338.84335" + y="352.28271" + style="fill:black;fill-opacity:1;font-family:Courier">e7639888bb2f</tspan></text> + </g> + <text + xml:space="preserve" + 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" + x="466.63208" + y="270.479" + id="text6118"><tspan + sodipodi:role="line" + id="tspan6120" + x="466.63208" + y="270.479">First parent (unchanged)</tspan></text> + <text + xml:space="preserve" + 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" + x="466.07544" + y="364.49615" + id="text6122"><tspan + sodipodi:role="line" + id="tspan6124" + x="466.07544" + y="364.49615">Second parent</tspan></text> + <text + xml:space="preserve" + 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" + x="446.61743" + y="231.36218" + id="text6195"><tspan + sodipodi:role="line" + id="tspan6197" + x="446.61743" + y="231.36218">Parents of working directory</tspan></text> + <path + 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" + d="M 466.82542,300.21999 L 377.00207,294.39744" + id="path6266" + inkscape:connector-type="polyline" + inkscape:connection-start="#g6130" + inkscape:connection-end="#rect1925" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 665.12232,418.17579 L 665.12232,418.17579" + id="path6270" + inkscape:connector-type="polyline" /> + <g + id="g2845"> + <rect + y="266.24374" + x="242.09048" + height="44.537449" + width="134.53746" + id="rect1925" + 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" /> + <text + id="text1927" + y="292.00446" + x="266.77298" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="292.00446" + x="266.77298" + id="tspan1929" + sodipodi:role="line">ffb20e1701ea</tspan></text> + </g> + <path + inkscape:connector-type="polyline" + id="path1933" + d="M 260.89978,311.15532 L 225.84185,327.53627" + 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" + inkscape:connection-end="#g6976" /> + <text + xml:space="preserve" + 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" + x="109.45568" + y="231.4554" + id="text2837"><tspan + sodipodi:role="line" + id="tspan2839" + x="109.45568" + y="231.4554">Pre-existing head</tspan></text> + <text + xml:space="preserve" + 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" + x="237.54184" + y="231.4554" + id="text2841"><tspan + sodipodi:role="line" + id="tspan2843" + x="237.54184" + y="231.4554">Newly created head (and tip)</tspan></text> + <path + 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)" + d="M 148.05048,235.87482 L 149.94915,265.86962" + id="path2850" + inkscape:connector-type="polyline" + inkscape:connection-end="#g1935" /> + <path + 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)" + d="M 303.83495,238.08453 L 306.87874,265.86962" + id="path2852" + inkscape:connector-type="polyline" + inkscape:connection-end="#g2845" /> + <path + 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" + d="M 466.82545,379.17944 L 219.0253,307.95488" + id="path3016" + inkscape:connector-type="polyline" + inkscape:connection-start="#g6135" + inkscape:connection-end="#g1935" /> + <g + id="g1935"> + <rect + y="266.24374" + x="84.113708" + height="44.537449" + width="134.53746" + id="rect5996" + 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" /> + <text + id="text5998" + y="292.00446" + x="108.7962" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="292.00446" + x="108.7962" + id="tspan6000" + sodipodi:role="line">e7639888bb2f</tspan></text> + </g> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/wdir-pre-branch.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,364 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg5971" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docbase="/home/bos/hg/hgbook/en" + sodipodi:docname="wdir-branch.svg"> + <defs + id="defs5973"> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mstart" + style="overflow:visible"> + <path + id="path4855" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.4) translate(10,0)" /> + </marker> + <linearGradient + id="linearGradient6049"> + <stop + style="stop-color:#686868;stop-opacity:1;" + offset="0" + id="stop6051" /> + <stop + style="stop-color:#f0f0f0;stop-opacity:1;" + offset="1" + id="stop6053" /> + </linearGradient> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path4852" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6083" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6142" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-42.00893,-30.49544)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6193" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6216" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6232" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000473,0,0,0.790947,-11.16012,50.85693)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6445" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6974" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-314.246,50.85694)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6996" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000473,0,0,0.790947,-85.16012,50.85693)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.90509668" + inkscape:cx="390.0539" + inkscape:cy="690.49342" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showguides="true" + inkscape:guide-bbox="true" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="0" + inkscape:window-y="25"> + <sodipodi:guide + orientation="vertical" + position="-1.4285714" + id="guide6022" /> + </sodipodi:namedview> + <metadata + id="metadata5976"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + y="245.94225" + x="20.198257" + height="204.51619" + width="174.36833" + id="rect6047" + 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" /> + <rect + 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" + id="rect5996" + width="134.53746" + height="44.537449" + x="40.113693" + y="266.24374" /> + <text + xml:space="preserve" + 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" + x="64.796204" + y="292.00446" + id="text5998"><tspan + sodipodi:role="line" + id="tspan6000" + x="64.796204" + y="292.00446" + style="font-family:Courier">e7639888bb2f</tspan></text> + <g + id="g6976"> + <rect + y="327.9104" + x="40.113693" + height="44.537449" + width="134.53746" + id="rect6004" + 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" /> + <text + id="text6006" + y="353.67111" + x="62.654205" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="353.67111" + x="62.654205" + id="tspan6008" + sodipodi:role="line">7b064d8bac5e</tspan></text> + </g> + <path + inkscape:connection-end="#rect6004" + inkscape:connector-type="polyline" + id="path6020" + d="M 107.38242,311.15529 L 107.38242,327.53626" + 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" /> + <rect + 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" + id="rect6039" + width="134.53746" + height="44.537449" + x="40.113571" + y="389.57703" /> + <text + xml:space="preserve" + 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" + x="64.797073" + y="415.33771" + id="text6041"><tspan + sodipodi:role="line" + id="tspan6043" + x="64.797073" + y="415.33771" + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> + <path + inkscape:connection-end="#rect6039" + inkscape:connector-type="polyline" + id="path6045" + d="M 107.38238,372.82195 L 107.38235,389.20301" + 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" /> + <text + xml:space="preserve" + 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" + x="19.660461" + y="231.36218" + id="text6102"><tspan + sodipodi:role="line" + id="tspan6104" + x="19.660461" + y="231.36218">History in repository</tspan></text> + <rect + y="245.94225" + x="249.28412" + height="204.51619" + width="174.36833" + id="rect6140" + 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" /> + <g + id="g6130" + transform="translate(-45.67459,24.38544)"> + <rect + 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" + id="rect6106" + width="134.53746" + height="44.537449" + x="314.87415" + y="257.95059" /> + <text + xml:space="preserve" + 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" + x="339.55664" + y="283.7113" + id="text6108"><tspan + sodipodi:role="line" + id="tspan6110" + x="339.55664" + y="283.7113" + style="font-family:Courier">7b064d8bac5e</tspan></text> + </g> + <g + id="g6135" + transform="translate(-44.96042,49.83106)"> + <rect + inkscape:transform-center-y="102.85714" + inkscape:transform-center-x="129.28571" + 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" + id="rect6112" + width="134.53746" + height="44.537449" + x="314.15985" + y="326.52203" /> + <text + inkscape:transform-center-y="102.7311" + inkscape:transform-center-x="128.69672" + xml:space="preserve" + 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" + x="338.84335" + y="352.28271" + id="text6114"><tspan + sodipodi:role="line" + id="tspan6116" + x="338.84335" + y="352.28271" + style="fill:#979797;fill-opacity:1;font-family:Courier">000000000000</tspan></text> + </g> + <text + xml:space="preserve" + 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" + x="268.63208" + y="270.479" + id="text6118"><tspan + sodipodi:role="line" + id="tspan6120" + x="268.63208" + y="270.479">First parent</tspan></text> + <text + xml:space="preserve" + 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" + x="268.07544" + y="364.49615" + id="text6122"><tspan + sodipodi:role="line" + id="tspan6124" + x="268.07544" + y="364.49615">Second parent</tspan></text> + <text + xml:space="preserve" + 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" + x="248.61746" + y="231.36218" + id="text6195"><tspan + sodipodi:role="line" + id="tspan6197" + x="248.61746" + y="231.36218">Parents of working directory</tspan></text> + <path + 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" + d="M 268.82543,318.06163 L 175.02528,336.72225" + id="path6266" + inkscape:connector-type="polyline" + inkscape:connection-end="#g6976" + inkscape:connection-start="#g6130" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 665.12232,418.17579 L 665.12232,418.17579" + id="path6270" + inkscape:connector-type="polyline" /> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/wdir.svg Tue Apr 21 00:36:40 2009 +0900 @@ -0,0 +1,348 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg5971" + sodipodi:version="0.32" + inkscape:version="0.44.1" + sodipodi:docbase="/home/bos/hg/hgbook/en" + sodipodi:docname="wdir.svg"> + <defs + id="defs5973"> + <marker + inkscape:stockid="Arrow1Mstart" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mstart" + style="overflow:visible"> + <path + id="path4855" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none" + transform="scale(0.4) translate(10,0)" /> + </marker> + <linearGradient + id="linearGradient6049"> + <stop + style="stop-color:#686868;stop-opacity:1;" + offset="0" + id="stop6051" /> + <stop + style="stop-color:#f0f0f0;stop-opacity:1;" + offset="1" + id="stop6053" /> + </linearGradient> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0.0" + refX="0.0" + id="Arrow1Mend" + style="overflow:visible;"> + <path + id="path4852" + 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 " + style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;" + transform="scale(0.4) rotate(180) translate(10,0)" /> + </marker> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6083" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6142" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-42.00893,-30.49544)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6193" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-240.0462,-8.633237e-6)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6216" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6232" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000473,0,0,0.790947,-11.16012,50.85693)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient6049" + id="linearGradient6445" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.000474,0,0,0.790947,-240.246,50.9948)" + x1="333.91171" + y1="488.79077" + x2="508.94543" + y2="263.79077" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.90509668" + inkscape:cx="390.0539" + inkscape:cy="690.49342" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showguides="true" + inkscape:guide-bbox="true" + inkscape:window-width="906" + inkscape:window-height="620" + inkscape:window-x="0" + inkscape:window-y="25"> + <sodipodi:guide + orientation="vertical" + position="-1.4285714" + id="guide6022" /> + </sodipodi:namedview> + <metadata + id="metadata5976"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="g6431" + transform="translate(0,-0.137863)"> + <rect + 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" + id="rect6047" + width="174.36833" + height="204.51619" + x="94.198257" + y="246.08011" /> + <rect + y="266.38159" + x="114.11369" + height="44.537449" + width="134.53746" + id="rect5996" + 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" /> + <text + id="text5998" + y="292.1423" + x="138.7962" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="292.1423" + x="138.7962" + id="tspan6000" + sodipodi:role="line">e7639888bb2f</tspan></text> + <rect + y="328.04825" + x="114.11369" + height="44.537449" + width="134.53746" + id="rect6004" + 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" /> + <text + id="text6006" + y="353.80896" + x="136.65421" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="353.80896" + x="136.65421" + id="tspan6008" + sodipodi:role="line">7b064d8bac5e</tspan></text> + <path + 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" + d="M 181.38242,311.29315 L 181.38242,327.67412" + id="path6020" + inkscape:connector-type="polyline" + inkscape:connection-end="#rect6004" /> + <rect + y="389.71487" + x="114.11357" + height="44.537449" + width="134.53746" + id="rect6039" + 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" /> + <text + id="text6041" + y="415.47556" + x="138.79707" + 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" + xml:space="preserve"><tspan + style="fill:#979797;fill-opacity:1;font-family:Courier" + y="415.47556" + x="138.79707" + id="tspan6043" + sodipodi:role="line">000000000000</tspan></text> + <path + 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" + d="M 181.38238,372.95981 L 181.38235,389.34087" + id="path6045" + inkscape:connector-type="polyline" + inkscape:connection-end="#rect6039" /> + </g> + <text + xml:space="preserve" + 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" + x="93.660484" + y="231.36218" + id="text6102"><tspan + sodipodi:role="line" + id="tspan6104" + x="93.660484" + y="231.36218">History in repository</tspan></text> + <g + id="g6416"> + <rect + 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" + id="rect6140" + width="174.36833" + height="204.51619" + x="323.28412" + y="245.94225" /> + <g + transform="translate(28.32541,24.38544)" + id="g6130"> + <rect + y="257.95059" + x="314.87415" + height="44.537449" + width="134.53746" + id="rect6106" + 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" /> + <text + id="text6108" + y="283.7113" + x="339.55664" + 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" + xml:space="preserve"><tspan + style="font-family:Courier" + y="283.7113" + x="339.55664" + id="tspan6110" + sodipodi:role="line">e7639888bb2f</tspan></text> + </g> + <g + transform="translate(29.03958,49.83106)" + id="g6135"> + <rect + y="326.52203" + x="314.15985" + height="44.537449" + width="134.53746" + id="rect6112" + 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" + inkscape:transform-center-x="129.28571" + inkscape:transform-center-y="102.85714" /> + <text + id="text6114" + y="352.28271" + x="338.84335" + 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" + xml:space="preserve" + inkscape:transform-center-x="128.69672" + inkscape:transform-center-y="102.7311"><tspan + style="fill:#979797;fill-opacity:1;font-family:Courier" + y="352.28271" + x="338.84335" + id="tspan6116" + sodipodi:role="line">000000000000</tspan></text> + </g> + <text + id="text6118" + y="270.479" + x="342.63208" + 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" + xml:space="preserve"><tspan + y="270.479" + x="342.63208" + id="tspan6120" + sodipodi:role="line">First parent</tspan></text> + <text + id="text6122" + y="364.49615" + x="342.07544" + 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" + xml:space="preserve"><tspan + y="364.49615" + x="342.07544" + id="tspan6124" + sodipodi:role="line">Second parent</tspan></text> + </g> + <text + xml:space="preserve" + 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" + x="322.61746" + y="231.36218" + id="text6195"><tspan + sodipodi:role="line" + id="tspan6197" + x="322.61746" + y="231.36218">Parents of working directory</tspan></text> + <path + 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" + d="M 342.82543,299.89384 L 249.02528,293.36123" + id="path6266" + inkscape:connector-type="polyline" + inkscape:connection-start="#g6130" + inkscape:connection-end="#rect5996" /> + <path + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 665.12232,418.17579 L 665.12232,418.17579" + id="path6270" + inkscape:connector-type="polyline" /> + </g> +</svg>