# HG changeset patch # User Yoshiki Yazawa # Date 1247160737 -32400 # Node ID 896ab6eaf1c6b6d6028ffdec642767f154bf28b1 # Parent 5276f40fca1c9ffc02c903192d619db4729cd8f7# Parent 5225ec140003740b7b4bf745bc901276f6dc7c48 merged diff -r 5225ec140003 -r 896ab6eaf1c6 .hgtags --- a/.hgtags Thu May 14 21:06:12 2009 -0700 +++ b/.hgtags Fri Jul 10 02:32:17 2009 +0900 @@ -1,1 +1,5 @@ +b0db5adf11c1e096c4b08f42befb8e7e18120ed0 japanese root +b0db5adf11c1e096c4b08f42befb8e7e18120ed0 ja_root +0000000000000000000000000000000000000000 japanese root +ec889c068d461b4f9be324d6f2f224708b85c7cb finished draft translation 18131160f7ee3b81bf39ce2c58f762b8d671cef3 submitted diff -r 5225ec140003 -r 896ab6eaf1c6 en/Makefile diff -r 5225ec140003 -r 896ab6eaf1c6 en/examples/run-example diff -r 5225ec140003 -r 896ab6eaf1c6 es/99defs.tex --- a/es/99defs.tex Thu May 14 21:06:12 2009 -0700 +++ b/es/99defs.tex Fri Jul 10 02:32:17 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 5225ec140003 -r 896ab6eaf1c6 ja/00book.tex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/00book.tex Fri Jul 10 02:32:17 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, 2008, 2009 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 5225ec140003 -r 896ab6eaf1c6 ja/99book.bib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/99book.bib Fri Jul 10 02:32:17 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 5225ec140003 -r 896ab6eaf1c6 ja/99defs.tex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/99defs.tex Fri Jul 10 02:32:17 2009 +0900 @@ -0,0 +1,145 @@ +% 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}} +\newcommand{\excode}[1]{\VerbatimInput[frame=single,numbers=left,commandchars=\\\{\}]{../contrib/#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 5225ec140003 -r 896ab6eaf1c6 ja/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/Makefile Fri Jul 10 02:32:17 2009 +0900 @@ -0,0 +1,219 @@ +# 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 \ + 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 5225ec140003 -r 896ab6eaf1c6 ja/Makefile.orig --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/Makefile.orig Fri Jul 10 02:32:17 2009 +0900 @@ -0,0 +1,240 @@ +# 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 \ + 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 5225ec140003 -r 896ab6eaf1c6 ja/Makefile.tex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/Makefile.tex Fri Jul 10 02:32:17 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-tex + cd examples && ./run-example-tex $(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 5225ec140003 -r 896ab6eaf1c6 ja/bookhtml.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/bookhtml.cfg Fri Jul 10 02:32:17 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 5225ec140003 -r 896ab6eaf1c6 ja/branch.tex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/branch.tex Fri Jul 10 02:32:17 2009 +0900 @@ -0,0 +1,725 @@ +%\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 in +%the root of your repository 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$?;~!$%j%]%8%H%j$N%k!<%H$K$"$k(B\sfilename{.hgtags}$B$H$$$&%U%!%$(B +$B%k$K%?%0$,J]B8$5$l$F$$$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 5225ec140003 -r 896ab6eaf1c6 ja/cmdref.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/cmdref.py Fri Jul 10 02:32:17 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 5225ec140003 -r 896ab6eaf1c6 ja/cmdref.tex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/cmdref.tex Fri Jul 10 02:32:17 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 5225ec140003 -r 896ab6eaf1c6 ja/collab.tex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/collab.tex Fri Jul 10 02:32:17 2009 +0900 @@ -0,0 +1,2108 @@ +%\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, there are several good ways to do this. + +$B<+J,$N%j%]%8%H%j$K%&%'%V%$%s%?%U%'!<%9$rMQ0U$9$k>l9g!$$$$/$D$+NI$$J}K!$,(B +$B$"$k!%(B + +%The easiest and fastest way to get started in an informal environment is +%to use 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. + +$B8x<0$G$O$J$$4D6-$G9T$&:G$b4JC1$GAa$$J}K!$O!$(B\hgcmd{serve}$B%3%^%s%I$r;H$&J}(B +$BK!$G!$$3$l$OC;4|4V$N(B``$B\:Y$J(B +$B;HMQK!$K$D$$$F$O2<5-$N(B~\ref{sec:collab:serve}$B@a$r;2>H$N$3$H!%%j%]%8%H%j$r(B +$BD94|4V$K$o$?$j1JB3E*$K%5!<%S%9$7$?$$>l9g$O!$(BMercurial$B$KFbB"$N(BCGI(Common +Gateway Interface)$B%5%]!<%H$rMxMQ$9$k$3$H$,$G$-$k!%(B CGI$B$N@_Dj$K$D$$$F(B +$B$O(B~\ref{sec:collab:cgi}$B@a$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 organizing 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 or a hacking session in a coffee shop are the perfect places 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$d%3!<%R!<%7%g%C%W$G$N%O%C%-%s%0%;%C%7%g%s$O(B\hgcmd{serve}$B%3%^%s(B +$B%I$r;H$&$N$^$5$K$K$&$C$F$D$1$N4D6-$G$"$k!%(B \hgcmd{serve}$B$O$N3+H/Z$9$k$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\emph{n}$B8D$N0[$J$C$?%j%]%8%H%j$N$I$l$+$i(Bpull$B$r(B +$B9T$($P$$$$$+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%K!<%:$rK~$?(B +$B$9$3$H$,$G$-$k!%(B + +%\subsection{A hosted central repository} +\subsection{$B%[%9%F%#%s%0$K$h$kCf1{%j%]%8%H%j%5!<%S%9(B} + +%A wonderful thing about public hosting services like Bitbucket +%(\url{http://bitbucket.org}) is that not only do they handle the +%fiddly server configuration details, such as user accounts, +%authentication, and secure wire protocols, they provide additional +%infrastructure to make this model work well. + +Bitbucket(\url{http://bitbucket.org})$B$N$h$&$J8x6&$N%[%9%F%#%s%0%5!<%S%9$G(B +$B$O!$%f!<%6%"%+%&%s%H$N@_Dj!$G'>Z!$%;%-%e%"$JDL?.%W%m%H%3%k$J$I$NLLE]$J%5!<(B +$B%P@_Dj$r8*Be$j$7$F$/$l$k$@$1$G$J$/!$$3$N%b%G%k$,$b$C$HNI$/5!G=$9$k$?$a$N(B +$B%$%s%U%i$rDs6!$7$F$$$k!%(B + +%For instance, a well-engineered hosting service will let +%people clone their own copies of a repository with a single +%click. This lets people work in separate spaces and share +%their changes when they're ready. + +$BNc$($P!$$&$^$/9=@.$5$l$?%[%9%F%#%s%0%5!<%S%9$O!$(B1$B%/%j%C%/$G%j%]%8%H%j$N%3(B +$B%T!<$r%/%m!<%s$G$-$k$h$&$K$J$C$F$$$k!%$3$l$K$h$j!$JL!9$N>l=j$G:n6H$r9T(B +$B$$!$=`Hw$,=PMhl9g!$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 into the stable branch. + +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, we 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} + +%If we need to make a change to the stable branch, we can then clone +%\emph{that} repository, make our changes, commit, and push our 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 we 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$9$k$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 + +%We'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, we can simply pull and merge changes from the stable to the +%main branch, and Mercurial will bring those bugfixes in for us. +%\interaction{branching.merge} + +$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 organized 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 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. + +$BNI$$J,;6%j%S%8%g%s%3%s%H%m!<%k%D!<%k$O!$N>J}$N%b%G%k$r%5%]!<%H$9$k!%%f!<(B +$B%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 sharing +%changes with 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 the name of both a command and a +%network protocol that let 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$KFk@w$_$N$J$$%f!<%6$N$?$a$K@bL@$9$k$H!$(Bssh$B$OB>$N%3%s%T%e!<%?$H0BA4$K(B +$BDL?.$r9T$&$?$a$N%3%^%s%I$*$h$S%M%C%H%o!<%/%W%m%H%3%k$NL>>N$G$"$k!%(B +Mercurial$B$G;H$&$?$a$K$O!$(B1$B$D0J>e$N%"%+%&%s%H$r%5!<%P$K@_Dj$7!$%j%b!<%H%f!<(B +$B%6$,%m%0%$%s$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, the TortoiseHg package is bundled with a version of Simon +%Tatham's excellent \command{plink} command, and you should not +%need to do any further configuration. + +Windows$B$G$O!$(BTortoiseHg$B%Q%C%1!<%8$K(BSimon Tatham$B$K$h$kM%$l$?%3%^%s%I$G$"$k(B +\command{plink}$B$,F1:-$5$l$F$*$j!$2?$b@_Dj$9$k$3$H$J$/MxMQ2DG=$G$"$k!%(B + +%\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. + +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!%(B + +\begin{note} +%Key pairs are not mandatory +$B80%Z%"$OI,?\$G$O$J$$(B + +%Mercurial knows nothing about ssh authentication or key pairs. You can, +%if you like, safely ignore this section and the one that follows until +%you grow tired of repeatedly typing ssh passwords. + +Mercurial$B<+?H$O(Bssh$B$G$NG'>Z$d80%Z%"$K$D$$$F$O0l@Z4XCN$7$J$$!%(Bssh$B%Q%9%o!<%I(B +$B$NF~NO$K7q$`$3$H$,$J$1$l$P!$$3$N@a$H8e$N@a$rL5;k$7$F$b:9$7;Y$($J$$!%(B +\end{note} + +\begin{itemize} +% \item On a Unix-like system, the \command{ssh-keygen} command will do +% the trick. + \item Unix$B7O%7%9%F%`$G$O!$(B\command{ssh-keygen}$B%3%^%s%I$G80%Z%"$r:n@.$G$-$k!%(B +% \item On Windows, if you're using TortoiseHg, you may need to download +% a command named \command{puttygen} from the PuTTY web site +% \url{http://www.chiark.greenend.org.uk/~sgtatham/putty} to +% generate a key pair. See the \command{puttygen} documentation +% \url{http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter8.htm} +% for details of how use the command. + \item Windows$B$G(BTortoiseHg$B$r;H$C$F$$$k$N$G$"$l$P!$(BPuTTY$B$N%&%'%V%5%$%H(B + \url{http://www.chiark.greenend.org.uk/~sgtatham/putty}$B$+$i%@%&%s(B + $B%m!<%I$G$-$k(B\command{puttygen}$B$H$$$&%3%^%s%I$G80%Z%"(B + $B$r:n@.$G$-$k!%$3$N%3%^%s%I$N;HMQK!$N>\:Y$K$D$$$F$O(B + \command{puttygen}$B$N%I%-%e%a%s%H(B + \url{http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter8.htm} + $B$r;2>H$5$l$?$$!%(B +\end{itemize} + +%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$rpageant +%command acts as the agent. As with \command{puttygen}, you'll need to +%download \command{pageant} +%\url{http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html} +%from the PuTTY web site and read its documentation +%\url{http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter9.html#pageant}. +%The \command{pageant} command adds an icon to your system tray that will +%let you manage stored passphrases. + +Windows$B$G(BTortoiseHg$B$r;H$C$F$$$k>l9g$O!$(B\command{pageant}$B%3%^%s%I$,%(!<%8%'(B +$B%s%H$H$7$FF0:n$9$k!%(B \command{puttygen}$B%3%^%s%I$N;~$HF1MM$K(B +\command{pageant}$B%3%^%s%I$O(BPuTTY$B$N%&%'%V%5%$%H(B +\url{http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html}$B$+$i(B +$B%@%&%s%m!<%I$G$-$k!%;HMQK!$K$D$$$F$O(B +\url{http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter9.html#pageant} +$B$r;2>H$5$l$?$$!%(B \command{pageant}$B%3%^%s%I$O5-21$7$?%Q%9%U%l!<%:$r4IM}$9(B +$B$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, a variety of +%things 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!$?7$?$K;H$$;O$a$k>l9g!$MM!9$JIT6q9g$,(B +$B5/$-$k2DG=@-$,$"$k!%(BMercurial$B$H6&$KF0$+$9>l9g!$$5$i$KB?$/$,BT$A9=$($F$$(B +$B$k!%$3$l$i$NKX$s$I$,%/%i%$%"%s%HB&$G$O$J$/%5!<%PB&$G5/$-$k!%$7$+$70lEY$-(B +$B$A$s$HF0:n$9$k@_Dj$r$7$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. +%Here is how to do so for regular \command{ssh} on Unix-like systems, for +%example. + +\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 Unix$B7O%7%9(B +$B%F%`$GDL>o$N(B\command{ssh}$B%3%^%s%I$r@_Dj$9$kNc$Ol9g!$%5!<%P$X$N(B +$B@\B3;~$K>o$K05=L$r;HMQ$9$k$h$&$K@_Dj$9$k$3$H$,$G$-$k!%@_Dj$K$O(B +\sfilename{.ssh/config}$B%U%!%$%k!JB8:_$7$J$$>l9g$O:n@.$9$k!K$r$N%(%$%j%"%9(B\texttt{hg}$B$rDj5A$9$k!%$3$N%[%9%HL>$r(B +\command{ssh}$B$N%3%^%s%I%i%$%s$^$?$O(BMercurial \texttt{ssh}-$B%W%m%H%3%k$G$N(B +URL$B$G;HMQ$9$k$H!$(B\command{ssh}$B%3%^%s%I$O(B\texttt{hg.example.com}$B$X$N@\B3$K(B +$B05=L$rMQ$$$k!%$3$NJ}K!$GC;=L7A$N%[%9%HL>$H05=L$N@_Dj$rF1;~$K9T$&$3$H$,$G(B +$B$-$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} + +%The simplest way to host one or more repositories in a permanent way is +%to use a web server and Mercurial's CGI support. + +$B0l$D$^$?$OJ#?t$N%j%]%8%H%j$r1JB3E*$K%5!<%S%9$9$k:G$b4JC1$JJ}K!$O!$%&%'%V(B +$B%5!<%P$G(BMercurial$B$N(BCGI$B%5%]!<%H$rMxMQ$9$k$3$H$G$"$k!%(B + +%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} +High pain tolerance required + +%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$7$rB3$1$k$3$H$,2fK}$G$-$J$+$C$?$j!$<+A0$N%5!<%S%9$,I,?\(B +$B$G$J$+$C$?$j$9$k>l9g$O!$A0=R$N8x6&%[%9%F%#%s%0%5!<%S%9$r8!F$$7$?J}$,NI$$(B +$B$@$m$&!%(B + +\end{note} + +%\subsection{Web server configuration checklist} +\subsection{Web$B%5!<%P@_Dj$N%A%'%C%/%j%9%H(B} + +%Before you continue, do take a few moments to check a few aspects of +%your system's setup. +$B$3$3$+$i@h$X?J$`A0$K!$FIl9g!$$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} +%Beware duplicate virtual paths + +%If several repositories have the same virtual path, +%\sfilename{hgwebdir.cgi} will not report an error. Instead, it will +%behave unpredictably. +%\end{note} + +\begin{note} +$B2>A[%Q%9$N=EJ#$KCm0U(B + +$BJ#?t$N%j%]%8%H%j$,F1$82>A[%Q%9$r;}$D>l9g$G$b(B\sfilename{hgwebdir.cgi}$B$O%(%i!<(B +$B$rI=<($7$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; see below for details. + +$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!%!J>\:Y$K$D$$$F$O2<5-$r;2>H!%!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 several web +% templates. +% +% \begin{itemize} +% \item \texttt{coal} is monochromatic. +% \item \texttt{gitweb} emulates the visual style of git's +% web interface. +% \item \texttt{monoblue} uses solid blues and greys. +% \item \texttt{paper} is the default. +% \item \texttt{spartan} was the default for a long time. +% \end{itemize} +% +% 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$$$/$D$+$N(B + $B%&%'%V%F%s%W%l!<%H$,F1:-$5$l$F$$$k!%(B + + \begin{itemize} + \item \texttt{coal} $BC1?'$N%F%s%W%l!<%H!%(B + \item \texttt{gitweb} git$B$N%&%'%V%$%s%?!<%U%'!<%9$rLOJo$7(B + $B$?%G%6%$%s$N$b$N!%(B + \item \texttt{monoblue} $BC1?'$N@D$H%0%l!\:Y(B + $B$O(B~\ref{chap:template}$B$r;2>H$N$3$H!%$3$3$G$O(B\texttt{gitweb}$B%9(B + $B%?%$%k$rM-8z$K$9$kJ}K!$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 + +%\section{System-wide configuration} +\section{$B%7%9%F%`%o%$%I$N@_Dj(B} + +%On Unix-like systems shared by multiple users (such as a server to which +%people publish changes), it often makes sense to set up some global +%default behaviors, such as what theme to use in web interfaces. + +$BJ#?t$N%f!<%6$,;HMQ$9$k(BUnix$B7O$N%7%9%F%`!J%f!<%6$,JQ99$r8x3+$9$k%5!<%P$J(B +$B$I!K$G$O!$%&%'%V%$%s%?%U%'!<%9$G;HMQ$9$k%F!<%^$N$h$&$K!$%7%9%F%`A4BN$G$N(B +$B%G%U%)%k%H$N5sF0$rDj5A$9$k$H$h$$>l9g$,$"$k!%(B + +%If a file named \filename{/etc/mercurial/hgrc} exists, Mercurial will +%read it at startup time and apply any configuration settings it finds in +%that file. It will also look for files ending in a \texttt{.rc} +%extension in a directory named \filename{/etc/mercurial/hgrc.d}, and +%apply any configuration settings it finds in each of those files. + +\filename{/etc/mercurial/hgrc}$B$H$$$&%U%!%$%k$,$"$k$H!$(BMercurial$B$O5/F0;~$K(B +$B$3$l$rFI$_!$A4$F$N@_Dj$rE,MQ$9$k!%$^$?!$(B\filename{/etc/mercurial/hgrc.d} +$B%G%#%l%/%H%jFb$N%U%!%$%kL>$,(B\texttt{.rc}$B$G=*$k%U%!%$%k$rC5$7!$=q$+$l$?@_(B +$BDj$rE,MQ$9$k!%(B + +%\subsection{Making Mercurial more trusting} +\subsection{Mercurial$B$N?.Mj@-$r>e$2$k(B} + +%One situation in which a global \filename{hgrc} can be useful is if +%users are pulling changes owned by other users. By default, Mercurial +%will not trust most of the configuration items in a \filename{.hg/hgrc} +%file inside a repository that is owned by a different user. If we clone +%or pull changes from such a repository, Mercurial will print a warning +%stating that it does not trust their \filename{.hg/hgrc}. + +$B%7%9%F%`A4BN$N(B\filename{hgrc}$B%U%!%$%k$,M-MQ$J>l9g$N0lNc$K!$B>$N%f!<%6$,=j(B +$BM-?t(Br$B%j%]%8%H%j$+$i(Bpull$B$9$k>l9g$,$"$k!%%G%U%)%k%H$G$O(BMercurial$B$OJL$N%f!<(B +$B%6$N=jM-$9$k%j%]%8%H%jFb$K$"$k(B\filename{.hg/hgrc}$B%U%!%$%k$N$[$H$s$I$N9`L\(B +$B$r?.Mj$7$J$$!%$=$N$h$&$J%j%]%8%H%j$+$i%/%m!<%s$dJQ99$N(Bpull$B$r9T$&(B +$B$H!$(BMercurial$B$O(B\filename{.hg/hgrc}$B$r?.Mj$7$J$$$H$$$&7Y9p$rI=<($9$k!%(B + +%If everyone in a particular Unix group is on the same team and +%\emph{should} trust each other's configuration settings, or we want to +%trust particular users, we can override Mercurial's skeptical defaults +%by creating a system-wide \filename{hgrc} file such as the following: + +Unix$B$GFCDj$N%0%k!<%W$KF~$C$F$$$k%f!<%6A4$F$,F1$8%A!<%`$KB0$7!$8_$$$KB>$N(B +$B%f!<%6$N@_Dj$r?.Mj(B\emph{$B$9$Y$-(B}$B>l9g$d!$FCDj$N%f!<%6$?$A$N@_Dj$r?.Mj$9$Y$-(B +$B>l9g$O!$\:Y$rM}2r$9$k$3$H$OI,$:$7$bI,(B +$BMW$G$O$J$/!$$3$N>O$rHt$P$7$F$b:9$7;Y$($J$$!%$7$+$7I.e$G2?$,5/$-$F$$$k$N$+$K$D$$$F%b%G%k$r0U<1$7$F$$$k$3$H$OM-MQ(B +$B$G$"$k$H9M$($F$$$k!%(B + +%Being able to understand what's going on behind the scenes 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. + +$BIqBfN"$G2?$,5/$3$C$F$$$k$N$+M}2r$G$-$k$H!$I./$J(B +$B$/$J$C$?!%(B + +%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. + +$B$3$N>O$G$O$^$:(BMercurial$B$N@_7W$N%3%"%3%s%;%W%H$r%+%P!<$9$k!%$=$7$Fe$N(B +$B$$$/$D$+$N6=L#?<$$E@$N>\:Y$K$D$$$F5DO@$9$k!%(B + +%\section{Mercurial's historical record} +\section{Mercurial$B$NMzNr5-O?(B} + +%\subsection{Tracking the history of a single file} +\subsection{$B%U%!%$%kMzNr$NDI@W(B} + +%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. + +Mercurial$B$O%U%!%$%k$X$NJQ99$rDI@W$9$k;~!$%U%!%$%k$NMzNr$r(B\emph{filelog}$B$H(B +$B8F$P$l$k%a%?%G!<%?%*%V%8%'%/%H$K3JG<$9$k!%%U%!%$%k%m%0Fb$N3F!9$N%(%s%H%j(B +$B$O!$DI@WBP>]$N%U%!%$%k$N%j%S%8%g%s$r:F7z$9$k$N$K==J,$J>pJs$r;}$D!%%U%!%$(B +$B%k%m%0$O(B\sdirname{.hg/store/data}$B%G%#%l%/%H%j$K%U%!%$%k$H$7$FJ]B8$5$l$k!%(B +$B%U%!%$%k%m%0$O%j%S%8%g%s%G!<%?$H(BMercurial$B$,%j%S%8%g%s$r8zN(E*$K8+$D$1$i$l(B +$B$k$h$&$K$9$k$?$a$N%$%s%G%C%/%9$N(B2$BpJs$r;}$D!%(B + +%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}. + +$B%5%$%:$NBg$-$J%U%!%$%k$d!$KDBg$JMzNr$r;}$D%U%!%$%k$O!$%G!<%?$,(B +(``\texttt{.d}'' suffix) $B$*$h$S%$%s%G%C%/%9(B (``\texttt{.i}'' suffix)$B$N%U%!(B +$B%$%k$KJ,3d$5$l$?(Bfilelog$B$r;}$D!%%5%$%:$,>.$5$/!$MzNr$NBg$-$/$J$$%U%!%$%k$O(B +$B%j%S%8%g%s%G!<%?$H%$%s%G%C%/%9$,(B1$B$D$N(B``\texttt{.i}''$B%U%!%$%k$K7k9g$5$l$F(B +$B$$$k!%%o!<%-%s%0%G%#%l%/%H%jFb$N%U%!%$%k$H%j%]%8%H%jFb$NMzNr$rDI@W$9$k(B +filelog$B$H$NBP1~$r?^(B~\ref{fig:concepts:filelog}$B$K<($9!%(B + +\begin{figure}[ht] + \centering +% \grafix{filelog} + \includegraphics{filelog} +% \caption{Relationships between files in working directory and +% filelogs in repository} + \caption{$B%o!<%-%s%0%G%#%l%/%H%jFb$N%U%!%$%k$H%j%]%8%H%j$N%U%!%$%k%m%0(B + $B$N4X78(B} + \label{fig:concepts:filelog} +\end{figure} + +%\subsection{Managing tracked files} +\subsection{$BDI@W$5$l$F$$$k%U%!%$%k$N4IM}(B} + +%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. + +Mercurial$B$O(B\emph{$B%^%K%U%'%9%H(B}$B$H8F$P$l$k9=B$$rMQ$$$F!$DI@W$9$Y$-%U%!%$%k(B +$B$N>pJs$r=8$a$F$$$k!%%^%K%U%'%9%HFb$N3F!9$N%(%s%H%j$O!$C10l$N%A%'%s%8%;%C(B +$B%HFb$KB8:_$9$k%U%!%$%k$N>pJs$r;}$C$F$$$k!%%(%s%H%j$O$I$N%U%!%$%k$,%A%'%s(B +$B%8%;%C%H$KB8:_$7$F$$$k$+!$$=$l$i$N%j%S%8%g%s$,2?$G$"$k$N$+$H$$$&>pJs$H!$(B +$B$$$/$D$+$NB>$N%U%!%$%k%a%?%G!<%?$r5-O?$7$F$$$k!%(B + +%\subsection{Recording changeset information} +\subsection{$B%A%'%s%8%;%C%H>pJs$N5-O?(B} + +%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. + +\emph{changelog}$B$O3F!9$N%A%'%s%8%;%C%H$N>pJs$r;}$D!%3F!9$N%j%S%8%g%s5-O?(B +$B$O!$C/$,JQ99$r%3%_%C%H$7$?$N$+!$%A%'%s%8%;%C%H$N%3%a%s%H!$JQ99$K4XO"$7$?(B +$BB>$N>pJs!$;HMQ$5$l$k%^%K%U%'%9%H$N%j%S%8%g%s$r;}$D!%(B + +%\subsection{Relationships between revisions} +\subsection{$B%j%S%8%g%s4V$N4X78(B} + +%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. + +$B%A%'%s%8%m%0!$%^%K%U%'%9%H!$%U%!%$%k%m%0Fb$G!$3F!9$N%j%S%8%g%s$OD>@\$N?F(B +$B!J$"$k$$$O%^!<%8$N>l9g$O$=$NN>?F!K$X$N%]%$%s%?$r;}$D!%(B +$B$9$G$K=R$Y$?$h$&$K!$$3$N9=B$$K8=$l$k%j%S%8%g%s$N4V$K$O4X78$,$"$j!$K\l9g$O!$%A%'%s%8%m%0Fb$G$3$l$i$N%A%'%s%8%;%C%H$rI=(B +$B$9%(%s%H%j$OF1$8%P!<%8%g%s$N%^%K%U%'%9%H$r<($9!%(BMercurial$B$,DI@W$9$k%U%!%$(B +$B%k$,!$(B2$B$D$N%A%'%s%8%;%C%H4V$GJQ2=$7$J$+$C$?>l9g$O!$(B 2$B$D$N%^%K%U%'%9%H$N%j(B +$B%S%8%g%s$G!$$=$N%U%!%$%k$r<($9%(%s%H%j$O%U%!%$%k%m%0$NF1$8%j%S%8%g%s$r<((B +$B$9!%(B + +%\section{Safe, efficient storage} +\section{$B0BA4$+$D8zN(E*$J%9%H%l!<%8(B} + +%The underpinnings of changelogs, manifests, and filelogs are provided +%by a single structure called the \emph{revlog}. + +$B%A%'%s%8%m%0!$%^%K%U%'%9%H$*$h$S%U%!%$%k%m%0$NEZBf$K;H$o$l$F$$$k$O6&DL$N(B +\emph{revlog}$B$H$$$&9=B$BN$G$"$k!%(B + +%\subsection{Efficient storage} +\subsection{$B8zN(E*$J%9%H%l!<%8(B} + +%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. + +revlog$B$O(B\emph{delta}$B5!9=$r;H$C$F%j%S%8%g%s$N8zN(E*$J5-21$rDs6!$9$k!%%U%!(B +$B%$%k$N3F!9$N%P!<%8%g%s$N40A4$J%3%T!<$rJ]B8$9$k$N$G$O$J$/!$8E$$%j%S%8%g%s(B +$B$r?7$7$$%P!<%8%g%s$XJQ49$9$k$N$KI,MW$JJQ99$rJ]B8$9$k!%B?$/$N%U%!%$%k%G!<(B +$B%?$KBP$7$F!$(B delta$B$OE57?E*$K$O%U%!%$%k$N%U%k%3%T!<$N(B1$B%Q!<%;%s%HL$K~$G$"$"(B +$B$k!%(B + +%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. + +$B8E$$%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$N$$$/$D$+$O%F%-%9%H%U%!%$%k$N(Bdelta$B$KBP(B +$B$7$F$7$+5!G=$7$J$$!%$=$l$i$N%7%9%F%`$G$O%P%$%J%j%U%!%$%k$O40A4$J%9%J%C%W(B +$B%7%g%C%H$+!$%F%-%9%HI=8=$K%(%s%3!<%I$5$l$?7A<0$G$"$kI,MW$,$"$k!%$3$l$i$O(B +$B6&$KL5BL$NB?$$%"%W%m!<%A$G$"$k!%(B Mercurial$B$OG$0U$N%P%$%J%j%U%!%$%k$K$D$$(B +$B$F!$(Bdelta$B$r8zN(E*$K07$&$3$H$,$G$-!$%F%-%9%H$rFCJL07$$$9$kI,MW$,$J$$!%(B + +%\subsection{Safe operation} +\subsection{$B0BA4$JF0:n(B} +\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. + +Mercurial$B$O(Brevlog$B%U%!%$%k$NKvHx$K%G!<%?$N(B\emph{$BDI2C(B}$B$N$_$r9T$&!%0lEY=q$-(B +$B9~$^$l$?ItJ,$O8e$K$J$C$FJQ99$5$l$k$3$H$O$J$$!%$3$l$O%G!<%?$NJQ99$d:F=q$-(B +$B9~$_$r9T$&J}K!$h$j$b4h6/$+$D8zN(E*$G$"$k!%(B + +%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. + +$B2C$($F!$(BMercurial$B$O$"$i$f$k=q$-9~$_$rJ#?t$N%U%!%$%k$X$N(B\emph{$B%H%i%s%6%/%7%g(B +$B%s(B}$B$N0lIt$H8+$J$9!%%H%i%s%6%/%7%g%sA4BN$,@.8y$7!$FI$_=P$7B&$K0lEY$K7k2L$,(B +$B8+$($k>l9g$b!$$=$&$G$J$$>l9g$b%H%i%s%6%/%7%g%s$O(B\emph{$B%"%H%_%C%/(B}$B$G$"$k!%(B +$B$3$N%"%H%_%C%/@-$NJ]>Z$O!$(B 2$B$D$N(BMercurial$B$r!$JRJ}$O%G!<%?$NFI$_=P$7!$$b$&(B +$B0lJ}$O=q$-9~$_$Gl9g!$FI$_=P$7B&$K$O:.Mp$N860x$H$J$kItJ,E*$J(B +$B=q$-9~$_7k2L$O8+$($J$$$3$H$r0UL#$9$k!%(B + +%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. + +Mercurial$B$O%U%!%$%k$KDI5-$N$_$r$9$k$3$H$G!$%H%i%s%6%/%7%g%s$NJ]>Z$rMF0W$K(B +$B$7$F$$$k!%J*;v$rC1=c2=$9$k$3$H$K$h$C$F!$=hM}$N@5$7$5$r3N$N%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$K%3%T!<$5$l$k(B +$B$[$I$&$^$/5!G=$7$F$$$k!%(B + +%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. + +$B?^(B~\ref{fig:concepts:snapshot}$B$K35G0$r<($9!%(BMercurial$B$O(Brevlog$B$N%$%s%G%C%/(B +$B%9%U%!%$%k$N%(%s%H%j$KFCDj$N%j%S%8%g%s$r:F8=$9$k$N$KI,MW$J%G!<%?%U%!%$%k(B +$BFb$N$"$kHO0O$N%(%s%H%j$rJ]B8$9$k!%(B + +%\subsubsection{Aside: the influence of video compression} +\subsubsection{$B$=$NB>(B: $B%S%G%*05=L$N1F6A(B} + +%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. + +$B%S%G%*05=L$K47$l$F$$$?$j!$%G%8%?%k$K$h$k%1!<%V%k$^$?$O1R@1J|Aw$K47$l$F$$(B +$B$k$N$J$i!$BgItJ,$N%S%G%*05=L$N;EAH$_$G$O!$%S%G%*$N3F%U%l!<%`$,!$A0$N%U%l!<(B +$B%`$H$N:9J,$H$7$FJ]B8$5$l$F$$$k$3$H$rCN$C$F$$$k$@$m$&!%2C$($F!$$3$l$i$N;E(B +$BAH$_$O05=LN($r2T$0$?$a$KIT2D5U$J05=L5;=Q$r;H$C$F$*$j!$1GA|$N%(%i!<$O%U%l!<(B +$B%`4V$N:9J,$,A}$($k$K=>$C$FC_@Q$7$F$$$/!%(B + +%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. + +$B%S%G%*%9%H%j!<%`$G$O!$?.9f$NIT6q9g$K$h$C$F;~@^%I%m%C%W%"%&%H$,=P$k$3$H$,(B +$B$"$j!$$^$?IT2D5U05=L$K$h$k1F6A$NC_@Q$rM^$($k$?$a!$%S%G%*%(%s%3!<%@$ODj4|(B +$BE*$K!J%-!<%U%l!<%`$H8F$P$l$k!K40A4$J%U%l!<%`$r%9%H%j!<%`$KA^F~$9$k!%o$KLa$k$3$H$,$G$-$k!%$^$?%(%s%3!<%I%(%i!<(B +$B$NC_@Q$O%-!<%U%l!<%`$4$H$K=|5n$5$l$k!%(B + +%\subsection{Identification and strong integrity} +\subsection{$B<1JL$H6/$$0l4S@-(B} + +%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. + +$B:9J,$d%9%J%C%W%7%g%C%H>pJs$H6&$K!$(Brevlog$B%(%s%H%j$O%G!<%?$N0E9f%O%C%7%e(B +$B$r;}$D!%%O%C%7%e$K$h$j!$%j%S%8%g%s$NFbMF$r56$k$3$H$,:$Fq$K$J$j!$$^$?(B +$B;v8N$K$h$C$FFbMF$,GKB;$7$?>l9g!$H/8+$,MF0W$K$J$k!%(B + +%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. + +$B%O%C%7%e$OC1$KGKB;$r%A%'%C%/$9$k0J>e$N$3$H$r9T$&!%$3$l$i$O%j%S%8%g%s$N<1(B +$BJL$K$bMQ$$$i$l$k!%%A%'%s%8%;%C%H$N<1JL%O%C%7%e$O!$%(%s%I%f!<%6$+$i$O%A%'(B +$B%s%8%m%0$G%f!<%6L>$H6&$K8=$l$k?t;z$H$7$FL\$K$9$k$3$H$,B?$$$@$m$&!%(B +$B%U%!%$%k%m%0$H%^%K%U%'%9%H$G$b%O%C%7%e$O;H$o$l$F$$$k$,!$(BMercurial$B$O$3$l(B +$B$i$rGX8e$G$N$_MQ$$$k!%(B + +%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. + +Mercurial$B$O%U%!%$%k$N%j%S%8%g%sl9g$G$b!$B?$/$N>l9g!$(Brevlog$B$NGKB;$7$F$$$J(B +$B$$ItJ,$+$iGKB;$7$?ItJ,$NA08e$G$$$/$D$+$N%j%S%8%g%s$dBgH>$N%j%S%8%g%s$r:F(B +$B7z$9$k$3$H$,$G$-$k!%:9J,$N$_$r5-O?$9$k%7%9%F%`$G$O$3$l$ro(B\emph{parent}$B$H$7$F;2>H$5$l$kD>(B +$B@\$NAD@h$N%j%S%8%g%s$rCN$C$F$$$k!%?F$r<($9%9%m%C%H$N(B +$BN>J}$K;}$A!$$3$N%j%S%8%g%s$,?F$N(B +$B%9%m%C%H$K;}$D!%(B + +\begin{figure}[ht] + \centering + \includegraphics{revlog} + \caption{} + \label{fig:concepts:revlog} +\end{figure} + +%\section{The working directory} +\section{$B%o!<%-%s%0%G%#%l%/%H%j(B} + +%In the working directory, Mercurial stores a snapshot of the files +%from the repository as of a particular changeset. + +Mercurial$B$O%j%]%8%H%j$N$"$kFCDj$N%A%'%s%8%;%C%H$N%U%!%$%k%9%J%C%W%7%g%C%H(B +$B$r%o!<%-%s%0%G%#%l%/%H%jFb$K;}$D!%(B + +%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. + +$B%o!<%-%s%0%G%#%l%/%H%j$,$I$N%A%'%s%8%;%C%H$K99?7$5$l$F$$$k$,$"$k$N$+$O4{(B +$BCN$G$"$k!%%o!<%-%s%0%G%#%l%/%H%j$,FCDj$N%A%'%s%8%;%C%H$K$J$k$h$&$K99?7$9(B +$B$k:]!$(B Mercurial$B$OE,@Z$J%j%S%8%g%s$N%^%K%U%'%9%H$r8!:w$7!$$=$N%A%'%s%8%;%C(B +$B%H$,%3%_%C%H$5$l$?;~E@$G$I$N%U%!%$%k$,DI@W$5$l$F$$$k$+$rD4$Y!$3F!9$N%U%!(B +$B%$%k$N%j%S%8%g%s$rFCDj$9$k!%$=$7$F%A%'%s%8%;%C%H$,%3%_%C%H$5$l$?;~E@$NFb(B +$BMF$r$b$D%U%!%$%k$N%3%T!<$r:n@.$9$k!%(B + +%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. + +\emph{dirstate}$B$K$O%o!<%-%s%0%G%#%l%/%H%j$K$D$$$F(BMercurial$B$,GD0.$7$F$$$k(B +$B>pJs$,3JG<$5$l$F$$$k!%$=$NFbMF$O%o!<%-%s%0%G%#%l%/%H%j$,%"%C%W%G!<%H$5$l(B +$B$F$$$k%A%'%s%8%;%C%H$*$h$S%o!<%-%s%0%G%#%l%/%H%jFb$G(BMercurial$B$,DI@W$7$F$$(B +$B$kA4$F$N%U%!%$%k$K$D$$$F$N>\:Y$G$"$k!%(B + +%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. + +revlog$B$K$*$1$k%j%S%8%g%s$,(B2$B$D$N?F$N>pJs$r3JG<$9$kNN0h$r;}$A!$DL>o$N%j%S%8%g(B +$B%s!J?F$O(B1$B$D!K$^$?$O(B2$B$D$N?F$N%^!<%8$rI=8=$G$-$k$N$HF1MM$K(Bdirstate$B$b(B2$B$D$N?F(B +$B$N$?$a$N%9%m%C%H$r;}$C$F$$$k!%(B\hgcmd{update}$B%3%^%s%I$r$N%A%'%s%8%;%C%H$H(B\hgcmd{merge}$B$r9T$&$H!$:G=i(B +$B$N?F$O$=$N$^$^$K!$(B2$BHVL\$N?F$O%^!<%8$9$k%A%'%s%8%;%C%H$H$J(B +$B$k!%(B\hgcmd{parents}$B%3%^%s%I$G(Bdirstate$B$NN>?F$rCN$k$3$H$,$G$-$k!%(B + +%\subsection{What happens when you commit} +\subsection{$B%3%_%C%H;~$K2?$,5/$-$k$N$+(B} + +%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. + +dirstate$B$O4IM}L\E*0U30$N>pJs$bJ]B8$7$F$$$k!%(B Mercurial$B$O!$%3%_%C%H$N:]$K(B +dirstate$B$NN>?F$r(B\emph{$B?7$?$J%A%'%s%8%;%C%H$NN>?F(B}$B$H$7$FMQ$$$k!%(B + +\begin{figure}[ht] + \centering + \includegraphics{wdir} +% \caption{The working directory can have two parents} + \caption{$B%o!<%-%s%0%G%#%l%/%H%j$O(B2$B$D$N?F$r;}$AF@$k(B} + \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. + +$B?^(B~\ref{fig:concepts:wdir}$B$K%o!<%-%s%0%G%#%l%/%H%j$NDL>o>uBV$r<($9!%(B +$B%j%]%8%H%j$N:G?7$N%A%'%s%8%;%C%H$O(B\emph{tip}$B$G!$;R$r0l@Z;}$?$J$$!%(B + +\begin{figure}[ht] + \centering + \includegraphics{wdir-after-commit} +% \caption{The working directory gains new parents after a commit} + \caption{$B%3%_%C%H8e!$%o!<%-%s%0%G%#%l%/%H%j$O?7$?$JN>?F$r;}$D(B} + \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. + +$B%o!<%-%s%0%G%#%l%/%H%j$,(B``$B%3%_%C%H$7$h$&$H$7$F$$$k%A%'%s%8%;%C%H(B''$B$G$"$k(B +$B$H8+$J$9$3$H$OLr$KN)$D!%DI2C!$:o=|!$%j%M!<%`$^$?$O%3%T!<$7$?%U%!%$%k$r(B +Mercurial$B$KG'<1$5$;$k$H!$$9$G$K(BMercurial$B$,DI@W$7$F$$$kG$0U$N%U%!%$%k$X$N(B +$BJQ99$HF1MM!$$9$Y$F%A%'%s%8%;%C%H$KH?1G$5$l$k!%?7$?$J%A%'%s%8%;%C%H$O%o!<(B +$B%-%s%0%G%#%l%/%H%j$NN>?F$rN>?F$H$7$F;}$D!%(B + +%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. + +$B%3%_%C%H8e!$(BMercurial$B$O%o!<%-%s%0%G%#%l%/%H%j$NN>?F$r99?7$7!$(B1$B$DL\$N?F$,(B +$B?7$?$J%A%'%s%8%;%C%H$N(BID$B!$(B2$BHVL\$r(Bnull ID$B$K$9$k!%$3$l$r(B +$B?^(B~\ref{fig:concepts:wdir-after-commit}$B$K<($9!%(BMercurial$B$O%3%_%C%H;~$K%o!<(B +$B%-%s%0%G%#%l%/%H%jFb$N%U%!%$%k$K$O0l@Z?($l$:!$(Bdirstate$B$K?7$?$JN>?F$r5-O?(B +$B$9$k!%(B + +%\subsection{Creating a new head} +\subsection{$B?7$?$J%X%C%I$r:n$k(B} + +%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 were when you +%committed that changeset. The effect of this is shown in +%figure~\ref{fig:concepts:wdir-pre-branch}. + +$B%o!<%-%s%0%G%#%l%/%H%j$r8=:_$N(Btip$B0J30$N%A%'%s%8%;%C%H$K99?7$9$k$3$H$O$$$5(B +$B$5$+$b$*$+$7$J$3$H$G$O$J$$!%Nc$($P!$$3$NA0$N2PMKF|$K%W%m%8%'%/%H$,$I$N$h(B +$B$&$J>uBV$G$"$C$?$+CN$j$?$$$H;W$&$+$b$7$l$J$$$7!$%A%'%s%8%;%C%H$N$&$A$N$I(B +$B$l$,%P%0$r:.F~$5$;$?$+FM$-;_$a$?$$$H9M$($k$3$H$,$"$k$+$b$7$l$J$$!%$3$N$h(B +$B$&$J>l9g!$%o!<%-%s%0%G%#%l%/%H%j$r6=L#$N$"$k%A%'%s%8%;%C%H$K99?7$7!$%A%'(B +$B%s%8%;%C%H$r%3%_%C%H$7$?;~$K$=$l$i$,$I$N$h$&$G$"$C$?$+$r8+$k$?$a$K%o!<%-(B +$B%s%0%G%#%l%/%H%jFb$N%U%!%$%k$rD4$Y$k$N$,<+A3$G$"$k!%$3$N1F6A$O(B +$B?^(B~\ref{fig:concepts:wdir-pre-branch}$B$K<($9!%(B + +\begin{figure}[ht] + \centering + \includegraphics{wdir-pre-branch} +% \caption{The working directory, updated to an older changeset} + \caption{$B8E$$%A%'%s%8%;%C%H$X$H99?7$5$l$?%o!<%-%s%0%G%#%l%/%H%j(B} + \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}. + +$B%o!<%-%s%0%G%#%l%/%H%j$r8E$$%A%'%s%8%;%C%H$K99?7$7!$JQ99$r9T$C$F%3%_%C%H(B +$B$9$k$H2?$,5/$3$k$@$m$&$+!)(B Mercurial$B$OA0=R$N$h$&$K?6Iq$&!%%o!<%-%s%0%G%#(B +$B%l%/%H%j$NN>?F$O?7$?$J%A%'%s%8%;%C%H$NN>?F$H$J$k!%?7$?$J%A%'%s%8%;%C%H$O(B +$B;R$r;}$?$:!$=>$C$F?7$?$J(Btip$B$H$J$k!%%j%]%8%H%j$K$O(B\emph{heads}$B$H8F$P$l$k(B2 +$B$D$N%A%'%s%8%;%C%H$,$G$-$k!%$3$N;~$N9=B$$r(B +$B?^(B~\ref{fig:concepts:wdir-branch}$B$K<($9!%(B + +\begin{figure}[ht] + \centering + \includegraphics{wdir-branch} +% \caption{After a commit made while synced to an older changeset} + \caption{$B8E$$%A%'%s%8%;%C%H$KF14|Cf$K%3%_%C%H$,9T$o$l$?>l9g(B} + \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's just something +% of a surprise for newcomers. I'll discuss other ways to avoid this +% behaviour, and why Mercurial behaves in this initially surprising way, +% later on. + +%\end{note} + +\begin{note} +Mercurial$B$r;H$$;O$a$?$P$+$j$G$"$l$P!$$h$/$"$k(B``$B%(%i!<(B''$B$r3P$($F$*$/$H$h(B +$B$$!%$=$l$O(B\hgcmd{pull}$B%3%^%s%I$r%*%W%7%g%s$J$7$GuBV$O(B\hgcmd{merge}$B$H(B +\hgcmd{commit}$B$@$1$G2r>C$G$-$k$+$i$@!%8@$$BX$($k$H!$$3$N>uBV$O$[$H$s$I$N(B +$B>l9g32$r$J$9$b$N$G$O$J$J$/!$C1$K=i?4/$7C1=c2=$9$k$H!$%^!<%8%W(B +$B%m%;%9$OAPJ}$N%A%'%s%8%;%C%H$N%^%K%U%'%9%HFb$K$"$kA4$F$N%U%!%$%k$KBP$7$F(B +$Bl9g!$%o!<%-%s%0%G%#%l%/%H%j$KJQ99$5$l$?%3%T!<$,:n@.$5$l(B + $B$k!%(B +%\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 $B0lJ}$N%A%'%s%8%;%C%H$G:o=|$5$l$?%U%!%$%k$,$"$j!$$b$&0lJ}$,$=$N%U%!(B + $B%$%k$r4^$^$J$$$+!$F1MM$K:o=|$5$l$F$$$k>l9g$O%o!<%-%s%0%G%#%l%/%H(B + $B%j$+$i$=$N%U%!%$%k$r:o=|$9$k!%(B +%\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 $B0lJ}$N%A%'%s%8%;%C%H$G%U%!%$%k$,:o=|$5$l$F$*$j!$$b$&0lJ}$G$O$=$N(B + $B%U%!%$%k$,JQ99$5$l$F$$$k>l9g$O!$JQ99$5$l$?%U%!%$%k$r0];}$9$k$+%U%!(B + $B%$%k$r>C5n$9$k$+$+%f!<%6$K?R$M$k!%(B +%\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 $BN>J}$N%A%'%s%8%;%C%H$G%U%!%$%k$,JQ99$5$l$F$$$k>l9g!$%^!<%88e$N%U%!(B + $B%$%k$NFbMF$rA*Br$9$k$?$a$K30It$N%^!<%8%W%m%0%i%`$r5/F0$9$k!%$3$l(B + $B$r9T$&$?$a$K$O%f!<%6$NF~NO$,I,MW$G$"$k!%(B +%\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. + \item $B0lJ}$N%A%'%s%8%;%C%H$G%U%!%$%k$,JQ99$5$l$F$*$j!$$b$&0lJ}$G$O%U%!(B + $B%$%k$,%j%M!<%`$^$?$O%3%T!<$5$l$F$$$k>l9g!$JQ99$O?7$7$$L>A0$N%U%!(B + $B%$%k$K\$7$/=R$Y$l$P%^!<%8$K$O$$$m$$$m$JFC$N%1!<%9$O40A4$K<+F0$G(B +$B$"$j!$$N%^!<%8$O>WFM$r2r7h$9$k$?$a$KF~NO$r5a$a$k$3$H$J$/<+F0E*(B +$B$K40N;$9$k!%(B + +%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. + +$B%^!<%88e$K%3%_%C%H$r9T$&$H$-2?$,5/$3$k$+$r9M$($k>l9g$O$d$O$j%o!<%-%s%0%G%#(B +$B%l%/%H%j$r(B``$B$3$l$+$i%3%_%C%H$7$h$&$H$9$k%A%'%s%8%;%C%H(B''$B$H9M$($k$H$h$$!%(B +\hgcmd{merge}$B%3%^%s%I$,40N;$7$?8e!$%o!<%-%s%0%G%#%l%/%H%j$O(B2$B$D$N?F$r;}(B +$B$A!$$3$l$i$O?7$?$J%A%'%s%8%;%C%H$NN>?F$H$J$k!%(B + +%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. + +Mercurial$B$OJ#?t2s$N%^!<%8$rB%$9!%$3$3$G$=$l$>$l$N%^!<%8$N7k2L$r<+J,<+?H$G(B +$B%3%_%C%H$7$J$1$l$P$J$i$J$$!%$3$l$O(BMercurial$B$,%j%S%8%g%s$H%o!<%-%s%0%G%#%l(B +$B%/%H%j$NAPJ}$K$D$$$F(B2$B$D$N?F$N$_$rDI@W$9$k$3$H$K$h$k!%J#?t$N%A%'%s%8%;%C%H(B +$B$r0lEY$K%^!<%8$9$k$3$H$O5;=QE*$K$O2DG=$@$,!$%^!<%8$K$h$k:.Mp$r0z$-5/$3(B +$B$7!$<}=&$,$D$+$J$/$J$k8+9~$_$,Bg$-$$!%(B + +\subsection{$B%^!<%8$H%j%M!<%`(B} +%A surprising number of revision control systems pay little or no +%attention to a file's \emph{name} over time. For instance, it used to +%be common that if a file got renamed on one side of a merge, the changes +%from the other side would be silently dropped. + +$B6C$/$[$IB?$/$N%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$,(B\emph{$B%U%!%$%kL>(B}$B$NJQ2=$KCm(B +$B0U$rJ'$C$F$$$J$$!%Nc$($P%^!<%8$N:]!$0lJ}$G%U%!%$%k$,%j%M!<%`$5$l$F$$$?>l(B +$B9g!$$b$&0lJ}$NJQ99$O2?$N7Y9p$bL5$7$KGK4~$5$l$F$7$^$&!%(B + +%Mercurial records metadata when you tell it to perform a rename or +%copy. It uses this metadata during a merge to do the right thing in the +%case of a merge. For instance, if I rename a file, and you edit it +%without renaming it, when we merge our work the file will be renamed and +%have your edits applied. + +Mercurial$B$O%j%M!<%`$d%3%T!<$r9T$&;~$K%a%?%G!<%?$r5-O?$7!$%^!<%8$r@5$7$/9T(B +$B$&$?$a$KMxMQ$9$k!%Nc$($P$"$k%f!<%6$,%U%!%$%k$r%j%M!<%`$7!$JL$N%f!<%6$,%j(B +$B%M!<%`$;$:$KF1$8%U%!%$%k$rJT=8$7$?$H$9$k$H!$%^!<%8$N:]$K%U%!%$%k$O%j%M!<(B +$B%`$5$l!$$J$*$+$DJT=8FbMF$b$N6=L#?<$$E@(B} + +%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. + +$BA0@a$G(BMercurial$B$N@_7W$N:G$b=EMW$JLL$K$D$$$Fe$2!$?.Mj@-$H@-G=$K:Y?4$N(B +$BCm0U$rJ'$C$F$$$k$3$H$r6/D4$7$?!%$7$+$7:YIt$X$NCm0U$O$=$l$@$1$KN1$^$i$J$$!%(B +Mercurial$B$N9=B$$K$O!$8D?ME*$K6=L#?<$/46$8$?E@$,B?!9$"$k!%9*L/$K@_7W$5$l$?(B +$B%7%9%F%`$NGX8e$K$"$k%"%$%G%#%"$K$D$$$FFIe$2$F$_$h$&(B +$B$H;W$&!%(B + +%\subsection{Clever compression} +\subsection{$B8-$$05=L(B} + +%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. + +$BE,@Z$J>l9g!$(BMercurial$B$O%9%J%C%W%7%g%C%H$H:9J,$r05=L$5$l$?7A<0$GJ]B8$9$k!%(B +Mercurial$B$O>o$K%9%J%C%W%7%g%C%H$d:9J,$N05=L$r(B\emph{$B;n$_$k(B}$B$,!$$=$l$rJ]B8(B +$B$9$k$N$O05=L$5$l$?%P!<%8%g%s$,85$N%P!<%8%g%s$h$j$b>.$5$$;~$N$_$G$"$k!%(B + +%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. + +$B$D$^$j!$(BMercurial$B$O(B\texttt{zip}$B%"!<%+%$%V$d(BJPEG$B2hA|$J$I$N$h$&$K85!905=L$5(B +$B$l$F$$$k%U%!%$%k$NJ]B8$r(B``$B@5$7$$$d$jJ}(B''$B$G9T$&!%$3$l$i$N%U%!%$%k$G$O!$:9(B +$BJ,o!$85$N%U%!%$%k$h$j(B +$B$bBg$-$/$J$k!%$=$3$G(BMercurial$B$O(B\texttt{zip}$B$d(BJPEG$B$r$=$N$^$^J]B8$9$k!%(B + +%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. + +$BDL>o!$05=L$5$l$?%U%!%$%k$N%j%S%8%g%s4V$N:9J,$O%U%!%$%k$N%9%J%C%W%7%g%C%H(B +$B$h$jBg$-$$!%$3$3$G$b(BMercurial$B$O(B``$B@5$7$$$d$jJ}(B''$B$rMQ$$$F$$$k!%$3$N$h$&$J(B +$B>u67$G!$:9J,$N%5%$%:$,%U%!%$%k$N40A4$J%9%J%C%W%7%g%C%H$H$7$FJ]B8$7$?J}$,(B +$BM-Mx$H$J$kogCM$r1[$($k$H!$:9J,$G$O$J$/%9%J%C%W%7%g%C%H$rJ]B8$9$k!%$3$N$h(B +$B$&$K$7$FC1=c$K:9J,$N$_$r5-O?$9$k%"%W%m!<%A$h$j$b5-21NN0h$r@aLs$7$F$$$k!%(B + +%\subsubsection{Network recompression} +\subsubsection{$B%M%C%H%o!<%/:F05=L(B} + +%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. + +$B%G%#%9%/$K%j%S%8%g%s$rJ]B8$9$k:]!$(BMercurial$B$O(B``deflate''$B05=L%"%k%4%j%:%`(B +$B$rMQ$$$k!%!J$3$l$O?M5$$N9b$$(B\texttt{zip}$B%"!<%+%$%V%U%)!<%^%C%H$HF1$8%"%k(B +$B%4%j%:%`$G$"$k!%!K$3$N%"%k%4%j%:%`$O9b$$05=LN($H9bB.@-$r%P%i%s%9$5$;$F$$(B +$B$k!%$7$+$7%j%S%8%g%s%G!<%?$r%M%C%H%o!<%/$GEAAw$9$k:]$K$O(BMercurial$B$O05=L$5(B +$B$l$F$$$k%j%S%8%g%s%G!<%?$r?-D9$9$k!%(B + +%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. + +HTTP$B$K$h$k@\B3$N>l9g!$(BMercurial$B$O%G!<%?%9%H%j!<%`A4BN$r$h$j05=LN($N9b$$%"(B +$B%k%4%j%:%`!J9-$/MQ$$$i$l$F$$$k05=L%Q%C%1!<%8$G$"$k(B\texttt{bzip2}$B$G;H$o$l(B +$B$F$$$k(BBurrows-Wheeler$B%"%k%4%j%:%`!K$G:F05=L$9$k!%$3$N%"%k%4%j%:%`$H!$!J%j(B +$B%S%8%g%sKh$G$J$/!K%9%H%j!<%`A4BN$r05=L$9$k$3$H$K$h$j!$Aw?.$5$l$k%P%$%H?t(B +$B$OBg$-$/Dc8:$5$l!$$"$i$f$k%M%C%H%o!<%/$G$h$$@-G=$r$($k$3$H$,$G$-$k!%(B + +%(If the connection is over \command{ssh}, Mercurial \emph{doesn't} +%recompress the stream, because \command{ssh} can already do this +%itself.) + +$B!J(B\command{ssh}$B$K$h$k@\B3$N>l9g!$(BMercurial$B$O%9%H%j!<%`$N:F05=L$O9T$o$J(B +$B$$!%(B\command{ssh}$B%3%^%s%I<+BN$,05=L$r9T$&$?$a$G$"$k!%!K(B + +%\subsection{Read/write ordering and atomicity} +\subsection{$BFI$_=q$-$N=g=x$H%"%H%_%C%/@-(B} + +%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. + +$B%U%!%$%k$X$NDI5-$OFI$_Z$H$7$F$O==J,$G(B +$B$O$J$$!%(B $B?^(B~\ref{fig:concepts:metadata}$B$r;W$$5/$3$9$H!$%A%'%s%8%m%0Fb$N%j(B +$B%S%8%g%s$O%^%K%U%'%9%HFb$N%j%S%8%g%s$r;X$7<($7$F$*$j!$%^%K%U%'%9%HFb$N%j(B +$B%S%8%g%s$O%U%!%$%k%m%0Fb$N%j%S%8%g%s$r;X$7<($7$F$$$?!%$3$N3,AX9=B$$O=EMW(B +$B$J0UL#$r;}$C$F$$$k!%(B + +%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. + +$B=q$-o$K%U%!%$%k%m%0$H%^%K%U%'%9%H%G!<%?$r%A%'%s%8%m%0$NA0$K=q$-9~$_(B +$B=*N;$7$F$$$k$?$a!$FI$_Z$K$h$j!$(BMercurial$B$G$O%G!<%?$NFI$_=P$7;~(B +$B$K%j%]%8%H%j$N(B\emph{$B%m%C%/(B}$B$,ITMW$K$J$C$F$$$k!%FI$_=P$7Cf$K=q$-9~$_$,H/@8(B +$B$7$?$H$7$F$bF1MM$G$"$k!%$3$N$3$H$O%9%1!<%i%S%j%F%#$KBg$-$J8z2L$r$b$?$i(B +$B$9!%B??t$N(BMercurial$B%W%m%;%9$,$"$C$F$b!$%j%]%8%H%j$X$N=q$-9~$_$NM-L5$K4X$o(B +$B$i$:!$%j%]%8%H%j$+$i0lEY$K0BA4$K%G!<%?$rFI$_=P$9$3$H$,$G$-$k!%(B + +%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 repositoryin 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$B$G$O!$%m%C%/L5$7$GFI$_=P$7$r9T$&$?$a!$%^%k%A%f!<%6%7%9%F%`>e$G%j(B +$B%]%8%H%j$r6&M-$7$F$$$k>l9g$G$b(Bclone$B$d(Bpull$B$r9T$*$&$H$9$kB>$N%m!<%+%k%f!<%6(B +$B$K%j%]%8%H%j$X$N(B\emph{$B=q$-9~$_(B}$B5v2D$rM?$($kI,MW$O$J$$!%H`$i$K$O(B\emph{$BFI$_(B +$B=P$7(B}$B5v2D$,$"$l$P$h$$!%!JB>$N%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$G$O$3$&$O$$$+(B +$B$:!$BgH>$N%7%9%F%`$G$OFI$_/$J$/$H$b(B1$B$D$N%G%#%l%/(B +$B%H%j$KBP$7$F=q$-9~$_5v2D$r;}$C$F$$$J$1$l$P$J$i$J$$$3$H$r0UL#$9$k!%$3$N$?(B +$B$a$K%;%-%e%j%F%#$d4IM}>e$NLq2p$JLdBj$,H/@8$7F@$k!%!K(B + +%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.) + +Mercurial$B$O0lEY$K(B1$B%W%m%;%9$@$1$,%j%]%8%H%j$K=q$-9~$`$3$H$rJ]>Z$9$k$?$a$K(B +$B%m%C%/$r;H$C$F$$$k!%!J(BMercurial$B$NMQ$$$k%m%C%/%a%+%K%:%`$O(BNFS$B$N$h$&$K%m%C(B +$B%/$HAj@-$N0-$$$3$H$GM-L>$J%U%!%$%k%7%9%F%`>e$G$b0BA4$G$"$k!%!K%j%]%8%H%j(B +$B$,%m%C%/$5$l$k$H!$=q$-9~$_%W%m%;%9$O%j%]%8%H%j$,%"%s%m%C%/$5$l$k$^$G$7$P(B +$B$i$/BT$D!%$7$+$7%j%]%8%H%j$,D9;~4V$K$o$?$C$F%m%C%/$5$lB3$1$k>l9g$O!$=q$-(B +$B9~$_$7$h$&$H$9$k%W%m%;%9$O%?%$%`%"%&%H$9$k!%$3$l$O!$Nc$($P!$F|>oMQ$$$k<+(B +$BF0%9%/%j%W%H$O1J1s$K%9%?%C%/$9$k$o$1$G$O$J$$$3$H$r0UL#$9$k!%!J$b$A$m$s%?(B +$B%$%`%"%&%H$^$G$N;~4V$O%<%m$+$iL58B$N4V$G@_Dj$+$N$&$G$"$k!K(B + +%\subsubsection{Safe dirstate access} +\subsubsection{$B0BA4$J(Bdirstate$B%"%/%;%9(B} + +%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. + +$B%j%S%8%g%s%G!<%?$N;~$HF1MM$K!$(BMercurial$B$O(Bdirstate$B%U%!%$%k$rFI$_=P$9:]$K$O(B +$B%m%C%/$r9T$o$J$$!%%m%C%/$r9T$&$N$O=q$-9~$_$N;~$N$_$G$"$k!%0lIt$N$_$,=q$-(B +$B9~$^$l$?(Bdirstate$B%U%!%$%k$rFI$_9~$^$J$$$h$&$K$9$k$?$a!$(B Mercurial$B$OF1$8%G%#(B +$B%l%/%H%jFb$K%f%K!<%/$JL>A0$G(Bdirstate$B%U%!%$%k$r=q$-!$$3$N0l;~%U%!%$%k$r%"(B +$B%H%_%C%/$K(B\filename{dirstate}$B$K%j%M!<%`$9$k!%$3$l$K$h(B +$B$j!$(B\filename{dirstate}$B%U%!%$%k$O>o$K40A4$G$"$k$3$H$,J]>Z$5$l$k!%(B + +%\subsection{Avoiding seeks} +\subsection{$B%7!<%/$N2sHr(B} + +%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. + +Mercurial$B$N@-G=$K$O!$%G%#%9%/%X%C%I$N%7!<%/$rHr$1$k$3$H$,IT2D7g$G$"$k!%(B +$B%7!<%/$OBg5,LO$JFI$_=P$7A`:n$HHf3S$7$F$bHs>o$K9b$/$D$/!%(B + +%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. + +$B$=$NM}M3$O!$Nc$($P!$(Bdirstate$B$O(B1$B$D$N%U%!%$%k$KJ]B8$5$l$F$$$k$?$a$G!$(B +Mercurial$B$,DI@W$7$F$$$k(Bdirstate$B%U%!%$%k$,%G%#%l%/%H%jKh$K$"$k(B +$B$H!$(BMercurial$B$O%G%#%l%/%H%jKh$K%7!<%/$r9T$&$3$H$K$J$k!%$r:n$k4JC1$JJ}K!$G$"$k!%(B Mercurial$B$O(Brevlog$B%U%!(B +$B%$%k$K=q$-9~$_$r9T$&:]$K%U%!%$%k$r<($9L>A0$,(B2$B$D0J>e$"$k2TF/$+$r%A%'%C%/$9(B +$B$k!%(B 2$B$D0J>e$NL>A0$,$"$k>l9g!$(B2$B$D0J>e$N%j%]%8%H%j$,%U%!%$%k$r;HMQ$7$F$*(B +$B$j!$(BMercurial$B$O%U%!%$%k$N%j%]%8%H%j$K8GM-$J?7$7$$%3%T!<$r:n@.$9$k!%(B + +%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. + +$B%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$N3+H/e$G:9J,$rl9g:G9b$N@-G=$r$b$?$i$9!%$=$NB>$N$NFbMF(B} + +%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. + +Mercurial$B$O!$%U%!%$%k$rJQ99$7$?>l9g$G$b!$JQ99$N?=9p$r6/@)$7$J$$$?$a!$(B +dirstate$B$KDI2C$N>pJs$rJ]B8$9$k$3$H$G%U%!%$%k$rJQ99$7$?$+$I$&$+8z2LE*$KH=(B +$BJL$9$k!%%o!<%-%s%0%G%#%l%/%H%j$N$9$Y$F$N%U%!%$%k$K$D$$$F!$:G8e$K%U%!%$%k(B +$B$,JQ99$5$l$?;~9o$H!$$=$N:]$N%U%!%$%k%5%$%:$r5-O?$7$F$$$k!%(B + +%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. + +$BL@<(E*$K%U%!%$%k$r(B\hgcmd{add}, \hgcmd{remove}, \hgcmd{rename} $B$^$?$O(B +\hgcmd{copy}$B$7$?>l9g!$(BMercurial$B$O(Bdirstate$B$r99?7$7!$%3%_%C%H$N:]$K$=$l$i(B +$B$N%U%!%$%k$r$I$&uBV$r%A%'%C%/$9$k:]$O!$$^$:(B +$B%U%!%$%k$N99?7F|;~$rD4$Y$k!%$3$l$,JQ99$5$l$F$$$J$$>l9g$O%U%!%$%k$OJQ99$,(B +$B$J$$$H$$$&$3$H$,$o$+$k!%%U%!%$%k%5%$%:$,JQ$o$C$F$$$k>l9g$O!$%U%!%$%k$,JQ(B +$B99$5$l$?$3$H$,$o$+$k!%99?7F|;~$,JQ$o$C$F$$$k$,!$%5%$%:$,F1$8>l9g$O(B +Mercurial$B$O%U%!%$%k$NFbMF$rD>@\8+$F!$JQ99$5$l$F$$$k$+$I$&$+$rH=CG$9$kI,MW(B +$B$,$"$k!%$3$l$i$N$4$/6O$+$N>pJs$rJ]B8$9$k$3$H$K$h$C$F!$(BMercurial$B$O%G!<%?$N(B +$BFI$_$N%j%S%8%g%s%3%s%H%m!<%k%7%9%F%`$HHf3S$7$FBg(B +$B$-$J@-G=8~>e$rC#@.$7$F$$$k!%(B + +%%% Local Variables: +%%% mode: yatex +%%% TeX-master: "00book" +%%% End: diff -r 5225ec140003 -r 896ab6eaf1c6 ja/daily.tex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ja/daily.tex Fri Jul 10 02:32:17 2009 +0900 @@ -0,0 +1,866 @@ +%\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$,DI@W$7$F$$(B +$B$k$b$N$N!$JQ99$N2C$($i$l$F$$$J$$%U%!%$%k$K$D$$$F2?$+$rCN$j$?$$$H$$$&$3$H(B +$B$O5)$G$"$k!%!J$b$A$m$sCN$j$?$$>l9g$O>pJs$rF@$k$3$H$b$G$-$k!%$3$l$K$D$$$F(B +$B$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{myfile.txt} 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{myfile.txt}$B$H$$$&L>A0$N%U%!%$%k$rDI2C$7$?:]$K$OI=<($7$F$$$J$+$C(B +$B$?E@$KCm0U$5$l$?$$!%(B + +%What's going on is that in the former case, we explicitly named the file +%to add on the command line. The assumption that Mercurial makes in such +%cases is that we know what we are doing, and it doesn't print any +%output. + +$BA0$NNc$G$O!$%3%^%s%I%i%$%s$GDI2C$9$k%U%!%$%k$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!$2?$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/