# HG changeset patch # User Yoshiki Yazawa # Date 1240241800 -32400 # Node ID 019040fbf5f5ead2956524e5586a79f22186919b # Parent 5981a0f7540ae9d9d8cc481625984aeb34e3b420# Parent 29f0f79cf6146b747b2cbc9afe658f6b23ee6810 merged to upstream: phase 1 diff -r 29f0f79cf614 -r 019040fbf5f5 .hgtags --- /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 diff -r 29f0f79cf614 -r 019040fbf5f5 en/Makefile diff -r 29f0f79cf614 -r 019040fbf5f5 en/examples/run-example diff -r 29f0f79cf614 -r 019040fbf5f5 es/99defs.tex --- 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: diff -r 29f0f79cf614 -r 019040fbf5f5 ja/00book.tex --- /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: diff -r 29f0f79cf614 -r 019040fbf5f5 ja/99book.bib --- /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}}, +} diff -r 29f0f79cf614 -r 019040fbf5f5 ja/99defs.tex --- /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: diff -r 29f0f79cf614 -r 019040fbf5f5 ja/Makefile --- /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 $< > $@ diff -r 29f0f79cf614 -r 019040fbf5f5 ja/Makefile.orig --- /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 + diff -r 29f0f79cf614 -r 019040fbf5f5 ja/bookhtml.cfg --- /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{}\ShowPar} + {\endItem \def\endItem{\EndP\Tg}\HCode{
  • }} + {\HCode{}} +\def\textbullet{} + +\begin{document} + +\EndPreamble diff -r 29f0f79cf614 -r 019040fbf5f5 ja/branch.tex --- /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!%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$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$NA0$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$&$,!$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$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$rl9g$O!$%3%_%C(B +$B%H8e$KK:$l$:(B\hgcmd{tags}$B$rl9g!$%(%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}$Bl9g(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%]%8O$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$FA0$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/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}$Gl9g!$%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/(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(NOe$N%+%F%4%j$KB0(B +$B$9$J$i!$%V%i%s%A$rl9g$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$rA0$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$Gl9g$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]$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$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$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$Ne$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$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(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: diff -r 29f0f79cf614 -r 019040fbf5f5 ja/cmdref.py --- /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\w+)}') + optref_re = re.compile(r'^\\l?optref{(?P\w+)}' + r'(?:{(?P[^}])})?' + r'{(?P[^}]+)}') + + 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) diff -r 29f0f79cf614 -r 019040fbf5f5 ja/cmdref.tex --- /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}{$BH$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$Gl9g$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$BoI=<($7$J$$2?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$,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,$rJ}(B}$B$N?F$H$N:9J,$rJ}$N?F$H$N:9J,$r$,%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,$rl9g!$@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: diff -r 29f0f79cf614 -r 019040fbf5f5 ja/collab.tex --- /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 +$BH$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\: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$Ol9g$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$$^$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@$kl9g$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?$/$Ol=j$G$N3V@d$7$?:n6H$r9nI~$7$F$$$k!%%9%W%j%s%H$G$O!$!J4k6H$N2q(B +$B5D</?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$N3+H/Z$9$k(B +$B$3$H$b$G$-$k!%$5$i$K!$?75!G=$Nl=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(NOH$;$:B>$N3+H/@\(B +$BJQ99$r(Bpull$B$9$k$3$H$K$O0UL#$,$"$k!%$N%P%0=$@5$r9T$C$?$,!$$3$l$rCf(B +$B1{$N%j%]%8%H%j$G8x3+$7!$B>$N3+H/l9g$r9M$($k!%%@%a!<%8$N2DG=@-$r2<$2$k$?$a$K!$JL$N3+H/u67$G$O!$3+H/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$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$$$/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$lFHN)$G$"$k$?$a!$(B +$B3+H/%V%i%s%A$G$NIT0BDj$JJQ99$O!$3+H/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.$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=$,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$$,l9g!$H`$i$NJQ99$r%l%S%e!<$9$k$3$H$b$7$J(B +$B$$!%Be9Te$G!$%a%s%F%J!<$KJQ99$r$l$NBeM}?M$O%l%S%e!$lFH<+$N%"%W%m!<%A$reN.$K$N3+H/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/$G!$(BLinus$B$,$$$^$@$KH=$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$N3+H/o$K7c$7$$O@Ah$NCO$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(NOLL$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/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.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$rH!%(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!$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$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$$!%l9g$d!$6((B +$BNOl9g$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$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$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!$$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!$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$Kl9g$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$/$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%/$Nl9g$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~$JpJs(B +$B$rl9g$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$rl9g$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-$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!$$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!<%Hl(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!%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\$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$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$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$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$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!$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$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 + AllowOverride FileInfo AuthConfig Limit + Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec + + Order allow,deny + Allow from all + + + Order deny,allow + Deny from all + + +\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$rl9g$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. + +$Bl9g$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.l(B +$B9g$b(BApache$B$N%;%/%7%g%s$rFI$`I,MW$,$"$k$H$$$&$3$H$G$b$"$k!%!KI. "" ) +\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$No$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$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!$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$rA[%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(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\: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: diff -r 29f0f79cf614 -r 019040fbf5f5 ja/concepts.tex --- /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: diff -r 29f0f79cf614 -r 019040fbf5f5 ja/daily.tex --- /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$rl9g!$(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$KuBV$N%9%J%C%W%7%g%C%H$rBP0EL[$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$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$,!$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/