# HG changeset patch # User Dongsheng Song # Date 1238401413 -28800 # Node ID 1c13ed2130a723f0a428418da100950920ac34c2 # Parent 6b1577ef513516ae34ad123926530416573e71e9# Parent 9e8e5292acaae158e2a5019fbee018e804aae452 Merge with http://hg.serpentine.com/mercurial/book diff -r 9e8e5292acaa -r 1c13ed2130a7 .hgignore --- a/.hgignore Fri Mar 27 00:41:15 2009 -0700 +++ b/.hgignore Mon Mar 30 16:23:33 2009 +0800 @@ -1,4 +1,4 @@ -[^/]+/html/ +[^/]+/htdocs/ syntax: glob @@ -19,4 +19,8 @@ web/hgbook/.database.sqlite3 web/hgbook/secrets.py web/index-read.html.in -xsl/system-xsl +stylesheets/system-xsl +build +en/html +en/examples/results +tools \ No newline at end of file diff -r 9e8e5292acaa -r 1c13ed2130a7 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,219 @@ +# +# Makefile for the hgbook, top-level +# + +FORMATS=html html-single pdf + +PO_LANGUAGES := zh +DBK_LANGUAGES := en +LANGUAGES := $(DBK_LANGUAGES) $(PO_LANGUAGES) + +UPDATEPO = PERLLIB=../tools/po4a/lib/ ../tools/po4a/po4a-updatepo -M UTF-8 \ + -f docbook -o doctype='docbook' -o includeexternal \ + -o nodefault=' ' \ + -o untranslated=' ' +TRANSLATE = PERLLIB=tools/po4a/lib/ tools/po4a/po4a-translate -M UTF-8 \ + -f docbook -o doctype='docbook' \ + -k 0 + +#rev_id = $(shell hg parents --template '{node|short} ({date|isodate})') +rev_id = $(shell hg parents --template '{node|short} ({date|shortdate})') + +images := \ + en/figs/feature-branches.png \ + en/figs/filelog.png \ + en/figs/metadata.png \ + en/figs/mq-stack.png \ + en/figs/revlog.png \ + en/figs/snapshot.png \ + en/figs/tour-history.png \ + en/figs/tour-merge-conflict.png \ + en/figs/tour-merge-merge.png \ + en/figs/tour-merge-pull.png \ + en/figs/tour-merge-sep-repos.png \ + en/figs/undo-manual-merge.png \ + en/figs/undo-manual.png \ + en/figs/undo-non-tip.png \ + en/figs/undo-simple.png \ + en/figs/wdir-after-commit.png \ + en/figs/wdir-branch.png \ + en/figs/wdir-merge.png \ + en/figs/wdir.png \ + en/figs/wdir-pre-branch.png + +help: + @echo " make html [LINGUA=en|zh|...]" + @echo " make html-single [LINGUA=en|zh|...]" + @echo " make pdf [LINGUA=en|zh|...]" + @echo " make validate [LINGUA=en|zh|...] # always before commit!" + @echo " make tidypo [LINGUA=zh|...] # always before commit!" + @echo " make updatepo [LINGUA=zh|...] # update po files." + @echo " make all [LINGUA=en|zh|...]" + @echo " make stat # print statistics about po files." + @echo " make clean # Remove the build files." + +clean: + @rm -fr build po/*.mo hello en/hello en/html en/.validated-00book.xml en/examples/.run en/examples/results \ + stylesheets/system-xsl en/figs/*-tmp.svg \ + en/figs/feature-branches.png \ + en/figs/filelog.png \ + en/figs/feature-branches.png \ + en/figs/filelog.png \ + en/figs/metadata.png \ + en/figs/mq-stack.png \ + en/figs/revlog.png \ + en/figs/snapshot.png \ + en/figs/tour-history.png \ + en/figs/tour-merge-conflict.png \ + en/figs/tour-merge-merge.png \ + en/figs/tour-merge-pull.png \ + en/figs/tour-merge-sep-repos.png \ + en/figs/undo-manual-merge.png \ + en/figs/undo-manual.png \ + en/figs/undo-non-tip.png \ + en/figs/undo-simple.png \ + en/figs/wdir-after-commit.png \ + en/figs/wdir-branch.png \ + en/figs/wdir-merge.png \ + en/figs/wdir-pre-branch.png \ + en/figs/wdir.png + +all: +ifdef LINGUA + for f in $(FORMATS); do \ + $(MAKE) LINGUA=$(LINGUA) $$f; \ + done +else + for l in $(LANGUAGES); do \ + for f in $(FORMATS); do \ + $(MAKE) LINGUA=$$l $$f; \ + done; \ + done +endif + +stat: + @( \ + LANG=C; export LANG; cd po; \ + for f in *.po; do \ + printf "%s\t" $$f; \ + msgfmt --statistics -c $$f; \ + done; \ + ) + +tidypo: +ifdef LINGUA + msgcat --sort-by-file --width=80 po/$(LINGUA).po > po/$(LINGUA).tmp && \ + mv po/$(LINGUA).tmp po/$(LINGUA).po; +else + for po in $(wildcard po/*.po); do \ + msgcat --sort-by-file --width=80 $$po > $$po.tmp && mv $$po.tmp $$po; \ + done +endif + +ifndef LINGUA +updatepo: + for l in $(PO_LANGUAGES); do \ + $(MAKE) $@ LINGUA=$$l; \ + done +else +updatepo: +ifneq "$(findstring $(LINGUA),$(PO_LANGUAGES))" "" + (cd po && $(UPDATEPO) -m ../en/00book.xml -p $(LINGUA).po) + $(MAKE) tidypo LINGUA=$(LINGUA) +endif +endif + +ifndef LINGUA +validate: + for l in $(LANGUAGES); do \ + $(MAKE) $@ LINGUA=$$l; \ + done +else +validate: build/$(LINGUA)/source/hgbook.xml + xmllint --nonet --noout --postvalid --xinclude $< + +ifneq "$(findstring $(LINGUA),$(DBK_LANGUAGES))" "" +$(LINGUA)/examples/.run: + (cd $(LINGUA)/examples; ./run-example -v -a) + +build/$(LINGUA)/source/hgbook.xml: $(wildcard $(LINGUA)/*.xml) $(images) $(LINGUA)/examples/.run $(images) + mkdir -p build/$(LINGUA)/source/figs + cp $(LINGUA)/figs/*.png build/$(LINGUA)/source/figs + (cd $(LINGUA); xmllint --nonet --noent --xinclude --postvalid --output ../$@.tmp 00book.xml) + cat $@.tmp | sed 's/\$$rev_id\$$/${rev_id}/' > $@ +else +en/examples/.run: + (cd en/examples; ./run-example -v -a) + +build/en/source/hgbook.xml: + ${MAKE} LINGUA=en $@ + +build/$(LINGUA)/source/hgbook.xml: build/en/source/hgbook.xml po/$(LINGUA).po $(images) + mkdir -p build/$(LINGUA)/source/figs + $(TRANSLATE) -m build/en/source/hgbook.xml -p po/$(LINGUA).po -l $@.tmp + cat $@.tmp | sed 's/\$$rev_id\$$/${rev_id}/' > $@ +endif + +endif + +ifndef LINGUA +html: + for l in $(LANGUAGES); do \ + $(MAKE) $@ LINGUA=$$l; \ + done +else +html: build/$(LINGUA)/html/index.html + +build/$(LINGUA)/html/index.html: build/$(LINGUA)/source/hgbook.xml stylesheets/html.xsl stylesheets/$(LINGUA)/html.xsl + mkdir -p build/$(LINGUA)/html/figs + cp en/figs/*.png build/$(LINGUA)/html/figs + cp stylesheets/hgbook.css build/$(LINGUA)/html + xsltproc --output build/$(LINGUA)/html/ \ + stylesheets/$(LINGUA)/html.xsl build/$(LINGUA)/source/hgbook.xml +endif + +ifndef LINGUA +html-single: + for l in $(LANGUAGES); do \ + $(MAKE) $@ LINGUA=$$l; \ + done +else +html-single: build/$(LINGUA)/html-single/hgbook.html + +build/$(LINGUA)/html-single/hgbook.html: build/$(LINGUA)/source/hgbook.xml stylesheets/html-single.xsl stylesheets/$(LINGUA)/html-single.xsl + mkdir -p build/$(LINGUA)/html-single/figs + cp en/figs/*.png build/$(LINGUA)/html-single/figs + cp stylesheets/hgbook.css build/$(LINGUA)/html-single + xsltproc --output build/$(LINGUA)/html-single/hgbook.html \ + stylesheets/$(LINGUA)/html-single.xsl build/$(LINGUA)/source/hgbook.xml +endif + +ifndef LINGUA +pdf: + for l in $(LANGUAGES); do \ + $(MAKE) $@ LINGUA=$$l; \ + done +else +pdf: build/$(LINGUA)/pdf/hgbook.pdf + +build/$(LINGUA)/pdf/hgbook.pdf: build/$(LINGUA)/source/hgbook.xml stylesheets/fo.xsl stylesheets/$(LINGUA)/fo.xsl + mkdir -p build/$(LINGUA)/pdf + java -classpath tools/fop/lib/saxon65.jar:tools/fop/lib/saxon65-dbxsl.jar:tools/fop/lib/xml-commons-resolver-1.2.jar:tools/fop/conf \ + com.icl.saxon.StyleSheet \ + -x org.apache.xml.resolver.tools.ResolvingXMLReader \ + -y org.apache.xml.resolver.tools.ResolvingXMLReader \ + -r org.apache.xml.resolver.tools.CatalogResolver \ + -o build/$(LINGUA)/source/hgbook.fo \ + build/$(LINGUA)/source/hgbook.xml \ + stylesheets/$(LINGUA)/fo.xsl \ + fop1.extensions=1 + + (cd build/$(LINGUA)/source && ../../../tools/fop/fop.sh hgbook.fo ../pdf/hgbook.pdf) +endif + +en/figs/%.png: en/figs/%.svg en/fixsvg + en/fixsvg $< + inkscape -D -d 120 -e $@ $<-tmp.svg + +en/figs/%.svg: en/figs/%.dot + dot -Tsvg -o $@ $< diff -r 9e8e5292acaa -r 1c13ed2130a7 README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,99 @@ +HOW-TO: Compiling the Mercurial Book +====================================== + +This Mercurial Book is written in DocBook 4.5. + +The goal of this document is to give simple instructions to anyone who +wants to compile this book into a useful format, like HTML or PDF. It +should state *exactly* which tools to use, and how to invoke them, in +simplest terms. + +Table of Contents: + + I. PRIMER + II. COMPILING THE DOCS +III. HACKING ON THE DOCS + +I. PRIMER + + DocBook has a tortured, confusing history. Before you do anything, + take a look at Eric Raymond's excellent "DocBook Demystification HOWTO": + + http://tldp.org/HOWTO/DocBook-Demystification-HOWTO/ + + It's very short and clears up many things. + + +II. COMPILING THE DOCS + + +1. Install XML DTD and XSL stylesheets for DocBook + + % sudo apt-get install docbook-xml docbook-xsl + +2. Install libxml2-utils + + % sudo apt-get install libxml2-utils + +3. Install graph drawing tools + + % sudo apt-get install graphviz inkscape + +4. Install pdf support + + % sudo apt-get install openjdk-6-jdk docbook-xsl-saxon libsaxon-java fop + + The Makefile will actually invoke tools/fop/fop.sh, you should do + some trick, let fop's CLASSPATH include saxon.jar and docbook-xsl-saxon.jar . + +5. Make + Run 'make' for more details, for example: + + * make all document(pdf, html and html-single for all languages) + % make all + + * make english document(pdf, html and html-single for all languages) + % make LINGUA=en all + + * make Chinese document(pdf, html and html-single for all languages) + % make LINGUA=zh all + + * make Chinese pdf document + % make LINGUA=zh pdf + +III. HACKING ON THE DOCS + +In addition to everything in section II: + + +1. Get a nice editing environment for SGML/XML. + + This isn't strictly required, but it's nice when your editor + colorizes things, understands the DTD, tells you what tags you can + insert, etc. + + If you use emacs, we recommend the PSGML major-mode. Most free + operating systems package it, or its home page is here: + + http://www.lysator.liu.se/projects/about_psgml.html + + If you use vim, you might check out xmledit, at: + + http://www.vim.org/scripts/script.php?script_id=301 + + +2. Get a validating parser. + + Actually, if you have what you need to compile the documentation, + then you almost certainly have an XML validator installed already - + it is called xmllint, and comes as part of libxml2. + + The makefile is preconfigured with a suitable invocation of it, + so simply run: + + $ make validate + +3. Read about DocBook. + + You'll want to get real intimate with a DocBook reference, such as + can be found at: http://www.docbook.org/tdg/en/html/ diff -r 9e8e5292acaa -r 1c13ed2130a7 contrib/hg-interdiff --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/hg-interdiff Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# +# Adapter for using interdiff with mercurial's extdiff extension. +# +# Copyright 2006 Bryan O'Sullivan +# +# This software may be used and distributed according to the terms of +# the GNU General Public License, incorporated herein by reference. + +import os, sys + +def walk(base): + # yield all non-directories below the base path. + for root, dirs, files in os.walk(base): + for f in files: + path = os.path.join(root, f) + yield path[len(base)+1:], path + else: + if os.path.isfile(base): + yield '', base + +# create list of unique file names under both directories. +files = dict(walk(sys.argv[1])) +files.update(walk(sys.argv[2])) +files = files.keys() +files.sort() + +def name(base, f): + if f: + path = os.path.join(base, f) + else: + path = base + # interdiff requires two files; use /dev/null if one is missing. + if os.path.exists(path): + return path + return '/dev/null' + +ret = 0 + +for f in files: + if os.system('interdiff "%s" "%s"' % (name(sys.argv[1], f), + name(sys.argv[2], f))): + ret = 1 + +sys.exit(ret) diff -r 9e8e5292acaa -r 1c13ed2130a7 contrib/hg-package --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/hg-package Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,66 @@ +#!/bin/sh + +build_dir=`dirname "$0"`/../build +rev_id=`hg parents --template '{date|shortdate}' | sed 's/-//g'` + +for l in en zh; do + ( + if [ ! -d "${build_dir}/${l}" ] ; then + continue + fi + + cd ${build_dir}/${l}; + + f='html' + if [ -f "${f}/index.html" ] ; then + d=hgbook-${l}-${f} + rm -fr ${d} && cp -r ${f} ${d} && tar czf ../${d}-${rev_id}.tar.gz ${d} + fi + + f='html-single' + if [ -f "${f}/hgbook.html" ] ; then + d=hgbook-${l}-${f} + rm -fr ${d} && cp -r ${f} ${d} && tar czf ../${d}-${rev_id}.tar.gz ${d} + fi + + if [ -f "pdf/hgbook.pdf" ] ; then + cp pdf/hgbook.pdf ../hgbook-${l}-${rev_id}.pdf + gzip -f9 ../hgbook-${l}-${rev_id}.pdf + fi + ) +done + +upload_pass=$1 +upload_user=$2 + +if [ "${upload_user}x" == "x" ]; then + upload_user="dongsheng.song" +fi + +if [ "${upload_pass}x" != "x" ]; then + ( + cd ${build_dir} + curl -s -O http://support.googlecode.com/svn/trunk/scripts/googlecode_upload.py + if [[ "0" != $? ]]; then + exit 1 + fi + + for l in en zh; do + if [ -f "hgbook-${l}-${rev_id}.pdf.gz" ] ; then + python googlecode_upload.py -u "dongsheng.song" -w "$1" \ + -p "i18n-zh" -l "Type-Docs,hgbook" \ + -s "Distributed revision control with Mercurial - ${l} - pdf" \ + hgbook-${l}-${rev_id}.pdf.gz + fi + + for f in html html-single; do + if [ -f "hgbook-${l}-${rev_id}.pdf.gz" ] ; then + python googlecode_upload.py -u "dongsheng.song" -w "$1" \ + -p "i18n-zh" -l "Type-Docs,hgbook" \ + -s "Distributed revision control with Mercurial - ${l} - ${f}" \ + hgbook-${l}-${f}-${rev_id}.tar.gz + fi + done + done + ) +fi diff -r 9e8e5292acaa -r 1c13ed2130a7 contrib/hg-replay --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/hg-replay Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# +# Adapter for using interdiff with mercurial's extdiff extension. +# +# Copyright 2006 Bryan O'Sullivan +# +# This software may be used and distributed according to the terms of +# the GNU General Public License, incorporated herein by reference. + +import os +import shutil +import sys +import tempfile + +if len(sys.argv) < 4: + print >> sys.stderr, ('usage: %s srcrepo destrepo cset-to-omit [...]' % + os.path.basename(sys.argv[0])) + sys.exit(1) + +srcrepo, destrepo = sys.argv[1], sys.argv[2] +omit = sys.argv[3:] + +changemap = {} +revs = [] + +parent = None + +sys.stdout.write('gathering history...') +sys.stdout.flush() + +for line in os.popen("hg --cwd %r log -r0:tip --template '{rev}:{node} {parents}\n'" % srcrepo): + changes = line.split() + cset = changes[0].split(':')[1] + rev = len(revs) + changemap[cset] = rev + if len(changes) >= 2: + p1 = int(changes[1].split(':', 1)[0]) + if len(changes) == 3: + p2 = int(changes[2].split(':', 1)[0]) + else: + p2 = None + if len(changes) == 1: + p1 = parent + revs.append((cset, p1, p2)) + parent = rev + +sys.stdout.write(' %d revs\n' % len(revs)) + +def findrev(r): + try: + i = int(r) + if str(i) == r: + rev = i + if rev < 0: + rev += len(revs) + if rev < 0 or rev > len(revs): + print >> sys.stderr, 'bad changeset: %r' % r + sys.exit(1) + cset = revs[rev][0] + except ValueError: + cset = r + matches = [changemap[c] for c in changemap if c.startswith(cset)] + if len(matches) != 1: + print >> sys.stderr, 'bad changeset: %r' % r + sys.exit(1) + rev = matches[0] + return rev + +def run(cmd): + print cmd + ret = os.system(cmd) + if ret: + print >> sys.stderr, 'failure:', cmd + sys.exit(1) + +omit = map(findrev, omit) +omit.sort() +newrevs = revs[:omit[0]] +tip = len(newrevs) - 1 +run('hg clone -q -r%s %r %r' % (tip, srcrepo, destrepo)) + +os.environ['HGMERGE'] = 'true' + +patchdir = tempfile.mkdtemp(prefix='replay.') +try: + run('hg --cwd %r export --git -o %r%s%%R %d:tip' % + (srcrepo, patchdir, os.sep, omit[0]+1)) + for rev in xrange(omit[0], len(revs)): + if rev in omit: + print 'omit', rev + newrevs.append((None, revs[rev][1], None)) + continue + _, p1, p2 = revs[rev] + np1 = newrevs[p1][1] + if tip != np1: + run('hg --cwd %r update -q -C %s' % (destrepo, np1)) + np2 = None + if p2: + np2 = newrevs[p2][1] + run('hg --cwd %r merge -q %s' % (destrepo, np2)) + print >> sys.stderr, 'XXX - cannot handle merges properly yet' + run('hg --cwd %r import -q -f %r%s%d' % (destrepo, patchdir, os.sep, rev)) + tip = len(newrevs) - 1 + newrevs.append((None, tip, np2)) +finally: + print 'cleaning up ...' + #shutil.rmtree(patchdir) diff -r 9e8e5292acaa -r 1c13ed2130a7 contrib/latex-to-docbook --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/latex-to-docbook Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,198 @@ +#!/usr/bin/python +# +# This is the most horrible of hacks. Pretend you're not looking. + +import cStringIO as StringIO +import re, sys + +sections = { + 'chapter': 'chapter', + 'section': 'sect1', + 'subsection': 'sect2', + 'subsubsection': 'sect3', + } + +envs = { + 'codesample2': 'programlisting', + 'codesample4': 'programlisting', + 'enumerate': 'orderedlist', + 'figure': 'informalfigure', + 'itemize': 'itemizedlist', + 'note': 'note', + 'quote': 'blockquote', + } + +def process(ifp, ofp): + print >> ofp, '\n' + stack = [] + para = True + inlist = 0 + for line in ifp: + if line.startswith('%%% Local Variables:'): + break + line = (line.rstrip() + .replace('~', ' ') + .replace('&', '&') + .replace('---', '&emdash;') + .replace('\_', '_') + .replace('\{', '{') + .replace('\}', '}') + .replace('\$', '$') + .replace('\%', '%') + .replace('\#', '#') + .replace('<', '<') + .replace('>', '>') + .replace('``', '') + .replace("''", '') + .replace('\\', '\\')) + line = re.sub(r'\s*\\(?:centering|small)\b\s*', '', line) + line = re.sub(r'\\(?:hgrc\\|hgrc)\b', + r' /.hgrc', line) + line = re.sub(r'\\item\[(?P[^]]+)\]', r'\item \g:', line) + line = re.sub(r'\\bug{(?P\d+)}', + r'issue \g', line) + line = re.sub(r'\\cite{([^}]+)}', r'\1', line) + line = re.sub(r'\\hggopt{(?P[^}]+)}', + r'', line) + line = re.sub(r'\\hgxopt{(?P[^}]+)}{(?P[^}]+)}{(?P[^}]+)}', + r'', line) + line = re.sub(r'\\hgxcmd{(?P[^}]+)}{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\hgext{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\hgopt{(?P[^}]+)}{(?P[^}]+)}', + r'', + line) + line = re.sub(r'\\cmdopt{(?P[^}]+)}{(?P[^}]+)}', + r'', + line) + line = re.sub(r'\\hgcmd{(?P[^}]+)}', + r'hg \g', line) + line = re.sub(r'\\caption{(?P[^}]+?)}', + r'\g', line) + line = re.sub(r'\\grafix{(?P[^}]+)}', + r'XXX add text', line) + line = re.sub(r'\\envar{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\rcsection{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\rcitem{(?P[^}]+)}{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\dirname{(?P[^}]+?)}', + r'\g', line) + line = re.sub(r'\\filename{(?P[^}]+?)}', + r'\g', line) + line = re.sub(r'\\tildefile{(?P[^}]+)}', + r'~/\g', line) + line = re.sub(r'\\sfilename{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\sdirname{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\interaction{(?P[^}]+)}', + r'', line) + line = re.sub(r'\\excode{(?P[^}]+)}', + r'', line) + line = re.sub(r'\\pymod{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\pymodclass{(?P[^}]+)}{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\url{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\href{(?P[^}]+)}{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\command{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\option{(?P[^}]+)}', + r'', line) + line = re.sub(r'\\ref{(?P[^}]+)}', r'', line) + line = re.sub(r'\\emph{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\texttt{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\textbf{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\hook{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\tplfilter{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\tplkword{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\tplkwfilt{(?P[^}]+)}{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\[vV]erb(.)(?P[^\1]+?)\1', + r'\g', line) + line = re.sub(r'\\package{(?P[^}]+)}', + r'\g', line) + line = re.sub(r'\\hgcmdargs{(?P[^}]+)}{(?P[^}]+)}', + r'hg \g \g', + line) + line = re.sub(r'\\cmdargs{(?P[^}]+)}{(?P[^}]+)}', + r'\g \g', + line) + m = re.match(r'\\(chapter|section|subsection|subsubsection){(.*)}', line) + if m: + kind, content = m.groups() + sec = sections[kind] + while stack and stack[-1] >= sec: + close = stack.pop() + print >> ofp, '' % close + stack.append(sec) + print >> ofp, '<%s>\n%s' % (sec, content) + else: + m = re.match(r'\s*\\(begin|end){(?P[^}]+)}', line) + if m: + if not para: + print >> ofp, '' + if inlist: + ofp.write('') + para = True + state, env = m.groups() + env = envs[env] + if state == 'begin': + ofp.write('<') + if env in ('itemizedlist', 'orderedlist'): + inlist = 1 + else: + ofp.write('> ofp, env + '>' + else: + if line.startswith('\\item '): + if inlist > 1: + print >> ofp, '' + print >> ofp, '' + else: + inlist = 2 + para = True + line = line[6:] + if line and para: + if inlist: + ofp.write('') + ofp.write('') + para = False + if not line and not para: + print >> ofp, '' + if inlist: + ofp.write('') + para = True + print >> ofp, line + while stack: + print >> ofp, '' % stack.pop() + ofp.write('\n'.join(['\n'])) + + +if __name__ == '__main__': + for name in sys.argv[1:]: + if not name.endswith('.tex'): + continue + newname = name[:-3] + 'xml' + ofp = StringIO.StringIO() + process(open(name), ofp) + s = ofp.getvalue() + s = re.sub('\n+', '', s, re.M) + open(newname, 'w').write(s) diff -r 9e8e5292acaa -r 1c13ed2130a7 contrib/sillybench.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/sillybench.py Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,177 @@ +#!/usr/bin/python +# +# Silly benchmarking program, to give a vague idea of how fast a few +# tools are on a handful of common operations. +# +# Use a fairly big and real source tarball to test with: Firefox +# 2.0.0.3 (37622 files, 5374 directories, 343MB unpacked onto +# 4KB-blocksize ext3). + +import csv +import os +import shutil +import sys +import tempfile +import time +import urllib2 + +url = 'ftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/2.0.0.3/source/firefox-2.0.0.3-source.tar.bz2' + +class CommandFailure(Exception): + pass + +class rcs(object): + def __init__(self): + self.logfp = open(self.__class__.__name__ + '.csv', 'w') + self.csv = csv.writer(self.logfp) + + def download(self): + name = url[url.rfind('/')+1:] + path = os.path.join(os.environ['HOME'], name) + if not os.path.isfile(path): + ofp = open(path + '.part', 'wb') + try: + ifp = urllib2.urlopen(url) + nbytes = ifp.info()['content-length'] + sys.stdout.write('%s: %s bytes ' % (name, nbytes)) + sys.stdout.flush() + while True: + data = ifp.read(131072) + if not data: break + sys.stdout.write('.') + sys.stdout.flush() + ofp.write(data) + del ofp + os.rename(path + '.part', path) + except: + if os.path.exists(path + '.part'): + os.unlink(path + '.part') + if os.path.exists(path): + os.unlink(path) + raise + return path + + def run(self, args, mustsucceed=True): + ret = os.spawnvp(os.P_WAIT, args[0], args) + if ret < 0: + msg = 'killed by signal %d' % (-ret) + if ret > 0: + msg = 'exited with status %d' % (ret) + if ret: + if mustsucceed: + raise CommandFailure('%s: %s' % (msg, ' '.join(args))) + print >> sys.stderr, 'WARNING: %s: %s' % (msg, ' '.join(args)) + + def time(self, *args, **kwargs): + start = time.time() + self.run(*args, **kwargs) + end = time.time() + return end - start + + def logtime(self, name, elapsed, rest=[]): + self.log('time:' + name, '%.3f' % elapsed, rest) + + def log(self, name, value, rest=[]): + item = (name, value, repr(rest)) + print ' '.join(item) + self.csv.writerow(item) + self.logfp.flush() + + def unpack(self): + tarball = self.download() + t = self.time(['tar', '-C', self.wdir, '-jxf', tarball]) + self.logtime('internal:untar', t) + for name in os.listdir(os.path.join(self.wdir, 'mozilla')): + os.rename(os.path.join(self.wdir, 'mozilla', name), + os.path.join(self.wdir, name)) + + def cleanup(self): + pass + + def add(self, paths): + pass + + def commit(self, msg, paths): + pass + + def status(self, path): + pass + + def remove(self, path): + pass + + +class subversion(rcs): + def __init__(self, root): + rcs.__init__(self) + self.repo = os.path.join(root, 'repo') + self.wdir = os.path.join(root, 'wc') + create = self.time(['svnadmin', 'create', '--fs-type=fsfs', self.repo]) + self.logtime('svn:create', create) + co = self.time(['svn', 'co', 'file://' + self.repo, self.wdir]) + self.logtime('svn:co', co) + self.logtime('init', create + co) + os.chdir(self.wdir) + + def dropmeta(self, names): + return [n for n in names if os.path.basename(n) != '.svn'] + + def add(self, paths): + t = self.time(['svn', 'add', '-q'] + paths) + self.logtime('add %r' % paths, t) + + def commit(self, msg, paths=[]): + if paths: + t = self.time(['svn', 'ci', '-q', '-m', msg] + paths) + else: + t = self.time(['svn', 'ci', '-q', '-m', msg]) + self.logtime('commit %r' % paths, t) + + +class mercurial(rcs): + def __init__(self, root): + rcs.__init__(self) + self.repo = os.path.join(root, 'repo') + self.wdir = self.repo + init = self.time(['hg', 'init', self.repo]) + self.logtime('init', init) + os.chdir(self.wdir) + + def dropmeta(self, names): + return [n for n in names if os.path.basename(n) != '.hg'] + + def add(self, paths): + t = self.time(['hg', 'add', '-q'] + paths) + self.logtime('add %r' % paths, t) + + def commit(self, msg, paths=[]): + if paths: + t = self.time(['hg', 'ci', '-q', '-m', msg] + paths) + else: + t = self.time(['hg', 'ci', '-q', '-m', msg]) + self.logtime('commit %r' % paths, t) + +def benchmark(cls): + oldcwd = os.getcwd() + root = tempfile.mkdtemp(prefix='sillybench.') + try: + print 'root', root + inst = cls(root) + inst.unpack() + names = inst.dropmeta(os.listdir('.')) + dirs = [n for n in names if os.path.isdir(n)] + nondirs = [n for n in names if not os.path.isdir(n)] + dirs.sort(key=hash) + names.sort(key=hash) + for d in dirs[:len(dirs)/2]: + inst.add([d]) + inst.commit('Add %r' % d, [d]) + inst.add(dirs[len(dirs)/2:] + names) + inst.commit('Add remaining dirs and files') + finally: + print >> sys.stderr, '[cleaning up...]' + shutil.rmtree(root) + os.chdir(oldcwd) + +benchmark(mercurial) +#benchmark(subversion) diff -r 9e8e5292acaa -r 1c13ed2130a7 en/00book.xml --- a/en/00book.xml Fri Mar 27 00:41:15 2009 -0700 +++ b/en/00book.xml Mon Mar 30 16:23:33 2009 +0800 @@ -39,6 +39,11 @@ Mercurial: The Definitive Guide + + + Compiled from $rev_id$ diff -r 9e8e5292acaa -r 1c13ed2130a7 en/Makefile --- a/en/Makefile Fri Mar 27 00:41:15 2009 -0700 +++ b/en/Makefile Mon Mar 30 16:23:33 2009 +0800 @@ -112,18 +112,18 @@ all: web -../xsl/system-xsl: $(system-xsl-dir) +../stylesheets/system-xsl: $(system-xsl-dir) ln -s $< $@ -web: ../xsl/system-xsl websup html +web: ../stylesheets/system-xsl websup html html: $(obj-web-read)/index.html ../web/index-read.html.in: ../web/genindex.py $(xml-src-files) $< -$(obj-web-read)/index.html: ../xsl/system-xsl .validated-00book.xml ../web/index-read.html.in - xsltproc $(xsltproc-opts) -o $(obj-web-read)/x ../xsl/chunk-stylesheet.xsl 00book.xml +$(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; \ @@ -131,11 +131,11 @@ websup: $(extras-web) $(image-web) mkdir -p $(obj-websup)/figs $(obj-web-read)/figs - cp ../xsl/system-xsl/images/*.png $(obj-websup)/figs + cp ../stylesheets/system-xsl/images/*.png $(obj-websup)/figs cp -f ../web/icons/*.png $(obj-websup)/figs -all-ids.dat: ../xsl/all-ids.xsl $(xml-src-files) - $(xsltproc) $(xsltproc-opts) -o $@ ../xsl/all-ids.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 diff -r 9e8e5292acaa -r 1c13ed2130a7 en/appA-cmdref.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/appB-mq-ref.xml --- a/en/appB-mq-ref.xml Fri Mar 27 00:41:15 2009 -0700 +++ b/en/appB-mq-ref.xml Mon Mar 30 16:23:33 2009 +0800 @@ -43,7 +43,7 @@ <command role="hg-ext-mq">qdelete</command>&emdash;delete a patch from the <filename role="special">series</filename> - file} + file The qdelete command removes the entry for a patch from the - + XXX add text diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch03-concepts.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch04-daily.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch05-collab.xml --- a/en/ch05-collab.xml Fri Mar 27 00:41:15 2009 -0700 +++ b/en/ch05-collab.xml Mon Mar 30 16:23:33 2009 +0800 @@ -272,7 +272,7 @@
Feature branches - + XXX add text
diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch06-filenames.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch07-branch.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch08-undo.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch09-hook.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch10-template.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch11-mq.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch12-mq-collab.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/ch13-hgext.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/auto-snippets.xml diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.init.out --- a/en/examples/results/backout.init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ hg init myrepo -$ cd myrepo -$ echo first change >> myfile -$ hg add myfile -$ hg commit -m 'first change' -$ echo second change >> myfile -$ hg commit -m 'second change' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.manual.backout.out --- a/en/examples/results/backout.manual.backout.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ echo third change >> myfile -$ hg commit -m 'third change' -$ hg backout -m 'back out second change' 1 -reverting myfile -created new head -changeset backs out changeset -the backout changeset is a new head - do not forget to merge -(use "backout --merge" if you want to auto-merge) - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.manual.cat.out --- a/en/examples/results/backout.manual.cat.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ cat myfile -first change -second change -third change - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.manual.clone.out --- a/en/examples/results/backout.manual.clone.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ cd .. -$ hg clone -r1 myrepo newrepo -requesting all changes -adding changesets -adding manifests -adding file changes -added 2 changesets with 2 changes to 1 files -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd newrepo - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.manual.heads.out --- a/en/examples/results/backout.manual.heads.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ hg heads -changeset: -tag: tip -parent: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: back out second change - -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: third change - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.manual.log.out --- a/en/examples/results/backout.manual.log.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ hg log --style compact -3[tip]:1 2009-03-10 04:37 +0000 bos - back out second change - -2 2009-03-10 04:37 +0000 bos - third change - -1 2009-03-10 04:37 +0000 bos - second change - -0 2009-03-10 04:37 +0000 bos - first change - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.manual.merge.out --- a/en/examples/results/backout.manual.merge.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ hg merge -merging myfile -0 files updated, 1 files merged, 0 files removed, 0 files unresolved -(branch merge, don't forget to commit) -$ hg commit -m 'merged backout with previous tip' -$ cat myfile -first change -third change - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.manual.parents.out --- a/en/examples/results/backout.manual.parents.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -$ hg parents -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: third change - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.non-tip.backout.out --- a/en/examples/results/backout.non-tip.backout.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ echo third change >> myfile -$ hg commit -m 'third change' -$ hg backout --merge -m 'back out second change' 1 -reverting myfile -created new head -changeset backs out changeset -merging with changeset -merging myfile -0 files updated, 1 files merged, 0 files removed, 0 files unresolved -(branch merge, don't forget to commit) - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.non-tip.cat.out --- a/en/examples/results/backout.non-tip.cat.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ cat myfile -first change -third change - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.non-tip.clone.out --- a/en/examples/results/backout.non-tip.clone.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ cd .. -$ hg clone -r1 myrepo non-tip-repo -requesting all changes -adding changesets -adding manifests -adding file changes -added 2 changesets with 2 changes to 1 files -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd non-tip-repo - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.simple.log.out --- a/en/examples/results/backout.simple.log.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ hg log --style compact -2[tip] 2009-03-10 04:37 +0000 bos - back out second change - -1 2009-03-10 04:37 +0000 bos - second change - -0 2009-03-10 04:37 +0000 bos - first change - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/backout.simple.out --- a/en/examples/results/backout.simple.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ hg backout -m 'back out second change' tip -reverting myfile -changeset backs out changeset -$ cat myfile -first change - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.commits.out --- a/en/examples/results/bisect.commits.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ - - - - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.help.out --- a/en/examples/results/bisect.help.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.init.out --- a/en/examples/results/bisect.init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.search.bad-init.out --- a/en/examples/results/bisect.search.bad-init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.search.good-init.out --- a/en/examples/results/bisect.search.good-init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.search.init.out --- a/en/examples/results/bisect.search.init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.search.mytest.out --- a/en/examples/results/bisect.search.mytest.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ - - - - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.search.reset.out --- a/en/examples/results/bisect.search.reset.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.search.rest.out --- a/en/examples/results/bisect.search.rest.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.search.step1.out --- a/en/examples/results/bisect.search.step1.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/bisect.search.step2.out --- a/en/examples/results/bisect.search.step2.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.branch.out --- a/en/examples/results/branch-named.branch.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg branch -default - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.branches.out --- a/en/examples/results/branch-named.branches.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ hg tip -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Initial commit - -$ hg branches -default - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.commit.out --- a/en/examples/results/branch-named.commit.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ echo 'hello again' >> myfile -$ hg commit -m 'Second commit' -$ hg tip -changeset: -branch: foo -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Second commit - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.create.out --- a/en/examples/results/branch-named.create.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg branch foo -marked working directory as branch foo -$ hg branch -foo - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.foo-commit.out --- a/en/examples/results/branch-named.foo-commit.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -$ echo something > somefile -$ hg commit -A -m 'New file' -adding somefile -created new head -$ hg heads -changeset: -branch: foo -tag: tip -parent: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: New file - -changeset: -branch: bar -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Third commit - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.merge.out --- a/en/examples/results/branch-named.merge.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -$ hg branch -bar -$ hg merge foo -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -(branch merge, don't forget to commit) -$ hg commit -m 'Merge' -$ hg tip -changeset: -branch: bar -tag: tip -parent: -parent: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Merge - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.parents.out --- a/en/examples/results/branch-named.parents.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -$ hg parents -changeset: -branch: bar -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Third commit - -$ hg branches -bar -foo (inactive) -default (inactive) - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.rebranch.out --- a/en/examples/results/branch-named.rebranch.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -$ hg branch -foo -$ hg branch bar -marked working directory as branch bar -$ echo new file > newfile -$ hg commit -A -m 'Third commit' -adding newfile -$ hg tip -changeset: -branch: bar -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Third commit - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.status.out --- a/en/examples/results/branch-named.status.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ hg status -$ hg tip -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Initial commit - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.update-bar.out --- a/en/examples/results/branch-named.update-bar.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg update bar -1 files updated, 0 files merged, 1 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.update-foo.out --- a/en/examples/results/branch-named.update-foo.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -$ \textbf{hg update foo} -0 files updated, 0 files merged, 1 files removed, 0 files unresolved -$ \textbf{hg update} -0 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ \textbf{hg parents} -changeset: -branch: foo -user: Bryan O'Sullivan - -summary: Second commit - -$ \textbf{hg update bar} -1 files updated, 0 files merged, 0 files removed, 0 files unresolved diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.update-nothing.out --- a/en/examples/results/branch-named.update-nothing.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg update foo -0 files updated, 0 files merged, 1 files removed, 0 files unresolved -$ hg update -0 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.update-switchy.out --- a/en/examples/results/branch-named.update-switchy.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -$ hg update foo -0 files updated, 0 files merged, 1 files removed, 0 files unresolved -$ hg parents -changeset: -branch: foo -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Second commit - -$ hg update bar -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ hg parents -changeset: -branch: bar -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Third commit - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-named.update.out --- a/en/examples/results/branch-named.update.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -$ \textbf{hg update foo} -0 files updated, 0 files merged, 1 files removed, 0 files unresolved -$ \textbf{hg update} -0 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ \textbf{hg parent} -changeset: -branch: foo -user: Bryan O'Sullivan - -summary: Second commit - -$ \textbf{hg update bar} -1 files updated, 0 files merged, 0 files removed, 0 files unresolved diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-repo.bugfix.out --- a/en/examples/results/branch-repo.bugfix.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ hg clone myproject-1.0.1 my-1.0.1-bugfix -updating working directory -2 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd my-1.0.1-bugfix -$ echo 'I fixed a bug using only echo!' >> myfile -$ hg commit -m 'Important fix for 1.0.1' -$ hg push -pushing to -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-repo.clone.out --- a/en/examples/results/branch-repo.clone.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ cd .. -$ hg clone myproject myproject-1.0.1 -updating working directory -2 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-repo.merge.out --- a/en/examples/results/branch-repo.merge.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -$ hg merge -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -(branch merge, don't forget to commit) -$ hg commit -m 'Merge bugfix from 1.0.1 branch' -$ hg push -pushing to -searching for changes -adding changesets -adding manifests -adding file changes -added 2 changesets with 1 changes to 1 files - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-repo.new.out --- a/en/examples/results/branch-repo.new.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -$ cd .. -$ hg clone myproject my-feature -updating working directory -2 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd my-feature -$ echo 'This sure is an exciting new feature!' > mynewfile -$ hg commit -A -m 'New feature' -adding mynewfile -$ hg push -pushing to -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-repo.pull.out --- a/en/examples/results/branch-repo.pull.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ cd .. -$ hg clone myproject myproject-merge -updating working directory -3 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd myproject-merge -$ hg pull ../myproject-1.0.1 -pulling from ../myproject-1.0.1 -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files (+1 heads) -(run 'hg heads' to see heads, 'hg merge' to merge) - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branch-repo.tag.out --- a/en/examples/results/branch-repo.tag.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ cd myproject -$ hg tag v1.0 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branching.clone.out --- a/en/examples/results/branching.clone.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ cd .. -$ hg clone -rv1.0 main stable -requesting all changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branching.init.out --- a/en/examples/results/branching.init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ hg init main -$ cd main -$ echo 'This is a boring feature.' > myfile -$ hg commit -A -m 'We have reached an important milestone!' -adding myfile - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branching.main.out --- a/en/examples/results/branching.main.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -$ cd ../main -$ echo 'This is exciting and new!' >> myfile -$ hg commit -m 'Add a new feature' -$ cat myfile -This is a boring feature. -This is exciting and new! - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branching.merge.out --- a/en/examples/results/branching.merge.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -$ cd ../main -$ hg pull ../stable -pulling from ../stable -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files (+1 heads) -(run 'hg heads' to see heads, 'hg merge' to merge) -$ hg merge -merging myfile -0 files updated, 1 files merged, 0 files removed, 0 files unresolved -(branch merge, don't forget to commit) -$ hg commit -m 'Bring in bugfix from stable branch' -$ cat myfile -This is a fix to a boring feature. -This is exciting and new! - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branching.stable.out --- a/en/examples/results/branching.stable.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ hg clone stable stable-fix -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd stable-fix -$ echo 'This is a fix to a boring feature.' > myfile -$ hg commit -m 'Fix a bug' -$ hg push -pushing to -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branching.tag.out --- a/en/examples/results/branching.tag.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -$ hg tag v1.0 -$ hg tip -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added tag v1.0 for changeset - -$ hg tags -tip -v1.0 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/branching.update.out --- a/en/examples/results/branching.update.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ cd .. -$ hg clone -U main main-old -$ cd main-old -$ hg update v1.0 -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cat myfile -This is a boring feature. - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/cmdref.diff-p.out --- a/en/examples/results/cmdref.diff-p.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -$ echo '[diff]' >> $HGRC -$ echo 'showfunc = False' >> $HGRC -$ hg diff -diff -r myfile.c - - -@@ -1,4 +1,4 @@ - int myfunc() - { -- return 1; -+ return 10; - } -$ hg diff -p -diff -r myfile.c - - -@@ -1,4 +1,4 @@ - int myfunc() - { -- return 1; -+ return 10; - } - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.after.out --- a/en/examples/results/daily.copy.after.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ cp a z -$ hg copy --after a z - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.cat.out --- a/en/examples/results/daily.copy.cat.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ cat file -line -new contents -$ cat ../my-copy/new-file -line - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.clone.out --- a/en/examples/results/daily.copy.clone.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ cd .. -$ hg clone my-copy your-copy -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.copy.out --- a/en/examples/results/daily.copy.copy.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ cd my-copy -$ hg copy file new-file - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.dir-dest.out --- a/en/examples/results/daily.copy.dir-dest.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ mkdir d -$ hg copy a b d -$ ls d -a b - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.dir-src-dest.out --- a/en/examples/results/daily.copy.dir-src-dest.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg copy c d -copying c/a/c to d/c/a/c - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.dir-src.out --- a/en/examples/results/daily.copy.dir-src.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg copy c e -copying c/a/c to e/a/c - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.init.out --- a/en/examples/results/daily.copy.init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ hg init my-copy -$ cd my-copy -$ echo line > file -$ hg add file -$ hg commit -m 'Added a file' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.merge.out --- a/en/examples/results/daily.copy.merge.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -$ hg pull ../my-copy -pulling from ../my-copy -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files (+1 heads) -(run 'hg heads' to see heads, 'hg merge' to merge) -$ hg merge -merging file and new-file to new-file -0 files updated, 1 files merged, 0 files removed, 0 files unresolved -(branch merge, don't forget to commit) -$ cat new-file -line -new contents - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.other.out --- a/en/examples/results/daily.copy.other.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ cd ../your-copy -$ echo 'new contents' >> file -$ hg commit -m 'Changed file' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.simple.out --- a/en/examples/results/daily.copy.simple.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ mkdir k -$ hg copy a k -$ ls k -a - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.status-copy.out --- a/en/examples/results/daily.copy.status-copy.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg status -C -A new-file - file -$ hg commit -m 'Copied file' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.copy.status.out --- a/en/examples/results/daily.copy.status.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg status -A new-file - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.files.add-dir.out --- a/en/examples/results/daily.files.add-dir.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ mkdir b -$ echo b > b/b -$ echo c > b/c -$ mkdir b/d -$ echo d > b/d/d -$ hg add b -adding b/b -adding b/c -adding b/d/d -$ hg commit -m 'Added all files in subdirectory' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.files.add.out --- a/en/examples/results/daily.files.add.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ hg init add-example -$ cd add-example -$ echo a > a -$ hg status -? a -$ hg add a -$ hg status -A a -$ hg commit -m 'Added one file' -$ hg status - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.files.addremove.out --- a/en/examples/results/daily.files.addremove.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ hg init addremove-example -$ cd addremove-example -$ echo a > a -$ echo b > b -$ hg addremove -adding a -adding b - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.files.commit-addremove.out --- a/en/examples/results/daily.files.commit-addremove.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ echo c > c -$ hg commit -A -m 'Commit with addremove' -adding c - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.files.hidden.out --- a/en/examples/results/daily.files.hidden.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -$ hg init hidden-example -$ cd hidden-example -$ mkdir empty -$ touch empty/.hidden -$ hg add empty/.hidden -$ hg commit -m 'Manage an empty-looking directory' -$ ls empty -$ cd .. -$ hg clone hidden-example tmp -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ ls tmp -empty -$ ls tmp/empty - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.files.missing.out --- a/en/examples/results/daily.files.missing.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ hg init missing-example -$ cd missing-example -$ echo a > a -$ hg add a -$ hg commit -m 'File about to be missing' -$ rm a -$ hg status -! a - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.files.recover-missing.out --- a/en/examples/results/daily.files.recover-missing.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg revert a -$ cat a -a -$ hg status - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.files.remove-after.out --- a/en/examples/results/daily.files.remove-after.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ hg remove --after a -$ hg status -R a - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.files.remove.out --- a/en/examples/results/daily.files.remove.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ hg init remove-example -$ cd remove-example -$ echo a > a -$ mkdir b -$ echo b > b/b -$ hg add a b -adding b/b -$ hg commit -m 'Small example for file removal' -$ hg remove a -$ hg status -R a -$ hg remove b -removing b/b - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.rename.rename.out --- a/en/examples/results/daily.rename.rename.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -$ hg rename a b - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.rename.status-copy.out --- a/en/examples/results/daily.rename.status-copy.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg status -C -A b - a -R a - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.rename.status.out --- a/en/examples/results/daily.rename.status.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ hg status -A b -R a - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.revert.add.out --- a/en/examples/results/daily.revert.add.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ echo oops > oops -$ hg add oops -$ hg status oops -A oops -$ hg revert oops -$ hg status -? oops - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.revert.copy.out --- a/en/examples/results/daily.revert.copy.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg copy file new-file -$ hg revert new-file -$ hg status -? new-file - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.revert.missing.out --- a/en/examples/results/daily.revert.missing.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -$ rm file -$ hg status -! file -$ hg revert file -$ ls file -file - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.revert.modify.out --- a/en/examples/results/daily.revert.modify.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ cat file -original content -$ echo unwanted change >> file -$ hg diff file -diff -r file - - -@@ -1,1 +1,2 @@ - original content -+unwanted change - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.revert.remove.out --- a/en/examples/results/daily.revert.remove.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ hg remove file -$ hg status -R file -$ hg revert file -$ hg status -$ ls file -file - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.revert.rename-orig.out --- a/en/examples/results/daily.revert.rename-orig.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg revert file -no changes needed to file -$ hg status -? new-file - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.revert.rename.out --- a/en/examples/results/daily.revert.rename.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg rename file new-file -$ hg revert new-file -$ hg status -? new-file - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.revert.status.out --- a/en/examples/results/daily.revert.status.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ hg status -? file.orig -$ cat file.orig -original content -unwanted change - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/daily.revert.unmodify.out --- a/en/examples/results/daily.revert.unmodify.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ hg status -M file -$ hg revert file -$ cat file -original content - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/extdiff.diff.out --- a/en/examples/results/extdiff.diff.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ hg diff -diff -r myfile - - -@@ -1,1 +1,2 @@ - The first line. -+The second line. - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/extdiff.extdiff-ctx.out --- a/en/examples/results/extdiff.extdiff-ctx.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ hg extdiff -o -NprcC5 - - -*************** -*** 1 **** - - The first line. -+ The second line. - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/extdiff.extdiff.out --- a/en/examples/results/extdiff.extdiff.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -$ hg extdiff - - -@@ -1 +1,2 @@ - The first line. -+The second line. - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.dirs.out --- a/en/examples/results/filenames.dirs.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ hg status src -? src/main.py -? src/watcher/_watcher.c -? src/watcher/watcher.py -? src/xyzzy.txt - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.files.out --- a/en/examples/results/filenames.files.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -$ hg add COPYING README examples/simple.py - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.filter.exclude.out --- a/en/examples/results/filenames.filter.exclude.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ hg status -X '**.py' src -? src/watcher/_watcher.c -? src/xyzzy.txt - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.filter.include.out --- a/en/examples/results/filenames.filter.include.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg status -I '*.in' -? MANIFEST.in - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.glob.group.out --- a/en/examples/results/filenames.glob.group.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ hg status 'glob:*.{in,py}' -? MANIFEST.in -? setup.py - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.glob.question.out --- a/en/examples/results/filenames.glob.question.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg status 'glob:**.?' -? src/watcher/_watcher.c - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.glob.range.out --- a/en/examples/results/filenames.glob.range.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ hg status 'glob:**[nr-t]' -? MANIFEST.in -? src/xyzzy.txt - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.glob.star-starstar.out --- a/en/examples/results/filenames.glob.star-starstar.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ hg status 'glob:*.py' -? setup.py -$ hg status 'glob:**.py' -A examples/simple.py -A src/main.py -? examples/performant.py -? setup.py -? src/watcher/watcher.py - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.glob.star.out --- a/en/examples/results/filenames.glob.star.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg add 'glob:*.py' -adding main.py - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.glob.starstar.out --- a/en/examples/results/filenames.glob.starstar.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ cd .. -$ hg status 'glob:**.py' -A examples/simple.py -A src/main.py -? examples/performant.py -? setup.py -? src/watcher/watcher.py - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.wdir-relname.out --- a/en/examples/results/filenames.wdir-relname.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -$ hg status -A COPYING -A README -A examples/simple.py -? MANIFEST.in -? examples/performant.py -? setup.py -? src/main.py -? src/watcher/_watcher.c -? src/watcher/watcher.py -? src/xyzzy.txt -$ hg status `hg root` -A ../COPYING -A ../README -A ../examples/simple.py -? ../MANIFEST.in -? ../examples/performant.py -? ../setup.py -? main.py -? watcher/_watcher.c -? watcher/watcher.py -? xyzzy.txt - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/filenames.wdir-subdir.out --- a/en/examples/results/filenames.wdir-subdir.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -$ cd src -$ hg add -n -adding ../MANIFEST.in -adding ../examples/performant.py -adding ../setup.py -adding main.py -adding watcher/_watcher.c -adding watcher/watcher.py -adding xyzzy.txt -$ hg add -n . -adding main.py -adding watcher/_watcher.c -adding watcher/watcher.py -adding xyzzy.txt - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/hook.msglen.go.out --- a/en/examples/results/hook.msglen.go.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ cat .hg/hgrc -[hooks] -pretxncommit.msglen = test `hg tip --template {desc} | wc -c` -ge 10 -$ echo a > a -$ hg add a -$ hg commit -A -m 'too short' -transaction abort! -rollback completed -abort: pretxncommit.msglen hook exited with status 1 -$ hg commit -A -m 'long enough' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/hook.msglen.run.out --- a/en/examples/results/hook.msglen.run.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ \textbf{cat .hg/hgrc} -[hooks] -pretxncommit.msglen = test `hg tip --template \{desc\} | wc -c` -ge 10 -$ \textbf{echo a > a} -$ \textbf{hg add a} -$ \textbf{hg commit -A -m 'too short'} -abort: pretxncommit.msglen hook exited with status 1 -transaction abort! -rollback completed -$ \textbf{hg commit -A -m 'long enough'} diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/hook.simple.ext.out --- a/en/examples/results/hook.simple.ext.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ echo 'commit.when = echo -n "date of commit: "; date' >> .hg/hgrc -$ echo a >> a -$ hg commit -m 'i have two hooks' -committed - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/hook.simple.init.out --- a/en/examples/results/hook.simple.init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -$ hg init hook-test -$ cd hook-test -$ echo '[hooks]' >> .hg/hgrc -$ echo 'commit = echo committed $HG_NODE' >> .hg/hgrc -$ cat .hg/hgrc -[hooks] -commit = echo committed $HG_NODE -$ echo a > a -$ hg add a -$ hg commit -m 'testing commit hook' -committed - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/hook.simple.pretxncommit.out --- a/en/examples/results/hook.simple.pretxncommit.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ cat check_bug_id -#!/bin/sh -# check that a commit comment mentions a numeric bug id -hg log -r $1 --template {desc} | grep -q "\<bug *[0-9]" -$ echo 'pretxncommit.bug_id_required = ./check_bug_id $HG_NODE' >> .hg/hgrc -$ echo a >> a -$ hg commit -m 'i am not mentioning a bug id' -transaction abort! -rollback completed -abort: pretxncommit.bug_id_required hook exited with status 1 -$ hg commit -m 'i refer you to bug 666' -committed - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/hook.ws.better.out --- a/en/examples/results/hook.ws.better.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -$ cat .hg/hgrc -[hooks] -pretxncommit.whitespace = .hg/check_whitespace.py -$ echo 'a ' >> a -$ hg commit -A -m 'add new line with trailing whitespace' -a, line 2: trailing whitespace added -commit message saved to .hg/commit.save -transaction abort! -rollback completed -abort: pretxncommit.whitespace hook exited with status 1 -$ sed -i 's, *$,,' a -$ hg commit -A -m 'trimmed trailing whitespace' -a, line 2: trailing whitespace added -commit message saved to .hg/commit.save -transaction abort! -rollback completed -abort: pretxncommit.whitespace hook exited with status 1 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/hook.ws.simple.out --- a/en/examples/results/hook.ws.simple.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -$ cat .hg/hgrc -[hooks] -pretxncommit.whitespace = hg export tip | (! egrep -q '^\+.*[ \t]$') -$ echo 'a ' > a -$ hg commit -A -m 'test with trailing whitespace' -adding a -transaction abort! -rollback completed -abort: pretxncommit.whitespace hook exited with status 1 -$ echo 'a' > a -$ hg commit -A -m 'drop trailing whitespace and try again' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/issue29.go.out --- a/en/examples/results/issue29.go.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -$ hg init issue29 -$ cd issue29 -$ echo a > a -$ hg ci -Ama -adding a -$ echo b > b -$ hg ci -Amb -adding b -$ hg up 0 -0 files updated, 0 files merged, 1 files removed, 0 files unresolved -$ mkdir b -$ echo b > b/b -$ hg ci -Amc -adding b/b -created new head -$ hg merge - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.dodiff.diff.out --- a/en/examples/results/mq.dodiff.diff.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ echo 'this is my original thought' > oldfile -$ echo 'i have changed my mind' > newfile -$ diff -u oldfile newfile > tiny.patch -$ cat tiny.patch - - -@@ -1 +1 @@ --this is my original thought -+i have changed my mind -$ patch < tiny.patch -patching file oldfile -$ cat oldfile -i have changed my mind - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.init.out --- a/en/examples/results/mq.guards.init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ hg qinit -$ hg qnew hello.patch -$ echo hello > hello -$ hg add hello -$ hg qrefresh -$ hg qnew goodbye.patch -$ echo goodbye > goodbye -$ hg add goodbye -$ hg qrefresh - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.qguard.neg.out --- a/en/examples/results/mq.guards.qguard.neg.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ hg qguard hello.patch -quux -$ hg qguard hello.patch -hello.patch: -quux - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.qguard.out --- a/en/examples/results/mq.guards.qguard.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg qguard -goodbye.patch: unguarded - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.qguard.pos.out --- a/en/examples/results/mq.guards.qguard.pos.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ hg qguard +foo -$ hg qguard -goodbye.patch: +foo - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.qselect.cat.out --- a/en/examples/results/mq.guards.qselect.cat.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ cat .hg/patches/guards -foo - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.qselect.error.out --- a/en/examples/results/mq.guards.qselect.error.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg qselect +foo -abort: guard '+foo' starts with invalid character: '+' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.qselect.foo.out --- a/en/examples/results/mq.guards.qselect.foo.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ hg qpop -a -patch queue now empty -$ hg qselect -no active guards -$ hg qselect foo -number of unguarded, unapplied patches has changed from 1 to 2 -$ hg qselect -foo - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.qselect.foobar.out --- a/en/examples/results/mq.guards.qselect.foobar.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ hg qselect foo bar -number of unguarded, unapplied patches has changed from 0 to 2 -$ hg qpop -a -no patches applied -$ hg qpush -a -applying hello.patch -applying goodbye.patch -now at: goodbye.patch - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.qselect.qpush.out --- a/en/examples/results/mq.guards.qselect.qpush.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg qpush -a -applying hello.patch -applying goodbye.patch -now at: goodbye.patch - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.qselect.quux.out --- a/en/examples/results/mq.guards.qselect.quux.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -$ hg qselect quux -number of guarded, applied patches has changed from 0 to 2 -$ hg qpop -a -patch queue now empty -$ hg qpush -a -patch series already fully applied - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.guards.series.out --- a/en/examples/results/mq.guards.series.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ cat .hg/patches/series -hello.patch #-quux -goodbye.patch #+foo - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.id.out.out --- a/en/examples/results/mq.id.out.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -$ \textbf{hg qapplied} -first.patch -second.patch -$ \textbf{hg log -r qbase:qtip} -changeset: -tag: first.patch -tag: qbase -user: Bryan O'Sullivan - -summary: patch queue: first.patch - -changeset: -tag: second.patch -tag: qtip -tag: tip -user: Bryan O'Sullivan - -summary: patch queue: second.patch - -$ \textbf{hg export second.patch} -# HG changeset patch -# User Bryan O'Sullivan - -# Node ID -# Parent -patch queue: second.patch - -diff -r -r other.c - - -@@ -0,0 +1,1 @@ -+double u; diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.id.output.out --- a/en/examples/results/mq.id.output.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -$ hg qapplied -first.patch -second.patch -$ hg log -r qbase:qtip -changeset: -tag: first.patch -tag: qbase -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: [mq]: first.patch - -changeset: -tag: qtip -tag: second.patch -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: [mq]: second.patch - -$ hg export second.patch -# HG changeset patch -# User Bryan O'Sullivan <bos@serpentine.com> - -# Node ID -# Parent -[mq]: second.patch - -diff -r -r other.c - - -@@ -0,0 +1,1 @@ -+double u; - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.qinit-help.help.out --- a/en/examples/results/mq.qinit-help.help.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -$ hg help qinit -hg qinit [-c] - -init a new queue repository - - The queue repository is unversioned by default. If -c is - specified, qinit will create a separate nested repository - for patches (qinit -c may also be run later to convert - an unversioned patch repository into a versioned one). - You can use qcommit to commit changes to this queue repository. - -options: - - -c --create-repo create queue repository - -use "hg -v help qinit" to show global options - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tarball.download.out --- a/en/examples/results/mq.tarball.download.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ download netplug-1.2.5.tar.bz2 -$ tar jxf netplug-1.2.5.tar.bz2 -$ cd netplug-1.2.5 -$ hg init -$ hg commit -q --addremove --message netplug-1.2.5 -$ cd .. -$ hg clone netplug-1.2.5 netplug -updating working directory -18 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tarball.newsource.out --- a/en/examples/results/mq.tarball.newsource.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ hg qpop -a -patch queue now empty -$ cd .. -$ download netplug-1.2.8.tar.bz2 -$ hg clone netplug-1.2.5 netplug-1.2.8 -updating working directory -18 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd netplug-1.2.8 -$ hg locate -0 | xargs -0 rm -$ cd .. -$ tar jxf netplug-1.2.8.tar.bz2 -$ cd netplug-1.2.8 -$ hg commit --addremove --message netplug-1.2.8 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tarball.qinit.out --- a/en/examples/results/mq.tarball.qinit.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -$ cd netplug -$ hg qinit -$ hg qnew -m 'fix build problem with gcc 4' build-fix.patch -$ perl -pi -e 's/int addr_len/socklen_t addr_len/' netlink.c -$ hg qrefresh -$ hg tip -p -changeset: -tag: qtip -tag: build-fix.patch -tag: tip -tag: qbase -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: fix build problem with gcc 4 - -diff -r -r netlink.c - - -@@ -275,7 +275,7 @@ - exit(1); - } - -- int addr_len = sizeof(addr); -+ socklen_t addr_len = sizeof(addr); - - if (getsockname(fd, (struct sockaddr *) &addr, &addr_len) == -1) { - do_log(LOG_ERR, "Could not get socket details: %m"); - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tarball.repush.out --- a/en/examples/results/mq.tarball.repush.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ cd ../netplug -$ hg pull ../netplug-1.2.8 -pulling from ../netplug-1.2.8 -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 12 changes to 12 files -(run 'hg update' to get a working copy) -$ hg qpush -a -(working directory not at tip) -applying build-fix.patch -now at: build-fix.patch - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tools.lsdiff.out --- a/en/examples/results/mq.tools.lsdiff.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -$ lsdiff -nvv remove-redundant-null-checks.patch -22 File #1 a/drivers/char/agp/sgi-agp.c - 24 Hunk #1 static int __devinit agp_sgi_init(void) -37 File #2 a/drivers/char/hvcs.c - 39 Hunk #1 static struct tty_operations hvcs_ops = - 53 Hunk #2 static int hvcs_alloc_index_list(int n) -69 File #3 a/drivers/message/fusion/mptfc.c - 71 Hunk #1 mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, in -85 File #4 a/drivers/message/fusion/mptsas.c - 87 Hunk #1 mptsas_probe_hba_phys(MPT_ADAPTER *ioc) -98 File #5 a/drivers/net/fs_enet/fs_enet-mii.c - 100 Hunk #1 static struct fs_enet_mii_bus *create_bu -111 File #6 a/drivers/net/wireless/ipw2200.c - 113 Hunk #1 static struct ipw_fw_error *ipw_alloc_er - 126 Hunk #2 static ssize_t clear_error(struct device - 140 Hunk #3 static void ipw_irq_tasklet(struct ipw_p - 150 Hunk #4 static void ipw_pci_remove(struct pci_de -164 File #7 a/drivers/scsi/libata-scsi.c - 166 Hunk #1 int ata_cmd_ioctl(struct scsi_device *sc -178 File #8 a/drivers/video/au1100fb.c - 180 Hunk #1 void __exit au1100fb_cleanup(void) - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tools.tools.out --- a/en/examples/results/mq.tools.tools.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -$ diffstat -p1 remove-redundant-null-checks.patch - drivers/char/agp/sgi-agp.c | 5 ++--- - drivers/char/hvcs.c | 11 +++++------ - drivers/message/fusion/mptfc.c | 6 ++---- - drivers/message/fusion/mptsas.c | 3 +-- - drivers/net/fs_enet/fs_enet-mii.c | 3 +-- - drivers/net/wireless/ipw2200.c | 22 ++++++---------------- - drivers/scsi/libata-scsi.c | 4 +--- - drivers/video/au1100fb.c | 3 +-- - 8 files changed, 19 insertions(+), 38 deletions(-) -$ filterdiff -i '*/video/*' remove-redundant-null-checks.patch - - -@@ -743,8 +743,7 @@ void __exit au1100fb_cleanup(void) - { - driver_unregister(&au1100fb_driver); - -- if (drv_info.opt_mode) -- kfree(drv_info.opt_mode); -+ kfree(drv_info.opt_mode); - } - - module_init(au1100fb_init); - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tutorial.add.out --- a/en/examples/results/mq.tutorial.add.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ echo 'file 3, line 1' >> file3 -$ hg qnew add-file3.patch -$ hg qnew -f add-file3.patch -abort: patch "add-file3.patch" already exists - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tutorial.qinit.out --- a/en/examples/results/mq.tutorial.qinit.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ hg init mq-sandbox -$ cd mq-sandbox -$ echo 'line 1' > file1 -$ echo 'another line 1' > file2 -$ hg add file1 file2 -$ hg commit -m'first change' -$ hg qinit - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tutorial.qnew.out --- a/en/examples/results/mq.tutorial.qnew.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -$ hg tip -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: first change - -$ hg qnew first.patch -$ hg tip -changeset: -tag: qtip -tag: first.patch -tag: tip -tag: qbase -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: [mq]: first.patch - -$ ls .hg/patches -first.patch series status - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tutorial.qnew2.out --- a/en/examples/results/mq.tutorial.qnew2.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -$ hg qnew second.patch -$ hg log --style=compact --limit=2 -2[qtip,second.patch,tip] 2009-03-10 04:38 +0000 bos - [mq]: second.patch - -1[first.patch,qbase] 2009-03-10 04:38 +0000 bos - [mq]: first.patch - -$ echo 'line 4' >> file1 -$ hg qrefresh -$ hg tip --style=compact --patch -2[qtip,second.patch,tip] 2009-03-10 04:38 +0000 bos - [mq]: second.patch - -diff -r -r file1 - - -@@ -1,3 +1,4 @@ - line 1 - line 2 - line 3 -+line 4 - -$ hg annotate file1 -0: line 1 -1: line 2 -1: line 3 -2: line 4 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tutorial.qpop.out --- a/en/examples/results/mq.tutorial.qpop.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -$ hg qapplied -first.patch -second.patch -$ hg qpop -now at: first.patch -$ hg qseries -first.patch -second.patch -$ hg qapplied -first.patch -$ cat file1 -line 1 -line 2 -line 3 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tutorial.qpush-a.out --- a/en/examples/results/mq.tutorial.qpush-a.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ hg qpush -a -applying second.patch -now at: second.patch -$ cat file1 -line 1 -line 2 -line 3 -line 4 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tutorial.qrefresh.out --- a/en/examples/results/mq.tutorial.qrefresh.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -$ echo 'line 2' >> file1 -$ hg diff -diff -r file1 - - -@@ -1,1 +1,2 @@ - line 1 -+line 2 -$ hg qrefresh -$ hg diff -$ hg tip --style=compact --patch -1[qtip,first.patch,tip,qbase] 2009-03-10 04:38 +0000 bos - [mq]: first.patch - -diff -r -r file1 - - -@@ -1,1 +1,2 @@ - line 1 -+line 2 - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tutorial.qrefresh2.out --- a/en/examples/results/mq.tutorial.qrefresh2.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -$ echo 'line 3' >> file1 -$ hg status -M file1 -$ hg qrefresh -$ hg tip --style=compact --patch -1[qtip,first.patch,tip,qbase] 2009-03-10 04:38 +0000 bos - [mq]: first.patch - -diff -r -r file1 - - -@@ -1,1 +1,3 @@ - line 1 -+line 2 -+line 3 - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/mq.tutorial.qseries.out --- a/en/examples/results/mq.tutorial.qseries.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -$ hg qseries -first.patch -second.patch -$ hg qapplied -first.patch -second.patch - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rename.divergent.clone.out --- a/en/examples/results/rename.divergent.clone.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -$ hg clone orig anne -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ hg clone orig bob -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rename.divergent.merge.out --- a/en/examples/results/rename.divergent.merge.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -# See http://www.selenic.com/mercurial/bts/issue455 -$ cd ../orig -$ hg pull -u ../anne -pulling from ../anne -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files -1 files updated, 0 files merged, 1 files removed, 0 files unresolved -$ hg pull ../bob -pulling from ../bob -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files (+1 heads) -(run 'hg heads' to see heads, 'hg merge' to merge) -$ hg merge -warning: detected divergent renames of foo to: - bar - quux -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -(branch merge, don't forget to commit) -$ ls -bar quux - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rename.divergent.rename.anne.out --- a/en/examples/results/rename.divergent.rename.anne.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ cd anne -$ hg mv foo bar -$ hg ci -m 'Rename foo to bar' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rename.divergent.rename.bob.out --- a/en/examples/results/rename.divergent.rename.bob.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ cd ../bob -$ hg mv foo quux -$ hg ci -m 'Rename foo to quux' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rollback.add.out --- a/en/examples/results/rollback.add.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg add b -$ hg commit -m 'Add file b, this time for real' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rollback.commit.out --- a/en/examples/results/rollback.commit.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg status -M a -$ echo b > b -$ hg commit -m 'Add file b' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rollback.rollback.out --- a/en/examples/results/rollback.rollback.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -$ hg rollback -rolling back last transaction -$ hg tip -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: First commit - -$ hg status -M a -? b - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rollback.status.out --- a/en/examples/results/rollback.status.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ hg status -? b -$ hg tip -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Add file b - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rollback.tip.out --- a/en/examples/results/rollback.tip.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/rollback.twice.out --- a/en/examples/results/rollback.twice.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg rollback -rolling back last transaction -$ hg rollback -no rollback information available - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tag.init.out --- a/en/examples/results/tag.init.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ hg init mytag -$ cd mytag -$ echo hello > myfile -$ hg commit -A -m 'Initial commit' -adding myfile - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tag.log.out --- a/en/examples/results/tag.log.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ hg log -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added tag v1.0 for changeset - -changeset: -tag: v1.0 -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Initial commit - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tag.log.v1.0.out --- a/en/examples/results/tag.log.v1.0.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ echo goodbye > myfile2 -$ hg commit -A -m 'Second commit' -adding myfile2 -$ hg log -r v1.0 -changeset: -tag: v1.0 -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Initial commit - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tag.remove.out --- a/en/examples/results/tag.remove.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ hg tag --remove v1.0 -$ hg tags -tip - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tag.replace.out --- a/en/examples/results/tag.replace.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ hg tag -r 1 v1.1 -$ hg tags -tip -v1.1 -$ hg tag -r 2 v1.1 -abort: tag 'v1.1' already exists (use -f to force) -$ hg tag -f -r 2 v1.1 -$ hg tags -tip -v1.1 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tag.tag.out --- a/en/examples/results/tag.tag.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -$ hg tag v1.0 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tag.tags.out --- a/en/examples/results/tag.tags.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ hg tags -tip -v1.0 - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tag.tip.out --- a/en/examples/results/tag.tip.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ hg tip -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added tag v1.1 for changeset - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.changelog.out --- a/en/examples/results/template.simple.changelog.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.combine.out --- a/en/examples/results/template.simple.combine.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.compact.out --- a/en/examples/results/template.simple.compact.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.datekeyword.out --- a/en/examples/results/template.simple.datekeyword.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.keywords.out --- a/en/examples/results/template.simple.keywords.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.manyfilters.out --- a/en/examples/results/template.simple.manyfilters.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.normal.out --- a/en/examples/results/template.simple.normal.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.rev.out --- a/en/examples/results/template.simple.rev.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.simplest.out --- a/en/examples/results/template.simple.simplest.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.simple.simplesub.out --- a/en/examples/results/template.simple.simplesub.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ - - - - - - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.svnstyle.id.out --- a/en/examples/results/template.svnstyle.id.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -$ hg log -r0 --template '{node}' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.svnstyle.result.out --- a/en/examples/results/template.svnstyle.result.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -$ hg log -r1 --style svn.style ------------------------------------------------------------------------- - -r1 | bos | - -added line to end of <<hello>> file. - -in addition, added a file with the helpful name (at least i hope that some -might consider it so) of goodbye. - ------------------------------------------------------------------------- - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.svnstyle.short.out --- a/en/examples/results/template.svnstyle.short.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ svn log -r9653 ------------------------------------------------------------------------- -r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines - -On reporting a route error, also include the status for the error, -rather than indicating a status of 0 when an error has occurred. - -Signed-off-by: Sean Hefty <sean.hefty@intel.com> - ------------------------------------------------------------------------- - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.svnstyle.simplest.out --- a/en/examples/results/template.svnstyle.simplest.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ cat svn.style -changeset = "{node|short}\n" -$ hg log -r1 --style svn.style - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.svnstyle.style.out --- a/en/examples/results/template.svnstyle.style.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ cat svn.style -header = '------------------------------------------------------------------------\n\n' -changeset = svn.template - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.svnstyle.syntax.error.out --- a/en/examples/results/template.svnstyle.syntax.error.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg log -r1 --style broken.style -abort: broken.style:1: parse error - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.svnstyle.syntax.input.out --- a/en/examples/results/template.svnstyle.syntax.input.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ cat broken.style -changeset = - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/template.svnstyle.template.out --- a/en/examples/results/template.svnstyle.template.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -$ cat svn.template -r{rev} | {author|user} | {date|isodate} ({date|rfc822date}) - -{desc|strip|fill76} - ------------------------------------------------------------------------- - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour-merge-conflict.commit.out --- a/en/examples/results/tour-merge-conflict.commit.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -$ cat > letter.txt <<EOF -> Greetings! -> I am Bryan O'Sullivan, no relation of the former -> Nigerian dictator Sani Abacha. -> EOF -$ hg resolve -m letter.txt -$ hg commit -m 'Send me your money' -$ hg tip -changeset: -tag: tip -parent: -parent: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Send me your money - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour-merge-conflict.cousin.out --- a/en/examples/results/tour-merge-conflict.cousin.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -$ cd .. -$ hg clone scam scam-cousin -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd scam-cousin -$ cat > letter.txt <<EOF -> Greetings! -> I am Shehu Musa Abacha, cousin to the former -> Nigerian dictator Sani Abacha. -> EOF -$ hg commit -m '419 scam, with cousin' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour-merge-conflict.merge.out --- a/en/examples/results/tour-merge-conflict.merge.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -$ export HGMERGE=merge -$ echo 'XXX this is broken and must be fixed' -XXX this is broken and must be fixed -$ hg merge -merging letter.txt -merge: warning: conflicts during merge -merging letter.txt failed! -0 files updated, 0 files merged, 0 files removed, 1 files unresolved -use 'hg resolve' to retry unresolved file merges -$ cat letter.txt -Greetings! -<<<<<<< /tmp/tour-merge-conflictBrdfE0/scam-merge/letter.txt -I am Shehu Musa Abacha, cousin to the former -======= -I am Alhaji Abba Abacha, son of the former ->>>>>>> /tmp/letter.txt~other.1ctEYy -Nigerian dictator Sani Abacha. - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour-merge-conflict.pull.out --- a/en/examples/results/tour-merge-conflict.pull.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -$ cd .. -$ hg clone scam-cousin scam-merge -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd scam-merge -$ hg pull -u ../scam-son -pulling from ../scam-son -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files (+1 heads) -not updating, since new heads added -(run 'hg heads' to see heads, 'hg merge' to merge) - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour-merge-conflict.son.out --- a/en/examples/results/tour-merge-conflict.son.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -$ cd .. -$ hg clone scam scam-son -updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd scam-son -$ cat > letter.txt <<EOF -> Greetings! -> I am Alhaji Abba Abacha, son of the former -> Nigerian dictator Sani Abacha. -> EOF -$ hg commit -m '419 scam, with son' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour-merge-conflict.wife.out --- a/en/examples/results/tour-merge-conflict.wife.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ cat > letter.txt <<EOF -> Greetings! -> I am Mariam Abacha, the wife of former -> Nigerian dictator Sani Abacha. -> EOF -$ hg add letter.txt -$ hg commit -m '419 scam, first draft' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.clone-pull.out --- a/en/examples/results/tour.clone-pull.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ cd .. -$ hg clone hello hello-pull -updating working directory -2 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.clone-push.out --- a/en/examples/results/tour.clone-push.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ cd .. -$ hg clone hello hello-push -updating working directory -2 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.clone.out --- a/en/examples/results/tour.clone.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ hg clone http://hg.serpentine.com/tutorial/hello -destination directory: hello -requesting all changes -adding changesets -adding manifests -adding file changes -added 5 changesets with 5 changes to 2 files -updating working directory -2 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.commit.out --- a/en/examples/results/tour.commit.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -$ hg commit - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.diff.out --- a/en/examples/results/tour.diff.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -$ hg diff -diff -r hello.c - - -@@ -8,5 +8,6 @@ - int main(int argc, char **argv) - { - printf("hello, world!\"); -+ printf("hello again!\n"); - return 0; - } - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.help.out --- a/en/examples/results/tour.help.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -$ hg help init -hg init [-e CMD] [--remotecmd CMD] [DEST] - -create a new repository in the given directory - - Initialize a new repository in the given directory. If the given - directory does not exist, it is created. - - If no directory is given, the current directory is used. - - It is possible to specify an ssh:// URL as the destination. - See 'hg help urls' for more information. - -options: - - -e --ssh specify ssh command to use - --remotecmd specify hg command to run on the remote side - -use "hg -v help init" to show global options - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.incoming.out --- a/en/examples/results/tour.incoming.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ cd hello-pull -$ hg incoming ../my-hello -comparing with ../my-hello -searching for changes -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added an extra line of output - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.log-r.out --- a/en/examples/results/tour.log-r.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -$ hg log -r 3 -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Get make to generate the final binary from a .o file. - -$ hg log -r -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Get make to generate the final binary from a .o file. - -$ hg log -r 1 -r 4 -changeset: -user: mpm@selenic.com - -summary: Create a makefile - -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Trim comments. - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.log-v.out --- a/en/examples/results/tour.log-v.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ hg log -v -r 3 -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -files: Makefile -description: -Get make to generate the final binary from a .o file. - - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.log-vp.out --- a/en/examples/results/tour.log-vp.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -$ hg log -v -p -r 2 -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -files: hello.c -description: -Introduce a typo into hello.c. - - -diff -r -r hello.c - - -@@ -11,6 +11,6 @@ - - int main(int argc, char **argv) - { -- printf("hello, world!\n"); -+ printf("hello, world!\"); - return 0; - } - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.log.out --- a/en/examples/results/tour.log.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -$ hg log -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Trim comments. - -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Get make to generate the final binary from a .o file. - -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Introduce a typo into hello.c. - -changeset: -user: mpm@selenic.com - -summary: Create a makefile - -changeset: -user: mpm@selenic.com - -summary: Create a standard "hello, world" program - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.log.range.out --- a/en/examples/results/tour.log.range.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -$ hg log -r 2:4 -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Introduce a typo into hello.c. - -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Get make to generate the final binary from a .o file. - -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Trim comments. - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.ls-a.out --- a/en/examples/results/tour.ls-a.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -$ cd hello -$ ls -a -. .. .hg Makefile hello.c - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.ls.out --- a/en/examples/results/tour.ls.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ ls -l - - -$ ls hello -Makefile hello.c - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.merge.cat.out --- a/en/examples/results/tour.merge.cat.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -$ cat hello.c -/* - * Placed in the public domain by Bryan O'Sullivan. This program is - * not covered by patents in the United States or other countries. - */ - -#include <stdio.h> - -int main(int argc, char **argv) -{ - printf("once more, hello.\n"); - printf("hello, world!\"); - return 0; -} -$ cat ../my-hello/hello.c -/* - * Placed in the public domain by Bryan O'Sullivan. This program is - * not covered by patents in the United States or other countries. - */ - -#include <stdio.h> - -int main(int argc, char **argv) -{ - printf("hello, world!\"); - printf("hello again!\n"); - return 0; -} - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.merge.clone.out --- a/en/examples/results/tour.merge.clone.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ cd .. -$ hg clone hello my-new-hello -updating working directory -2 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd my-new-hello -$ sed -i '/printf/i\\tprintf("once more, hello.\\n");' hello.c -$ hg commit -m 'A new hello for a new day.' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.merge.commit.out --- a/en/examples/results/tour.merge.commit.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -$ hg commit -m 'Merged changes' - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.merge.heads.out --- a/en/examples/results/tour.merge.heads.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -$ hg heads -changeset: -tag: tip -parent: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added an extra line of output - -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: A new hello for a new day. - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.merge.merge.out --- a/en/examples/results/tour.merge.merge.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg merge -merging hello.c -0 files updated, 1 files merged, 0 files removed, 0 files unresolved -(branch merge, don't forget to commit) - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.merge.parents.out --- a/en/examples/results/tour.merge.parents.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -$ hg parents -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: A new hello for a new day. - -changeset: -tag: tip -parent: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added an extra line of output - -$ cat hello.c -/* - * Placed in the public domain by Bryan O'Sullivan. This program is - * not covered by patents in the United States or other countries. - */ - -#include <stdio.h> - -int main(int argc, char **argv) -{ - printf("once more, hello.\n"); - printf("hello, world!\"); - printf("hello again!\n"); - return 0; -} - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.merge.pull.out --- a/en/examples/results/tour.merge.pull.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -$ hg pull ../my-hello -pulling from ../my-hello -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files (+1 heads) -(run 'hg heads' to see heads, 'hg merge' to merge) - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.merge.tip.out --- a/en/examples/results/tour.merge.tip.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ hg tip -changeset: -tag: tip -parent: -parent: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Merged changes - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.merge.update.out --- a/en/examples/results/tour.merge.update.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -$ hg update -abort: crosses branches (use 'hg merge' or 'hg update -C') - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.older.out --- a/en/examples/results/tour.older.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ hg update 2 -2 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ hg parents -changeset: -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Introduce a typo into hello.c. - -$ hg update -2 files updated, 0 files merged, 0 files removed, 0 files unresolved - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.outgoing.net.out --- a/en/examples/results/tour.outgoing.net.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -$ hg outgoing http://hg.serpentine.com/tutorial/hello -comparing with http://hg.serpentine.com/tutorial/hello -searching for changes -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added an extra line of output - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.outgoing.out --- a/en/examples/results/tour.outgoing.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -$ cd my-hello -$ hg outgoing ../hello-push -comparing with ../hello-push -searching for changes -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added an extra line of output - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.parents.out --- a/en/examples/results/tour.parents.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ hg parents -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added an extra line of output - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.pull.out --- a/en/examples/results/tour.pull.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -$ hg tip -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Trim comments. - -$ hg pull ../my-hello -pulling from ../my-hello -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files -(run 'hg update' to get a working copy) -$ hg tip -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -summary: Added an extra line of output - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.push.net.out --- a/en/examples/results/tour.push.net.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg push http://hg.serpentine.com/tutorial/hello -pushing to http://hg.serpentine.com/tutorial/hello -searching for changes -ssl required - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.push.nothing.out --- a/en/examples/results/tour.push.nothing.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ hg push ../hello-push -pushing to ../hello-push -searching for changes -no changes found - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.push.out --- a/en/examples/results/tour.push.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ hg push ../hello-push -pushing to ../hello-push -searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.reclone.out --- a/en/examples/results/tour.reclone.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -$ cd .. -$ hg clone hello my-hello -updating working directory -2 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ cd my-hello - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.sed.out --- a/en/examples/results/tour.sed.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -$ sed -i '/printf/a\\tprintf("hello again!\\n");' hello.c - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.status.out --- a/en/examples/results/tour.status.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -$ ls -Makefile hello.c -$ hg status -M hello.c - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.tip.out --- a/en/examples/results/tour.tip.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -$ hg tip -vp -changeset: -tag: tip -user: Bryan O'Sullivan <bos@serpentine.com> - -files: hello.c -description: -Added an extra line of output - - -diff -r -r hello.c - - -@@ -8,5 +8,6 @@ - int main(int argc, char **argv) - { - printf("hello, world!\"); -+ printf("hello again!\n"); - return 0; - } - - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.update.out --- a/en/examples/results/tour.update.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -$ grep printf hello.c - printf("hello, world!\"); -$ hg update tip -1 files updated, 0 files merged, 0 files removed, 0 files unresolved -$ grep printf hello.c - printf("hello, world!\"); - printf("hello again!\n"); - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/examples/results/tour.version.out --- a/en/examples/results/tour.version.out Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -$ hg version -Mercurial Distributed SCM (version ) - -Copyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - diff -r 9e8e5292acaa -r 1c13ed2130a7 en/figs/kdiff3.png Binary file en/figs/kdiff3.png has changed diff -r 9e8e5292acaa -r 1c13ed2130a7 en/figs/note.png Binary file en/figs/note.png has changed diff -r 9e8e5292acaa -r 1c13ed2130a7 examples/hg-interdiff --- a/examples/hg-interdiff Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# -# Adapter for using interdiff with mercurial's extdiff extension. -# -# Copyright 2006 Bryan O'Sullivan -# -# This software may be used and distributed according to the terms of -# the GNU General Public License, incorporated herein by reference. - -import os, sys - -def walk(base): - # yield all non-directories below the base path. - for root, dirs, files in os.walk(base): - for f in files: - path = os.path.join(root, f) - yield path[len(base)+1:], path - else: - if os.path.isfile(base): - yield '', base - -# create list of unique file names under both directories. -files = dict(walk(sys.argv[1])) -files.update(walk(sys.argv[2])) -files = files.keys() -files.sort() - -def name(base, f): - if f: - path = os.path.join(base, f) - else: - path = base - # interdiff requires two files; use /dev/null if one is missing. - if os.path.exists(path): - return path - return '/dev/null' - -ret = 0 - -for f in files: - if os.system('interdiff "%s" "%s"' % (name(sys.argv[1], f), - name(sys.argv[2], f))): - ret = 1 - -sys.exit(ret) diff -r 9e8e5292acaa -r 1c13ed2130a7 examples/hg-replay --- a/examples/hg-replay Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -#!/usr/bin/env python -# -# Adapter for using interdiff with mercurial's extdiff extension. -# -# Copyright 2006 Bryan O'Sullivan -# -# This software may be used and distributed according to the terms of -# the GNU General Public License, incorporated herein by reference. - -import os -import shutil -import sys -import tempfile - -if len(sys.argv) < 4: - print >> sys.stderr, ('usage: %s srcrepo destrepo cset-to-omit [...]' % - os.path.basename(sys.argv[0])) - sys.exit(1) - -srcrepo, destrepo = sys.argv[1], sys.argv[2] -omit = sys.argv[3:] - -changemap = {} -revs = [] - -parent = None - -sys.stdout.write('gathering history...') -sys.stdout.flush() - -for line in os.popen("hg --cwd %r log -r0:tip --template '{rev}:{node} {parents}\n'" % srcrepo): - changes = line.split() - cset = changes[0].split(':')[1] - rev = len(revs) - changemap[cset] = rev - if len(changes) >= 2: - p1 = int(changes[1].split(':', 1)[0]) - if len(changes) == 3: - p2 = int(changes[2].split(':', 1)[0]) - else: - p2 = None - if len(changes) == 1: - p1 = parent - revs.append((cset, p1, p2)) - parent = rev - -sys.stdout.write(' %d revs\n' % len(revs)) - -def findrev(r): - try: - i = int(r) - if str(i) == r: - rev = i - if rev < 0: - rev += len(revs) - if rev < 0 or rev > len(revs): - print >> sys.stderr, 'bad changeset: %r' % r - sys.exit(1) - cset = revs[rev][0] - except ValueError: - cset = r - matches = [changemap[c] for c in changemap if c.startswith(cset)] - if len(matches) != 1: - print >> sys.stderr, 'bad changeset: %r' % r - sys.exit(1) - rev = matches[0] - return rev - -def run(cmd): - print cmd - ret = os.system(cmd) - if ret: - print >> sys.stderr, 'failure:', cmd - sys.exit(1) - -omit = map(findrev, omit) -omit.sort() -newrevs = revs[:omit[0]] -tip = len(newrevs) - 1 -run('hg clone -q -r%s %r %r' % (tip, srcrepo, destrepo)) - -os.environ['HGMERGE'] = 'true' - -patchdir = tempfile.mkdtemp(prefix='replay.') -try: - run('hg --cwd %r export --git -o %r%s%%R %d:tip' % - (srcrepo, patchdir, os.sep, omit[0]+1)) - for rev in xrange(omit[0], len(revs)): - if rev in omit: - print 'omit', rev - newrevs.append((None, revs[rev][1], None)) - continue - _, p1, p2 = revs[rev] - np1 = newrevs[p1][1] - if tip != np1: - run('hg --cwd %r update -q -C %s' % (destrepo, np1)) - np2 = None - if p2: - np2 = newrevs[p2][1] - run('hg --cwd %r merge -q %s' % (destrepo, np2)) - print >> sys.stderr, 'XXX - cannot handle merges properly yet' - run('hg --cwd %r import -q -f %r%s%d' % (destrepo, patchdir, os.sep, rev)) - tip = len(newrevs) - 1 - newrevs.append((None, tip, np2)) -finally: - print 'cleaning up ...' - #shutil.rmtree(patchdir) diff -r 9e8e5292acaa -r 1c13ed2130a7 htdocs/hgicon.png Binary file htdocs/hgicon.png has changed diff -r 9e8e5292acaa -r 1c13ed2130a7 htdocs/index.en.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/htdocs/index.en.html Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,51 @@ + + + + + + + Distributed revision control with Mercurial + + + +

Distributed revision control with Mercurial

+ +

Welcome to the home of the book “Distributed revision + control with Mercurial”, by Bryan O'Sullivan. + This is a freely licensed book + about the Mercurial revision + control system.

+ + + +

How you can help Mercurial, and help free software

+ +

Mercurial is a member of the Software + Freedom Conservancy, a wonderful non-profit + organisation that offers its member projects legal and + administrative advice. The SFC can accept accept + donations (tax-free under IRS 501(c)(3), within the United + States) on behalf of its member projects. If you would like to + support Mercurial directly, please consider making a donation to + the SFC on its behalf.

+ +

If you would like to help free software developers to provide + their important public services without being impeded by legal + issues, please consider donating to the SFC's sister + organisation, the Software Freedom Law + Center.

+ + diff -r 9e8e5292acaa -r 1c13ed2130a7 htdocs/index.es.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/htdocs/index.es.html Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,53 @@ + + + + + + + Control Distribuido de Revisiones con Mercurial + + + +

Control Distribuido de Revisiones con Mercurial

+ +

Bienvenido al sito del libro “Control Distribuido de Revisiones con Mercurial”, en español, + por Bryan O'Sullivan. + Este libro está cobijado por una licencia abierta + y trata del sistema de control de revisiones + Mercurial. + +

Los traductores son Javier Rojas e + Igor Támara. En este sitio usted puede encontrar: +

+ Para más detalles acerca del proceso de traducción, por favor vea este + fichero. + +

¿Cómo puede usted ayudar a Mercurial, y el software libre?

+ +

Mercurial es miembro del Conservatorio + de Software Libre, una maravillosa organización sin ánimo + de lucro que ofrece a sus proyectos miembros consejo legal y + administrativo. La SFC acepta donaciones + (deducibles de impuestos bajo IRS 501(c)(3), dentro de los Estados Unidos) + en representación de sus proyectos miembros. Si desea dar un apoyo + directo a Mercurial, por favor considere hacer una donación a SFC + en su representación.

+ +

Si desea apoyar a los desarrolladores de software libre en su + importante servicio público sin estar impedido por cuestiones + legales, por favor considere donar a la organización hermana de + SFC, el Centro de Leyes de Software + Libre.

+ + diff -r 9e8e5292acaa -r 1c13ed2130a7 htdocs/index.html.var --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/htdocs/index.html.var Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,7 @@ +URI: index.en.html +Content-Language: en +Content-Type: text/html; charset=UTF-8 + +URI: index.es.html +Content-Language: es +Content-Type: text/html; charset=UTF-8 diff -r 9e8e5292acaa -r 1c13ed2130a7 html/hgicon.png Binary file html/hgicon.png has changed diff -r 9e8e5292acaa -r 1c13ed2130a7 html/index.en.html --- a/html/index.en.html Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ - - - - - - - Distributed revision control with Mercurial - - - -

Distributed revision control with Mercurial

- -

Welcome to the home of the book “Distributed revision - control with Mercurial”, by Bryan O'Sullivan. - This is a freely licensed book - about the Mercurial revision - control system.

- - - -

How you can help Mercurial, and help free software

- -

Mercurial is a member of the Software - Freedom Conservancy, a wonderful non-profit - organisation that offers its member projects legal and - administrative advice. The SFC can accept accept - donations (tax-free under IRS 501(c)(3), within the United - States) on behalf of its member projects. If you would like to - support Mercurial directly, please consider making a donation to - the SFC on its behalf.

- -

If you would like to help free software developers to provide - their important public services without being impeded by legal - issues, please consider donating to the SFC's sister - organisation, the Software Freedom Law - Center.

- - diff -r 9e8e5292acaa -r 1c13ed2130a7 html/index.es.html --- a/html/index.es.html Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ - - - - - - - Control Distribuido de Revisiones con Mercurial - - - -

Control Distribuido de Revisiones con Mercurial

- -

Bienvenido al sito del libro “Control Distribuido de Revisiones con Mercurial”, en español, - por Bryan O'Sullivan. - Este libro está cobijado por una licencia abierta - y trata del sistema de control de revisiones - Mercurial. - -

Los traductores son Javier Rojas e - Igor Támara. En este sitio usted puede encontrar: -

- Para más detalles acerca del proceso de traducción, por favor vea este - fichero. - -

¿Cómo puede usted ayudar a Mercurial, y el software libre?

- -

Mercurial es miembro del Conservatorio - de Software Libre, una maravillosa organización sin ánimo - de lucro que ofrece a sus proyectos miembros consejo legal y - administrativo. La SFC acepta donaciones - (deducibles de impuestos bajo IRS 501(c)(3), dentro de los Estados Unidos) - en representación de sus proyectos miembros. Si desea dar un apoyo - directo a Mercurial, por favor considere hacer una donación a SFC - en su representación.

- -

Si desea apoyar a los desarrolladores de software libre en su - importante servicio público sin estar impedido por cuestiones - legales, por favor considere donar a la organización hermana de - SFC, el Centro de Leyes de Software - Libre.

- - diff -r 9e8e5292acaa -r 1c13ed2130a7 html/index.html.var --- a/html/index.html.var Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -URI: index.en.html -Content-Language: en -Content-Type: text/html; charset=UTF-8 - -URI: index.es.html -Content-Language: es -Content-Type: text/html; charset=UTF-8 diff -r 9e8e5292acaa -r 1c13ed2130a7 po/zh.po --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/po/zh.po Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,16668 @@ +# +# Simplified Chinese translation for hgbook +# This file is distributed under the same license as the hgbook. +# +# Authors: +# Dongsheng Song , 2009 +# +# Update to new pot: +# msgmerge --update zh.po hgbook.pot +# +# Check translation: +# msgfmt --statistics -c -o zh.mo zh.po +# +# Please format your translation before commit: +# msgcat --sort-by-file --width=80 -o zh_new.po zh.po +# mv -f zh_new.po zh.po +# +# Dictionary: +# blame 追溯 +# branch 分支 +# changes 修改 +# changeset 修改集 +# checkout 检出 +# remove 移除(从版本库删除) +# delete 删除(只从文件系统删除) +# patchset 补丁集 +# pushing to 推到 +# pulling from 拉自,抓取 +# rename 改名 +# repository 版本库 +# revert 恢复 +# revision 版本 +# tag 标签 +# tip 顶点 +# undo 撤销 +# unversioned 未版本控制 +# versioned 受版本控制 +# working copy 工作副本 +# ... +# +msgid "" +msgstr "" +"Project-Id-Version: hgbook 1.2\n" +"POT-Creation-Date: 2009-03-20 17:12+0800\n" +"PO-Revision-Date: 2009-03-20 17:12+0800\n" +"Last-Translator: \n" +"Language-Team: Simplified Chinese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Chinese\n" +"X-Poedit-Country: CHINA\n" +"X-Poedit-SourceCharset: utf-8\n" + +#. type: Content of: +#: ../en/00book.xml:41 +msgid "Mercurial: The Definitive Guide" +msgstr "Mercurial 权威指南" + +#. type: Content of: <book><subtitle> +#: ../en/00book.xml:46 +msgid "Compiled from $rev_id$" +msgstr "编译自 $rev_id$" + +#. type: Content of: <book><bookinfo><authorgroup><author><firstname> +#: ../en/00book.xml:50 +msgid "Bryan" +msgstr "Bryan" + +#. type: Content of: <book><bookinfo><authorgroup><author><surname> +#: ../en/00book.xml:51 +msgid "O'Sullivan" +msgstr "O'Sullivan" + +#. type: Content of: <book><bookinfo> +#: ../en/00book.xml:55 +msgid "" +"<editor> <firstname>Mike</firstname> <surname>Loukides</surname> </editor> " +"<copyright> <year>2006</year> <year>2007</year> <year>2008</year> <year>2009</" +"year> <holder>Bryan O'Sullivan</holder> </copyright>" +msgstr "" +"<editor> <firstname>Mike</firstname> <surname>Loukides</surname> </editor> " +"<copyright> <year>2006</year> <year>2007</year> <year>2008</year> <year>2009</" +"year> <holder>Bryan O'Sullivan</holder> </copyright>" + +#. type: Content of: <book><appendix><title> +#: ../en/appA-cmdref.xml:4 +msgid "Command reference" +msgstr "命令参考" + +#. type: Content of: <book><appendix><para> +#: ../en/appA-cmdref.xml:6 +msgid "" +"\\cmdref{add}{add files at the next commit} \\optref{add}{I}{include} \\optref" +"{add}{X}{exclude} \\optref{add}{n}{dry-run}" +msgstr "" + +#. type: Content of: <book><appendix><para> +#: ../en/appA-cmdref.xml:11 +msgid "\\cmdref{diff}{print changes in history or working directory}" +msgstr "" + +#. type: Content of: <book><appendix><para> +#: ../en/appA-cmdref.xml:13 +msgid "" +"Show differences between revisions for the specified files or directories, " +"using the unified diff format. For a description of the unified diff format, " +"see section <xref linkend=\"sec.mq.patch\"/>." +msgstr "" + +#. type: Content of: <book><appendix><para> +#: ../en/appA-cmdref.xml:17 +msgid "" +"By default, this command does not print diffs for files that Mercurial " +"considers to contain binary data. To control this behaviour, see the <option " +"role=\"hg-opt-diff\">-a</option> and <option role=\"hg-opt-diff\">--git</" +"option> options." +msgstr "" + +#. type: Content of: <book><appendix><sect2><title> +#: ../en/appA-cmdref.xml:22 +msgid "Options" +msgstr "选项" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:24 +msgid "\\loptref{diff}{nodates}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:26 +msgid "Omit date and time information when printing diff headers." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:28 +msgid "\\optref{diff}{B}{ignore-blank-lines}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:30 +msgid "" +"Do not print changes that only insert or delete blank lines. A line that " +"contains only whitespace is not considered blank." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:34 +msgid "\\optref{diff}{I}{include}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:37 +msgid "Include files and directories whose names match the given patterns." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:40 +msgid "\\optref{diff}{X}{exclude}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:43 +msgid "Exclude files and directories whose names match the given patterns." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:46 +msgid "\\optref{diff}{a}{text}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:49 +msgid "" +"If this option is not specified, <command role=\"hg-cmd\">hg diff</command> " +"will refuse to print diffs for files that it detects as binary. Specifying " +"<option role=\"hg-opt-diff\">-a</option> forces <command role=\"hg-cmd\">hg " +"diff</command> to treat all files as text, and generate diffs for all of them." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:55 +msgid "" +"This option is useful for files that are <quote>mostly text</quote> 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." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:60 +msgid "\\optref{diff}{b}{ignore-space-change}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:63 +msgid "" +"Do not print a line if the only change to that line is in the amount of white " +"space it contains." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:67 +msgid "\\optref{diff}{g}{git}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:70 +msgid "" +"Print <command>git</command>-compatible diffs. XXX reference a format " +"description." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:74 +msgid "\\optref{diff}{p}{show-function}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:77 +msgid "" +"Display the name of the enclosing function in a hunk header, using a simple " +"heuristic. This functionality is enabled by default, so the <option role=" +"\"hg-opt-diff\">-p</option> option has no effect unless you change the value " +"of the <envar role=\"rc-item-diff\">showfunc</envar> config item, as in the " +"following example." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:84 +msgid "\\optref{diff}{r}{rev}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:87 +msgid "" +"Specify one or more revisions to compare. The <command role=\"hg-cmd\">hg " +"diff</command> command accepts up to two <option role=\"hg-opt-diff\">-r</" +"option> options to specify the revisions to compare." +msgstr "" + +#. type: Content of: <book><appendix><sect2><orderedlist><listitem><para> +#: ../en/appA-cmdref.xml:93 +msgid "" +"Display the differences between the parent revision of the working directory " +"and the working directory." +msgstr "" + +#. type: Content of: <book><appendix><sect2><orderedlist><listitem><para> +#: ../en/appA-cmdref.xml:97 +msgid "" +"Display the differences between the specified changeset and the working " +"directory." +msgstr "" + +#. type: Content of: <book><appendix><sect2><orderedlist><listitem><para> +#: ../en/appA-cmdref.xml:101 +msgid "Display the differences between the two specified changesets." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:105 +msgid "" +"You can specify two revisions using either two <option role=\"hg-opt-diff\">-" +"r</option> options or revision range notation. For example, the two revision " +"specifications below are equivalent." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:112 +msgid "" +"When you provide two revisions, Mercurial treats the order of those revisions " +"as significant. Thus, <command role=\"hg-cmd\">hg diff -r10:20</command> " +"will produce a diff that will transform files from their contents as of " +"revision 10 to their contents as of revision 20, while <command role=\"hg-cmd" +"\">hg diff -r20:10</command> means the opposite: the diff that will transform " +"files from their revision 20 contents to their revision 10 contents. You " +"cannot reverse the ordering in this way if you are diffing against the " +"working directory." +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:122 +msgid "\\optref{diff}{w}{ignore-all-space}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:125 +msgid "\\cmdref{version}{print version and copyright information}" +msgstr "" + +#. type: Content of: <book><appendix><sect2><para> +#: ../en/appA-cmdref.xml:128 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><appendix><sect2><itemizedlist><listitem><para> +#: ../en/appA-cmdref.xml:133 +msgid "" +"The string <quote><literal>unknown</literal></quote>. This version of " +"Mercurial was not built in a Mercurial repository, and cannot determine its " +"own version." +msgstr "" + +#. type: Content of: <book><appendix><sect2><itemizedlist><listitem><para> +#: ../en/appA-cmdref.xml:138 +msgid "" +"A short numeric string, such as <quote><literal>1.1</literal></quote>. This " +"is a build of a revision of Mercurial that was identified by a specific tag " +"in the repository where it was built. (This doesn't necessarily mean that " +"you're running an official release; someone else could have added that tag to " +"any revision in the repository where they built Mercurial.)" +msgstr "" + +#. type: Content of: <book><appendix><sect2><itemizedlist><listitem><para> +#: ../en/appA-cmdref.xml:146 +msgid "" +"A hexadecimal string, such as <quote><literal>875489e31abe</literal></" +"quote>. This is a build of the given revision of Mercurial." +msgstr "" + +#. type: Content of: <book><appendix><sect2><itemizedlist><listitem><para> +#: ../en/appA-cmdref.xml:150 +msgid "" +"A hexadecimal string followed by a date, such as <quote><literal>875489e31abe" +"+20070205</literal></quote>. This is a build of the given revision of " +"Mercurial, where the build repository contained some local changes that had " +"not been committed." +msgstr "" + +#. type: Content of: <book><appendix><sect2><title> +#: ../en/appA-cmdref.xml:159 +msgid "Tips and tricks" +msgstr "" + +#. type: Content of: <book><appendix><sect2><sect3><title> +#: ../en/appA-cmdref.xml:162 +msgid "" +"Why do the results of <command role=\"hg-cmd\">hg diff</command> and <command " +"role=\"hg-cmd\">hg status</command> differ?" +msgstr "" +"为什么 <command role=\"hg-cmd\">hg diff</command> 与 <command role=\"hg-cmd" +"\">hg status</command> 的结果不同 ?" + +#. type: Content of: <book><appendix><sect2><sect3><para> +#: ../en/appA-cmdref.xml:164 +msgid "" +"When you run the <command role=\"hg-cmd\">hg status</command> command, you'll " +"see a list of files that Mercurial will record changes for the next time you " +"perform a commit. If you run the <command role=\"hg-cmd\">hg diff</command> " +"command, you may notice that it prints diffs for only a <emphasis>subset</" +"emphasis> of the files that <command role=\"hg-cmd\">hg status</command> " +"listed. There are two possible reasons for this." +msgstr "" + +#. type: Content of: <book><appendix><sect2><sect3><para> +#: ../en/appA-cmdref.xml:171 +msgid "" +"The first is that <command role=\"hg-cmd\">hg status</command> prints some " +"kinds of modifications that <command role=\"hg-cmd\">hg diff</command> " +"doesn't normally display. The <command role=\"hg-cmd\">hg diff</command> " +"command normally outputs unified diffs, which don't have the ability to " +"represent some changes that Mercurial can track. Most notably, traditional " +"diffs can't represent a change in whether or not a file is executable, but " +"Mercurial records this information." +msgstr "" + +#. type: Content of: <book><appendix><sect2><sect3><para> +#: ../en/appA-cmdref.xml:179 +msgid "" +"If you use the <option role=\"hg-opt-diff\">--git</option> option to <command " +"role=\"hg-cmd\">hg diff</command>, it will display <command>git</command>-" +"compatible diffs that <emphasis>can</emphasis> display this extra information." +msgstr "" + +#. type: Content of: <book><appendix><sect2><sect3><para> +#: ../en/appA-cmdref.xml:184 +msgid "" +"The second possible reason that <command role=\"hg-cmd\">hg diff</command> " +"might be printing diffs for a subset of the files displayed by <command role=" +"\"hg-cmd\">hg status</command> is that if you invoke it without any " +"arguments, <command role=\"hg-cmd\">hg diff</command> prints diffs against " +"the first parent of the working directory. If you have run <command role=" +"\"hg-cmd\">hg merge</command> to merge two changesets, but you haven't yet " +"committed the results of the merge, your working directory has two parents " +"(use <command role=\"hg-cmd\">hg parents</command> to see them). While " +"<command role=\"hg-cmd\">hg status</command> prints modifications relative to " +"<emphasis>both</emphasis> parents after an uncommitted merge, <command role=" +"\"hg-cmd\">hg diff</command> 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 <option role=\"hg-opt-diff\">-r</option> " +"option. There is no way to print diffs relative to both parents." +msgstr "" + +#. type: Content of: <book><appendix><sect2><sect3><title> +#: ../en/appA-cmdref.xml:200 +msgid "Generating safe binary diffs" +msgstr "生成安全的二进制差异" + +#. type: Content of: <book><appendix><sect2><sect3><para> +#: ../en/appA-cmdref.xml:202 +msgid "" +"If you use the <option role=\"hg-opt-diff\">-a</option> option to force " +"Mercurial to print diffs of files that are either <quote>mostly text</quote> " +"or contain lots of binary data, those diffs cannot subsequently be applied by " +"either Mercurial's <command role=\"hg-cmd\">hg import</command> command or " +"the system's <command>patch</command> command." +msgstr "" + +#. type: Content of: <book><appendix><sect2><sect3><para> +#: ../en/appA-cmdref.xml:209 +msgid "" +"If you want to generate a diff of a binary file that is safe to use as input " +"for <command role=\"hg-cmd\">hg import</command>, use the <command role=\"hg-" +"cmd\">hg diff</command>{--git} option when you generate the patch. The " +"system <command>patch</command> command cannot handle binary patches at all." +msgstr "" + +#. type: Content of: <book><appendix><title> +#: ../en/appB-mq-ref.xml:5 +msgid "Mercurial Queues reference" +msgstr "Mercurial 队列参考" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appB-mq-ref.xml:8 +msgid "MQ command reference" +msgstr "MQ 命令参考" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appB-mq-ref.xml:10 +msgid "" +"For an overview of the commands provided by MQ, use the command <command role=" +"\"hg-cmd\">hg help mq</command>." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:14 +msgid "" +"<command role=\"hg-ext-mq\">qapplied</command>&emdash;print applied patches" +msgstr "<command role=\"hg-ext-mq\">qapplied</command>&emdash;显示已应用的补丁" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:17 +msgid "" +"The <command role=\"hg-ext-mq\">qapplied</command> command prints the current " +"stack of applied patches. Patches are printed in oldest-to-newest order, so " +"the last patch in the list is the <quote>top</quote> patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:24 +msgid "" +"<command role=\"hg-ext-mq\">qcommit</command>&emdash;commit changes in the " +"queue repository" +msgstr "<command role=\"hg-ext-mq\">qcommit</command>&emdash;提交队列中的修改" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:27 +msgid "" +"The <command role=\"hg-ext-mq\">qcommit</command> command commits any " +"outstanding changes in the <filename role=\"special\" class=\"directory\">.hg/" +"patches</filename> repository. This command only works if the <filename role=" +"\"special\" class=\"directory\">.hg/patches</filename> directory is a " +"repository, i.e. you created the directory using <command role=\"hg-cmd\">hg " +"qinit <option role=\"hg-ext-mq-cmd-qinit-opt\">-c</option></command> or ran " +"<command role=\"hg-cmd\">hg init</command> in the directory after running " +"<command role=\"hg-ext-mq\">qinit</command>." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:39 +msgid "" +"This command is shorthand for <command role=\"hg-cmd\">hg commit --cwd .hg/" +"patches</command>." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:43 +msgid "" +"<command role=\"hg-ext-mq\">qdelete</command>&emdash;delete a patch from the " +"<filename role=\"special\">series</filename> file" +msgstr "" +"<command role=\"hg-ext-mq\">qdelete</command>&emdash;从文件 <filename role=" +"\"special\">series</filename> 中删除补丁" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:48 +msgid "" +"The <command role=\"hg-ext-mq\">qdelete</command> command removes the entry " +"for a patch from the <filename role=\"special\">series</filename> file in the " +"<filename role=\"special\" class=\"directory\">.hg/patches</filename> " +"directory. It does not pop the patch if the patch is already applied. By " +"default, it does not delete the patch file; use the <option role=\"hg-ext-mq-" +"cmd-qdel-opt\">-f</option> option to do that." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:57 ../en/appB-mq-ref.xml:99 ../en/appB-mq-ref.xml:157 +#: ../en/appB-mq-ref.xml:197 ../en/appB-mq-ref.xml:264 +#: ../en/appB-mq-ref.xml:335 ../en/appB-mq-ref.xml:404 +#: ../en/appB-mq-ref.xml:497 +msgid "Options:" +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:59 +msgid "" +"<option role=\"hg-ext-mq-cmd-qdel-opt\">-f</option>: Delete the patch file." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:66 +msgid "" +"<command role=\"hg-ext-mq\">qdiff</command>&emdash;print a diff of the " +"topmost applied patch" +msgstr "" +"<command role=\"hg-ext-mq\">qdiff</command>&emdash;显示最新应用补丁的差异" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:69 +msgid "" +"The <command role=\"hg-ext-mq\">qdiff</command> command prints a diff of the " +"topmost applied patch. It is equivalent to <command role=\"hg-cmd\">hg diff -" +"r-2:-1</command>." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:75 +msgid "" +"<command role=\"hg-ext-mq\">qfold</command>&emdash;merge (<quote>fold</" +"quote>) several patches into one" +msgstr "" +"<command role=\"hg-ext-mq\">qfold</command>&emdash;将多个补丁合并(<quote>折叠" +"</quote>)成一个" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:78 +msgid "" +"The <command role=\"hg-ext-mq\">qfold</command> command merges multiple " +"patches into the topmost applied patch, so that the topmost applied patch " +"makes the union of all of the changes in the patches in question." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:83 +msgid "" +"The patches to fold must not be applied; <command role=\"hg-ext-mq\">qfold</" +"command> will exit with an error if any is. The order in which patches are " +"folded is significant; <command role=\"hg-cmd\">hg qfold a b</command> means " +"<quote>apply the current topmost patch, followed by <literal>a</literal>, " +"followed by <literal>b</literal></quote>." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:91 +msgid "" +"The comments from the folded patches are appended to the comments of the " +"destination patch, with each block of comments separated by three asterisk " +"(<quote><literal>*</literal></quote>) characters. Use the <option role=\"hg-" +"ext-mq-cmd-qfold-opt\">-e</option> option to edit the commit message for the " +"combined patch/changeset after the folding has completed." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:101 +msgid "" +"<option role=\"hg-ext-mq-cmd-qfold-opt\">-e</option>: Edit the commit message " +"and patch description for the newly folded patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:106 +msgid "" +"<option role=\"hg-ext-mq-cmd-qfold-opt\">-l</option>: Use the contents of the " +"given file as the new commit message and patch description for the folded " +"patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:111 +msgid "" +"<option role=\"hg-ext-mq-cmd-qfold-opt\">-m</option>: Use the given text as " +"the new commit message and patch description for the folded patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:119 +msgid "" +"<command role=\"hg-ext-mq\">qheader</command>&emdash;display the header/" +"description of a patch" +msgstr "<command role=\"hg-ext-mq\">qheader</command>&emdash;显示补丁头部描述" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:123 +msgid "" +"The <command role=\"hg-ext-mq\">qheader</command> command prints the header, " +"or description, of a patch. By default, it prints the header of the topmost " +"applied patch. Given an argument, it prints the header of the named patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:130 +msgid "" +"<command role=\"hg-ext-mq\">qimport</command>&emdash;import a third-party " +"patch into the queue" +msgstr "" +"<command role=\"hg-ext-mq\">qimport</command>&emdash;将第三方补丁导入队列" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:133 +msgid "" +"The <command role=\"hg-ext-mq\">qimport</command> command adds an entry for " +"an external patch to the <filename role=\"special\">series</filename> file, " +"and copies the patch into the <filename role=\"special\" class=\"directory\">." +"hg/patches</filename> directory. It adds the entry immediately after the " +"topmost applied patch, but does not push the patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:141 +msgid "" +"If the <filename role=\"special\" class=\"directory\">.hg/patches</filename> " +"directory is a repository, <command role=\"hg-ext-mq\">qimport</command> " +"automatically does an <command role=\"hg-cmd\">hg add</command> of the " +"imported patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:149 +msgid "" +"<command role=\"hg-ext-mq\">qinit</command>&emdash;prepare a repository to " +"work with MQ" +msgstr "<command role=\"hg-ext-mq\">qinit</command>&emdash;为使用 MQ 配置版本库" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:152 +msgid "" +"The <command role=\"hg-ext-mq\">qinit</command> command prepares a repository " +"to work with MQ. It creates a directory called <filename role=\"special\" " +"class=\"directory\">.hg/patches</filename>." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:159 +msgid "" +"<option role=\"hg-ext-mq-cmd-qinit-opt\">-c</option>: Create <filename role=" +"\"special\" class=\"directory\">.hg/patches</filename> as a repository in its " +"own right. Also creates a <filename role=\"special\">.hgignore</filename> " +"file that will ignore the <filename role=\"special\">status</filename> file." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:169 +msgid "" +"When the <filename role=\"special\" class=\"directory\">.hg/patches</" +"filename> directory is a repository, the <command role=\"hg-ext-mq\">qimport</" +"command> and <command role=\"hg-ext-mq\">qnew</command> commands " +"automatically <command role=\"hg-cmd\">hg add</command> new patches." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:178 +msgid "<command role=\"hg-ext-mq\">qnew</command>&emdash;create a new patch" +msgstr "<command role=\"hg-ext-mq\">qnew</command>&emdash;创建新补丁" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:181 +msgid "" +"The <command role=\"hg-ext-mq\">qnew</command> command creates a new patch. " +"It takes one mandatory argument, the name to use for the patch file. The " +"newly created patch is created empty by default. It is added to the " +"<filename role=\"special\">series</filename> file after the current topmost " +"applied patch, and is immediately pushed on top of that patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:189 +msgid "" +"If <command role=\"hg-ext-mq\">qnew</command> finds modified files in the " +"working directory, it will refuse to create a new patch unless the <option " +"role=\"hg-ext-mq-cmd-qnew-opt\">-f</option> option is used (see below). This " +"behaviour allows you to <command role=\"hg-ext-mq\">qrefresh</command> your " +"topmost applied patch before you apply a new patch on top of it." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:199 +msgid "" +"<option role=\"hg-ext-mq-cmd-qnew-opt\">-f</option>: Create a new patch if " +"the contents of the working directory are modified. Any outstanding " +"modifications are added to the newly created patch, so after this command " +"completes, the working directory will no longer be modified." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:206 +msgid "" +"<option role=\"hg-ext-mq-cmd-qnew-opt\">-m</option>: Use the given text as " +"the commit message. This text will be stored at the beginning of the patch " +"file, before the patch data." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:215 +msgid "" +"<command role=\"hg-ext-mq\">qnext</command>&emdash;print the name of the next " +"patch" +msgstr "<command role=\"hg-ext-mq\">qnext</command>&emdash;显示下个补丁的名称" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:218 +msgid "" +"The <command role=\"hg-ext-mq\">qnext</command> command prints the name name " +"of the next patch in the <filename role=\"special\">series</filename> file " +"after the topmost applied patch. This patch will become the topmost applied " +"patch if you run <command role=\"hg-ext-mq\">qpush</command>." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:227 +msgid "" +"<command role=\"hg-ext-mq\">qpop</command>&emdash;pop patches off the stack" +msgstr "<command role=\"hg-ext-mq\">qpop</command>&emdash;删除堆栈顶部的补丁" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:230 +msgid "" +"The <command role=\"hg-ext-mq\">qpop</command> command removes applied " +"patches from the top of the stack of applied patches. By default, it removes " +"only one patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:234 +msgid "" +"This command removes the changesets that represent the popped patches from " +"the repository, and updates the working directory to undo the effects of the " +"patches." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:238 +msgid "" +"This command takes an optional argument, which it uses as the name or index " +"of the patch to pop to. If given a name, it will pop patches until the named " +"patch is the topmost applied patch. If given a number, <command role=\"hg-" +"ext-mq\">qpop</command> treats the number as an index into the entries in the " +"series file, counting from zero (empty lines and lines containing only " +"comments do not count). It pops patches until the patch identified by the " +"given index is the topmost applied patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:248 +msgid "" +"The <command role=\"hg-ext-mq\">qpop</command> command does not read or write " +"patches or the <filename role=\"special\">series</filename> file. It is thus " +"safe to <command role=\"hg-ext-mq\">qpop</command> a patch that you have " +"removed from the <filename role=\"special\">series</filename> file, or a " +"patch that you have renamed or deleted entirely. In the latter two cases, " +"use the name of the patch as it was when you applied it." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:257 +msgid "" +"By default, the <command role=\"hg-ext-mq\">qpop</command> command will not " +"pop any patches if the working directory has been modified. You can override " +"this behaviour using the <option role=\"hg-ext-mq-cmd-qpop-opt\">-f</option> " +"option, which reverts all modifications in the working directory." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:266 +msgid "" +"<option role=\"hg-ext-mq-cmd-qpop-opt\">-a</option>: Pop all applied " +"patches. This returns the repository to its state before you applied any " +"patches." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:271 +msgid "" +"<option role=\"hg-ext-mq-cmd-qpop-opt\">-f</option>: Forcibly revert any " +"modifications to the working directory when popping." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:276 +msgid "" +"<option role=\"hg-ext-mq-cmd-qpop-opt\">-n</option>: Pop a patch from the " +"named queue." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:281 +msgid "" +"The <command role=\"hg-ext-mq\">qpop</command> command removes one line from " +"the end of the <filename role=\"special\">status</filename> file for each " +"patch that it pops." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:288 +msgid "" +"<command role=\"hg-ext-mq\">qprev</command>&emdash;print the name of the " +"previous patch" +msgstr "<command role=\"hg-ext-mq\">qprev</command>&emdash;显示上个补丁的名称" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:291 +msgid "" +"The <command role=\"hg-ext-mq\">qprev</command> command prints the name of " +"the patch in the <filename role=\"special\">series</filename> file that comes " +"before the topmost applied patch. This will become the topmost applied patch " +"if you run <command role=\"hg-ext-mq\">qpop</command>." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:300 +msgid "" +"<command role=\"hg-ext-mq\">qpush</command>&emdash;push patches onto the stack" +msgstr "<command role=\"hg-ext-mq\">qpush</command>&emdash;增加补丁到堆栈" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:303 +msgid "" +"The <command role=\"hg-ext-mq\">qpush</command> command adds patches onto the " +"applied stack. By default, it adds only one patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:307 +msgid "" +"This command creates a new changeset to represent each applied patch, and " +"updates the working directory to apply the effects of the patches." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:311 +msgid "The default data used when creating a changeset are as follows:" +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:314 +msgid "" +"The commit date and time zone are the current date and time zone. Because " +"these data are used to compute the identity of a changeset, this means that " +"if you <command role=\"hg-ext-mq\">qpop</command> a patch and <command role=" +"\"hg-ext-mq\">qpush</command> it again, the changeset that you push will have " +"a different identity than the changeset you popped." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:322 +msgid "" +"The author is the same as the default used by the <command role=\"hg-cmd\">hg " +"commit</command> command." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:326 +msgid "" +"The commit message is any text from the patch file that comes before the " +"first diff header. If there is no such text, a default commit message is " +"used that identifies the name of the patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:331 +msgid "" +"If a patch contains a Mercurial patch header (XXX add link), the information " +"in the patch header overrides these defaults." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:337 +msgid "" +"<option role=\"hg-ext-mq-cmd-qpush-opt\">-a</option>: Push all unapplied " +"patches from the <filename role=\"special\">series</filename> file until " +"there are none left to push." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:343 +msgid "" +"<option role=\"hg-ext-mq-cmd-qpush-opt\">-l</option>: Add the name of the " +"patch to the end of the commit message." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:347 +msgid "" +"<option role=\"hg-ext-mq-cmd-qpush-opt\">-m</option>: If a patch fails to " +"apply cleanly, use the entry for the patch in another saved queue to compute " +"the parameters for a three-way merge, and perform a three-way merge using the " +"normal Mercurial merge machinery. Use the resolution of the merge as the new " +"patch content." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:355 +msgid "" +"<option role=\"hg-ext-mq-cmd-qpush-opt\">-n</option>: Use the named queue if " +"merging while pushing." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:360 +msgid "" +"The <command role=\"hg-ext-mq\">qpush</command> command reads, but does not " +"modify, the <filename role=\"special\">series</filename> file. It appends " +"one line to the <command role=\"hg-cmd\">hg status</command> file for each " +"patch that it pushes." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:368 +msgid "" +"<command role=\"hg-ext-mq\">qrefresh</command>&emdash;update the topmost " +"applied patch" +msgstr "<command role=\"hg-ext-mq\">qrefresh</command>&emdash;更新最新的补丁" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:372 +msgid "" +"The <command role=\"hg-ext-mq\">qrefresh</command> command updates the " +"topmost applied patch. It modifies the patch, removes the old changeset that " +"represented the patch, and creates a new changeset to represent the modified " +"patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:378 +msgid "" +"The <command role=\"hg-ext-mq\">qrefresh</command> command looks for the " +"following modifications:" +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:381 +msgid "" +"Changes to the commit message, i.e. the text before the first diff header in " +"the patch file, are reflected in the new changeset that represents the patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:386 +msgid "" +"Modifications to tracked files in the working directory are added to the " +"patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:389 +msgid "" +"Changes to the files tracked using <command role=\"hg-cmd\">hg add</command>, " +"<command role=\"hg-cmd\">hg copy</command>, <command role=\"hg-cmd\">hg " +"remove</command>, or <command role=\"hg-cmd\">hg rename</command>. Added " +"files and copy and rename destinations are added to the patch, while removed " +"files and rename sources are removed." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:398 +msgid "" +"Even if <command role=\"hg-ext-mq\">qrefresh</command> detects no changes, it " +"still recreates the changeset that represents the patch. This causes the " +"identity of the changeset to differ from the previous changeset that " +"identified the patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:406 +msgid "" +"<option role=\"hg-ext-mq-cmd-qrefresh-opt\">-e</option>: Modify the commit " +"and patch description, using the preferred text editor." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:411 +msgid "" +"<option role=\"hg-ext-mq-cmd-qrefresh-opt\">-m</option>: Modify the commit " +"message and patch description, using the given text." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:416 +msgid "" +"<option role=\"hg-ext-mq-cmd-qrefresh-opt\">-l</option>: Modify the commit " +"message and patch description, using text from the given file." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:424 +msgid "<command role=\"hg-ext-mq\">qrename</command>&emdash;rename a patch" +msgstr "<command role=\"hg-ext-mq\">qrename</command>&emdash;改名补丁" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:427 +msgid "" +"The <command role=\"hg-ext-mq\">qrename</command> command renames a patch, " +"and changes the entry for the patch in the <filename role=\"special\">series</" +"filename> file." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:431 +msgid "" +"With a single argument, <command role=\"hg-ext-mq\">qrename</command> renames " +"the topmost applied patch. With two arguments, it renames its first argument " +"to its second." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:438 +msgid "" +"<command role=\"hg-ext-mq\">qrestore</command>&emdash;restore saved queue " +"state" +msgstr "<command role=\"hg-ext-mq\">qrestore</command>&emdash;恢复保存的队列" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:442 +msgid "XXX No idea what this does." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:446 +msgid "" +"<command role=\"hg-ext-mq\">qsave</command>&emdash;save current queue state" +msgstr "<command role=\"hg-ext-mq\">qsave</command>&emdash;保存当前的队列状态" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:449 +msgid "XXX Likewise." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:453 +msgid "" +"<command role=\"hg-ext-mq\">qseries</command>&emdash;print the entire patch " +"series" +msgstr "<command role=\"hg-ext-mq\">qseries</command>&emdash;显示补丁序列" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:456 +msgid "" +"The <command role=\"hg-ext-mq\">qseries</command> command prints the entire " +"patch series from the <filename role=\"special\">series</filename> file. It " +"prints only patch names, not empty lines or comments. It prints in order " +"from first to be applied to last." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:464 +msgid "" +"<command role=\"hg-ext-mq\">qtop</command>&emdash;print the name of the " +"current patch" +msgstr "<command role=\"hg-ext-mq\">qtop</command>&emdash;显示当前补丁的名称" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:467 +msgid "" +"The <command role=\"hg-ext-mq\">qtop</command> prints the name of the topmost " +"currently applied patch." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:472 +msgid "" +"<command role=\"hg-ext-mq\">qunapplied</command>&emdash;print patches not yet " +"applied" +msgstr "" +"<command role=\"hg-ext-mq\">qunapplied</command>&emdash;显示尚未应用的补丁" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:476 +msgid "" +"The <command role=\"hg-ext-mq\">qunapplied</command> command prints the names " +"of patches from the <filename role=\"special\">series</filename> file that " +"are not yet applied. It prints them in order from the next patch that will " +"be pushed to the last." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:484 +msgid "" +"<command role=\"hg-cmd\">hg strip</command>&emdash;remove a revision and " +"descendants" +msgstr "<command role=\"hg-cmd\">hg strip</command>&emdash;删除一个版本及其后继" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:487 +msgid "" +"The <command role=\"hg-cmd\">hg strip</command> command removes a revision, " +"and all of its descendants, from the repository. It undoes the effects of " +"the removed revisions from the repository, and updates the working directory " +"to the first parent of the removed revision." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:493 +msgid "" +"The <command role=\"hg-cmd\">hg strip</command> command saves a backup of the " +"removed changesets in a bundle, so that they can be reapplied if removed in " +"error." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:499 +msgid "" +"<option role=\"hg-opt-strip\">-b</option>: Save unrelated changesets that are " +"intermixed with the stripped changesets in the backup bundle." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:503 +msgid "" +"<option role=\"hg-opt-strip\">-f</option>: If a branch has multiple heads, " +"remove all heads. XXX This should be renamed, and use <literal>-f</literal> " +"to strip revs when there are pending changes." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> +#: ../en/appB-mq-ref.xml:508 +msgid "<option role=\"hg-opt-strip\">-n</option>: Do not save a backup bundle." +msgstr "" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appB-mq-ref.xml:515 +msgid "MQ file reference" +msgstr "MQ 文件参考" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:518 +msgid "The <filename role=\"special\">series</filename> file" +msgstr "<filename role=\"special\">序列</filename>文件" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:521 +msgid "" +"The <filename role=\"special\">series</filename> file contains a list of the " +"names of all patches that MQ can apply. It is represented as a list of " +"names, with one name saved per line. Leading and trailing white space in " +"each line are ignored." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:527 +msgid "" +"Lines may contain comments. A comment begins with the <quote><literal>#</" +"literal></quote> character, and extends to the end of the line. Empty lines, " +"and lines that contain only comments, are ignored." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:532 +msgid "" +"You will often need to edit the <filename role=\"special\">series</filename> " +"file by hand, hence the support for comments and empty lines noted above. " +"For example, you can comment out a patch temporarily, and <command role=\"hg-" +"ext-mq\">qpush</command> will skip over that patch when applying patches. " +"You can also change the order in which patches are applied by reordering " +"their entries in the <filename role=\"special\">series</filename> file." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:541 +msgid "" +"Placing the <filename role=\"special\">series</filename> file under revision " +"control is also supported; it is a good idea to place all of the patches that " +"it refers to under revision control, as well. If you create a patch " +"directory using the <option role=\"hg-ext-mq-cmd-qinit-opt\">-c</option> " +"option to <command role=\"hg-ext-mq\">qinit</command>, this will be done for " +"you automatically." +msgstr "" + +#. type: Content of: <book><appendix><sect1><sect2><title> +#: ../en/appB-mq-ref.xml:551 +msgid "The <filename role=\"special\">status</filename> file" +msgstr "<filename role=\"special\">状态</filename>文件" + +#. type: Content of: <book><appendix><sect1><sect2><para> +#: ../en/appB-mq-ref.xml:554 +msgid "" +"The <filename role=\"special\">status</filename> file contains the names and " +"changeset hashes of all patches that MQ currently has applied. Unlike the " +"<filename role=\"special\">series</filename> file, this file is not intended " +"for editing. You should not place this file under revision control, or " +"modify it in any way. It is used by MQ strictly for internal book-keeping." +msgstr "" + +#. type: Content of: <book><appendix><title> +#: ../en/appC-srcinstall.xml:5 +msgid "Installing Mercurial from source" +msgstr "从源代码安装 Mercurial" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appC-srcinstall.xml:8 +msgid "On a Unix-like system" +msgstr "类 Unix 系统" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appC-srcinstall.xml:10 +msgid "" +"If you are using a Unix-like system that has a sufficiently recent version of " +"Python (2.3 or newer) available, it is easy to install Mercurial from source." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appC-srcinstall.xml:14 +msgid "" +"Download a recent source tarball from <ulink url=\"http://www.selenic.com/" +"mercurial/download\">http://www.selenic.com/mercurial/download</ulink>." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appC-srcinstall.xml:17 +msgid "Unpack the tarball:" +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appC-srcinstall.xml:20 +msgid "" +"Go into the source directory and run the installer script. This will build " +"Mercurial and install it in your home directory." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appC-srcinstall.xml:27 +msgid "" +"Once the install finishes, Mercurial will be in the <literal>bin</literal> " +"subdirectory of your home directory. Don't forget to make sure that this " +"directory is present in your shell's search path." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appC-srcinstall.xml:32 +msgid "" +"You will probably need to set the <envar>PYTHONPATH</envar> environment " +"variable so that the Mercurial executable can find the rest of the Mercurial " +"packages. For example, on my laptop, I have set it to <literal>/home/bos/lib/" +"python</literal>. The exact path that you will need to use depends on how " +"Python was built for your system, but should be easy to figure out. If " +"you're uncertain, look through the output of the installer script above, and " +"see where the contents of the <literal>mercurial</literal> directory were " +"installed to." +msgstr "" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appC-srcinstall.xml:44 +msgid "On Windows" +msgstr "Windows 系统" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appC-srcinstall.xml:46 +msgid "" +"Building and installing Mercurial on Windows requires a variety of tools, a " +"fair amount of technical knowledge, and considerable patience. I very much " +"<emphasis>do not recommend</emphasis> this route if you are a <quote>casual " +"user</quote>. Unless you intend to hack on Mercurial, I strongly suggest " +"that you use a binary package instead." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appC-srcinstall.xml:53 +msgid "" +"If you are intent on building Mercurial from source on Windows, follow the " +"<quote>hard way</quote> directions on the Mercurial wiki at <ulink url=" +"\"http://www.selenic.com/mercurial/wiki/index.cgi/WindowsInstall\">http://www." +"selenic.com/mercurial/wiki/index.cgi/WindowsInstall</ulink>, and expect the " +"process to involve a lot of fiddly work." +msgstr "" + +#. type: Content of: <book><appendix><title> +#: ../en/appD-license.xml:5 +msgid "Open Publication License" +msgstr "" + +#. type: Content of: <book><appendix><para> +#: ../en/appD-license.xml:7 +msgid "Version 1.0, 8 June 1999" +msgstr "" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appD-license.xml:10 +msgid "Requirements on both unmodified and modified versions" +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:13 +msgid "" +"The Open Publication works may be reproduced and distributed in whole or in " +"part, in any medium physical or electronic, provided that the terms of this " +"license are adhered to, and that this license or an incorporation of it by " +"reference (with any options elected by the author(s) and/or publisher) is " +"displayed in the reproduction." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:20 +msgid "Proper form for an incorporation by reference is as follows:" +msgstr "" + +#. type: Content of: <book><appendix><sect1><blockquote><para> +#: ../en/appD-license.xml:24 +msgid "" +"Copyright (c) <emphasis>year</emphasis> by <emphasis>author's name or " +"designee</emphasis>. This material may be distributed only subject to the " +"terms and conditions set forth in the Open Publication License, v<emphasis>x." +"y</emphasis> or later (the latest version is presently available at <ulink " +"url=\"http://www.opencontent.org/openpub/\">http://www.opencontent.org/" +"openpub/</ulink>)." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:33 +msgid "" +"The reference must be immediately followed with any options elected by the " +"author(s) and/or publisher of the document (see section <xref linkend=\"sec." +"opl.options\"/>)." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:37 +msgid "" +"Commercial redistribution of Open Publication-licensed material is permitted." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:40 +msgid "" +"Any publication in standard (paper) book form shall require the citation of " +"the original publisher and author. The publisher and author's names shall " +"appear on all outer surfaces of the book. On all outer surfaces of the book " +"the original publisher's name shall be as large as the title of the work and " +"cited as possessive with respect to the title." +msgstr "" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appD-license.xml:49 +msgid "Copyright" +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:51 +msgid "" +"The copyright to each Open Publication is owned by its author(s) or designee." +msgstr "" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appD-license.xml:56 +msgid "Scope of license" +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:58 +msgid "" +"The following license terms apply to all Open Publication works, unless " +"otherwise explicitly stated in the document." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:62 +msgid "" +"Mere aggregation of Open Publication works or a portion of an Open " +"Publication work with other works or programs on the same media shall not " +"cause this license to apply to those other works. The aggregate work shall " +"contain a notice specifying the inclusion of the Open Publication material " +"and appropriate copyright notice." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:69 +msgid "" +"<emphasis role=\"bold\">Severability</emphasis>. If any part of this license " +"is found to be unenforceable in any jurisdiction, the remaining portions of " +"the license remain in force." +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:74 +msgid "" +"<emphasis role=\"bold\">No warranty</emphasis>. Open Publication works are " +"licensed and provided <quote>as is</quote> without warranty of any kind, " +"express or implied, including, but not limited to, the implied warranties of " +"merchantability and fitness for a particular purpose or a warranty of non-" +"infringement." +msgstr "" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appD-license.xml:83 +msgid "Requirements on modified works" +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:85 +msgid "" +"All modified versions of documents covered by this license, including " +"translations, anthologies, compilations and partial documents, must meet the " +"following requirements:" +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:90 +msgid "The modified version must be labeled as such." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:93 +msgid "" +"The person making the modifications must be identified and the modifications " +"dated." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:96 +msgid "" +"Acknowledgement of the original author and publisher if applicable must be " +"retained according to normal academic citation practices." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:100 +msgid "The location of the original unmodified document must be identified." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:103 +msgid "" +"The original author's (or authors') name(s) may not be used to assert or " +"imply endorsement of the resulting document without the original author's (or " +"authors') permission." +msgstr "" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appD-license.xml:111 +msgid "Good-practice recommendations" +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:113 +msgid "" +"In addition to the requirements of this license, it is requested from and " +"strongly recommended of redistributors that:" +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:118 +msgid "" +"If you are distributing Open Publication works on hardcopy or CD-ROM, you " +"provide email notification to the authors of your intent to redistribute at " +"least thirty days before your manuscript or media freeze, to give the authors " +"time to provide updated documents. This notification should describe " +"modifications, if any, made to the document." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:125 +msgid "" +"All substantive modifications (including deletions) be either clearly marked " +"up in the document or else described in an attachment to the document." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:129 +msgid "" +"Finally, while it is not mandatory under this license, it is considered good " +"form to offer a free copy of any hardcopy and CD-ROM expression of an Open " +"Publication-licensed work to its author(s)." +msgstr "" + +#. type: Content of: <book><appendix><sect1><title> +#: ../en/appD-license.xml:137 +msgid "License options" +msgstr "" + +#. type: Content of: <book><appendix><sect1><para> +#: ../en/appD-license.xml:139 +msgid "" +"The author(s) and/or publisher of an Open Publication-licensed document may " +"elect certain options by appending language to the reference to or copy of " +"the license. These options are considered part of the license instance and " +"must be included with the license (or its incorporation by reference) in " +"derived works." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:147 +msgid "" +"To prohibit distribution of substantively modified versions without the " +"explicit permission of the author(s). <quote>Substantive modification</quote> " +"is defined as a change to the semantic content of the document, and excludes " +"mere changes in format or typographical corrections." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:154 +msgid "" +"To accomplish this, add the phrase <quote>Distribution of substantively " +"modified versions of this document is prohibited without the explicit " +"permission of the copyright holder.</quote> to the license reference or copy." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:160 +msgid "" +"To prohibit any publication of this work or derivative works in whole or in " +"part in standard (paper) book form for commercial purposes is prohibited " +"unless prior permission is obtained from the copyright holder." +msgstr "" + +#. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> +#: ../en/appD-license.xml:165 +msgid "" +"To accomplish this, add the phrase <quote>Distribution of the work or " +"derivative of the work in any standard (paper) book form is prohibited unless " +"prior permission is obtained from the copyright holder.</quote> to the " +"license reference or copy." +msgstr "" + +#. type: Content of: <book><preface><title> +#: ../en/ch00-preface.xml:5 +msgid "Preface" +msgstr "序言" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:8 +msgid "Why revision control? Why Mercurial?" +msgstr "为什么使用版本控制? 为什么使用 Mercurial?" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:10 +msgid "" +"Revision control is the process of managing multiple versions of a piece of " +"information. In its simplest form, this is something that many people do by " +"hand: every time you modify a file, save it under a new name that contains a " +"number, each one higher than the number of the preceding version." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:16 +msgid "" +"Manually managing multiple versions of even a single file is an error-prone " +"task, though, so software tools to help automate this process have long been " +"available. The earliest automated revision control tools were intended to " +"help a single user to manage revisions of a single file. Over the past few " +"decades, the scope of revision control tools has expanded greatly; they now " +"manage multiple files, and help multiple people to work together. The best " +"modern revision control tools have no problem coping with thousands of people " +"working together on projects that consist of hundreds of thousands of files." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:27 +msgid "" +"The arrival of distributed revision control is relatively recent, and so far " +"this new field has grown due to people's willingness to explore ill-charted " +"territory." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:31 +msgid "" +"I am writing a book about distributed revision control because I believe that " +"it is an important subject that deserves a field guide. I chose to write " +"about Mercurial because it is the easiest tool to learn the terrain with, and " +"yet it scales to the demands of real, challenging environments where many " +"other revision control tools buckle." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><title> +#: ../en/ch00-preface.xml:39 +msgid "Why use revision control?" +msgstr "为什么使用版本控制?" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:41 +msgid "" +"There are a number of reasons why you or your team might want to use an " +"automated revision control tool for a project." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:46 +msgid "" +"It will track the history and evolution of your project, so you don't have " +"to. For every change, you'll have a log of <emphasis>who</emphasis> made it; " +"<emphasis>why</emphasis> they made it; <emphasis>when</emphasis> they made " +"it; and <emphasis>what</emphasis> the change was." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:53 +msgid "" +"When you're working with other people, revision control software makes it " +"easier for you to collaborate. For example, when people more or less " +"simultaneously make potentially incompatible changes, the software will help " +"you to identify and resolve those conflicts." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:59 +msgid "" +"It can help you to recover from mistakes. If you make a change that later " +"turns out to be in error, you can revert to an earlier version of one or more " +"files. In fact, a <emphasis>really</emphasis> good revision control tool " +"will even help you to efficiently figure out exactly when a problem was " +"introduced (see section <xref linkend=\"sec.undo.bisect\"/> for details)." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:66 +msgid "" +"It will help you to work simultaneously on, and manage the drift between, " +"multiple versions of your project." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:71 +msgid "" +"Most of these reasons are equally valid---at least in theory---whether you're " +"working on a project by yourself, or with a hundred other people." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:75 +msgid "" +"A key question about the practicality of revision control at these two " +"different scales (<quote>lone hacker</quote> and <quote>huge team</quote>) is " +"how its <emphasis>benefits</emphasis> compare to its <emphasis>costs</" +"emphasis>. A revision control tool that's difficult to understand or use is " +"going to impose a high cost." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:83 +msgid "" +"A five-hundred-person project is likely to collapse under its own weight " +"almost immediately without a revision control tool and process. In this case, " +"the cost of using revision control might hardly seem worth considering, since " +"<emphasis>without</emphasis> it, failure is almost guaranteed." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:90 +msgid "" +"On the other hand, a one-person <quote>quick hack</quote> might seem like a " +"poor place to use a revision control tool, because surely the cost of using " +"one must be close to the overall cost of the project. Right?" +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:95 +msgid "" +"Mercurial uniquely supports <emphasis>both</emphasis> of these scales of " +"development. You can learn the basics in just a few minutes, and due to its " +"low overhead, you can apply revision control to the smallest of projects with " +"ease. Its simplicity means you won't have a lot of abstruse concepts or " +"command sequences competing for mental space with whatever you're " +"<emphasis>really</emphasis> trying to do. At the same time, Mercurial's high " +"performance and peer-to-peer nature let you scale painlessly to handle large " +"projects." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:105 +msgid "" +"No revision control tool can rescue a poorly run project, but a good choice " +"of tools can make a huge difference to the fluidity with which you can work " +"on a project." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><title> +#: ../en/ch00-preface.xml:112 +msgid "The many names of revision control" +msgstr "版本控制的别名" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:114 +msgid "" +"Revision control is a diverse field, so much so that it is referred to by " +"many names and acronyms. Here are a few of the more common variations you'll " +"encounter:" +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:118 +msgid "Revision control (RCS)" +msgstr "版本控制(RCS)" + +#. type: Content of: <book><preface><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:119 +msgid "Software configuration management (SCM), or configuration management" +msgstr "软件配置管理(SCM),或配置管理" + +#. type: Content of: <book><preface><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:121 +msgid "Source code management" +msgstr "源代码管理" + +#. type: Content of: <book><preface><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:122 +msgid "Source code control, or source control" +msgstr "源代码控制,或源控制" + +#. type: Content of: <book><preface><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:124 +msgid "Version control (VCS)" +msgstr "版本控制(VCS)" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:126 +msgid "" +"Some people claim that these terms actually have different meanings, but in " +"practice they overlap so much that there's no agreed or even useful way to " +"tease them apart." +msgstr "" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:134 +msgid "This book is a work in progress" +msgstr "本书正在编写中" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:136 +msgid "" +"I am releasing this book while I am still writing it, in the hope that it " +"will prove useful to others. I am writing under an open license in the hope " +"that you, my readers, will contribute feedback and perhaps content of your " +"own." +msgstr "" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:143 +msgid "About the examples in this book" +msgstr "本书的例子" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:145 +msgid "" +"This book takes an unusual approach to code samples. Every example is " +"<quote>live</quote>---each one is actually the result of a shell script that " +"executes the Mercurial commands you see. Every time an image of the book is " +"built from its sources, all the example scripts are automatically run, and " +"their current results compared against their expected results." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:152 +msgid "" +"The advantage of this approach is that the examples are always accurate; they " +"describe <emphasis>exactly</emphasis> the behaviour of the version of " +"Mercurial that's mentioned at the front of the book. If I update the version " +"of Mercurial that I'm documenting, and the output of some command changes, " +"the build fails." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:159 +msgid "" +"There is a small disadvantage to this approach, which is that the dates and " +"times you'll see in examples tend to be <quote>squashed</quote> together in a " +"way that they wouldn't be if the same commands were being typed by a human. " +"Where a human can issue no more than one command every few seconds, with any " +"resulting timestamps correspondingly spread out, my automated example scripts " +"run many commands in one second." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:167 +msgid "" +"As an instance of this, several consecutive commits in an example can show up " +"as having occurred during the same second. You can see this occur in the " +"<literal role=\"hg-ext\">bisect</literal> example in section <xref linkend=" +"\"sec.undo.bisect\"/>, for instance." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:173 +msgid "" +"So when you're reading examples, don't place too much weight on the dates or " +"times you see in the output of commands. But <emphasis>do</emphasis> be " +"confident that the behaviour you're seeing is consistent and reproducible." +msgstr "" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:181 +msgid "Trends in the field" +msgstr "版本控制的发展趋势" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:183 +msgid "" +"There has been an unmistakable trend in the development and use of revision " +"control tools over the past four decades, as people have become familiar with " +"the capabilities of their tools and constrained by their limitations." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:188 +msgid "" +"The first generation began by managing single files on individual computers. " +"Although these tools represented a huge advance over ad-hoc manual revision " +"control, their locking model and reliance on a single computer limited them " +"to small, tightly-knit teams." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:194 +msgid "" +"The second generation loosened these constraints by moving to network-" +"centered architectures, and managing entire projects at a time. As projects " +"grew larger, they ran into new problems. With clients needing to talk to " +"servers very frequently, server scaling became an issue for large projects. " +"An unreliable network connection could prevent remote users from being able " +"to talk to the server at all. As open source projects started making read-" +"only access available anonymously to anyone, people without commit privileges " +"found that they could not use the tools to interact with a project in a " +"natural way, as they could not record their changes." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:206 +msgid "" +"The current generation of revision control tools is peer-to-peer in nature. " +"All of these systems have dropped the dependency on a single central server, " +"and allow people to distribute their revision control data to where it's " +"actually needed. Collaboration over the Internet has moved from constrained " +"by technology to a matter of choice and consensus. Modern tools can operate " +"offline indefinitely and autonomously, with a network connection only needed " +"when syncing changes with another repository." +msgstr "" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:218 +msgid "A few of the advantages of distributed revision control" +msgstr "分布版本控制的优点" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:221 +msgid "" +"Even though distributed revision control tools have for several years been as " +"robust and usable as their previous-generation counterparts, people using " +"older tools have not yet necessarily woken up to their advantages. There are " +"a number of ways in which distributed tools shine relative to centralised " +"ones." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:228 +msgid "" +"For an individual developer, distributed tools are almost always much faster " +"than centralised tools. This is for a simple reason: a centralised tool " +"needs to talk over the network for many common operations, because most " +"metadata is stored in a single copy on the central server. A distributed " +"tool stores all of its metadata locally. All else being equal, talking over " +"the network adds overhead to a centralised tool. Don't underestimate the " +"value of a snappy, responsive tool: you're going to spend a lot of time " +"interacting with your revision control software." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:239 +msgid "" +"Distributed tools are indifferent to the vagaries of your server " +"infrastructure, again because they replicate metadata to so many locations. " +"If you use a centralised system and your server catches fire, you'd better " +"hope that your backup media are reliable, and that your last backup was " +"recent and actually worked. With a distributed tool, you have many backups " +"available on every contributor's computer." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:247 +msgid "" +"The reliability of your network will affect distributed tools far less than " +"it will centralised tools. You can't even use a centralised tool without a " +"network connection, except for a few highly constrained commands. With a " +"distributed tool, if your network connection goes down while you're working, " +"you may not even notice. The only thing you won't be able to do is talk to " +"repositories on other computers, something that is relatively rare compared " +"with local operations. If you have a far-flung team of collaborators, this " +"may be significant." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><title> +#: ../en/ch00-preface.xml:258 +msgid "Advantages for open source projects" +msgstr "开源项目的优点" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:260 +msgid "" +"If you take a shine to an open source project and decide that you would like " +"to start hacking on it, and that project uses a distributed revision control " +"tool, you are at once a peer with the people who consider themselves the " +"<quote>core</quote> of that project. If they publish their repositories, you " +"can immediately copy their project history, start making changes, and record " +"your work, using the same tools in the same ways as insiders. By contrast, " +"with a centralised tool, you must use the software in a <quote>read only</" +"quote> mode unless someone grants you permission to commit changes to their " +"central server. Until then, you won't be able to record changes, and your " +"local modifications will be at risk of corruption any time you try to update " +"your client's view of the repository." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><sect3><title> +#: ../en/ch00-preface.xml:276 +msgid "The forking non-problem" +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><sect3><para> +#: ../en/ch00-preface.xml:278 +msgid "" +"It has been suggested that distributed revision control tools pose some sort " +"of risk to open source projects because they make it easy to <quote>fork</" +"quote> the development of a project. A fork happens when there are " +"differences in opinion or attitude between groups of developers that cause " +"them to decide that they can't work together any longer. Each side takes a " +"more or less complete copy of the project's source code, and goes off in its " +"own direction." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><sect3><para> +#: ../en/ch00-preface.xml:288 +msgid "" +"Sometimes the camps in a fork decide to reconcile their differences. With a " +"centralised revision control system, the <emphasis>technical</emphasis> " +"process of reconciliation is painful, and has to be performed largely by " +"hand. You have to decide whose revision history is going to <quote>win</" +"quote>, and graft the other team's changes into the tree somehow. This " +"usually loses some or all of one side's revision history." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><sect3><para> +#: ../en/ch00-preface.xml:297 +msgid "" +"What distributed tools do with respect to forking is they make forking the " +"<emphasis>only</emphasis> way to develop a project. Every single change that " +"you make is potentially a fork point. The great strength of this approach is " +"that a distributed revision control tool has to be really good at " +"<emphasis>merging</emphasis> forks, because forks are absolutely fundamental: " +"they happen all the time." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><sect3><para> +#: ../en/ch00-preface.xml:306 +msgid "" +"If every piece of work that everybody does, all the time, is framed in terms " +"of forking and merging, then what the open source world refers to as a " +"<quote>fork</quote> becomes <emphasis>purely</emphasis> a social issue. If " +"anything, distributed tools <emphasis>lower</emphasis> the likelihood of a " +"fork:" +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:313 +msgid "" +"They eliminate the social distinction that centralised tools impose: that " +"between insiders (people with commit access) and outsiders (people without)." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:317 +msgid "" +"They make it easier to reconcile after a social fork, because all that's " +"involved from the perspective of the revision control software is just " +"another merge." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><sect3><para> +#: ../en/ch00-preface.xml:322 +msgid "" +"Some people resist distributed tools because they want to retain tight " +"control over their projects, and they believe that centralised tools give " +"them this control. However, if you're of this belief, and you publish your " +"CVS or Subversion repositories publicly, there are plenty of tools available " +"that can pull out your entire project's history (albeit slowly) and recreate " +"it somewhere that you don't control. So while your control in this case is " +"illusory, you are forgoing the ability to fluidly collaborate with whatever " +"people feel compelled to mirror and fork your history." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><title> +#: ../en/ch00-preface.xml:337 +msgid "Advantages for commercial projects" +msgstr "商业项目的优点" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:339 +msgid "" +"Many commercial projects are undertaken by teams that are scattered across " +"the globe. Contributors who are far from a central server will see slower " +"command execution and perhaps less reliability. Commercial revision control " +"systems attempt to ameliorate these problems with remote-site replication add-" +"ons that are typically expensive to buy and cantankerous to administer. A " +"distributed system doesn't suffer from these problems in the first place. " +"Better yet, you can easily set up multiple authoritative servers, say one per " +"site, so that there's no redundant communication between repositories over " +"expensive long-haul network links." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:351 +msgid "" +"Centralised revision control systems tend to have relatively low " +"scalability. It's not unusual for an expensive centralised system to fall " +"over under the combined load of just a few dozen concurrent users. Once " +"again, the typical response tends to be an expensive and clunky replication " +"facility. Since the load on a central server---if you have one at all---is " +"many times lower with a distributed tool (because all of the data is " +"replicated everywhere), a single cheap server can handle the needs of a much " +"larger team, and replication to balance load becomes a simple matter of " +"scripting." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:363 +msgid "" +"If you have an employee in the field, troubleshooting a problem at a " +"customer's site, they'll benefit from distributed revision control. The tool " +"will let them generate custom builds, try different fixes in isolation from " +"each other, and search efficiently through history for the sources of bugs " +"and regressions in the customer's environment, all without needing to connect " +"to your company's network." +msgstr "" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:374 +msgid "Why choose Mercurial?" +msgstr "为什么选择 Mercurial?" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:376 +msgid "" +"Mercurial has a unique set of properties that make it a particularly good " +"choice as a revision control system." +msgstr "" + +#. type: Content of: <book><preface><sect1><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:379 +msgid "It is easy to learn and use." +msgstr "" + +#. type: Content of: <book><preface><sect1><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:380 +msgid "It is lightweight." +msgstr "" + +#. type: Content of: <book><preface><sect1><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:381 +msgid "It scales excellently." +msgstr "" + +#. type: Content of: <book><preface><sect1><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:382 +msgid "It is easy to customise." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:385 +msgid "" +"If you are at all familiar with revision control systems, you should be able " +"to get up and running with Mercurial in less than five minutes. Even if not, " +"it will take no more than a few minutes longer. Mercurial's command and " +"feature sets are generally uniform and consistent, so you can keep track of a " +"few general rules instead of a host of exceptions." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:392 +msgid "" +"On a small project, you can start working with Mercurial in moments. Creating " +"new changes and branches; transferring changes around (whether locally or " +"over a network); and history and status operations are all fast. Mercurial " +"attempts to stay nimble and largely out of your way by combining low " +"cognitive overhead with blazingly fast operations." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:399 +msgid "" +"The usefulness of Mercurial is not limited to small projects: it is used by " +"projects with hundreds to thousands of contributors, each containing tens of " +"thousands of files and hundreds of megabytes of source code." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:404 +msgid "" +"If the core functionality of Mercurial is not enough for you, it's easy to " +"build on. Mercurial is well suited to scripting tasks, and its clean " +"internals and implementation in Python make it easy to add features in the " +"form of extensions. There are a number of popular and useful extensions " +"already available, ranging from helping to identify bugs to improving " +"performance." +msgstr "" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:414 +msgid "Mercurial compared with other tools" +msgstr "Mercurial 与其它工具的比较" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:416 +msgid "" +"Before you read on, please understand that this section necessarily reflects " +"my own experiences, interests, and (dare I say it) biases. I have used every " +"one of the revision control tools listed below, in most cases for several " +"years at a time." +msgstr "" + +#. type: Content of: <book><preface><sect1><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:424 ../en/ch00-preface.xml:635 +msgid "Subversion" +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:426 +msgid "" +"Subversion is a popular revision control tool, developed to replace CVS. It " +"has a centralised client/server architecture." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:430 +msgid "" +"Subversion and Mercurial have similarly named commands for performing the " +"same operations, so if you're familiar with one, it is easy to learn to use " +"the other. Both tools are portable to all popular operating systems." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:435 +msgid "" +"Prior to version 1.5, Subversion had no useful support for merges. At the " +"time of writing, its merge tracking capability is new, and known to be <ulink " +"url=\"http://svnbook.red-bean.com/nightly/en/svn.branchmerge.advanced." +"html#svn.branchmerge.advanced.finalword\">complicated and buggy</ulink>." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:441 +msgid "" +"Mercurial has a substantial performance advantage over Subversion on every " +"revision control operation I have benchmarked. I have measured its advantage " +"as ranging from a factor of two to a factor of six when compared with " +"Subversion 1.4.3's <emphasis>ra_local</emphasis> file store, which is the " +"fastest access method available. In more realistic deployments involving a " +"network-based store, Subversion will be at a substantially larger " +"disadvantage. Because many Subversion commands must talk to the server and " +"Subversion does not have useful replication facilities, server capacity and " +"network bandwidth become bottlenecks for modestly large projects." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:454 +msgid "" +"Additionally, Subversion incurs substantial storage overhead to avoid network " +"transactions for a few common operations, such as finding modified files " +"(<literal>status</literal>) and displaying modifications against the current " +"revision (<literal>diff</literal>). As a result, a Subversion working copy " +"is often the same size as, or larger than, a Mercurial repository and working " +"directory, even though the Mercurial repository contains a complete history " +"of the project." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:464 +msgid "" +"Subversion is widely supported by third party tools. Mercurial currently " +"lags considerably in this area. This gap is closing, however, and indeed " +"some of Mercurial's GUI tools now outshine their Subversion equivalents. " +"Like Mercurial, Subversion has an excellent user manual." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:470 +msgid "" +"Because Subversion doesn't store revision history on the client, it is well " +"suited to managing projects that deal with lots of large, opaque binary " +"files. If you check in fifty revisions to an incompressible 10MB file, " +"Subversion's client-side space usage stays constant The space used by any " +"distributed SCM will grow rapidly in proportion to the number of revisions, " +"because the differences between each revision are large." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:479 +msgid "" +"In addition, it's often difficult or, more usually, impossible to merge " +"different versions of a binary file. Subversion's ability to let a user lock " +"a file, so that they temporarily have the exclusive right to commit changes " +"to it, can be a significant advantage to a project where binary files are " +"widely used." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:486 +msgid "" +"Mercurial can import revision history from a Subversion repository. It can " +"also export revision history to a Subversion repository. This makes it easy " +"to <quote>test the waters</quote> and use Mercurial and Subversion in " +"parallel before deciding to switch. History conversion is incremental, so " +"you can perform an initial conversion, then small additional conversions " +"afterwards to bring in new changes." +msgstr "" + +#. type: Content of: <book><preface><sect1><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:498 ../en/ch00-preface.xml:637 +msgid "Git" +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:500 +msgid "" +"Git is a distributed revision control tool that was developed for managing " +"the Linux kernel source tree. Like Mercurial, its early design was somewhat " +"influenced by Monotone." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:505 +msgid "" +"Git has a very large command set, with version 1.5.0 providing 139 individual " +"commands. It has something of a reputation for being difficult to learn. " +"Compared to Git, Mercurial has a strong focus on simplicity." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:510 +msgid "" +"In terms of performance, Git is extremely fast. In several cases, it is " +"faster than Mercurial, at least on Linux, while Mercurial performs better on " +"other operations. However, on Windows, the performance and general level of " +"support that Git provides is, at the time of writing, far behind that of " +"Mercurial." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:517 +msgid "" +"While a Mercurial repository needs no maintenance, a Git repository requires " +"frequent manual <quote>repacks</quote> of its metadata. Without these, " +"performance degrades, while space usage grows rapidly. A server that " +"contains many Git repositories that are not rigorously and frequently " +"repacked will become heavily disk-bound during backups, and there have been " +"instances of daily backups taking far longer than 24 hours as a result. A " +"freshly packed Git repository is slightly smaller than a Mercurial " +"repository, but an unpacked repository is several orders of magnitude larger." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:528 +msgid "" +"The core of Git is written in C. Many Git commands are implemented as shell " +"or Perl scripts, and the quality of these scripts varies widely. I have " +"encountered several instances where scripts charged along blindly in the " +"presence of errors that should have been fatal." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:534 +msgid "Mercurial can import revision history from a Git repository." +msgstr "" + +#. type: Content of: <book><preface><sect1><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:540 ../en/ch00-preface.xml:636 +msgid "CVS" +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:542 +msgid "" +"CVS is probably the most widely used revision control tool in the world. Due " +"to its age and internal untidiness, it has been only lightly maintained for " +"many years." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:546 +msgid "" +"It has a centralised client/server architecture. It does not group related " +"file changes into atomic commits, making it easy for people to <quote>break " +"the build</quote>: one person can successfully commit part of a change and " +"then be blocked by the need for a merge, causing other people to see only a " +"portion of the work they intended to do. This also affects how you work with " +"project history. If you want to see all of the modifications someone made as " +"part of a task, you will need to manually inspect the descriptions and " +"timestamps of the changes made to each file involved (if you even know what " +"those files were)." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:558 +msgid "" +"CVS has a muddled notion of tags and branches that I will not attempt to even " +"describe. It does not support renaming of files or directories well, making " +"it easy to corrupt a repository. It has almost no internal consistency " +"checking capabilities, so it is usually not even possible to tell whether or " +"how a repository is corrupt. I would not recommend CVS for any project, " +"existing or new." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:566 +msgid "" +"Mercurial can import CVS revision history. However, there are a few caveats " +"that apply; these are true of every other revision control tool's CVS " +"importer, too. Due to CVS's lack of atomic changes and unversioned " +"filesystem hierarchy, it is not possible to reconstruct CVS history " +"completely accurately; some guesswork is involved, and renames will usually " +"not show up. Because a lot of advanced CVS administration has to be done by " +"hand and is hence error-prone, it's common for CVS importers to run into " +"multiple problems with corrupted repositories (completely bogus revision " +"timestamps and files that have remained locked for over a decade are just two " +"of the less interesting problems I can recall from personal experience)." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:580 +msgid "Mercurial can import revision history from a CVS repository." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><title> +#: ../en/ch00-preface.xml:586 +msgid "Commercial tools" +msgstr "商业工具" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:588 +msgid "" +"Perforce has a centralised client/server architecture, with no client-side " +"caching of any data. Unlike modern revision control tools, Perforce requires " +"that a user run a command to inform the server about every file they intend " +"to edit." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:594 +msgid "" +"The performance of Perforce is quite good for small teams, but it falls off " +"rapidly as the number of users grows beyond a few dozen. Modestly large " +"Perforce installations require the deployment of proxies to cope with the " +"load their users generate." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><title> +#: ../en/ch00-preface.xml:603 +msgid "Choosing a revision control tool" +msgstr "选择版本控制工具" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:605 +msgid "" +"With the exception of CVS, all of the tools listed above have unique " +"strengths that suit them to particular styles of work. There is no single " +"revision control tool that is best in all situations." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:610 +msgid "" +"As an example, Subversion is a good choice for working with frequently edited " +"binary files, due to its centralised nature and support for file locking." +msgstr "" + +#. type: Content of: <book><preface><sect1><sect2><para> +#: ../en/ch00-preface.xml:614 +msgid "" +"I personally find Mercurial's properties of simplicity, performance, and good " +"merge support to be a compelling combination that has served me well for " +"several years." +msgstr "" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:622 +msgid "Switching from another tool to Mercurial" +msgstr "从其它工具切换到 Mercurial" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:624 +msgid "" +"Mercurial is bundled with an extension named <literal role=\"hg-ext" +"\">convert</literal>, which can incrementally import revision history from " +"several other revision control tools. By <quote>incremental</quote>, I mean " +"that you can convert all of a project's history to date in one go, then rerun " +"the conversion later to obtain new changes that happened after the initial " +"conversion." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:632 +msgid "" +"The revision control tools supported by <literal role=\"hg-ext\">convert</" +"literal> are as follows:" +msgstr "<literal role=\"hg-ext\">convert</literal> 支持的版本控制工具有:" + +#. type: Content of: <book><preface><sect1><itemizedlist><listitem><para> +#: ../en/ch00-preface.xml:638 +msgid "Darcs" +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:640 +msgid "" +"In addition, <literal role=\"hg-ext\">convert</literal> can export changes " +"from Mercurial to Subversion. This makes it possible to try Subversion and " +"Mercurial in parallel before committing to a switchover, without risking the " +"loss of any work." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:646 +msgid "" +"The <command role=\"hg-ext-convert\">convert</command> command is easy to " +"use. Simply point it at the path or URL of the source repository, optionally " +"give it the name of the destination repository, and it will start working. " +"After the initial conversion, just run the same command again to import new " +"changes." +msgstr "" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:655 +msgid "A short history of revision control" +msgstr "版本控制简史" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:657 +msgid "" +"The best known of the old-time revision control tools is SCCS (Source Code " +"Control System), which Marc Rochkind wrote at Bell Labs, in the early 1970s. " +"SCCS operated on individual files, and required every person working on a " +"project to have access to a shared workspace on a single system. Only one " +"person could modify a file at any time; arbitration for access to files was " +"via locks. It was common for people to lock files, and later forget to " +"unlock them, preventing anyone else from modifying those files without the " +"help of an administrator." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:668 +msgid "" +"Walter Tichy developed a free alternative to SCCS in the early 1980s; he " +"called his program RCS (Revision Control System). Like SCCS, RCS required " +"developers to work in a single shared workspace, and to lock files to prevent " +"multiple people from modifying them simultaneously." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:674 +msgid "" +"Later in the 1980s, Dick Grune used RCS as a building block for a set of " +"shell scripts he initially called cmt, but then renamed to CVS (Concurrent " +"Versions System). The big innovation of CVS was that it let developers work " +"simultaneously and somewhat independently in their own personal workspaces. " +"The personal workspaces prevented developers from stepping on each other's " +"toes all the time, as was common with SCCS and RCS. Each developer had a copy " +"of every project file, and could modify their copies independently. They had " +"to merge their edits prior to committing changes to the central repository." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:685 +msgid "" +"Brian Berliner took Grune's original scripts and rewrote them in C, releasing " +"in 1989 the code that has since developed into the modern version of CVS. " +"CVS subsequently acquired the ability to operate over a network connection, " +"giving it a client/server architecture. CVS's architecture is centralised; " +"only the server has a copy of the history of the project. Client workspaces " +"just contain copies of recent versions of the project's files, and a little " +"metadata to tell them where the server is. CVS has been enormously " +"successful; it is probably the world's most widely used revision control " +"system." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:696 +msgid "" +"In the early 1990s, Sun Microsystems developed an early distributed revision " +"control system, called TeamWare. A TeamWare workspace contains a complete " +"copy of the project's history. TeamWare has no notion of a central " +"repository. (CVS relied upon RCS for its history storage; TeamWare used " +"SCCS.)" +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:703 +msgid "" +"As the 1990s progressed, awareness grew of a number of problems with CVS. It " +"records simultaneous changes to multiple files individually, instead of " +"grouping them together as a single logically atomic operation. It does not " +"manage its file hierarchy well; it is easy to make a mess of a repository by " +"renaming files and directories. Worse, its source code is difficult to read " +"and maintain, which made the <quote>pain level</quote> of fixing these " +"architectural problems prohibitive." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:713 +msgid "" +"In 2001, Jim Blandy and Karl Fogel, two developers who had worked on CVS, " +"started a project to replace it with a tool that would have a better " +"architecture and cleaner code. The result, Subversion, does not stray from " +"CVS's centralised client/server model, but it adds multi-file atomic commits, " +"better namespace management, and a number of other features that make it a " +"generally better tool than CVS. Since its initial release, it has rapidly " +"grown in popularity." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:722 +msgid "" +"More or less simultaneously, Graydon Hoare began working on an ambitious " +"distributed revision control system that he named Monotone. While Monotone " +"addresses many of CVS's design flaws and has a peer-to-peer architecture, it " +"goes beyond earlier (and subsequent) revision control tools in a number of " +"innovative ways. It uses cryptographic hashes as identifiers, and has an " +"integral notion of <quote>trust</quote> for code from different sources." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:731 +msgid "" +"Mercurial began life in 2005. While a few aspects of its design are " +"influenced by Monotone, Mercurial focuses on ease of use, high performance, " +"and scalability to very large projects." +msgstr "" + +#. type: Content of: <book><preface><sect1><title> +#: ../en/ch00-preface.xml:739 +msgid "Colophon&emdash;this book is Free" +msgstr "后记&emdash;本书是自由的!" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:741 +msgid "" +"This book is licensed under the Open Publication License, and is produced " +"entirely using Free Software tools. It is typeset with DocBook XML. " +"Illustrations are drawn and rendered with <ulink url=\"http://www.inkscape." +"org/\">Inkscape</ulink>." +msgstr "" + +#. type: Content of: <book><preface><sect1><para> +#: ../en/ch00-preface.xml:746 +msgid "" +"The complete source code for this book is published as a Mercurial " +"repository, at <ulink url=\"http://hg.serpentine.com/mercurial/book\">http://" +"hg.serpentine.com/mercurial/book</ulink>." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch01-tour-basic.xml:5 +msgid "A tour of Mercurial: the basics" +msgstr "Mercurial 教程: 基础知识" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch01-tour-basic.xml:8 +msgid "Installing Mercurial on your system" +msgstr "安装 Mercurial" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:10 +msgid "" +"Prebuilt binary packages of Mercurial are available for every popular " +"operating system. These make it easy to start using Mercurial on your " +"computer immediately." +msgstr "" +"对于每种流行的操作系统,都有已经构建的二进制软件包。这让在你的计算机上开始使" +"用 Mercurial 变得很容易。" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:15 +msgid "Linux" +msgstr "Linux" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:17 +msgid "" +"Because each Linux distribution has its own packaging tools, policies, and " +"rate of development, it's difficult to give a comprehensive set of " +"instructions on how to install Mercurial binaries. The version of Mercurial " +"that you will end up with can vary depending on how active the person is who " +"maintains the package for your distribution." +msgstr "" +"由于每种 Linux 发行版都有自己的包管理工具,开发策略和进度,从而很难给出安装 " +"Mercurial 二进制包的全面说明。你安装的 Mercurial 版本,在很大程度上依赖于你所" +"使用的发行版的 Mercurial 维护者的活跃程度。" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:24 +msgid "" +"To keep things simple, I will focus on installing Mercurial from the command " +"line under the most popular Linux distributions. Most of these distributions " +"provide graphical package managers that will let you install Mercurial with a " +"single click; the package name to look for is <literal>mercurial</literal>." +msgstr "" +"为了让事情简单,我会致力于说明在最流行的 Linux 发行版中,从命令行安装 " +"Mercurial 的方法。这些发行版都提供了图形界面的包管理器,让你通过点击鼠标安装 " +"Mercurial;寻找的包名称是 <literal>mercurial</literal>。" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:32 +msgid "Debian:" +msgstr "Debian:" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:34 +msgid "Fedora Core:" +msgstr "Fedora Core:" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:36 +msgid "Gentoo:" +msgstr "Gentoo:" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:38 +msgid "OpenSUSE:" +msgstr "OpenSUSE:" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:40 +msgid "" +"Ubuntu: Ubuntu's Mercurial package is based on Debian's. To install it, run " +"the following command." +msgstr "Ubuntu: Ubuntu 的 Mercurial 包基于 Debian。安装时,使用如下命令:" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:48 +msgid "Solaris" +msgstr "Solaris" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:50 +msgid "" +"SunFreeWare, at <ulink url=\"http://www.sunfreeware.com\">http://www." +"sunfreeware.com</ulink>, is a good source for a large number of pre-built " +"Solaris packages for 32 and 64 bit Intel and Sparc architectures, including " +"current versions of Mercurial." +msgstr "" +"位于 <ulink url=\"http://www.sunfreeware.com\">http://www.sunfreeware.com</" +"ulink> 的 SunFreeWare 是很好的二进制安装源,它包含 Intel 和 Sparc 架构的 32 位" +"和 64 位包,包含 Mercurial 的当前版本。" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:58 +msgid "Mac OS X" +msgstr "Mac OS X" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:60 +msgid "" +"Lee Cantey publishes an installer of Mercurial for Mac OS X at <ulink url=" +"\"http://mercurial.berkwood.com\">http://mercurial.berkwood.com</ulink>. " +"This package works on both Intel- and Power-based Macs. Before you can use " +"it, you must install a compatible version of Universal MacPython " +"<citation>web:macpython</citation>. This is easy to do; simply follow the " +"instructions on Lee's site." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:69 +msgid "" +"It's also possible to install Mercurial using Fink or MacPorts, two popular " +"free package managers for Mac OS X. If you have Fink, use <command>sudo apt-" +"get install mercurial-py25</command>. If MacPorts, <command>sudo port " +"install mercurial</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:77 +msgid "Windows" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:79 +msgid "" +"Lee Cantey publishes an installer of Mercurial for Windows at <ulink url=" +"\"http://mercurial.berkwood.com\">http://mercurial.berkwood.com</ulink>. " +"This package has no external dependencies; it <quote>just works</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch01-tour-basic.xml:86 +msgid "" +"The Windows version of Mercurial does not automatically convert line endings " +"between Windows and Unix styles. If you want to share work with Unix users, " +"you must do a little additional configuration work. XXX Flesh this out." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch01-tour-basic.xml:96 +msgid "Getting started" +msgstr "开始" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:98 +msgid "" +"To begin, we'll use the <command role=\"hg-cmd\">hg version</command> command " +"to find out whether Mercurial is actually installed properly. The actual " +"version information that it prints isn't so important; it's whether it prints " +"anything at all that we care about." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:107 +msgid "Built-in help" +msgstr "内置帮助" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:109 +msgid "" +"Mercurial provides a built-in help system. This is invaluable for those " +"times when you find yourself stuck trying to remember how to run a command. " +"If you are completely stuck, simply run <command role=\"hg-cmd\">hg help</" +"command>; it will print a brief list of commands, along with a description of " +"what each does. If you ask for help on a specific command (as below), it " +"prints more detailed information." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:120 +msgid "" +"For a more impressive level of detail (which you won't usually need) run " +"<command role=\"hg-cmd\">hg help <option role=\"hg-opt-global\">-v</option></" +"command>. The <option role=\"hg-opt-global\">-v</option> option is short for " +"<option role=\"hg-opt-global\">--verbose</option>, and tells Mercurial to " +"print more information than it usually would." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch01-tour-basic.xml:131 +msgid "Working with a repository" +msgstr "使用版本库" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:133 +msgid "" +"In Mercurial, everything happens inside a <emphasis>repository</emphasis>. " +"The repository for a project contains all of the files that <quote>belong to</" +"quote> that project, along with a historical record of the project's files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:139 +msgid "" +"There's nothing particularly magical about a repository; it is simply a " +"directory tree in your filesystem that Mercurial treats as special. You can " +"rename or delete a repository any time you like, using either the command " +"line or your file browser." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:146 +msgid "Making a local copy of a repository" +msgstr "创建版本库的工作副本" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:148 +msgid "" +"<emphasis>Copying</emphasis> a repository is just a little bit special. " +"While you could use a normal file copying command to make a copy of a " +"repository, it's best to use a built-in command that Mercurial provides. " +"This command is called <command role=\"hg-cmd\">hg clone</command>, because " +"it creates an identical copy of an existing repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:157 +msgid "" +"If our clone succeeded, we should now have a local directory called <filename " +"class=\"directory\">hello</filename>. This directory will contain some files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:163 +msgid "" +"These files have the same contents and history in our repository as they do " +"in the repository we cloned." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:166 +msgid "" +"Every Mercurial repository is complete, self-contained, and independent. It " +"contains its own private copy of a project's files and history. A cloned " +"repository remembers the location of the repository it was cloned from, but " +"it does not communicate with that repository, or any other, unless you tell " +"it to." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:173 +msgid "" +"What this means for now is that we're free to experiment with our repository, " +"safe in the knowledge that it's a private <quote>sandbox</quote> that won't " +"affect anyone else." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:179 +msgid "What's in a repository?" +msgstr "什么是版本库?" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:181 +msgid "" +"When we take a more detailed look inside a repository, we can see that it " +"contains a directory named <filename class=\"directory\">.hg</filename>. " +"This is where Mercurial keeps all of its metadata for the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:188 +msgid "" +"The contents of the <filename class=\"directory\">.hg</filename> directory " +"and its subdirectories are private to Mercurial. Every other file and " +"directory in the repository is yours to do with as you please." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:194 +msgid "" +"To introduce a little terminology, the <filename class=\"directory\">.hg</" +"filename> directory is the <quote>real</quote> repository, and all of the " +"files and directories that coexist with it are said to live in the " +"<emphasis>working directory</emphasis>. An easy way to remember the " +"distinction is that the <emphasis>repository</emphasis> contains the " +"<emphasis>history</emphasis> of your project, while the <emphasis>working " +"directory</emphasis> contains a <emphasis>snapshot</emphasis> of your project " +"at a particular point in history." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch01-tour-basic.xml:209 +msgid "A tour through history" +msgstr "回溯历史" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:211 +msgid "" +"One of the first things we might want to do with a new, unfamiliar repository " +"is understand its history. The <command role=\"hg-cmd\">hg log</command> " +"command gives us a view of history." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:218 +msgid "" +"By default, this command prints a brief paragraph of output for each change " +"to the project that was recorded. In Mercurial terminology, we call each of " +"these recorded events a <emphasis>changeset</emphasis>, because it can " +"contain a record of changes to several files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:224 +msgid "" +"The fields in a record of output from <command role=\"hg-cmd\">hg log</" +"command> are as follows." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:227 +msgid "" +"<literal>changeset</literal>: This field has the format of a number, followed " +"by a colon, followed by a hexadecimal string. These are " +"<emphasis>identifiers</emphasis> for the changeset. There are two " +"identifiers because the number is shorter and easier to type than the hex " +"string." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:233 +msgid "" +"<literal>user</literal>: The identity of the person who created the " +"changeset. This is a free-form field, but it most often contains a person's " +"name and email address." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:237 +msgid "" +"<literal>date</literal>: The date and time on which the changeset was " +"created, and the timezone in which it was created. (The date and time are " +"local to that timezone; they display what time and date it was for the person " +"who created the changeset.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:242 +msgid "" +"<literal>summary</literal>: The first line of the text message that the " +"creator of the changeset entered to describe the changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:245 +msgid "" +"The default output printed by <command role=\"hg-cmd\">hg log</command> is " +"purely a summary; it is missing a lot of detail." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:249 +msgid "" +"Figure <xref endterm=\"fig.tour-basic.history.caption\" linkend=\"fig.tour-" +"basic.history\"/> provides a graphical representation of the history of the " +"<filename class=\"directory\">hello</filename> repository, to make it a " +"little easier to see which direction history is <quote>flowing</quote> in. " +"We'll be returning to this figure several times in this chapter and the " +"chapter that follows." +msgstr "" + +#. type: Content of: <book><chapter><sect1><informalfigure><mediaobject> +#: ../en/ch01-tour-basic.xml:260 +msgid "" +"<imageobject><imagedata fileref=\"images/tour-history.png\"/></imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><textobject><phrase> +#: ../en/ch01-tour-basic.xml:261 ../en/ch02-tour-merge.xml:48 +#: ../en/ch02-tour-merge.xml:78 ../en/ch02-tour-merge.xml:126 +#: ../en/ch02-tour-merge.xml:182 ../en/ch02-tour-merge.xml:254 +#: ../en/ch03-concepts.xml:56 ../en/ch03-concepts.xml:108 +#: ../en/ch03-concepts.xml:194 ../en/ch03-concepts.xml:301 +#: ../en/ch03-concepts.xml:353 ../en/ch03-concepts.xml:370 +#: ../en/ch03-concepts.xml:414 ../en/ch03-concepts.xml:436 +#: ../en/ch03-concepts.xml:480 ../en/ch05-collab.xml:277 +#: ../en/ch08-undo.xml:366 ../en/ch08-undo.xml:417 ../en/ch08-undo.xml:485 +#: ../en/ch08-undo.xml:527 ../en/ch11-mq.xml:410 +msgid "XXX add text" +msgstr "" + +#. type: Content of: <book><chapter><sect1><informalfigure><mediaobject><caption><para> +#: ../en/ch01-tour-basic.xml:262 +msgid "" +"Graphical history of the <filename class=\"directory\">hello</filename> " +"repository" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:269 +msgid "Changesets, revisions, and talking to other people" +msgstr "改变集,版本,与其它用户交互" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:272 +msgid "" +"As English is a notoriously sloppy language, and computer science has a " +"hallowed history of terminological confusion (why use one term when four will " +"do?), revision control has a variety of words and phrases that mean the same " +"thing. If you are talking about Mercurial history with other people, you " +"will find that the word <quote>changeset</quote> is often compressed to " +"<quote>change</quote> or (when written) <quote>cset</quote>, and sometimes a " +"changeset is referred to as a <quote>revision</quote> or a <quote>rev</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:282 +msgid "" +"While it doesn't matter what <emphasis>word</emphasis> you use to refer to " +"the concept of <quote>a changeset</quote>, the <emphasis>identifier</" +"emphasis> that you use to refer to <quote>a <emphasis>specific</emphasis> " +"changeset</quote> is of great importance. Recall that the <literal>changeset</" +"literal> field in the output from <command role=\"hg-cmd\">hg log</command> " +"identifies a changeset using both a number and a hexadecimal string." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:291 +msgid "" +"The revision number is <emphasis>only valid in that repository</emphasis>," +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:293 +msgid "" +"while the hex string is the <emphasis>permanent, unchanging identifier</" +"emphasis> that will always identify that exact changeset in <emphasis>every</" +"emphasis> copy of the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:298 +msgid "" +"This distinction is important. If you send someone an email talking about " +"<quote>revision 33</quote>, there's a high likelihood that their revision 33 " +"will <emphasis>not be the same</emphasis> as yours. The reason for this is " +"that a revision number depends on the order in which changes arrived in a " +"repository, and there is no guarantee that the same changes will happen in " +"the same order in different repositories. Three changes $a,b,c$ can easily " +"appear in one repository as $0,1,2$, while in another as $1,0,2$." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:308 +msgid "" +"Mercurial uses revision numbers purely as a convenient shorthand. If you " +"need to discuss a changeset with someone, or make a record of a changeset for " +"some other reason (for example, in a bug report), use the hexadecimal " +"identifier." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:316 +msgid "Viewing specific revisions" +msgstr "察看指定版本" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:318 +msgid "" +"To narrow the output of <command role=\"hg-cmd\">hg log</command> down to a " +"single revision, use the <option role=\"hg-opt-log\">-r</option> (or <option " +"role=\"hg-opt-log\">--rev</option>) option. You can use either a revision " +"number or a long-form changeset identifier, and you can provide as many " +"revisions as you want." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:327 +msgid "" +"If you want to see the history of several revisions without having to list " +"each one, you can use <emphasis>range notation</emphasis>; this lets you " +"express the idea <quote>I want all revisions between <literal>abc</literal> " +"and <literal>def</literal>, inclusive</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:335 +msgid "" +"Mercurial also honours the order in which you specify revisions, so <command " +"role=\"hg-cmd\">hg log -r 2:4</command> prints 2, 3, and 4. while <command " +"role=\"hg-cmd\">hg log -r 4:2</command> prints 4, 3, and 2." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:342 +msgid "More detailed information" +msgstr "更详细的信息" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:344 +msgid "" +"While the summary information printed by <command role=\"hg-cmd\">hg log</" +"command> is useful if you already know what you're looking for, you may need " +"to see a complete description of the change, or a list of the files changed, " +"if you're trying to decide whether a changeset is the one you're looking for. " +"The <command role=\"hg-cmd\">hg log</command> command's <option role=\"hg-opt-" +"global\">-v</option> (or <option role=\"hg-opt-global\">--verbose</option>) " +"option gives you this extra detail." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:356 +msgid "" +"If you want to see both the description and content of a change, add the " +"<option role=\"hg-opt-log\">-p</option> (or <option role=\"hg-opt-log\">--" +"patch</option>) option. This displays the content of a change as a " +"<emphasis>unified diff</emphasis> (if you've never seen a unified diff " +"before, see section <xref linkend=\"sec.mq.patch\"/> for an overview)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch01-tour-basic.xml:369 +msgid "All about command options" +msgstr "命令选项" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:371 +msgid "" +"Let's take a brief break from exploring Mercurial commands to discuss a " +"pattern in the way that they work; you may find this useful to keep in mind " +"as we continue our tour." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:375 +msgid "" +"Mercurial has a consistent and straightforward approach to dealing with the " +"options that you can pass to commands. It follows the conventions for " +"options that are common to modern Linux and Unix systems." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:380 +msgid "" +"Every option has a long name. For example, as we've already seen, the " +"<command role=\"hg-cmd\">hg log</command> command accepts a <option role=\"hg-" +"opt-log\">--rev</option> option." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:384 +msgid "" +"Most options have short names, too. Instead of <option role=\"hg-opt-log\">--" +"rev</option>, we can use <option role=\"hg-opt-log\">-r</option>. (The " +"reason that some options don't have short names is that the options in " +"question are rarely used.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:389 +msgid "" +"Long options start with two dashes (e.g. <option role=\"hg-opt-log\">--rev</" +"option>), while short options start with one (e.g. <option role=\"hg-opt-log" +"\">-r</option>)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:393 +msgid "" +"Option naming and usage is consistent across commands. For example, every " +"command that lets you specify a changeset ID or revision number accepts both " +"<option role=\"hg-opt-log\">-r</option> and <option role=\"hg-opt-log\">--" +"rev</option> arguments." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:399 +msgid "" +"In the examples throughout this book, I use short options instead of long. " +"This just reflects my own preference, so don't read anything significant into " +"it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:403 +msgid "" +"Most commands that print output of some kind will print more output when " +"passed a <option role=\"hg-opt-global\">-v</option> (or <option role=\"hg-opt-" +"global\">--verbose</option>) option, and less when passed <option role=\"hg-" +"opt-global\">-q</option> (or <option role=\"hg-opt-global\">--quiet</option>)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch01-tour-basic.xml:411 +msgid "Making and reviewing changes" +msgstr "创建和复审修改" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:413 +msgid "" +"Now that we have a grasp of viewing history in Mercurial, let's take a look " +"at making some changes and examining them." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:417 +msgid "" +"The first thing we'll do is isolate our experiment in a repository of its " +"own. We use the <command role=\"hg-cmd\">hg clone</command> command, but we " +"don't need to clone a copy of the remote repository. Since we already have a " +"copy of it locally, we can just clone that instead. This is much faster than " +"cloning over the network, and cloning a local repository uses less disk space " +"in most cases, too." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:427 +msgid "" +"As an aside, it's often good practice to keep a <quote>pristine</quote> copy " +"of a remote repository around, which you can then make temporary clones of to " +"create sandboxes for each task you want to work on. This lets you work on " +"multiple tasks in parallel, each isolated from the others until it's complete " +"and you're ready to integrate it back. Because local clones are so cheap, " +"there's almost no overhead to cloning and destroying repositories whenever " +"you want." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:436 +msgid "" +"In our <filename class=\"directory\">my-hello</filename> repository, we have " +"a file <filename>hello.c</filename> that contains the classic <quote>hello, " +"world</quote> program. Let's use the ancient and venerable <command>sed</" +"command> command to edit this file so that it prints a second line of " +"output. (I'm only using <command>sed</command> to do this because it's easy " +"to write a scripted example this way. Since you're not under the same " +"constraint, you probably won't want to use <command>sed</command>; simply use " +"your preferred text editor to do the same thing.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:449 +msgid "" +"Mercurial's <command role=\"hg-cmd\">hg status</command> command will tell us " +"what Mercurial knows about the files in the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:455 +msgid "" +"The <command role=\"hg-cmd\">hg status</command> command prints no output for " +"some files, but a line starting with <quote><literal>M</literal></quote> for " +"<filename>hello.c</filename>. Unless you tell it to, <command role=\"hg-cmd" +"\">hg status</command> will not print any output for files that have not been " +"modified." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:462 +msgid "" +"The <quote><literal>M</literal></quote> indicates that Mercurial has noticed " +"that we modified <filename>hello.c</filename>. We didn't need to " +"<emphasis>inform</emphasis> Mercurial that we were going to modify the file " +"before we started, or that we had modified the file after we were done; it " +"was able to figure this out itself." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:470 +msgid "" +"It's a little bit helpful to know that we've modified <filename>hello.c</" +"filename>, but we might prefer to know exactly <emphasis>what</emphasis> " +"changes we've made to it. To do this, we use the <command role=\"hg-cmd\">hg " +"diff</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch01-tour-basic.xml:480 +msgid "Recording changes in a new changeset" +msgstr "在新修改集中记录修改" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:482 +msgid "" +"We can modify files, build and test our changes, and use <command role=\"hg-" +"cmd\">hg status</command> and <command role=\"hg-cmd\">hg diff</command> to " +"review our changes, until we're satisfied with what we've done and arrive at " +"a natural stopping point where we want to record our work in a new changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:489 +msgid "" +"The <command role=\"hg-cmd\">hg commit</command> command lets us create a new " +"changeset; we'll usually refer to this as <quote>making a commit</quote> or " +"<quote>committing</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:495 +msgid "Setting up a username" +msgstr "配置用户名称" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:497 +msgid "" +"When you try to run <command role=\"hg-cmd\">hg commit</command> for the " +"first time, it is not guaranteed to succeed. Mercurial records your name and " +"address with each change that you commit, so that you and others will later " +"be able to tell who made each change. Mercurial tries to automatically " +"figure out a sensible username to commit the change with. It will attempt " +"each of the following methods, in order:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:506 +msgid "" +"If you specify a <option role=\"hg-opt-commit\">-u</option> option to the " +"<command role=\"hg-cmd\">hg commit</command> command on the command line, " +"followed by a username, this is always given the highest precedence." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:511 +msgid "" +"If you have set the <envar>HGUSER</envar> environment variable, this is " +"checked next." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:514 +msgid "" +"If you create a file in your home directory called <filename role=\"special" +"\">.hgrc</filename>, with a <envar role=\"rc-item-ui\">username</envar> " +"entry, that will be used next. To see what the contents of this file should " +"look like, refer to section <xref linkend=\"sec.tour-basic.username\"/> below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:521 +msgid "" +"If you have set the <envar>EMAIL</envar> environment variable, this will be " +"used next." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch01-tour-basic.xml:524 +msgid "" +"Mercurial will query your system to find out your local user name and host " +"name, and construct a username from these components. Since this often " +"results in a username that is not very useful, it will print a warning if it " +"has to do this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:531 +msgid "" +"If all of these mechanisms fail, Mercurial will fail, printing an error " +"message. In this case, it will not let you commit until you set up a " +"username." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:535 +msgid "" +"You should think of the <envar>HGUSER</envar> environment variable and the " +"<option role=\"hg-opt-commit\">-u</option> option to the <command role=\"hg-" +"cmd\">hg commit</command> command as ways to <emphasis>override</emphasis> " +"Mercurial's default selection of username. For normal use, the simplest and " +"most robust way to set a username for yourself is by creating a <filename " +"role=\"special\">.hgrc</filename> file; see below for details." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch01-tour-basic.xml:544 +msgid "Creating a Mercurial configuration file" +msgstr "创建 Mercurial 的配置文件" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch01-tour-basic.xml:546 +msgid "" +"To set a user name, use your favourite editor to create a file called " +"<filename role=\"special\">.hgrc</filename> in your home directory. " +"Mercurial will use this file to look up your personalised configuration " +"settings. The initial contents of your <filename role=\"special\">.hgrc</" +"filename> should look like this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch01-tour-basic.xml:558 +msgid "" +"The <quote><literal>[ui]</literal></quote> line begins a <emphasis>section</" +"emphasis> of the config file, so you can read the <quote><literal>username " +"= ...</literal></quote> line as meaning <quote>set the value of the " +"<literal>username</literal> item in the <literal>ui</literal> section</" +"quote>. A section continues until a new section begins, or the end of the " +"file. Mercurial ignores empty lines and treats any text from " +"<quote><literal>#</literal></quote> to the end of a line as a comment." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch01-tour-basic.xml:571 +msgid "Choosing a user name" +msgstr "选择用户名称" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch01-tour-basic.xml:573 +msgid "" +"You can use any text you like as the value of the <literal>username</literal> " +"config item, since this information is for reading by other people, but for " +"interpreting by Mercurial. The convention that most people follow is to use " +"their name and email address, as in the example above." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><note><para> +#: ../en/ch01-tour-basic.xml:580 +msgid "" +"Mercurial's built-in web server obfuscates email addresses, to make it more " +"difficult for the email harvesting tools that spammers use. This reduces the " +"likelihood that you'll start receiving more junk email if you publish a " +"Mercurial repository on the web." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:590 +msgid "Writing a commit message" +msgstr "写提交日志" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:592 +msgid "" +"When we commit a change, Mercurial drops us into a text editor, to enter a " +"message that will describe the modifications we've made in this changeset. " +"This is called the <emphasis>commit message</emphasis>. It will be a record " +"for readers of what we did and why, and it will be printed by <command role=" +"\"hg-cmd\">hg log</command> after we've finished committing." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:602 +msgid "" +"The editor that the <command role=\"hg-cmd\">hg commit</command> command " +"drops us into will contain an empty line, followed by a number of lines " +"starting with <quote><literal>HG:</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:609 +msgid "" +"Mercurial ignores the lines that start with <quote><literal>HG:</literal></" +"quote>; it uses them only to tell us which files it's recording changes to. " +"Modifying or deleting these lines has no effect." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:615 +msgid "Writing a good commit message" +msgstr "写好提交日志" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:617 +msgid "" +"Since <command role=\"hg-cmd\">hg log</command> only prints the first line of " +"a commit message by default, it's best to write a commit message whose first " +"line stands alone. Here's a real example of a commit message that " +"<emphasis>doesn't</emphasis> follow this guideline, and hence has a summary " +"that is not readable." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:631 +msgid "" +"As far as the remainder of the contents of the commit message are concerned, " +"there are no hard-and-fast rules. Mercurial itself doesn't interpret or care " +"about the contents of the commit message, though your project may have " +"policies that dictate a certain kind of formatting." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:637 +msgid "" +"My personal preference is for short, but informative, commit messages that " +"tell me something that I can't figure out with a quick glance at the output " +"of <command role=\"hg-cmd\">hg log --patch</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:644 +msgid "Aborting a commit" +msgstr "终止提交" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:646 +msgid "" +"If you decide that you don't want to commit while in the middle of editing a " +"commit message, simply exit from your editor without saving the file that " +"it's editing. This will cause nothing to happen to either the repository or " +"the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:651 +msgid "" +"If we run the <command role=\"hg-cmd\">hg commit</command> command without " +"any arguments, it records all of the changes we've made, as reported by " +"<command role=\"hg-cmd\">hg status</command> and <command role=\"hg-cmd\">hg " +"diff</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:658 +msgid "Admiring our new handiwork" +msgstr "欣赏我们的新手艺" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:660 +msgid "" +"Once we've finished the commit, we can use the <command role=\"hg-cmd\">hg " +"tip</command> command to display the changeset we just created. This command " +"produces output that is identical to <command role=\"hg-cmd\">hg log</" +"command>, but it only displays the newest revision in the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:669 +msgid "" +"We refer to the newest revision in the repository as the tip revision, or " +"simply the tip." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch01-tour-basic.xml:676 +msgid "Sharing changes" +msgstr "共享修改" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch01-tour-basic.xml:678 +msgid "" +"We mentioned earlier that repositories in Mercurial are self-contained. This " +"means that the changeset we just created exists only in our <filename class=" +"\"directory\">my-hello</filename> repository. Let's look at a few ways that " +"we can propagate this change into other repositories." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:686 +msgid "Pulling changes from another repository" +msgstr "从其它版本库取得修改" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:687 +msgid "" +"To get started, let's clone our original <filename class=\"directory\">hello</" +"filename> repository, which does not contain the change we just committed. " +"We'll call our temporary repository <filename class=\"directory\">hello-pull</" +"filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:695 +msgid "" +"We'll use the <command role=\"hg-cmd\">hg pull</command> command to bring " +"changes from <filename class=\"directory\">my-hello</filename> into <filename " +"class=\"directory\">hello-pull</filename>. However, blindly pulling unknown " +"changes into a repository is a somewhat scary prospect. Mercurial provides " +"the <command role=\"hg-cmd\">hg incoming</command> command to tell us what " +"changes the <command role=\"hg-cmd\">hg pull</command> command " +"<emphasis>would</emphasis> pull into the repository, without actually pulling " +"the changes in." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:708 +msgid "" +"(Of course, someone could cause more changesets to appear in the repository " +"that we ran <command role=\"hg-cmd\">hg incoming</command> in, before we get " +"a chance to <command role=\"hg-cmd\">hg pull</command> the changes, so that " +"we could end up pulling changes that we didn't expect.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:715 +msgid "" +"Bringing changes into a repository is a simple matter of running the <command " +"role=\"hg-cmd\">hg pull</command> command, and telling it which repository to " +"pull from." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:722 +msgid "" +"As you can see from the before-and-after output of <command role=\"hg-cmd" +"\">hg tip</command>, we have successfully pulled changes into our " +"repository. There remains one step before we can see these changes in the " +"working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:730 +msgid "Updating the working directory" +msgstr "更新工作目录" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:732 +msgid "" +"We have so far glossed over the relationship between a repository and its " +"working directory. The <command role=\"hg-cmd\">hg pull</command> command " +"that we ran in section <xref linkend=\"sec.tour.pull\"/> brought changes into " +"the repository, but if we check, there's no sign of those changes in the " +"working directory. This is because <command role=\"hg-cmd\">hg pull</" +"command> does not (by default) touch the working directory. Instead, we use " +"the <command role=\"hg-cmd\">hg update</command> command to do this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:744 +msgid "" +"It might seem a bit strange that <command role=\"hg-cmd\">hg pull</command> " +"doesn't update the working directory automatically. There's actually a good " +"reason for this: you can use <command role=\"hg-cmd\">hg update</command> to " +"update the working directory to the state it was in at <emphasis>any " +"revision</emphasis> in the history of the repository. If you had the working " +"directory updated to an old revision---to hunt down the origin of a bug, " +"say---and ran a <command role=\"hg-cmd\">hg pull</command> which " +"automatically updated the working directory to a new revision, you might not " +"be terribly happy." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:755 +msgid "" +"However, since pull-then-update is such a common thing to do, Mercurial lets " +"you combine the two by passing the <option role=\"hg-opt-pull\">-u</option> " +"option to <command role=\"hg-cmd\">hg pull</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:760 +msgid "" +"If you look back at the output of <command role=\"hg-cmd\">hg pull</command> " +"in section <xref linkend=\"sec.tour.pull\"/> when we ran it without <option " +"role=\"hg-opt-pull\">-u</option>, you can see that it printed a helpful " +"reminder that we'd have to take an explicit step to update the working " +"directory:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:769 +msgid "" +"To find out what revision the working directory is at, use the <command role=" +"\"hg-cmd\">hg parents</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:775 +msgid "" +"If you look back at figure <xref endterm=\"fig.tour-basic.history.caption\" " +"linkend=\"fig.tour-basic.history\"/>, you'll see arrows connecting each " +"changeset. The node that the arrow leads <emphasis>from</emphasis> in each " +"case is a parent, and the node that the arrow leads <emphasis>to</emphasis> " +"is its child. The working directory has a parent in just the same way; this " +"is the changeset that the working directory currently contains." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:785 +msgid "" +"To update the working directory to a particular revision, give a revision " +"number or changeset ID to the <command role=\"hg-cmd\">hg update</command> " +"command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:792 +msgid "" +"If you omit an explicit revision, <command role=\"hg-cmd\">hg update</" +"command> will update to the tip revision, as shown by the second call to " +"<command role=\"hg-cmd\">hg update</command> in the example above." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:800 +msgid "Pushing changes to another repository" +msgstr "发布修改到其它版本库" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:802 +msgid "" +"Mercurial lets us push changes to another repository, from the repository " +"we're currently visiting. As with the example of <command role=\"hg-cmd\">hg " +"pull</command> above, we'll create a temporary repository to push our changes " +"into." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:810 +msgid "" +"The <command role=\"hg-cmd\">hg outgoing</command> command tells us what " +"changes would be pushed into another repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:816 +msgid "" +"And the <command role=\"hg-cmd\">hg push</command> command does the actual " +"push." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:822 +msgid "" +"As with <command role=\"hg-cmd\">hg pull</command>, the <command role=\"hg-cmd" +"\">hg push</command> command does not update the working directory in the " +"repository that it's pushing changes into. (Unlike <command role=\"hg-cmd" +"\">hg pull</command>, <command role=\"hg-cmd\">hg push</command> does not " +"provide a <literal>-u</literal> option that updates the other repository's " +"working directory.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:831 +msgid "" +"What happens if we try to pull or push changes and the receiving repository " +"already has those changes? Nothing too exciting." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch01-tour-basic.xml:838 +msgid "Sharing changes over a network" +msgstr "通过网络共享修改" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:840 +msgid "" +"The commands we have covered in the previous few sections are not limited to " +"working with local repositories. Each works in exactly the same fashion over " +"a network connection; simply pass in a URL instead of a local path." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch01-tour-basic.xml:848 +msgid "" +"In this example, we can see what changes we could push to the remote " +"repository, but the repository is understandably not set up to let anonymous " +"users push to it." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch02-tour-merge.xml:5 +msgid "A tour of Mercurial: merging work" +msgstr "Mercurial 教程: 合并工作" + +#. type: Content of: <book><chapter><para> +#: ../en/ch02-tour-merge.xml:7 +msgid "" +"We've now covered cloning a repository, making changes in a repository, and " +"pulling or pushing changes from one repository into another. Our next step " +"is <emphasis>merging</emphasis> changes from separate repositories." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch02-tour-merge.xml:13 +msgid "Merging streams of work" +msgstr "合并的流程" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:15 +msgid "" +"Merging is a fundamental part of working with a distributed revision control " +"tool." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch02-tour-merge.xml:18 +msgid "" +"Alice and Bob each have a personal copy of a repository for a project they're " +"collaborating on. Alice fixes a bug in her repository; Bob adds a new " +"feature in his. They want the shared repository to contain both the bug fix " +"and the new feature." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch02-tour-merge.xml:24 +msgid "" +"I frequently work on several different tasks for a single project at once, " +"each safely isolated in its own repository. Working this way means that I " +"often need to merge one piece of my own work with another." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:30 +msgid "" +"Because merging is such a common thing to need to do, Mercurial makes it " +"easy. Let's walk through the process. We'll begin by cloning yet another " +"repository (see how often they spring up?) and making a change in it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:37 +msgid "" +"We should now have two copies of <filename>hello.c</filename> with different " +"contents. The histories of the two repositories have also diverged, as " +"illustrated in figure <xref endterm=\"fig.tour-merge.sep-repos.caption\" " +"linkend=\"fig.tour-merge.sep-repos\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><informalfigure><mediaobject> +#: ../en/ch02-tour-merge.xml:47 +msgid "" +"<imageobject><imagedata fileref=\"images/tour-merge-sep-repos.png\"/></" +"imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><informalfigure><mediaobject><caption><para> +#: ../en/ch02-tour-merge.xml:49 +msgid "" +"Divergent recent histories of the <filename class=\"directory\">my-hello</" +"filename> and <filename class=\"directory\">my-new-hello</filename> " +"repositories" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:57 +msgid "" +"We already know that pulling changes from our <filename class=\"directory" +"\">my-hello</filename> repository will have no effect on the working " +"directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:63 +msgid "" +"However, the <command role=\"hg-cmd\">hg pull</command> command says " +"something about <quote>heads</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch02-tour-merge.xml:67 +msgid "Head changesets" +msgstr "顶点改变集" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:69 +msgid "" +"A head is a change that has no descendants, or children, as they're also " +"known. The tip revision is thus a head, because the newest revision in a " +"repository doesn't have any children, but a repository can contain more than " +"one head." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch02-tour-merge.xml:77 +msgid "" +"<imageobject><imagedata fileref=\"images/tour-merge-pull.png\"/></imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch02-tour-merge.xml:79 +msgid "" +"Repository contents after pulling from <filename class=\"directory\">my-" +"hello</filename> into <filename class=\"directory\">my-new-hello</filename>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:85 +msgid "" +"In figure <xref endterm=\"fig.tour-merge.pull.caption\" linkend=\"fig.tour-" +"merge.pull\"/>, you can see the effect of the pull from <filename class=" +"\"directory\">my-hello</filename> into <filename class=\"directory\">my-new-" +"hello</filename>. The history that was already present in <filename class=" +"\"directory\">my-new-hello</filename> is untouched, but a new revision has " +"been added. By referring to figure <xref endterm=\"fig.tour-merge.sep-repos." +"caption\" linkend=\"fig.tour-merge.sep-repos\"/>, we can see that the " +"<emphasis>changeset ID</emphasis> remains the same in the new repository, but " +"the <emphasis>revision number</emphasis> has changed. (This, incidentally, " +"is a fine example of why it's not safe to use revision numbers when " +"discussing changesets.) We can view the heads in a repository using the " +"<command role=\"hg-cmd\">hg heads</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch02-tour-merge.xml:106 +msgid "Performing the merge" +msgstr "执行合并" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:108 +msgid "" +"What happens if we try to use the normal <command role=\"hg-cmd\">hg update</" +"command> command to update to the new tip?" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:114 +msgid "" +"Mercurial is telling us that the <command role=\"hg-cmd\">hg update</command> " +"command won't do a merge; it won't update the working directory when it " +"thinks we might be wanting to do a merge, unless we force it to do so. " +"Instead, we use the <command role=\"hg-cmd\">hg merge</command> command to " +"merge the two heads." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch02-tour-merge.xml:125 +msgid "" +"<imageobject><imagedata fileref=\"images/tour-merge-merge.png\"/></" +"imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch02-tour-merge.xml:127 +msgid "Working directory and repository during merge, and following commit" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:132 +msgid "" +"This updates the working directory so that it contains changes from " +"<emphasis>both</emphasis> heads, which is reflected in both the output of " +"<command role=\"hg-cmd\">hg parents</command> and the contents of " +"<filename>hello.c</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch02-tour-merge.xml:142 +msgid "Committing the results of the merge" +msgstr "提交合并结果" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:144 +msgid "" +"Whenever we've done a merge, <command role=\"hg-cmd\">hg parents</command> " +"will display two parents until we <command role=\"hg-cmd\">hg commit</" +"command> the results of the merge." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:151 +msgid "" +"We now have a new tip revision; notice that it has <emphasis>both</emphasis> " +"of our former heads as its parents. These are the same revisions that were " +"previously displayed by <command role=\"hg-cmd\">hg parents</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:158 +msgid "" +"In figure <xref endterm=\"fig.tour-merge.merge.caption\" linkend=\"fig.tour-" +"merge.merge\"/>, you can see a representation of what happens to the working " +"directory during the merge, and how this affects the repository when the " +"commit happens. During the merge, the working directory has two parent " +"changesets, and these become the parents of the new changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch02-tour-merge.xml:169 +msgid "Merging conflicting changes" +msgstr "合并有冲突的改变" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:171 +msgid "" +"Most merges are simple affairs, but sometimes you'll find yourself merging " +"changes where each modifies the same portions of the same files. Unless both " +"modifications are identical, this results in a <emphasis>conflict</emphasis>, " +"where you have to decide how to reconcile the different changes into " +"something coherent." +msgstr "" + +#. type: Content of: <book><chapter><sect1><informalfigure><mediaobject> +#: ../en/ch02-tour-merge.xml:180 +msgid "" +"<imageobject><imagedata fileref=\"images/tour-merge-conflict.png\"/> </" +"imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><informalfigure><mediaobject><caption><para> +#: ../en/ch02-tour-merge.xml:183 +msgid "Conflicting changes to a document" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:188 +msgid "" +"Figure <xref endterm=\"fig.tour-merge.conflict.caption\" linkend=\"fig.tour-" +"merge.conflict\"/> illustrates an instance of two conflicting changes to a " +"document. We started with a single version of the file; then we made some " +"changes; while someone else made different changes to the same text. Our " +"task in resolving the conflicting changes is to decide what the file should " +"look like." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:196 +msgid "" +"Mercurial doesn't have a built-in facility for handling conflicts. Instead, " +"it runs an external program called <command>hgmerge</command>. This is a " +"shell script that is bundled with Mercurial; you can change it to behave " +"however you please. What it does by default is try to find one of several " +"different merging tools that are likely to be installed on your system. It " +"first tries a few fully automatic merging tools; if these don't succeed " +"(because the resolution process requires human guidance) or aren't present, " +"the script tries a few different graphical merging tools." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:207 +msgid "" +"It's also possible to get Mercurial to run another program or script instead " +"of <command>hgmerge</command>, by setting the <envar>HGMERGE</envar> " +"environment variable to the name of your preferred program." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch02-tour-merge.xml:213 +msgid "Using a graphical merge tool" +msgstr "使用图形合并工具" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:215 +msgid "" +"My preferred graphical merge tool is <command>kdiff3</command>, which I'll " +"use to describe the features that are common to graphical file merging " +"tools. You can see a screenshot of <command>kdiff3</command> in action in " +"figure <xref endterm=\"fig.tour-merge.kdiff3.caption\" linkend=\"fig.tour-" +"merge.kdiff3\"/>. The kind of merge it is performing is called a " +"<emphasis>three-way merge</emphasis>, because there are three different " +"versions of the file of interest to us. The tool thus splits the upper " +"portion of the window into three panes:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch02-tour-merge.xml:226 +msgid "" +"At the left is the <emphasis>base</emphasis> version of the file, i.e. the " +"most recent version from which the two versions we're trying to merge are " +"descended." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch02-tour-merge.xml:231 +msgid "" +"In the middle is <quote>our</quote> version of the file, with the contents " +"that we modified." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch02-tour-merge.xml:234 +msgid "" +"On the right is <quote>their</quote> version of the file, the one that from " +"the changeset that we're trying to merge with." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:238 +msgid "" +"In the pane below these is the current <emphasis>result</emphasis> of the " +"merge. Our task is to replace all of the red text, which indicates unresolved " +"conflicts, with some sensible merger of the <quote>ours</quote> and " +"<quote>theirs</quote> versions of the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:245 +msgid "" +"All four of these panes are <emphasis>locked together</emphasis>; if we " +"scroll vertically or horizontally in any of them, the others are updated to " +"display the corresponding sections of their respective files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch02-tour-merge.xml:252 +msgid "" +"<imageobject><imagedata width=\"100%\" fileref=\"images/kdiff3.png\"/> </" +"imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch02-tour-merge.xml:255 +msgid "Using <command>kdiff3</command> to merge versions of a file" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:261 +msgid "" +"For each conflicting portion of the file, we can choose to resolve the " +"conflict using some combination of text from the base version, ours, or " +"theirs. We can also manually edit the merged file at any time, in case we " +"need to make further modifications." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:267 +msgid "" +"There are <emphasis>many</emphasis> file merging tools available, too many to " +"cover here. They vary in which platforms they are available for, and in " +"their particular strengths and weaknesses. Most are tuned for merging files " +"containing plain text, while a few are aimed at specialised file formats " +"(generally XML)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch02-tour-merge.xml:276 +msgid "A worked example" +msgstr "合并实例" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:278 +msgid "" +"In this example, we will reproduce the file modification history of figure " +"<xref endterm=\"fig.tour-merge.conflict.caption\" linkend=\"fig.tour-merge." +"conflict\"/> above. Let's begin by creating a repository with a base version " +"of our document." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:286 +msgid "We'll clone the repository and make a change to the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:291 +msgid "" +"And another clone, to simulate someone else making a change to the file. " +"(This hints at the idea that it's not all that unusual to merge with yourself " +"when you isolate tasks in separate repositories, and indeed to find and " +"resolve conflicts while doing so.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:299 +msgid "" +"Having created two different versions of the file, we'll set up an " +"environment suitable for running our merge." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:305 +msgid "" +"In this example, I won't use Mercurial's normal <command>hgmerge</command> " +"program to do the merge, because it would drop my nice automated example-" +"running tool into a graphical user interface. Instead, I'll set " +"<envar>HGMERGE</envar> to tell Mercurial to use the non-interactive " +"<command>merge</command> command. This is bundled with many Unix-like " +"systems. If you're following this example on your computer, don't bother " +"setting <envar>HGMERGE</envar>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:315 +msgid "<emphasis role=\"bold\">XXX FIX THIS EXAMPLE.</emphasis>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:320 +msgid "" +"Because <command>merge</command> can't resolve the conflicting changes, it " +"leaves <emphasis>merge markers</emphasis> inside the file that has conflicts, " +"indicating which lines have conflicts, and whether they came from our version " +"of the file or theirs." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:326 +msgid "" +"Mercurial can tell from the way <command>merge</command> exits that it wasn't " +"able to merge successfully, so it tells us what commands we'll need to run if " +"we want to redo the merging operation. This could be useful if, for example, " +"we were running a graphical merge tool and quit because we were confused or " +"realised we had made a mistake." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch02-tour-merge.xml:333 +msgid "" +"If automatic or manual merges fail, there's nothing to prevent us from " +"<quote>fixing up</quote> the affected files ourselves, and committing the " +"results of our merge:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch02-tour-merge.xml:342 +msgid "Simplifying the pull-merge-commit sequence" +msgstr "简化拉-合并-提交程序" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:344 +msgid "" +"The process of merging changes as outlined above is straightforward, but " +"requires running three commands in sequence." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:350 +msgid "" +"In the case of the final commit, you also need to enter a commit message, " +"which is almost always going to be a piece of uninteresting " +"<quote>boilerplate</quote> text." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:354 +msgid "" +"It would be nice to reduce the number of steps needed, if this were " +"possible. Indeed, Mercurial is distributed with an extension called <literal " +"role=\"hg-ext\">fetch</literal> that does just this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:359 +msgid "" +"Mercurial provides a flexible extension mechanism that lets people extend its " +"functionality, while keeping the core of Mercurial small and easy to deal " +"with. Some extensions add new commands that you can use from the command " +"line, while others work <quote>behind the scenes,</quote> for example adding " +"capabilities to the server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:366 +msgid "" +"The <literal role=\"hg-ext\">fetch</literal> extension adds a new command " +"called, not surprisingly, <command role=\"hg-cmd\">hg fetch</command>. This " +"extension acts as a combination of <command role=\"hg-cmd\">hg pull</" +"command>, <command role=\"hg-cmd\">hg update</command> and <command role=\"hg-" +"cmd\">hg merge</command>. It begins by pulling changes from another " +"repository into the current repository. If it finds that the changes added a " +"new head to the repository, it begins a merge, then commits the result of the " +"merge with an automatically-generated commit message. If no new heads were " +"added, it updates the working directory to the new tip changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:379 +msgid "" +"Enabling the <literal role=\"hg-ext\">fetch</literal> extension is easy. " +"Edit your <filename role=\"special\">.hgrc</filename>, and either go to the " +"<literal role=\"rc-extensions\">extensions</literal> section or create an " +"<literal role=\"rc-extensions\">extensions</literal> section. Then add a line " +"that simply reads <quote><literal>fetch </literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch02-tour-merge.xml:388 +msgid "" +"(Normally, on the right-hand side of the <quote><literal>=</literal></quote> " +"would appear the location of the extension, but since the <literal role=\"hg-" +"ext\">fetch</literal> extension is in the standard distribution, Mercurial " +"knows where to search for it.)" +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch03-concepts.xml:5 +msgid "Behind the scenes" +msgstr "Mercurial 内幕" + +#. type: Content of: <book><chapter><para> +#: ../en/ch03-concepts.xml:7 +msgid "" +"Unlike many revision control systems, the concepts upon which Mercurial is " +"built are simple enough that it's easy to understand how the software really " +"works. Knowing this certainly isn't necessary, but I find it useful to have " +"a <quote>mental model</quote> of what's going on." +msgstr "" + +#. type: Content of: <book><chapter><para> +#: ../en/ch03-concepts.xml:13 +msgid "" +"This understanding gives me confidence that Mercurial has been carefully " +"designed to be both <emphasis>safe</emphasis> and <emphasis>efficient</" +"emphasis>. 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." +msgstr "" + +#. type: Content of: <book><chapter><para> +#: ../en/ch03-concepts.xml:20 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch03-concepts.xml:25 +msgid "Mercurial's historical record" +msgstr "Mercurial 的历史记录" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:28 +msgid "Tracking the history of a single file" +msgstr "跟踪单一文件的历史" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:30 +msgid "" +"When Mercurial tracks modifications to a file, it stores the history of that " +"file in a metadata object called a <emphasis>filelog</emphasis>. 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 <filename " +"role=\"special\" class=\"directory\">.hg/store/data</filename> directory. A " +"filelog contains two kinds of information: revision data, and an index to " +"help Mercurial to find a revision efficiently." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:41 +msgid "" +"A file that is large, or has a lot of history, has its filelog stored in " +"separate data (<quote><literal>.d</literal></quote> suffix) and index " +"(<quote><literal>.i</literal></quote> suffix) files. For small files without " +"much history, the revision data and index are combined in a single " +"<quote><literal>.i</literal></quote> file. The correspondence between a file " +"in the working directory and the filelog that tracks its history in the " +"repository is illustrated in figure <xref endterm=\"fig.concepts.filelog." +"caption\" linkend=\"fig.concepts.filelog\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch03-concepts.xml:55 +msgid "<imageobject><imagedata fileref=\"images/filelog.png\"/></imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch03-concepts.xml:57 +msgid "" +"Relationships between files in working directory and filelogs in repository" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:65 +msgid "Managing tracked files" +msgstr "管理跟踪的文件" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:67 +msgid "" +"Mercurial uses a structure called a <emphasis>manifest</emphasis> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:77 +msgid "Recording changeset information" +msgstr "记录修改集信息" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:79 +msgid "" +"The <emphasis>changelog</emphasis> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:87 +msgid "Relationships between revisions" +msgstr "版本之间的关系" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:89 +msgid "" +"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 " +"<emphasis>across</emphasis> these structures, and they are hierarchical in " +"nature." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:96 +msgid "" +"For every changeset in a repository, there is exactly one revision stored in " +"the changelog. Each revision of the changelog contains a pointer to a single " +"revision of the manifest. A revision of the manifest stores a pointer to a " +"single revision of each filelog tracked when that changeset was created. " +"These relationships are illustrated in figure <xref endterm=\"fig.concepts." +"metadata.caption\" linkend=\"fig.concepts.metadata\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch03-concepts.xml:107 +msgid "<imageobject><imagedata fileref=\"images/metadata.png\"/></imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch03-concepts.xml:109 +msgid "Metadata relationships" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:114 +msgid "" +"As the illustration shows, there is <emphasis>not</emphasis> a <quote>one to " +"one</quote> relationship between revisions in the changelog, manifest, or " +"filelog. If the manifest hasn't changed between two changesets, the changelog " +"entries for those changesets will point to the same revision of the " +"manifest. If a file that Mercurial tracks hasn't changed between two " +"changesets, the entry for that file in the two revisions of the manifest will " +"point to the same revision of its filelog." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch03-concepts.xml:127 +msgid "Safe, efficient storage" +msgstr "安全,高效的存储" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch03-concepts.xml:129 +msgid "" +"The underpinnings of changelogs, manifests, and filelogs are provided by a " +"single structure called the <emphasis>revlog</emphasis>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:134 +msgid "Efficient storage" +msgstr "高效存储" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:136 +msgid "" +"The revlog provides efficient storage of revisions using a <emphasis>delta</" +"emphasis> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:144 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:153 +msgid "Safe operation" +msgstr "安全操作" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:155 +msgid "" +"Mercurial only ever <emphasis>appends</emphasis> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:161 +msgid "" +"In addition, Mercurial treats every write as part of a <emphasis>transaction</" +"emphasis> that can span a number of files. A transaction is " +"<emphasis>atomic</emphasis>: 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:171 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:178 +msgid "Fast retrieval" +msgstr "快速检索" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:180 +msgid "" +"Mercurial cleverly avoids a pitfall common to all earlier revision control " +"systems: the problem of <emphasis>inefficient retrieval</emphasis>. Most " +"revision control systems store the contents of a revision as an incremental " +"series of modifications against a <quote>snapshot</quote>. To reconstruct a " +"specific revision, you must first read the snapshot, and then every one of " +"the revisions between the snapshot and your target revision. The more " +"history that a file accumulates, the more revisions you must read, hence the " +"longer it takes to reconstruct a particular revision." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch03-concepts.xml:193 +msgid "<imageobject><imagedata fileref=\"images/snapshot.png\"/></imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch03-concepts.xml:195 +msgid "Snapshot of a revlog, with incremental deltas" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:200 +msgid "" +"The innovation that Mercurial applies to this problem is simple but " +"effective. Once the cumulative amount of delta information stored since the " +"last snapshot exceeds a fixed threshold, it stores a new snapshot " +"(compressed, of course), instead of another delta. This makes it possible to " +"reconstruct <emphasis>any</emphasis> revision of a file quickly. This " +"approach works so well that it has since been copied by several other " +"revision control systems." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:209 +msgid "" +"Figure <xref endterm=\"fig.concepts.snapshot.caption\" linkend=\"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch03-concepts.xml:216 +msgid "Aside: the influence of video compression" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch03-concepts.xml:218 +msgid "" +"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 <quote>lossy</quote> " +"compression techniques to increase the compression ratio, so visual errors " +"accumulate over the course of a number of inter-frame deltas." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch03-concepts.xml:227 +msgid "" +"Because it's possible for a video stream to <quote>drop out</quote> " +"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 <quote>key frame</quote>) 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:241 +msgid "Identification and strong integrity" +msgstr "鉴别和强完整性" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:243 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:248 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:255 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:260 +msgid "" +"In addition to the effect it has on retrieval efficiency, Mercurial's use of " +"periodic snapshots makes it more robust against partial data corruption. If " +"a revlog becomes partly corrupted due to a hardware error or system bug, it's " +"often possible to reconstruct some or most revisions from the uncorrupted " +"sections of the revlog, both before and after the corrupted section. This " +"would not be possible with a delta-only storage model." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch03-concepts.xml:272 +msgid "Revision history, branching, and merging" +msgstr "修订历史,分支与合并" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch03-concepts.xml:274 +msgid "" +"Every entry in a Mercurial revlog knows the identity of its immediate " +"ancestor revision, usually referred to as its <emphasis>parent</emphasis>. " +"In fact, a revision contains room for not one parent, but two. Mercurial " +"uses a special hash, called the <quote>null ID</quote>, to represent the idea " +"<quote>there is no parent here</quote>. This hash is simply a string of " +"zeroes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch03-concepts.xml:282 +msgid "" +"In figure <xref endterm=\"fig.concepts.revlog.caption\" linkend=\"fig." +"concepts.revlog\"/>, you can see an example of the conceptual structure of a " +"revlog. Filelogs, manifests, and changelogs all have this same structure; " +"they differ only in the kind of data stored in each delta or snapshot." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch03-concepts.xml:289 +msgid "" +"The first revision in a revlog (at the bottom of the image) has the null ID " +"in both of its parent slots. For a <quote>normal</quote> revision, its first " +"parent slot contains the ID of its parent revision, and its second contains " +"the null ID, indicating that the revision has only one real parent. Any two " +"revisions that have the same parent ID are branches. A revision that " +"represents a merge between branches has two normal revision IDs in its parent " +"slots." +msgstr "" + +#. type: Content of: <book><chapter><sect1><informalfigure><mediaobject> +#: ../en/ch03-concepts.xml:300 +msgid "<imageobject><imagedata fileref=\"images/revlog.png\"/></imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><informalfigure><mediaobject><caption><para> +#: ../en/ch03-concepts.xml:302 +msgid "Revision in revlog" +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch03-concepts.xml:309 +msgid "The working directory" +msgstr "工作目录" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch03-concepts.xml:311 +msgid "" +"In the working directory, Mercurial stores a snapshot of the files from the " +"repository as of a particular changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch03-concepts.xml:314 +msgid "" +"The working directory <quote>knows</quote> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch03-concepts.xml:323 +msgid "" +"The <emphasis>dirstate</emphasis> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch03-concepts.xml:329 +msgid "" +"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 " +"<command role=\"hg-cmd\">hg update</command> command, the changeset that you " +"update to is stored in the <quote>first parent</quote> slot, and the null ID " +"in the second. When you <command role=\"hg-cmd\">hg merge</command> with " +"another changeset, the first parent remains unchanged, and the second parent " +"is filled in with the changeset you're merging with. The <command role=\"hg-" +"cmd\">hg parents</command> command tells you what the parents of the dirstate " +"are." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:343 +msgid "What happens when you commit" +msgstr "当你提交时发生的事情" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:345 +msgid "" +"The dirstate stores parent information for more than just book-keeping " +"purposes. Mercurial uses the parents of the dirstate as <emphasis>the " +"parents of a new changeset</emphasis> when you perform a commit." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch03-concepts.xml:352 +msgid "<imageobject><imagedata fileref=\"images/wdir.png\"/></imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch03-concepts.xml:354 +msgid "The working directory can have two parents" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:359 +msgid "" +"Figure <xref endterm=\"fig.concepts.wdir.caption\" linkend=\"fig.concepts.wdir" +"\"/> shows the normal state of the working directory, where it has a single " +"changeset as parent. That changeset is the <emphasis>tip</emphasis>, the " +"newest changeset in the repository that has no children." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch03-concepts.xml:368 +msgid "" +"<imageobject><imagedata fileref=\"images/wdir-after-commit.png\"/> </" +"imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch03-concepts.xml:371 +msgid "The working directory gains new parents after a commit" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:376 +msgid "" +"It's useful to think of the working directory as <quote>the changeset I'm " +"about to commit</quote>. 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:384 +msgid "" +"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 <xref endterm=\"fig.concepts.wdir-after-" +"commit.caption\" linkend=\"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:396 +msgid "Creating a new head" +msgstr "创建新顶点" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:398 +msgid "" +"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 <xref endterm=\"fig.concepts.wdir-pre-branch.caption\" linkend=\"fig." +"concepts.wdir-pre-branch\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch03-concepts.xml:412 +msgid "" +"<imageobject><imagedata fileref=\"images/wdir-pre-branch.png\"/> </" +"imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch03-concepts.xml:415 +msgid "The working directory, updated to an older changeset" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:420 +msgid "" +"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 <emphasis>heads</emphasis>. You can see the structure that " +"this creates in figure <xref endterm=\"fig.concepts.wdir-branch.caption\" " +"linkend=\"fig.concepts.wdir-branch\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch03-concepts.xml:434 +msgid "" +"<imageobject><imagedata fileref=\"images/wdir-branch.png\"/> </imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch03-concepts.xml:437 +msgid "After a commit made while synced to an older changeset" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch03-concepts.xml:443 +msgid "" +"If you're new to Mercurial, you should keep in mind a common <quote>error</" +"quote>, which is to use the <command role=\"hg-cmd\">hg pull</command> " +"command without any options. By default, the <command role=\"hg-cmd\">hg " +"pull</command> command <emphasis>does not</emphasis> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch03-concepts.xml:455 +msgid "" +"I put the word <quote>error</quote> in quotes because all that you need to do " +"to rectify this situation is <command role=\"hg-cmd\">hg merge</command>, " +"then <command role=\"hg-cmd\">hg commit</command>. In other words, this " +"almost never has negative consequences; it just surprises people. I'll " +"discuss other ways to avoid this behaviour, and why Mercurial behaves in this " +"initially surprising way, later on." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:467 +msgid "Merging heads" +msgstr "合并顶点" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:469 +msgid "" +"When you run the <command role=\"hg-cmd\">hg merge</command> command, " +"Mercurial leaves the first parent of the working directory unchanged, and " +"sets the second parent to the changeset you're merging with, as shown in " +"figure <xref endterm=\"fig.concepts.wdir-merge.caption\" linkend=\"fig." +"concepts.wdir-merge\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch03-concepts.xml:478 +msgid "" +"<imageobject><imagedata fileref=\"images/wdir-merge.png\"/> </imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch03-concepts.xml:481 +msgid "Merging two heads" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:486 +msgid "" +"Mercurial also has to modify the working directory, to merge the files " +"managed in the two changesets. Simplified a little, the merging process goes " +"like this, for every file in the manifests of both changesets." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch03-concepts.xml:491 +msgid "If neither changeset has modified a file, do nothing with that file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch03-concepts.xml:494 +msgid "" +"If one changeset has modified a file, and the other hasn't, create the " +"modified copy of the file in the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch03-concepts.xml:498 +msgid "" +"If one changeset has removed a file, and the other hasn't (or has also " +"deleted it), delete the file from the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch03-concepts.xml:502 +msgid "" +"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?" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch03-concepts.xml:506 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch03-concepts.xml:511 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:515 +msgid "" +"There are more details&emdash;merging has plenty of corner cases&emdash;but " +"these are the most common choices that are involved in a merge. As you can " +"see, most cases are completely automatic, and indeed most merges finish " +"automatically, without requiring your input to resolve any conflicts." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:522 +msgid "" +"When you're thinking about what happens when you commit after a merge, once " +"again the working directory is <quote>the changeset I'm about to commit</" +"quote>. After the <command role=\"hg-cmd\">hg merge</command> command " +"completes, the working directory has two parents; these will become the " +"parents of the new changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:529 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch03-concepts.xml:540 +msgid "Other interesting design features" +msgstr "其它有趣的设计特性" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch03-concepts.xml:542 +msgid "" +"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 <quote>big ticket</quote> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:553 +msgid "Clever compression" +msgstr "智能压缩" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:555 +msgid "" +"When appropriate, Mercurial will store both snapshots and deltas in " +"compressed form. It does this by always <emphasis>trying to</emphasis> " +"compress a snapshot or delta, but only storing the compressed version if it's " +"smaller than the uncompressed version." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:561 +msgid "" +"This means that Mercurial does <quote>the right thing</quote> when storing a " +"file whose native form is compressed, such as a <literal>zip</literal> " +"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 <literal>zip</literal> or JPEG." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:569 +msgid "" +"Deltas between revisions of a compressed file are usually larger than " +"snapshots of the file, and Mercurial again does <quote>the right thing</" +"quote> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch03-concepts.xml:578 +msgid "Network recompression" +msgstr "网络重新压缩" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch03-concepts.xml:580 +msgid "" +"When storing revisions on disk, Mercurial uses the <quote>deflate</quote> " +"compression algorithm (the same one used by the popular <literal>zip</" +"literal> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch03-concepts.xml:588 +msgid "" +"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 <literal>bzip2</literal> " +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch03-concepts.xml:598 +msgid "" +"(If the connection is over <command>ssh</command>, Mercurial " +"<emphasis>doesn't</emphasis> recompress the stream, because <command>ssh</" +"command> can already do this itself.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:606 +msgid "Read/write ordering and atomicity" +msgstr "读写顺序与原子性" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:608 +msgid "" +"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 <xref endterm=\"fig." +"concepts.metadata.caption\" linkend=\"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:616 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:621 +msgid "" +"Since the writer has always finished writing filelog and manifest data before " +"it writes to the changelog, a reader will never read a pointer to a partially " +"written manifest revision from the changelog, and it will never read a " +"pointer to a partially written filelog revision from the manifest." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:629 +msgid "Concurrent access" +msgstr "并发访问" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:631 +msgid "" +"The read/write ordering and atomicity guarantees mean that Mercurial never " +"needs to <emphasis>lock</emphasis> a repository when it's reading data, even " +"if the repository is being written to while the read is occurring. This has a " +"big effect on scalability; you can have an arbitrary number of Mercurial " +"processes safely reading data from a repository safely all at once, no matter " +"whether it's being written to or not." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:640 +msgid "" +"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 " +"<emphasis>write</emphasis> to your repository in order for them to be able to " +"clone it or pull changes from it; they only need <emphasis>read</emphasis> " +"permission. (This is <emphasis>not</emphasis> 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.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:653 +msgid "" +"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.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch03-concepts.xml:665 +msgid "Safe dirstate access" +msgstr "安全的目录状态访问" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch03-concepts.xml:667 +msgid "" +"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</filename>. The " +"file named <filename>dirstate</filename> is thus guaranteed to be complete, " +"not partially written." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:680 +msgid "Avoiding seeks" +msgstr "避免查找" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:682 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:686 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:692 +msgid "" +"Mercurial also uses a <quote>copy on write</quote> scheme when cloning a " +"repository on local storage. Instead of copying every revlog file from the " +"old repository into the new repository, it makes a <quote>hard link</quote>, " +"which is a shorthand way to say <quote>these two names point to the same " +"file</quote>. When Mercurial is about to write to one of a revlog's files, " +"it checks to see if the number of names pointing at the file is greater than " +"one. If it is, more than one repository is using the file, so Mercurial " +"makes a new copy of the file that is private to this repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:703 +msgid "" +"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 " +"<quote>feel</quote> of day-to-day use." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch03-concepts.xml:715 +msgid "Other contents of the dirstate" +msgstr "目录状态的其它内容" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:717 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:724 +msgid "" +"When you explicitly <command role=\"hg-cmd\">hg add</command>, <command role=" +"\"hg-cmd\">hg remove</command>, <command role=\"hg-cmd\">hg rename</command> " +"or <command role=\"hg-cmd\">hg copy</command> files, Mercurial updates the " +"dirstate so that it knows what to do with those files when you commit." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch03-concepts.xml:731 +msgid "" +"When Mercurial is checking the states of files in the working directory, it " +"first checks a file's modification time. If that has not changed, the file " +"must not have been modified. If the file's size has changed, the file must " +"have been modified. If the modification time has changed, but the size has " +"not, only then does Mercurial need to read the actual contents of the file to " +"see if they've changed. Storing these few extra pieces of information " +"dramatically reduces the amount of data that Mercurial needs to read, which " +"yields large performance improvements compared to other revision control " +"systems." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch04-daily.xml:5 +msgid "Mercurial in daily use" +msgstr "Mercurial 的日常使用" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch04-daily.xml:8 +msgid "Telling Mercurial which files to track" +msgstr "告诉 Mercurial 要跟踪哪些文件" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:10 +msgid "" +"Mercurial does not work with files in your repository unless you tell it to " +"manage them. The <command role=\"hg-cmd\">hg status</command> command will " +"tell you which files Mercurial doesn't know about; it uses a <quote><literal>?" +"</literal></quote> to display such files." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:17 +msgid "" +"To tell Mercurial to track a file, use the <command role=\"hg-cmd\">hg add</" +"command> command. Once you have added a file, the entry in the output of " +"<command role=\"hg-cmd\">hg status</command> for that file changes from " +"<quote><literal>?</literal></quote> to <quote><literal>A</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:26 +msgid "" +"After you run a <command role=\"hg-cmd\">hg commit</command>, the files that " +"you added before the commit will no longer be listed in the output of " +"<command role=\"hg-cmd\">hg status</command>. The reason for this is that " +"<command role=\"hg-cmd\">hg status</command> only tells you about " +"<quote>interesting</quote> files&emdash;those that you have modified or told " +"Mercurial to do something with&emdash;by default. If you have a repository " +"that contains thousands of files, you will rarely want to know about files " +"that Mercurial is tracking, but that have not changed. (You can still get " +"this information; we'll return to this later.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:38 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:45 +msgid "Explicit versus implicit file naming" +msgstr "明确与隐含文件命名" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:47 +msgid "" +"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 <quote>I " +"want to operate on every file in this directory and its subdirectories</" +"quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:54 +msgid "" +"Notice in this example that Mercurial printed the names of the files it " +"added, whereas it didn't do so when we added the file named <filename>a</" +"filename> in the earlier example." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:59 +msgid "" +"What's going on is that in the former case, we explicitly named the file to " +"add on the command line, so the assumption that Mercurial makes in such cases " +"is that you know what you were doing, and it doesn't print any output." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:64 +msgid "" +"However, when we <emphasis>imply</emphasis> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:73 +msgid "Aside: Mercurial tracks files, not directories" +msgstr "旁白: Mercurial 只跟踪文件,不跟踪目录" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:75 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:84 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:91 +msgid "" +"If you need an empty directory in your repository, there are a few ways to " +"achieve this. One is to create a directory, then <command role=\"hg-cmd\">hg " +"add</command> a <quote>hidden</quote> file to that directory. On Unix-like " +"systems, any file name that begins with a period (<quote><literal>.</" +"literal></quote>) is treated as hidden by most commands and GUI tools. This " +"approach is illustrated below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:102 +msgid "" +"Another way to tackle a need for an empty directory is to simply create one " +"in your automated build scripts before they will need it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch04-daily.xml:109 +msgid "How to stop tracking a file" +msgstr "如何停止跟踪文件" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:111 +msgid "" +"Once you decide that a file no longer belongs in your repository, use the " +"<command role=\"hg-cmd\">hg remove</command> command; this deletes the file, " +"and tells Mercurial to stop tracking it. A removed file is represented in " +"the output of <command role=\"hg-cmd\">hg status</command> with a " +"<quote><literal>R</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:120 +msgid "" +"After you <command role=\"hg-cmd\">hg remove</command> a file, Mercurial will " +"no longer track changes to that file, even if you recreate a file with the " +"same name in your working directory. If you do recreate a file with the same " +"name and want Mercurial to track the new file, simply <command role=\"hg-cmd" +"\">hg add</command> it. Mercurial will know that the newly added file is not " +"related to the old file of the same name." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:129 +msgid "Removing a file does not affect its history" +msgstr "删除文件不影响历史" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:131 +msgid "It is important to understand that removing a file has only two effects." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch04-daily.xml:134 +msgid "It removes the current version of the file from the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch04-daily.xml:137 +msgid "" +"It stops Mercurial from tracking changes to the file, from the time of the " +"next commit." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:140 +msgid "" +"Removing a file <emphasis>does not</emphasis> in any way alter the " +"<emphasis>history</emphasis> of the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:143 +msgid "" +"If you update the working directory to a changeset in which a file that you " +"have removed was still tracked, it will reappear in the working directory, " +"with the contents it had when you committed that changeset. If you then " +"update the working directory to a later changeset, in which the file had been " +"removed, Mercurial will once again remove the file from the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:153 +msgid "Missing files" +msgstr "丢失的文件" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:155 +msgid "" +"Mercurial considers a file that you have deleted, but not used <command role=" +"\"hg-cmd\">hg remove</command> to delete, to be <emphasis>missing</" +"emphasis>. A missing file is represented with <quote><literal>!</literal></" +"quote> in the output of <command role=\"hg-cmd\">hg status</command>. " +"Mercurial commands will not generally do anything with missing files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:165 +msgid "" +"If your repository contains a file that <command role=\"hg-cmd\">hg status</" +"command> reports as missing, and you want the file to stay gone, you can run " +"<command role=\"hg-cmd\">hg remove <option role=\"hg-opt-remove\">--after</" +"option></command> at any time later on, to tell Mercurial that you really did " +"mean to remove the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:175 +msgid "" +"On the other hand, if you deleted the missing file by accident, give <command " +"role=\"hg-cmd\">hg revert</command> the name of the file to recover. It will " +"reappear, in unmodified form." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:184 +msgid "Aside: why tell Mercurial explicitly to remove a file?" +msgstr "旁白: 为什么要明确告诉 Mercurial 删除文件?" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:187 +msgid "" +"You might wonder why Mercurial requires you to explicitly tell it that you " +"are deleting a file. Early during the development of Mercurial, it let you " +"delete a file however you pleased; Mercurial would notice the absence of the " +"file automatically when you next ran a <command role=\"hg-cmd\">hg commit</" +"command>, and stop tracking the file. In practice, this made it too easy to " +"accidentally remove a file without noticing." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:198 +msgid "Useful shorthand&emdash;adding and removing files in one step" +msgstr "有用的速记&emdash;一个步骤添加和删除文件" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:201 +msgid "" +"Mercurial offers a combination command, <command role=\"hg-cmd\">hg " +"addremove</command>, that adds untracked files and marks missing files as " +"removed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:207 +msgid "" +"The <command role=\"hg-cmd\">hg commit</command> command also provides a " +"<option role=\"hg-opt-commit\">-A</option> option that performs this same add-" +"and-remove, immediately followed by a commit." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch04-daily.xml:217 +msgid "Copying files" +msgstr "复制文件" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:219 +msgid "" +"Mercurial provides a <command role=\"hg-cmd\">hg copy</command> command that " +"lets you make a new copy of a file. When you copy a file using this command, " +"Mercurial makes a record of the fact that the new file is a copy of the " +"original file. It treats these copied files specially when you merge your " +"work with someone else's." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:227 +msgid "The results of copying during a merge" +msgstr "合并期间的复制结果" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:229 +msgid "" +"What happens during a merge is that changes <quote>follow</quote> a copy. To " +"best illustrate what this means, let's create an example. We'll start with " +"the usual tiny repository that contains a single file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:236 +msgid "" +"We need to do some work in parallel, so that we'll have something to merge. " +"So let's clone our repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:242 +msgid "" +"Back in our initial repository, let's use the <command role=\"hg-cmd\">hg " +"copy</command> command to make a copy of the first file we created." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:248 +msgid "" +"If we look at the output of the <command role=\"hg-cmd\">hg status</command> " +"command afterwards, the copied file looks just like a normal added file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:254 +msgid "" +"But if we pass the <option role=\"hg-opt-status\">-C</option> option to " +"<command role=\"hg-cmd\">hg status</command>, it prints another line of " +"output: this is the file that our newly-added file was copied <emphasis>from</" +"emphasis>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:262 +msgid "" +"Now, back in the repository we cloned, let's make a change in parallel. " +"We'll add a line of content to the original file that we created." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:268 +msgid "" +"Now we have a modified <filename>file</filename> in this repository. When we " +"pull the changes from the first repository, and merge the two heads, " +"Mercurial will propagate the changes that we made locally to <filename>file</" +"filename> into its copy, <filename>new-file</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:278 +msgid "Why should changes follow copies?" +msgstr "为什么复制后需要后续修改?" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:280 +msgid "" +"This behaviour, of changes to a file propagating out to copies of the file, " +"might seem esoteric, but in most cases it's highly desirable." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:284 +msgid "" +"First of all, remember that this propagation <emphasis>only</emphasis> " +"happens when you merge. So if you <command role=\"hg-cmd\">hg copy</command> " +"a file, and subsequently modify the original file during the normal course of " +"your work, nothing will happen." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:290 +msgid "" +"The second thing to know is that modifications will only propagate across a " +"copy as long as the repository that you're pulling changes from " +"<emphasis>doesn't know</emphasis> about the copy." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:295 +msgid "" +"The reason that Mercurial does this is as follows. Let's say I make an " +"important bug fix in a source file, and commit my changes. Meanwhile, you've " +"decided to <command role=\"hg-cmd\">hg copy</command> the file in your " +"repository, without knowing about the bug or having seen the fix, and you " +"have started hacking on your copy of the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:302 +msgid "" +"If you pulled and merged my changes, and Mercurial <emphasis>didn't</" +"emphasis> propagate changes across copies, your source file would now contain " +"the bug, and unless you remembered to propagate the bug fix by hand, the bug " +"would <emphasis>remain</emphasis> in your copy of the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:308 +msgid "" +"By automatically propagating the change that fixed the bug from the original " +"file to the copy, Mercurial prevents this class of problem. To my knowledge, " +"Mercurial is the <emphasis>only</emphasis> revision control system that " +"propagates changes across copies like this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:314 +msgid "" +"Once your change history has a record that the copy and subsequent merge " +"occurred, there's usually no further need to propagate changes from the " +"original file to the copied file, and that's why Mercurial only propagates " +"changes across copies until this point, and no further." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:322 +msgid "How to make changes <emphasis>not</emphasis> follow a copy" +msgstr "如何让复制后<emphasis>不</emphasis>修改?" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:325 +msgid "" +"If, for some reason, you decide that this business of automatically " +"propagating changes across copies is not for you, simply use your system's " +"normal file copy command (on Unix-like systems, that's <command>cp</command>) " +"to make a copy of a file, then <command role=\"hg-cmd\">hg add</command> the " +"new copy by hand. Before you do so, though, please do reread section <xref " +"linkend=\"sec.daily.why-copy\"/>, and make an informed decision that this " +"behaviour is not appropriate to your specific case." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:338 +msgid "Behaviour of the <command role=\"hg-cmd\">hg copy</command> command" +msgstr "命令 <command role=\"hg-cmd\">hg copy</command> 的特性" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:341 +msgid "" +"When you use the <command role=\"hg-cmd\">hg copy</command> command, " +"Mercurial makes a copy of each source file as it currently stands in the " +"working directory. This means that if you make some modifications to a file, " +"then <command role=\"hg-cmd\">hg copy</command> it without first having " +"committed those changes, the new copy will also contain the modifications you " +"have made up until that point. (I find this behaviour a little " +"counterintuitive, which is why I mention it here.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:351 +msgid "" +"The <command role=\"hg-cmd\">hg copy</command> command acts similarly to the " +"Unix <command>cp</command> command (you can use the <command role=\"hg-cmd" +"\">hg cp</command> alias if you prefer). The last argument is the " +"<emphasis>destination</emphasis>, and all prior arguments are " +"<emphasis>sources</emphasis>. If you pass it a single file as the source, " +"and the destination does not exist, it creates a new file with that name." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:362 +msgid "" +"If the destination is a directory, Mercurial copies its sources into that " +"directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:367 +msgid "" +"Copying a directory is recursive, and preserves the directory structure of " +"the source." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:373 +msgid "" +"If the source and destination are both directories, the source tree is " +"recreated in the destination directory." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:378 +msgid "" +"As with the <command role=\"hg-cmd\">hg rename</command> command, if you copy " +"a file manually and then want Mercurial to know that you've copied the file, " +"simply use the <option role=\"hg-opt-copy\">--after</option> option to " +"<command role=\"hg-cmd\">hg copy</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch04-daily.xml:389 +msgid "Renaming files" +msgstr "改名文件" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:391 +msgid "" +"It's rather more common to need to rename a file than to make a copy of it. " +"The reason I discussed the <command role=\"hg-cmd\">hg copy</command> command " +"before talking about renaming files is that Mercurial treats a rename in " +"essentially the same way as a copy. Therefore, knowing what Mercurial does " +"when you copy a file tells you what to expect when you rename a file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:399 +msgid "" +"When you use the <command role=\"hg-cmd\">hg rename</command> command, " +"Mercurial makes a copy of each source file, then deletes it and marks the " +"file as removed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:405 +msgid "" +"The <command role=\"hg-cmd\">hg status</command> command shows the newly " +"copied file as added, and the copied-from file as removed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:411 +msgid "" +"As with the results of a <command role=\"hg-cmd\">hg copy</command>, we must " +"use the <option role=\"hg-opt-status\">-C</option> option to <command role=" +"\"hg-cmd\">hg status</command> to see that the added file is really being " +"tracked by Mercurial as a copy of the original, now removed, file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:420 +msgid "" +"As with <command role=\"hg-cmd\">hg remove</command> and <command role=\"hg-" +"cmd\">hg copy</command>, you can tell Mercurial about a rename after the fact " +"using the <option role=\"hg-opt-rename\">--after</option> option. In most " +"other respects, the behaviour of the <command role=\"hg-cmd\">hg rename</" +"command> command, and the options it accepts, are similar to the <command " +"role=\"hg-cmd\">hg copy</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:430 +msgid "Renaming files and merging changes" +msgstr "改名文件与合并修改" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:432 +msgid "" +"Since Mercurial's rename is implemented as copy-and-remove, the same " +"propagation of changes happens when you merge after a rename as after a copy." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:436 +msgid "" +"If I modify a file, and you rename it to a new name, and then we merge our " +"respective changes, my modifications to the file under its original name will " +"be propagated into the file under its new name. (This is something you might " +"expect to <quote>simply work,</quote> but not all revision control systems " +"actually do this.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:443 +msgid "" +"Whereas having changes follow a copy is a feature where you can perhaps nod " +"and say <quote>yes, that might be useful,</quote> it should be clear that " +"having them follow a rename is definitely important. Without this facility, " +"it would simply be too easy for changes to become orphaned when files are " +"renamed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:452 +msgid "Divergent renames and merging" +msgstr "改名与合并的分歧" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:454 +msgid "" +"The case of diverging names occurs when two developers start with a " +"file&emdash;let's call it <filename>foo</filename>&emdash;in their respective " +"repositories." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:461 +msgid "Anne renames the file to <filename>bar</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:465 +msgid "Meanwhile, Bob renames it to <filename>quux</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:470 +msgid "" +"I like to think of this as a conflict because each developer has expressed " +"different intentions about what the file ought to be named." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:474 +msgid "" +"What do you think should happen when they merge their work? Mercurial's " +"actual behaviour is that it always preserves <emphasis>both</emphasis> names " +"when it merges changesets that contain divergent renames." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:481 +msgid "" +"Notice that Mercurial does warn about the divergent renames, but it leaves it " +"up to you to do something about the divergence after the merge." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:487 +msgid "Convergent renames and merging" +msgstr "收敛改名与合并" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:489 +msgid "" +"Another kind of rename conflict occurs when two people choose to rename " +"different <emphasis>source</emphasis> files to the same " +"<emphasis>destination</emphasis>. In this case, Mercurial runs its normal " +"merge machinery, and lets you guide it to a suitable resolution." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch04-daily.xml:497 +msgid "Other name-related corner cases" +msgstr "其它名称相关的角落" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch04-daily.xml:499 +msgid "" +"Mercurial has a longstanding bug in which it fails to handle a merge where " +"one side has a file with a given name, while another has a directory with the " +"same name. This is documented as <ulink role=\"hg-bug\" url=\"http://www." +"selenic.com/mercurial/bts/issue29\">issue 29</ulink>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch04-daily.xml:511 +msgid "Recovering from mistakes" +msgstr "从错误恢复" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:513 +msgid "" +"Mercurial has some useful commands that will help you to recover from some " +"common mistakes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:516 +msgid "" +"The <command role=\"hg-cmd\">hg revert</command> command lets you undo " +"changes that you have made to your working directory. For example, if you " +"<command role=\"hg-cmd\">hg add</command> a file by accident, just run " +"<command role=\"hg-cmd\">hg revert</command> with the name of the file you " +"added, and while the file won't be touched in any way, it won't be tracked " +"for adding by Mercurial any longer, either. You can also use <command role=" +"\"hg-cmd\">hg revert</command> to get rid of erroneous changes to a file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:526 +msgid "" +"It's useful to remember that the <command role=\"hg-cmd\">hg revert</command> " +"command is useful for changes that you have not yet committed. Once you've " +"committed a change, if you decide it was a mistake, you can still do " +"something about it, though your options may be more limited." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch04-daily.xml:532 +msgid "" +"For more information about the <command role=\"hg-cmd\">hg revert</command> " +"command, and details about how to deal with changes you have already " +"committed, see chapter <xref linkend=\"chap.undo\"/>." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch05-collab.xml:5 +msgid "Collaborating with other people" +msgstr "团体协作" + +#. type: Content of: <book><chapter><para> +#: ../en/ch05-collab.xml:7 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch05-collab.xml:14 +msgid "Mercurial's web interface" +msgstr "Mercurial 的 web 接口" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:16 +msgid "" +"Mercurial has a powerful web interface that provides several useful " +"capabilities." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:19 +msgid "" +"For interactive use, the web interface lets you browse a single repository or " +"a collection of repositories. You can view the history of a repository, " +"examine each change (comments and diffs), and view the contents of each " +"directory and file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:24 +msgid "" +"Also for human consumption, the web interface provides an RSS feed of the " +"changes in a repository. This lets you <quote>subscribe</quote> to a " +"repository using your favourite feed reader, and be automatically notified of " +"activity in that repository as soon as it happens. I find this capability " +"much more convenient than the model of subscribing to a mailing list to which " +"notifications are sent, as it requires no additional configuration on the " +"part of whoever is serving the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:34 +msgid "" +"The web interface also lets remote users clone a repository, pull changes " +"from it, and (when the server is configured to permit it) push changes back " +"to it. Mercurial's HTTP tunneling protocol aggressively compresses data, so " +"that it works efficiently even over low-bandwidth network connections." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:40 +msgid "" +"The easiest way to get started with the web interface is to use your web " +"browser to visit an existing repository, such as the master Mercurial " +"repository at <ulink url=\"http://www.selenic.com/repo/hg?style=gitweb" +"\">http://www.selenic.com/repo/hg?style=gitweb</ulink>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:45 +msgid "" +"If you're interested in providing a web interface to your own repositories, " +"Mercurial provides two ways to do this. The first is using the <command role=" +"\"hg-cmd\">hg serve</command> command, which is best suited to short-term " +"<quote>lightweight</quote> serving. See section <xref linkend=\"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 <xref linkend=\"sec.collab.cgi\"/> " +"for details of CGI configuration." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch05-collab.xml:60 +msgid "Collaboration models" +msgstr "协作模型" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:62 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:70 +msgid "Factors to keep in mind" +msgstr "要牢记的因素" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:72 +msgid "" +"The most important aspect of any model that you must keep in mind is how well " +"it matches the needs and capabilities of the people who will be using it. " +"This might seem self-evident; even so, you still can't afford to forget it " +"for a moment." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:78 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:88 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:102 +msgid "Informal anarchy" +msgstr "无政府状态" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:104 +msgid "" +"I wouldn't suggest an <quote>anything goes</quote> approach as something " +"sustainable, but it's a model that's easy to grasp, and it works perfectly " +"well in a few unusual situations." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:109 +msgid "" +"As one example, many projects have a loose-knit group of collaborators who " +"rarely physically meet each other. Some groups like to overcome the " +"isolation of working at a distance by organising occasional <quote>sprints</" +"quote>. 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:118 +msgid "" +"A sprint is the perfect place to use the <command role=\"hg-cmd\">hg serve</" +"command> command, since <command role=\"hg-cmd\">hg serve</command> does not " +"require any fancy server infrastructure. You can get started with <command " +"role=\"hg-cmd\">hg serve</command> in moments, by reading section <xref " +"linkend=\"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:132 +msgid "" +"The charm, and the problem, with doing things in an ad hoc fashion like this " +"is that only people who know about your changes, and where they are, can see " +"them. Such an informal approach simply doesn't scale beyond a handful " +"people, because each individual needs to know about $n$ different " +"repositories to pull from." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:141 +msgid "A single central repository" +msgstr "单一中央版本库" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:143 +msgid "" +"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 " +"<quote>building block</quote> for more ambitious workflow schemes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:149 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:154 +msgid "" +"Under this model, it can still often make sense for people to pull changes " +"directly from each other, without going through the central repository. " +"Consider a case in which I have a tentative bug fix, but I am worried that if " +"I were to publish it to the central repository, it might subsequently break " +"everyone else's trees as they pull it. To reduce the potential for damage, I " +"can ask you to clone my repository into a temporary repository of your own " +"and test it. This lets us put off publishing the potentially unsafe change " +"until it has had a little testing." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:165 +msgid "" +"In this kind of scenario, people usually use the <command>ssh</command> " +"protocol to securely push changes to the central repository, as documented in " +"section <xref linkend=\"sec.collab.ssh\"/>. It's also usual to publish a " +"read-only copy of the repository over HTTP using CGI, as in section <xref " +"linkend=\"sec.collab.cgi\"/>. Publishing over HTTP satisfies the needs of " +"people who don't have push access, and those who want to use web browsers to " +"browse the repository's history." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:178 +msgid "Working with multiple branches" +msgstr "使用多个分支工作" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:180 +msgid "" +"Projects of any significant size naturally tend to make progress on several " +"fronts simultaneously. In the case of software, it's common for a project to " +"go through periodic official releases. A release might then go into " +"<quote>maintenance mode</quote> for a while after its first publication; " +"maintenance releases tend to contain only bug fixes, not new features. In " +"parallel with these maintenance releases, one or more future releases may be " +"under development. People normally use the word <quote>branch</quote> to " +"refer to one of these many slightly different directions in which development " +"is proceeding." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:193 +msgid "" +"Mercurial is particularly well suited to managing a number of simultaneous, " +"but not identical, branches. Each <quote>development direction</quote> can " +"live in its own central repository, and you can merge changes from one to " +"another as the need arises. Because repositories are independent of each " +"other, unstable changes in a development branch will never affect a stable " +"branch unless someone explicitly merges those changes in." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:202 +msgid "" +"Here's an example of how this can work in practice. Let's say you have one " +"<quote>main branch</quote> on a central server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:208 +msgid "People clone it, make changes locally, test them, and push them back." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:211 +msgid "" +"Once the main branch reaches a release milestone, you can use the <command " +"role=\"hg-cmd\">hg tag</command> command to give a permanent name to the " +"milestone revision." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:217 +msgid "Let's say some ongoing development occurs on the main branch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:222 +msgid "" +"Using the tag that was recorded at the milestone, people who clone that " +"repository at any time in the future can use <command role=\"hg-cmd\">hg " +"update</command> to get a copy of the working directory exactly as it was " +"when that tagged revision was committed." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:230 +msgid "" +"In addition, immediately after the main branch is tagged, someone can then " +"clone the main branch on the server to a new <quote>stable</quote> branch, " +"also on the server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:236 +msgid "" +"Someone who needs to make a change to the stable branch can then clone " +"<emphasis>that</emphasis> repository, make their changes, commit, and push " +"their changes back there." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:242 +msgid "" +"Because Mercurial repositories are independent, and Mercurial doesn't move " +"changes around automatically, the stable and main branches are " +"<emphasis>isolated</emphasis> from each other. The changes that you made on " +"the main branch don't <quote>leak</quote> to the stable branch, and vice " +"versa." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:249 +msgid "" +"You'll often want all of your bugfixes on the stable branch to show up on the " +"main branch, too. Rather than rewrite a bugfix on the main branch, you can " +"simply pull and merge changes from the stable to the main branch, and " +"Mercurial will bring those bugfixes in for you." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:257 +msgid "" +"The main branch will still contain changes that are not on the stable branch, " +"but it will also contain all of the bugfixes from the stable branch. The " +"stable branch remains unaffected by these changes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch05-collab.xml:264 ../en/ch05-collab.xml:278 +msgid "Feature branches" +msgstr "特性分支" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:266 +msgid "" +"For larger projects, an effective way to manage change is to break up a team " +"into smaller groups. Each group has a shared branch of its own, cloned from " +"a single <quote>master</quote> branch used by the entire project. People " +"working on an individual branch are typically quite isolated from " +"developments on other branches." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch05-collab.xml:275 +msgid "" +"<imageobject><imagedata fileref=\"images/feature-branches.png\"/> </" +"imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:283 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:290 +msgid "The release train" +msgstr "发布列车" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:292 +msgid "" +"Some projects are organised on a <quote>train</quote> basis: a release is " +"scheduled to happen every few months, and whatever features are ready when " +"the <quote>train</quote> is ready to leave are allowed in." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:297 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:306 +msgid "The Linux kernel model" +msgstr "Linux 内核模型" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:308 +msgid "" +"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</command>, 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:316 +msgid "" +"At the center of the community sits Linus Torvalds, the creator of Linux. He " +"publishes a single source repository that is considered the " +"<quote>authoritative</quote> current tree by the entire developer community. " +"Anyone can clone Linus's tree, but he is very choosy about whose trees he " +"pulls from." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:323 +msgid "" +"Linus has a number of <quote>trusted lieutenants</quote>. As a general rule, " +"he pulls whatever changes they publish, in most cases without even reviewing " +"those changes. Some of those lieutenants are generally agreed to be " +"<quote>maintainers</quote>, responsible for specific subsystems within the " +"kernel. If a random kernel hacker wants to make a change to a subsystem that " +"they want to end up in Linus's tree, they must find out who the subsystem's " +"maintainer is, and ask that maintainer to take their change. If the " +"maintainer reviews their changes and agrees to take them, they'll pass them " +"along to Linus in due course." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:335 +msgid "" +"Individual lieutenants have their own approaches to reviewing, accepting, and " +"publishing changes; and for deciding when to feed them to Linus. In " +"addition, there are several well known branches that people use for different " +"purposes. For example, a few people maintain <quote>stable</quote> " +"repositories of older versions of the kernel, to which they apply critical " +"fixes as needed. Some maintainers publish multiple trees: one for " +"experimental changes; one for changes that they are about to feed upstream; " +"and so on. Others just publish a single tree." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:346 +msgid "" +"This model has two notable features. The first is that it's <quote>pull " +"only</quote>. You have to ask, convince, or beg another developer to take a " +"change from you, because there are almost no trees to which more than one " +"person can push, and there's no way to push changes into a tree that someone " +"else controls." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:353 +msgid "" +"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 " +"<quote>good</quote> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:364 +msgid "" +"Reputation and acclaim don't necessarily cross subsystem or <quote>people</" +"quote> boundaries. If you're a respected but specialised storage hacker, and " +"you try to fix a networking bug, that change will receive a level of scrutiny " +"from a network maintainer comparable to a change from a complete stranger." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:371 +msgid "" +"To people who come from more orderly project backgrounds, the comparatively " +"chaotic Linux kernel development process often seems completely insane. It's " +"subject to the whims of individuals; people make sweeping changes whenever " +"they deem it appropriate; and the pace of development is astounding. And yet " +"Linux is a highly successful, well-regarded piece of software." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:381 +msgid "Pull-only versus shared-push collaboration" +msgstr "只读与共享写协作" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:383 +msgid "" +"A perpetual source of heat in the open source community is whether a " +"development model in which people only ever pull changes from others is " +"<quote>better than</quote> one in which multiple people can push changes to a " +"shared repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:389 +msgid "" +"Typically, the backers of the shared-push model use tools that actively " +"enforce this approach. If you're using a centralised revision control tool " +"such as Subversion, there's no way to make a choice over which model you'll " +"use: the tool gives you shared-push, and if you want to do anything else, " +"you'll have to roll your own approach on top (such as applying a patch by " +"hand)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:397 +msgid "" +"A good distributed revision control tool, such as Mercurial, will support " +"both models. You and your collaborators can then structure how you work " +"together based on your own needs and preferences, not on what contortions " +"your tools force you into." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:405 +msgid "Where collaboration meets branch management" +msgstr "协作与分支管理" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:407 +msgid "" +"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 <xref linkend=\"chap.branch" +"\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch05-collab.xml:419 +msgid "The technical side of sharing" +msgstr "共享的技术因素" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:421 +msgid "" +"The remainder of this chapter is devoted to the question of serving data to " +"your collaborators." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch05-collab.xml:426 +msgid "Informal sharing with <command role=\"hg-cmd\">hg serve</command>" +msgstr "使用 <command role=\"hg-cmd\">hg serve</command> 进行非正式共享" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:429 +msgid "" +"Mercurial's <command role=\"hg-cmd\">hg serve</command> command is " +"wonderfully suited to small, tight-knit, and fast-paced group environments. " +"It also provides a great way to get a feel for using Mercurial commands over " +"a network." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:434 +msgid "" +"Run <command role=\"hg-cmd\">hg serve</command> 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 <command role=\"hg-" +"cmd\">hg serve</command> instance running on a laptop is likely to look " +"something like <literal>http://my-laptop.local:8000/</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:445 +msgid "" +"The <command role=\"hg-cmd\">hg serve</command> command is <emphasis>not</" +"emphasis> a general-purpose web server. It can do only two things:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:449 +msgid "" +"Allow people to browse the history of the repository it's serving, from their " +"normal web browsers." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:453 +msgid "" +"Speak Mercurial's wire protocol, so that people can <command role=\"hg-cmd" +"\">hg clone</command> or <command role=\"hg-cmd\">hg pull</command> changes " +"from that repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:458 +msgid "" +"In particular, <command role=\"hg-cmd\">hg serve</command> won't allow remote " +"users to <emphasis>modify</emphasis> your repository. It's intended for read-" +"only use." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:462 +msgid "" +"If you're getting started with Mercurial, there's nothing to prevent you from " +"using <command role=\"hg-cmd\">hg serve</command> to serve up a repository on " +"your own computer, then use commands like <command role=\"hg-cmd\">hg clone</" +"command>, <command role=\"hg-cmd\">hg incoming</command>, 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:472 +msgid "A few things to keep in mind" +msgstr "要牢记的几件事" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:474 +msgid "" +"Because it provides unauthenticated read access to all clients, you should " +"only use <command role=\"hg-cmd\">hg serve</command> in an environment where " +"you either don't care, or have complete control over, who can access your " +"network and pull data from your repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:480 +msgid "" +"The <command role=\"hg-cmd\">hg serve</command> 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 <command role=\"hg-cmd\">hg serve</command> instance, " +"the second thing you should do (<emphasis>after</emphasis> you make sure that " +"they're using the correct URL) is check your firewall configuration." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:489 +msgid "" +"By default, <command role=\"hg-cmd\">hg serve</command> listens for incoming " +"connections on port 8000. If another process is already listening on the " +"port you want to use, you can specify a different port to listen on using the " +"<option role=\"hg-opt-serve\">-p</option> option." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:495 +msgid "" +"Normally, when <command role=\"hg-cmd\">hg serve</command> 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 <option role=\"hg-opt-global\">-v</option> " +"option." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch05-collab.xml:505 +msgid "Using the Secure Shell (ssh) protocol" +msgstr "使用 ssh 协议" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:507 +msgid "" +"You can pull and push changes securely over a network connection using the " +"Secure Shell (<literal>ssh</literal>) protocol. To use this successfully, " +"you may have to do a little bit of configuration on the client or server " +"sides." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:512 +msgid "" +"If you're not familiar with ssh, it's a network protocol that lets you " +"securely communicate with another computer. To use it with Mercurial, you'll " +"be setting up one or more user accounts on a server so that remote users can " +"log in and execute commands." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:518 +msgid "" +"(If you <emphasis>are</emphasis> familiar with ssh, you'll probably find some " +"of the material that follows to be elementary in nature.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:523 +msgid "How to read and write ssh URLs" +msgstr "如何读写 ssh 路径" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:525 +msgid "An ssh URL tends to look like this:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch05-collab.xml:528 +msgid "" +"The <quote><literal>ssh://</literal></quote> part tells Mercurial to use the " +"ssh protocol." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch05-collab.xml:531 +msgid "" +"The <quote><literal>bos@</literal></quote> component indicates what username " +"to log into the server as. You can leave this out if the remote username is " +"the same as your local username." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch05-collab.xml:536 +msgid "" +"The <quote><literal>hg.serpentine.com</literal></quote> gives the hostname of " +"the server to log into." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch05-collab.xml:540 +msgid "" +"The <quote>:22</quote> identifies the port number to connect to the server " +"on. The default port is 22, so you only need to specify a colon and port " +"number if you're <emphasis>not</emphasis> using port 22." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch05-collab.xml:545 +msgid "" +"The remainder of the URL is the local path to the repository on the server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:549 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:556 +msgid "" +"Mercurial treats the path to a repository on the server as relative to the " +"remote user's home directory. For example, if user <literal>foo</literal> on " +"the server has a home directory of <filename class=\"directory\">/home/foo</" +"filename>, then an ssh URL that contains a path component of <filename class=" +"\"directory\">bar</filename> <emphasis>really</emphasis> refers to the " +"directory <filename class=\"directory\">/home/foo/bar</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:565 +msgid "" +"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 <literal>otheruser</literal>), like this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:571 +msgid "" +"And if you really want to specify an <emphasis>absolute</emphasis> path on " +"the server, begin the path component with two slashes, as in this example." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:578 +msgid "Finding an ssh client for your system" +msgstr "为你的系统寻找 ssh 客户端" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:580 +msgid "" +"Almost every Unix-like system comes with OpenSSH preinstalled. If you're " +"using such a system, run <literal>which ssh</literal> to find out if the " +"<command>ssh</command> command is installed (it's usually in <filename class=" +"\"directory\">/usr/bin</filename>). In the unlikely event that it isn't " +"present, take a look at your system documentation to figure out how to " +"install it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:588 +msgid "" +"On Windows, you'll first need to download a suitable ssh client. There are " +"two alternatives." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:591 +msgid "" +"Simon Tatham's excellent PuTTY package <citation>web:putty</citation> " +"provides a complete suite of ssh client commands." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:595 +msgid "" +"If you have a high tolerance for pain, you can use the Cygwin port of OpenSSH." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:598 +msgid "" +"In either case, you'll need to edit your <filename role=\"special\">hg.ini</" +"filename> file to tell Mercurial where to find the actual client command. " +"For example, if you're using PuTTY, you'll need to use the <command>plink</" +"command> command as a command-line ssh client." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch05-collab.xml:608 +msgid "" +"The path to <command>plink</command> shouldn't contain any whitespace " +"characters, or Mercurial may not be able to run it correctly (so putting it " +"in <filename class=\"directory\">C:\\Program Files</filename> is probably not " +"a good idea)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:617 +msgid "Generating a key pair" +msgstr "产生密钥对" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:619 +msgid "" +"To avoid the need to repetitively type a password every time you need to use " +"your ssh client, I recommend generating a key pair. On a Unix-like system, " +"the <command>ssh-keygen</command> command will do the trick. On Windows, if " +"you're using PuTTY, the <command>puttygen</command> command is what you'll " +"need." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:627 +msgid "" +"When you generate a key pair, it's usually <emphasis>highly</emphasis> " +"advisable to protect it with a passphrase. (The only time that you might not " +"want to do this is when you're using the ssh protocol for automated tasks on " +"a secure network.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:633 +msgid "" +"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 <filename role=\"special" +"\">authorized_keys</filename> in their <filename role=\"special\" class=" +"\"directory\">.ssh</filename> directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:642 +msgid "" +"On a Unix-like system, your public key will have a <filename>.pub</filename> " +"extension. If you're using <command>puttygen</command> 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 <filename role=\"special" +"\">authorized_keys</filename> file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:651 +msgid "Using an authentication agent" +msgstr "使用认证代理" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:653 +msgid "" +"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)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:662 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:669 +msgid "" +"On Unix-like systems, the agent is called <command>ssh-agent</command>, and " +"it's often run automatically for you when you log in. You'll need to use the " +"<command>ssh-add</command> command to add passphrases to the agent's store. " +"On Windows, if you're using PuTTY, the <command>pageant</command> command " +"acts as the agent. It adds an icon to your system tray that will let you " +"manage stored passphrases." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:680 +msgid "Configuring the server side properly" +msgstr "正确配置服务器端" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:682 +msgid "" +"Because ssh can be fiddly to set up if you're new to it, there's a variety of " +"things that can go wrong. Add Mercurial on top, and there's plenty more " +"scope for head-scratching. Most of these potential problems occur on the " +"server side, not the client side. The good news is that once you've gotten a " +"configuration working, it will usually continue to work indefinitely." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:690 +msgid "" +"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</command> or <command>putty</" +"command> 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, <emphasis>before</emphasis> you worry about whether " +"there's a problem with Mercurial." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:701 +msgid "" +"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</command> or " +"<command>putty</command> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:708 +msgid "" +"If you get a <quote>connection refused</quote> error, either there isn't an " +"SSH daemon running on the server at all, or it's inaccessible due to firewall " +"configuration." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:713 +msgid "" +"If you get a <quote>no route to host</quote> error, you either have an " +"incorrect address for the server or a seriously locked down firewall that " +"won't admit its existence at all." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:718 +msgid "" +"If you get a <quote>permission denied</quote> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:723 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:733 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:739 +msgid "" +"You might have forgotten to use <command>ssh-add</command> or " +"<command>pageant</command> to store the passphrase." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:743 +msgid "You might have stored the passphrase for the wrong key." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:746 +msgid "" +"If you're being prompted for the remote user's password, there are another " +"few possible problems to check." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:749 +msgid "" +"Either the user's home directory or their <filename role=\"special\" class=" +"\"directory\">.ssh</filename> directory might have excessively liberal " +"permissions. As a result, the ssh daemon will not trust or read their " +"<filename role=\"special\">authorized_keys</filename> file. For example, a " +"group-writable home or <filename role=\"special\" class=\"directory\">.ssh</" +"filename> directory will often cause this symptom." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:758 +msgid "" +"The user's <filename role=\"special\">authorized_keys</filename> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:765 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:770 +msgid "" +"If, on your server, you have login scripts that print banners or other junk " +"even when running non-interactive commands like this, you should fix them " +"before you continue, so that they only print output if they're run " +"interactively. Otherwise these banners will at least clutter up Mercurial's " +"output. Worse, they could potentially cause problems with running Mercurial " +"commands remotely. Mercurial makes tries to detect and ignore banners in non-" +"interactive <command>ssh</command> sessions, but it is not foolproof. (If " +"you're editing your login scripts on your server, the usual way to see if a " +"login script is running in an interactive shell is to check the return code " +"from the command <literal>tty -s</literal>.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:784 +msgid "" +"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:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:791 +msgid "" +"If you see an error message instead of normal <command role=\"hg-cmd\">hg " +"version</command> output, this is usually because you haven't installed " +"Mercurial to <filename class=\"directory\">/usr/bin</filename>. Don't worry " +"if this is the case; you don't need to do that. But you should check for a " +"few possible problems." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:798 +msgid "" +"Is Mercurial really installed on the server at all? I know this sounds " +"trivial, but it's worth checking!" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:802 +msgid "" +"Maybe your shell's search path (usually set via the <envar>PATH</envar> " +"environment variable) is simply misconfigured." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:806 +msgid "" +"Perhaps your <envar>PATH</envar> environment variable is only being set to " +"point to the location of the <command>hg</command> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:813 +msgid "" +"The <envar>PYTHONPATH</envar> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:820 +msgid "" +"If you can run <command role=\"hg-cmd\">hg version</command> 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 <option role=\"hg-opt-global\">--debug</option> " +"option to get a clearer picture of what's going on." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:830 +msgid "Using compression with ssh" +msgstr "通过 ssh 使用压缩" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:832 +msgid "" +"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 <emphasis>not</emphasis> to request compression." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:837 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:844 +msgid "" +"Both <command>ssh</command> and <command>plink</command> accept a <option " +"role=\"cmd-opt-ssh\">-C</option> option which turns on compression. You can " +"easily edit your <filename role=\"special\">~/.hgrc</filename> to enable " +"compression for all of Mercurial's uses of the ssh protocol." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:852 +msgid "" +"If you use <command>ssh</command>, you can configure it to always use " +"compression when talking to your server. To do this, edit your <filename " +"role=\"special\">.ssh/config</filename> file (which may not yet exist), as " +"follows." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:860 +msgid "" +"This defines an alias, <literal>hg</literal>. When you use it on the " +"<command>ssh</command> command line or in a Mercurial <literal>ssh</literal>-" +"protocol URL, it will cause <command>ssh</command> to connect to <literal>hg." +"example.com</literal> and use compression. This gives you both a shorter " +"name to type and compression, each of which is a good thing in its own right." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch05-collab.xml:871 +msgid "Serving over HTTP using CGI" +msgstr "使用 CGI 通过 HTTP 提供服务" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:873 +msgid "" +"Depending on how ambitious you are, configuring Mercurial's CGI interface can " +"take anything from a few moments to several hours." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch05-collab.xml:877 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><note><para> +#: ../en/ch05-collab.xml:883 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:893 +msgid "Web server configuration checklist" +msgstr "Web 服务器配置检查表" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:895 +msgid "" +"Before you continue, do take a few moments to check a few aspects of your " +"system's setup." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch05-collab.xml:899 +msgid "" +"Do you have a web server installed at all? Mac OS X ships with Apache, but " +"many other systems may not have a web server installed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch05-collab.xml:903 +msgid "" +"If you have a web server installed, is it actually running? On most systems, " +"even if one is present, it will be disabled by default." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch05-collab.xml:907 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:913 +msgid "" +"If you don't have a web server installed, and don't have substantial " +"experience configuring Apache, you should consider using the " +"<literal>lighttpd</literal> web server instead of Apache. Apache has a well-" +"deserved reputation for baroque and confusing configuration. While " +"<literal>lighttpd</literal> is less capable in some ways than Apache, most of " +"these capabilities are not relevant to serving Mercurial repositories. And " +"<literal>lighttpd</literal> is undeniably <emphasis>much</emphasis> easier to " +"get started with than Apache." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:926 +msgid "Basic CGI configuration" +msgstr "基本 CGI 配置" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:928 +msgid "" +"On Unix-like systems, it's common for users to have a subdirectory named " +"something like <filename class=\"directory\">public_html</filename> in their " +"home directory, from which they can serve up web pages. A file named " +"<filename>foo</filename> in this directory will be accessible at a URL of the " +"form <literal>http://www.example.com/username/foo</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:936 +msgid "" +"To get started, find the <filename role=\"special\">hgweb.cgi</filename> " +"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 <ulink url=\"http://www.selenic.com/repo/hg/raw-file/" +"tip/hgweb.cgi\">http://www.selenic.com/repo/hg/raw-file/tip/hgweb.cgi</ulink>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:943 ../en/ch05-collab.xml:1112 +msgid "" +"You'll need to copy this script into your <filename class=\"directory" +"\">public_html</filename> directory, and ensure that it's executable." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:948 +msgid "" +"The <literal>755</literal> argument to <command>chmod</command> is a little " +"more general than just making the script executable: it ensures that the " +"script is executable by anyone, and that <quote>group</quote> and " +"<quote>other</quote> write permissions are <emphasis>not</emphasis> set. If " +"you were to leave those write permissions enabled, Apache's <literal>suexec</" +"literal> subsystem would likely refuse to execute the script. In fact, " +"<literal>suexec</literal> also insists that the <emphasis>directory</" +"emphasis> in which the script resides must not be writable by others." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch05-collab.xml:962 +msgid "What could <emphasis>possibly</emphasis> go wrong?" +msgstr "什么<emphasis>可能</emphasis>会出错?" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:965 +msgid "" +"Once you've copied the CGI script into place, go into a web browser, and try " +"to open the URL <ulink url=\"http://myhostname/ myuser/hgweb.cgi\">http://" +"myhostname/ myuser/hgweb.cgi</ulink>, <emphasis>but</emphasis> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:979 +msgid "" +"Your web server may have per-user directories disabled. If you're using " +"Apache, search your config file for a <literal>UserDir</literal> directive. " +"If there's none present, per-user directories will be disabled. If one " +"exists, but its value is <literal>disabled</literal>, then per-user " +"directories will be disabled. Otherwise, the string after <literal>UserDir</" +"literal> gives the name of the subdirectory that Apache will look in under " +"your home directory, for example <filename class=\"directory\">public_html</" +"filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:990 +msgid "" +"Your file access permissions may be too restrictive. The web server must be " +"able to traverse your home directory and directories under your <filename " +"class=\"directory\">public_html</filename> directory, and read files under " +"the latter too. Here's a quick recipe to help you to make your permissions " +"more appropriate." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1000 +msgid "" +"The other possibility with permissions is that you might get a completely " +"empty window when you try to load the script. In this case, it's likely that " +"your access permissions are <emphasis>too permissive</emphasis>. Apache's " +"<literal>suexec</literal> subsystem won't execute a script that's group- or " +"world-writable, for example." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1007 +msgid "" +"Your web server may be configured to disallow execution of CGI programs in " +"your per-user web directory. Here's Apache's default per-user configuration " +"from my Fedora system." +msgstr "" + +#. type: CDATA +#: ../en/ch05-collab.xml:1012 +#, no-wrap +msgid "&ch06-apache-config.lst;]]" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1014 +msgid "" +"If you find a similar-looking <literal>Directory</literal> group in your " +"Apache configuration, the directive to look at inside it is <literal>Options</" +"literal>. Add <literal>ExecCGI</literal> to the end of this list if it's " +"missing, and restart the web server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1021 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1027 +msgid "" +"The next possibility is that you might be served with a colourful Python " +"backtrace claiming that it can't import a <literal>mercurial</literal>-" +"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 <filename role=" +"\"special\">hgweb.cgi</filename> and follow the directions inside it to " +"correctly set your <envar>PYTHONPATH</envar> environment variable." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1041 +msgid "" +"Finally, you are <emphasis>certain</emphasis> to by served with another " +"colourful Python backtrace: this one will complain that it can't find " +"<filename class=\"directory\">/path/to/repository</filename>. Edit your " +"<filename role=\"special\">hgweb.cgi</filename> script and replace the " +"<filename class=\"directory\">/path/to/repository</filename> string with the " +"complete path to the repository you want to serve up." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1051 +msgid "" +"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!" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch05-collab.xml:1057 +msgid "Configuring lighttpd" +msgstr "配置 lighttpd" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1059 +msgid "" +"To be exhaustive in my experiments, I tried configuring the increasingly " +"popular <literal>lighttpd</literal> 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 <filename role=\"special\">hgweb.cgi</filename> script was properly edited." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1069 +msgid "" +"Once I had Apache running, getting <literal>lighttpd</literal> to serve the " +"repository was a snap (in other words, even if you're trying to use " +"<literal>lighttpd</literal>, you should read the Apache section). I first " +"had to edit the <literal>mod_access</literal> section of its config file to " +"enable <literal>mod_cgi</literal> and <literal>mod_userdir</literal>, both of " +"which were disabled by default on my system. I then added a few lines to the " +"end of the config file, to configure these modules." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1081 +msgid "" +"With this done, <literal>lighttpd</literal> ran immediately for me. If I had " +"configured <literal>lighttpd</literal> 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 <literal>lighttpd</literal> 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 <literal>lighttpd</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:1094 +msgid "Sharing multiple repositories with one CGI script" +msgstr "使用一个 CGI 脚本共享多个版本库" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1096 +msgid "" +"The <filename role=\"special\">hgweb.cgi</filename> 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 " +"<filename role=\"special\">hgwebdir.cgi</filename> script." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1104 +msgid "" +"The procedure to configure <filename role=\"special\">hgwebdir.cgi</filename> " +"is only a little more involved than for <filename role=\"special\">hgweb.cgi</" +"filename>. 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 " +"<ulink url=\"http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi" +"\">http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi</ulink>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1117 +msgid "" +"With basic configuration out of the way, try to visit <ulink url=\"http://" +"myhostname/ myuser/hgwebdir.cgi\">http://myhostname/ myuser/hgwebdir.cgi</" +"ulink> in your browser. It should display an empty list of repositories. If " +"you get a blank window or error message, try walking through the list of " +"potential problems in section <xref linkend=\"sec.collab.wtf\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1126 +msgid "" +"The <filename role=\"special\">hgwebdir.cgi</filename> script relies on an " +"external configuration file. By default, it searches for a file named " +"<filename role=\"special\">hgweb.config</filename> 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 <quote>ini</quote> file, as " +"understood by Python's <literal>ConfigParser</literal> <citation>web:" +"configparser</citation> module." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1136 +msgid "" +"The easiest way to configure <filename role=\"special\">hgwebdir.cgi</" +"filename> is with a section named <literal>collections</literal>. This will " +"automatically publish <emphasis>every</emphasis> repository under the " +"directories you name. The section should look like this:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1144 +msgid "" +"Mercurial interprets this by looking at the directory name on the " +"<emphasis>right</emphasis> hand side of the <quote><literal>=</literal></" +"quote> sign; finding repositories in that directory hierarchy; and using the " +"text on the <emphasis>left</emphasis> to strip off matching text from the " +"names it will actually list in the web interface. The remaining component of " +"a path after this stripping has occurred is called a <quote>virtual path</" +"quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1153 +msgid "" +"Given the example above, if we have a repository whose local path is " +"<filename class=\"directory\">/my/root/this/repo</filename>, the CGI script " +"will strip the leading <filename class=\"directory\">/my/root</filename> from " +"the name, and publish the repository with a virtual path of <filename class=" +"\"directory\">this/repo</filename>. If the base URL for our CGI script is " +"<ulink url=\"http://myhostname/ myuser/hgwebdir.cgi\">http://myhostname/ " +"myuser/hgwebdir.cgi</ulink>, the complete URL for that repository will be " +"<ulink url=\"http://myhostname/ myuser/hgwebdir.cgi/this/repo\">http://" +"myhostname/ myuser/hgwebdir.cgi/this/repo</ulink>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1167 +msgid "" +"If we replace <filename class=\"directory\">/my/root</filename> on the left " +"hand side of this example with <filename class=\"directory\">/my</filename>, " +"then <filename role=\"special\">hgwebdir.cgi</filename> will only strip off " +"<filename class=\"directory\">/my</filename> from the repository name, and " +"will give us a virtual path of <filename class=\"directory\">root/this/repo</" +"filename> instead of <filename class=\"directory\">this/repo</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1177 +msgid "" +"The <filename role=\"special\">hgwebdir.cgi</filename> script will " +"recursively search each directory listed in the <literal>collections</" +"literal> section of its configuration file, but it will <literal>not</" +"literal> recurse into the repositories it finds." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1183 +msgid "" +"The <literal>collections</literal> mechanism makes it easy to publish many " +"repositories in a <quote>fire and forget</quote> 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 <filename role=" +"\"special\">hgwebdir.cgi</filename> to look." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch05-collab.xml:1193 +msgid "Explicitly specifying which repositories to publish" +msgstr "明确指出要发布的版本库" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1196 +msgid "" +"In addition to the <literal>collections</literal> mechanism, the <filename " +"role=\"special\">hgwebdir.cgi</filename> script allows you to publish a " +"specific list of repositories. To do so, create a <literal>paths</literal> " +"section, with contents of the following form." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1205 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1212 +msgid "" +"If you wish, you can use both the <literal>collections</literal> and " +"<literal>paths</literal> mechanisms simultaneously in a single configuration " +"file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><note><para> +#: ../en/ch05-collab.xml:1218 +msgid "" +"If multiple repositories have the same virtual path, <filename role=\"special" +"\">hgwebdir.cgi</filename> will not report an error. Instead, it will behave " +"unpredictably." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:1227 +msgid "Downloading source archives" +msgstr "下载源代码档案包" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1229 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1234 +msgid "" +"By default, this feature is not enabled. To enable it, you'll need to add an " +"<envar role=\"rc-item-web\">allow_archive</envar> item to the <literal role=" +"\"rc-web\">web</literal> section of your <filename role=\"special\">~/.hgrc</" +"filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch05-collab.xml:1242 +msgid "Web configuration options" +msgstr "Web 配置选项" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1244 +msgid "" +"Mercurial's web interfaces (the <command role=\"hg-cmd\">hg serve</command> " +"command, and the <filename role=\"special\">hgweb.cgi</filename> and " +"<filename role=\"special\">hgwebdir.cgi</filename> scripts) have a number of " +"configuration options that you can set. These belong in a section named " +"<literal role=\"rc-web\">web</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1252 +msgid "" +"<envar role=\"rc-item-web\">allow_archive</envar>: 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1261 +msgid "" +"<literal>bz2</literal>: A <command>tar</command> archive, compressed using " +"<literal>bzip2</literal> compression. This has the best compression ratio, " +"but uses the most CPU time on the server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1267 +msgid "" +"<literal>gz</literal>: A <command>tar</command> archive, compressed using " +"<literal>gzip</literal> compression." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1271 +msgid "" +"<literal>zip</literal>: A <command>zip</command> archive, compressed using " +"LZW compression. This format has the worst compression ratio, but is widely " +"used in the Windows world." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1277 +msgid "" +"If you provide an empty list, or don't have an <envar role=\"rc-item-web" +"\">allow_archive</envar> entry at all, this feature will be disabled. Here " +"is an example of how to enable all three supported formats." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1284 +msgid "" +"<envar role=\"rc-item-web\">allowpull</envar>: Boolean. Determines whether " +"the web interface allows remote users to <command role=\"hg-cmd\">hg pull</" +"command> and <command role=\"hg-cmd\">hg clone</command> this repository over " +"HTTP. If set to <literal>no</literal> or <literal>false</literal>, only the " +"<quote>human-oriented</quote> portion of the web interface is available." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1293 +msgid "" +"<envar role=\"rc-item-web\">contact</envar>: 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 " +"<filename role=\"special\">.hg/hgrc</filename> file, but it can make sense to " +"use in a global <filename role=\"special\">~/.hgrc</filename> if every " +"repository has a single maintainer." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1304 +msgid "" +"<envar role=\"rc-item-web\">maxchanges</envar>: Integer. The default maximum " +"number of changesets to display in a single page of output." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1308 +msgid "" +"<envar role=\"rc-item-web\">maxfiles</envar>: Integer. The default maximum " +"number of modified files to display in a single page of output." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1312 +msgid "" +"<envar role=\"rc-item-web\">stripes</envar>: Integer. If the web interface " +"displays alternating <quote>stripes</quote> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1318 +msgid "" +"<envar role=\"rc-item-web\">style</envar>: Controls the template Mercurial " +"uses to display the web interface. Mercurial ships with two web templates, " +"named <literal>default</literal> and <literal>gitweb</literal> (the latter is " +"much more visually attractive). You can also specify a custom template of " +"your own; see chapter <xref linkend=\"chap.template\"/> for details. Here, " +"you can see how to enable the <literal>gitweb</literal> style." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1330 +msgid "" +"<envar role=\"rc-item-web\">templates</envar>: Path. The directory in which " +"to search for template files. By default, Mercurial searches in the " +"directory in which it was installed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch05-collab.xml:1335 +msgid "" +"If you are using <filename role=\"special\">hgwebdir.cgi</filename>, you can " +"place a few configuration items in a <literal role=\"rc-web\">web</literal> " +"section of the <filename role=\"special\">hgweb.config</filename> file " +"instead of a <filename role=\"special\">~/.hgrc</filename> file, for " +"convenience. These items are <envar role=\"rc-item-web\">motd</envar> and " +"<envar role=\"rc-item-web\">style</envar>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch05-collab.xml:1346 +msgid "Options specific to an individual repository" +msgstr "针对单个版本库的选项" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1348 +msgid "" +"A few <literal role=\"rc-web\">web</literal> configuration items ought to be " +"placed in a repository's local <filename role=\"special\">.hg/hgrc</" +"filename>, rather than a user's or global <filename role=\"special\">~/.hgrc</" +"filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1353 +msgid "" +"<envar role=\"rc-item-web\">description</envar>: String. A free-form (but " +"preferably brief) string that describes the contents or purpose of the " +"repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1358 +msgid "" +"<envar role=\"rc-item-web\">name</envar>: 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch05-collab.xml:1366 +msgid "" +"Options specific to the <command role=\"hg-cmd\">hg serve</command> command" +msgstr "命令 <command role=\"hg-cmd\">hg serve</command> 的选项" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1369 +msgid "" +"Some of the items in the <literal role=\"rc-web\">web</literal> section of a " +"<filename role=\"special\">~/.hgrc</filename> file are only for use with the " +"<command role=\"hg-cmd\">hg serve</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1375 +msgid "" +"<envar role=\"rc-item-web\">accesslog</envar>: Path. The name of a file into " +"which to write an access log. By default, the <command role=\"hg-cmd\">hg " +"serve</command> command writes this information to standard output, not to a " +"file. Log entries are written in the standard <quote>combined</quote> file " +"format used by almost all web servers." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1383 +msgid "" +"<envar role=\"rc-item-web\">address</envar>: String. The local address on " +"which the server should listen for incoming connections. By default, the " +"server listens on all addresses." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1388 +msgid "" +"<envar role=\"rc-item-web\">errorlog</envar>: Path. The name of a file into " +"which to write an error log. By default, the <command role=\"hg-cmd\">hg " +"serve</command> command writes this information to standard error, not to a " +"file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1394 +msgid "" +"<envar role=\"rc-item-web\">ipv6</envar>: Boolean. Whether to use the IPv6 " +"protocol. By default, IPv6 is not used." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch05-collab.xml:1398 +msgid "" +"<envar role=\"rc-item-web\">port</envar>: Integer. The TCP port number on " +"which the server should listen. The default port number used is 8000." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch05-collab.xml:1405 +msgid "" +"Choosing the right <filename role=\"special\">~/.hgrc</filename> file to add " +"<literal role=\"rc-web\">web</literal> items to" +msgstr "" +"选择正确的 <filename role=\"special\"> ~/.hgrc</filename> 文件增加到 <literal " +"role=\"rc-web\">web</literal> 条目" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1409 +msgid "" +"It is important to remember that a web server like Apache or " +"<literal>lighttpd</literal> will run under a user ID that is different to " +"yours. CGI scripts run by your server, such as <filename role=\"special" +"\">hgweb.cgi</filename>, will usually also run under that user ID." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch05-collab.xml:1416 +msgid "" +"If you add <literal role=\"rc-web\">web</literal> items to your own personal " +"<filename role=\"special\">~/.hgrc</filename> file, CGI scripts won't read " +"that <filename role=\"special\">~/.hgrc</filename> file. Those settings will " +"thus only affect the behaviour of the <command role=\"hg-cmd\">hg serve</" +"command> command when you run it. To cause CGI scripts to see your settings, " +"either create a <filename role=\"special\">~/.hgrc</filename> file in the " +"home directory of the user ID that runs your web server, or add those " +"settings to a system-wide <filename role=\"special\">~/.hgrc</filename> file." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch06-filenames.xml:5 +msgid "File names and pattern matching" +msgstr "文件名称与模式匹配" + +#. type: Content of: <book><chapter><para> +#: ../en/ch06-filenames.xml:7 +msgid "" +"Mercurial provides mechanisms that let you work with file names in a " +"consistent and expressive way." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch06-filenames.xml:11 +msgid "Simple file naming" +msgstr "简单文件名称" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:13 +msgid "" +"Mercurial uses a unified piece of machinery <quote>under the hood</quote> to " +"handle file names. Every command behaves uniformly with respect to file " +"names. The way in which commands work with file names is as follows." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:18 +msgid "" +"If you explicitly name real files on the command line, Mercurial works with " +"exactly those files, as you would expect. &interaction.filenames.files;" +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:22 +msgid "" +"When you provide a directory name, Mercurial will interpret this as " +"<quote>operate on every file in this directory and its subdirectories</" +"quote>. Mercurial traverses the files and subdirectories in a directory in " +"alphabetical order. When it encounters a subdirectory, it will traverse that " +"subdirectory before continuing with the current directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch06-filenames.xml:33 +msgid "Running commands without any file names" +msgstr "不提供文件名称的执行命令" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:35 +msgid "" +"Mercurial's commands that work with file names have useful default behaviours " +"when you invoke them without providing any file names or patterns. What kind " +"of behaviour you should expect depends on what the command does. Here are a " +"few rules of thumb you can use to predict what a command is likely to do if " +"you don't give it any names to work with." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch06-filenames.xml:42 +msgid "" +"Most commands will operate on the entire working directory. This is what the " +"<command role=\"hg-cmd\">hg add</command> command does, for example." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch06-filenames.xml:46 +msgid "" +"If the command has effects that are difficult or impossible to reverse, it " +"will force you to explicitly provide at least one name or pattern (see " +"below). This protects you from accidentally deleting files by running " +"<command role=\"hg-cmd\">hg remove</command> with no arguments, for example." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:54 +msgid "" +"It's easy to work around these default behaviours if they don't suit you. If " +"a command normally operates on the whole working directory, you can invoke it " +"on just the current directory and its subdirectories by giving it the name " +"<quote><filename class=\"directory\">.</filename></quote>." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:62 +msgid "" +"Along the same lines, some commands normally print file names relative to the " +"root of the repository, even if you're invoking them from a subdirectory. " +"Such a command will print file names relative to your subdirectory if you " +"give it explicit names. Here, we're going to run <command role=\"hg-cmd\">hg " +"status</command> from a subdirectory, and get it to operate on the entire " +"working directory while printing file names relative to our subdirectory, by " +"passing it the output of the <command role=\"hg-cmd\">hg root</command> " +"command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch06-filenames.xml:76 +msgid "Telling you what's going on" +msgstr "告诉你正在做什么" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:78 +msgid "" +"The <command role=\"hg-cmd\">hg add</command> example in the preceding " +"section illustrates something else that's helpful about Mercurial commands. " +"If a command operates on a file that you didn't name explicitly on the " +"command line, it will usually print the name of the file, so that you will " +"not be surprised what's going on." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:85 +msgid "" +"The principle here is of <emphasis>least surprise</emphasis>. If you've " +"exactly named a file on the command line, there's no point in repeating it " +"back at you. If Mercurial is acting on a file <emphasis>implicitly</" +"emphasis>, because you provided no names, or a directory, or a pattern (see " +"below), it's safest to tell you what it's doing." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:92 +msgid "" +"For commands that behave this way, you can silence them using the <option " +"role=\"hg-opt-global\">-q</option> option. You can also get them to print " +"the name of every file, even those you've named explicitly, using the <option " +"role=\"hg-opt-global\">-v</option> option." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch06-filenames.xml:100 +msgid "Using patterns to identify files" +msgstr "使用模式标识文件" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:102 +msgid "" +"In addition to working with file and directory names, Mercurial lets you use " +"<emphasis>patterns</emphasis> to identify files. Mercurial's pattern " +"handling is expressive." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:106 +msgid "" +"On Unix-like systems (Linux, MacOS, etc.), the job of matching file names to " +"patterns normally falls to the shell. On these systems, you must explicitly " +"tell Mercurial that a name is a pattern. On Windows, the shell does not " +"expand patterns, so Mercurial will automatically identify names that are " +"patterns, and expand them for you." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:113 +msgid "" +"To provide a pattern in place of a regular name on the command line, the " +"mechanism is simple:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:116 +msgid "" +"That is, a pattern is identified by a short text string that says what kind " +"of pattern this is, followed by a colon, followed by the actual pattern." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:120 +msgid "" +"Mercurial supports two kinds of pattern syntax. The most frequently used is " +"called <literal>glob</literal>; this is the same kind of pattern matching " +"used by the Unix shell, and should be familiar to Windows command prompt " +"users, too." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:125 +msgid "" +"When Mercurial does automatic pattern matching on Windows, it uses " +"<literal>glob</literal> syntax. You can thus omit the <quote><literal>glob:</" +"literal></quote> prefix on Windows, but it's safe to use it, too." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:130 +msgid "" +"The <literal>re</literal> syntax is more powerful; it lets you specify " +"patterns using regular expressions, also known as regexps." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:134 +msgid "" +"By the way, in the examples that follow, notice that I'm careful to wrap all " +"of my patterns in quote characters, so that they won't get expanded by the " +"shell before Mercurial sees them." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch06-filenames.xml:140 +msgid "Shell-style <literal>glob</literal> patterns" +msgstr "外壳风格的 <literal>glob</literal> 模式" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:142 +msgid "" +"This is an overview of the kinds of patterns you can use when you're matching " +"on glob patterns." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:145 +msgid "" +"The <quote><literal>*</literal></quote> character matches any string, within " +"a single directory." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:150 +msgid "" +"The <quote><literal>**</literal></quote> pattern matches any string, and " +"crosses directory boundaries. It's not a standard Unix glob token, but it's " +"accepted by several popular Unix shells, and is very useful." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:157 +msgid "" +"The <quote><literal>?</literal></quote> pattern matches any single character." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:162 +msgid "" +"The <quote><literal>[</literal></quote> character begins a " +"<emphasis>character class</emphasis>. This matches any single character " +"within the class. The class ends with a <quote><literal>]</literal></quote> " +"character. A class may contain multiple <emphasis>range</emphasis>s of the " +"form <quote><literal>a-f</literal></quote>, which is shorthand for " +"<quote><literal>abcdef</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:172 +msgid "" +"If the first character after the <quote><literal>[</literal></quote> in a " +"character class is a <quote><literal>!</literal></quote>, it " +"<emphasis>negates</emphasis> the class, making it match any single character " +"not in the class." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:178 +msgid "" +"A <quote><literal>{</literal></quote> begins a group of subpatterns, where " +"the whole group matches if any subpattern in the group matches. The " +"<quote><literal>,</literal></quote> character separates subpatterns, and " +"<quote><literal>}</literal></quote> ends the group." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch06-filenames.xml:187 +msgid "Watch out!" +msgstr "千万小心!" + +# +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch06-filenames.xml:189 +msgid "" +"Don't forget that if you want to match a pattern in any directory, you should " +"not be using the <quote><literal>*</literal></quote> match-any token, as this " +"will only match within one directory. Instead, use the <quote><literal>**</" +"literal></quote> token. This small example illustrates the difference " +"between the two." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch06-filenames.xml:201 +msgid "Regular expression matching with <literal>re</literal> patterns" +msgstr "使用 <literal>re</literal> 模式的正则表达式匹配" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:204 +msgid "" +"Mercurial accepts the same regular expression syntax as the Python " +"programming language (it uses Python's regexp engine internally). This is " +"based on the Perl language's regexp syntax, which is the most popular dialect " +"in use (it's also used in Java, for example)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:210 +msgid "" +"I won't discuss Mercurial's regexp dialect in any detail here, as regexps are " +"not often used. Perl-style regexps are in any case already exhaustively " +"documented on a multitude of web sites, and in many books. Instead, I will " +"focus here on a few things you should know if you find yourself needing to " +"use regexps with Mercurial." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:217 +msgid "" +"A regexp is matched against an entire file name, relative to the root of the " +"repository. In other words, even if you're already in subbdirectory " +"<filename class=\"directory\">foo</filename>, if you want to match files " +"under this directory, your pattern must start with <quote><literal>foo/</" +"literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:224 +msgid "" +"One thing to note, if you're familiar with Perl-style regexps, is that " +"Mercurial's are <emphasis>rooted</emphasis>. That is, a regexp starts " +"matching against the beginning of a string; it doesn't look for a match " +"anywhere within the string. To match anywhere in a string, start your " +"pattern with <quote><literal>.*</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch06-filenames.xml:234 +msgid "Filtering files" +msgstr "过滤文件" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:236 +msgid "" +"Not only does Mercurial give you a variety of ways to specify files; it lets " +"you further winnow those files using <emphasis>filters</emphasis>. Commands " +"that work with file names accept two filtering options." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch06-filenames.xml:241 +msgid "" +"<option role=\"hg-opt-global\">-I</option>, or <option role=\"hg-opt-global" +"\">--include</option>, lets you specify a pattern that file names must match " +"in order to be processed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch06-filenames.xml:246 +msgid "" +"<option role=\"hg-opt-global\">-X</option>, or <option role=\"hg-opt-global" +"\">--exclude</option>, gives you a way to <emphasis>avoid</emphasis> " +"processing files, if they match this pattern." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:251 +msgid "" +"You can provide multiple <option role=\"hg-opt-global\">-I</option> and " +"<option role=\"hg-opt-global\">-X</option> options on the command line, and " +"intermix them as you please. Mercurial interprets the patterns you provide " +"using glob syntax by default (but you can use regexps if you need to)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:258 +msgid "" +"You can read a <option role=\"hg-opt-global\">-I</option> filter as " +"<quote>process only the files that match this filter</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:264 +msgid "" +"The <option role=\"hg-opt-global\">-X</option> filter is best read as " +"<quote>process only the files that don't match this pattern</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch06-filenames.xml:272 +msgid "Ignoring unwanted files and directories" +msgstr "忽略不需要的文件和目录" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:274 +msgid "XXX." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch06-filenames.xml:278 +msgid "Case sensitivity" +msgstr "大小写敏感性" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:280 +msgid "" +"If you're working in a mixed development environment that contains both Linux " +"(or other Unix) systems and Macs or Windows systems, you should keep in the " +"back of your mind the knowledge that they treat the case (<quote>N</quote> " +"versus <quote>n</quote>) of file names in incompatible ways. This is not " +"very likely to affect you, and it's easy to deal with if it does, but it " +"could surprise you if you don't know about it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:289 +msgid "" +"Operating systems and filesystems differ in the way they handle the " +"<emphasis>case</emphasis> of characters in file and directory names. There " +"are three common ways to handle case in names." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch06-filenames.xml:294 +msgid "" +"Completely case insensitive. Uppercase and lowercase versions of a letter " +"are treated as identical, both when creating a file and during subsequent " +"accesses. This is common on older DOS-based systems." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch06-filenames.xml:299 +msgid "" +"Case preserving, but insensitive. When a file or directory is created, the " +"case of its name is stored, and can be retrieved and displayed by the " +"operating system. When an existing file is being looked up, its case is " +"ignored. This is the standard arrangement on Windows and MacOS. The names " +"<filename>foo</filename> and <filename>FoO</filename> identify the same " +"file. This treatment of uppercase and lowercase letters as interchangeable " +"is also referred to as <emphasis>case folding</emphasis>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch06-filenames.xml:310 +msgid "" +"Case sensitive. The case of a name is significant at all times. The names " +"<filename>foo</filename> and {FoO} identify different files. This is the way " +"Linux and Unix systems normally work." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch06-filenames.xml:316 +msgid "" +"On Unix-like systems, it is possible to have any or all of the above ways of " +"handling case in action at once. For example, if you use a USB thumb drive " +"formatted with a FAT32 filesystem on a Linux system, Linux will handle names " +"on that filesystem in a case preserving, but insensitive, way." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch06-filenames.xml:323 +msgid "Safe, portable repository storage" +msgstr "安全,可移植的版本库存储" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:325 +msgid "" +"Mercurial's repository storage mechanism is <emphasis>case safe</emphasis>. " +"It translates file names so that they can be safely stored on both case " +"sensitive and case insensitive filesystems. This means that you can use " +"normal file copying tools to transfer a Mercurial repository onto, for " +"example, a USB thumb drive, and safely move that drive and repository back " +"and forth between a Mac, a PC running Windows, and a Linux box." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch06-filenames.xml:336 +msgid "Detecting case conflicts" +msgstr "检测大小写冲突" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:338 +msgid "" +"When operating in the working directory, Mercurial honours the naming policy " +"of the filesystem where the working directory is located. If the filesystem " +"is case preserving, but insensitive, Mercurial will treat names that differ " +"only in case as the same." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:344 +msgid "" +"An important aspect of this approach is that it is possible to commit a " +"changeset on a case sensitive (typically Linux or Unix) filesystem that will " +"cause trouble for users on case insensitive (usually Windows and MacOS) " +"users. If a Linux user commits changes to two files, one named " +"<filename>myfile.c</filename> and the other named <filename>MyFile.C</" +"filename>, they will be stored correctly in the repository. And in the " +"working directories of other Linux users, they will be correctly represented " +"as separate files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:355 +msgid "" +"If a Windows or Mac user pulls this change, they will not initially have a " +"problem, because Mercurial's repository storage mechanism is case safe. " +"However, once they try to <command role=\"hg-cmd\">hg update</command> the " +"working directory to that changeset, or <command role=\"hg-cmd\">hg merge</" +"command> with that changeset, Mercurial will spot the conflict between the " +"two file names that the filesystem would treat as the same, and forbid the " +"update or merge from occurring." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch06-filenames.xml:367 +msgid "Fixing a case conflict" +msgstr "修正大小写冲突" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:369 +msgid "" +"If you are using Windows or a Mac in a mixed environment where some of your " +"collaborators are using Linux or Unix, and Mercurial reports a case folding " +"conflict when you try to <command role=\"hg-cmd\">hg update</command> or " +"<command role=\"hg-cmd\">hg merge</command>, the procedure to fix the problem " +"is simple." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:376 +msgid "" +"Just find a nearby Linux or Unix box, clone the problem repository onto it, " +"and use Mercurial's <command role=\"hg-cmd\">hg rename</command> command to " +"change the names of any offending files or directories so that they will no " +"longer cause case folding conflicts. Commit this change, <command role=\"hg-" +"cmd\">hg pull</command> or <command role=\"hg-cmd\">hg push</command> it " +"across to your Windows or MacOS system, and <command role=\"hg-cmd\">hg " +"update</command> to the revision with the non-conflicting names." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch06-filenames.xml:386 +msgid "" +"The changeset with case-conflicting names will remain in your project's " +"history, and you still won't be able to <command role=\"hg-cmd\">hg update</" +"command> your working directory to that changeset on a Windows or MacOS " +"system, but you can continue development unimpeded." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch06-filenames.xml:393 +msgid "" +"Prior to version 0.9.3, Mercurial did not use a case safe repository storage " +"mechanism, and did not detect case folding conflicts. If you are using an " +"older version of Mercurial on Windows or MacOS, I strongly recommend that you " +"upgrade." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch07-branch.xml:5 +msgid "Managing releases and branchy development" +msgstr "发布管理与分支开发" + +#. type: Content of: <book><chapter><para> +#: ../en/ch07-branch.xml:7 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><para> +#: ../en/ch07-branch.xml:12 +msgid "" +"Many software projects issue periodic <quote>major</quote> releases that " +"contain substantial new features. In parallel, they may issue <quote>minor</" +"quote> releases. These are usually identical to the major releases off which " +"they're based, but with a few bugs fixed." +msgstr "" + +#. type: Content of: <book><chapter><para> +#: ../en/ch07-branch.xml:18 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch07-branch.xml:25 +msgid "Giving a persistent name to a revision" +msgstr "给版本指定一个永久的名称" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:27 +msgid "" +"Once you decide that you'd like to call a particular revision a " +"<quote>release</quote>, 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;" +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:34 +msgid "" +"Mercurial lets you give a permanent name to any revision using the <command " +"role=\"hg-cmd\">hg tag</command> command. Not surprisingly, these names are " +"called <quote>tags</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:40 +msgid "" +"A tag is nothing more than a <quote>symbolic name</quote> 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:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch07-branch.xml:49 +msgid "Colon (ASCII 58, <quote><literal>:</literal></quote>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch07-branch.xml:52 +msgid "Carriage return (ASCII 13, <quote><literal>\\r</literal></quote>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch07-branch.xml:55 +msgid "Newline (ASCII 10, <quote><literal>\\n</literal></quote>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:59 +msgid "" +"You can use the <command role=\"hg-cmd\">hg tags</command> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:67 +msgid "" +"Notice that <literal>tip</literal> is listed in the output of <command role=" +"\"hg-cmd\">hg tags</command>. The <literal>tip</literal> tag is a special " +"<quote>floating</quote> tag, which always identifies the newest revision in " +"the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:73 +msgid "" +"In the output of the <command role=\"hg-cmd\">hg tags</command> 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 <literal>tip</" +"literal> is always going to be the first tag listed in the output of <command " +"role=\"hg-cmd\">hg tags</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:80 +msgid "" +"When you run <command role=\"hg-cmd\">hg log</command>, if it displays a " +"revision that has tags associated with it, it will print those tags." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:86 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:93 +msgid "" +"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 <quote>too many</quote> (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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:101 +msgid "" +"For example, if your project has milestones as frequent as every few days, " +"it's perfectly reasonable to tag each one of those. But if you have a " +"continuous build system that makes sure every revision can be built cleanly, " +"you'd be introducing a lot of noise if you were to tag every clean build. " +"Instead, you could tag failed builds (on the assumption that they're rare!), " +"or simply not use tags to track buildability." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:109 +msgid "" +"If you want to remove a tag that you no longer want, use <command role=\"hg-" +"cmd\">hg tag --remove</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:114 +msgid "" +"You can also modify a tag at any time, so that it identifies a different " +"revision, by simply issuing a new <command role=\"hg-cmd\">hg tag</command> " +"command. You'll have to use the <option role=\"hg-opt-tag\">-f</option> " +"option to tell Mercurial that you <emphasis>really</emphasis> want to update " +"the tag." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:123 +msgid "" +"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." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:129 +msgid "" +"Mercurial stores tags in a normal revision-controlled file in your " +"repository. If you've created any tags, you'll find them in a file named " +"<filename role=\"special\">.hgtags</filename>. When you run the <command " +"role=\"hg-cmd\">hg tag</command> command, Mercurial modifies this file, then " +"automatically commits the change to it. This means that every time you run " +"<command role=\"hg-cmd\">hg tag</command>, you'll see a corresponding " +"changeset in the output of <command role=\"hg-cmd\">hg log</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch07-branch.xml:142 +msgid "Handling tag conflicts during a merge" +msgstr "在合并期间处理标签冲突" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch07-branch.xml:144 +msgid "" +"You won't often need to care about the <filename role=\"special\">.hgtags</" +"filename> file, but it sometimes makes its presence known during a merge. " +"The format of the file is simple: it consists of a series of lines. Each " +"line starts with a changeset hash, followed by a space, followed by the name " +"of a tag." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch07-branch.xml:151 +msgid "" +"If you're resolving a conflict in the <filename role=\"special\">.hgtags</" +"filename> file during a merge, there's one twist to modifying the <filename " +"role=\"special\">.hgtags</filename> file: when Mercurial is parsing the tags " +"in a repository, it <emphasis>never</emphasis> reads the working copy of the " +"<filename role=\"special\">.hgtags</filename> file. Instead, it reads the " +"<emphasis>most recently committed</emphasis> revision of the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch07-branch.xml:161 +msgid "" +"An unfortunate consequence of this design is that you can't actually verify " +"that your merged <filename role=\"special\">.hgtags</filename> file is " +"correct until <emphasis>after</emphasis> you've committed a change. So if " +"you find yourself resolving a conflict on <filename role=\"special\">.hgtags</" +"filename> during a merge, be sure to run <command role=\"hg-cmd\">hg tags</" +"command> after you commit. If it finds an error in the <filename role=" +"\"special\">.hgtags</filename> file, it will report the location of the " +"error, which you can then fix and commit. You should then run <command role=" +"\"hg-cmd\">hg tags</command> again, just to be sure that your fix is correct." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch07-branch.xml:176 +msgid "Tags and cloning" +msgstr "标签与克隆" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch07-branch.xml:178 +msgid "" +"You may have noticed that the <command role=\"hg-cmd\">hg clone</command> " +"command has a <option role=\"hg-opt-clone\">-r</option> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch07-branch.xml:186 +msgid "" +"Recall that a tag is stored as a revision to the <filename role=\"special\">." +"hgtags</filename> file, so that when you create a tag, the changeset in which " +"it's recorded necessarily refers to an older changeset. When you run " +"<command role=\"hg-cmd\">hg clone -r foo</command> to clone a repository as " +"of tag <literal>foo</literal>, the new clone <emphasis>will not contain the " +"history that created the tag</emphasis> that you used to clone the " +"repository. The result is that you'll get exactly the right subset of the " +"project's history in the new repository, but <emphasis>not</emphasis> the tag " +"you might have expected." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch07-branch.xml:201 +msgid "When permanent tags are too much" +msgstr "当永久标签太多的时候" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch07-branch.xml:203 +msgid "" +"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 " +"<literal>4237e45506ee</literal> is really <literal>v2.0.2</literal>. If " +"you're trying to track down a subtle bug, you might want a tag to remind you " +"of something like <quote>Anne saw the symptoms with this revision</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch07-branch.xml:213 +msgid "" +"For cases like this, what you might want to use are <emphasis>local</" +"emphasis> tags. You can create a local tag with the <option role=\"hg-opt-tag" +"\">-l</option> option to the <command role=\"hg-cmd\">hg tag</command> " +"command. This will store the tag in a file called <filename role=\"special" +"\">.hg/localtags</filename>. Unlike <filename role=\"special\">.hgtags</" +"filename>, <filename role=\"special\">.hg/localtags</filename> is not " +"revision controlled. Any tags you create using <option role=\"hg-opt-tag\">-" +"l</option> remain strictly local to the repository you're currently working " +"in." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch07-branch.xml:228 +msgid "The flow of changes&emdash;big picture vs. little" +msgstr "修改流程&emdash;宏观与微观" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:230 +msgid "" +"To return to the outline I sketched at the beginning of a chapter, let's " +"think about a project that has multiple concurrent pieces of work under " +"development at once." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:234 +msgid "" +"There might be a push for a new <quote>main</quote> release; a new minor " +"bugfix release to the last main release; and an unexpected <quote>hot fix</" +"quote> to an old release that is now in maintenance mode." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:239 +msgid "" +"The usual way people refer to these different concurrent directions of " +"development is as <quote>branches</quote>. However, we've already seen " +"numerous times that Mercurial treats <emphasis>all of history</emphasis> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch07-branch.xml:246 +msgid "" +"<quote>Big picture</quote> branches represent the sweep of a project's " +"evolution; people give them names, and talk about them in conversation." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch07-branch.xml:250 +msgid "" +"<quote>Little picture</quote> branches are artefacts of the day-to-day " +"activity of developing and merging changes. They expose the narrative of how " +"the code was developed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch07-branch.xml:258 +msgid "Managing big-picture branches in repositories" +msgstr "在版本库中管理分支" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:260 +msgid "" +"The easiest way to isolate a <quote>big picture</quote> branch in Mercurial " +"is in a dedicated repository. If you have an existing shared " +"repository&emdash;let's call it <literal>myproject</literal>&emdash;that " +"reaches a <quote>1.0</quote> 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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:270 +msgid "" +"You can then clone a new shared <literal>myproject-1.0.1</literal> repository " +"as of that tag." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:276 +msgid "" +"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 <literal>myproject-1.0.1</" +"literal> repository, make their changes, and push them back." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:283 +msgid "" +"Meanwhile, development for the next major release can continue, isolated and " +"unabated, in the <literal>myproject</literal> repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch07-branch.xml:291 +msgid "Don't repeat yourself: merging across branches" +msgstr "不要重复劳动:在分支间合并" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:293 +msgid "" +"In many cases, if you have a bug to fix on a maintenance branch, the chances " +"are good that the bug exists on your project's main branch (and possibly " +"other maintenance branches, too). It's a rare developer who wants to fix the " +"same bug multiple times, so let's look at a few ways that Mercurial can help " +"you to manage these bugfixes without duplicating your work." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:301 +msgid "" +"In the simplest instance, all you need to do is pull changes from your " +"maintenance branch into your local clone of the target branch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:307 +msgid "" +"You'll then need to merge the heads of the two branches, and push back to the " +"main branch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch07-branch.xml:314 +msgid "Naming branches within one repository" +msgstr "版本库中的命名分支" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:316 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:323 +msgid "" +"If you're more in the <quote>power user</quote> category (<emphasis>and</" +"emphasis> 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 <quote>small picture</quote> and <quote>big " +"picture</quote> branches. While Mercurial works with multiple <quote>small " +"picture</quote> branches in a repository all the time (for example after you " +"pull changes in, but before you merge them), it can <emphasis>also</emphasis> " +"work with multiple <quote>big picture</quote> branches." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:334 +msgid "" +"The key to working this way is that Mercurial lets you assign a persistent " +"<emphasis>name</emphasis> to a branch. There always exists a branch named " +"<literal>default</literal>. Even before you start naming branches yourself, " +"you can find traces of the <literal>default</literal> branch if you look for " +"them." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:341 +msgid "" +"As an example, when you run the <command role=\"hg-cmd\">hg commit</command> " +"command, and it pops up your editor so that you can enter a commit message, " +"look for a line that contains the text <quote><literal>HG: branch default</" +"literal></quote> at the bottom. This is telling you that your commit will " +"occur on the branch named <literal>default</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:348 +msgid "" +"To start working with named branches, use the <command role=\"hg-cmd\">hg " +"branches</command> command. This command lists the named branches already " +"present in your repository, telling you which changeset is the tip of each." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:355 +msgid "" +"Since you haven't created any named branches yet, the only one that exists is " +"<literal>default</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:358 +msgid "" +"To find out what the <quote>current</quote> branch is, run the <command role=" +"\"hg-cmd\">hg branch</command> command, giving it no arguments. This tells " +"you what branch the parent of the current changeset is on." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:365 +msgid "" +"To create a new branch, run the <command role=\"hg-cmd\">hg branch</command> " +"command again. This time, give it one argument: the name of the branch you " +"want to create." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:371 +msgid "" +"After you've created a branch, you might wonder what effect the <command role=" +"\"hg-cmd\">hg branch</command> command has had. What do the <command role=" +"\"hg-cmd\">hg status</command> and <command role=\"hg-cmd\">hg tip</command> " +"commands report?" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:378 +msgid "" +"Nothing has changed in the working directory, and there's been no new history " +"created. As this suggests, running the <command role=\"hg-cmd\">hg branch</" +"command> command has no permanent effect; it only tells Mercurial what branch " +"name to use the <emphasis>next</emphasis> time you commit a changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:385 +msgid "" +"When you commit a change, Mercurial records the name of the branch on which " +"you committed. Once you've switched from the <literal>default</literal> " +"branch to another and committed, you'll see the name of the new branch show " +"up in the output of <command role=\"hg-cmd\">hg log</command>, <command role=" +"\"hg-cmd\">hg tip</command>, and other commands that display the same kind of " +"output." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:395 +msgid "" +"The <command role=\"hg-cmd\">hg log</command>-like commands will print the " +"branch name of every changeset that's not on the <literal>default</literal> " +"branch. As a result, if you never use named branches, you'll never see this " +"information." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:400 +msgid "" +"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 <command " +"role=\"hg-cmd\">hg branch</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:408 +msgid "" +"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.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch07-branch.xml:414 +msgid "Dealing with multiple named branches in a repository" +msgstr "在版本库中处理多个命名分支" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:417 +msgid "" +"If you have more than one named branch in a repository, Mercurial will " +"remember the branch that your working directory on when you start a command " +"like <command role=\"hg-cmd\">hg update</command> or <command role=\"hg-cmd" +"\">hg pull -u</command>. It will update the working directory to the tip of " +"this branch, no matter what the <quote>repo-wide</quote> tip is. To update " +"to a revision that's on a different named branch, you may need to use the " +"<option role=\"hg-opt-update\">-C</option> option to <command role=\"hg-cmd" +"\">hg update</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:427 +msgid "" +"This behaviour is a little subtle, so let's see it in action. First, let's " +"remind ourselves what branch we're currently on, and what branches are in our " +"repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:433 +msgid "" +"We're on the <literal>bar</literal> branch, but there also exists an older " +"<command role=\"hg-cmd\">hg foo</command> branch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:437 +msgid "" +"We can <command role=\"hg-cmd\">hg update</command> back and forth between " +"the tips of the <literal>foo</literal> and <literal>bar</literal> branches " +"without needing to use the <option role=\"hg-opt-update\">-C</option> option, " +"because this only involves going backwards and forwards linearly through our " +"change history." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:446 +msgid "" +"If we go back to the <literal>foo</literal> branch and then run <command role=" +"\"hg-cmd\">hg update</command>, it will keep us on <literal>foo</literal>, " +"not move us to the tip of <literal>bar</literal>." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:453 +msgid "" +"Committing a new change on the <literal>foo</literal> branch introduces a new " +"head." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch07-branch.xml:460 +msgid "Branch names and merging" +msgstr "分支名称与合并" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:462 +msgid "" +"As you've probably noticed, merges in Mercurial are not symmetrical. Let's " +"say our repository has two heads, 17 and 23. If I <command role=\"hg-cmd" +"\">hg update</command> to 17 and then <command role=\"hg-cmd\">hg merge</" +"command> with 23, Mercurial records 17 as the first parent of the merge, and " +"23 as the second. Whereas if I <command role=\"hg-cmd\">hg update</command> " +"to 23 and then <command role=\"hg-cmd\">hg merge</command> with 17, it " +"records 23 as the first parent, and 17 as the second." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:472 +msgid "" +"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 " +"<literal>foo</literal>, and you merge with <literal>bar</literal>, the branch " +"name will still be <literal>foo</literal> after you merge." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:479 +msgid "" +"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 <literal>foo</literal> " +"branch, and so are you. We commit different changes; I pull your changes; I " +"now have two heads, each claiming to be on the <literal>foo</literal> " +"branch. The result of a merge will be a single head on the <literal>foo</" +"literal> branch, as you might hope." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:487 +msgid "" +"But if I'm working on the <literal>bar</literal> branch, and I merge work " +"from the <literal>foo</literal> branch, the result will remain on the " +"<literal>bar</literal> branch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:493 +msgid "" +"To give a more concrete example, if I'm working on the <literal>bleeding-" +"edge</literal> branch, and I want to bring in the latest fixes from the " +"<literal>stable</literal> branch, Mercurial will choose the <quote>right</" +"quote> (<literal>bleeding-edge</literal>) branch name when I pull and merge " +"from <literal>stable</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch07-branch.xml:502 +msgid "Branch naming is generally useful" +msgstr "分支名称通常都很有用" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:504 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:509 +msgid "" +"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." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch07-branch.xml:514 +msgid "" +"If you're working with shared repositories, you can set up a <literal role=" +"\"hook\">pretxnchangegroup</literal> hook on each that will block incoming " +"changes that have the <quote>wrong</quote> branch name. This provides a " +"simple, but effective, defence against people accidentally pushing changes " +"from a <quote>bleeding edge</quote> branch to a <quote>stable</quote> " +"branch. Such a hook might look like this inside the shared repo's <filename " +"role=\"special\"> /.hgrc</filename>." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch08-undo.xml:5 +msgid "Finding and fixing mistakes" +msgstr "查找和修改错误" + +#. type: Content of: <book><chapter><para> +#: ../en/ch08-undo.xml:7 +msgid "" +"To err might be human, but to really handle the consequences well takes a top-" +"notch revision control system. In this chapter, we'll discuss some of the " +"techniques you can use when you find that a problem has crept into your " +"project. Mercurial has some highly capable features that will help you to " +"isolate the sources of problems, and to handle them appropriately." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch08-undo.xml:15 +msgid "Erasing local history" +msgstr "销毁本地历史" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:18 +msgid "The accidental commit" +msgstr "意外的提交" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:20 +msgid "" +"I have the occasional but persistent problem of typing rather more quickly " +"than I can think, which sometimes results in me committing a changeset that " +"is either incomplete or plain wrong. In my case, the usual kind of " +"incomplete changeset is one in which I've created a new source file, but " +"forgotten to <command role=\"hg-cmd\">hg add</command> it. A <quote>plain " +"wrong</quote> changeset is not as common, but no less annoying." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:31 +msgid "Rolling back a transaction" +msgstr "回滚一个事务" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:33 +msgid "" +"In section <xref linkend=\"sec.concepts.txn\"/>, I mentioned that Mercurial " +"treats each modification of a repository as a <emphasis>transaction</" +"emphasis>. Every time you commit a changeset or pull changes from another " +"repository, Mercurial remembers what you did. You can undo, or " +"<emphasis>roll back</emphasis>, exactly one of these actions using the " +"<command role=\"hg-cmd\">hg rollback</command> command. (See section <xref " +"linkend=\"sec.undo.rollback-after-push\"/> for an important caveat about the " +"use of this command.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:43 +msgid "" +"Here's a mistake that I often find myself making: committing a change in " +"which I've created a new file, but forgotten to <command role=\"hg-cmd\">hg " +"add</command> it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:50 +msgid "" +"Looking at the output of <command role=\"hg-cmd\">hg status</command> after " +"the commit immediately confirms the error." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:56 +msgid "" +"The commit captured the changes to the file <filename>a</filename>, but not " +"the new file <filename>b</filename>. If I were to push this changeset to a " +"repository that I shared with a colleague, the chances are high that " +"something in <filename>a</filename> would refer to <filename>b</filename>, " +"which would not be present in their repository when they pulled my changes. " +"I would thus become the object of some indignation." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:65 +msgid "" +"However, luck is with me&emdash;I've caught my error before I pushed the " +"changeset. I use the <command role=\"hg-cmd\">hg rollback</command> command, " +"and Mercurial makes that last changeset vanish." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:72 +msgid "" +"Notice that the changeset is no longer present in the repository's history, " +"and the working directory once again thinks that the file <filename>a</" +"filename> is modified. The commit and rollback have left the working " +"directory exactly as it was prior to the commit; the changeset has been " +"completely erased. I can now safely <command role=\"hg-cmd\">hg add</" +"command> the file <filename>b</filename>, and rerun my commit." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:85 +msgid "The erroneous pull" +msgstr "错误的抓取" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:87 +msgid "" +"It's common practice with Mercurial to maintain separate development branches " +"of a project in different repositories. Your development team might have one " +"shared repository for your project's <quote>0.9</quote> release, and another, " +"containing different changes, for the <quote>1.0</quote> release." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:94 +msgid "" +"Given this, you can imagine that the consequences could be messy if you had a " +"local <quote>0.9</quote> repository, and accidentally pulled changes from the " +"shared <quote>1.0</quote> repository into it. At worst, you could be paying " +"insufficient attention, and push those changes into the shared <quote>0.9</" +"quote> tree, confusing your entire team (but don't worry, we'll return to " +"this horror scenario later). However, it's more likely that you'll notice " +"immediately, because Mercurial will display the URL it's pulling from, or you " +"will see it pull a suspiciously large number of changes into the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:106 +msgid "" +"The <command role=\"hg-cmd\">hg rollback</command> command will work nicely " +"to expunge all of the changesets that you just pulled. Mercurial groups all " +"changes from one <command role=\"hg-cmd\">hg pull</command> into a single " +"transaction, so one <command role=\"hg-cmd\">hg rollback</command> is all you " +"need to undo this mistake." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:115 +msgid "Rolling back is useless once you've pushed" +msgstr "当完成推送后,回滚是无效的" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:117 +msgid "" +"The value of the <command role=\"hg-cmd\">hg rollback</command> command drops " +"to zero once you've pushed your changes to another repository. Rolling back " +"a change makes it disappear entirely, but <emphasis>only</emphasis> in the " +"repository in which you perform the <command role=\"hg-cmd\">hg rollback</" +"command>. Because a rollback eliminates history, there's no way for the " +"disappearance of a change to propagate between repositories." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:126 +msgid "" +"If you've pushed a change to another repository&emdash;particularly if it's a " +"shared repository&emdash;it has essentially <quote>escaped into the wild,</" +"quote> and you'll have to recover from your mistake in a different way. What " +"will happen if you push a changeset somewhere, then roll it back, then pull " +"from the repository you pushed to, is that the changeset will reappear in " +"your repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:135 +msgid "" +"(If you absolutely know for sure that the change you want to roll back is the " +"most recent change in the repository that you pushed to, <emphasis>and</" +"emphasis> you know that nobody else could have pulled it from that " +"repository, you can roll back the changeset there, too, but you really should " +"really not rely on this working reliably. If you do this, sooner or later a " +"change really will make it into a repository that you don't directly control " +"(or have forgotten about), and come back to bite you.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:147 +msgid "You can only roll back once" +msgstr "你只能回滚一次" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:149 +msgid "" +"Mercurial stores exactly one transaction in its transaction log; that " +"transaction is the most recent one that occurred in the repository. This " +"means that you can only roll back one transaction. If you expect to be able " +"to roll back one transaction, then its predecessor, this is not the behaviour " +"you will get." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:158 +msgid "" +"Once you've rolled back one transaction in a repository, you can't roll back " +"again in that repository until you perform another commit or pull." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch08-undo.xml:165 +msgid "Reverting the mistaken change" +msgstr "撤销错误的修改" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:167 +msgid "" +"If you make a modification to a file, and decide that you really didn't want " +"to change the file at all, and you haven't yet committed your changes, the " +"<command role=\"hg-cmd\">hg revert</command> command is the one you'll need. " +"It looks at the changeset that's the parent of the working directory, and " +"restores the contents of the file to their state as of that changeset. " +"(That's a long-winded way of saying that, in the normal case, it undoes your " +"modifications.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:176 +msgid "" +"Let's illustrate how the <command role=\"hg-cmd\">hg revert</command> command " +"works with yet another small example. We'll begin by modifying a file that " +"Mercurial is already tracking." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:183 +msgid "" +"If we don't want that change, we can simply <command role=\"hg-cmd\">hg " +"revert</command> the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:189 +msgid "" +"The <command role=\"hg-cmd\">hg revert</command> command provides us with an " +"extra degree of safety by saving our modified file with a <filename>.orig</" +"filename> extension." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:196 +msgid "" +"Here is a summary of the cases that the <command role=\"hg-cmd\">hg revert</" +"command> command can deal with. We will describe each of these in more " +"detail in the section that follows." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:201 +msgid "If you modify a file, it will restore the file to its unmodified state." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:204 +msgid "" +"If you <command role=\"hg-cmd\">hg add</command> a file, it will undo the " +"<quote>added</quote> state of the file, but leave the file itself untouched." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:208 +msgid "" +"If you delete a file without telling Mercurial, it will restore the file to " +"its unmodified contents." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:211 +msgid "" +"If you use the <command role=\"hg-cmd\">hg remove</command> command to remove " +"a file, it will undo the <quote>removed</quote> state of the file, and " +"restore the file to its unmodified contents." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:218 +msgid "File management errors" +msgstr "文件管理错误" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:220 +msgid "" +"The <command role=\"hg-cmd\">hg revert</command> command is useful for more " +"than just modified files. It lets you reverse the results of all of " +"Mercurial's file management commands&emdash;<command role=\"hg-cmd\">hg add</" +"command>, <command role=\"hg-cmd\">hg remove</command>, and so on." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:226 +msgid "" +"If you <command role=\"hg-cmd\">hg add</command> a file, then decide that in " +"fact you don't want Mercurial to track it, use <command role=\"hg-cmd\">hg " +"revert</command> to undo the add. Don't worry; Mercurial will not modify the " +"file in any way. It will just <quote>unmark</quote> the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:234 +msgid "" +"Similarly, if you ask Mercurial to <command role=\"hg-cmd\">hg remove</" +"command> a file, you can use <command role=\"hg-cmd\">hg revert</command> to " +"restore it to the contents it had as of the parent of the working directory. " +"&interaction.daily.revert.remove; This works just as well for a file that you " +"deleted by hand, without telling Mercurial (recall that in Mercurial " +"terminology, this kind of file is called <quote>missing</quote>)." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:245 +msgid "" +"If you revert a <command role=\"hg-cmd\">hg copy</command>, the copied-to " +"file remains in your working directory afterwards, untracked. Since a copy " +"doesn't affect the copied-from file in any way, Mercurial doesn't do anything " +"with the copied-from file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch08-undo.xml:254 +msgid "A slightly special case: reverting a rename" +msgstr "一个稍微特别的案例:撤销改名" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch08-undo.xml:256 +msgid "" +"If you <command role=\"hg-cmd\">hg rename</command> a file, there is one " +"small detail that you should remember. When you <command role=\"hg-cmd\">hg " +"revert</command> a rename, it's not enough to provide the name of the renamed-" +"to file, as you can see here." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch08-undo.xml:264 +msgid "" +"As you can see from the output of <command role=\"hg-cmd\">hg status</" +"command>, the renamed-to file is no longer identified as added, but the " +"renamed-<emphasis>from</emphasis> file is still removed! This is counter-" +"intuitive (at least to me), but at least it's easy to deal with." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch08-undo.xml:273 +msgid "" +"So remember, to revert a <command role=\"hg-cmd\">hg rename</command>, you " +"must provide <emphasis>both</emphasis> the source and destination names." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch08-undo.xml:278 +msgid "% TODO: the output doesn't look like it will be removed!" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch08-undo.xml:281 +msgid "" +"(By the way, if you rename a file, then modify the renamed-to file, then " +"revert both components of the rename, when Mercurial restores the file that " +"was removed as part of the rename, it will be unmodified. If you need the " +"modifications in the renamed-to file to show up in the renamed-from file, " +"don't forget to copy them over.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch08-undo.xml:288 +msgid "" +"These fiddly aspects of reverting a rename arguably constitute a small bug in " +"Mercurial." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch08-undo.xml:295 +msgid "Dealing with committed changes" +msgstr "处理已经提交的修改" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:297 +msgid "" +"Consider a case where you have committed a change $a$, and another change $b$ " +"on top of it; you then realise that change $a$ was incorrect. Mercurial lets " +"you <quote>back out</quote> an entire changeset automatically, and building " +"blocks that let you reverse part of a changeset by hand." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:303 +msgid "" +"Before you read this section, here's something to keep in mind: the <command " +"role=\"hg-cmd\">hg backout</command> command undoes changes by " +"<emphasis>adding</emphasis> history, not by modifying or erasing it. It's " +"the right tool to use if you're fixing bugs, but not if you're trying to undo " +"some change that has catastrophic consequences. To deal with those, see " +"section <xref linkend=\"sec.undo.aaaiiieee\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:312 +msgid "Backing out a changeset" +msgstr "恢复一个修改集" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:314 +msgid "" +"The <command role=\"hg-cmd\">hg backout</command> command lets you " +"<quote>undo</quote> the effects of an entire changeset in an automated " +"fashion. Because Mercurial's history is immutable, this command " +"<emphasis>does not</emphasis> get rid of the changeset you want to undo. " +"Instead, it creates a new changeset that <emphasis>reverses</emphasis> the " +"effect of the to-be-undone changeset." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:323 +msgid "" +"The operation of the <command role=\"hg-cmd\">hg backout</command> command is " +"a little intricate, so let's illustrate it with some examples. First, we'll " +"create a repository with some simple changes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:330 +msgid "" +"The <command role=\"hg-cmd\">hg backout</command> command takes a single " +"changeset ID as its argument; this is the changeset to back out. Normally, " +"<command role=\"hg-cmd\">hg backout</command> will drop you into a text " +"editor to write a commit message, so you can record why you're backing the " +"change out. In this example, we provide a commit message on the command line " +"using the <option role=\"hg-opt-backout\">-m</option> option." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:341 +msgid "Backing out the tip changeset" +msgstr "恢复顶点修改集" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:343 +msgid "We're going to start by backing out the last changeset we committed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:348 +msgid "" +"You can see that the second line from <filename>myfile</filename> is no " +"longer present. Taking a look at the output of <command role=\"hg-cmd\">hg " +"log</command> gives us an idea of what the <command role=\"hg-cmd\">hg " +"backout</command> command has done. &interaction.backout.simple.log; Notice " +"that the new changeset that <command role=\"hg-cmd\">hg backout</command> has " +"created is a child of the changeset we backed out. It's easier to see this " +"in figure <xref endterm=\"fig.undo.backout.caption\" linkend=\"fig.undo." +"backout\"/>, which presents a graphical view of the change history. As you " +"can see, the history is nice and linear." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch08-undo.xml:364 +msgid "" +"<imageobject><imagedata fileref=\"images/undo-simple.png\"/> </imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch08-undo.xml:367 ../en/ch08-undo.xml:486 +msgid "" +"Backing out a change using the <command role=\"hg-cmd\">hg backout</command> " +"command" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:376 +msgid "Backing out a non-tip change" +msgstr "恢复非顶点的修改" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:378 +msgid "" +"If you want to back out a change other than the last one you committed, pass " +"the <option role=\"hg-opt-backout\">--merge</option> option to the <command " +"role=\"hg-cmd\">hg backout</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:385 +msgid "" +"This makes backing out any changeset a <quote>one-shot</quote> operation " +"that's usually simple and fast." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:391 +msgid "" +"If you take a look at the contents of <filename>myfile</filename> after the " +"backout finishes, you'll see that the first and third changes are present, " +"but not the second." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:398 +msgid "" +"As the graphical history in figure <xref endterm=\"fig.undo.backout-non-tip." +"caption\" linkend=\"fig.undo.backout-non-tip\"/> illustrates, Mercurial " +"actually commits <emphasis>two</emphasis> changes in this kind of situation " +"(the box-shaped nodes are the ones that Mercurial commits automatically). " +"Before Mercurial begins the backout process, it first remembers what the " +"current parent of the working directory is. It then backs out the target " +"changeset, and commits that as a changeset. Finally, it merges back to the " +"previous parent of the working directory, and commits the result of the merge." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:410 +msgid "" +"% TODO: to me it looks like mercurial doesn't commit the second merge " +"automatically!" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch08-undo.xml:415 +msgid "" +"<imageobject><imagedata fileref=\"images/undo-non-tip.png\"/> </imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch08-undo.xml:418 +msgid "" +"Automated backout of a non-tip change using the <command role=\"hg-cmd\">hg " +"backout</command> command" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:424 +msgid "" +"The result is that you end up <quote>back where you were</quote>, only with " +"some extra history that undoes the effect of the changeset you wanted to back " +"out." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch08-undo.xml:429 +msgid "Always use the <option role=\"hg-opt-backout\">--merge</option> option" +msgstr "始终使用选项 <option role=\"hg-opt-backout\">--merge</option>" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch08-undo.xml:432 +msgid "" +"In fact, since the <option role=\"hg-opt-backout\">--merge</option> option " +"will do the <quote>right thing</quote> whether or not the changeset you're " +"backing out is the tip (i.e. it won't try to merge if it's backing out the " +"tip, since there's no need), you should <emphasis>always</emphasis> use this " +"option when you run the <command role=\"hg-cmd\">hg backout</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:443 +msgid "Gaining more control of the backout process" +msgstr "在恢复处理中获得更多控制" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:445 +msgid "" +"While I've recommended that you always use the <option role=\"hg-opt-backout" +"\">--merge</option> option when backing out a change, the <command role=\"hg-" +"cmd\">hg backout</command> command lets you decide how to merge a backout " +"changeset. Taking control of the backout process by hand is something you " +"will rarely need to do, but it can be useful to understand what the <command " +"role=\"hg-cmd\">hg backout</command> command is doing for you automatically. " +"To illustrate this, let's clone our first repository, but omit the backout " +"change that it contains." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:458 +msgid "" +"As with our earlier example, We'll commit a third changeset, then back out " +"its parent, and see what happens." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:464 +msgid "" +"Our new changeset is again a descendant of the changeset we backout out; it's " +"thus a new head, <emphasis>not</emphasis> a descendant of the changeset that " +"was the tip. The <command role=\"hg-cmd\">hg backout</command> command was " +"quite explicit in telling us this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:472 +msgid "" +"Again, it's easier to see what has happened by looking at a graph of the " +"revision history, in figure <xref endterm=\"fig.undo.backout-manual.caption\" " +"linkend=\"fig.undo.backout-manual\"/>. This makes it clear that when we use " +"<command role=\"hg-cmd\">hg backout</command> to back out a change other than " +"the tip, Mercurial adds a new head to the repository (the change it committed " +"is box-shaped)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch08-undo.xml:483 +msgid "" +"<imageobject><imagedata fileref=\"images/undo-manual.png\"/> </imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:492 +msgid "" +"After the <command role=\"hg-cmd\">hg backout</command> command has " +"completed, it leaves the new <quote>backout</quote> changeset as the parent " +"of the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:499 +msgid "Now we have two isolated sets of changes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:503 +msgid "" +"Let's think about what we expect to see as the contents of <filename>myfile</" +"filename> now. The first change should be present, because we've never " +"backed it out. The second change should be missing, as that's the change we " +"backed out. Since the history graph shows the third change as a separate " +"head, we <emphasis>don't</emphasis> expect to see the third change present in " +"<filename>myfile</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:513 +msgid "" +"To get the third change back into the file, we just do a normal merge of our " +"two heads." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:518 +msgid "" +"Afterwards, the graphical history of our repository looks like figure <xref " +"endterm=\"fig.undo.backout-manual-merge.caption\" linkend=\"fig.undo.backout-" +"manual-merge\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch08-undo.xml:525 +msgid "" +"<imageobject><imagedata fileref=\"images/undo-manual-merge.png\"/> </" +"imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch08-undo.xml:528 +msgid "Manually merging a backout change" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:535 +msgid "Why <command role=\"hg-cmd\">hg backout</command> works as it does" +msgstr "<command role=\"hg-cmd\">hg backout</command> 的内幕" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:538 +msgid "" +"Here's a brief description of how the <command role=\"hg-cmd\">hg backout</" +"command> command works." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:541 +msgid "" +"It ensures that the working directory is <quote>clean</quote>, i.e. that the " +"output of <command role=\"hg-cmd\">hg status</command> would be empty." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:545 +msgid "" +"It remembers the current parent of the working directory. Let's call this " +"changeset <literal>orig</literal>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:549 +msgid "" +"It does the equivalent of a <command role=\"hg-cmd\">hg update</command> to " +"sync the working directory to the changeset you want to back out. Let's call " +"this changeset <literal>backout</literal>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:554 +msgid "" +"It finds the parent of that changeset. Let's call that changeset " +"<literal>parent</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:557 +msgid "" +"For each file that the <literal>backout</literal> changeset affected, it does " +"the equivalent of a <command role=\"hg-cmd\">hg revert -r parent</command> on " +"that file, to restore it to the contents it had before that changeset was " +"committed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:564 +msgid "" +"It commits the result as a new changeset. This changeset has " +"<literal>backout</literal> as its parent." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:568 +msgid "" +"If you specify <option role=\"hg-opt-backout\">--merge</option> on the " +"command line, it merges with <literal>orig</literal>, and commits the result " +"of the merge." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:574 +msgid "" +"An alternative way to implement the <command role=\"hg-cmd\">hg backout</" +"command> command would be to <command role=\"hg-cmd\">hg export</command> the " +"to-be-backed-out changeset as a diff, then use the <option role=\"cmd-opt-" +"patch\">--reverse</option> option to the <command>patch</command> command to " +"reverse the effect of the change without fiddling with the working " +"directory. This sounds much simpler, but it would not work nearly as well." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:584 +msgid "" +"The reason that <command role=\"hg-cmd\">hg backout</command> does an update, " +"a commit, a merge, and another commit is to give the merge machinery the best " +"chance to do a good job when dealing with all the changes <emphasis>between</" +"emphasis> the change you're backing out and the current tip." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:591 +msgid "" +"If you're backing out a changeset that's 100 revisions back in your project's " +"history, the chances that the <command>patch</command> command will be able " +"to apply a reverse diff cleanly are not good, because intervening changes are " +"likely to have <quote>broken the context</quote> that <command>patch</" +"command> uses to determine whether it can apply a patch (if this sounds like " +"gibberish, see <xref linkend=\"sec.mq.patch\"/> for a discussion of the " +"<command>patch</command> command). Also, Mercurial's merge machinery will " +"handle files and directories being renamed, permission changes, and " +"modifications to binary files, none of which <command>patch</command> can " +"deal with." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch08-undo.xml:608 +msgid "Changes that should never have been" +msgstr "不该发生的修改" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:610 +msgid "" +"Most of the time, the <command role=\"hg-cmd\">hg backout</command> command " +"is exactly what you need if you want to undo the effects of a change. It " +"leaves a permanent record of exactly what you did, both when committing the " +"original changeset and when you cleaned up after it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:616 +msgid "" +"On rare occasions, though, you may find that you've committed a change that " +"really should not be present in the repository at all. For example, it would " +"be very unusual, and usually considered a mistake, to commit a software " +"project's object files as well as its source files. Object files have almost " +"no intrinsic value, and they're <emphasis>big</emphasis>, so they increase " +"the size of the repository and the amount of time it takes to clone or pull " +"changes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:625 +msgid "" +"Before I discuss the options that you have if you commit a <quote>brown paper " +"bag</quote> change (the kind that's so bad that you want to pull a brown " +"paper bag over your head), let me first discuss some approaches that probably " +"won't work." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:630 +msgid "" +"Since Mercurial treats history as accumulative&emdash;every change builds on " +"top of all changes that preceded it&emdash;you generally can't just make " +"disastrous changes disappear. The one exception is when you've just " +"committed a change, and it hasn't been pushed or pulled into another " +"repository. That's when you can safely use the <command role=\"hg-cmd\">hg " +"rollback</command> command, as I detailed in section <xref linkend=\"sec.undo." +"rollback\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:639 +msgid "" +"After you've pushed a bad change to another repository, you <emphasis>could</" +"emphasis> still use <command role=\"hg-cmd\">hg rollback</command> to make " +"your local copy of the change disappear, but it won't have the consequences " +"you want. The change will still be present in the remote repository, so it " +"will reappear in your local repository the next time you pull." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:647 +msgid "" +"If a situation like this arises, and you know which repositories your bad " +"change has propagated into, you can <emphasis>try</emphasis> to get rid of " +"the changeefrom <emphasis>every</emphasis> one of those repositories. This " +"is, of course, not a satisfactory solution: if you miss even a single " +"repository while you're expunging, the change is still <quote>in the wild</" +"quote>, and could propagate further." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:655 +msgid "" +"If you've committed one or more changes <emphasis>after</emphasis> the change " +"that you'd like to see disappear, your options are further reduced. Mercurial " +"doesn't provide a way to <quote>punch a hole</quote> in history, leaving " +"changesets intact." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:661 +msgid "" +"XXX This needs filling out. The <literal>hg-replay</literal> script in the " +"<literal>examples</literal> directory works, but doesn't handle merge " +"changesets. Kind of an important omission." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:667 +msgid "Protect yourself from <quote>escaped</quote> changes" +msgstr "使用<quote>校验</quote>修改来保护你自己" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:670 +msgid "" +"If you've committed some changes to your local repository and they've been " +"pushed or pulled somewhere else, this isn't necessarily a disaster. You can " +"protect yourself ahead of time against some classes of bad changeset. This " +"is particularly easy if your team usually pulls changes from a central " +"repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:677 +msgid "" +"By configuring some hooks on that repository to validate incoming changesets " +"(see chapter <xref linkend=\"chap.hook\"/>), you can automatically prevent " +"some kinds of bad changeset from being pushed to the central repository at " +"all. With such a configuration in place, some kinds of bad changeset will " +"naturally tend to <quote>die out</quote> because they can't propagate into " +"the central repository. Better yet, this happens without any need for " +"explicit intervention." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:687 +msgid "" +"For instance, an incoming change hook that verifies that a changeset will " +"actually compile can prevent people from inadvertantly <quote>breaking the " +"build</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch08-undo.xml:694 +msgid "Finding the source of a bug" +msgstr "查找问题的根源" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:696 +msgid "" +"While it's all very well to be able to back out a changeset that introduced a " +"bug, this requires that you know which changeset to back out. Mercurial " +"provides an invaluable command, called <command role=\"hg-cmd\">hg bisect</" +"command>, that helps you to automate this process and accomplish it very " +"efficiently." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:703 +msgid "" +"The idea behind the <command role=\"hg-cmd\">hg bisect</command> command is " +"that a changeset has introduced some change of behaviour that you can " +"identify with a simple binary test. You don't know which piece of code " +"introduced the change, but you know how to test for the presence of the bug. " +"The <command role=\"hg-cmd\">hg bisect</command> command uses your test to " +"direct its search for the changeset that introduced the code that caused the " +"bug." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:712 +msgid "" +"Here are a few scenarios to help you understand how you might apply this " +"command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:715 +msgid "" +"The most recent version of your software has a bug that you remember wasn't " +"present a few weeks ago, but you don't know when it was introduced. Here, " +"your binary test checks for the presence of that bug." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:720 +msgid "" +"You fixed a bug in a rush, and now it's time to close the entry in your " +"team's bug database. The bug database requires a changeset ID when you close " +"an entry, but you don't remember which changeset you fixed the bug in. Once " +"again, your binary test checks for the presence of the bug." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:727 +msgid "" +"Your software works correctly, but runs 15% slower than the last time you " +"measured it. You want to know which changeset introduced the performance " +"regression. In this case, your binary test measures the performance of your " +"software, to see whether it's <quote>fast</quote> or <quote>slow</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:734 +msgid "" +"The sizes of the components of your project that you ship exploded recently, " +"and you suspect that something changed in the way you build your project." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:739 +msgid "" +"From these examples, it should be clear that the <command role=\"hg-cmd\">hg " +"bisect</command> command is not useful only for finding the sources of bugs. " +"You can use it to find any <quote>emergent property</quote> of a repository " +"(anything that you can't find from a simple text search of the files in the " +"tree) for which you can write a binary test." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:746 +msgid "" +"We'll introduce a little bit of terminology here, just to make it clear which " +"parts of the search process are your responsibility, and which are " +"Mercurial's. A <emphasis>test</emphasis> is something that <emphasis>you</" +"emphasis> run when <command role=\"hg-cmd\">hg bisect</command> chooses a " +"changeset. A <emphasis>probe</emphasis> is what <command role=\"hg-cmd\">hg " +"bisect</command> runs to tell whether a revision is good. Finally, we'll use " +"the word <quote>bisect</quote>, as both a noun and a verb, to stand in for " +"the phrase <quote>search using the <command role=\"hg-cmd\">hg bisect</" +"command> command</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:759 +msgid "" +"One simple way to automate the searching process would be simply to probe " +"every changeset. However, this scales poorly. If it took ten minutes to " +"test a single changeset, and you had 10,000 changesets in your repository, " +"the exhaustive approach would take on average 35 <emphasis>days</emphasis> to " +"find the changeset that introduced a bug. Even if you knew that the bug was " +"introduced by one of the last 500 changesets, and limited your search to " +"those, you'd still be looking at over 40 hours to find the changeset that " +"introduced your bug." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:769 +msgid "" +"What the <command role=\"hg-cmd\">hg bisect</command> command does is use its " +"knowledge of the <quote>shape</quote> of your project's revision history to " +"perform a search in time proportional to the <emphasis>logarithm</emphasis> " +"of the number of changesets to check (the kind of search it performs is " +"called a dichotomic search). With this approach, searching through 10,000 " +"changesets will take less than three hours, even at ten minutes per test (the " +"search will require about 14 tests). Limit your search to the last hundred " +"changesets, and it will take only about an hour (roughly seven tests)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch08-undo.xml:780 +msgid "" +"The <command role=\"hg-cmd\">hg bisect</command> command is aware of the " +"<quote>branchy</quote> nature of a Mercurial project's revision history, so " +"it has no problems dealing with branches, merges, or multiple heads in a " +"repository. It can prune entire branches of history with a single probe, " +"which is how it operates so efficiently." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:788 +msgid "Using the <command role=\"hg-cmd\">hg bisect</command> command" +msgstr "使用命令 <command role=\"hg-cmd\">hg bisect</command>" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:791 +msgid "" +"Here's an example of <command role=\"hg-cmd\">hg bisect</command> in action." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch08-undo.xml:795 +msgid "" +"In versions 0.9.5 and earlier of Mercurial, <command role=\"hg-cmd\">hg " +"bisect</command> was not a core command: it was distributed with Mercurial as " +"an extension. This section describes the built-in command, not the old " +"extension." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:802 +msgid "" +"Now let's create a repository, so that we can try out the <command role=\"hg-" +"cmd\">hg bisect</command> command in isolation." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:808 +msgid "" +"We'll simulate a project that has a bug in it in a simple-minded way: create " +"trivial changes in a loop, and nominate one specific change that will have " +"the <quote>bug</quote>. This loop creates 35 changesets, each adding a " +"single file to the repository. We'll represent our <quote>bug</quote> with a " +"file that contains the text <quote>i have a gub</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:818 +msgid "" +"The next thing that we'd like to do is figure out how to use the <command " +"role=\"hg-cmd\">hg bisect</command> command. We can use Mercurial's normal " +"built-in help mechanism for this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:825 +msgid "" +"The <command role=\"hg-cmd\">hg bisect</command> command works in steps. " +"Each step proceeds as follows." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:828 +msgid "You run your binary test." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:830 +msgid "" +"If the test succeeded, you tell <command role=\"hg-cmd\">hg bisect</command> " +"by running the <command role=\"hg-cmd\">hg bisect good</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:835 +msgid "" +"If it failed, run the <command role=\"hg-cmd\">hg bisect bad</command> " +"command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:839 +msgid "" +"The command uses your information to decide which changeset to test next." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> +#: ../en/ch08-undo.xml:842 +msgid "" +"It updates the working directory to that changeset, and the process begins " +"again." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:845 +msgid "" +"The process ends when <command role=\"hg-cmd\">hg bisect</command> identifies " +"a unique changeset that marks the point where your test transitioned from " +"<quote>succeeding</quote> to <quote>failing</quote>." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:850 +msgid "" +"To start the search, we must run the <command role=\"hg-cmd\">hg bisect --" +"reset</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:855 +msgid "" +"In our case, the binary test we use is simple: we check to see if any file in " +"the repository contains the string <quote>i have a gub</quote>. If it does, " +"this changeset contains the change that <quote>caused the bug</quote>. By " +"convention, a changeset that has the property we're searching for is " +"<quote>bad</quote>, while one that doesn't is <quote>good</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:863 +msgid "" +"Most of the time, the revision to which the working directory is synced " +"(usually the tip) already exhibits the problem introduced by the buggy " +"change, so we'll mark it as <quote>bad</quote>." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:870 +msgid "" +"Our next task is to nominate a changeset that we know <emphasis>doesn't</" +"emphasis> have the bug; the <command role=\"hg-cmd\">hg bisect</command> " +"command will <quote>bracket</quote> its search between the first pair of good " +"and bad changesets. In our case, we know that revision 10 didn't have the " +"bug. (I'll have more words about choosing the first <quote>good</quote> " +"changeset later.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:880 +msgid "Notice that this command printed some output." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:882 +msgid "" +"It told us how many changesets it must consider before it can identify the " +"one that introduced the bug, and how many tests that will require." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:886 +msgid "" +"It updated the working directory to the next changeset to test, and told us " +"which changeset it's testing." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:891 +msgid "" +"We now run our test in the working directory. We use the <command>grep</" +"command> command to see if our <quote>bad</quote> file is present in the " +"working directory. If it is, this revision is bad; if not, this revision is " +"good. &interaction.bisect.search.step1;" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:897 +msgid "" +"This test looks like a perfect candidate for automation, so let's turn it " +"into a shell function." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:901 +msgid "" +"We can now run an entire test step with a single command, <literal>mytest</" +"literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:906 +msgid "A few more invocations of our canned test step command, and we're done." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:911 +msgid "" +"Even though we had 40 changesets to search through, the <command role=\"hg-cmd" +"\">hg bisect</command> command let us find the changeset that introduced our " +"<quote>bug</quote> with only five tests. Because the number of tests that " +"the <command role=\"hg-cmd\">hg bisect</command> command performs grows " +"logarithmically with the number of changesets to search, the advantage that " +"it has over the <quote>brute force</quote> search approach increases with " +"every changeset you add." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:922 +msgid "Cleaning up after your search" +msgstr "搜索后的清理" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:924 +msgid "" +"When you're finished using the <command role=\"hg-cmd\">hg bisect</command> " +"command in a repository, you can use the <command role=\"hg-cmd\">hg bisect " +"reset</command> command to drop the information it was using to drive your " +"search. The command doesn't use much space, so it doesn't matter if you " +"forget to run this command. However, <command role=\"hg-cmd\">hg bisect</" +"command> won't let you start a new search in that repository until you do a " +"<command role=\"hg-cmd\">hg bisect reset</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch08-undo.xml:939 +msgid "Tips for finding bugs effectively" +msgstr "有效查找问题的技巧" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:942 +msgid "Give consistent input" +msgstr "给出一致的输入" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:944 +msgid "" +"The <command role=\"hg-cmd\">hg bisect</command> command requires that you " +"correctly report the result of every test you perform. If you tell it that a " +"test failed when it really succeeded, it <emphasis>might</emphasis> be able " +"to detect the inconsistency. If it can identify an inconsistency in your " +"reports, it will tell you that a particular changeset is both good and bad. " +"However, it can't do this perfectly; it's about as likely to report the wrong " +"changeset as the source of the bug." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:956 +msgid "Automate as much as possible" +msgstr "尽量自动" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:958 +msgid "" +"When I started using the <command role=\"hg-cmd\">hg bisect</command> " +"command, I tried a few times to run my tests by hand, on the command line. " +"This is an approach that I, at least, am not suited to. After a few tries, I " +"found that I was making enough mistakes that I was having to restart my " +"searches several times before finally getting correct results." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:966 +msgid "" +"My initial problems with driving the <command role=\"hg-cmd\">hg bisect</" +"command> command by hand occurred even with simple searches on small " +"repositories; if the problem you're looking for is more subtle, or the number " +"of tests that <command role=\"hg-cmd\">hg bisect</command> must perform " +"increases, the likelihood of operator error ruining the search is much " +"higher. Once I started automating my tests, I had much better results." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:975 +msgid "The key to automated testing is twofold:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:977 +msgid "always test for the same symptom, and" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:979 +msgid "" +"always feed consistent input to the <command role=\"hg-cmd\">hg bisect</" +"command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:982 +msgid "" +"In my tutorial example above, the <command>grep</command> command tests for " +"the symptom, and the <literal>if</literal> statement takes the result of this " +"check and ensures that we always feed the same input to the <command role=" +"\"hg-cmd\">hg bisect</command> command. The <literal>mytest</literal> " +"function marries these together in a reproducible way, so that every test is " +"uniform and consistent." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:992 +msgid "Check your results" +msgstr "检查你的结果" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:994 +msgid "" +"Because the output of a <command role=\"hg-cmd\">hg bisect</command> search " +"is only as good as the input you give it, don't take the changeset it reports " +"as the absolute truth. A simple way to cross-check its report is to manually " +"run your test at each of the following changesets:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:1000 +msgid "" +"The changeset that it reports as the first bad revision. Your test should " +"still report this as bad." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:1004 +msgid "" +"The parent of that changeset (either parent, if it's a merge). Your test " +"should report this changeset as good." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch08-undo.xml:1008 +msgid "" +"A child of that changeset. Your test should report this changeset as bad." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:1014 +msgid "Beware interference between bugs" +msgstr "谨防问题之间的冲突" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:1016 +msgid "" +"It's possible that your search for one bug could be disrupted by the presence " +"of another. For example, let's say your software crashes at revision 100, " +"and worked correctly at revision 50. Unknown to you, someone else introduced " +"a different crashing bug at revision 60, and fixed it at revision 80. This " +"could distort your results in one of several ways." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:1024 +msgid "" +"It is possible that this other bug completely <quote>masks</quote> yours, " +"which is to say that it occurs before your bug has a chance to manifest " +"itself. If you can't avoid that other bug (for example, it prevents your " +"project from building), and so can't tell whether your bug is present in a " +"particular changeset, the <command role=\"hg-cmd\">hg bisect</command> " +"command cannot help you directly. Instead, you can mark a changeset as " +"untested by running <command role=\"hg-cmd\">hg bisect --skip</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:1034 +msgid "" +"A different problem could arise if your test for a bug's presence is not " +"specific enough. If you check for <quote>my program crashes</quote>, then " +"both your crashing bug and an unrelated crashing bug that masks it will look " +"like the same thing, and mislead <command role=\"hg-cmd\">hg bisect</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:1041 +msgid "" +"Another useful situation in which to use <command role=\"hg-cmd\">hg bisect --" +"skip</command> is if you can't test a revision because your project was in a " +"broken and hence untestable state at that revision, perhaps because someone " +"checked in a change that prevented the project from building." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch08-undo.xml:1050 +msgid "Bracket your search lazily" +msgstr "减少你的查找工作" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:1052 +msgid "" +"Choosing the first <quote>good</quote> and <quote>bad</quote> changesets that " +"will mark the end points of your search is often easy, but it bears a little " +"discussion nevertheless. From the perspective of <command role=\"hg-cmd\">hg " +"bisect</command>, the <quote>newest</quote> changeset is conventionally " +"<quote>bad</quote>, and the older changeset is <quote>good</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:1060 +msgid "" +"If you're having trouble remembering when a suitable <quote>good</quote> " +"change was, so that you can tell <command role=\"hg-cmd\">hg bisect</" +"command>, you could do worse than testing changesets at random. Just " +"remember to eliminate contenders that can't possibly exhibit the bug (perhaps " +"because the feature with the bug isn't present yet) and those where another " +"problem masks the bug (as I discussed above)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch08-undo.xml:1069 +msgid "" +"Even if you end up <quote>early</quote> by thousands of changesets or months " +"of history, you will only add a handful of tests to the total number that " +"<command role=\"hg-cmd\">hg bisect</command> must perform, thanks to its " +"logarithmic behaviour." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch09-hook.xml:5 +msgid "Handling repository events with hooks" +msgstr "使用钩子处理版本库事件" + +#. type: Content of: <book><chapter><para> +#: ../en/ch09-hook.xml:7 +msgid "" +"Mercurial offers a powerful mechanism to let you perform automated actions in " +"response to events that occur in a repository. In some cases, you can even " +"control Mercurial's response to those events." +msgstr "" + +#. type: Content of: <book><chapter><para> +#: ../en/ch09-hook.xml:12 +msgid "" +"The name Mercurial uses for one of these actions is a <emphasis>hook</" +"emphasis>. Hooks are called <quote>triggers</quote> in some revision control " +"systems, but the two names refer to the same idea." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch09-hook.xml:18 +msgid "An overview of hooks in Mercurial" +msgstr "Mercurial 钩子概述" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:20 +msgid "" +"Here is a brief list of the hooks that Mercurial supports. We will revisit " +"each of these hooks in more detail later, in section <xref linkend=\"sec.hook." +"ref\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:25 +msgid "" +"<literal role=\"hook\">changegroup</literal>: This is run after a group of " +"changesets has been brought into the repository from elsewhere." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:29 +msgid "" +"<literal role=\"hook\">commit</literal>: This is run after a new changeset " +"has been created in the local repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:33 +msgid "" +"<literal role=\"hook\">incoming</literal>: This is run once for each new " +"changeset that is brought into the repository from elsewhere. Notice the " +"difference from <literal role=\"hook\">changegroup</literal>, which is run " +"once per <emphasis>group</emphasis> of changesets brought in." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:40 +msgid "" +"<literal role=\"hook\">outgoing</literal>: This is run after a group of " +"changesets has been transmitted from this repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:44 +msgid "" +"<literal role=\"hook\">prechangegroup</literal>: This is run before starting " +"to bring a group of changesets into the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:49 +msgid "" +"<literal role=\"hook\">precommit</literal>: Controlling. This is run before " +"starting a commit." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:53 +msgid "" +"<literal role=\"hook\">preoutgoing</literal>: Controlling. This is run before " +"starting to transmit a group of changesets from this repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:58 +msgid "" +"<literal role=\"hook\">pretag</literal>: Controlling. This is run before " +"creating a tag." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:62 +msgid "" +"<literal role=\"hook\">pretxnchangegroup</literal>: Controlling. This is run " +"after a group of changesets has been brought into the local repository from " +"another, but before the transaction completes that will make the changes " +"permanent in the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:70 +msgid "" +"<literal role=\"hook\">pretxncommit</literal>: Controlling. This is run after " +"a new changeset has been created in the local repository, but before the " +"transaction completes that will make it permanent." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:76 +msgid "" +"<literal role=\"hook\">preupdate</literal>: Controlling. This is run before " +"starting an update or merge of the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:81 +msgid "" +"<literal role=\"hook\">tag</literal>: This is run after a tag is created." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:85 +msgid "" +"<literal role=\"hook\">update</literal>: This is run after an update or merge " +"of the working directory has finished." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:90 +msgid "" +"Each of the hooks whose description begins with the word <quote>Controlling</" +"quote> has the ability to determine whether an activity can proceed. If the " +"hook succeeds, the activity may proceed; if it fails, the activity is either " +"not permitted or undone, depending on the hook." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch09-hook.xml:99 +msgid "Hooks and security" +msgstr "钩子与安全性" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:102 +msgid "Hooks are run with your privileges" +msgstr "钩子以你的特权执行" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:104 +msgid "" +"When you run a Mercurial command in a repository, and the command causes a " +"hook to run, that hook runs on <emphasis>your</emphasis> system, under " +"<emphasis>your</emphasis> user account, with <emphasis>your</emphasis> " +"privilege level. Since hooks are arbitrary pieces of executable code, you " +"should treat them with an appropriate level of suspicion. Do not install a " +"hook unless you are confident that you know who created it and what it does." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:115 +msgid "" +"In some cases, you may be exposed to hooks that you did not install " +"yourself. If you work with Mercurial on an unfamiliar system, Mercurial will " +"run hooks defined in that system's global <filename role=\"special\">~/.hgrc</" +"filename> file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:122 +msgid "" +"If you are working with a repository owned by another user, Mercurial can run " +"hooks defined in that user's repository, but it will still run them as " +"<quote>you</quote>. For example, if you <command role=\"hg-cmd\">hg pull</" +"command> from that repository, and its <filename role=\"special\">.hg/hgrc</" +"filename> defines a local <literal role=\"hook\">outgoing</literal> hook, " +"that hook will run under your user account, even though you don't own that " +"repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch09-hook.xml:134 +msgid "" +"This only applies if you are pulling from a repository on a local or network " +"filesystem. If you're pulling over http or ssh, any <literal role=\"hook" +"\">outgoing</literal> hook will run under whatever account is executing the " +"server process, on the server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:142 +msgid "" +"XXX To see what hooks are defined in a repository, use the <command role=\"hg-" +"cmd\">hg config hooks</command> command. If you are working in one " +"repository, but talking to another that you do not own (e.g. using <command " +"role=\"hg-cmd\">hg pull</command> or <command role=\"hg-cmd\">hg incoming</" +"command>), remember that it is the other repository's hooks you should be " +"checking, not your own." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:153 +msgid "Hooks do not propagate" +msgstr "钩子不会传播" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:155 +msgid "" +"In Mercurial, hooks are not revision controlled, and do not propagate when " +"you clone, or pull from, a repository. The reason for this is simple: a hook " +"is a completely arbitrary piece of executable code. It runs under your user " +"identity, with your privilege level, on your machine." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:162 +msgid "" +"It would be extremely reckless for any distributed revision control system to " +"implement revision-controlled hooks, as this would offer an easily " +"exploitable way to subvert the accounts of users of the revision control " +"system." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:168 +msgid "" +"Since Mercurial does not propagate hooks, if you are collaborating with other " +"people on a common project, you should not assume that they are using the " +"same Mercurial hooks as you are, or that theirs are correctly configured. " +"You should document the hooks you expect people to use." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:175 +msgid "" +"In a corporate intranet, this is somewhat easier to control, as you can for " +"example provide a <quote>standard</quote> installation of Mercurial on an NFS " +"filesystem, and use a site-wide <filename role=\"special\">~/.hgrc</filename> " +"file to define hooks that all users will see. However, this too has its " +"limits; see below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:184 +msgid "Hooks can be overridden" +msgstr "钩子可以被覆盖" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:186 +msgid "" +"Mercurial allows you to override a hook definition by redefining the hook. " +"You can disable it by setting its value to the empty string, or change its " +"behaviour as you wish." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:191 +msgid "" +"If you deploy a system- or site-wide <filename role=\"special\">~/.hgrc</" +"filename> file that defines some hooks, you should thus understand that your " +"users can disable or override those hooks." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:199 +msgid "Ensuring that critical hooks are run" +msgstr "确保关键钩子的执行" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:201 +msgid "" +"Sometimes you may want to enforce a policy that you do not want others to be " +"able to work around. For example, you may have a requirement that every " +"changeset must pass a rigorous set of tests. Defining this requirement via a " +"hook in a site-wide <filename role=\"special\">~/.hgrc</filename> won't work " +"for remote users on laptops, and of course local users can subvert it at will " +"by overriding the hook." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:210 +msgid "" +"Instead, you can set up your policies for use of Mercurial so that people are " +"expected to propagate changes through a well-known <quote>canonical</quote> " +"server that you have locked down and configured appropriately." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:216 +msgid "" +"One way to do this is via a combination of social engineering and " +"technology. Set up a restricted-access account; users can push changes over " +"the network to repositories managed by this account, but they cannot log into " +"the account and run normal shell commands. In this scenario, a user can " +"commit a changeset that contains any old garbage they want." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:225 +msgid "" +"When someone pushes a changeset to the server that everyone pulls from, the " +"server will test the changeset before it accepts it as permanent, and reject " +"it if it fails to pass the test suite. If people only pull changes from this " +"filtering server, it will serve to ensure that all changes that people pull " +"have been automatically vetted." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch09-hook.xml:236 +msgid "Care with <literal>pretxn</literal> hooks in a shared-access repository" +msgstr "在共享版本库中注意 <literal>pretxn</literal> 钩子" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:239 +msgid "" +"If you want to use hooks to do some automated work in a repository that a " +"number of people have shared access to, you need to be careful in how you do " +"this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:244 +msgid "" +"Mercurial only locks a repository when it is writing to the repository, and " +"only the parts of Mercurial that write to the repository pay attention to " +"locks. Write locks are necessary to prevent multiple simultaneous writers " +"from scribbling on each other's work, corrupting the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:251 +msgid "" +"Because Mercurial is careful with the order in which it reads and writes " +"data, it does not need to acquire a lock when it wants to read data from the " +"repository. The parts of Mercurial that read from the repository never pay " +"attention to locks. This lockless reading scheme greatly increases " +"performance and concurrency." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:259 +msgid "" +"With great performance comes a trade-off, though, one which has the potential " +"to cause you trouble unless you're aware of it. To describe this requires a " +"little detail about how Mercurial adds changesets to a repository and reads " +"those changes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:266 +msgid "" +"When Mercurial <emphasis>writes</emphasis> metadata, it writes it straight " +"into the destination file. It writes file data first, then manifest data " +"(which contains pointers to the new file data), then changelog data (which " +"contains pointers to the new manifest data). Before the first write to each " +"file, it stores a record of where the end of the file was in its transaction " +"log. If the transaction must be rolled back, Mercurial simply truncates each " +"file back to the size it was before the transaction began." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:277 +msgid "" +"When Mercurial <emphasis>reads</emphasis> metadata, it reads the changelog " +"first, then everything else. Since a reader will only access parts of the " +"manifest or file metadata that it can see in the changelog, it can never see " +"partially written data." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:283 +msgid "" +"Some controlling hooks (<literal role=\"hook\">pretxncommit</literal> and " +"<literal role=\"hook\">pretxnchangegroup</literal>) run when a transaction is " +"almost complete. All of the metadata has been written, but Mercurial can " +"still roll the transaction back and cause the newly-written data to disappear." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:291 +msgid "" +"If one of these hooks runs for long, it opens a window of time during which a " +"reader can see the metadata for changesets that are not yet permanent, and " +"should not be thought of as <quote>really there</quote>. The longer the hook " +"runs, the longer that window is open." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:299 +msgid "The problem illustrated" +msgstr "问题的演示" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:301 +msgid "" +"In principle, a good use for the <literal role=\"hook\">pretxnchangegroup</" +"literal> hook would be to automatically build and test incoming changes " +"before they are accepted into a central repository. This could let you " +"guarantee that nobody can push changes to this repository that <quote>break " +"the build</quote>. But if a client can pull changes while they're being " +"tested, the usefulness of the test is zero; an unsuspecting someone can pull " +"untested changes, potentially breaking their build." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:312 +msgid "" +"The safest technological answer to this challenge is to set up such a " +"<quote>gatekeeper</quote> repository as <emphasis>unidirectional</emphasis>. " +"Let it take changes pushed in from the outside, but do not allow anyone to " +"pull changes from it (use the <literal role=\"hook\">preoutgoing</literal> " +"hook to lock it down). Configure a <literal role=\"hook\">changegroup</" +"literal> hook so that if a build or test succeeds, the hook will push the new " +"changes out to another repository that people <emphasis>can</emphasis> pull " +"from." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:324 +msgid "" +"In practice, putting a centralised bottleneck like this in place is not often " +"a good idea, and transaction visibility has nothing to do with the problem. " +"As the size of a project&emdash;and the time it takes to build and " +"test&emdash;grows, you rapidly run into a wall with this <quote>try before " +"you buy</quote> approach, where you have more changesets to test than time in " +"which to deal with them. The inevitable result is frustration on the part of " +"all involved." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:335 +msgid "" +"An approach that scales better is to get people to build and test before they " +"push, then run automated builds and tests centrally <emphasis>after</" +"emphasis> a push, to be sure all is well. The advantage of this approach is " +"that it does not impose a limit on the rate at which the repository can " +"accept changes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch09-hook.xml:346 +msgid "A short tutorial on using hooks" +msgstr "使用钩子的简短指南" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:348 +msgid "" +"It is easy to write a Mercurial hook. Let's start with a hook that runs when " +"you finish a <command role=\"hg-cmd\">hg commit</command>, and simply prints " +"the hash of the changeset you just created. The hook is called <literal role=" +"\"hook\">commit</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:355 +msgid "All hooks follow the pattern in this example." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:359 +msgid "" +"You add an entry to the <literal role=\"rc-hooks\">hooks</literal> section of " +"your <filename role=\"special\">~/.hgrc</filename>. On the left is the name " +"of the event to trigger on; on the right is the action to take. As you can " +"see, you can run an arbitrary shell command in a hook. Mercurial passes " +"extra information to the hook using environment variables (look for " +"<envar>HG_NODE</envar> in the example)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:369 +msgid "Performing multiple actions per event" +msgstr "每个事件执行多个操作" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:371 +msgid "" +"Quite often, you will want to define more than one hook for a particular kind " +"of event, as shown below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:376 +msgid "" +"Mercurial lets you do this by adding an <emphasis>extension</emphasis> to the " +"end of a hook's name. You extend a hook's name by giving the name of the " +"hook, followed by a full stop (the <quote><literal>.</literal></quote> " +"character), followed by some more text of your choosing. For example, " +"Mercurial will run both <literal>commit.foo</literal> and <literal>commit." +"bar</literal> when the <literal>commit</literal> event occurs." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:387 +msgid "" +"To give a well-defined order of execution when there are multiple hooks " +"defined for an event, Mercurial sorts hooks by extension, and executes the " +"hook commands in this sorted order. In the above example, it will execute " +"<literal>commit.bar</literal> before <literal>commit.foo</literal>, and " +"<literal>commit</literal> before both." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:396 +msgid "" +"It is a good idea to use a somewhat descriptive extension when you define a " +"new hook. This will help you to remember what the hook was for. If the hook " +"fails, you'll get an error message that contains the hook name and extension, " +"so using a descriptive extension could give you an immediate hint as to why " +"the hook failed (see section <xref linkend=\"sec.hook.perm\"/> for an " +"example)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:407 +msgid "Controlling whether an activity can proceed" +msgstr "控制处理的活动" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:409 +msgid "" +"In our earlier examples, we used the <literal role=\"hook\">commit</literal> " +"hook, which is run after a commit has completed. This is one of several " +"Mercurial hooks that run after an activity finishes. Such hooks have no way " +"of influencing the activity itself." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:416 +msgid "" +"Mercurial defines a number of events that occur before an activity starts; or " +"after it starts, but before it finishes. Hooks that trigger on these events " +"have the added ability to choose whether the activity can continue, or will " +"abort." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:422 +msgid "" +"The <literal role=\"hook\">pretxncommit</literal> hook runs after a commit " +"has all but completed. In other words, the metadata representing the " +"changeset has been written out to disk, but the transaction has not yet been " +"allowed to complete. The <literal role=\"hook\">pretxncommit</literal> hook " +"has the ability to decide whether the transaction can complete, or must be " +"rolled back." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:431 +msgid "" +"If the <literal role=\"hook\">pretxncommit</literal> hook exits with a status " +"code of zero, the transaction is allowed to complete; the commit finishes; " +"and the <literal role=\"hook\">commit</literal> hook is run. If the <literal " +"role=\"hook\">pretxncommit</literal> hook exits with a non-zero status code, " +"the transaction is rolled back; the metadata representing the changeset is " +"erased; and the <literal role=\"hook\">commit</literal> hook is not run." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:443 +msgid "" +"The hook in the example above checks that a commit comment contains a bug " +"ID. If it does, the commit can complete. If not, the commit is rolled back." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch09-hook.xml:451 +msgid "Writing your own hooks" +msgstr "编写钩子" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:453 +msgid "" +"When you are writing a hook, you might find it useful to run Mercurial either " +"with the <option role=\"hg-opt-global\">-v</option> option, or the <envar " +"role=\"rc-item-ui\">verbose</envar> config item set to <quote>true</quote>. " +"When you do so, Mercurial will print a message before it calls each hook." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:462 +msgid "Choosing how your hook should run" +msgstr "选择钩子的执行方式" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:464 +msgid "" +"You can write a hook either as a normal program&emdash;typically a shell " +"script&emdash;or as a Python function that is executed within the Mercurial " +"process." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:469 +msgid "" +"Writing a hook as an external program has the advantage that it requires no " +"knowledge of Mercurial's internals. You can call normal Mercurial commands " +"to get any added information you need. The trade-off is that external hooks " +"are slower than in-process hooks." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:476 +msgid "" +"An in-process Python hook has complete access to the Mercurial API, and does " +"not <quote>shell out</quote> to another process, so it is inherently faster " +"than an external hook. It is also easier to obtain much of the information " +"that a hook requires by using the Mercurial API than by running Mercurial " +"commands." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:484 +msgid "" +"If you are comfortable with Python, or require high performance, writing your " +"hooks in Python may be a good choice. However, when you have a " +"straightforward hook to write and you don't need to care about performance " +"(probably the majority of hooks), a shell script is perfectly fine." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:493 +msgid "Hook parameters" +msgstr "钩子的参数" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:495 +msgid "" +"Mercurial calls each hook with a set of well-defined parameters. In Python, " +"a parameter is passed as a keyword argument to your hook function. For an " +"external program, a parameter is passed as an environment variable." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:501 +msgid "" +"Whether your hook is written in Python or as a shell script, the hook-" +"specific parameter names and values will be the same. A boolean parameter " +"will be represented as a boolean value in Python, but as the number 1 (for " +"<quote>true</quote>) or 0 (for <quote>false</quote>) as an environment " +"variable for an external hook. If a hook parameter is named <literal>foo</" +"literal>, the keyword argument for a Python hook will also be named " +"<literal>foo</literal>, while the environment variable for an external hook " +"will be named <literal>HG_FOO</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:515 +msgid "Hook return values and activity control" +msgstr "钩子的返回值与活动控制" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:517 +msgid "" +"A hook that executes successfully must exit with a status of zero if " +"external, or return boolean <quote>false</quote> if in-process. Failure is " +"indicated with a non-zero exit status from an external hook, or an in-process " +"hook returning boolean <quote>true</quote>. If an in-process hook raises an " +"exception, the hook is considered to have failed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:525 +msgid "" +"For a hook that controls whether an activity can proceed, zero/false means " +"<quote>allow</quote>, while non-zero/true/exception means <quote>deny</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:532 +msgid "Writing an external hook" +msgstr "编写外部钩子" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:534 +msgid "" +"When you define an external hook in your <filename role=\"special\">~/.hgrc</" +"filename> and the hook is run, its value is passed to your shell, which " +"interprets it. This means that you can use normal shell constructs in the " +"body of the hook." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:541 +msgid "" +"An executable hook is always run with its current directory set to a " +"repository's root directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:545 +msgid "" +"Each hook parameter is passed in as an environment variable; the name is " +"upper-cased, and prefixed with the string <quote><literal>HG_</literal></" +"quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:550 +msgid "" +"With the exception of hook parameters, Mercurial does not set or modify any " +"environment variables when running a hook. This is useful to remember if you " +"are writing a site-wide hook that may be run by a number of different users " +"with differing environment variables set. In multi-user situations, you " +"should not rely on environment variables being set to the values you have in " +"your environment when testing the hook." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:561 +msgid "Telling Mercurial to use an in-process hook" +msgstr "让 Mercurial 使用进程内钩子" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:563 +msgid "" +"The <filename role=\"special\">~/.hgrc</filename> syntax for defining an in-" +"process hook is slightly different than for an executable hook. The value of " +"the hook must start with the text <quote><literal>python:</literal></quote>, " +"and continue with the fully-qualified name of a callable object to use as the " +"hook's value." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:571 +msgid "" +"The module in which a hook lives is automatically imported when a hook is " +"run. So long as you have the module name and <envar>PYTHONPATH</envar> " +"right, it should <quote>just work</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:577 +msgid "" +"The following <filename role=\"special\">~/.hgrc</filename> example snippet " +"illustrates the syntax and meaning of the notions we just described." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:583 +msgid "" +"When Mercurial runs the <literal>commit.example</literal> hook, it imports " +"<literal>mymodule.submodule</literal>, looks for the callable object named " +"<literal>myhook</literal>, and calls it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:591 +msgid "Writing an in-process hook" +msgstr "编写进程内钩子" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:593 +msgid "" +"The simplest in-process hook does nothing, but illustrates the basic shape of " +"the hook API:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:598 +msgid "" +"The first argument to a Python hook is always a <literal role=\"py-mod-" +"mercurial.ui\">ui</literal> object. The second is a repository object; at " +"the moment, it is always an instance of <literal role=\"py-mod-mercurial." +"localrepo\">localrepository</literal>. Following these two arguments are " +"other keyword arguments. Which ones are passed in depends on the hook being " +"called, but a hook can ignore arguments it doesn't care about by dropping " +"them into a keyword argument dict, as with <literal>**kwargs</literal> above." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch09-hook.xml:613 +msgid "Some hook examples" +msgstr "钩子样例" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:616 +msgid "Writing meaningful commit messages" +msgstr "编写有意义的提交日志" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:618 +msgid "" +"It's hard to imagine a useful commit message being very short. The simple " +"<literal role=\"hook\">pretxncommit</literal> hook of the example below will " +"prevent you from committing a changeset with a message that is less than ten " +"bytes long." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:628 +msgid "Checking for trailing whitespace" +msgstr "检查行尾空格" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:630 +msgid "" +"An interesting use of a commit-related hook is to help you to write cleaner " +"code. A simple example of <quote>cleaner code</quote> is the dictum that a " +"change should not add any new lines of text that contain <quote>trailing " +"whitespace</quote>. Trailing whitespace is a series of space and tab " +"characters at the end of a line of text. In most cases, trailing whitespace " +"is unnecessary, invisible noise, but it is occasionally problematic, and " +"people often prefer to get rid of it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:641 +msgid "" +"You can use either the <literal role=\"hook\">precommit</literal> or <literal " +"role=\"hook\">pretxncommit</literal> hook to tell whether you have a trailing " +"whitespace problem. If you use the <literal role=\"hook\">precommit</" +"literal> hook, the hook will not know which files you are committing, so it " +"will have to check every modified file in the repository for trailing white " +"space. If you want to commit a change to just the file <filename>foo</" +"filename>, but the file <filename>bar</filename> contains trailing " +"whitespace, doing a check in the <literal role=\"hook\">precommit</literal> " +"hook will prevent you from committing <filename>foo</filename> due to the " +"problem with <filename>bar</filename>. This doesn't seem right." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:657 +msgid "" +"Should you choose the <literal role=\"hook\">pretxncommit</literal> hook, the " +"check won't occur until just before the transaction for the commit " +"completes. This will allow you to check for problems only the exact files " +"that are being committed. However, if you entered the commit message " +"interactively and the hook fails, the transaction will roll back; you'll have " +"to re-enter the commit message after you fix the trailing whitespace and run " +"<command role=\"hg-cmd\">hg commit</command> again." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:670 +msgid "" +"In this example, we introduce a simple <literal role=\"hook\">pretxncommit</" +"literal> hook that checks for trailing whitespace. This hook is short, but " +"not very helpful. It exits with an error status if a change adds a line with " +"trailing whitespace to any file, but does not print any information that " +"might help us to identify the offending file or line. It also has the nice " +"property of not paying attention to unmodified lines; only lines that " +"introduce new trailing whitespace cause problems." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:681 +msgid "" +"The above version is much more complex, but also more useful. It parses a " +"unified diff to see if any lines add trailing whitespace, and prints the name " +"of the file and the line number of each such occurrence. Even better, if the " +"change adds trailing whitespace, this hook saves the commit comment and " +"prints the name of the save file before exiting and telling Mercurial to roll " +"the transaction back, so you can use the <option role=\"hg-opt-commit\">-l " +"filename</option> option to <command role=\"hg-cmd\">hg commit</command> to " +"reuse the saved commit message once you've corrected the problem." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:695 +msgid "" +"As a final aside, note in the example above the use of <command>perl</" +"command>'s in-place editing feature to get rid of trailing whitespace from a " +"file. This is concise and useful enough that I will reproduce it here." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch09-hook.xml:705 +msgid "Bundled hooks" +msgstr "内置的钩子" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch09-hook.xml:707 +msgid "" +"Mercurial ships with several bundled hooks. You can find them in the " +"<filename class=\"directory\">hgext</filename> directory of a Mercurial " +"source tree. If you are using a Mercurial binary package, the hooks will be " +"located in the <filename class=\"directory\">hgext</filename> directory of " +"wherever your package installer put Mercurial." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:716 +msgid "" +"<literal role=\"hg-ext\">acl</literal>&emdash;access control for parts of a " +"repository" +msgstr "<literal role=\"hg-ext\">acl</literal>&emdash;版本库的访问控制" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:719 +msgid "" +"The <literal role=\"hg-ext\">acl</literal> extension lets you control which " +"remote users are allowed to push changesets to a networked server. You can " +"protect any portion of a repository (including the entire repo), so that a " +"specific remote user can push changes that do not affect the protected " +"portion." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:727 +msgid "" +"This extension implements access control based on the identity of the user " +"performing a push, <emphasis>not</emphasis> on who committed the changesets " +"they're pushing. It makes sense to use this hook only if you have a locked-" +"down server environment that authenticates remote users, and you want to be " +"sure that only specific users are allowed to push changes to that server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch09-hook.xml:737 +msgid "Configuring the <literal role=\"hook\">acl</literal> hook" +msgstr "配置 <literal role=\"hook\">acl</literal> 钩子" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:740 +msgid "" +"In order to manage incoming changesets, the <literal role=\"hg-ext\">acl</" +"literal> hook must be used as a <literal role=\"hook\">pretxnchangegroup</" +"literal> hook. This lets it see which files are modified by each incoming " +"changeset, and roll back a group of changesets if they modify " +"<quote>forbidden</quote> files. Example:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:750 +msgid "" +"The <literal role=\"hg-ext\">acl</literal> extension is configured using " +"three sections." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:754 +msgid "" +"The <literal role=\"rc-acl\">acl</literal> section has only one entry, <envar " +"role=\"rc-item-acl\">sources</envar>, which lists the sources of incoming " +"changesets that the hook should pay attention to. You don't normally need to " +"configure this section." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:761 +msgid "" +"<envar role=\"rc-item-acl\">serve</envar>: Control incoming changesets that " +"are arriving from a remote repository over http or ssh. This is the default " +"value of <envar role=\"rc-item-acl\">sources</envar>, and usually the only " +"setting you'll need for this configuration item." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:769 +msgid "" +"<envar role=\"rc-item-acl\">pull</envar>: Control incoming changesets that " +"are arriving via a pull from a local repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:774 +msgid "" +"<envar role=\"rc-item-acl\">push</envar>: Control incoming changesets that " +"are arriving via a push from a local repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:779 +msgid "" +"<envar role=\"rc-item-acl\">bundle</envar>: Control incoming changesets that " +"are arriving from another repository via a bundle." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:785 +msgid "" +"The <literal role=\"rc-acl.allow\">acl.allow</literal> section controls the " +"users that are allowed to add changesets to the repository. If this section " +"is not present, all users that are not explicitly denied are allowed. If " +"this section is present, all users that are not explicitly allowed are denied " +"(so an empty section means that all users are denied)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:794 +msgid "" +"The <literal role=\"rc-acl.deny\">acl.deny</literal> section determines which " +"users are denied from adding changesets to the repository. If this section " +"is not present or is empty, no users are denied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:800 +msgid "" +"The syntaxes for the <literal role=\"rc-acl.allow\">acl.allow</literal> and " +"<literal role=\"rc-acl.deny\">acl.deny</literal> sections are identical. On " +"the left of each entry is a glob pattern that matches files or directories, " +"relative to the root of the repository; on the right, a user name." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:808 +msgid "" +"In the following example, the user <literal>docwriter</literal> can only push " +"changes to the <filename class=\"directory\">docs</filename> subtree of the " +"repository, while <literal>intern</literal> can push changes to any file or " +"directory except <filename class=\"directory\">source/sensitive</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch09-hook.xml:822 ../en/ch09-hook.xml:1089 ../en/ch09-hook.xml:1280 +msgid "Testing and troubleshooting" +msgstr "测试与问题处理" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:824 +msgid "" +"If you want to test the <literal role=\"hg-ext\">acl</literal> hook, run it " +"with Mercurial's debugging output enabled. Since you'll probably be running " +"it on a server where it's not convenient (or sometimes possible) to pass in " +"the <option role=\"hg-opt-global\">--debug</option> option, don't forget that " +"you can enable debugging output in your <filename role=\"special\">~/.hgrc</" +"filename>:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:835 +msgid "" +"With this enabled, the <literal role=\"hg-ext\">acl</literal> hook will print " +"enough information to let you figure out why it is allowing or forbidding " +"pushes from specific users." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:844 +msgid "" +"<literal role=\"hg-ext\">bugzilla</literal>&emdash;integration with Bugzilla" +msgstr "<literal role=\"hg-ext\">bugzilla</literal>&emdash;与 Bugzilla 的集成" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:848 +msgid "" +"The <literal role=\"hg-ext\">bugzilla</literal> extension adds a comment to a " +"Bugzilla bug whenever it finds a reference to that bug ID in a commit " +"comment. You can install this hook on a shared server, so that any time a " +"remote user pushes changes to this server, the hook gets run." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:855 +msgid "" +"It adds a comment to the bug that looks like this (you can configure the " +"contents of the comment&emdash;see below):" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:864 +msgid "" +"The value of this hook is that it automates the process of updating a bug any " +"time a changeset refers to it. If you configure the hook properly, it makes " +"it easy for people to browse straight from a Bugzilla bug to a changeset that " +"refers to that bug." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:871 +msgid "" +"You can use the code in this hook as a starting point for some more exotic " +"Bugzilla integration recipes. Here are a few possibilities:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:876 +msgid "" +"Require that every changeset pushed to the server have a valid bug ID in its " +"commit comment. In this case, you'd want to configure the hook as a <literal " +"role=\"hook\">pretxncommit</literal> hook. This would allow the hook to " +"reject changes that didn't contain bug IDs." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:884 +msgid "" +"Allow incoming changesets to automatically modify the <emphasis>state</" +"emphasis> of a bug, as well as simply adding a comment. For example, the " +"hook could recognise the string <quote>fixed bug 31337</quote> as indicating " +"that it should update the state of bug 31337 to <quote>requires testing</" +"quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch09-hook.xml:894 +msgid "Configuring the <literal role=\"hook\">bugzilla</literal> hook" +msgstr "配置 <literal role=\"hook\">bugzilla</literal> 钩子" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:897 +msgid "" +"You should configure this hook in your server's <filename role=\"special\">~/." +"hgrc</filename> as an <literal role=\"hook\">incoming</literal> hook, for " +"example as follows:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:905 +msgid "" +"Because of the specialised nature of this hook, and because Bugzilla was not " +"written with this kind of integration in mind, configuring this hook is a " +"somewhat involved process." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:911 +msgid "" +"Before you begin, you must install the MySQL bindings for Python on the host" +"(s) where you'll be running the hook. If this is not available as a binary " +"package for your system, you can download it from <citation>web:mysql-python</" +"citation>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:918 +msgid "" +"Configuration information for this hook lives in the <literal role=\"rc-" +"bugzilla\">bugzilla</literal> section of your <filename role=\"special\">~/." +"hgrc</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:923 +msgid "" +"<envar role=\"rc-item-bugzilla\">version</envar>: The version of Bugzilla " +"installed on the server. The database schema that Bugzilla uses changes " +"occasionally, so this hook has to know exactly which schema to use. At the " +"moment, the only version supported is <literal>2.16</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:932 +msgid "" +"<envar role=\"rc-item-bugzilla\">host</envar>: The hostname of the MySQL " +"server that stores your Bugzilla data. The database must be configured to " +"allow connections from whatever host you are running the <literal role=\"hook" +"\">bugzilla</literal> hook on." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:939 +msgid "" +"<envar role=\"rc-item-bugzilla\">user</envar>: The username with which to " +"connect to the MySQL server. The database must be configured to allow this " +"user to connect from whatever host you are running the <literal role=\"hook" +"\">bugzilla</literal> hook on. This user must be able to access and modify " +"Bugzilla tables. The default value of this item is <literal>bugs</literal>, " +"which is the standard name of the Bugzilla user in a MySQL database." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:950 +msgid "" +"<envar role=\"rc-item-bugzilla\">password</envar>: The MySQL password for the " +"user you configured above. This is stored as plain text, so you should make " +"sure that unauthorised users cannot read the <filename role=\"special\">~/." +"hgrc</filename> file where you store this information." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:959 +msgid "" +"<envar role=\"rc-item-bugzilla\">db</envar>: The name of the Bugzilla " +"database on the MySQL server. The default value of this item is " +"<literal>bugs</literal>, which is the standard name of the MySQL database " +"where Bugzilla stores its data." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:966 +msgid "" +"<envar role=\"rc-item-bugzilla\">notify</envar>: If you want Bugzilla to send " +"out a notification email to subscribers after this hook has added a comment " +"to a bug, you will need this hook to run a command whenever it updates the " +"database. The command to run depends on where you have installed Bugzilla, " +"but it will typically look something like this, if you have Bugzilla " +"installed in <filename class=\"directory\">/var/www/html/bugzilla</filename>:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:979 +msgid "" +"The Bugzilla <literal>processmail</literal> program expects to be given a bug " +"ID (the hook replaces <quote><literal>%s</literal></quote> with the bug ID) " +"and an email address. It also expects to be able to write to some files in " +"the directory that it runs in. If Bugzilla and this hook are not installed " +"on the same machine, you will need to find a way to run <literal>processmail</" +"literal> on the server where Bugzilla is installed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch09-hook.xml:994 +msgid "Mapping committer names to Bugzilla user names" +msgstr "提交者的名称与 Bugzilla 用户名称的映射" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:996 +msgid "" +"By default, the <literal role=\"hg-ext\">bugzilla</literal> hook tries to use " +"the email address of a changeset's committer as the Bugzilla user name with " +"which to update a bug. If this does not suit your needs, you can map " +"committer email addresses to Bugzilla user names using a <literal role=\"rc-" +"usermap\">usermap</literal> section." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1005 +msgid "" +"Each item in the <literal role=\"rc-usermap\">usermap</literal> section " +"contains an email address on the left, and a Bugzilla user name on the right." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1012 +msgid "" +"You can either keep the <literal role=\"rc-usermap\">usermap</literal> data " +"in a normal <filename role=\"special\">~/.hgrc</filename>, or tell the " +"<literal role=\"hg-ext\">bugzilla</literal> hook to read the information from " +"an external <filename>usermap</filename> file. In the latter case, you can " +"store <filename>usermap</filename> data by itself in (for example) a user-" +"modifiable repository. This makes it possible to let your users maintain " +"their own <envar role=\"rc-item-bugzilla\">usermap</envar> entries. The main " +"<filename role=\"special\">~/.hgrc</filename> file might look like this:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1028 +msgid "" +"While the <filename>usermap</filename> file that it refers to might look like " +"this:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch09-hook.xml:1036 +msgid "Configuring the text that gets added to a bug" +msgstr "配置增加到问题中的正文" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1038 +msgid "" +"You can configure the text that this hook adds as a comment; you specify it " +"in the form of a Mercurial template. Several <filename role=\"special\">~/." +"hgrc</filename> entries (still in the <literal role=\"rc-bugzilla\">bugzilla</" +"literal> section) control this behaviour." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1045 +msgid "" +"<literal>strip</literal>: The number of leading path elements to strip from a " +"repository's path name to construct a partial path for a URL. For example, if " +"the repositories on your server live under <filename class=\"directory\">/" +"home/hg/repos</filename>, and you have a repository whose path is <filename " +"class=\"directory\">/home/hg/repos/app/tests</filename>, then setting " +"<literal>strip</literal> to <literal>4</literal> will give a partial path of " +"<filename class=\"directory\">app/tests</filename>. The hook will make this " +"partial path available when expanding a template, as <literal>webroot</" +"literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1059 +msgid "" +"<literal>template</literal>: The text of the template to use. In addition to " +"the usual changeset-related variables, this template can use <literal>hgweb</" +"literal> (the value of the <literal>hgweb</literal> configuration item above) " +"and <literal>webroot</literal> (the path constructed using <literal>strip</" +"literal> above)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1069 +msgid "" +"In addition, you can add a <envar role=\"rc-item-web\">baseurl</envar> item " +"to the <literal role=\"rc-web\">web</literal> section of your <filename role=" +"\"special\">~/.hgrc</filename>. The <literal role=\"hg-ext\">bugzilla</" +"literal> hook will make this available when expanding a template, as the base " +"string to use when constructing a URL that will let users browse from a " +"Bugzilla comment to view a changeset. Example:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1081 +msgid "" +"Here is an example set of <literal role=\"hg-ext\">bugzilla</literal> hook " +"config information." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1091 +msgid "" +"The most common problems with configuring the <literal role=\"hg-ext" +"\">bugzilla</literal> hook relate to running Bugzilla's " +"<filename>processmail</filename> script and mapping committer names to user " +"names." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1097 +msgid "" +"Recall from section <xref linkend=\"sec.hook.bugzilla.config\"/> above that " +"the user that runs the Mercurial process on the server is also the one that " +"will run the <filename>processmail</filename> script. The " +"<filename>processmail</filename> script sometimes causes Bugzilla to write to " +"files in its configuration directory, and Bugzilla's configuration files are " +"usually owned by the user that your web server runs under." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1108 +msgid "" +"You can cause <filename>processmail</filename> to be run with the suitable " +"user's identity using the <command>sudo</command> command. Here is an " +"example entry for a <filename>sudoers</filename> file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1115 +msgid "" +"This allows the <literal>hg_user</literal> user to run a " +"<filename>processmail-wrapper</filename> program under the identity of " +"<literal>httpd_user</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1120 +msgid "" +"This indirection through a wrapper script is necessary, because " +"<filename>processmail</filename> expects to be run with its current directory " +"set to wherever you installed Bugzilla; you can't specify that kind of " +"constraint in a <filename>sudoers</filename> file. The contents of the " +"wrapper script are simple:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1129 +msgid "" +"It doesn't seem to matter what email address you pass to " +"<filename>processmail</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1133 +msgid "" +"If your <literal role=\"rc-usermap\">usermap</literal> is not set up " +"correctly, users will see an error message from the <literal role=\"hg-ext" +"\">bugzilla</literal> hook when they push changes to the server. The error " +"message will look like this:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1140 +msgid "" +"What this means is that the committer's address, <literal>john.q." +"public@example.com</literal>, is not a valid Bugzilla user name, nor does it " +"have an entry in your <literal role=\"rc-usermap\">usermap</literal> that " +"maps it to a valid Bugzilla user name." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1150 +msgid "" +"<literal role=\"hg-ext\">notify</literal>&emdash;send email notifications" +msgstr "<literal role=\"hg-ext\">notify</literal>&emdash;邮件通知" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1153 +msgid "" +"Although Mercurial's built-in web server provides RSS feeds of changes in " +"every repository, many people prefer to receive change notifications via " +"email. The <literal role=\"hg-ext\">notify</literal> hook lets you send out " +"notifications to a set of email addresses whenever changesets arrive that " +"those subscribers are interested in." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1161 +msgid "" +"As with the <literal role=\"hg-ext\">bugzilla</literal> hook, the <literal " +"role=\"hg-ext\">notify</literal> hook is template-driven, so you can " +"customise the contents of the notification messages that it sends." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1167 +msgid "" +"By default, the <literal role=\"hg-ext\">notify</literal> hook includes a " +"diff of every changeset that it sends out; you can limit the size of the " +"diff, or turn this feature off entirely. It is useful for letting " +"subscribers review changes immediately, rather than clicking to follow a URL." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch09-hook.xml:1175 +msgid "Configuring the <literal role=\"hg-ext\">notify</literal> hook" +msgstr "配置 <literal role=\"hg-ext\">notify</literal> 钩子" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1178 +msgid "" +"You can set up the <literal role=\"hg-ext\">notify</literal> hook to send one " +"email message per incoming changeset, or one per incoming group of changesets " +"(all those that arrived in a single pull or push)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1190 +msgid "" +"Configuration information for this hook lives in the <literal role=\"rc-notify" +"\">notify</literal> section of a <filename role=\"special\">~/.hgrc</" +"filename> file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1195 +msgid "" +"<envar role=\"rc-item-notify\">test</envar>: By default, this hook does not " +"send out email at all; instead, it prints the message that it " +"<emphasis>would</emphasis> send. Set this item to <literal>false</literal> " +"to allow email to be sent. The reason that sending of email is turned off by " +"default is that it takes several tries to configure this extension exactly as " +"you would like, and it would be bad form to spam subscribers with a number of " +"<quote>broken</quote> notifications while you debug your configuration." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1207 +msgid "" +"<envar role=\"rc-item-notify\">config</envar>: The path to a configuration " +"file that contains subscription information. This is kept separate from the " +"main <filename role=\"special\">~/.hgrc</filename> so that you can maintain " +"it in a repository of its own. People can then clone that repository, update " +"their subscriptions, and push the changes back to your server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1216 +msgid "" +"<envar role=\"rc-item-notify\">strip</envar>: The number of leading path " +"separator characters to strip from a repository's path, when deciding whether " +"a repository has subscribers. For example, if the repositories on your " +"server live in <filename class=\"directory\">/home/hg/repos</filename>, and " +"<literal role=\"hg-ext\">notify</literal> is considering a repository named " +"<filename class=\"directory\">/home/hg/repos/shared/test</filename>, setting " +"<envar role=\"rc-item-notify\">strip</envar> to <literal>4</literal> will " +"cause <literal role=\"hg-ext\">notify</literal> to trim the path it considers " +"down to <filename class=\"directory\">shared/test</filename>, and it will " +"match subscribers against that." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1233 +msgid "" +"<envar role=\"rc-item-notify\">template</envar>: The template text to use " +"when sending messages. This specifies both the contents of the message " +"header and its body." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1239 +msgid "" +"<envar role=\"rc-item-notify\">maxdiff</envar>: The maximum number of lines " +"of diff data to append to the end of a message. If a diff is longer than " +"this, it is truncated. By default, this is set to 300. Set this to " +"<literal>0</literal> to omit diffs from notification emails." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1248 +msgid "" +"<envar role=\"rc-item-notify\">sources</envar>: A list of sources of " +"changesets to consider. This lets you limit <literal role=\"hg-ext\">notify</" +"literal> to only sending out email about changes that remote users pushed " +"into this repository via a server, for example. See section <xref linkend=" +"\"sec.hook.sources\"/> for the sources you can specify here." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1260 +msgid "" +"If you set the <envar role=\"rc-item-web\">baseurl</envar> item in the " +"<literal role=\"rc-web\">web</literal> section, you can use it in a template; " +"it will be available as <literal>webroot</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1266 +msgid "" +"Here is an example set of <literal role=\"hg-ext\">notify</literal> " +"configuration information." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1272 +msgid "This will produce a message that looks like the following:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1282 +msgid "" +"Do not forget that by default, the <literal role=\"hg-ext\">notify</literal> " +"extension <emphasis>will not send any mail</emphasis> until you explicitly " +"configure it to do so, by setting <envar role=\"rc-item-notify\">test</envar> " +"to <literal>false</literal>. Until you do that, it simply prints the message " +"it <emphasis>would</emphasis> send." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch09-hook.xml:1294 +msgid "Information for writers of hooks" +msgstr "编写钩子的信息" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1297 +msgid "In-process hook execution" +msgstr "进程内钩子的执行" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1299 +msgid "An in-process hook is called with arguments of the following form:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1303 +msgid "" +"The <literal>ui</literal> parameter is a <literal role=\"py-mod-mercurial.ui" +"\">ui</literal> object. The <literal>repo</literal> parameter is a <literal " +"role=\"py-mod-mercurial.localrepo\">localrepository</literal> object. The " +"names and values of the <literal>**kwargs</literal> parameters depend on the " +"hook being invoked, with the following common features:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1312 +msgid "" +"If a parameter is named <literal>node</literal> or <literal>parentN</" +"literal>, it will contain a hexadecimal changeset ID. The empty string is " +"used to represent <quote>null changeset ID</quote> instead of a string of " +"zeroes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1319 +msgid "" +"If a parameter is named <literal>url</literal>, it will contain the URL of a " +"remote repository, if that can be determined." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1324 +msgid "" +"Boolean-valued parameters are represented as Python <literal>bool</literal> " +"objects." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1329 +msgid "" +"An in-process hook is called without a change to the process's working " +"directory (unlike external hooks, which are run in the root of the " +"repository). It must not change the process's working directory, or it will " +"cause any calls it makes into the Mercurial API to fail." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1336 +msgid "" +"If a hook returns a boolean <quote>false</quote> value, it is considered to " +"have succeeded. If it returns a boolean <quote>true</quote> value or raises " +"an exception, it is considered to have failed. A useful way to think of the " +"calling convention is <quote>tell me if you fail</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1343 +msgid "" +"Note that changeset IDs are passed into Python hooks as hexadecimal strings, " +"not the binary hashes that Mercurial's APIs normally use. To convert a hash " +"from hex to binary, use the <literal>bin</literal> function." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1351 +msgid "External hook execution" +msgstr "外部钩子的执行" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1353 +msgid "" +"An external hook is passed to the shell of the user running Mercurial. " +"Features of that shell, such as variable substitution and command " +"redirection, are available. The hook is run in the root directory of the " +"repository (unlike in-process hooks, which are run in the same directory that " +"Mercurial was run in)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1361 +msgid "" +"Hook parameters are passed to the hook as environment variables. Each " +"environment variable's name is converted in upper case and prefixed with the " +"string <quote><literal>HG_</literal></quote>. For example, if the name of a " +"parameter is <quote><literal>node</literal></quote>, the name of the " +"environment variable representing that parameter will be " +"<quote><literal>HG_NODE</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1370 +msgid "" +"A boolean parameter is represented as the string <quote><literal>1</literal></" +"quote> for <quote>true</quote>, <quote><literal>0</literal></quote> for " +"<quote>false</quote>. If an environment variable is named <envar>HG_NODE</" +"envar>, <envar>HG_PARENT1</envar> or <envar>HG_PARENT2</envar>, it contains a " +"changeset ID represented as a hexadecimal string. The empty string is used " +"to represent <quote>null changeset ID</quote> instead of a string of zeroes. " +"If an environment variable is named <envar>HG_URL</envar>, it will contain " +"the URL of a remote repository, if that can be determined." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1382 +msgid "" +"If a hook exits with a status of zero, it is considered to have succeeded. " +"If it exits with a non-zero status, it is considered to have failed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1389 +msgid "Finding out where changesets come from" +msgstr "检查修改集来自何处" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1391 +msgid "" +"A hook that involves the transfer of changesets between a local repository " +"and another may be able to find out information about the <quote>far side</" +"quote>. Mercurial knows <emphasis>how</emphasis> changes are being " +"transferred, and in many cases <emphasis>where</emphasis> they are being " +"transferred to or from." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch09-hook.xml:1400 +msgid "Sources of changesets" +msgstr "修改集的来源" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1402 +msgid "" +"Mercurial will tell a hook what means are, or were, used to transfer " +"changesets between repositories. This is provided by Mercurial in a Python " +"parameter named <literal>source</literal>, or an environment variable named " +"<envar>HG_SOURCE</envar>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1410 +msgid "" +"<literal>serve</literal>: Changesets are transferred to or from a remote " +"repository over http or ssh." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1415 +msgid "" +"<literal>pull</literal>: Changesets are being transferred via a pull from one " +"repository into another." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1420 +msgid "" +"<literal>push</literal>: Changesets are being transferred via a push from one " +"repository into another." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1425 +msgid "" +"<literal>bundle</literal>: Changesets are being transferred to or from a " +"bundle." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><title> +#: ../en/ch09-hook.xml:1432 +msgid "Where changes are going&emdash;remote repository URLs" +msgstr "修改集要到哪里&emdash;远程版本库的地址" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1435 +msgid "" +"When possible, Mercurial will tell a hook the location of the <quote>far " +"side</quote> of an activity that transfers changeset data between " +"repositories. This is provided by Mercurial in a Python parameter named " +"<literal>url</literal>, or an environment variable named <envar>HG_URL</" +"envar>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><para> +#: ../en/ch09-hook.xml:1443 +msgid "" +"This information is not always known. If a hook is invoked in a repository " +"that is being served via http or ssh, Mercurial cannot tell where the remote " +"repository is, but it may know where the client is connecting from. In such " +"cases, the URL will take one of the following forms:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1450 +msgid "" +"<literal>remote:ssh:1.2.3.4</literal>&emdash;remote ssh client, at the IP " +"address <literal>1.2.3.4</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1455 +msgid "" +"<literal>remote:http:1.2.3.4</literal>&emdash;remote http client, at the IP " +"address <literal>1.2.3.4</literal>. If the client is using SSL, this will be " +"of the form <literal>remote:https:1.2.3.4</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1462 +msgid "Empty&emdash;no information could be discovered about the remote client." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch09-hook.xml:1471 +msgid "Hook reference" +msgstr "钩子参考" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1474 +msgid "" +"<literal role=\"hook\">changegroup</literal>&emdash;after remote changesets " +"added" +msgstr "<literal role=\"hook\">changegroup</literal>&emdash;增加远程修改集之后" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1477 +msgid "" +"This hook is run after a group of pre-existing changesets has been added to " +"the repository, for example via a <command role=\"hg-cmd\">hg pull</command> " +"or <command role=\"hg-cmd\">hg unbundle</command>. This hook is run once per " +"operation that added one or more changesets. This is in contrast to the " +"<literal role=\"hook\">incoming</literal> hook, which is run once per " +"changeset, regardless of whether the changesets arrive in a group." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1487 +msgid "" +"Some possible uses for this hook include kicking off an automated build or " +"test of the added changesets, updating a bug database, or notifying " +"subscribers that a repository contains new changes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1493 ../en/ch09-hook.xml:1533 ../en/ch09-hook.xml:1576 +#: ../en/ch09-hook.xml:1618 ../en/ch09-hook.xml:1673 ../en/ch09-hook.xml:1713 +#: ../en/ch09-hook.xml:1749 ../en/ch09-hook.xml:1784 ../en/ch09-hook.xml:1846 +#: ../en/ch09-hook.xml:1904 ../en/ch09-hook.xml:1938 ../en/ch09-hook.xml:1966 +msgid "Parameters to this hook:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1496 ../en/ch09-hook.xml:1849 +msgid "" +"<literal>node</literal>: A changeset ID. The changeset ID of the first " +"changeset in the group that was added. All changesets between this and " +"<literal role=\"tag\">tip</literal>, inclusive, were added by a single " +"<command role=\"hg-cmd\">hg pull</command>, <command role=\"hg-cmd\">hg push</" +"command> or <command role=\"hg-cmd\">hg unbundle</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1505 ../en/ch09-hook.xml:1583 ../en/ch09-hook.xml:1676 +#: ../en/ch09-hook.xml:1859 +msgid "" +"<literal>source</literal>: A string. The source of these changes. See " +"section <xref linkend=\"sec.hook.sources\"/> for details." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1510 ../en/ch09-hook.xml:1588 ../en/ch09-hook.xml:1639 +#: ../en/ch09-hook.xml:1681 ../en/ch09-hook.xml:1763 ../en/ch09-hook.xml:1864 +msgid "" +"<literal>url</literal>: A URL. The location of the remote repository, if " +"known. See section <xref linkend=\"sec.hook.url\"/> for more information." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1517 +msgid "" +"See also: <literal role=\"hook\">incoming</literal> (section <xref linkend=" +"\"sec.hook.incoming\"/>), <literal role=\"hook\">prechangegroup</literal> " +"(section <xref linkend=\"sec.hook.prechangegroup\"/>), <literal role=\"hook" +"\">pretxnchangegroup</literal> (section <xref linkend=\"sec.hook." +"pretxnchangegroup\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1527 +msgid "" +"<literal role=\"hook\">commit</literal>&emdash;after a new changeset is " +"created" +msgstr "<literal role=\"hook\">commit</literal>&emdash;创建新修改集之后" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1530 +msgid "This hook is run after a new changeset has been created." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1536 ../en/ch09-hook.xml:1907 +msgid "" +"<literal>node</literal>: A changeset ID. The changeset ID of the newly " +"committed changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1540 ../en/ch09-hook.xml:1911 +msgid "" +"<literal>parent1</literal>: A changeset ID. The changeset ID of the first " +"parent of the newly committed changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1545 ../en/ch09-hook.xml:1916 +msgid "" +"<literal>parent2</literal>: A changeset ID. The changeset ID of the second " +"parent of the newly committed changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1551 +msgid "" +"See also: <literal role=\"hook\">precommit</literal> (section <xref linkend=" +"\"sec.hook.precommit\"/>), <literal role=\"hook\">pretxncommit</literal> " +"(section <xref linkend=\"sec.hook.pretxncommit\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1559 +msgid "" +"<literal role=\"hook\">incoming</literal>&emdash;after one remote changeset " +"is added" +msgstr "<literal role=\"hook\">incoming</literal>&emdash;增加远程修改集之后" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1562 +msgid "" +"This hook is run after a pre-existing changeset has been added to the " +"repository, for example via a <command role=\"hg-cmd\">hg push</command>. If " +"a group of changesets was added in a single operation, this hook is called " +"once for each added changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1569 +msgid "" +"You can use this hook for the same purposes as the <literal role=\"hook" +"\">changegroup</literal> hook (section <xref linkend=\"sec.hook.changegroup\"/" +">); it's simply more convenient sometimes to run a hook once per group of " +"changesets, while other times it's handier once per changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1579 +msgid "" +"<literal>node</literal>: A changeset ID. The ID of the newly added changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1595 +msgid "" +"See also: <literal role=\"hook\">changegroup</literal> (section <xref linkend=" +"\"sec.hook.changegroup\"/>) <literal role=\"hook\">prechangegroup</literal> " +"(section <xref linkend=\"sec.hook.prechangegroup\"/>), <literal role=\"hook" +"\">pretxnchangegroup</literal> (section <xref linkend=\"sec.hook." +"pretxnchangegroup\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1605 +msgid "" +"<literal role=\"hook\">outgoing</literal>&emdash;after changesets are " +"propagated" +msgstr "<literal role=\"hook\">outgoing</literal>&emdash;传播修改集之后" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1608 +msgid "" +"This hook is run after a group of changesets has been propagated out of this " +"repository, for example by a <command role=\"hg-cmd\">hg push</command> or " +"<command role=\"hg-cmd\">hg bundle</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1614 +msgid "" +"One possible use for this hook is to notify administrators that changes have " +"been pulled." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1621 +msgid "" +"<literal>node</literal>: A changeset ID. The changeset ID of the first " +"changeset of the group that was sent." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1626 +msgid "" +"<literal>source</literal>: A string. The source of the of the operation (see " +"section <xref linkend=\"sec.hook.sources\"/>). If a remote client pulled " +"changes from this repository, <literal>source</literal> will be " +"<literal>serve</literal>. If the client that obtained changes from this " +"repository was local, <literal>source</literal> will be <literal>bundle</" +"literal>, <literal>pull</literal>, or <literal>push</literal>, depending on " +"the operation the client performed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1646 +msgid "" +"See also: <literal role=\"hook\">preoutgoing</literal> (section <xref linkend=" +"\"sec.hook.preoutgoing\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1652 +msgid "" +"<literal role=\"hook\">prechangegroup</literal>&emdash;before starting to add " +"remote changesets" +msgstr "" +"<literal role=\"hook\">prechangegroup</literal>&emdash;增加远程修改集之前" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1656 +msgid "" +"This controlling hook is run before Mercurial begins to add a group of " +"changesets from another repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1660 +msgid "" +"This hook does not have any information about the changesets to be added, " +"because it is run before transmission of those changesets is allowed to " +"begin. If this hook fails, the changesets will not be transmitted." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1666 +msgid "" +"One use for this hook is to prevent external changes from being added to a " +"repository. For example, you could use this to <quote>freeze</quote> a " +"server-hosted branch temporarily or permanently so that users cannot push to " +"it, while still allowing a local administrator to modify the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1688 +msgid "" +"See also: <literal role=\"hook\">changegroup</literal> (section <xref linkend=" +"\"sec.hook.changegroup\"/>), <literal role=\"hook\">incoming</literal> " +"(section <xref linkend=\"sec.hook.incoming\"/>), , <literal role=\"hook" +"\">pretxnchangegroup</literal> (section <xref linkend=\"sec.hook." +"pretxnchangegroup\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1698 +msgid "" +"<literal role=\"hook\">precommit</literal>&emdash;before starting to commit a " +"changeset" +msgstr "<literal role=\"hook\">precommit</literal>&emdash;提交修改集之前" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1701 +msgid "" +"This hook is run before Mercurial begins to commit a new changeset. It is run " +"before Mercurial has any of the metadata for the commit, such as the files to " +"be committed, the commit message, or the commit date." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1707 +msgid "" +"One use for this hook is to disable the ability to commit new changesets, " +"while still allowing incoming changesets. Another is to run a build or test, " +"and only allow the commit to begin if the build or test succeeds." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1716 +msgid "" +"<literal>parent1</literal>: A changeset ID. The changeset ID of the first " +"parent of the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1721 +msgid "" +"<literal>parent2</literal>: A changeset ID. The changeset ID of the second " +"parent of the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1726 +msgid "" +"If the commit proceeds, the parents of the working directory will become the " +"parents of the new changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1730 +msgid "" +"See also: <literal role=\"hook\">commit</literal> (section <xref linkend=" +"\"sec.hook.commit\"/>), <literal role=\"hook\">pretxncommit</literal> " +"(section <xref linkend=\"sec.hook.pretxncommit\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1738 +msgid "" +"<literal role=\"hook\">preoutgoing</literal>&emdash;before starting to " +"propagate changesets" +msgstr "<literal role=\"hook\">preoutgoing</literal>&emdash;传播修改集之前" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1741 +msgid "" +"This hook is invoked before Mercurial knows the identities of the changesets " +"to be transmitted." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1745 +msgid "" +"One use for this hook is to prevent changes from being transmitted to another " +"repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1752 +msgid "" +"<literal>source</literal>: A string. The source of the operation that is " +"attempting to obtain changes from this repository (see section <xref linkend=" +"\"sec.hook.sources\"/>). See the documentation for the <literal>source</" +"literal> parameter to the <literal role=\"hook\">outgoing</literal> hook, in " +"section <xref linkend=\"sec.hook.outgoing\"/>, for possible values of this " +"parameter." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1770 +msgid "" +"See also: <literal role=\"hook\">outgoing</literal> (section <xref linkend=" +"\"sec.hook.outgoing\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1776 +msgid "" +"<literal role=\"hook\">pretag</literal>&emdash;before tagging a changeset" +msgstr "<literal role=\"hook\">pretag</literal>&emdash;创建标签之前" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1779 +msgid "" +"This controlling hook is run before a tag is created. If the hook succeeds, " +"creation of the tag proceeds. If the hook fails, the tag is not created." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1787 +msgid "" +"<literal>local</literal>: A boolean. Whether the tag is local to this " +"repository instance (i.e. stored in <filename role=\"special\">.hg/localtags</" +"filename>) or managed by Mercurial (stored in <filename role=\"special\">." +"hgtags</filename>)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1794 +msgid "" +"<literal>node</literal>: A changeset ID. The ID of the changeset to be " +"tagged." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1798 +msgid "<literal>tag</literal>: A string. The name of the tag to be created." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1803 +msgid "" +"If the tag to be created is revision-controlled, the <literal role=\"hook" +"\">precommit</literal> and <literal role=\"hook\">pretxncommit</literal> " +"hooks (sections <xref linkend=\"sec.hook.commit\"/> and <xref linkend=\"sec." +"hook.pretxncommit\"/>) will also be run." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1810 +msgid "" +"See also: <literal role=\"hook\">tag</literal> (section <xref linkend=\"sec." +"hook.tag\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1815 +msgid "" +"<literal role=\"hook\">pretxnchangegroup</literal>&emdash;before completing " +"addition of remote changesets" +msgstr "" +"<literal role=\"hook\">pretxnchangegroup</literal>&emdash;完成增加远程修改集之" +"前" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1819 +msgid "" +"This controlling hook is run before a transaction&emdash;that manages the " +"addition of a group of new changesets from outside the repository&emdash;" +"completes. If the hook succeeds, the transaction completes, and all of the " +"changesets become permanent within this repository. If the hook fails, the " +"transaction is rolled back, and the data for the changesets is erased." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1828 +msgid "" +"This hook can access the metadata associated with the almost-added " +"changesets, but it should not do anything permanent with this data. It must " +"also not modify the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1834 +msgid "" +"While this hook is running, if other Mercurial processes access this " +"repository, they will be able to see the almost-added changesets as if they " +"are permanent. This may lead to race conditions if you do not take steps to " +"avoid them." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1841 +msgid "" +"This hook can be used to automatically vet a group of changesets. If the " +"hook fails, all of the changesets are <quote>rejected</quote> when the " +"transaction rolls back." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1871 +msgid "" +"See also: <literal role=\"hook\">changegroup</literal> (section <xref linkend=" +"\"sec.hook.changegroup\"/>), <literal role=\"hook\">incoming</literal> " +"(section <xref linkend=\"sec.hook.incoming\"/>), <literal role=\"hook" +"\">prechangegroup</literal> (section <xref linkend=\"sec.hook.prechangegroup" +"\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1881 +msgid "" +"<literal role=\"hook\">pretxncommit</literal>&emdash;before completing commit " +"of new changeset" +msgstr "<literal role=\"hook\">pretxncommit</literal>&emdash;完成提交之前" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1884 +msgid "" +"This controlling hook is run before a transaction&emdash;that manages a new " +"commit&emdash;completes. If the hook succeeds, the transaction completes and " +"the changeset becomes permanent within this repository. If the hook fails, " +"the transaction is rolled back, and the commit data is erased." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1892 +msgid "" +"This hook can access the metadata associated with the almost-new changeset, " +"but it should not do anything permanent with this data. It must also not " +"modify the working directory." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1898 +msgid "" +"While this hook is running, if other Mercurial processes access this " +"repository, they will be able to see the almost-new changeset as if it is " +"permanent. This may lead to race conditions if you do not take steps to " +"avoid them." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1922 +msgid "" +"See also: <literal role=\"hook\">precommit</literal> (section <xref linkend=" +"\"sec.hook.precommit\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1928 +msgid "" +"<literal role=\"hook\">preupdate</literal>&emdash;before updating or merging " +"working directory" +msgstr "" +"<literal role=\"hook\">preupdate</literal>&emdash;更新或合并工作目录之前" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1931 +msgid "" +"This controlling hook is run before an update or merge of the working " +"directory begins. It is run only if Mercurial's normal pre-update checks " +"determine that the update or merge can proceed. If the hook succeeds, the " +"update or merge may proceed; if it fails, the update or merge does not start." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1941 +msgid "" +"<literal>parent1</literal>: A changeset ID. The ID of the parent that the " +"working directory is to be updated to. If the working directory is being " +"merged, it will not change this parent." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1947 +msgid "" +"<literal>parent2</literal>: A changeset ID. Only set if the working " +"directory is being merged. The ID of the revision that the working directory " +"is being merged with." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1954 +msgid "" +"See also: <literal role=\"hook\">update</literal> (section <xref linkend=" +"\"sec.hook.update\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1960 +msgid "<literal role=\"hook\">tag</literal>&emdash;after tagging a changeset" +msgstr "<literal role=\"hook\">tag</literal>&emdash;创建标签之后" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1963 +msgid "This hook is run after a tag has been created." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1969 +msgid "" +"<literal>local</literal>: A boolean. Whether the new tag is local to this " +"repository instance (i.e. stored in <filename role=\"special\">.hg/" +"localtags</filename>) or managed by Mercurial (stored in <filename role=" +"\"special\">.hgtags</filename>)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1977 +msgid "" +"<literal>node</literal>: A changeset ID. The ID of the changeset that was " +"tagged." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:1981 +msgid "<literal>tag</literal>: A string. The name of the tag that was created." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1986 +msgid "" +"If the created tag is revision-controlled, the <literal role=\"hook\">commit</" +"literal> hook (section <xref linkend=\"sec.hook.commit\"/>) is run before " +"this hook." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:1991 +msgid "" +"See also: <literal role=\"hook\">pretag</literal> (section <xref linkend=" +"\"sec.hook.pretag\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch09-hook.xml:1997 +msgid "" +"<literal role=\"hook\">update</literal>&emdash;after updating or merging " +"working directory" +msgstr "<literal role=\"hook\">update</literal>&emdash;更新或合并工作目录之后" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:2000 +msgid "" +"This hook is run after an update or merge of the working directory " +"completes. Since a merge can fail (if the external <command>hgmerge</" +"command> command fails to resolve conflicts in a file), this hook " +"communicates whether the update or merge completed cleanly." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:2008 +msgid "" +"<literal>error</literal>: A boolean. Indicates whether the update or merge " +"completed successfully." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:2013 +msgid "" +"<literal>parent1</literal>: A changeset ID. The ID of the parent that the " +"working directory was updated to. If the working directory was merged, it " +"will not have changed this parent." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch09-hook.xml:2019 +msgid "" +"<literal>parent2</literal>: A changeset ID. Only set if the working " +"directory was merged. The ID of the revision that the working directory was " +"merged with." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch09-hook.xml:2025 +msgid "" +"See also: <literal role=\"hook\">preupdate</literal> (section <xref linkend=" +"\"sec.hook.preupdate\"/>)" +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch10-template.xml:5 +msgid "Customising the output of Mercurial" +msgstr "定制 Mercurial 的输出" + +#. type: Content of: <book><chapter><para> +#: ../en/ch10-template.xml:7 +msgid "" +"Mercurial provides a powerful mechanism to let you control how it displays " +"information. The mechanism is based on templates. You can use templates to " +"generate specific output for a single command, or to customise the entire " +"appearance of the built-in web interface." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch10-template.xml:14 +msgid "Using precanned output styles" +msgstr "使用预定义的输出样式" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:16 +msgid "" +"Packaged with Mercurial are some output styles that you can use immediately. " +"A style is simply a precanned template that someone wrote and installed " +"somewhere that Mercurial can find." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:21 +msgid "" +"Before we take a look at Mercurial's bundled styles, let's review its normal " +"output." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:26 +msgid "" +"This is somewhat informative, but it takes up a lot of space&emdash;five " +"lines of output per changeset. The <literal>compact</literal> style reduces " +"this to three lines, presented in a sparse manner." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:33 +msgid "" +"The <literal>changelog</literal> style hints at the expressive power of " +"Mercurial's templating engine. This style attempts to follow the GNU " +"Project's changelog guidelines<citation>web:changelog</citation>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:40 +msgid "" +"You will not be shocked to learn that Mercurial's default output style is " +"named <literal>default</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch10-template.xml:44 +msgid "Setting a default style" +msgstr "设置默认样式" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:46 +msgid "" +"You can modify the output style that Mercurial will use for every command by " +"editing your <filename role=\"special\">~/.hgrc</filename> file, naming the " +"style you would prefer to use." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:54 +msgid "" +"If you write a style of your own, you can use it by either providing the path " +"to your style file, or copying your style file into a location where " +"Mercurial can find it (typically the <literal>templates</literal> " +"subdirectory of your Mercurial install directory)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch10-template.xml:63 +msgid "Commands that support styles and templates" +msgstr "支持样式和模版的命令" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:65 +msgid "" +"All of Mercurial's <quote><literal>log</literal>-like</quote> commands let " +"you use styles and templates: <command role=\"hg-cmd\">hg incoming</command>, " +"<command role=\"hg-cmd\">hg log</command>, <command role=\"hg-cmd\">hg " +"outgoing</command>, and <command role=\"hg-cmd\">hg tip</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:72 +msgid "" +"As I write this manual, these are so far the only commands that support " +"styles and templates. Since these are the most important commands that need " +"customisable output, there has been little pressure from the Mercurial user " +"community to add style and template support to other commands." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch10-template.xml:80 +msgid "The basics of templating" +msgstr "模版基础" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:82 +msgid "" +"At its simplest, a Mercurial template is a piece of text. Some of the text " +"never changes, while other parts are <emphasis>expanded</emphasis>, or " +"replaced with new text, when necessary." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:87 +msgid "" +"Before we continue, let's look again at a simple example of Mercurial's " +"normal output." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:92 +msgid "" +"Now, let's run the same command, but using a template to change its output." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:97 +msgid "" +"The example above illustrates the simplest possible template; it's just a " +"piece of static text, printed once for each changeset. The <option role=\"hg-" +"opt-log\">--template</option> option to the <command role=\"hg-cmd\">hg log</" +"command> command tells Mercurial to use the given text as the template when " +"printing each changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:105 +msgid "" +"Notice that the template string above ends with the text <quote><literal>\\n</" +"literal></quote>. This is an <emphasis>escape sequence</emphasis>, telling " +"Mercurial to print a newline at the end of each template item. If you omit " +"this newline, Mercurial will run each piece of output together. See section " +"<xref linkend=\"sec.template.escape\"/> for more details of escape sequences." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:113 +msgid "" +"A template that prints a fixed string of text all the time isn't very useful; " +"let's try something a bit more complex." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:119 +msgid "" +"As you can see, the string <quote><literal>{desc}</literal></quote> in the " +"template has been replaced in the output with the description of each " +"changeset. Every time Mercurial finds text enclosed in curly braces " +"(<quote><literal>{</literal></quote> and <quote><literal>}</literal></" +"quote>), it will try to replace the braces and text with the expansion of " +"whatever is inside. To print a literal curly brace, you must escape it, as " +"described in section <xref linkend=\"sec.template.escape\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch10-template.xml:132 +msgid "Common template keywords" +msgstr "模版关键字" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:134 +msgid "" +"You can start writing simple templates immediately using the keywords below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:138 +msgid "" +"<literal role=\"template-keyword\">author</literal>: String. The unmodified " +"author of the changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:142 +msgid "" +"<literal role=\"template-keyword\">branches</literal>: String. The name of " +"the branch on which the changeset was committed. Will be empty if the branch " +"name was <literal>default</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:148 +msgid "" +"<literal role=\"template-keyword\">date</literal>: Date information. The " +"date when the changeset was committed. This is <emphasis>not</emphasis> " +"human-readable; you must pass it through a filter that will render it " +"appropriately. See section <xref linkend=\"sec.template.filter\"/> for more " +"information on filters. The date is expressed as a pair of numbers. The " +"first number is a Unix UTC timestamp (seconds since January 1, 1970); the " +"second is the offset of the committer's timezone from UTC, in seconds." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:159 +msgid "" +"<literal role=\"template-keyword\">desc</literal>: String. The text of the " +"changeset description." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:162 +msgid "" +"<literal role=\"template-keyword\">files</literal>: List of strings. All " +"files modified, added, or removed by this changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:167 +msgid "" +"<literal role=\"template-keyword\">file_adds</literal>: List of strings. " +"Files added by this changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:171 +msgid "" +"<literal role=\"template-keyword\">file_dels</literal>: List of strings. " +"Files removed by this changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:175 +msgid "" +"<literal role=\"template-keyword\">node</literal>: String. The changeset " +"identification hash, as a 40-character hexadecimal string." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:179 +msgid "" +"<literal role=\"template-keyword\">parents</literal>: List of strings. The " +"parents of the changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:183 +msgid "" +"<literal role=\"template-keyword\">rev</literal>: Integer. The repository-" +"local changeset revision number." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:187 +msgid "" +"<literal role=\"template-keyword\">tags</literal>: List of strings. Any tags " +"associated with the changeset." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:192 +msgid "" +"A few simple experiments will show us what to expect when we use these " +"keywords; you can see the results below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:197 +msgid "" +"As we noted above, the date keyword does not produce human-readable output, " +"so we must treat it specially. This involves using a <emphasis>filter</" +"emphasis>, about which more in section <xref linkend=\"sec.template.filter\"/" +">." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch10-template.xml:207 +msgid "Escape sequences" +msgstr "转义序列" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:209 +msgid "" +"Mercurial's templating engine recognises the most commonly used escape " +"sequences in strings. When it sees a backslash (<quote><literal>\\</" +"literal></quote>) character, it looks at the following character and " +"substitutes the two characters with a single replacement, as described below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:216 +msgid "" +"<literal>\\</literal>: Backslash, <quote><literal>\\</literal></quote>, ASCII " +"134." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:220 +msgid "<literal>\\n</literal>: Newline, ASCII 12." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:223 +msgid "<literal>\\r</literal>: Carriage return, ASCII 15." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:226 +msgid "<literal>\\t</literal>: Tab, ASCII 11." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:229 +msgid "<literal>\\v</literal>: Vertical tab, ASCII 13." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:232 +msgid "" +"<literal>{</literal>: Open curly brace, <quote><literal>{</literal></quote>, " +"ASCII 173." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:236 +msgid "" +"<literal>}</literal>: Close curly brace, <quote><literal>}</literal></quote>, " +"ASCII 175." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:241 +msgid "" +"As indicated above, if you want the expansion of a template to contain a " +"literal <quote><literal>\\</literal></quote>, <quote><literal>{</literal></" +"quote>, or <quote><literal>{</literal></quote> character, you must escape it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch10-template.xml:249 +msgid "Filtering keywords to change their results" +msgstr "通过过滤关键字来修改输出结果" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:251 +msgid "" +"Some of the results of template expansion are not immediately easy to use. " +"Mercurial lets you specify an optional chain of <emphasis>filters</emphasis> " +"to modify the result of expanding a keyword. You have already seen a common " +"filter, <literal role=\"template-kw-filt-date\">isodate</literal>, in action " +"above, to make a date readable." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:258 +msgid "" +"Below is a list of the most commonly used filters that Mercurial supports. " +"While some filters can be applied to any text, others can only be used in " +"specific circumstances. The name of each filter is followed first by an " +"indication of where it can be used, then a description of its effect." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:265 +msgid "" +"<literal role=\"template-filter\">addbreaks</literal>: Any text. Add an XHTML " +"<quote><literal><br/></literal></quote> tag before the end of every " +"line except the last. For example, <quote><literal>foo\\nbar</literal></" +"quote> becomes <quote><literal>foo<br/>\\nbar</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:272 +msgid "" +"<literal role=\"template-kw-filt-date\">age</literal>: <literal role=" +"\"template-keyword\">date</literal> keyword. Render the age of the date, " +"relative to the current time. Yields a string like <quote><literal>10 " +"minutes</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:279 +msgid "" +"<literal role=\"template-filter\">basename</literal>: Any text, but most " +"useful for the <literal role=\"template-keyword\">files</literal> keyword and " +"its relatives. Treat the text as a path, and return the basename. For " +"example, <quote><literal>foo/bar/baz</literal></quote> becomes " +"<quote><literal>baz</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:288 +msgid "" +"<literal role=\"template-kw-filt-date\">date</literal>: <literal role=" +"\"template-keyword\">date</literal> keyword. Render a date in a similar " +"format to the Unix <literal role=\"template-keyword\">date</literal> command, " +"but with timezone included. Yields a string like <quote><literal>Mon Sep 04 " +"15:13:13 2006 -0700</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:296 +msgid "" +"<literal role=\"template-kw-filt-author\">domain</literal>: Any text, but " +"most useful for the <literal role=\"template-keyword\">author</literal> " +"keyword. Finds the first string that looks like an email address, and " +"extract just the domain component. For example, <quote><literal>Bryan " +"O'Sullivan <bos@serpentine.com></literal></quote> becomes " +"<quote><literal>serpentine.com</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:306 +msgid "" +"<literal role=\"template-kw-filt-author\">email</literal>: Any text, but most " +"useful for the <literal role=\"template-keyword\">author</literal> keyword. " +"Extract the first string that looks like an email address. For example, " +"<quote><literal>Bryan O'Sullivan <bos@serpentine.com></literal></quote> " +"becomes <quote><literal>bos@serpentine.com</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:315 +msgid "" +"<literal role=\"template-filter\">escape</literal>: Any text. Replace the " +"special XML/XHTML characters <quote><literal>&</literal></quote>, " +"<quote><literal><</literal></quote> and <quote><literal>></literal></" +"quote> with XML entities." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:323 +msgid "" +"<literal role=\"template-filter\">fill68</literal>: Any text. Wrap the text " +"to fit in 68 columns. This is useful before you pass text through the " +"<literal role=\"template-filter\">tabindent</literal> filter, and still want " +"it to fit in an 80-column fixed-font window." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:331 +msgid "" +"<literal role=\"template-filter\">fill76</literal>: Any text. Wrap the text " +"to fit in 76 columns." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:335 +msgid "" +"<literal role=\"template-filter\">firstline</literal>: Any text. Yield the " +"first line of text, without any trailing newlines." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:340 +msgid "" +"<literal role=\"template-kw-filt-date\">hgdate</literal>: <literal role=" +"\"template-keyword\">date</literal> keyword. Render the date as a pair of " +"readable numbers. Yields a string like <quote><literal>1157407993 25200</" +"literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:347 +msgid "" +"<literal role=\"template-kw-filt-date\">isodate</literal>: <literal role=" +"\"template-keyword\">date</literal> keyword. Render the date as a text " +"string in ISO 8601 format. Yields a string like <quote><literal>2006-09-04 " +"15:13:13 -0700</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:354 +msgid "" +"<literal role=\"template-filter\">obfuscate</literal>: Any text, but most " +"useful for the <literal role=\"template-keyword\">author</literal> keyword. " +"Yield the input text rendered as a sequence of XML entities. This helps to " +"defeat some particularly stupid screen-scraping email harvesting spambots." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:362 +msgid "" +"<literal role=\"template-kw-filt-author\">person</literal>: Any text, but " +"most useful for the <literal role=\"template-keyword\">author</literal> " +"keyword. Yield the text before an email address. For example, " +"<quote><literal>Bryan O'Sullivan <bos@serpentine.com></literal></quote> " +"becomes <quote><literal>Bryan O'Sullivan</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:371 +msgid "" +"<literal role=\"template-kw-filt-date\">rfc822date</literal>: <literal role=" +"\"template-keyword\">date</literal> keyword. Render a date using the same " +"format used in email headers. Yields a string like <quote><literal>Mon, 04 " +"Sep 2006 15:13:13 -0700</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:378 +msgid "" +"<literal role=\"template-kw-filt-node\">short</literal>: Changeset hash. " +"Yield the short form of a changeset hash, i.e. a 12-character hexadecimal " +"string." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:383 +msgid "" +"<literal role=\"template-kw-filt-date\">shortdate</literal>: <literal role=" +"\"template-keyword\">date</literal> keyword. Render the year, month, and day " +"of the date. Yields a string like <quote><literal>2006-09-04</literal></" +"quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:389 +msgid "" +"<literal role=\"template-filter\">strip</literal>: Any text. Strip all " +"leading and trailing whitespace from the string." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:393 +msgid "" +"<literal role=\"template-filter\">tabindent</literal>: Any text. Yield the " +"text, with every line except the first starting with a tab character." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:398 +msgid "" +"<literal role=\"template-filter\">urlescape</literal>: Any text. Escape all " +"characters that are considered <quote>special</quote> by URL parsers. For " +"example, <literal>foo bar</literal> becomes <literal>foo%20bar</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:405 +msgid "" +"<literal role=\"template-kw-filt-author\">user</literal>: Any text, but most " +"useful for the <literal role=\"template-keyword\">author</literal> keyword. " +"Return the <quote>user</quote> portion of an email address. For example, " +"<quote><literal>Bryan O'Sullivan <bos@serpentine.com></literal></quote> " +"becomes <quote><literal>bos</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><note><para> +#: ../en/ch10-template.xml:418 +msgid "" +"If you try to apply a filter to a piece of data that it cannot process, " +"Mercurial will fail and print a Python exception. For example, trying to run " +"the output of the <literal role=\"template-keyword\">desc</literal> keyword " +"into the <literal role=\"template-kw-filt-date\">isodate</literal> filter is " +"not a good idea." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch10-template.xml:427 +msgid "Combining filters" +msgstr "组合过滤器" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:429 +msgid "" +"It is easy to combine filters to yield output in the form you would like. " +"The following chain of filters tidies up a description, then makes sure that " +"it fits cleanly into 68 columns, then indents it by a further 8 characters " +"(at least on Unix-like systems, where a tab is conventionally 8 characters " +"wide)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:438 +msgid "" +"Note the use of <quote><literal>\\t</literal></quote> (a tab character) in " +"the template to force the first line to be indented; this is necessary since " +"<literal role=\"template-keyword\">tabindent</literal> indents all lines " +"<emphasis>except</emphasis> the first." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:444 +msgid "" +"Keep in mind that the order of filters in a chain is significant. The first " +"filter is applied to the result of the keyword; the second to the result of " +"the first filter; and so on. For example, using <literal>fill68|tabindent</" +"literal> gives very different results from <literal>tabindent|fill68</" +"literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch10-template.xml:455 +msgid "From templates to styles" +msgstr "从模版到样式" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:457 +msgid "" +"A command line template provides a quick and simple way to format some " +"output. Templates can become verbose, though, and it's useful to be able to " +"give a template a name. A style file is a template with a name, stored in a " +"file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:462 +msgid "" +"More than that, using a style file unlocks the power of Mercurial's " +"templating engine in ways that are not possible using the command line " +"<option role=\"hg-opt-log\">--template</option> option." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch10-template.xml:468 +msgid "The simplest of style files" +msgstr "最简单的样式文件" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:470 +msgid "Our simple style file contains just one line:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:474 +msgid "" +"This tells Mercurial, <quote>if you're printing a changeset, use the text on " +"the right as the template</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch10-template.xml:480 +msgid "Style file syntax" +msgstr "样式文件语法" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:482 +msgid "The syntax rules for a style file are simple." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:485 +msgid "The file is processed one line at a time." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:488 +msgid "Leading and trailing white space are ignored." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:491 +msgid "Empty lines are skipped." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:493 +msgid "" +"If a line starts with either of the characters <quote><literal>#</literal></" +"quote> or <quote><literal>;</literal></quote>, the entire line is treated as " +"a comment, and skipped as if empty." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:498 +msgid "" +"A line starts with a keyword. This must start with an alphabetic character " +"or underscore, and can subsequently contain any alphanumeric character or " +"underscore. (In regexp notation, a keyword must match <literal>[A-Za-z_][A-" +"Za-z0-9_]*</literal>.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:504 +msgid "" +"The next element must be an <quote><literal>=</literal></quote> character, " +"which can be preceded or followed by an arbitrary amount of white space." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:509 +msgid "" +"If the rest of the line starts and ends with matching quote characters " +"(either single or double quote), it is treated as a template body." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:513 +msgid "" +"If the rest of the line <emphasis>does not</emphasis> start with a quote " +"character, it is treated as the name of a file; the contents of this file " +"will be read and used as a template body." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch10-template.xml:522 +msgid "Style files by example" +msgstr "样式文件例子" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch10-template.xml:524 +msgid "" +"To illustrate how to write a style file, we will construct a few by example. " +"Rather than provide a complete style file and walk through it, we'll mirror " +"the usual process of developing a style file by starting with something very " +"simple, and walking through a series of successively more complete examples." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch10-template.xml:531 +msgid "Identifying mistakes in style files" +msgstr "在样式文件中定位错误" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:533 +msgid "" +"If Mercurial encounters a problem in a style file you are working on, it " +"prints a terse error message that, once you figure out what it means, is " +"actually quite useful." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:539 +msgid "" +"Notice that <filename>broken.style</filename> attempts to define a " +"<literal>changeset</literal> keyword, but forgets to give any content for it. " +"When instructed to use this style file, Mercurial promptly complains." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:546 +msgid "This error message looks intimidating, but it is not too hard to follow." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:550 +msgid "" +"The first component is simply Mercurial's way of saying <quote>I am giving " +"up</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:554 +msgid "Next comes the name of the style file that contains the error." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:558 +msgid "" +"Following the file name is the line number where the error was encountered." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:562 +msgid "Finally, a description of what went wrong." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:566 +msgid "" +"The description of the problem is not always clear (as in this case), but " +"even when it is cryptic, it is almost always trivial to visually inspect the " +"offending line in the style file and see what is wrong." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch10-template.xml:574 +msgid "Uniquely identifying a repository" +msgstr "版本库的唯一标识" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:576 +msgid "" +"If you would like to be able to identify a Mercurial repository <quote>fairly " +"uniquely</quote> using a short string as an identifier, you can use the first " +"revision in the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:583 +msgid "" +"This is not guaranteed to be unique, but it is nevertheless useful in many " +"cases." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:586 +msgid "" +"It will not work in a completely empty repository, because such a repository " +"does not have a revision zero." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:590 +msgid "" +"Neither will it work in the (extremely rare) case where a repository is a " +"merge of two or more formerly independent repositories, and you still have " +"those repositories around." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:595 +msgid "Here are some uses to which you could put this identifier:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:598 +msgid "" +"As a key into a table for a database that manages repositories on a server." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:601 +msgid "" +"As half of a {<emphasis>repository ID</emphasis>, <emphasis>revision ID</" +"emphasis>} tuple. Save this information away when you run an automated build " +"or other activity, so that you can <quote>replay</quote> the build later if " +"necessary." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch10-template.xml:610 +msgid "Mimicking Subversion's output" +msgstr "模仿 Subversion 的输出" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:612 +msgid "" +"Let's try to emulate the default output format used by another revision " +"control tool, Subversion." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:617 +msgid "" +"Since Subversion's output style is fairly simple, it is easy to copy-and-" +"paste a hunk of its output into a file, and replace the text produced above " +"by Subversion with the template values we'd like to see expanded." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:624 +msgid "" +"There are a few small ways in which this template deviates from the output " +"produced by Subversion." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:627 +msgid "" +"Subversion prints a <quote>readable</quote> date (the <quote><literal>Wed, 27 " +"Sep 2006</literal></quote> in the example output above) in parentheses. " +"Mercurial's templating engine does not provide a way to display a date in " +"this format without also printing the time and time zone." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:634 +msgid "" +"We emulate Subversion's printing of <quote>separator</quote> lines full of " +"<quote><literal>-</literal></quote> characters by ending the template with " +"such a line. We use the templating engine's <literal role=\"template-keyword" +"\">header</literal> keyword to print a separator line as the first line of " +"output (see below), thus achieving similar output to Subversion." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch10-template.xml:643 +msgid "" +"Subversion's output includes a count in the header of the number of lines in " +"the commit message. We cannot replicate this in Mercurial; the templating " +"engine does not currently provide a filter that counts the number of lines " +"the template generates." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:649 +msgid "" +"It took me no more than a minute or two of work to replace literal text from " +"an example of Subversion's output with some keywords and filters to give the " +"template above. The style file simply refers to the template." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch10-template.xml:656 +msgid "" +"We could have included the text of the template file directly in the style " +"file by enclosing it in quotes and replacing the newlines with " +"<quote><literal>\\n</literal></quote> sequences, but it would have made the " +"style file too difficult to read. Readability is a good guide when you're " +"trying to decide whether some text belongs in a style file, or in a template " +"file that the style file points to. If the style file will look too big or " +"cluttered if you insert a literal piece of text, drop it into a template " +"instead." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch11-mq.xml:5 +msgid "Managing change with Mercurial Queues" +msgstr "使用 MQ 管理修改" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:8 +msgid "The patch management problem" +msgstr "补丁的管理问题" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:10 +msgid "" +"Here is a common scenario: you need to install a software package from " +"source, but you find a bug that you must fix in the source before you can " +"start using the package. You make your changes, forget about the package for " +"a while, and a few months later you need to upgrade to a newer version of the " +"package. If the newer version of the package still has the bug, you must " +"extract your fix from the older source tree and apply it against the newer " +"version. This is a tedious task, and it's easy to make mistakes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:20 +msgid "" +"This is a simple case of the <quote>patch management</quote> problem. You " +"have an <quote>upstream</quote> source tree that you can't change; you need " +"to make some local changes on top of the upstream tree; and you'd like to be " +"able to keep those changes separate, so that you can apply them to newer " +"versions of the upstream source." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:27 +msgid "" +"The patch management problem arises in many situations. Probably the most " +"visible is that a user of an open source software project will contribute a " +"bug fix or new feature to the project's maintainers in the form of a patch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:32 +msgid "" +"Distributors of operating systems that include open source software often " +"need to make changes to the packages they distribute so that they will build " +"properly in their environments." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:37 +msgid "" +"When you have few changes to maintain, it is easy to manage a single patch " +"using the standard <command>diff</command> and <command>patch</command> " +"programs (see section <xref linkend=\"sec.mq.patch\"/> for a discussion of " +"these tools). Once the number of changes grows, it starts to make sense to " +"maintain patches as discrete <quote>chunks of work,</quote> so that for " +"example a single patch will contain only one bug fix (the patch might modify " +"several files, but it's doing <quote>only one thing</quote>), and you may " +"have a number of such patches for different bugs you need fixed and local " +"changes you require. In this situation, if you submit a bug fix patch to the " +"upstream maintainers of a package and they include your fix in a subsequent " +"release, you can simply drop that single patch when you're updating to the " +"newer release." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:52 +msgid "" +"Maintaining a single patch against an upstream tree is a little tedious and " +"error-prone, but not difficult. However, the complexity of the problem grows " +"rapidly as the number of patches you have to maintain increases. With more " +"than a tiny number of patches in hand, understanding which ones you have " +"applied and maintaining them moves from messy to overwhelming." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:59 +msgid "" +"Fortunately, Mercurial includes a powerful extension, Mercurial Queues (or " +"simply <quote>MQ</quote>), that massively simplifies the patch management " +"problem." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:65 +msgid "The prehistory of Mercurial Queues" +msgstr "MQ 的历史" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:67 +msgid "" +"During the late 1990s, several Linux kernel developers started to maintain " +"<quote>patch series</quote> that modified the behaviour of the Linux kernel. " +"Some of these series were focused on stability, some on feature coverage, and " +"others were more speculative." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:73 +msgid "" +"The sizes of these patch series grew rapidly. In 2002, Andrew Morton " +"published some shell scripts he had been using to automate the task of " +"managing his patch queues. Andrew was successfully using these scripts to " +"manage hundreds (sometimes thousands) of patches on top of the Linux kernel." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:80 +msgid "A patchwork quilt" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:82 +msgid "" +"In early 2003, Andreas Gruenbacher and Martin Quinson borrowed the approach " +"of Andrew's scripts and published a tool called <quote>patchwork quilt</" +"quote> <citation>web:quilt</citation>, or simply <quote>quilt</quote> (see " +"<citation>gruenbacher:2005</citation> for a paper describing it). Because " +"quilt substantially automated patch management, it rapidly gained a large " +"following among open source software developers." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:91 +msgid "" +"Quilt manages a <emphasis>stack of patches</emphasis> on top of a directory " +"tree. To begin, you tell quilt to manage a directory tree, and tell it which " +"files you want to manage; it stores away the names and contents of those " +"files. To fix a bug, you create a new patch (using a single command), edit " +"the files you need to fix, then <quote>refresh</quote> the patch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:99 +msgid "" +"The refresh step causes quilt to scan the directory tree; it updates the " +"patch with all of the changes you have made. You can create another patch on " +"top of the first, which will track the changes required to modify the tree " +"from <quote>tree with one patch applied</quote> to <quote>tree with two " +"patches applied</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:106 +msgid "" +"You can <emphasis>change</emphasis> which patches are applied to the tree. " +"If you <quote>pop</quote> a patch, the changes made by that patch will vanish " +"from the directory tree. Quilt remembers which patches you have popped, " +"though, so you can <quote>push</quote> a popped patch again, and the " +"directory tree will be restored to contain the modifications in the patch. " +"Most importantly, you can run the <quote>refresh</quote> command at any time, " +"and the topmost applied patch will be updated. This means that you can, at " +"any time, change both which patches are applied and what modifications those " +"patches make." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:118 +msgid "" +"Quilt knows nothing about revision control tools, so it works equally well on " +"top of an unpacked tarball or a Subversion working copy." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:124 +msgid "From patchwork quilt to Mercurial Queues" +msgstr "从 patchwork quilt 到 MQ" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:126 +msgid "" +"In mid-2005, Chris Mason took the features of quilt and wrote an extension " +"that he called Mercurial Queues, which added quilt-like behaviour to " +"Mercurial." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:130 +msgid "" +"The key difference between quilt and MQ is that quilt knows nothing about " +"revision control systems, while MQ is <emphasis>integrated</emphasis> into " +"Mercurial. Each patch that you push is represented as a Mercurial " +"changeset. Pop a patch, and the changeset goes away." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:136 +msgid "" +"Because quilt does not care about revision control tools, it is still a " +"tremendously useful piece of software to know about for situations where you " +"cannot use Mercurial and MQ." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:144 +msgid "The huge advantage of MQ" +msgstr "MQ 的巨大优势" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:146 +msgid "" +"I cannot overstate the value that MQ offers through the unification of " +"patches and revision control." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:149 +msgid "" +"A major reason that patches have persisted in the free software and open " +"source world&emdash;in spite of the availability of increasingly capable " +"revision control tools over the years&emdash;is the <emphasis>agility</" +"emphasis> they offer." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:155 +msgid "" +"Traditional revision control tools make a permanent, irreversible record of " +"everything that you do. While this has great value, it's also somewhat " +"stifling. If you want to perform a wild-eyed experiment, you have to be " +"careful in how you go about it, or you risk leaving unneeded&emdash;or worse, " +"misleading or destabilising&emdash;traces of your missteps and errors in the " +"permanent revision record." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:163 +msgid "" +"By contrast, MQ's marriage of distributed revision control with patches makes " +"it much easier to isolate your work. Your patches live on top of normal " +"revision history, and you can make them disappear or reappear at will. If " +"you don't like a patch, you can drop it. If a patch isn't quite as you want " +"it to be, simply fix it&emdash;as many times as you need to, until you have " +"refined it into the form you desire." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:171 +msgid "" +"As an example, the integration of patches with revision control makes " +"understanding patches and debugging their effects&emdash;and their interplay " +"with the code they're based on&emdash;<emphasis>enormously</emphasis> easier. " +"Since every applied patch has an associated changeset, you can give <command " +"role=\"hg-cmd\">hg log</command> a file name to see which changesets and " +"patches affected the file. You can use the <command role=\"hg-cmd\">hg " +"bisect</command> command to binary-search through all changesets and applied " +"patches to see where a bug got introduced or fixed. You can use the <command " +"role=\"hg-cmd\">hg annotate</command> command to see which changeset or patch " +"modified a particular line of a source file. And so on." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:187 +msgid "Understanding patches" +msgstr "理解补丁" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:189 +msgid "" +"Because MQ doesn't hide its patch-oriented nature, it is helpful to " +"understand what patches are, and a little about the tools that work with them." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:193 +msgid "" +"The traditional Unix <command>diff</command> command compares two files, and " +"prints a list of differences between them. The <command>patch</command> " +"command understands these differences as <emphasis>modifications</emphasis> " +"to make to a file. Take a look below for a simple example of these commands " +"in action." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:202 +msgid "" +"The type of file that <command>diff</command> generates (and <command>patch</" +"command> takes as input) is called a <quote>patch</quote> or a <quote>diff</" +"quote>; there is no difference between a patch and a diff. (We'll use the " +"term <quote>patch</quote>, since it's more commonly used.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:208 +msgid "" +"A patch file can start with arbitrary text; the <command>patch</command> " +"command ignores this text, but MQ uses it as the commit message when creating " +"changesets. To find the beginning of the patch content, <command>patch</" +"command> searches for the first line that starts with the string " +"<quote><literal>diff -</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:215 +msgid "" +"MQ works with <emphasis>unified</emphasis> diffs (<command>patch</command> " +"can accept several other diff formats, but MQ doesn't). A unified diff " +"contains two kinds of header. The <emphasis>file header</emphasis> describes " +"the file being modified; it contains the name of the file to modify. When " +"<command>patch</command> sees a new file header, it looks for a file with " +"that name to start modifying." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:223 +msgid "" +"After the file header comes a series of <emphasis>hunks</emphasis>. Each " +"hunk starts with a header; this identifies the range of line numbers within " +"the file that the hunk should modify. Following the header, a hunk starts " +"and ends with a few (usually three) lines of text from the unmodified file; " +"these are called the <emphasis>context</emphasis> for the hunk. If there's " +"only a small amount of context between successive hunks, <command>diff</" +"command> doesn't print a new hunk header; it just runs the hunks together, " +"with a few lines of context between modifications." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:235 +msgid "" +"Each line of context begins with a space character. Within the hunk, a line " +"that begins with <quote><literal>-</literal></quote> means <quote>remove this " +"line,</quote> while a line that begins with <quote><literal>+</literal></" +"quote> means <quote>insert this line.</quote> For example, a line that is " +"modified is represented by one deletion and one insertion." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:243 +msgid "" +"We will return to some of the more subtle aspects of patches later (in " +"section <xref linkend=\"sec.mq.adv-patch\"/>), but you should have enough " +"information now to use MQ." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:250 +msgid "Getting started with Mercurial Queues" +msgstr "开始使用 MQ" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:252 +msgid "" +"Because MQ is implemented as an extension, you must explicitly enable before " +"you can use it. (You don't need to download anything; MQ ships with the " +"standard Mercurial distribution.) To enable MQ, edit your <filename role=" +"\"home\">~/.hgrc</filename> file, and add the lines below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:262 +msgid "" +"Once the extension is enabled, it will make a number of new commands " +"available. To verify that the extension is working, you can use <command " +"role=\"hg-cmd\">hg help</command> to see if the <command role=\"hg-ext-mq" +"\">qinit</command> command is now available." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:270 +msgid "" +"You can use MQ with <emphasis>any</emphasis> Mercurial repository, and its " +"commands only operate within that repository. To get started, simply prepare " +"the repository using the <command role=\"hg-ext-mq\">qinit</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:277 +msgid "" +"This command creates an empty directory called <filename role=\"special\" " +"class=\"directory\">.hg/patches</filename>, where MQ will keep its metadata. " +"As with many Mercurial commands, the <command role=\"hg-ext-mq\">qinit</" +"command> command prints nothing if it succeeds." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:284 +msgid "Creating a new patch" +msgstr "创建新补丁" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:286 +msgid "" +"To begin work on a new patch, use the <command role=\"hg-ext-mq\">qnew</" +"command> command. This command takes one argument, the name of the patch to " +"create." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:290 +msgid "" +"MQ will use this as the name of an actual file in the <filename role=\"special" +"\" class=\"directory\">.hg/patches</filename> directory, as you can see below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:297 +msgid "" +"Also newly present in the <filename role=\"special\" class=\"directory\">.hg/" +"patches</filename> directory are two other files, <filename role=\"special" +"\">series</filename> and <filename role=\"special\">status</filename>. The " +"<filename role=\"special\">series</filename> file lists all of the patches " +"that MQ knows about for this repository, with one patch per line. Mercurial " +"uses the <filename role=\"special\">status</filename> file for internal book-" +"keeping; it tracks all of the patches that MQ has <emphasis>applied</" +"emphasis> in this repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch11-mq.xml:309 +msgid "" +"You may sometimes want to edit the <filename role=\"special\">series</" +"filename> file by hand; for example, to change the sequence in which some " +"patches are applied. However, manually editing the <filename role=\"special" +"\">status</filename> file is almost always a bad idea, as it's easy to " +"corrupt MQ's idea of what is happening." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:318 +msgid "" +"Once you have created your new patch, you can edit files in the working " +"directory as you usually would. All of the normal Mercurial commands, such " +"as <command role=\"hg-cmd\">hg diff</command> and <command role=\"hg-cmd\">hg " +"annotate</command>, work exactly as they did before." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:326 +msgid "Refreshing a patch" +msgstr "刷新补丁" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:328 +msgid "" +"When you reach a point where you want to save your work, use the <command " +"role=\"hg-ext-mq\">qrefresh</command> command to update the patch you are " +"working on." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:334 +msgid "" +"This command folds the changes you have made in the working directory into " +"your patch, and updates its corresponding changeset to contain those changes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:338 +msgid "" +"You can run <command role=\"hg-ext-mq\">qrefresh</command> as often as you " +"like, so it's a good way to <quote>checkpoint</quote> your work. Refresh " +"your patch at an opportune time; try an experiment; and if the experiment " +"doesn't work out, <command role=\"hg-cmd\">hg revert</command> your " +"modifications back to the last time you refreshed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:349 +msgid "Stacking and tracking patches" +msgstr "堆叠和跟踪补丁" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:351 +msgid "" +"Once you have finished working on a patch, or need to work on another, you " +"can use the <command role=\"hg-ext-mq\">qnew</command> command again to " +"create a new patch. Mercurial will apply this patch on top of your existing " +"patch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:358 +msgid "" +"Notice that the patch contains the changes in our prior patch as part of its " +"context (you can see this more clearly in the output of <command role=\"hg-cmd" +"\">hg annotate</command>)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:363 +msgid "" +"So far, with the exception of <command role=\"hg-ext-mq\">qnew</command> and " +"<command role=\"hg-ext-mq\">qrefresh</command>, we've been careful to only " +"use regular Mercurial commands. However, MQ provides many commands that are " +"easier to use when you are thinking about patches, as illustrated below." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:373 +msgid "" +"The <command role=\"hg-ext-mq\">qseries</command> command lists every patch " +"that MQ knows about in this repository, from oldest to newest (most recently " +"<emphasis>created</emphasis>)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:379 +msgid "" +"The <command role=\"hg-ext-mq\">qapplied</command> command lists every patch " +"that MQ has <emphasis>applied</emphasis> in this repository, again from " +"oldest to newest (most recently applied)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:388 +msgid "Manipulating the patch stack" +msgstr "操作补丁堆栈" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:390 +msgid "" +"The previous discussion implied that there must be a difference between " +"<quote>known</quote> and <quote>applied</quote> patches, and there is. MQ " +"can manage a patch without it being applied in the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:395 +msgid "" +"An <emphasis>applied</emphasis> patch has a corresponding changeset in the " +"repository, and the effects of the patch and changeset are visible in the " +"working directory. You can undo the application of a patch using the " +"<command role=\"hg-ext-mq\">qpop</command> command. MQ still <emphasis>knows " +"about</emphasis>, or manages, a popped patch, but the patch no longer has a " +"corresponding changeset in the repository, and the working directory does not " +"contain the changes made by the patch. Figure <xref endterm=\"fig.mq.stack." +"caption\" linkend=\"fig.mq.stack\"/> illustrates the difference between " +"applied and tracked patches." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject> +#: ../en/ch11-mq.xml:409 +msgid "<imageobject><imagedata fileref=\"images/mq-stack.png\"/></imageobject>" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><informalfigure><mediaobject><caption><para> +#: ../en/ch11-mq.xml:411 +msgid "Applied and unapplied patches in the MQ patch stack" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:416 +msgid "" +"You can reapply an unapplied, or popped, patch using the <command role=\"hg-" +"ext-mq\">qpush</command> command. This creates a new changeset to correspond " +"to the patch, and the patch's changes once again become present in the " +"working directory. See below for examples of <command role=\"hg-ext-mq" +"\">qpop</command> and <command role=\"hg-ext-mq\">qpush</command> in action." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:425 +msgid "" +"Notice that once we have popped a patch or two patches, the output of " +"<command role=\"hg-ext-mq\">qseries</command> remains the same, while that of " +"<command role=\"hg-ext-mq\">qapplied</command> has changed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:433 +msgid "Pushing and popping many patches" +msgstr "压入或弹出多个补丁" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:435 +msgid "" +"While <command role=\"hg-ext-mq\">qpush</command> and <command role=\"hg-ext-" +"mq\">qpop</command> each operate on a single patch at a time by default, you " +"can push and pop many patches in one go. The <option role=\"hg-ext-mq-cmd-" +"qpush-opt\">hg -a</option> option to <command role=\"hg-ext-mq\">qpush</" +"command> causes it to push all unapplied patches, while the <option role=\"hg-" +"ext-mq-cmd-qpop-opt\">-a</option> option to <command role=\"hg-ext-mq\">qpop</" +"command> causes it to pop all applied patches. (For some more ways to push " +"and pop many patches, see section <xref linkend=\"sec.mq.perf\"/> below.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:452 +msgid "Safety checks, and overriding them" +msgstr "安全的检查,然后覆盖它们" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:454 +msgid "" +"Several MQ commands check the working directory before they do anything, and " +"fail if they find any modifications. They do this to ensure that you won't " +"lose any changes that you have made, but not yet incorporated into a patch. " +"The example below illustrates this; the <command role=\"hg-ext-mq\">qnew</" +"command> command will not create a new patch if there are outstanding " +"changes, caused in this case by the <command role=\"hg-cmd\">hg add</command> " +"of <filename>file3</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:466 +msgid "" +"Commands that check the working directory all take an <quote>I know what I'm " +"doing</quote> option, which is always named <option>-f</option>. The exact " +"meaning of <option>-f</option> depends on the command. For example, <command " +"role=\"hg-cmd\">hg qnew <option role=\"hg-ext-mq-cmd-qnew-opt\">hg -f</" +"option></command> will incorporate any outstanding changes into the new patch " +"it creates, but <command role=\"hg-cmd\">hg qpop <option role=\"hg-ext-mq-cmd-" +"qpop-opt\">hg -f</option></command> will revert modifications to any files " +"affected by the patch that it is popping. Be sure to read the documentation " +"for a command's <option>-f</option> option before you use it!" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:481 +msgid "Working on several patches at once" +msgstr "同时处理多个补丁" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:483 +msgid "" +"The <command role=\"hg-ext-mq\">qrefresh</command> command always refreshes " +"the <emphasis>topmost</emphasis> applied patch. This means that you can " +"suspend work on one patch (by refreshing it), pop or push to make a different " +"patch the top, and work on <emphasis>that</emphasis> patch for a while." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:490 +msgid "" +"Here's an example that illustrates how you can use this ability. Let's say " +"you're developing a new feature as two patches. The first is a change to the " +"core of your software, and the second&emdash;layered on top of the " +"first&emdash;changes the user interface to use the code you just added to the " +"core. If you notice a bug in the core while you're working on the UI patch, " +"it's easy to fix the core. Simply <command role=\"hg-ext-mq\">qrefresh</" +"command> the UI patch to save your in-progress changes, and <command role=" +"\"hg-ext-mq\">qpop</command> down to the core patch. Fix the core bug, " +"<command role=\"hg-ext-mq\">qrefresh</command> the core patch, and <command " +"role=\"hg-ext-mq\">qpush</command> back to the UI patch to continue where you " +"left off." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:507 +msgid "More about patches" +msgstr "关于补丁的更多信息" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:509 +msgid "" +"MQ uses the GNU <command>patch</command> command to apply patches, so it's " +"helpful to know a few more detailed aspects of how <command>patch</command> " +"works, and about patches themselves." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:515 +msgid "The strip count" +msgstr "修剪计数" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:517 +msgid "" +"If you look at the file headers in a patch, you will notice that the " +"pathnames usually have an extra component on the front that isn't present in " +"the actual path name. This is a holdover from the way that people used to " +"generate patches (people still do this, but it's somewhat rare with modern " +"revision control tools)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:524 +msgid "" +"Alice would unpack a tarball, edit her files, then decide that she wanted to " +"create a patch. So she'd rename her working directory, unpack the tarball " +"again (hence the need for the rename), and use the <option role=\"cmd-opt-diff" +"\">-r</option> and <option role=\"cmd-opt-diff\">-N</option> options to " +"<command>diff</command> to recursively generate a patch between the " +"unmodified directory and the modified one. The result would be that the name " +"of the unmodified directory would be at the front of the left-hand path in " +"every file header, and the name of the modified directory would be at the " +"front of the right-hand path." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:537 +msgid "" +"Since someone receiving a patch from the Alices of the net would be unlikely " +"to have unmodified and modified directories with exactly the same names, the " +"<command>patch</command> command has a <option role=\"cmd-opt-patch\">-p</" +"option> option that indicates the number of leading path name components to " +"strip when trying to apply a patch. This number is called the " +"<emphasis>strip count</emphasis>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:545 +msgid "" +"An option of <quote><literal>-p1</literal></quote> means <quote>use a strip " +"count of one</quote>. If <command>patch</command> sees a file name " +"<filename>foo/bar/baz</filename> in a file header, it will strip " +"<filename>foo</filename> and try to patch a file named <filename>bar/baz</" +"filename>. (Strictly speaking, the strip count refers to the number of " +"<emphasis>path separators</emphasis> (and the components that go with them ) " +"to strip. A strip count of one will turn <filename>foo/bar</filename> into " +"<filename>bar</filename>, but <filename>/foo/bar</filename> (notice the extra " +"leading slash) into <filename>foo/bar</filename>.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:558 +msgid "" +"The <quote>standard</quote> strip count for patches is one; almost all " +"patches contain one leading path name component that needs to be stripped. " +"Mercurial's <command role=\"hg-cmd\">hg diff</command> command generates path " +"names in this form, and the <command role=\"hg-cmd\">hg import</command> " +"command and MQ expect patches to have a strip count of one." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:566 +msgid "" +"If you receive a patch from someone that you want to add to your patch queue, " +"and the patch needs a strip count other than one, you cannot just <command " +"role=\"hg-ext-mq\">qimport</command> the patch, because <command role=\"hg-" +"ext-mq\">qimport</command> does not yet have a <literal>-p</literal> option " +"(see <ulink role=\"hg-bug\" url=\"http://www.selenic.com/mercurial/bts/" +"issue311\">issue 311</ulink>). Your best bet is to <command role=\"hg-ext-mq" +"\">qnew</command> a patch of your own, then use <command>patch -pN</command> " +"to apply their patch, followed by <command role=\"hg-cmd\">hg addremove</" +"command> to pick up any files added or removed by the patch, followed by " +"<command role=\"hg-ext-mq\">hg qrefresh</command>. This complexity may become " +"unnecessary; see <ulink role=\"hg-bug\" url=\"http://www.selenic.com/" +"mercurial/bts/issue311\">issue 311</ulink> for details." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:585 +msgid "Strategies for applying a patch" +msgstr "应用补丁的策略" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:587 +msgid "" +"When <command>patch</command> applies a hunk, it tries a handful of " +"successively less accurate strategies to try to make the hunk apply. This " +"falling-back technique often makes it possible to take a patch that was " +"generated against an old version of a file, and apply it against a newer " +"version of that file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:594 +msgid "" +"First, <command>patch</command> tries an exact match, where the line numbers, " +"the context, and the text to be modified must apply exactly. If it cannot " +"make an exact match, it tries to find an exact match for the context, without " +"honouring the line numbering information. If this succeeds, it prints a line " +"of output saying that the hunk was applied, but at some <emphasis>offset</" +"emphasis> from the original line number." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:603 +msgid "" +"If a context-only match fails, <command>patch</command> removes the first and " +"last lines of the context, and tries a <emphasis>reduced</emphasis> context-" +"only match. If the hunk with reduced context succeeds, it prints a message " +"saying that it applied the hunk with a <emphasis>fuzz factor</emphasis> (the " +"number after the fuzz factor indicates how many lines of context " +"<command>patch</command> had to trim before the patch applied)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:612 +msgid "" +"When neither of these techniques works, <command>patch</command> prints a " +"message saying that the hunk in question was rejected. It saves rejected " +"hunks (also simply called <quote>rejects</quote>) to a file with the same " +"name, and an added <filename role=\"special\">.rej</filename> extension. It " +"also saves an unmodified copy of the file with a <filename role=\"special\">." +"orig</filename> extension; the copy of the file without any extensions will " +"contain any changes made by hunks that <emphasis>did</emphasis> apply " +"cleanly. If you have a patch that modifies <filename>foo</filename> with six " +"hunks, and one of them fails to apply, you will have: an unmodified " +"<filename>foo.orig</filename>, a <filename>foo.rej</filename> containing one " +"hunk, and <filename>foo</filename>, containing the changes made by the five " +"successful hunks." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:630 +msgid "Some quirks of patch representation" +msgstr "补丁的一些特性" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:632 +msgid "" +"There are a few useful things to know about how <command>patch</command> " +"works with files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:635 +msgid "" +"This should already be obvious, but <command>patch</command> cannot handle " +"binary files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:639 +msgid "" +"Neither does it care about the executable bit; it creates new files as " +"readable, but not executable." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:643 +msgid "" +"<command>patch</command> treats the removal of a file as a diff between the " +"file to be removed and the empty file. So your idea of <quote>I deleted this " +"file</quote> looks like <quote>every line of this file was deleted</quote> in " +"a patch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:649 +msgid "" +"It treats the addition of a file as a diff between the empty file and the " +"file to be added. So in a patch, your idea of <quote>I added this file</" +"quote> looks like <quote>every line of this file was added</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:655 +msgid "" +"It treats a renamed file as the removal of the old name, and the addition of " +"the new name. This means that renamed files have a big footprint in " +"patches. (Note also that Mercurial does not currently try to infer when " +"files have been renamed or copied in a patch.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:661 +msgid "" +"<command>patch</command> cannot represent empty files, so you cannot use a " +"patch to represent the notion <quote>I added this empty file to the tree</" +"quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:668 +msgid "Beware the fuzz" +msgstr "当心毛刺" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:670 +msgid "" +"While applying a hunk at an offset, or with a fuzz factor, will often be " +"completely successful, these inexact techniques naturally leave open the " +"possibility of corrupting the patched file. The most common cases typically " +"involve applying a patch twice, or at an incorrect location in the file. If " +"<command>patch</command> or <command role=\"hg-ext-mq\">qpush</command> ever " +"mentions an offset or fuzz factor, you should make sure that the modified " +"files are correct afterwards." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:680 +msgid "" +"It's often a good idea to refresh a patch that has applied with an offset or " +"fuzz factor; refreshing the patch generates new context information that will " +"make it apply cleanly. I say <quote>often,</quote> not <quote>always,</" +"quote> because sometimes refreshing a patch will make it fail to apply " +"against a different revision of the underlying files. In some cases, such as " +"when you're maintaining a patch that must sit on top of multiple versions of " +"a source tree, it's acceptable to have a patch apply with some fuzz, provided " +"you've verified the results of the patching process in such cases." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:693 +msgid "Handling rejection" +msgstr "处理拒绝" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:695 +msgid "" +"If <command role=\"hg-ext-mq\">qpush</command> fails to apply a patch, it " +"will print an error message and exit. If it has left <filename role=\"special" +"\">.rej</filename> files behind, it is usually best to fix up the rejected " +"hunks before you push more patches or do any further work." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:701 +msgid "" +"If your patch <emphasis>used to</emphasis> apply cleanly, and no longer does " +"because you've changed the underlying code that your patches are based on, " +"Mercurial Queues can help; see section <xref linkend=\"sec.mq.merge\"/> for " +"details." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:707 +msgid "" +"Unfortunately, there aren't any great techniques for dealing with rejected " +"hunks. Most often, you'll need to view the <filename role=\"special\">.rej</" +"filename> file and edit the target file, applying the rejected hunks by hand." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:712 +msgid "" +"If you're feeling adventurous, Neil Brown, a Linux kernel hacker, wrote a " +"tool called <command>wiggle</command> <citation>web:wiggle</citation>, which " +"is more vigorous than <command>patch</command> in its attempts to make a " +"patch apply." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:718 +msgid "" +"Another Linux kernel hacker, Chris Mason (the author of Mercurial Queues), " +"wrote a similar tool called <command>mpatch</command> <citation>web:mpatch</" +"citation>, which takes a simple approach to automating the application of " +"hunks rejected by <command>patch</command>. The <command>mpatch</command> " +"command can help with four common reasons that a hunk may be rejected:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:727 +msgid "The context in the middle of a hunk has changed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:730 +msgid "A hunk is missing some context at the beginning or end." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:733 +msgid "" +"A large hunk might apply better&emdash;either entirely or in part&emdash;if " +"it was broken up into smaller hunks." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:737 +msgid "" +"A hunk removes lines with slightly different content than those currently " +"present in the file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:741 +msgid "" +"If you use <command>wiggle</command> or <command>mpatch</command>, you should " +"be doubly careful to check your results when you're done. In fact, " +"<command>mpatch</command> enforces this method of double-checking the tool's " +"output, by automatically dropping you into a merge program when it has done " +"its job, so that you can verify its work and finish off any remaining merges." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:753 +msgid "Getting the best performance out of MQ" +msgstr "MQ 的性能" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:755 +msgid "" +"MQ is very efficient at handling a large number of patches. I ran some " +"performance experiments in mid-2006 for a talk that I gave at the 2006 " +"EuroPython conference <citation>web:europython</citation>. I used as my data " +"set the Linux 2.6.17-mm1 patch series, which consists of 1,738 patches. I " +"applied these on top of a Linux kernel repository containing all 27,472 " +"revisions between Linux 2.6.12-rc2 and Linux 2.6.17." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:764 +msgid "" +"On my old, slow laptop, I was able to <command role=\"hg-cmd\">hg qpush " +"<option role=\"hg-ext-mq-cmd-qpush-opt\">hg -a</option></command> all 1,738 " +"patches in 3.5 minutes, and <command role=\"hg-cmd\">hg qpop <option role=" +"\"hg-ext-mq-cmd-qpop-opt\">hg -a</option></command> them all in 30 seconds. " +"(On a newer laptop, the time to push all patches dropped to two minutes.) I " +"could <command role=\"hg-ext-mq\">qrefresh</command> one of the biggest " +"patches (which made 22,779 lines of changes to 287 files) in 6.6 seconds." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:775 +msgid "" +"Clearly, MQ is well suited to working in large trees, but there are a few " +"tricks you can use to get the best performance of it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:779 +msgid "" +"First of all, try to <quote>batch</quote> operations together. Every time " +"you run <command role=\"hg-ext-mq\">qpush</command> or <command role=\"hg-ext-" +"mq\">qpop</command>, these commands scan the working directory once to make " +"sure you haven't made some changes and then forgotten to run <command role=" +"\"hg-ext-mq\">qrefresh</command>. On a small tree, the time that this scan " +"takes is unnoticeable. However, on a medium-sized tree (containing tens of " +"thousands of files), it can take a second or more." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:790 +msgid "" +"The <command role=\"hg-ext-mq\">qpush</command> and <command role=\"hg-ext-mq" +"\">qpop</command> commands allow you to push and pop multiple patches at a " +"time. You can identify the <quote>destination patch</quote> that you want to " +"end up at. When you <command role=\"hg-ext-mq\">qpush</command> with a " +"destination specified, it will push patches until that patch is at the top of " +"the applied stack. When you <command role=\"hg-ext-mq\">qpop</command> to a " +"destination, MQ will pop patches until the destination patch is at the top." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:800 +msgid "" +"You can identify a destination patch using either the name of the patch, or " +"by number. If you use numeric addressing, patches are counted from zero; " +"this means that the first patch is zero, the second is one, and so on." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:807 +msgid "Updating your patches when the underlying code changes" +msgstr "当基础代码改变时,更新补丁的方法" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:810 +msgid "" +"It's common to have a stack of patches on top of an underlying repository " +"that you don't modify directly. If you're working on changes to third-party " +"code, or on a feature that is taking longer to develop than the rate of " +"change of the code beneath, you will often need to sync up with the " +"underlying code, and fix up any hunks in your patches that no longer apply. " +"This is called <emphasis>rebasing</emphasis> your patch series." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:819 +msgid "" +"The simplest way to do this is to <command role=\"hg-cmd\">hg qpop <option " +"role=\"hg-ext-mq-cmd-qpop-opt\">hg -a</option></command> your patches, then " +"<command role=\"hg-cmd\">hg pull</command> changes into the underlying " +"repository, and finally <command role=\"hg-cmd\">hg qpush <option role=\"hg-" +"ext-mq-cmd-qpop-opt\">hg -a</option></command> your patches again. MQ will " +"stop pushing any time it runs across a patch that fails to apply during " +"conflicts, allowing you to fix your conflicts, <command role=\"hg-ext-mq" +"\">qrefresh</command> the affected patch, and continue pushing until you have " +"fixed your entire stack." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:831 +msgid "" +"This approach is easy to use and works well if you don't expect changes to " +"the underlying code to affect how well your patches apply. If your patch " +"stack touches code that is modified frequently or invasively in the " +"underlying repository, however, fixing up rejected hunks by hand quickly " +"becomes tiresome." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:838 +msgid "" +"It's possible to partially automate the rebasing process. If your patches " +"apply cleanly against some revision of the underlying repo, MQ can use this " +"information to help you to resolve conflicts between your patches and a " +"different revision." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:844 +msgid "The process is a little involved." +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch11-mq.xml:846 +msgid "" +"To begin, <command role=\"hg-cmd\">hg qpush -a</command> all of your patches " +"on top of the revision where you know that they apply cleanly." +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch11-mq.xml:850 +msgid "" +"Save a backup copy of your patch directory using <command role=\"hg-cmd\">hg " +"qsave <option role=\"hg-ext-mq-cmd-qsave-opt\">hg -e</option> <option role=" +"\"hg-ext-mq-cmd-qsave-opt\">hg -c</option></command>. This prints the name " +"of the directory that it has saved the patches in. It will save the patches " +"to a directory called <filename role=\"special\" class=\"directory\">.hg/" +"patches.N</filename>, where <literal>N</literal> is a small integer. It also " +"commits a <quote>save changeset</quote> on top of your applied patches; this " +"is for internal book-keeping, and records the states of the <filename role=" +"\"special\">series</filename> and <filename role=\"special\">status</" +"filename> files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch11-mq.xml:864 +msgid "" +"Use <command role=\"hg-cmd\">hg pull</command> to bring new changes into the " +"underlying repository. (Don't run <command role=\"hg-cmd\">hg pull -u</" +"command>; see below for why.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch11-mq.xml:869 +msgid "" +"Update to the new tip revision, using <command role=\"hg-cmd\">hg update " +"<option role=\"hg-opt-update\">-C</option></command> to override the patches " +"you have pushed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch11-mq.xml:874 +msgid "" +"Merge all patches using <command>hg qpush -m -a</command>. The <option role=" +"\"hg-ext-mq-cmd-qpush-opt\">-m</option> option to <command role=\"hg-ext-mq" +"\">qpush</command> tells MQ to perform a three-way merge if the patch fails " +"to apply." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:882 +msgid "" +"During the <command role=\"hg-cmd\">hg qpush <option role=\"hg-ext-mq-cmd-" +"qpush-opt\">hg -m</option></command>, each patch in the <filename role=" +"\"special\">series</filename> file is applied normally. If a patch applies " +"with fuzz or rejects, MQ looks at the queue you <command role=\"hg-ext-mq" +"\">qsave</command>d, and performs a three-way merge with the corresponding " +"changeset. This merge uses Mercurial's normal merge machinery, so it may pop " +"up a GUI merge tool to help you to resolve problems." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:892 +msgid "" +"When you finish resolving the effects of a patch, MQ refreshes your patch " +"based on the result of the merge." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:895 +msgid "" +"At the end of this process, your repository will have one extra head from the " +"old patch queue, and a copy of the old patch queue will be in <filename role=" +"\"special\" class=\"directory\">.hg/patches.N</filename>. You can remove the " +"extra head using <command role=\"hg-cmd\">hg qpop -a -n patches.N</command> " +"or <command role=\"hg-cmd\">hg strip</command>. You can delete <filename " +"role=\"special\" class=\"directory\">.hg/patches.N</filename> once you are " +"sure that you no longer need it as a backup." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:907 +msgid "Identifying patches" +msgstr "标识补丁" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:909 +msgid "" +"MQ commands that work with patches let you refer to a patch either by using " +"its name or by a number. By name is obvious enough; pass the name " +"<filename>foo.patch</filename> to <command role=\"hg-ext-mq\">qpush</" +"command>, for example, and it will push patches until <filename>foo.patch</" +"filename> is applied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:916 +msgid "" +"As a shortcut, you can refer to a patch using both a name and a numeric " +"offset; <literal>foo.patch-2</literal> means <quote>two patches before " +"<literal>foo.patch</literal></quote>, while <literal>bar.patch+4</literal> " +"means <quote>four patches after <literal>bar.patch</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:922 +msgid "" +"Referring to a patch by index isn't much different. The first patch printed " +"in the output of <command role=\"hg-ext-mq\">qseries</command> is patch zero " +"(yes, it's one of those start-at-zero counting systems); the second is patch " +"one; and so on." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:928 +msgid "" +"MQ also makes it easy to work with patches when you are using normal " +"Mercurial commands. Every command that accepts a changeset ID will also " +"accept the name of an applied patch. MQ augments the tags normally in the " +"repository with an eponymous one for each applied patch. In addition, the " +"special tags <literal role=\"tag\">qbase</literal> and <literal role=\"tag" +"\">qtip</literal> identify the <quote>bottom-most</quote> and topmost applied " +"patches, respectively." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:938 +msgid "" +"These additions to Mercurial's normal tagging capabilities make dealing with " +"patches even more of a breeze." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:941 +msgid "Want to patchbomb a mailing list with your latest series of changes?" +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:944 +msgid "" +"(Don't know what <quote>patchbombing</quote> is? See section <xref linkend=" +"\"sec.hgext.patchbomb\"/>.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:947 +msgid "" +"Need to see all of the patches since <literal>foo.patch</literal> that have " +"touched files in a subdirectory of your tree?" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:954 +msgid "" +"Because MQ makes the names of patches available to the rest of Mercurial " +"through its normal internal tag machinery, you don't need to type in the " +"entire name of a patch when you want to identify it by name." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:959 +msgid "" +"Another nice consequence of representing patch names as tags is that when you " +"run the <command role=\"hg-cmd\">hg log</command> command, it will display a " +"patch's name as a tag, simply as part of its normal output. This makes it " +"easy to visually distinguish applied patches from underlying <quote>normal</" +"quote> revisions. The following example shows a few normal Mercurial " +"commands in use with applied patches." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:972 +msgid "Useful things to know about" +msgstr "其它需要了解的东西" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:974 +msgid "" +"There are a number of aspects of MQ usage that don't fit tidily into sections " +"of their own, but that are good to know. Here they are, in one place." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:979 +msgid "" +"Normally, when you <command role=\"hg-ext-mq\">qpop</command> a patch and " +"<command role=\"hg-ext-mq\">qpush</command> it again, the changeset that " +"represents the patch after the pop/push will have a <emphasis>different " +"identity</emphasis> than the changeset that represented the hash beforehand. " +"See section <xref linkend=\"sec.mqref.cmd.qpush\"/> for information as to why " +"this is." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:988 +msgid "" +"It's not a good idea to <command role=\"hg-cmd\">hg merge</command> changes " +"from another branch with a patch changeset, at least if you want to maintain " +"the <quote>patchiness</quote> of that changeset and changesets below it on " +"the patch stack. If you try to do this, it will appear to succeed, but MQ " +"will become confused." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:999 +msgid "Managing patches in a repository" +msgstr "在版本库管理补丁" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1001 +msgid "" +"Because MQ's <filename role=\"special\" class=\"directory\">.hg/patches</" +"filename> directory resides outside a Mercurial repository's working " +"directory, the <quote>underlying</quote> Mercurial repository knows nothing " +"about the management or presence of patches." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1007 +msgid "" +"This presents the interesting possibility of managing the contents of the " +"patch directory as a Mercurial repository in its own right. This can be a " +"useful way to work. For example, you can work on a patch for a while, " +"<command role=\"hg-ext-mq\">qrefresh</command> it, then <command role=\"hg-cmd" +"\">hg commit</command> the current state of the patch. This lets you " +"<quote>roll back</quote> to that version of the patch later on." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1016 +msgid "" +"You can then share different versions of the same patch stack among multiple " +"underlying repositories. I use this when I am developing a Linux kernel " +"feature. I have a pristine copy of my kernel sources for each of several CPU " +"architectures, and a cloned repository under each that contains the patches I " +"am working on. When I want to test a change on a different architecture, I " +"push my current patches to the patch repository associated with that kernel " +"tree, pop and push all of my patches, and build and test that kernel." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1026 +msgid "" +"Managing patches in a repository makes it possible for multiple developers to " +"work on the same patch series without colliding with each other, all on top " +"of an underlying source base that they may or may not control." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:1032 +msgid "MQ support for patch repositories" +msgstr "MQ 支持补丁版本库" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1034 +msgid "" +"MQ helps you to work with the <filename role=\"special\" class=\"directory\">." +"hg/patches</filename> directory as a repository; when you prepare a " +"repository for working with patches using <command role=\"hg-ext-mq\">qinit</" +"command>, you can pass the <option role=\"hg-ext-mq-cmd-qinit-opt\">hg -c</" +"option> option to create the <filename role=\"special\" class=\"directory\">." +"hg/patches</filename> directory as a Mercurial repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch11-mq.xml:1044 +msgid "" +"If you forget to use the <option role=\"hg-ext-mq-cmd-qinit-opt\">hg -c</" +"option> option, you can simply go into the <filename role=\"special\" class=" +"\"directory\">.hg/patches</filename> directory at any time and run <command " +"role=\"hg-cmd\">hg init</command>. Don't forget to add an entry for the " +"<filename role=\"special\">status</filename> file to the <filename role=" +"\"special\">.hgignore</filename> file, though" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch11-mq.xml:1053 +msgid "" +"(<command role=\"hg-cmd\">hg qinit <option role=\"hg-ext-mq-cmd-qinit-opt" +"\">hg -c</option></command> does this for you automatically); you " +"<emphasis>really</emphasis> don't want to manage the <filename role=\"special" +"\">status</filename> file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1060 +msgid "" +"As a convenience, if MQ notices that the <filename class=\"directory\">.hg/" +"patches</filename> directory is a repository, it will automatically <command " +"role=\"hg-cmd\">hg add</command> every patch that you create and import." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1065 +msgid "" +"MQ provides a shortcut command, <command role=\"hg-ext-mq\">qcommit</" +"command>, that runs <command role=\"hg-cmd\">hg commit</command> in the " +"<filename role=\"special\" class=\"directory\">.hg/patches</filename> " +"directory. This saves some bothersome typing." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1071 +msgid "" +"Finally, as a convenience to manage the patch directory, you can define the " +"alias <command>mq</command> on Unix systems. For example, on Linux systems " +"using the <command>bash</command> shell, you can include the following " +"snippet in your <filename role=\"home\">~/.bashrc</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1080 +msgid "" +"You can then issue commands of the form <command>mq pull</command> from the " +"main repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:1085 +msgid "A few things to watch out for" +msgstr "需要注意的事情" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1087 +msgid "" +"MQ's support for working with a repository full of patches is limited in a " +"few small respects." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1090 +msgid "" +"MQ cannot automatically detect changes that you make to the patch directory. " +"If you <command role=\"hg-cmd\">hg pull</command>, manually edit, or <command " +"role=\"hg-cmd\">hg update</command> changes to patches or the <filename role=" +"\"special\">series</filename> file, you will have to <command role=\"hg-cmd" +"\">hg qpop <option role=\"hg-ext-mq-cmd-qpop-opt\">hg -a</option></command> " +"and then <command role=\"hg-cmd\">hg qpush <option role=\"hg-ext-mq-cmd-qpush-" +"opt\">hg -a</option></command> in the underlying repository to see those " +"changes show up there. If you forget to do this, you can confuse MQ's idea " +"of which patches are applied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:1106 +msgid "Third party tools for working with patches" +msgstr "操作补丁的第三方工具" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1108 +msgid "" +"Once you've been working with patches for a while, you'll find yourself " +"hungry for tools that will help you to understand and manipulate the patches " +"you're dealing with." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1112 +msgid "" +"The <command>diffstat</command> command <citation>web:diffstat</citation> " +"generates a histogram of the modifications made to each file in a patch. It " +"provides a good way to <quote>get a sense of</quote> a patch&emdash;which " +"files it affects, and how much change it introduces to each file and as a " +"whole. (I find that it's a good idea to use <command>diffstat</command>'s " +"<option role=\"cmd-opt-diffstat\">-p</option> option as a matter of course, " +"as otherwise it will try to do clever things with prefixes of file names that " +"inevitably confuse at least me.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1126 +msgid "" +"The <literal role=\"package\">patchutils</literal> package <citation>web:" +"patchutils</citation> is invaluable. It provides a set of small utilities " +"that follow the <quote>Unix philosophy;</quote> each does one useful thing " +"with a patch. The <literal role=\"package\">patchutils</literal> command I " +"use most is <command>filterdiff</command>, which extracts subsets from a " +"patch file. For example, given a patch that modifies hundreds of files " +"across dozens of directories, a single invocation of <command>filterdiff</" +"command> can generate a smaller patch that only touches files whose names " +"match a particular glob pattern. See section <xref linkend=\"mq-collab.tips." +"interdiff\"/> for another example." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:1142 +msgid "Good ways to work with patches" +msgstr "操作补丁的好习惯" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1144 +msgid "" +"Whether you are working on a patch series to submit to a free software or " +"open source project, or a series that you intend to treat as a sequence of " +"regular changesets when you're done, you can use some simple techniques to " +"keep your work well organised." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1150 +msgid "" +"Give your patches descriptive names. A good name for a patch might be " +"<filename>rework-device-alloc.patch</filename>, because it will immediately " +"give you a hint what the purpose of the patch is. Long names shouldn't be a " +"problem; you won't be typing the names often, but you <emphasis>will</" +"emphasis> be running commands like <command role=\"hg-ext-mq\">qapplied</" +"command> and <command role=\"hg-ext-mq\">qtop</command> over and over. Good " +"naming becomes especially important when you have a number of patches to work " +"with, or if you are juggling a number of different tasks and your patches " +"only get a fraction of your attention." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1162 +msgid "" +"Be aware of what patch you're working on. Use the <command role=\"hg-ext-mq" +"\">qtop</command> command and skim over the text of your patches " +"frequently&emdash;for example, using <command role=\"hg-cmd\">hg tip <option " +"role=\"hg-opt-tip\">-p</option></command>)&emdash;to be sure of where you " +"stand. I have several times worked on and <command role=\"hg-ext-mq" +"\">qrefresh</command>ed a patch other than the one I intended, and it's often " +"tricky to migrate changes into the right patch after making them in the wrong " +"one." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1172 +msgid "" +"For this reason, it is very much worth investing a little time to learn how " +"to use some of the third-party tools I described in section <xref linkend=" +"\"sec.mq.tools\"/>, particularly <command>diffstat</command> and " +"<command>filterdiff</command>. The former will give you a quick idea of what " +"changes your patch is making, while the latter makes it easy to splice hunks " +"selectively out of one patch and into another." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:1183 +msgid "MQ cookbook" +msgstr "MQ 手册" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:1186 +msgid "Manage <quote>trivial</quote> patches" +msgstr "管理<quote>琐碎的</quote>补丁" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1188 +msgid "" +"Because the overhead of dropping files into a new Mercurial repository is so " +"low, it makes a lot of sense to manage patches this way even if you simply " +"want to make a few changes to a source tarball that you downloaded." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1193 +msgid "" +"Begin by downloading and unpacking the source tarball, and turning it into a " +"Mercurial repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1198 +msgid "Continue by creating a patch stack and making your changes." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1203 +msgid "" +"Let's say a few weeks or months pass, and your package author releases a new " +"version. First, bring their changes into the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1209 +msgid "" +"The pipeline starting with <command role=\"hg-cmd\">hg locate</command> above " +"deletes all files in the working directory, so that <command role=\"hg-cmd" +"\">hg commit</command>'s <option role=\"hg-opt-commit\">--addremove</option> " +"option can actually tell which files have really been removed in the newer " +"version of the source." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1217 +msgid "Finally, you can apply your patches on top of the new tree." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:1224 +msgid "Combining entire patches" +msgstr "组合全部的补丁" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1226 +msgid "" +"MQ provides a command, <command role=\"hg-ext-mq\">qfold</command> that lets " +"you combine entire patches. This <quote>folds</quote> the patches you name, " +"in the order you name them, into the topmost applied patch, and concatenates " +"their descriptions onto the end of its description. The patches that you " +"fold must be unapplied before you fold them." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1234 +msgid "" +"The order in which you fold patches matters. If your topmost applied patch " +"is <literal>foo</literal>, and you <command role=\"hg-ext-mq\">qfold</" +"command> <literal>bar</literal> and <literal>quux</literal> into it, you will " +"end up with a patch that has the same effect as if you applied first " +"<literal>foo</literal>, then <literal>bar</literal>, followed by " +"<literal>quux</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch11-mq.xml:1245 +msgid "Merging part of one patch into another" +msgstr "合并补丁的部分内容到其它补丁" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1247 +msgid "" +"Merging <emphasis>part</emphasis> of one patch into another is more difficult " +"than combining entire patches." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1251 +msgid "" +"If you want to move changes to entire files, you can use <command>filterdiff</" +"command>'s <option role=\"cmd-opt-filterdiff\">-i</option> and <option role=" +"\"cmd-opt-filterdiff\">-x</option> options to choose the modifications to " +"snip out of one patch, concatenating its output onto the end of the patch you " +"want to merge into. You usually won't need to modify the patch you've merged " +"the changes from. Instead, MQ will report some rejected hunks when you " +"<command role=\"hg-ext-mq\">qpush</command> it (from the hunks you moved into " +"the other patch), and you can simply <command role=\"hg-ext-mq\">qrefresh</" +"command> the patch to drop the duplicate hunks." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1264 +msgid "" +"If you have a patch that has multiple hunks modifying a file, and you only " +"want to move a few of those hunks, the job becomes more messy, but you can " +"still partly automate it. Use <command>lsdiff -nvv</command> to print some " +"metadata about the patch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1272 +msgid "This command prints three different kinds of number:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:1275 +msgid "" +"(in the first column) a <emphasis>file number</emphasis> to identify each " +"file modified in the patch;" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:1279 +msgid "" +"(on the next line, indented) the line number within a modified file where a " +"hunk starts; and" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch11-mq.xml:1282 +msgid "" +"(on the same line) a <emphasis>hunk number</emphasis> to identify that hunk." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1286 +msgid "" +"You'll have to use some visual inspection, and reading of the patch, to " +"identify the file and hunk numbers you'll want, but you can then pass them to " +"to <command>filterdiff</command>'s <option role=\"cmd-opt-filterdiff\">--" +"files</option> and <option role=\"cmd-opt-filterdiff\">--hunks</option> " +"options, to select exactly the file and hunk you want to extract." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch11-mq.xml:1294 +msgid "" +"Once you have this hunk, you can concatenate it onto the end of your " +"destination patch and continue with the remainder of section <xref linkend=" +"\"sec.mq.combine\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch11-mq.xml:1301 +msgid "Differences between quilt and MQ" +msgstr "MQ 与 quilt 的区别" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1303 +msgid "" +"If you are already familiar with quilt, MQ provides a similar command set. " +"There are a few differences in the way that it works." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch11-mq.xml:1307 +msgid "" +"You will already have noticed that most quilt commands have MQ counterparts " +"that simply begin with a <quote><literal>q</literal></quote>. The exceptions " +"are quilt's <literal>add</literal> and <literal>remove</literal> commands, " +"the counterparts for which are the normal Mercurial <command role=\"hg-cmd" +"\">hg add</command> and <command role=\"hg-cmd\">hg remove</command> " +"commands. There is no MQ equivalent of the quilt <literal>edit</literal> " +"command." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch12-mq-collab.xml:5 +msgid "Advanced uses of Mercurial Queues" +msgstr "MQ 的高级用法" + +#. type: Content of: <book><chapter><para> +#: ../en/ch12-mq-collab.xml:7 +msgid "" +"While it's easy to pick up straightforward uses of Mercurial Queues, use of a " +"little discipline and some of MQ's less frequently used capabilities makes it " +"possible to work in complicated development environments." +msgstr "" + +#. type: Content of: <book><chapter><para> +#: ../en/ch12-mq-collab.xml:12 +msgid "" +"In this chapter, I will use as an example a technique I have used to manage " +"the development of an Infiniband device driver for the Linux kernel. The " +"driver in question is large (at least as drivers go), with 25,000 lines of " +"code spread across 35 source files. It is maintained by a small team of " +"developers." +msgstr "" + +#. type: Content of: <book><chapter><para> +#: ../en/ch12-mq-collab.xml:18 +msgid "" +"While much of the material in this chapter is specific to Linux, the same " +"principles apply to any code base for which you're not the primary owner, and " +"upon which you need to do a lot of development." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch12-mq-collab.xml:24 +msgid "The problem of many targets" +msgstr "多个目标的问题" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:26 +msgid "" +"The Linux kernel changes rapidly, and has never been internally stable; " +"developers frequently make drastic changes between releases. This means that " +"a version of the driver that works well with a particular released version of " +"the kernel will not even <emphasis>compile</emphasis> correctly against, " +"typically, any other version." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:33 +msgid "" +"To maintain a driver, we have to keep a number of distinct versions of Linux " +"in mind." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:36 +msgid "" +"One target is the main Linux kernel development tree. Maintenance of the code " +"is in this case partly shared by other developers in the kernel community, " +"who make <quote>drive-by</quote> modifications to the driver as they develop " +"and refine kernel subsystems." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:42 +msgid "" +"We also maintain a number of <quote>backports</quote> to older versions of " +"the Linux kernel, to support the needs of customers who are running older " +"Linux distributions that do not incorporate our drivers. (To " +"<emphasis>backport</emphasis> a piece of code is to modify it to work in an " +"older version of its target environment than the version it was developed " +"for.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:50 +msgid "" +"Finally, we make software releases on a schedule that is necessarily not " +"aligned with those used by Linux distributors and kernel developers, so that " +"we can deliver new features to customers without forcing them to upgrade " +"their entire kernels or distributions." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch12-mq-collab.xml:58 +msgid "Tempting approaches that don't work well" +msgstr "工作不好的诱人方法" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:60 +msgid "" +"There are two <quote>standard</quote> ways to maintain a piece of software " +"that has to target many different environments." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:64 +msgid "" +"The first is to maintain a number of branches, each intended for a single " +"target. The trouble with this approach is that you must maintain iron " +"discipline in the flow of changes between repositories. A new feature or bug " +"fix must start life in a <quote>pristine</quote> repository, then percolate " +"out to every backport repository. Backport changes are more limited in the " +"branches they should propagate to; a backport change that is applied to a " +"branch where it doesn't belong will probably stop the driver from compiling." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:74 +msgid "" +"The second is to maintain a single source tree filled with conditional " +"statements that turn chunks of code on or off depending on the intended " +"target. Because these <quote>ifdefs</quote> are not allowed in the Linux " +"kernel tree, a manual or automatic process must be followed to strip them out " +"and yield a clean tree. A code base maintained in this fashion rapidly " +"becomes a rat's nest of conditional blocks that are difficult to understand " +"and maintain." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:83 +msgid "" +"Neither of these approaches is well suited to a situation where you don't " +"<quote>own</quote> the canonical copy of a source tree. In the case of a " +"Linux driver that is distributed with the standard kernel, Linus's tree " +"contains the copy of the code that will be treated by the world as " +"canonical. The upstream version of <quote>my</quote> driver can be modified " +"by people I don't know, without me even finding out about it until after the " +"changes show up in Linus's tree." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:93 +msgid "" +"These approaches have the added weakness of making it difficult to generate " +"well-formed patches to submit upstream." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:97 +msgid "" +"In principle, Mercurial Queues seems like a good candidate to manage a " +"development scenario such as the above. While this is indeed the case, MQ " +"contains a few added features that make the job more pleasant." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch12-mq-collab.xml:105 +msgid "Conditionally applying patches with guards" +msgstr "有条件的应用补丁" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:107 +msgid "" +"Perhaps the best way to maintain sanity with so many targets is to be able to " +"choose specific patches to apply for a given situation. MQ provides a " +"feature called <quote>guards</quote> (which originates with quilt's " +"<literal>guards</literal> command) that does just this. To start off, let's " +"create a simple repository for experimenting in." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:116 +msgid "" +"This gives us a tiny repository that contains two patches that don't have any " +"dependencies on each other, because they touch different files." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:120 +msgid "" +"The idea behind conditional application is that you can <quote>tag</quote> a " +"patch with a <emphasis>guard</emphasis>, which is simply a text string of " +"your choosing, then tell MQ to select specific guards to use when applying " +"patches. MQ will then either apply, or skip over, a guarded patch, depending " +"on the guards that you have selected." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:127 +msgid "" +"A patch can have an arbitrary number of guards; each one is " +"<emphasis>positive</emphasis> (<quote>apply this patch if this guard is " +"selected</quote>) or <emphasis>negative</emphasis> (<quote>skip this patch if " +"this guard is selected</quote>). A patch with no guards is always applied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch12-mq-collab.xml:135 +msgid "Controlling the guards on a patch" +msgstr "控制补丁的应用条件" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:137 +msgid "" +"The <command role=\"hg-ext-mq\">qguard</command> command lets you determine " +"which guards should apply to a patch, or display the guards that are already " +"in effect. Without any arguments, it displays the guards on the current " +"topmost patch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:144 +msgid "" +"To set a positive guard on a patch, prefix the name of the guard with a " +"<quote><literal>+</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:149 +msgid "" +"To set a negative guard on a patch, prefix the name of the guard with a " +"<quote><literal>-</literal></quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><note><para> +#: ../en/ch12-mq-collab.xml:156 +msgid "" +"The <command role=\"hg-ext-mq\">qguard</command> command <emphasis>sets</" +"emphasis> the guards on a patch; it doesn't <emphasis>modify</emphasis> " +"them. What this means is that if you run <command role=\"hg-cmd\">hg qguard " +"+a +b</command> on a patch, then <command role=\"hg-cmd\">hg qguard +c</" +"command> on the same patch, the <emphasis>only</emphasis> guard that will be " +"set on it afterwards is <literal>+c</literal>." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:165 +msgid "" +"Mercurial stores guards in the <filename role=\"special\">series</filename> " +"file; the form in which they are stored is easy both to understand and to " +"edit by hand. (In other words, you don't have to use the <command role=\"hg-" +"ext-mq\">qguard</command> command if you don't want to; it's okay to simply " +"edit the <filename role=\"special\">series</filename> file.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch12-mq-collab.xml:177 +msgid "Selecting the guards to use" +msgstr "选择使用的条件" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:179 +msgid "" +"The <command role=\"hg-ext-mq\">qselect</command> command determines which " +"guards are active at a given time. The effect of this is to determine which " +"patches MQ will apply the next time you run <command role=\"hg-ext-mq" +"\">qpush</command>. It has no other effect; in particular, it doesn't do " +"anything to patches that are already applied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:186 +msgid "" +"With no arguments, the <command role=\"hg-ext-mq\">qselect</command> command " +"lists the guards currently in effect, one per line of output. Each argument " +"is treated as the name of a guard to apply." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:193 +msgid "" +"In case you're interested, the currently selected guards are stored in the " +"<filename role=\"special\">guards</filename> file." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:198 +msgid "" +"We can see the effect the selected guards have when we run <command role=\"hg-" +"ext-mq\">qpush</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:203 +msgid "" +"A guard cannot start with a <quote><literal>+</literal></quote> or " +"<quote><literal>-</literal></quote> character. The name of a guard must not " +"contain white space, but most other characters are acceptable. If you try to " +"use a guard with an invalid name, MQ will complain:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:212 +msgid "Changing the selected guards changes the patches that are applied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:217 +msgid "" +"You can see in the example below that negative guards take precedence over " +"positive guards." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch12-mq-collab.xml:224 +msgid "MQ's rules for applying patches" +msgstr "MQ 应用补丁的规则" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:226 +msgid "" +"The rules that MQ uses when deciding whether to apply a patch are as follows." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:229 +msgid "A patch that has no guards is always applied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:232 +msgid "" +"If the patch has any negative guard that matches any currently selected " +"guard, the patch is skipped." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:235 +msgid "" +"If the patch has any positive guard that matches any currently selected " +"guard, the patch is applied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:238 +msgid "" +"If the patch has positive or negative guards, but none matches any currently " +"selected guard, the patch is skipped." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch12-mq-collab.xml:245 +msgid "Trimming the work environment" +msgstr "修剪工作环境" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:247 +msgid "" +"In working on the device driver I mentioned earlier, I don't apply the " +"patches to a normal Linux kernel tree. Instead, I use a repository that " +"contains only a snapshot of the source files and headers that are relevant to " +"Infiniband development. This repository is 1% the size of a kernel " +"repository, so it's easier to work with." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:254 +msgid "" +"I then choose a <quote>base</quote> version on top of which the patches are " +"applied. This is a snapshot of the Linux kernel tree as of a revision of my " +"choosing. When I take the snapshot, I record the changeset ID from the " +"kernel repository in the commit message. Since the snapshot preserves the " +"<quote>shape</quote> and content of the relevant parts of the kernel tree, I " +"can apply my patches on top of either my tiny repository or a normal kernel " +"tree." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:263 +msgid "" +"Normally, the base tree atop which the patches apply should be a snapshot of " +"a very recent upstream tree. This best facilitates the development of " +"patches that can easily be submitted upstream with few or no modifications." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch12-mq-collab.xml:270 +msgid "Dividing up the <filename role=\"special\">series</filename> file" +msgstr "分类补丁<filename role=\"special\">系列</filename>" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:273 +msgid "" +"I categorise the patches in the <filename role=\"special\">series</filename> " +"file into a number of logical groups. Each section of like patches begins " +"with a block of comments that describes the purpose of the patches that " +"follow." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:279 +msgid "" +"The sequence of patch groups that I maintain follows. The ordering of these " +"groups is important; I'll describe why after I introduce the groups." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:283 +msgid "" +"The <quote>accepted</quote> group. Patches that the development team has " +"submitted to the maintainer of the Infiniband subsystem, and which he has " +"accepted, but which are not present in the snapshot that the tiny repository " +"is based on. These are <quote>read only</quote> patches, present only to " +"transform the tree into a similar state as it is in the upstream maintainer's " +"repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:291 +msgid "" +"The <quote>rework</quote> group. Patches that I have submitted, but that the " +"upstream maintainer has requested modifications to before he will accept them." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:296 +msgid "" +"The <quote>pending</quote> group. Patches that I have not yet submitted to " +"the upstream maintainer, but which we have finished working on. These will be " +"<quote>read only</quote> for a while. If the upstream maintainer accepts " +"them upon submission, I'll move them to the end of the <quote>accepted</" +"quote> group. If he requests that I modify any, I'll move them to the " +"beginning of the <quote>rework</quote> group." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:305 +msgid "" +"The <quote>in progress</quote> group. Patches that are actively being " +"developed, and should not be submitted anywhere yet." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:309 +msgid "" +"The <quote>backport</quote> group. Patches that adapt the source tree to " +"older versions of the kernel tree." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:313 +msgid "" +"The <quote>do not ship</quote> group. Patches that for some reason should " +"never be submitted upstream. For example, one such patch might change " +"embedded driver identification strings to make it easier to distinguish, in " +"the field, between an out-of-tree version of the driver and a version shipped " +"by a distribution vendor." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:321 +msgid "" +"Now to return to the reasons for ordering groups of patches in this way. We " +"would like the lowest patches in the stack to be as stable as possible, so " +"that we will not need to rework higher patches due to changes in context. " +"Putting patches that will never be changed first in the <filename role=" +"\"special\">series</filename> file serves this purpose." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:329 +msgid "" +"We would also like the patches that we know we'll need to modify to be " +"applied on top of a source tree that resembles the upstream tree as closely " +"as possible. This is why we keep accepted patches around for a while." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:334 +msgid "" +"The <quote>backport</quote> and <quote>do not ship</quote> patches float at " +"the end of the <filename role=\"special\">series</filename> file. The " +"backport patches must be applied on top of all other patches, and the " +"<quote>do not ship</quote> patches might as well stay out of harm's way." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch12-mq-collab.xml:343 +msgid "Maintaining the patch series" +msgstr "维护补丁系列" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:345 +msgid "" +"In my work, I use a number of guards to control which patches are to be " +"applied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:349 +msgid "" +"<quote>Accepted</quote> patches are guarded with <literal>accepted</" +"literal>. I enable this guard most of the time. When I'm applying the " +"patches on top of a tree where the patches are already present, I can turn " +"this patch off, and the patches that follow it will apply cleanly." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:356 +msgid "" +"Patches that are <quote>finished</quote>, but not yet submitted, have no " +"guards. If I'm applying the patch stack to a copy of the upstream tree, I " +"don't need to enable any guards in order to get a reasonably safe source tree." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:362 +msgid "" +"Those patches that need reworking before being resubmitted are guarded with " +"<literal>rework</literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:366 +msgid "" +"For those patches that are still under development, I use <literal>devel</" +"literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch12-mq-collab.xml:369 +msgid "" +"A backport patch may have several guards, one for each version of the kernel " +"to which it applies. For example, a patch that backports a piece of code to " +"2.6.9 will have a <literal>2.6.9</literal> guard." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch12-mq-collab.xml:374 +msgid "" +"This variety of guards gives me considerable flexibility in determining what " +"kind of source tree I want to end up with. For most situations, the " +"selection of appropriate guards is automated during the build process, but I " +"can manually tune the guards to use for less common circumstances." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch12-mq-collab.xml:381 +msgid "The art of writing backport patches" +msgstr "编写向后移植补丁的艺术" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:383 +msgid "" +"Using MQ, writing a backport patch is a simple process. All such a patch has " +"to do is modify a piece of code that uses a kernel feature not present in the " +"older version of the kernel, so that the driver continues to work correctly " +"under that older version." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:389 +msgid "" +"A useful goal when writing a good backport patch is to make your code look as " +"if it was written for the older version of the kernel you're targeting. The " +"less obtrusive the patch, the easier it will be to understand and maintain. " +"If you're writing a collection of backport patches to avoid the <quote>rat's " +"nest</quote> effect of lots of <literal>#ifdef</literal>s (hunks of source " +"code that are only used conditionally) in your code, don't introduce version-" +"dependent <literal>#ifdef</literal>s into the patches. Instead, write " +"several patches, each of which makes unconditional changes, and control their " +"application using guards." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:402 +msgid "" +"There are two reasons to divide backport patches into a distinct group, away " +"from the <quote>regular</quote> patches whose effects they modify. The first " +"is that intermingling the two makes it more difficult to use a tool like the " +"<literal role=\"hg-ext\">patchbomb</literal> extension to automate the " +"process of submitting the patches to an upstream maintainer. The second is " +"that a backport patch could perturb the context in which a subsequent regular " +"patch is applied, making it impossible to apply the regular patch cleanly " +"<emphasis>without</emphasis> the earlier backport patch already being applied." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch12-mq-collab.xml:417 +msgid "Useful tips for developing with MQ" +msgstr "使用 MQ 开发的技巧" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch12-mq-collab.xml:420 +msgid "Organising patches in directories" +msgstr "将补丁放到几个目录中" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:422 +msgid "" +"If you're working on a substantial project with MQ, it's not difficult to " +"accumulate a large number of patches. For example, I have one patch " +"repository that contains over 250 patches." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:427 +msgid "" +"If you can group these patches into separate logical categories, you can if " +"you like store them in different directories; MQ has no problems with patch " +"names that contain path separators." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch12-mq-collab.xml:434 +msgid "Viewing the history of a patch" +msgstr "察看补丁的历史" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:436 +msgid "" +"If you're developing a set of patches over a long time, it's a good idea to " +"maintain them in a repository, as discussed in section <xref linkend=\"sec.mq." +"repo\"/>. If you do so, you'll quickly discover that using the <command role=" +"\"hg-cmd\">hg diff</command> command to look at the history of changes to a " +"patch is unworkable. This is in part because you're looking at the second " +"derivative of the real code (a diff of a diff), but also because MQ adds " +"noise to the process by modifying time stamps and directory names when it " +"updates a patch." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:448 +msgid "" +"However, you can use the <literal role=\"hg-ext\">extdiff</literal> " +"extension, which is bundled with Mercurial, to turn a diff of two versions of " +"a patch into something readable. To do this, you will need a third-party " +"package called <literal role=\"package\">patchutils</literal> <citation>web:" +"patchutils</citation>. This provides a command named <command>interdiff</" +"command>, which shows the differences between two diffs as a diff. Used on " +"two versions of the same diff, it generates a diff that represents the diff " +"from the first to the second version." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:459 +msgid "" +"You can enable the <literal role=\"hg-ext\">extdiff</literal> extension in " +"the usual way, by adding a line to the <literal role=\"rc-extensions" +"\">extensions</literal> section of your <filename role=\"special\">~/.hgrc</" +"filename>." +msgstr "" + +# +#. &example.hg-interdiff; +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:466 +msgid "" +"The <command>interdiff</command> command expects to be passed the names of " +"two files, but the <literal role=\"hg-ext\">extdiff</literal> extension " +"passes the program it runs a pair of directories, each of which can contain " +"an arbitrary number of files. We thus need a small program that will run " +"<command>interdiff</command> on each pair of files in these two directories. " +"This program is available as <filename role=\"special\">hg-interdiff</" +"filename> in the <filename class=\"directory\">examples</filename> directory " +"of the source code repository that accompanies this book." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:478 +msgid "" +"With the <filename role=\"special\">hg-interdiff</filename> program in your " +"shell's search path, you can run it as follows, from inside an MQ patch " +"directory:" +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:482 +msgid "" +"Since you'll probably want to use this long-winded command a lot, you can get " +"<literal role=\"hg-ext\">hgext</literal> to make it available as a normal " +"Mercurial command, again by editing your <filename role=\"special\">~/.hgrc</" +"filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:489 +msgid "" +"This directs <literal role=\"hg-ext\">hgext</literal> to make an " +"<literal>interdiff</literal> command available, so you can now shorten the " +"previous invocation of <command role=\"hg-ext-extdiff\">extdiff</command> to " +"something a little more wieldy." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><note><para> +#: ../en/ch12-mq-collab.xml:497 +msgid "" +"The <command>interdiff</command> command works well only if the underlying " +"files against which versions of a patch are generated remain the same. If " +"you create a patch, modify the underlying files, and then regenerate the " +"patch, <command>interdiff</command> may not produce useful output." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch12-mq-collab.xml:505 +msgid "" +"The <literal role=\"hg-ext\">extdiff</literal> extension is useful for more " +"than merely improving the presentation of MQ patches. To read more about it, " +"go to section <xref linkend=\"sec.hgext.extdiff\"/>." +msgstr "" + +#. type: Content of: <book><chapter><title> +#: ../en/ch13-hgext.xml:5 +msgid "Adding functionality with extensions" +msgstr "使用扩展增加功能" + +#. type: Content of: <book><chapter><para> +#: ../en/ch13-hgext.xml:7 +msgid "" +"While the core of Mercurial is quite complete from a functionality " +"standpoint, it's deliberately shorn of fancy features. This approach of " +"preserving simplicity keeps the software easy to deal with for both " +"maintainers and users." +msgstr "" + +#. type: Content of: <book><chapter><para> +#: ../en/ch13-hgext.xml:12 +msgid "" +"However, Mercurial doesn't box you in with an inflexible command set: you can " +"add features to it as <emphasis>extensions</emphasis> (sometimes known as " +"<emphasis>plugins</emphasis>). We've already discussed a few of these " +"extensions in earlier chapters." +msgstr "" + +#. type: Content of: <book><chapter><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:18 +msgid "" +"Section <xref linkend=\"sec.tour-merge.fetch\"/> covers the <literal role=" +"\"hg-ext\">fetch</literal> extension; this combines pulling new changes and " +"merging them with local changes into a single command, <command role=\"hg-ext-" +"fetch\">fetch</command>." +msgstr "" + +#. type: Content of: <book><chapter><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:24 +msgid "" +"In chapter <xref linkend=\"chap.hook\"/>, we covered several extensions that " +"are useful for hook-related functionality: <literal role=\"hg-ext\">acl</" +"literal> adds access control lists; <literal role=\"hg-ext\">bugzilla</" +"literal> adds integration with the Bugzilla bug tracking system; and <literal " +"role=\"hg-ext\">notify</literal> sends notification emails on new changes." +msgstr "" + +#. type: Content of: <book><chapter><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:33 +msgid "" +"The Mercurial Queues patch management extension is so invaluable that it " +"merits two chapters and an appendix all to itself. Chapter <xref linkend=" +"\"chap.mq\"/> covers the basics; chapter <xref linkend=\"chap.mq-collab\"/> " +"discusses advanced topics; and appendix <xref linkend=\"chap.mqref\"/> goes " +"into detail on each command." +msgstr "" + +#. type: Content of: <book><chapter><para> +#: ../en/ch13-hgext.xml:43 +msgid "" +"In this chapter, we'll cover some of the other extensions that are available " +"for Mercurial, and briefly touch on some of the machinery you'll need to know " +"about if you want to write an extension of your own." +msgstr "" + +#. type: Content of: <book><chapter><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:48 +msgid "" +"In section <xref linkend=\"sec.hgext.inotify\"/>, we'll discuss the " +"possibility of <emphasis>huge</emphasis> performance improvements using the " +"<literal role=\"hg-ext\">inotify</literal> extension." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch13-hgext.xml:55 +msgid "" +"Improve performance with the <literal role=\"hg-ext\">inotify</literal> " +"extension" +msgstr "使用扩展 <literal role=\"hg-ext\">inotify</literal> 以提高性能" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:58 +msgid "" +"Are you interested in having some of the most common Mercurial operations run " +"as much as a hundred times faster? Read on!" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:62 +msgid "" +"Mercurial has great performance under normal circumstances. For example, " +"when you run the <command role=\"hg-cmd\">hg status</command> command, " +"Mercurial has to scan almost every directory and file in your repository so " +"that it can display file status. Many other Mercurial commands need to do " +"the same work behind the scenes; for example, the <command role=\"hg-cmd\">hg " +"diff</command> command uses the status machinery to avoid doing an expensive " +"comparison operation on files that obviously haven't changed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:72 +msgid "" +"Because obtaining file status is crucial to good performance, the authors of " +"Mercurial have optimised this code to within an inch of its life. However, " +"there's no avoiding the fact that when you run <command role=\"hg-cmd\">hg " +"status</command>, Mercurial is going to have to perform at least one " +"expensive system call for each managed file to determine whether it's changed " +"since the last time Mercurial checked. For a sufficiently large repository, " +"this can take a long time." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:82 +msgid "" +"To put a number on the magnitude of this effect, I created a repository " +"containing 150,000 managed files. I timed <command role=\"hg-cmd\">hg " +"status</command> as taking ten seconds to run, even when <emphasis>none</" +"emphasis> of those files had been modified." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:88 +msgid "" +"Many modern operating systems contain a file notification facility. If a " +"program signs up to an appropriate service, the operating system will notify " +"it every time a file of interest is created, modified, or deleted. On Linux " +"systems, the kernel component that does this is called <literal>inotify</" +"literal>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:95 +msgid "" +"Mercurial's <literal role=\"hg-ext\">inotify</literal> extension talks to the " +"kernel's <literal>inotify</literal> component to optimise <command role=\"hg-" +"cmd\">hg status</command> commands. The extension has two components. A " +"daemon sits in the background and receives notifications from the " +"<literal>inotify</literal> subsystem. It also listens for connections from a " +"regular Mercurial command. The extension modifies Mercurial's behaviour so " +"that instead of scanning the filesystem, it queries the daemon. Since the " +"daemon has perfect information about the state of the repository, it can " +"respond with a result instantaneously, avoiding the need to scan every " +"directory and file in the repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:108 +msgid "" +"Recall the ten seconds that I measured plain Mercurial as taking to run " +"<command role=\"hg-cmd\">hg status</command> on a 150,000 file repository. " +"With the <literal role=\"hg-ext\">inotify</literal> extension enabled, the " +"time dropped to 0.1 seconds, a factor of <emphasis>one hundred</emphasis> " +"faster." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:115 +msgid "Before we continue, please pay attention to some caveats." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:118 +msgid "" +"The <literal role=\"hg-ext\">inotify</literal> extension is Linux-specific. " +"Because it interfaces directly to the Linux kernel's <literal>inotify</" +"literal> subsystem, it does not work on other operating systems." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:123 +msgid "" +"It should work on any Linux distribution that was released after early 2005. " +"Older distributions are likely to have a kernel that lacks <literal>inotify</" +"literal>, or a version of <literal>glibc</literal> that does not have the " +"necessary interfacing support." +msgstr "" + +#. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:130 +msgid "" +"Not all filesystems are suitable for use with the <literal role=\"hg-ext" +"\">inotify</literal> extension. Network filesystems such as NFS are a non-" +"starter, for example, particularly if you're running Mercurial on several " +"systems, all mounting the same network filesystem. The kernel's " +"<literal>inotify</literal> system has no way of knowing about changes made on " +"another system. Most local filesystems (e.g. ext3, XFS, ReiserFS) should " +"work fine." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:141 +msgid "" +"The <literal role=\"hg-ext\">inotify</literal> extension is not yet shipped " +"with Mercurial as of May 2007, so it's a little more involved to set up than " +"other extensions. But the performance improvement is worth it!" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:146 +msgid "" +"The extension currently comes in two parts: a set of patches to the Mercurial " +"source code, and a library of Python bindings to the <literal>inotify</" +"literal> subsystem." +msgstr "" + +#. type: Content of: <book><chapter><sect1><note><para> +#: ../en/ch13-hgext.xml:150 +msgid "" +"There are <emphasis>two</emphasis> Python <literal>inotify</literal> binding " +"libraries. One of them is called <literal>pyinotify</literal>, and is " +"packaged by some Linux distributions as <literal>python-inotify</literal>. " +"This is <emphasis>not</emphasis> the one you'll need, as it is too buggy and " +"inefficient to be practical." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:157 +msgid "" +"To get going, it's best to already have a functioning copy of Mercurial " +"installed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><note><para> +#: ../en/ch13-hgext.xml:160 +msgid "" +"If you follow the instructions below, you'll be <emphasis>replacing</" +"emphasis> and overwriting any existing installation of Mercurial that you " +"might already have, using the latest <quote>bleeding edge</quote> Mercurial " +"code. Don't say you weren't warned!" +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch13-hgext.xml:167 +msgid "" +"Clone the Python <literal>inotify</literal> binding repository. Build and " +"install it." +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch13-hgext.xml:174 +msgid "" +"Clone the <filename class=\"directory\">crew</filename> Mercurial " +"repository. Clone the <literal role=\"hg-ext\">inotify</literal> patch " +"repository so that Mercurial Queues will be able to apply patches to your " +"cope of the <filename class=\"directory\">crew</filename> repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch13-hgext.xml:184 +msgid "" +"Make sure that you have the Mercurial Queues extension, <literal role=\"hg-ext" +"\">mq</literal>, enabled. If you've never used MQ, read section <xref " +"linkend=\"sec.mq.start\"/> to get started quickly." +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch13-hgext.xml:190 +msgid "" +"Go into the <filename class=\"directory\">inotify</filename> repo, and apply " +"all of the <literal role=\"hg-ext\">inotify</literal> patches using the " +"<option role=\"hg-ext-mq-cmd-qpush-opt\">hg -a</option> option to the " +"<command role=\"hg-ext-mq\">qpush</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch13-hgext.xml:199 +msgid "" +"If you get an error message from <command role=\"hg-ext-mq\">qpush</command>, " +"you should not continue. Instead, ask for help." +msgstr "" + +#. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> +#: ../en/ch13-hgext.xml:203 +msgid "Build and install the patched version of Mercurial." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:209 +msgid "" +"Once you've build a suitably patched version of Mercurial, all you need to do " +"to enable the <literal role=\"hg-ext\">inotify</literal> extension is add an " +"entry to your <filename role=\"special\">~/.hgrc</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:214 +msgid "" +"When the <literal role=\"hg-ext\">inotify</literal> extension is enabled, " +"Mercurial will automatically and transparently start the status daemon the " +"first time you run a command that needs status in a repository. It runs one " +"status daemon per repository." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:220 +msgid "" +"The status daemon is started silently, and runs in the background. If you " +"look at a list of running processes after you've enabled the <literal role=" +"\"hg-ext\">inotify</literal> extension and run a few commands in different " +"repositories, you'll thus see a few <literal>hg</literal> processes sitting " +"around, waiting for updates from the kernel and queries from Mercurial." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:228 +msgid "" +"The first time you run a Mercurial command in a repository when you have the " +"<literal role=\"hg-ext\">inotify</literal> extension enabled, it will run " +"with about the same performance as a normal Mercurial command. This is " +"because the status daemon needs to perform a normal status scan so that it " +"has a baseline against which to apply later updates from the kernel. " +"However, <emphasis>every</emphasis> subsequent command that does any kind of " +"status check should be noticeably faster on repositories of even fairly " +"modest size. Better yet, the bigger your repository is, the greater a " +"performance advantage you'll see. The <literal role=\"hg-ext\">inotify</" +"literal> daemon makes status operations almost instantaneous on repositories " +"of all sizes!" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:242 +msgid "" +"If you like, you can manually start a status daemon using the <command role=" +"\"hg-ext-inotify\">inserve</command> command. This gives you slightly finer " +"control over how the daemon ought to run. This command will of course only " +"be available when the <literal role=\"hg-ext\">inotify</literal> extension is " +"enabled." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:249 +msgid "" +"When you're using the <literal role=\"hg-ext\">inotify</literal> extension, " +"you should notice <emphasis>no difference at all</emphasis> in Mercurial's " +"behaviour, with the sole exception of status-related commands running a whole " +"lot faster than they used to. You should specifically expect that commands " +"will not print different output; neither should they give different results. " +"If either of these situations occurs, please report a bug." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch13-hgext.xml:260 +msgid "" +"Flexible diff support with the <literal role=\"hg-ext\">extdiff</literal> " +"extension" +msgstr "使用扩展 <literal role=\"hg-ext\">extdiff</literal> 以扩展差异支持" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:263 +msgid "" +"Mercurial's built-in <command role=\"hg-cmd\">hg diff</command> command " +"outputs plaintext unified diffs." +msgstr "" +"Mercurial 内置命令 <command role=\"hg-cmd\">hg diff</command> 的输出与统一差异" +"不同。" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:268 +msgid "" +"If you would like to use an external tool to display modifications, you'll " +"want to use the <literal role=\"hg-ext\">extdiff</literal> extension. This " +"will let you use, for example, a graphical diff tool." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:273 +msgid "" +"The <literal role=\"hg-ext\">extdiff</literal> extension is bundled with " +"Mercurial, so it's easy to set up. In the <literal role=\"rc-extensions" +"\">extensions</literal> section of your <filename role=\"special\">~/.hgrc</" +"filename>, simply add a one-line entry to enable the extension." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:280 +msgid "" +"This introduces a command named <command role=\"hg-ext-extdiff\">extdiff</" +"command>, which by default uses your system's <command>diff</command> command " +"to generate a unified diff in the same form as the built-in <command role=" +"\"hg-cmd\">hg diff</command> command." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:288 +msgid "" +"The result won't be exactly the same as with the built-in <command role=\"hg-" +"cmd\">hg diff</command> variations, because the output of <command>diff</" +"command> varies from one system to another, even when passed the same options." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:293 +msgid "" +"As the <quote><literal>making snapshot</literal></quote> lines of output " +"above imply, the <command role=\"hg-ext-extdiff\">extdiff</command> command " +"works by creating two snapshots of your source tree. The first snapshot is " +"of the source revision; the second, of the target revision or working " +"directory. The <command role=\"hg-ext-extdiff\">extdiff</command> command " +"generates these snapshots in a temporary directory, passes the name of each " +"directory to an external diff viewer, then deletes the temporary directory. " +"For efficiency, it only snapshots the directories and files that have changed " +"between the two revisions." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:306 +msgid "" +"Snapshot directory names have the same base name as your repository. If your " +"repository path is <filename class=\"directory\">/quux/bar/foo</filename>, " +"then <filename class=\"directory\">foo</filename> will be the name of each " +"snapshot directory. Each snapshot directory name has its changeset ID " +"appended, if appropriate. If a snapshot is of revision " +"<literal>a631aca1083f</literal>, the directory will be named <filename class=" +"\"directory\">foo.a631aca1083f</filename>. A snapshot of the working " +"directory won't have a changeset ID appended, so it would just be <filename " +"class=\"directory\">foo</filename> in this example. To see what this looks " +"like in practice, look again at the <command role=\"hg-ext-extdiff\">extdiff</" +"command> example above. Notice that the diff has the snapshot directory " +"names embedded in its header." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:322 +msgid "" +"The <command role=\"hg-ext-extdiff\">extdiff</command> command accepts two " +"important options. The <option role=\"hg-ext-extdiff-cmd-extdiff-opt\">hg -p</" +"option> option lets you choose a program to view differences with, instead of " +"<command>diff</command>. With the <option role=\"hg-ext-extdiff-cmd-extdiff-" +"opt\">hg -o</option> option, you can change the options that <command role=" +"\"hg-ext-extdiff\">extdiff</command> passes to the program (by default, these " +"options are <quote><literal>-Npru</literal></quote>, which only make sense if " +"you're running <command>diff</command>). In other respects, the <command " +"role=\"hg-ext-extdiff\">extdiff</command> command acts similarly to the built-" +"in <command role=\"hg-cmd\">hg diff</command> command: you use the same " +"option names, syntax, and arguments to specify the revisions you want, the " +"files you want, and so on." +msgstr "" + +# +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:339 +msgid "" +"As an example, here's how to run the normal system <command>diff</command> " +"command, getting it to generate context diffs (using the <option role=\"cmd-" +"opt-diff\">-c</option> option) instead of unified diffs, and five lines of " +"context instead of the default three (passing <literal>5</literal> as the " +"argument to the <option role=\"cmd-opt-diff\">-C</option> option)." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:348 +msgid "" +"Launching a visual diff tool is just as easy. Here's how to launch the " +"<command>kdiff3</command> viewer." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:352 +msgid "" +"If your diff viewing command can't deal with directories, you can easily work " +"around this with a little scripting. For an example of such scripting in " +"action with the <literal role=\"hg-ext\">mq</literal> extension and the " +"<command>interdiff</command> command, see section <xref linkend=\"mq-collab." +"tips.interdiff\"/>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch13-hgext.xml:360 +msgid "Defining command aliases" +msgstr "定义命令的别名" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch13-hgext.xml:362 +msgid "" +"It can be cumbersome to remember the options to both the <command role=\"hg-" +"ext-extdiff\">extdiff</command> command and the diff viewer you want to use, " +"so the <literal role=\"hg-ext\">extdiff</literal> extension lets you define " +"<emphasis>new</emphasis> commands that will invoke your diff viewer with " +"exactly the right options." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch13-hgext.xml:369 +msgid "" +"All you need to do is edit your <filename role=\"special\">~/.hgrc</" +"filename>, and add a section named <literal role=\"rc-extdiff\">extdiff</" +"literal>. Inside this section, you can define multiple commands. Here's how " +"to add a <literal>kdiff3</literal> command. Once you've defined this, you " +"can type <quote><literal>hg kdiff3</literal></quote> and the <literal role=" +"\"hg-ext\">extdiff</literal> extension will run <command>kdiff3</command> for " +"you." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch13-hgext.xml:379 +msgid "" +"If you leave the right hand side of the definition empty, as above, the " +"<literal role=\"hg-ext\">extdiff</literal> extension uses the name of the " +"command you defined as the name of the external program to run. But these " +"names don't have to be the same. Here, we define a command named " +"<quote><literal>hg wibble</literal></quote>, which runs <command>kdiff3</" +"command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch13-hgext.xml:389 +msgid "" +"You can also specify the default options that you want to invoke your diff " +"viewing program with. The prefix to use is <quote><literal>opts.</literal></" +"quote>, followed by the name of the command to which the options apply. This " +"example defines a <quote><literal>hg vimdiff</literal></quote> command that " +"runs the <command>vim</command> editor's <literal>DirDiff</literal> extension." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch13-hgext.xml:403 +msgid "" +"Cherrypicking changes with the <literal role=\"hg-ext\">transplant</literal> " +"extension" +msgstr "使用扩展 <literal role=\"hg-ext\">transplant</literal> 以挑选修改" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:406 +msgid "Need to have a long chat with Brendan about this." +msgstr "" + +#. type: Content of: <book><chapter><sect1><title> +#: ../en/ch13-hgext.xml:410 +msgid "" +"Send changes via email with the <literal role=\"hg-ext\">patchbomb</literal> " +"extension" +msgstr "" +"使用扩展 <literal role=\"hg-ext\">patchbomb</literal> 通过 email 发送修改" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:413 +msgid "" +"Many projects have a culture of <quote>change review</quote>, in which people " +"send their modifications to a mailing list for others to read and comment on " +"before they commit the final version to a shared repository. Some projects " +"have people who act as gatekeepers; they apply changes from other people to a " +"repository to which those others don't have access." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:421 +msgid "" +"Mercurial makes it easy to send changes over email for review or application, " +"via its <literal role=\"hg-ext\">patchbomb</literal> extension. The " +"extension is so named because changes are formatted as patches, and it's " +"usual to send one changeset per email message. Sending a long series of " +"changes by email is thus much like <quote>bombing</quote> the recipient's " +"inbox, hence <quote>patchbomb</quote>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:429 +msgid "" +"As usual, the basic configuration of the <literal role=\"hg-ext\">patchbomb</" +"literal> extension takes just one or two lines in your <filename role=" +"\"special\"> /.hgrc</filename>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:435 +msgid "" +"Once you've enabled the extension, you will have a new command available, " +"named <command role=\"hg-ext-patchbomb\">email</command>." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:439 +msgid "" +"The safest and best way to invoke the <command role=\"hg-ext-patchbomb" +"\">email</command> command is to <emphasis>always</emphasis> run it first " +"with the <option role=\"hg-ext-patchbomb-cmd-email-opt\">hg -n</option> " +"option. This will show you what the command <emphasis>would</emphasis> send, " +"without actually sending anything. Once you've had a quick glance over the " +"changes and verified that you are sending the right ones, you can rerun the " +"same command, with the <option role=\"hg-ext-patchbomb-cmd-email-opt\">hg -n</" +"option> option removed." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:450 +msgid "" +"The <command role=\"hg-ext-patchbomb\">email</command> command accepts the " +"same kind of revision syntax as every other Mercurial command. For example, " +"this command will send every revision between 7 and <literal>tip</literal>, " +"inclusive." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:455 +msgid "" +"You can also specify a <emphasis>repository</emphasis> to compare with. If " +"you provide a repository but no revisions, the <command role=\"hg-ext-" +"patchbomb\">email</command> command will send all revisions in the local " +"repository that are not present in the remote repository. If you " +"additionally specify revisions or a branch name (the latter using the <option " +"role=\"hg-ext-patchbomb-cmd-email-opt\">hg -b</option> option), this will " +"constrain the revisions sent." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:464 +msgid "" +"It's perfectly safe to run the <command role=\"hg-ext-patchbomb\">email</" +"command> command without the names of the people you want to send to: if you " +"do this, it will just prompt you for those values interactively. (If you're " +"using a Linux or Unix-like system, you should have enhanced " +"<literal>readline</literal>-style editing capabilities when entering those " +"headers, too, which is useful.)" +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:472 +msgid "" +"When you are sending just one revision, the <command role=\"hg-ext-patchbomb" +"\">email</command> command will by default use the first line of the " +"changeset description as the subject of the single email message it sends." +msgstr "" + +#. type: Content of: <book><chapter><sect1><para> +#: ../en/ch13-hgext.xml:477 +msgid "" +"If you send multiple revisions, the <command role=\"hg-ext-patchbomb\">email</" +"command> command will usually send one message per changeset. It will " +"preface the series with an introductory message, in which you should describe " +"the purpose of the series of changes you're sending." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><title> +#: ../en/ch13-hgext.xml:484 +msgid "Changing the behaviour of patchbombs" +msgstr "修改 patchbomb 的行为" + +#. type: Content of: <book><chapter><sect1><sect2><para> +#: ../en/ch13-hgext.xml:486 +msgid "" +"Not every project has exactly the same conventions for sending changes in " +"email; the <literal role=\"hg-ext\">patchbomb</literal> extension tries to " +"accommodate a number of variations through command line options." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:492 +msgid "" +"You can write a subject for the introductory message on the command line " +"using the <option role=\"hg-ext-patchbomb-cmd-email-opt\">hg -s</option> " +"option. This takes one argument, the text of the subject to use." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:498 +msgid "" +"To change the email address from which the messages originate, use the " +"<option role=\"hg-ext-patchbomb-cmd-email-opt\">hg -f</option> option. This " +"takes one argument, the email address to use." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:504 +msgid "" +"The default behaviour is to send unified diffs (see section <xref linkend=" +"\"sec.mq.patch\"/> for a description of the format), one per message. You " +"can send a binary bundle instead with the <option role=\"hg-ext-patchbomb-cmd-" +"email-opt\">hg -b</option> option." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:512 +msgid "" +"Unified diffs are normally prefaced with a metadata header. You can omit " +"this, and send unadorned diffs, with the <option role=\"hg-ext-patchbomb-cmd-" +"email-opt\">hg --plain</option> option." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:518 +msgid "" +"Diffs are normally sent <quote>inline</quote>, in the same body part as the " +"description of a patch. This makes it easiest for the largest number of " +"readers to quote and respond to parts of a diff, as some mail clients will " +"only quote the first MIME body part in a message. If you'd prefer to send the " +"description and the diff in separate body parts, use the <option role=\"hg-" +"ext-patchbomb-cmd-email-opt\">hg -a</option> option." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:528 +msgid "" +"Instead of sending mail messages, you can write them to an <literal>mbox</" +"literal>-format mail folder using the <option role=\"hg-ext-patchbomb-cmd-" +"email-opt\">hg -m</option> option. That option takes one argument, the name " +"of the file to write to." +msgstr "" + +#. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> +#: ../en/ch13-hgext.xml:535 +msgid "" +"If you would like to add a <command>diffstat</command>-format summary to each " +"patch, and one to the introductory message, use the <option role=\"hg-ext-" +"patchbomb-cmd-email-opt\">hg -d</option> option. The <command>diffstat</" +"command> command displays a table containing the name of each file patched, " +"the number of lines affected, and a histogram showing how much each file is " +"modified. This gives readers a qualitative glance at how complex a patch is." +msgstr "" diff -r 9e8e5292acaa -r 1c13ed2130a7 sillybench/sillybench.py --- a/sillybench/sillybench.py Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -#!/usr/bin/python -# -# Silly benchmarking program, to give a vague idea of how fast a few -# tools are on a handful of common operations. -# -# Use a fairly big and real source tarball to test with: Firefox -# 2.0.0.3 (37622 files, 5374 directories, 343MB unpacked onto -# 4KB-blocksize ext3). - -import csv -import os -import shutil -import sys -import tempfile -import time -import urllib2 - -url = 'ftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/2.0.0.3/source/firefox-2.0.0.3-source.tar.bz2' - -class CommandFailure(Exception): - pass - -class rcs(object): - def __init__(self): - self.logfp = open(self.__class__.__name__ + '.csv', 'w') - self.csv = csv.writer(self.logfp) - - def download(self): - name = url[url.rfind('/')+1:] - path = os.path.join(os.environ['HOME'], name) - if not os.path.isfile(path): - ofp = open(path + '.part', 'wb') - try: - ifp = urllib2.urlopen(url) - nbytes = ifp.info()['content-length'] - sys.stdout.write('%s: %s bytes ' % (name, nbytes)) - sys.stdout.flush() - while True: - data = ifp.read(131072) - if not data: break - sys.stdout.write('.') - sys.stdout.flush() - ofp.write(data) - del ofp - os.rename(path + '.part', path) - except: - if os.path.exists(path + '.part'): - os.unlink(path + '.part') - if os.path.exists(path): - os.unlink(path) - raise - return path - - def run(self, args, mustsucceed=True): - ret = os.spawnvp(os.P_WAIT, args[0], args) - if ret < 0: - msg = 'killed by signal %d' % (-ret) - if ret > 0: - msg = 'exited with status %d' % (ret) - if ret: - if mustsucceed: - raise CommandFailure('%s: %s' % (msg, ' '.join(args))) - print >> sys.stderr, 'WARNING: %s: %s' % (msg, ' '.join(args)) - - def time(self, *args, **kwargs): - start = time.time() - self.run(*args, **kwargs) - end = time.time() - return end - start - - def logtime(self, name, elapsed, rest=[]): - self.log('time:' + name, '%.3f' % elapsed, rest) - - def log(self, name, value, rest=[]): - item = (name, value, repr(rest)) - print ' '.join(item) - self.csv.writerow(item) - self.logfp.flush() - - def unpack(self): - tarball = self.download() - t = self.time(['tar', '-C', self.wdir, '-jxf', tarball]) - self.logtime('internal:untar', t) - for name in os.listdir(os.path.join(self.wdir, 'mozilla')): - os.rename(os.path.join(self.wdir, 'mozilla', name), - os.path.join(self.wdir, name)) - - def cleanup(self): - pass - - def add(self, paths): - pass - - def commit(self, msg, paths): - pass - - def status(self, path): - pass - - def remove(self, path): - pass - - -class subversion(rcs): - def __init__(self, root): - rcs.__init__(self) - self.repo = os.path.join(root, 'repo') - self.wdir = os.path.join(root, 'wc') - create = self.time(['svnadmin', 'create', '--fs-type=fsfs', self.repo]) - self.logtime('svn:create', create) - co = self.time(['svn', 'co', 'file://' + self.repo, self.wdir]) - self.logtime('svn:co', co) - self.logtime('init', create + co) - os.chdir(self.wdir) - - def dropmeta(self, names): - return [n for n in names if os.path.basename(n) != '.svn'] - - def add(self, paths): - t = self.time(['svn', 'add', '-q'] + paths) - self.logtime('add %r' % paths, t) - - def commit(self, msg, paths=[]): - if paths: - t = self.time(['svn', 'ci', '-q', '-m', msg] + paths) - else: - t = self.time(['svn', 'ci', '-q', '-m', msg]) - self.logtime('commit %r' % paths, t) - - -class mercurial(rcs): - def __init__(self, root): - rcs.__init__(self) - self.repo = os.path.join(root, 'repo') - self.wdir = self.repo - init = self.time(['hg', 'init', self.repo]) - self.logtime('init', init) - os.chdir(self.wdir) - - def dropmeta(self, names): - return [n for n in names if os.path.basename(n) != '.hg'] - - def add(self, paths): - t = self.time(['hg', 'add', '-q'] + paths) - self.logtime('add %r' % paths, t) - - def commit(self, msg, paths=[]): - if paths: - t = self.time(['hg', 'ci', '-q', '-m', msg] + paths) - else: - t = self.time(['hg', 'ci', '-q', '-m', msg]) - self.logtime('commit %r' % paths, t) - -def benchmark(cls): - oldcwd = os.getcwd() - root = tempfile.mkdtemp(prefix='sillybench.') - try: - print 'root', root - inst = cls(root) - inst.unpack() - names = inst.dropmeta(os.listdir('.')) - dirs = [n for n in names if os.path.isdir(n)] - nondirs = [n for n in names if not os.path.isdir(n)] - dirs.sort(key=hash) - names.sort(key=hash) - for d in dirs[:len(dirs)/2]: - inst.add([d]) - inst.commit('Add %r' % d, [d]) - inst.add(dirs[len(dirs)/2:] + names) - inst.commit('Add remaining dirs and files') - finally: - print >> sys.stderr, '[cleaning up...]' - shutil.rmtree(root) - os.chdir(oldcwd) - -benchmark(mercurial) -#benchmark(subversion) diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/all-ids.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/all-ids.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Prepare an ASCII dump file of all IDs, and the pages in which + they live, for loading into a database. Assumes one-level chunked + HTML output, with each chunk containing either a chapter or + sect1. --> + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + + <xsl:output method="text"/> + <xsl:strip-space elements="title"/> + + <xsl:template match="/"> + <xsl:for-each select="//preface|//chapter|//appendix|//bibliography|//sect1"> + <xsl:variable name="id"> + <xsl:choose> + <xsl:when test="local-name(.)='sect1'"> + <xsl:value-of select="../@id"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@id"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="sectitle"> + <xsl:value-of select="normalize-space(./title)"/> + </xsl:variable> + <xsl:for-each select=".//para[@id]|.//programlisting[@id]|.//screen[@id]"> + <xsl:value-of select="@id"/> + <xsl:text>|</xsl:text> + <xsl:copy-of select="$id"/> + <xsl:text>|</xsl:text> + <xsl:copy-of select="$sectitle"/> + <xsl:text> </xsl:text> + </xsl:for-each> + </xsl:for-each> + </xsl:template> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/base-html-stylesheet.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/base-html-stylesheet.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,120 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + + <xsl:param name="html.stylesheet">/support/styles.css</xsl:param> + <xsl:param name="toc.section.depth">3</xsl:param> + <xsl:param name="annotate.toc">0</xsl:param> + + <xsl:param name="generate.id.attributes" select="1"></xsl:param> + <xsl:param name="header.rule" select="0"></xsl:param> + <xsl:param name="footer.rule" select="0"></xsl:param> + <xsl:param name="html.cleanup" select="1"></xsl:param> + <xsl:param name="admon.style"><xsl:text></xsl:text></xsl:param> + <xsl:param name="admon.graphics" select="1"></xsl:param> + <xsl:param name="admon.graphics.path">/support/figs/</xsl:param> + + <xsl:template match="sect1" mode="toc"> + <xsl:param name="toc-context" select="."/> + <xsl:call-template name="subtoc"> + <xsl:with-param name="toc-context" select="$toc-context"/> + <xsl:with-param name="nodes" + select="sect2|refentry|bridgehead[$bridgehead.in.toc != 0]"/> + </xsl:call-template> + </xsl:template> + + <xsl:template match="sect2" mode="toc"> + <xsl:param name="toc-context" select="."/> + + <xsl:call-template name="subtoc"> + <xsl:with-param name="toc-context" select="$toc-context"/> + <xsl:with-param name="nodes" + select="sect3|refentry|bridgehead[$bridgehead.in.toc != 0]"/> + </xsl:call-template> + </xsl:template> + + <!-- Add id attributes to <p> tags. This is mostly a copy of the + base XSL. --> + <xsl:template name="paragraph"> + <xsl:param name="class" select="''"/> + <xsl:param name="content"/> + + <xsl:variable name="p"> + <p> + <xsl:call-template name="dir"/> + <xsl:if test="$class != ''"> + <xsl:apply-templates select="." mode="class.attribute"> + <xsl:with-param name="class" select="$class"/> + </xsl:apply-templates> + </xsl:if> + <!-- Here we go. --> + <xsl:if test="$generate.id.attributes != 0"> + <xsl:attribute name="id"> + <xsl:call-template name="object.id"/> + </xsl:attribute> + </xsl:if> + <xsl:copy-of select="$content"/> + </p> + </xsl:variable> + + <xsl:choose> + <xsl:when test="$html.cleanup != 0"> + <xsl:call-template name="unwrap.p"> + <xsl:with-param name="p" select="$p"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:copy-of select="$p"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Add id attributes to <programlisting> and <screen> tags. Once + again, this is mostly a copy of the base XSL, although rather + trimmed down. --> + <xsl:template match="programlisting|screen"> + <xsl:param name="suppress-numbers" select="'0'"/> + + <xsl:call-template name="anchor"/> + + <pre> + <!-- Here we go. --> + <xsl:if test="$generate.id.attributes != 0"> + <xsl:attribute name="id"> + <xsl:call-template name="object.id"/> + </xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="." mode="class.attribute"/> + <xsl:call-template name="apply-highlighting"/> + </pre> + </xsl:template> + + <!-- The default stylesheet generates a little TOC at the beginning + of each qandaset. Uh, no thanks. --> + <xsl:template name="process.qanda.toc"/> + + <xsl:template name="user.header.navigation"> + <div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a> <span class="authors">by Bryan O'Sullivan</span></h2></div> + </xsl:template> + + <xsl:template name="user.head.content"> + <link rel="alternate" type="application/atom+xml" title="Comments" + href="/feeds/comments/"/> + <link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"/> + <script type="text/javascript" src="/support/jquery-min.js"></script> + <script type="text/javascript" src="/support/form.js"></script> + <script type="text/javascript" src="/support/hsbook.js"></script> + </xsl:template> + + <xsl:template name="user.footer.content"> + <div class="hgfooter"> + <p><img src="/support/figs/rss.png"/> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p> + <p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan. + Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p> + </div> + </xsl:template> + + <xsl:template name="user.footer.navigation"> + <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script> + <script type="text/javascript">_uacct = "UA-1805907-3"; urchinTracker();</script> + </xsl:template> +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/chunk-stylesheet.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/chunk-stylesheet.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,17 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + + <xsl:import href="system-xsl/html/chunk.xsl"/> + <xsl:include href="base-html-stylesheet.xsl"/> + + <!-- PARAMETER REFERENCE: --> + <!-- http://docbook.sourceforge.net/release/xsl/current/doc/html/ --> + + <!-- Uncomment this to enable auto-numbering of sections --> + <!-- xsl:param name="section.autolabel" select="1" / --> + <xsl:param name="chunker.output.encoding">UTF-8</xsl:param> + <xsl:param name="use.id.as.filename" select="1"/> + <xsl:param name="chunk.first.sections" select="0"/> + <xsl:param name="chunk.section.depth" select="0"/> + <xsl:param name="chunk.quietly" select="0"/> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/dtd-profile.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/dtd-profile.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,15 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + <xsl:import href="system-xsl/profiling/profile.xsl"></xsl:import> + + <!-- For some reason, xsltproc omits the DTD from the file it + outputs. Add a sensible one back in, because otherwise xmllint + won't validate profiled documents. --> + + <xsl:template match="/"> + <xsl:text disable-output-escaping="yes"><![CDATA[ +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" + "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> + ]]></xsl:text> + <xsl:apply-templates select="." mode="profile"/> + </xsl:template> +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/en/fo.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/en/fo.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:fo="http://www.w3.org/1999/XSL/Format" + version='1.0'> + + <xsl:import href="../fo.xsl"/> + + <xsl:param name="l10n.gentext.language" select="'en'"/> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/en/html-single.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/en/html-single.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + + <xsl:import href="../html-single.xsl"/> + + <xsl:param name="l10n.gentext.language" select="'en'"/> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/en/html.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/en/html.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + + <xsl:import href="../html.xsl"/> + + <xsl:param name="l10n.gentext.language" select="'en'"/> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/fo.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/fo.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,79 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + + <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/> + + <xsl:param name="draft.mode" select="no"/> + + <!-- These extensions are required for table printing and other stuff --> + <xsl:param name="use.extensions">1</xsl:param> + <xsl:param name="callouts.extension">1</xsl:param> + <xsl:param name="linenumbering.extension">1</xsl:param> + <xsl:param name="tablecolumns.extension">1</xsl:param> + <xsl:param name="textinsert.extension">1</xsl:param> + + <xsl:param name="admon.graphics" select="1" /> + <xsl:param name="admon.graphics.extension">.png</xsl:param> + <xsl:param name="callout.graphics" select="1" /> + <xsl:param name="callout.graphics.extension">.png</xsl:param> + + <xsl:param name="section.autolabel" select="1" /> + <xsl:param name="section.label.includes.component.label">1</xsl:param> + + <xsl:param name="variablelist.as.blocks" select="1" /> <!-- fo only --> + <xsl:param name="hyphenate">false</xsl:param> <!-- fo only --> + <xsl:param name="paper.type" select="'A4'"></xsl:param> <!-- fo only --> + + <!-- Default font settings --> + <!-- + <xsl:param name="title.font.family">sans-serif</xsl:param> + <xsl:param name="body.font.family">serif</xsl:param> + <xsl:param name="sans.font.family">sans-serif</xsl:param> + <xsl:param name="dingbat.font.family">serif</xsl:param> + <xsl:param name="monospace.font.family">monospace</xsl:param> + <xsl:param name="symbol.font.family">Symbol,ZapfDingbats</xsl:param> + --> + + <!-- Custom font settings - preferred truetype font --> + <xsl:param name="title.font.family">Calibri,sans-serif,SimHei</xsl:param> + <xsl:param name="body.font.family">Cambria,Cambria Math,serif,SimSun</xsl:param> + <xsl:param name="sans.font.family">Calibri,sans-serif,SimHei</xsl:param> + <xsl:param name="dingbat.font.family">Cambria,Cambria Math,serif,SimSun</xsl:param> + <xsl:param name="monospace.font.family">Courier New,monospace,FangSong</xsl:param> + + <!-- Page related Settings --> + <xsl:param name="page.margin.inner">1.5cm</xsl:param> + <xsl:param name="page.margin.outer">1.5cm</xsl:param> + <xsl:param name="title.margin.left">0pt</xsl:param> + <xsl:param name="body.start.indent">24pt</xsl:param> + <xsl:param name="body.end.indent">0pt</xsl:param> + + <!-- Breaking long lines --> + <xsl:param name="hyphenate.verbatim">1</xsl:param> + <xsl:attribute-set name="monospace.verbatim.properties" + use-attribute-sets="verbatim.properties monospace.properties"> + <xsl:attribute name="wrap-option">wrap</xsl:attribute> + <xsl:attribute name="hyphenation-character">►</xsl:attribute> + </xsl:attribute-set> + + <!-- Prevent blank pages in output --> + <xsl:template name="book.titlepage.before.verso"> + </xsl:template> + <xsl:template name="book.titlepage.verso"> + </xsl:template> + <xsl:template name="book.titlepage.separator"> + </xsl:template> + + <!-- Colourize links in output --> + <xsl:attribute-set name="xref.properties"> + <xsl:attribute name="color"> + <xsl:choose> + <xsl:when test="self::ulink">blue</xsl:when> + <xsl:when test="self::xref">blue</xsl:when> + <xsl:when test="self::uri">blue</xsl:when> + <xsl:otherwise>red</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:attribute-set> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/hgbook.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/hgbook.css Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,441 @@ +body { + font: 12px/1.5 Verdana, sans-serif; + padding-top: 50px; + padding-left: 80px; + padding-right: 80px; + padding-bottom: 90px; +} +.ptmr7t- { + font-family: monospace; +} +.ptmr7t-x-x-172 { + font-size: 172%; + font-family: monospace; +} +.ptmr7t-x-x-120 { + font-size: 120%; +} +.zpzccmry-x-x-120 { + font-size: 120%; + font-weight: bold; + font-style: italic; +} +.zpzccmry-x-x-120 { + font-weight: bold; + font-style: italic; +} +.pcrr7tn- { + font-family: monospace; +} +.ptmri7t- { + font-style: italic; +} +.ptmr7t-x-x-50 { + font-size: 50%; + font-family: monospace; +} +.ptmb7t- { + font-weight: bold; +} +.zptmcmr- { + font-style: italic; +} +.zptmcmrm- { + font-style: italic; +} +.zpzccmry- { + font-weight: bold; + font-style: italic; +} +.pcrb7t- { + font-family: monospace; + font-weight: bold; +} +.pcrro7t- { + font-family: monospace; + font-style: oblique; +} +p.noindent { + text-indent: 0em; + margin: 0em; +} +p.nopar { + text-indent: 0em; +} +p.indent { + text-indent: 1.5em; + margin: 0em; +} +a img { + border-top: 0; + border-left: 0; + border-right: 0; +} +center { + margin-top: 1em; + margin-bottom: 1em; +} +td center { + margin-top: 0em; + margin-bottom: 0em; +} +.Canvas { + position: relative; +} +img.math { + vertical-align: middle; +} +li p.indent { + text-indent: 0em; +} +.enumerate1 { + list-style-type: decimal; +} +.enumerate2 { + list-style-type: lower-alpha; +} +.enumerate3 { + list-style-type: lower-roman; +} +.enumerate4 { + list-style-type: upper-alpha; +} +div.newtheorem { + margin-bottom: 2em; + margin-top: 2em; +} +.obeylines-h,.obeylines-v { + white-space: nowrap; +} +div.obeylines-v p { + margin-top: 0; + margin-bottom: 0; +} +.overline { + text-decoration: overline; +} +.overline img { + border-top: 1px solid black; +} +td.displaylines { + text-align: center; + white-space: nowrap; +} +.centerline { + text-align: center; +} +.rightline { + text-align: right; +} +div.verbatim { + font-family: monospace; + white-space: nowrap; +} +table.verbatim { + width: 100%; +} +.fbox { + background: url(note.png) no-repeat #cec; + padding-left: 65px; + padding-top: 1em; + padding-bottom: 1em; + padding-right: 1em; + text-indent: 0pt; + border: dotted black 1px; +} +div.center div.fbox { + text-align: center; + clear: both; + padding-left: 3.0pt; + padding-right: 3.0pt; + text-indent: 0pt; + border: solid black 0.4pt; +} +table.minipage { + width: 100%; +} +div.center, div.center div.center { + text-align: center; + margin-left: 1em; + margin-right: 1em; +} +div.center div { + text-align: left; +} +div.flushright, div.flushright div.flushright { + text-align: right; +} +div.flushright div { + text-align: left; +} +div.flushleft { + text-align: left; +} +.underline { + text-decoration: underline; +} +.underline img { + border-bottom: 1px solid black; + margin-bottom: 1pt; +} +.framebox-c, .framebox-l, .framebox-r { + padding-left: 3.0pt; + padding-right: 3.0pt; + text-indent: 0pt; + border: solid black 0.4pt; +} +.framebox-c { + text-align: center; +} +.framebox-l { + text-align: left; +} +.framebox-r { + text-align: right; +} +span.thank-mark { + vertical-align: super +} +span.footnote-mark sup.textsuperscript, span.footnote-mark a sup.textsuperscript { + font-size: 80%; +} +div.tabular, div.center div.tabular { + text-align: center; + margin-top: 0.5em; + margin-bottom: 0.5em; +} +table.tabular td p { + margin-top: 0em; +} +table.tabular { + margin-left: auto; + margin-right: auto; +} +div.td00 { + margin-left: 0pt; + margin-right: 0pt; +} +div.td01 { + margin-left: 0pt; + margin-right: 5pt; +} +div.td10 { + margin-left: 5pt; + margin-right: 0pt; +} +div.td11 { + margin-left: 5pt; + margin-right: 5pt; +} +table[rules] { + border-left: solid black 0.4pt; + border-right: solid black 0.4pt; +} +td.td00 { + padding-left: 0pt; + padding-right: 0pt; +} +td.td01 { + padding-left: 0pt; + padding-right: 5pt; +} +td.td10 { + padding-left: 5pt; + padding-right: 0pt; +} +td.td11 { + padding-left: 5pt; + padding-right: 5pt; +} +table[rules] { + border-left: solid black 0.4pt; + border-right: solid black 0.4pt; +} +.hline hr, .cline hr { + height : 1px; + margin: 0px; +} +.tabbing-right { + text-align: right; +} +span.TEX { + letter-spacing: -0.125em; +} +span.TEX span.E { + position: relative;top: 0.5ex;left: -0.0417em; +} +a span.TEX span.E { + text-decoration: none; +} +span.LATEX span.A { + position: relative; + top: -0.5ex; + left: -0.4em; + font-size: 85%; +} +span.LATEX span.TEX { + position: relative; + left: -0.4em; +} +div.float img, div.float .caption { + text-align: center; +} +div.figure img, div.figure .caption { + text-align: center; +} +.marginpar { + width: 20%; + float: right; + text-align: left; + margin-left: auto; + margin-top: 0.5em; + font-size: 85%; + text-decoration: underline; +} +.marginpar p { + margin-top: 0.4em; + margin-bottom: 0.4em; +} +table.equation { + width: 100%; +} +.equation td { + text-align: center; +} +td.equation { + margin-top: 1em; + margin-bottom: 1em; +} +td.equation-label { + width: 5%; + text-align: center; +} +td.eqnarray4 { + width: 5%; + white-space: normal; +} +td.eqnarray2 { + width: 5%; +} +table.eqnarray-star, table.eqnarray { + width: 100%; +} +div.eqnarray { + text-align: center; +} +div.array { + text-align: center; +} +div.pmatrix { + text-align: center; +} +table.pmatrix { + width: 100%; +} +span.pmatrix img { + vertical-align: middle; +} +div.pmatrix { + text-align: center; +} +table.pmatrix { + width: 100%; +} +img.cdots { + vertical-align: middle; +} +.partToc a, .partToc, .likepartToc a, .likepartToc { + line-height: 200%; + font-weight: bold; + font-size: 110%; +} +.chapterToc a, .chapterToc, .likechapterToc a, .likechapterToc, .appendixToc a, .appendixToc { + line-height: 200%; + font-weight: bold; +} +.caption td.id { + font-weight: bold; + white-space: nowrap; +} +table.caption { + text-align: center; +} +h1.partHead { + text-align: center; +} +p.bibitem { + text-indent: -2em; + margin-left: 2em; + margin-top: 0.6em; + margin-bottom: 0.6em; +} +p.bibitem-p { + text-indent: 0em; + margin-left: 2em; + margin-top: 0.6em; + margin-bottom: 0.6em; +} +.paragraphHead, .likeparagraphHead { + margin-top: 2em; + font-weight: bold; +} +.subparagraphHead, .likesubparagraphHead { + font-weight: bold; +} +.quote { + margin-bottom: 0.25em; + margin-top: 0.25em; + margin-left: 1em; + margin-right: 1em; + text-align: justify; +} +.verse { + white-space: nowrap; + margin-left: 2em} +div.maketitle { + text-align: center; +} +h2.titleHead { + text-align: center; +} +div.maketitle { + margin-bottom: 2em; +} +div.author, div.date { + text-align: center; +} +div.thanks { + text-align: left; + margin-left: 10%; + font-size: 85%; + font-style: italic; +} +div.author { + white-space: nowrap; +} +.quotation { + margin-bottom: 0.25em; + margin-top: 0.25em; + margin-left: 1em; +} +h1.partHead { + text-align: center; +} +img.graphics { + margin-left: 10%; +} +.figure { + width: 100%; +} +P.fancyvrb { + white-space: nowrap; +} +hr { + border: 0; + height: 1px; +} +div#fancyvrb { + white-space: nowrap; + background: #eee; + padding: 1em; +} diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/html-single.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/html-single.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,30 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + + <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/> + + <xsl:param name="draft.mode" select="no"/> + + <!-- xsltproc can't support these extensions + <xsl:param name="use.extensions">1</xsl:param> + <xsl:param name="callouts.extension">1</xsl:param> + <xsl:param name="linenumbering.extension">1</xsl:param> + <xsl:param name="tablecolumns.extension">1</xsl:param> + <xsl:param name="textinsert.extension">1</xsl:param> + --> + + <xsl:param name="admon.graphics" select="1" /> + <xsl:param name="admon.graphics.extension">.png</xsl:param> + <xsl:param name="callout.graphics" select="1" /> + <xsl:param name="callout.graphics.extension">.png</xsl:param> + + <xsl:param name="section.autolabel" select="1" /> + <xsl:param name="section.label.includes.component.label">1</xsl:param> + + <xsl:output method="html" encoding="utf-8" indent="yes"/> <!-- html only --> + <xsl:param name="use.id.as.filename">0</xsl:param> <!-- html only --> + <xsl:param name="chunk.section.depth">0</xsl:param> <!-- html only --> + <xsl:param name="chunker.output.indent">yes</xsl:param> <!-- html only --> + <xsl:param name="html.stylesheet">hgbook.css</xsl:param> <!-- html only --> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/html.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/html.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + + <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl"/> + + <xsl:param name="draft.mode" select="no"/> + + <!-- xsltproc can't support these extensions + <xsl:param name="use.extensions">1</xsl:param> + <xsl:param name="callouts.extension">1</xsl:param> + <xsl:param name="linenumbering.extension">1</xsl:param> + <xsl:param name="tablecolumns.extension">1</xsl:param> + <xsl:param name="textinsert.extension">1</xsl:param> + --> + + <xsl:param name="admon.graphics" select="1" /> + <xsl:param name="admon.graphics.extension">.png</xsl:param> + <xsl:param name="callout.graphics" select="1" /> + <xsl:param name="callout.graphics.extension">.png</xsl:param> + + <xsl:param name="section.autolabel" select="1" /> + <xsl:param name="section.label.includes.component.label">1</xsl:param> + + <xsl:output method="html" encoding="utf-8" indent="yes"/> <!-- html only --> + <xsl:param name="chunker.output.encoding" select="'utf-8'"/> <!-- html only --> + <xsl:param name="chunker.output.indent" select="'yes'"/> <!-- html only --> + <xsl:param name="use.id.as.filename">0</xsl:param> <!-- html only --> + <xsl:param name="chunk.section.depth">0</xsl:param> <!-- html only --> + <xsl:param name="chunker.output.indent">yes</xsl:param> <!-- html only --> + <xsl:param name="html.stylesheet">hgbook.css</xsl:param> <!-- html only --> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/zh/fo.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/zh/fo.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,30 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:fo="http://www.w3.org/1999/XSL/Format" + version='1.0'> + + <xsl:import href="../fo.xsl"/> + + <xsl:param name="l10n.gentext.language" select="'zh'"/> + + <!-- Chinese font related settings --> + <xsl:param name="body.font.master">12</xsl:param> + + <xsl:attribute-set name="standard.para.spacing" use-attribute-sets="normal.para.spacing"> + <xsl:attribute name="text-indent">24pt</xsl:attribute> + </xsl:attribute-set> + + <xsl:template match="abstract/para|appendix/para|chapter/para|colophon/para|legalnotice/para|preface/para|section/para|sect1/para|sect2/para"> + <fo:block xsl:use-attribute-sets="standard.para.spacing"> + <xsl:call-template name="anchor"/> + <xsl:apply-templates/> + </fo:block> + </xsl:template> + + <xsl:template match="section/para/*"> + <fo:wrapper text-indent="0pt"> + <xsl:apply-imports/> + </fo:wrapper> + </xsl:template> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/zh/html-single.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/zh/html-single.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + + <xsl:import href="../html-single.xsl"/> + + <xsl:param name="l10n.gentext.language" select="'zh'"/> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 stylesheets/zh/html.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stylesheets/zh/html.xsl Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> + + <xsl:import href="../html.xsl"/> + + <xsl:param name="l10n.gentext.language" select="'zh'"/> + +</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 tools/latex-to-docbook --- a/tools/latex-to-docbook Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,198 +0,0 @@ -#!/usr/bin/python -# -# This is the most horrible of hacks. Pretend you're not looking.</para> - -import cStringIO as StringIO -import re, sys - -sections = { - 'chapter': 'chapter', - 'section': 'sect1', - 'subsection': 'sect2', - 'subsubsection': 'sect3', - } - -envs = { - 'codesample2': 'programlisting', - 'codesample4': 'programlisting', - 'enumerate': 'orderedlist', - 'figure': 'informalfigure', - 'itemize': 'itemizedlist', - 'note': 'note', - 'quote': 'blockquote', - } - -def process(ifp, ofp): - print >> ofp, '<!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->\n' - stack = [] - para = True - inlist = 0 - for line in ifp: - if line.startswith('%%% Local Variables:'): - break - line = (line.rstrip() - .replace('~', ' ') - .replace('&', '&') - .replace('---', '&emdash;') - .replace('\_', '_') - .replace('\{', '{') - .replace('\}', '}') - .replace('\$', '$') - .replace('\%', '%') - .replace('\#', '#') - .replace('<', '<') - .replace('>', '>') - .replace('``', '<quote>') - .replace("''", '</quote>') - .replace('\\', '\\')) - line = re.sub(r'\s*\\(?:centering|small)\b\s*', '', line) - line = re.sub(r'\\(?:hgrc\\|hgrc)\b', - r'<filename role="special"> /.hgrc</filename>', line) - line = re.sub(r'\\item\[(?P<key>[^]]+)\]', r'\item \g<key>:', line) - line = re.sub(r'\\bug{(?P<id>\d+)}', - r'<ulink role="hg-bug" url="http://www.selenic.com/mercurial/bts/issue\g<id>">issue \g<id></ulink>', line) - line = re.sub(r'\\cite{([^}]+)}', r'<citation>\1</citation>', line) - line = re.sub(r'\\hggopt{(?P<opt>[^}]+)}', - r'<option role="hg-opt-global">\g<opt></option>', line) - line = re.sub(r'\\hgxopt{(?P<ext>[^}]+)}{(?P<cmd>[^}]+)}{(?P<opt>[^}]+)}', - r'<option role="hg-ext-\g<ext>-cmd-\g<cmd>-opt">\g<opt></option>', line) - line = re.sub(r'\\hgxcmd{(?P<ext>[^}]+)}{(?P<cmd>[^}]+)}', - r'<command role="hg-ext-\g<ext>">\g<cmd></command>', line) - line = re.sub(r'\\hgext{(?P<ext>[^}]+)}', - r'<literal role="hg-ext">\g<ext></literal>', line) - line = re.sub(r'\\hgopt{(?P<cmd>[^}]+)}{(?P<opt>[^}]+)}', - r'<option role="hg-opt-\g<cmd>">\g<opt></option>', - line) - line = re.sub(r'\\cmdopt{(?P<cmd>[^}]+)}{(?P<opt>[^}]+)}', - r'<option role="cmd-opt-\g<cmd>">\g<opt></option>', - line) - line = re.sub(r'\\hgcmd{(?P<cmd>[^}]+)}', - r'<command role="hg-cmd">hg \g<cmd></command>', line) - line = re.sub(r'\\caption{(?P<text>[^}]+?)}', - r'<caption><para>\g<text></para></caption>', line) - line = re.sub(r'\\grafix{(?P<name>[^}]+)}', - r'<mediaobject><imageobject><imagedata fileref="\g<name>"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>', line) - line = re.sub(r'\\envar{(?P<name>[^}]+)}', - r'<envar>\g<name></envar>', line) - line = re.sub(r'\\rcsection{(?P<sect>[^}]+)}', - r'<literal role="rc-\g<sect>">\g<sect></literal>', line) - line = re.sub(r'\\rcitem{(?P<sect>[^}]+)}{(?P<name>[^}]+)}', - r'<envar role="rc-item-\g<sect>">\g<name></envar>', line) - line = re.sub(r'\\dirname{(?P<dir>[^}]+?)}', - r'<filename class="directory">\g<dir></filename>', line) - line = re.sub(r'\\filename{(?P<file>[^}]+?)}', - r'<filename>\g<file></filename>', line) - line = re.sub(r'\\tildefile{(?P<file>[^}]+)}', - r'<filename role="home">~/\g<file></filename>', line) - line = re.sub(r'\\sfilename{(?P<file>[^}]+)}', - r'<filename role="special">\g<file></filename>', line) - line = re.sub(r'\\sdirname{(?P<dir>[^}]+)}', - r'<filename role="special" class="directory">\g<dir></filename>', line) - line = re.sub(r'\\interaction{(?P<id>[^}]+)}', - r'<!-- &interaction.\g<id>; -->', line) - line = re.sub(r'\\excode{(?P<id>[^}]+)}', - r'<!-- &example.\g<id>; -->', line) - line = re.sub(r'\\pymod{(?P<mod>[^}]+)}', - r'<literal role="py-mod">\g<mod></literal>', line) - line = re.sub(r'\\pymodclass{(?P<mod>[^}]+)}{(?P<class>[^}]+)}', - r'<literal role="py-mod-\g<mod>">\g<class></literal>', line) - line = re.sub(r'\\url{(?P<url>[^}]+)}', - r'<ulink url="\g<url>">\g<url></ulink>', line) - line = re.sub(r'\\href{(?P<url>[^}]+)}{(?P<text>[^}]+)}', - r'<ulink url="\g<url>">\g<text></ulink>', line) - line = re.sub(r'\\command{(?P<cmd>[^}]+)}', - r'<command>\g<cmd></command>', line) - line = re.sub(r'\\option{(?P<opt>[^}]+)}', - r'<option>\g<opt></option>', line) - line = re.sub(r'\\ref{(?P<id>[^}]+)}', r'<xref linkend="\g<id>"/>', line) - line = re.sub(r'\\emph{(?P<txt>[^}]+)}', - r'<emphasis>\g<txt></emphasis>', line) - line = re.sub(r'\\texttt{(?P<txt>[^}]+)}', - r'<literal>\g<txt></literal>', line) - line = re.sub(r'\\textbf{(?P<txt>[^}]+)}', - r'<emphasis role="bold">\g<txt></emphasis>', line) - line = re.sub(r'\\hook{(?P<name>[^}]+)}', - r'<literal role="hook">\g<name></literal>', line) - line = re.sub(r'\\tplfilter{(?P<name>[^}]+)}', - r'<literal role="template-filter">\g<name></literal>', line) - line = re.sub(r'\\tplkword{(?P<name>[^}]+)}', - r'<literal role="template-keyword">\g<name></literal>', line) - line = re.sub(r'\\tplkwfilt{(?P<tpl>[^}]+)}{(?P<name>[^}]+)}', - r'<literal role="template-kw-filt-\g<tpl>">\g<name></literal>', line) - line = re.sub(r'\\[vV]erb(.)(?P<txt>[^\1]+?)\1', - r'<literal>\g<txt></literal>', line) - line = re.sub(r'\\package{(?P<name>[^}]+)}', - r'<literal role="package">\g<name></literal>', line) - line = re.sub(r'\\hgcmdargs{(?P<cmd>[^}]+)}{(?P<args>[^}]+)}', - r'<command role="hg-cmd">hg \g<cmd> \g<args></command>', - line) - line = re.sub(r'\\cmdargs{(?P<cmd>[^}]+)}{(?P<args>[^}]+)}', - r'<command>\g<cmd> \g<args></command>', - line) - m = re.match(r'\\(chapter|section|subsection|subsubsection){(.*)}', line) - if m: - kind, content = m.groups() - sec = sections[kind] - while stack and stack[-1] >= sec: - close = stack.pop() - print >> ofp, '</%s>' % close - stack.append(sec) - print >> ofp, '<%s>\n<title>%s' % (sec, content) - else: - m = re.match(r'\s*\\(begin|end){(?P[^}]+)}', line) - if m: - if not para: - print >> ofp, '
' - if inlist: - ofp.write('') - para = True - state, env = m.groups() - env = envs[env] - if state == 'begin': - ofp.write('<') - if env in ('itemizedlist', 'orderedlist'): - inlist = 1 - else: - ofp.write('> ofp, env + '>' - else: - if line.startswith('\\item '): - if inlist > 1: - print >> ofp, '' - print >> ofp, '' - else: - inlist = 2 - para = True - line = line[6:] - if line and para: - if inlist: - ofp.write('') - ofp.write('') - para = False - if not line and not para: - print >> ofp, '' - if inlist: - ofp.write('') - para = True - print >> ofp, line - while stack: - print >> ofp, '' % stack.pop() - ofp.write('\n'.join(['\n'])) - - -if __name__ == '__main__': - for name in sys.argv[1:]: - if not name.endswith('.tex'): - continue - newname = name[:-3] + 'xml' - ofp = StringIO.StringIO() - process(open(name), ofp) - s = ofp.getvalue() - s = re.sub('\n+', '', s, re.M) - open(newname, 'w').write(s) diff -r 9e8e5292acaa -r 1c13ed2130a7 tools/po4a/lib/Locale/Po4a/Chooser.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/po4a/lib/Locale/Po4a/Chooser.pm Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,148 @@ +# Locale::Po4a::Pod -- Convert POD data to PO file, for translation. +# $Id: Chooser.pm,v 1.41 2008-07-20 16:31:55 nekral-guest Exp $ +# +# This program is free software; you may redistribute it and/or modify it +# under the terms of GPL (see COPYING). +# +# This module converts POD to PO file, so that it becomes possible to +# translate POD formatted documentation. See gettext documentation for +# more info about PO files. + +############################################################################ +# Modules and declarations +############################################################################ + + +package Locale::Po4a::Chooser; + +use 5.006; +use strict; +use warnings; +use Locale::Po4a::Common; + +sub new { + my ($module)=shift; + my (%options)=@_; + + die wrap_mod("po4a::chooser", gettext("Need to provide a module name")) + unless defined $module; + + my $modname; + if ($module eq 'kernelhelp') { + $modname = 'KernelHelp'; + } elsif ($module eq 'newsdebian') { + $modname = 'NewsDebian'; + } elsif ($module eq 'latex') { + $modname = 'LaTeX'; + } elsif ($module eq 'bibtex') { + $modname = 'BibTex'; + } elsif ($module eq 'tex') { + $modname = 'TeX'; + } else { + $modname = ucfirst($module); + } + if (! UNIVERSAL::can("Locale::Po4a::$modname", 'new')) { + eval qq{use Locale::Po4a::$modname}; + if ($@) { + my $error=$@; + warn wrap_msg(gettext("Unknown format type: %s."), $module); + warn wrap_mod("po4a::chooser", + gettext("Module loading error: %s"), $error) + if defined $options{'verbose'} && $options{'verbose'} > 0; + list(1); + } + } + return "Locale::Po4a::$modname"->new(%options); +} + +sub list { + warn wrap_msg(gettext("List of valid formats:") +# ."\n - ".gettext("bibtex: BibTex bibliography format.") + ."\n - ".gettext("dia: uncompressed Dia diagrams.") + ."\n - ".gettext("docbook: Docbook XML.") + ."\n - ".gettext("guide: Gentoo Linux's xml documentation format.") +# ."\n - ".gettext("html: HTML documents (EXPERIMENTAL).") + ."\n - ".gettext("ini: .INI format.") + ."\n - ".gettext("kernelhelp: Help messages of each kernel compilation option.") + ."\n - ".gettext("latex: LaTeX format.") + ."\n - ".gettext("man: Good old manual page format.") + ."\n - ".gettext("pod: Perl Online Documentation format.") + ."\n - ".gettext("sgml: either debiandoc or docbook DTD.") + ."\n - ".gettext("texinfo: The info page format.") + ."\n - ".gettext("tex: generic TeX documents (see also latex).") + ."\n - ".gettext("text: simple text document.") + ."\n - ".gettext("wml: WML documents.") + ."\n - ".gettext("xhtml: XHTML documents.") + ."\n - ".gettext("xml: generic XML documents (see also docbook).") + ); + exit shift; +} +############################################################################## +# Module return value and documentation +############################################################################## + +1; +__END__ + +=head1 NAME + +Locale::Po4a::Chooser - Manage po4a modules + +=head1 DESCRIPTION + +Locale::Po4a::Chooser is a module to manage po4a modules. Before, all po4a +binaries used to know all po4a modules (pod, man, sgml, etc). This made the +add of a new module boring, to make sure the documentation is synchronized +in all modules, and that each of them can access the new module. + +Now, you just have to call the Locale::Po4a::Chooser::new() function, +passing the name of module as argument. + +You also have the Locale::Po4a::Chooser::list() function which lists the +available format and exits on the value passed as argument. + +=head1 SEE ALSO + +=over 4 + +=item About po4a: + +L, +L, +L + +=item About modules: + +L, +L, +L, +L, +L, +L, +L, +L, +L, +L, +L, +L, +L, +L. +L, +L, +L. + +=back + +=head1 AUTHORS + + Denis Barbier + Martin Quinson (mquinson#debian.org) + +=head1 COPYRIGHT AND LICENSE + +Copyright 2002,2003,2004,2005 by SPI, inc. + +This program is free software; you may redistribute it and/or modify it +under the terms of GPL (see the COPYING file). + +=cut diff -r 9e8e5292acaa -r 1c13ed2130a7 tools/po4a/lib/Locale/Po4a/Common.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/po4a/lib/Locale/Po4a/Common.pm Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,246 @@ +# Locale::Po4a::Common -- Common parts of the po4a scripts and utils +# $Id: Common.pm,v 1.20 2009-02-13 23:16:44 nekral-guest Exp $ +# +# Copyright 2005 by Jordi Vilalta +# +# This program is free software; you may redistribute it and/or modify it +# under the terms of GPL (see COPYING). +# +# This module has common utilities for the various scripts of po4a + +=head1 NAME + +Locale::Po4a::Common - Common parts of the po4a scripts and utils + +=head1 DESCRIPTION + +Locale::Po4a::Common contains common parts of the po4a scripts and some useful +functions used along the other modules. + +In order to use Locale::Po4a programatically, one may want to disable +the use of Text::WrapI18N, by writing e.g. + + use Locale::Po4a::Common qw(nowrapi18n); + use Locale::Po4a::Text; + +instead of: + + use Locale::Po4a::Text; + +Ordering is important here: as most Locale::Po4a modules themselves +load Locale::Po4a::Common, the first time this module is loaded +determines whether Text::WrapI18N is used. + +=cut + +package Locale::Po4a::Common; + +require Exporter; +use vars qw(@ISA @EXPORT); +@ISA = qw(Exporter); +@EXPORT = qw(wrap_msg wrap_mod wrap_ref_mod textdomain gettext dgettext); + +use 5.006; +use strict; +use warnings; + +sub import { + my $class=shift; + + my $wrapi18n=1; + if (exists $_[0] && defined $_[0] && $_[0] eq 'nowrapi18n') { + shift; + $wrapi18n=0; + } + $class->export_to_level(1, $class, @_); + + return if defined &wrapi18n; + + if ($wrapi18n && -t STDERR && -t STDOUT && eval { require Text::WrapI18N }) { + + # Don't bother determining the wrap column if we cannot wrap. + my $col=$ENV{COLUMNS}; + if (!defined $col) { + my @term=eval "use Term::ReadKey; Term::ReadKey::GetTerminalSize()"; + $col=$term[0] if (!$@); + # If GetTerminalSize() failed we will fallback to a safe default. + # This can happen if Term::ReadKey is not available + # or this is a terminal-less build or such strange condition. + } + $col=76 if (!defined $col); + + eval ' use Text::WrapI18N qw($columns); + $columns = $col; + '; + + eval ' sub wrapi18n($$$) { Text::WrapI18N::wrap($_[0],$_[1],$_[2]) } ' + } else { + + # If we cannot wrap, well, that's too bad. Survive anyway. + eval ' sub wrapi18n($$$) { $_[0].$_[2] } ' + } +} + +sub min($$) { + return $_[0] < $_[1] ? $_[0] : $_[1]; +} + +=head1 FUNCTIONS + +=head2 Showing output messages + +=over + +=item + +show_version($) + +Shows the current version of the script, and a short copyright message. It +takes the name of the script as an argument. + +=cut + +sub show_version { + my $name = shift; + + print sprintf(gettext( + "%s version %s.\n". + "written by Martin Quinson and Denis Barbier.\n\n". + "Copyright (C) 2002, 2003, 2004 Software of Public Interest, Inc.\n". + "This is free software; see source code for copying\n". + "conditions. There is NO warranty; not even for\n". + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + ), $name, $Locale::Po4a::TransTractor::VERSION)."\n"; +} + +=item + +wrap_msg($@) + +This function displays a message the same way than sprintf() does, but wraps +the result so that they look nice on the terminal. + +=cut + +sub wrap_msg($@) { + my $msg = shift; + my @args = @_; + + return wrapi18n("", "", sprintf($msg, @args))."\n"; +} + +=item + +wrap_mod($$@) + +This function works like wrap_msg(), but it takes a module name as the first +argument, and leaves a space at the left of the message. + +=cut + +sub wrap_mod($$@) { + my ($mod, $msg) = (shift, shift); + my @args = @_; + + $mod .= ": "; + my $spaces = " " x min(length($mod), 15); + return wrapi18n($mod, $spaces, sprintf($msg, @args))."\n"; +} + +=item + +wrap_ref_mod($$$@) + +This function works like wrap_msg(), but it takes a file:line reference as the +first argument, a module name as the second one, and leaves a space at the left +of the message. + +=back + +=cut + +sub wrap_ref_mod($$$@) { + my ($ref, $mod, $msg) = (shift, shift, shift); + my @args = @_; + + if (!$mod) { + # If we don't get a module name, show the message like wrap_mod does + return wrap_mod($ref, $msg, @args); + } else { + $ref .= ": "; + my $spaces = " " x min(length($ref), 15); + $msg = "$ref($mod)\n$msg"; + return wrapi18n("", $spaces, sprintf($msg, @args))."\n"; + } +} + +=head2 Wrappers for other modules + +=over + +=item + +Locale::Gettext + +When the Locale::Gettext module cannot be loaded, this module provide dummy +(empty) implementation of the following functions. In that case, po4a +messages won't get translated but the program will continue to work. + +If Locale::gettext is present, this wrapper also calls +setlocale(LC_MESSAGES, "") so callers don't depend on the POSIX module +either. + +=over + +=item + +bindtextdomain($$) + +=item + +textdomain($) + +=item + +gettext($) + +=item + +dgettext($$) + +=back + +=back + +=cut + +BEGIN { + if (eval { require Locale::gettext }) { + import Locale::gettext; + require POSIX; + POSIX::setlocale(&POSIX::LC_MESSAGES, ''); + } else { + eval ' + sub bindtextdomain($$) { } + sub textdomain($) { } + sub gettext($) { shift } + sub dgettext($$) { return $_[1] } + ' + } +} + +1; +__END__ + +=head1 AUTHORS + + Jordi Vilalta + +=head1 COPYRIGHT AND LICENSE + +Copyright 2005 by SPI, inc. + +This program is free software; you may redistribute it and/or modify it +under the terms of GPL (see the COPYING file). + +=cut diff -r 9e8e5292acaa -r 1c13ed2130a7 tools/po4a/lib/Locale/Po4a/Docbook.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/po4a/lib/Locale/Po4a/Docbook.pm Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,2040 @@ +#!/usr/bin/perl +# aptitude: cmdsynopsis => missing removal of leading spaces + +# Po4a::Docbook.pm +# +# extract and translate translatable strings from Docbook XML documents. +# +# This code extracts plain text from tags and attributes on Docbook XML +# documents. +# +# Copyright (c) 2004 by Jordi Vilalta +# Copyright (c) 2007-2009 by Nicolas François +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +######################################################################## + +=head1 NAME + +Locale::Po4a::Docbook - Convert Docbook XML documents from/to PO files + +=head1 DESCRIPTION + +The po4a (po for anything) project goal is to ease translations (and more +interestingly, the maintenance of translations) using gettext tools on +areas where they were not expected like documentation. + +Locale::Po4a::Docbook is a module to help the translation of DocBook XML +documents into other [human] languages. + +Please note that this module is still under heavy development, and not +distributed in official po4a release since we don't feel it to be mature +enough. If you insist on trying, check the CVS out. + +=head1 STATUS OF THIS MODULE + +This module is fully functional, as it relies in the L +module. This only defines the translatable tags and attributes. + +The only known issue is that it doesn't handle entities yet, and this includes +the file inclusion entities, but you can translate most of those files alone +(except the typical entities files), and it's usually better to maintain them +separated. + +=head1 SEE ALSO + +L, L, L. + +=head1 AUTHORS + + Jordi Vilalta + +=head1 COPYRIGHT AND LICENSE + + Copyright (c) 2004 by Jordi Vilalta + Copyright (c) 2007-2009 by Nicolas François + +This program is free software; you may redistribute it and/or modify it +under the terms of GPL (see the COPYING file). + +=cut + +package Locale::Po4a::Docbook; + +use 5.006; +use strict; +use warnings; + +use Locale::Po4a::Xml; + +use vars qw(@ISA); +@ISA = qw(Locale::Po4a::Xml); + +sub initialize { + my $self = shift; + my %options = @_; + + $self->SUPER::initialize(%options); + $self->{options}{'wrap'}=1; + $self->{options}{'doctype'}=$self->{options}{'doctype'} || 'docbook xml'; + +# AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + + # abbrev; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # abstract; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # accel; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # ackno; does not contain text; Formatted as a displayed block + # Replaced by acknowledgements in Docbook v5.0 + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + # acknowledgements; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # acronym; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # action; contains text; Formatted inline; v4, not in v5 + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # address; contains text; Formatted as a displayed block; verbatim + $self->{options}{'_default_translated'} .= " W
"; + $self->{options}{'_default_placeholder'} .= "
"; + + # affiliation; does not contain text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # alt; contains text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # anchor; does not contain text; Produces no output + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # annotation; does not contain text; + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_placeholder'} .= " "; + + # answer; does not contain text; + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # appendix; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # appendixinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_placeholder'} .= " "; + + # application; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # arc; does not contain text; + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # area; does not contain text; + # NOTE: the area is not translatable as is, but the coords + # attribute might be. + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # areaset; does not contain text; + # NOTE: the areaset is not translatable as is. depending on the + # language there might be more or less area tags inside. + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # areaspec; does not contain text; + # NOTE: see area and areaset + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # arg; contains text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # artheader; does not contain text; renamed to articleinfo in v4.0 + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_placeholder'} .= " "; + + # article; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= "
"; + $self->{options}{'_default_break'} .= "
"; + + # articleinfo; does not contain text; v4 only + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_placeholder'} .= " "; + + # artpagenums; contains text; Formatted inline + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # attribution; contains text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # audiodata; does not contain text; + # NOTE: the attributes might be translated + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_placeholder'} .= " "; + $self->{options}{'_default_attributes'}.=' fileref'; + + # audioobject; does not contain text; + # NOTE: might be contaioned in a inlinemediaobject + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_placeholder'} .= " "; + + # author; does not contain text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # authorblurb; does not contain text; Formatted as a displayed block. + # v4, not in v5 + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_placeholder'} .= " "; + + # authorgroup; does not contain text; Formatted inline or as a + # displayed block depending on context + # NOTE: given the possible parents, it is probably very rarely + # inlined + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # authorinitials; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + +# BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB + + # beginpage; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # bibliocoverage; contains text; Formatted inline + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # bibliodiv; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # biblioentry; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # bibliography; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # bibliographyinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_placeholder'} .= " "; + + # biblioid; contains text; Formatted inline + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # bibliolist; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " "; + $self->{options}{'_default_break'} .= " "; + + # bibliomisc; contains text; Formatted inline + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_inline'} .= " "; + + # bibliomixed; contains text; Formatted as a displayed block + $self->{options}{'_default_translated'} .= " "; + $self->{options}{'_default_placeholder'} .= " "; + + # bibliomset; contains text; Formatted as a displayed block + # NOTE: content might need to be inlined, e.g. + $self->{options}{'_default_translated'} .= " <bibliomset>"; + $self->{options}{'_default_placeholder'} .= " <bibliomset>"; + + # biblioref; does not contain text; Formatted inline + $self->{options}{'_default_untranslated'} .= " <biblioref>"; + $self->{options}{'_default_inline'} .= " <biblioref>"; + + # bibliorelation; does not contain text; Formatted inline + $self->{options}{'_default_translated'} .= " <bibliorelation>"; + $self->{options}{'_default_inline'} .= " <bibliorelation>"; + + # biblioset; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <biblioset>"; + $self->{options}{'_default_break'} .= " <biblioset>"; + + # bibliosource; contains text; Formatted inline + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " <bibliosource>"; + $self->{options}{'_default_inline'} .= " <bibliosource>"; + + # blockinfo; does not contain text; v4.2, not in v5 + $self->{options}{'_default_untranslated'} .= " <blockinfo>"; + $self->{options}{'_default_placeholder'} .= " <blockinfo>"; + + # blockquote; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <blockquote>"; + $self->{options}{'_default_break'} .= " <blockquote>"; + + # book; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <book>"; + $self->{options}{'_default_break'} .= " <book>"; + + # bookbiblio; does not contain text; Formatted as a displayed block + # Removed in v4.0 + $self->{options}{'_default_untranslated'} .= " <bookbiblio>"; + $self->{options}{'_default_break'} .= " <bookbiblio>"; + + # bookinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <bookinfo>"; + $self->{options}{'_default_placeholder'} .= " <bookinfo>"; + + # bridgehead; contains text; Formatted as a displayed block + $self->{options}{'_default_translated'} .= " <bridgehead>"; + $self->{options}{'_default_break'} .= " <bridgehead>"; + +# CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC + + # callout; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <callout>"; + $self->{options}{'_default_break'} .= " <callout>"; + + # calloutlist; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <calloutlist>"; + $self->{options}{'_default_break'} .= " <calloutlist>"; + + # caption; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <caption>"; + $self->{options}{'_default_break'} .= " <caption>"; + + # caption (db.html.caption); contains text; Formatted as a displayed block + # TODO: Check if this works + $self->{options}{'_default_translated'} .= " <table><caption>"; + $self->{options}{'_default_break'} .= " <table><caption>"; + + # caution; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <caution>"; + $self->{options}{'_default_break'} .= " <caution>"; + + # chapter; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <chapter>"; + $self->{options}{'_default_break'} .= " <chapter>"; + + # chapterinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <chapterinfo>"; + $self->{options}{'_default_placeholder'} .= " <chapterinfo>"; + + # citation; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <citation>"; + $self->{options}{'_default_inline'} .= " <citation>"; + + # citebiblioid; contains text; Formatted inline + # NOTE: maybe untranslated? + $self->{options}{'_default_translated'} .= " <citebiblioid>"; + $self->{options}{'_default_inline'} .= " <citebiblioid>"; + + # citerefentry; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <citerefentry>"; + $self->{options}{'_default_inline'} .= " <citerefentry>"; + + # citetitle; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <citetitle>"; + $self->{options}{'_default_inline'} .= " <citetitle>"; + + # city; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <city>"; + $self->{options}{'_default_inline'} .= " <city>"; + + # classname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <classname>"; + $self->{options}{'_default_inline'} .= " <classname>"; + + # classsynopsis; does not contain text; may be in a para + # NOTE: It may contain a classsynopsisinfo, which should be + # verbatim + # XXX: since it is in untranslated class, does the W flag takes + # effect? + $self->{options}{'_default_untranslated'} .= " W<classsynopsis>"; + $self->{options}{'_default_placeholder'} .= " <classsynopsis>"; + + # classsynopsisinfo; contains text; + # NOTE: see above + $self->{options}{'_default_translated'} .= " W<classsynopsisinfo>"; + $self->{options}{'_default_inline'} .= " <classsynopsisinfo>"; + + # cmdsynopsis; does not contain text; may be in a para + # NOTE: It may be clearer as a verbatim block + # XXX: since it is in untranslated class, does the W flag takes + # effect? => not completely. Rewrap afterward? + $self->{options}{'_default_untranslated'} .= " W<cmdsynopsis>"; + $self->{options}{'_default_placeholder'} .= " <cmdsynopsis>"; + + # co; does not contain text; Formatted inline + # XXX: tranlsated or not? (label attribute) + $self->{options}{'_default_translated'} .= " <co>"; + $self->{options}{'_default_inline'} .= " <co>"; + + # code; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <code>"; + $self->{options}{'_default_inline'} .= " <code>"; + + # col; does not contain text; + # NOTE: could be translated to change the layout in a translation + # To be done on colgroup in that case. + $self->{options}{'_default_untranslated'} .= " <col>"; + $self->{options}{'_default_break'} .= " <col>"; + + # colgroup; does not contain text; + # NOTE: could be translated to change the layout in a translation + $self->{options}{'_default_untranslated'} .= " <colgroup>"; + $self->{options}{'_default_break'} .= " <colgroup>"; + + # collab; does not contain text; Formatted inline or as a + # displayed block depending on context + # NOTE: could be in the break class + $self->{options}{'_default_untranslated'} .= " <collab>"; + $self->{options}{'_default_inline'} .= " <collab>"; + + # collabname; contains text; Formatted inline or as a + # displayed block depending on context; v4, not in v5 + $self->{options}{'_default_translated'} .= " <collabname>"; + $self->{options}{'_default_inline'} .= " <collabname>"; + + # colophon; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <colophon>"; + $self->{options}{'_default_break'} .= " <colophon>"; + + # colspec; does not contain text; + # NOTE: could be translated to change the layout in a translation + $self->{options}{'_default_untranslated'} .= " <colspec>"; + $self->{options}{'_default_break'} .= " <colspec>"; + + # command; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <command>"; + $self->{options}{'_default_inline'} .= " <command>"; + + # comment; contains text; Formatted inline or as a displayed block + # Renamed to remark in v4.0 + $self->{options}{'_default_translated'} .= " <comment>"; + $self->{options}{'_default_inline'} .= " <comment>"; + + # computeroutput; contains text; Formatted inline + # NOTE: "is not a verbatim environment, but an inline." + $self->{options}{'_default_translated'} .= " <computeroutput>"; + $self->{options}{'_default_inline'} .= " <computeroutput>"; + + # confdates; contains text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_translated'} .= " <confdates>"; + $self->{options}{'_default_inline'} .= " <confdates>"; + + # confgroup; does not contain text; Formatted inline or as a + # displayed block depending on context + # NOTE: could be in the break class + $self->{options}{'_default_untranslated'} .= " <confgroup>"; + $self->{options}{'_default_inline'} .= " <confgroup>"; + + # confnum; contains text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_translated'} .= " <confnum>"; + $self->{options}{'_default_inline'} .= " <confnum>"; + + # confsponsor; contains text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_translated'} .= " <confsponsor>"; + $self->{options}{'_default_inline'} .= " <confsponsor>"; + + # conftitle; contains text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_translated'} .= " <conftitle>"; + $self->{options}{'_default_inline'} .= " <conftitle>"; + + # constant; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <constant>"; + $self->{options}{'_default_inline'} .= " <constant>"; + + # constraint; does not contain text; + # NOTE: it might be better to have the production as verbatim + # Keeping the constrainst inline to have it close to the + # lhs or rhs. + # The attribute is translatable + $self->{options}{'_default_untranslated'} .= " <constraint>"; + $self->{options}{'_default_break'} .= " <constraint>"; + + # constraintdef; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <constraintdef>"; + $self->{options}{'_default_break'} .= " <constraintdef>"; + + # constructorsynopsis; does not contain text; may be in a para + # NOTE: It may be clearer as a verbatim block + # XXX: since it is in untranslated class, does the W flag takes + # effect? + $self->{options}{'_default_untranslated'} .= " W<constructorsynopsis>"; + $self->{options}{'_default_placeholder'} .= " <constructorsynopsis>"; + + # contractnum; contains text; Formatted inline or as a displayed block + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " <contractnum>"; + $self->{options}{'_default_inline'} .= " <contractnum>"; + + # contractsponsor; contains text; Formatted inline or as a displayed block + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " <contractsponsor>"; + $self->{options}{'_default_inline'} .= " <contractsponsor>"; + + # contrib; contains text; Formatted inline or as a displayed block + $self->{options}{'_default_translated'} .= " <contrib>"; + $self->{options}{'_default_inline'} .= " <contrib>"; + + # copyright; contains text; Formatted inline or as a displayed block + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " <copyright>"; + $self->{options}{'_default_inline'} .= " <copyright>"; + + # coref; does not contain text; Formatted inline + # XXX: tranlsated or not? (label attribute) + $self->{options}{'_default_translated'} .= " <coref>"; + $self->{options}{'_default_inline'} .= " <coref>"; + + # corpauthor; contains text; Formatted inline or as a + # displayed block depending on context; v4, not in v5 + $self->{options}{'_default_translated'} .= " <corpauthor>"; + $self->{options}{'_default_inline'} .= " <corpauthor>"; + + # corpcredit; contains text; Formatted inline or as a + # displayed block depending on context; v4, not in v5 + $self->{options}{'_default_translated'} .= " <corpcredit>"; + $self->{options}{'_default_inline'} .= " <corpcredit>"; + + # corpname; contains text; Formatted inline or as a + # displayed block depending on context; v4, not in v5 + $self->{options}{'_default_translated'} .= " <corpname>"; + $self->{options}{'_default_inline'} .= " <corpname>"; + + # country; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <country>"; + $self->{options}{'_default_inline'} .= " <country>"; + + # cover; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <cover>"; + $self->{options}{'_default_break'} .= " <cover>"; + +# DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD + + # database; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <database>"; + $self->{options}{'_default_inline'} .= " <database>"; + + # date; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <date>"; + $self->{options}{'_default_inline'} .= " <date>"; + + # dedication; contains text; Formatted as a displayed block + $self->{options}{'_default_translated'} .= " <dedication>"; + $self->{options}{'_default_break'} .= " <dedication>"; + + # destructorsynopsis; does not contain text; may be in a para + # NOTE: It may be clearer as a verbatim block + # XXX: since it is in untranslated class, does the W flag takes + # effect? + $self->{options}{'_default_untranslated'} .= " W<destructorsynopsis>"; + $self->{options}{'_default_placeholder'} .= " <destructorsynopsis>"; + + # docinfo; does not contain text; removed in v4.0 + $self->{options}{'_default_untranslated'} .= " <docinfo>"; + $self->{options}{'_default_placeholder'} .= " <docinfo>"; + +# EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE + + # edition; contains text; Formatted inline or as a displayed block + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " <edition>"; + $self->{options}{'_default_inline'} .= " <edition>"; + + # editor; does not contain text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_untranslated'} .= " <editor>"; + $self->{options}{'_default_inline'} .= " <editor>"; + + # email; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <email>"; + $self->{options}{'_default_inline'} .= " <email>"; + + # emphasis; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <emphasis>"; + $self->{options}{'_default_inline'} .= " <emphasis>"; + + # entry; contains text; + $self->{options}{'_default_translated'} .= " <entry>"; + $self->{options}{'_default_break'} .= " <entry>"; + + # entrytbl; does not contain text; + $self->{options}{'_default_untranslated'} .= " <entrytbl>"; + $self->{options}{'_default_break'} .= " <entrytbl>"; + + # envar; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <envar>"; + $self->{options}{'_default_inline'} .= " <envar>"; + + # epigraph; contains text; Formatted as a displayed block. + # NOTE: maybe contained in a para + $self->{options}{'_default_translated'} .= " <epigraph>"; + $self->{options}{'_default_placeholder'} .= " <epigraph>"; + + # equation; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <equation>"; + $self->{options}{'_default_break'} .= " <equation>"; + + # errorcode; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <errorcode>"; + $self->{options}{'_default_inline'} .= " <errorcode>"; + + # errorname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <errorname>"; + $self->{options}{'_default_inline'} .= " <errorname>"; + + # errortext; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <errortext>"; + $self->{options}{'_default_inline'} .= " <errortext>"; + + # errortype; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <errortype>"; + $self->{options}{'_default_inline'} .= " <errortype>"; + + # example; does not contain text; Formatted as a displayed block. + # NOTE: maybe contained in a para + $self->{options}{'_default_untranslated'} .= " <example>"; + $self->{options}{'_default_placeholder'} .= " <example>"; + + # exceptionname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <exceptionname>"; + $self->{options}{'_default_inline'} .= " <exceptionname>"; + + # extendedlink; does not contain text; + $self->{options}{'_default_untranslated'} .= " <extendedlink>"; + $self->{options}{'_default_inline'} .= " <extendedlink>"; + +# FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + # fax; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <fax>"; + $self->{options}{'_default_inline'} .= " <fax>"; + + # fieldsynopsis; does not contain text; may be in a para + $self->{options}{'_default_untranslated'} .= " <fieldsynopsis>"; + $self->{options}{'_default_inline'} .= " <fieldsynopsis>"; + + # figure; does not contain text; Formatted as a displayed block. + # NOTE: maybe contained in a para + $self->{options}{'_default_untranslated'} .= " <figure>"; + $self->{options}{'_default_placeholder'} .= " <figure>"; + + # filename; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <filename>"; + $self->{options}{'_default_inline'} .= " <filename>"; + + # firstname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <firstname>"; + $self->{options}{'_default_inline'} .= " <firstname>"; + + # firstterm; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <firstterm>"; + $self->{options}{'_default_inline'} .= " <firstterm>"; + + # footnote; contains text; + $self->{options}{'_default_translated'} .= " <footnote>"; + $self->{options}{'_default_placeholder'} .= " <footnote>"; + + # footnoteref; contains text; + $self->{options}{'_default_translated'} .= " <footnoteref>"; + $self->{options}{'_default_inline'} .= " <footnoteref>"; + + # foreignphrase; contains text; + $self->{options}{'_default_translated'} .= " <foreignphrase>"; + $self->{options}{'_default_inline'} .= " <foreignphrase>"; + + # formalpara; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <formalpara>"; + $self->{options}{'_default_break'} .= " <formalpara>"; + + # funcdef; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <funcdef>"; + $self->{options}{'_default_inline'} .= " <funcdef>"; + + # funcparams; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <funcparams>"; + $self->{options}{'_default_inline'} .= " <funcparams>"; + + # funcprototype; does not contain text; + # NOTE: maybe contained in a funcsynopsis, contained in a para + $self->{options}{'_default_untranslated'} .= " <funcprototype>"; + $self->{options}{'_default_placeholder'} .= " <funcprototype>"; + + # funcsynopsis; does not contain text; + # NOTE: maybe contained in a para + $self->{options}{'_default_untranslated'} .= " <funcsynopsis>"; + $self->{options}{'_default_placeholder'} .= " <funcsynopsis>"; + + # funcsynopsisinfo; contains text; verbatim + # NOTE: maybe contained in a funcsynopsis, contained in a para + $self->{options}{'_default_translated'} .= " W<funcsynopsisinfo>"; + $self->{options}{'_default_placeholder'} .= " <funcsynopsisinfo>"; + + # function; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <function>"; + $self->{options}{'_default_inline'} .= " <function>"; + +# GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG + + # glossary; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <glossary>"; + $self->{options}{'_default_break'} .= " <glossary>"; + + # glossaryinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <glossaryinfo>"; + $self->{options}{'_default_placeholder'} .= " <glossaryinfo>"; + + # glossdef; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <glossdef>"; + $self->{options}{'_default_break'} .= " <glossdef>"; + + # glossdiv; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <glossdiv>"; + $self->{options}{'_default_break'} .= " <glossdiv>"; + + # glossentry; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <glossentry>"; + $self->{options}{'_default_break'} .= " <glossentry>"; + + # glosslist; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <glosslist>"; + $self->{options}{'_default_break'} .= " <glosslist>"; + + # glosssee; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <glosssee>"; + $self->{options}{'_default_break'} .= " <glosssee>"; + + # glossseealso; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <glossseealso>"; + $self->{options}{'_default_break'} .= " <glossseealso>"; + + # glossterm; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <glossterm>"; + $self->{options}{'_default_inline'} .= " <glossterm>"; + + # graphic; does not contain text; Formatted as a displayed block + # v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <graphic>"; + $self->{options}{'_default_inline'} .= " <graphic>"; + $self->{options}{'_default_attributes'}.=' <graphic>fileref'; + + # graphicco; does not contain text; Formatted as a displayed block. + # v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <graphicco>"; + $self->{options}{'_default_placeholder'} .= " <graphicco>"; + + # group; does not contain text; Formatted inline + $self->{options}{'_default_untranslated'} .= " W<group>"; + $self->{options}{'_default_inline'} .= " <group>"; + + # guibutton; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <guibutton>"; + $self->{options}{'_default_inline'} .= " <guibutton>"; + + # guiicon; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <guiicon>"; + $self->{options}{'_default_inline'} .= " <guiicon>"; + + # guilabel; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <guilabel>"; + $self->{options}{'_default_inline'} .= " <guilabel>"; + + # guimenu; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <guimenu>"; + $self->{options}{'_default_inline'} .= " <guimenu>"; + + # guimenuitem; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <guimenuitem>"; + $self->{options}{'_default_inline'} .= " <guimenuitem>"; + + # guisubmenu; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <guisubmenu>"; + $self->{options}{'_default_inline'} .= " <guisubmenu>"; + +# HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + + # hardware; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <hardware>"; + $self->{options}{'_default_inline'} .= " <hardware>"; + + # highlights; does not contain text; Formatted inline + # v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <highlights>"; + $self->{options}{'_default_break'} .= " <highlights>"; + + # holder; contains text; + # NOTE: may depend on the copyright container + $self->{options}{'_default_translated'} .= " <holder>"; + $self->{options}{'_default_inline'} .= " <holder>"; + + # honorific; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <honorific>"; + $self->{options}{'_default_inline'} .= " <honorific>"; + + # html:button; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <html:button>"; + $self->{options}{'_default_inline'} .= " <html:button>"; + + # html:fieldset; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <html:fieldset>"; + $self->{options}{'_default_inline'} .= " <html:fieldset>"; + + # html:form; does not contain text; + $self->{options}{'_default_translated'} .= " <html:form>"; + $self->{options}{'_default_inline'} .= " <html:form>"; + + # html:input; does not contain text; Formatted inline + # NOTE: attributes are translatable + $self->{options}{'_default_translated'} .= " <html:input>"; + $self->{options}{'_default_inline'} .= " <html:input>"; + + # html:label; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <html:label>"; + $self->{options}{'_default_inline'} .= " <html:label>"; + + # html:legend; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <html:legend>"; + $self->{options}{'_default_inline'} .= " <html:legend>"; + + # html:option; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <html:option>"; + $self->{options}{'_default_inline'} .= " <html:option>"; + + # html:select; does not contain text; Formatted inline + $self->{options}{'_default_translated'} .= " <html:select>"; + $self->{options}{'_default_inline'} .= " <html:select>"; + + # html:textarea; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <html:textarea>"; + $self->{options}{'_default_placeholder'} .= " <html:textarea>"; + + # imagedata; does not contain text; May be formatted inline or + # as a displayed block, depending on context + $self->{options}{'_default_translated'} .= " <imagedata>"; + $self->{options}{'_default_inline'} .= " <imagedata>"; + $self->{options}{'_default_attributes'}.=' <imagedata>fileref'; + + # imageobject; does not contain text; May be formatted inline or + # as a displayed block, depending on context + $self->{options}{'_default_untranslated'} .= " <imageobject>"; + $self->{options}{'_default_inline'} .= " <imageobject>"; + + # imageobjectco; does not contain text; Formatted as a displayed block + # NOTE: may be in a inlinemediaobject + # TODO: check if this works when the inlinemediaobject is defined + # as inline + $self->{options}{'_default_untranslated'} .= " <imageobjectco>"; + $self->{options}{'_default_break'} .= " <imageobjectco>"; + + # important; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <important>"; + $self->{options}{'_default_break'} .= " <important>"; + + # index; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <index>"; + $self->{options}{'_default_break'} .= " <index>"; + + # indexdiv; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <indexdiv>"; + $self->{options}{'_default_break'} .= " <indexdiv>"; + + # indexentry; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <indexentry>"; + $self->{options}{'_default_break'} .= " <indexentry>"; + + # indexinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <indexinfo>"; + $self->{options}{'_default_placeholder'} .= " <indexinfo>"; + + # indexterm; does not contain text; + $self->{options}{'_default_untranslated'} .= " <indexterm>"; + $self->{options}{'_default_placeholder'} .= " <indexterm>"; + + # info; does not contain text; + $self->{options}{'_default_untranslated'} .= " <info>"; + $self->{options}{'_default_placeholder'} .= " <info>"; + + # informalequation; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <informalequation>"; + $self->{options}{'_default_placeholder'} .= " <informalequation>"; + + # informalexample; does not contain text; Formatted as a displayed block. + # NOTE: can be in a para + $self->{options}{'_default_untranslated'} .= " <informalexample>"; + $self->{options}{'_default_break'} .= " <informalexample>"; + + # informalfigure; does not contain text; Formatted as a displayed block. + # NOTE: can be in a para + $self->{options}{'_default_untranslated'} .= " <informalfigure>"; + $self->{options}{'_default_break'} .= " <informalfigure>"; + + # informaltable; does not contain text; Formatted as a displayed block. + # NOTE: can be in a para + $self->{options}{'_default_untranslated'} .= " <informaltable>"; + $self->{options}{'_default_break'} .= " <informaltable>"; + + # initializer; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <initializer>"; + $self->{options}{'_default_inline'} .= " <initializer>"; + + # inlineequation; does not contain text; Formatted inline + $self->{options}{'_default_translated'} .= " W<inlineequation>"; + $self->{options}{'_default_placeholder'} .= " <inlineequation>"; + + # inlinegraphic; does not contain text; Formatted inline + # empty; v4, not in v5 + $self->{options}{'_default_translated'} .= " W<inlinegraphic>"; + $self->{options}{'_default_inline'} .= " <inlinegraphic>"; + + # inlinemediaobject; does not contain text; Formatted inline + $self->{options}{'_default_translated'} .= " <inlinemediaobject>"; + $self->{options}{'_default_placeholder'} .= " <inlinemediaobject>"; + + # interface; contains text; Formatted inline; v4, not in v5 + $self->{options}{'_default_translated'} .= " <interface>"; + $self->{options}{'_default_inline'} .= " <interface>"; + + # interfacedefinition; contains text; Formatted inline + # Removed in v4.0 + $self->{options}{'_default_translated'} .= " <interfacedefinition>"; + $self->{options}{'_default_inline'} .= " <interfacedefinition>"; + + # interfacename; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <interfacename>"; + $self->{options}{'_default_inline'} .= " <interfacename>"; + + # invpartnumber; contains text; Formatted inline; v4, not in v5 + $self->{options}{'_default_translated'} .= " <invpartnumber>"; + $self->{options}{'_default_inline'} .= " <invpartnumber>"; + + # isbn; contains text; Formatted inline; v4, not in v5 + $self->{options}{'_default_translated'} .= " <isbn>"; + $self->{options}{'_default_inline'} .= " <isbn>"; + + # issn; contains text; Formatted inline; v4, not in v5 + $self->{options}{'_default_translated'} .= " <issn>"; + $self->{options}{'_default_inline'} .= " <issn>"; + + # issuenum; contains text; Formatted inline or as a displayed block + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " <issuenum>"; + $self->{options}{'_default_inline'} .= " <issuenum>"; + + # itemizedlist; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <itemizedlist>"; + $self->{options}{'_default_break'} .= " <itemizedlist>"; + + # itermset; does not contain text; + # FIXME + $self->{options}{'_default_untranslated'} .= " <itermset>"; + $self->{options}{'_default_inline'} .= " <itermset>"; + +# JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ + + # jobtitle; contains text; Formatted inline or as a displayed block + # NOTE: can be in a para + $self->{options}{'_default_translated'} .= " <jobtitle>"; + $self->{options}{'_default_inline'} .= " <jobtitle>"; + +# KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK + + # keycap; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <keycap>"; + $self->{options}{'_default_inline'} .= " <keycap>"; + + # keycode; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <keycode>"; + $self->{options}{'_default_inline'} .= " <keycode>"; + + # keycombo; does not contain text; Formatted inline + $self->{options}{'_default_translated'} .= " <keycombo>"; + $self->{options}{'_default_inline'} .= " <keycombo>"; + + # keysym; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <keysym>"; + $self->{options}{'_default_inline'} .= " <keysym>"; + + # keyword; contains text; + # NOTE: could be inline + $self->{options}{'_default_translated'} .= " <keyword>"; + $self->{options}{'_default_break'} .= " <keyword>"; + + # keywordset; contains text; Formatted inline or as a displayed block + # NOTE: could be placeholder/break + $self->{options}{'_default_translated'} .= " <keywordset>"; + $self->{options}{'_default_break'} .= " <keywordset>"; + +# LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL + + # label; contains text; Formatted as a displayed block + $self->{options}{'_default_translated'} .= " <label>"; + $self->{options}{'_default_break'} .= " <label>"; + + # legalnotice; contains text; Formatted as a displayed block + $self->{options}{'_default_translated'} .= " <legalnotice>"; + $self->{options}{'_default_break'} .= " <legalnotice>"; + + # lhs; contains text; Formatted as a displayed block. + # NOTE: it might be better to have the production as verbatim + # Keeping the constrainst inline to have it close to the + # lhs or rhs. + $self->{options}{'_default_translated'} .= " <lhs>"; + $self->{options}{'_default_break'} .= " <lhs>"; + + # lineage; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <lineage>"; + $self->{options}{'_default_inline'} .= " <lineage>"; + + # lineannotation; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <lineannotation>"; + $self->{options}{'_default_inline'} .= " <lineannotation>"; + + # link; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <link>"; + $self->{options}{'_default_inline'} .= " <link>"; + + # listitem; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <listitem>"; + $self->{options}{'_default_break'} .= " <listitem>"; + + # literal; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <literal>"; + $self->{options}{'_default_inline'} .= " <literal>"; + + # literallayout; contains text; verbatim + $self->{options}{'_default_translated'} .= " W<literallayout>"; + $self->{options}{'_default_placeholder'} .= " <literallayout>"; + + # locator; does not contain text; + $self->{options}{'_default_untranslated'} .= " <locator>"; + $self->{options}{'_default_inline'} .= " <locator>"; + + # lot; does not contain text; Formatted as a displayed block. + # v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <lot>"; + $self->{options}{'_default_break'} .= " <lot>"; + + # lotentry; contains text; Formatted as a displayed block. + # v4, not in v5 + $self->{options}{'_default_translated'} .= " <lotentry>"; + $self->{options}{'_default_break'} .= " <lotentry>"; + +# MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM + + # manvolnum; contains text; + $self->{options}{'_default_translated'} .= " <manvolnum>"; + $self->{options}{'_default_inline'} .= " <manvolnum>"; + + # markup; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <markup>"; + $self->{options}{'_default_inline'} .= " <markup>"; + + # mathphrase; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <mathphrase>"; + $self->{options}{'_default_inline'} .= " <mathphrase>"; + + # medialabel; contains text; Formatted inline + # v4, not in v5 + $self->{options}{'_default_translated'} .= " <medialabel>"; + $self->{options}{'_default_inline'} .= " <medialabel>"; + + # mediaobject; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <mediaobject>"; + $self->{options}{'_default_placeholder'} .= " <mediaobject>"; + + # mediaobjectco; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <mediaobjectco>"; + $self->{options}{'_default_placeholder'} .= " <mediaobjectco>"; + + # member; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <member>"; + $self->{options}{'_default_inline'} .= " <member>"; + + # menuchoice; does not contain text; Formatted inline + $self->{options}{'_default_translated'} .= " <menuchoice>"; + $self->{options}{'_default_inline'} .= " <menuchoice>"; + + # methodname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <methodname>"; + $self->{options}{'_default_inline'} .= " <methodname>"; + + # methodparam; does not contain text; Formatted inline + $self->{options}{'_default_translated'} .= " <methodparam>"; + $self->{options}{'_default_inline'} .= " <methodparam>"; + + # methodsynopsis; does not contain text; Formatted inline + $self->{options}{'_default_translated'} .= " <methodsynopsis>"; + $self->{options}{'_default_inline'} .= " <methodsynopsis>"; + + # modifier; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <modifier>"; + $self->{options}{'_default_inline'} .= " <modifier>"; + + # mousebutton; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <mousebutton>"; + $self->{options}{'_default_inline'} .= " <mousebutton>"; + + # msg; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <msg>"; + $self->{options}{'_default_break'} .= " <msg>"; + + # msgaud; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <msgaud>"; + $self->{options}{'_default_break'} .= " <msgaud>"; + + # msgentry; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <msgentry>"; + $self->{options}{'_default_break'} .= " <msgentry>"; + + # msgexplan; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <msgexplan>"; + $self->{options}{'_default_break'} .= " <msgexplan>"; + + # msginfo; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <msginfo>"; + $self->{options}{'_default_break'} .= " <msginfo>"; + + # msglevel; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <msglevel>"; + $self->{options}{'_default_break'} .= " <msglevel>"; + + # msgmain; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <msgmain>"; + $self->{options}{'_default_break'} .= " <msgmain>"; + + # msgorig; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <msgorig>"; + $self->{options}{'_default_break'} .= " <msgorig>"; + + # msgrel; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <msgrel>"; + $self->{options}{'_default_break'} .= " <msgrel>"; + + # msgset; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <msgset>"; + $self->{options}{'_default_placeholder'} .= " <msgset>"; + + # msgsub; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <msgsub>"; + $self->{options}{'_default_break'} .= " <msgsub>"; + + # msgtext; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <msgtext>"; + $self->{options}{'_default_break'} .= " <msgtext>"; + +# NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN + + # nonterminal; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <nonterminal>"; + $self->{options}{'_default_inline'} .= " <nonterminal>"; + + # note; does not contain text; Formatted inline + # NOTE: can be in a para + $self->{options}{'_default_untranslated'} .= " <note>"; + $self->{options}{'_default_inline'} .= " <note>"; + +# OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO + + # objectinfo; does not contain text; v3.1 -> v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <objectinfo>"; + $self->{options}{'_default_placeholder'} .= " <objectinfo>"; + + # olink; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <olink>"; + $self->{options}{'_default_inline'} .= " <olink>"; + + # ooclass; does not contain text; Formatted inline + $self->{options}{'_default_translated'} .= " <ooclass>"; + $self->{options}{'_default_inline'} .= " <ooclass>"; + + # ooexception; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <ooexception>"; + $self->{options}{'_default_inline'} .= " <ooexception>"; + + # oointerface; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <oointerface>"; + $self->{options}{'_default_inline'} .= " <oointerface>"; + + # option; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <option>"; + $self->{options}{'_default_inline'} .= " <option>"; + + # optional; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <optional>"; + $self->{options}{'_default_inline'} .= " <optional>"; + + # orderedlist; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <orderedlist>"; + $self->{options}{'_default_placeholder'} .= " <orderedlist>"; + + # org; does not contain text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_untranslated'} .= " <org>"; + $self->{options}{'_default_inline'} .= " <org>"; + + # orgdiv; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <orgdiv>"; + $self->{options}{'_default_inline'} .= " <orgdiv>"; + + # orgname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <orgname>"; + $self->{options}{'_default_inline'} .= " <orgname>"; + + # otheraddr; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <otheraddr>"; + $self->{options}{'_default_inline'} .= " <otheraddr>"; + + # othercredit; does not contain text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_untranslated'} .= " <othercredit>"; + $self->{options}{'_default_inline'} .= " <othercredit>"; + + # othername; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <othername>"; + $self->{options}{'_default_inline'} .= " <othername>"; + +# PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP + + # package; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <package>"; + $self->{options}{'_default_inline'} .= " <package>"; + + # pagenums; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <pagenums>"; + $self->{options}{'_default_inline'} .= " <pagenums>"; + + # para; contains text; Formatted as a displayed block + $self->{options}{'_default_translated'} .= " <para>"; + $self->{options}{'_default_break'} .= " <para>"; + + # paramdef; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <paramdef>"; + $self->{options}{'_default_inline'} .= " <paramdef>"; + + # parameter; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <parameter>"; + $self->{options}{'_default_inline'} .= " <parameter>"; + + # part; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <part>"; + $self->{options}{'_default_break'} .= " <part>"; + + # partinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <partinfo>"; + $self->{options}{'_default_placeholder'} .= " <partinfo>"; + + # partintro; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <partintro>"; + $self->{options}{'_default_break'} .= " <partintro>"; + + # person; does not contain text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_untranslated'} .= " <person>"; + $self->{options}{'_default_inline'} .= " <person>"; + + # personblurb; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <personblurb>"; + $self->{options}{'_default_placeholder'} .= " <personblurb>"; + + # personname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <personname>"; + $self->{options}{'_default_inline'} .= " <personname>"; + + # phone; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <phone>"; + $self->{options}{'_default_inline'} .= " <phone>"; + + # phrase; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <phrase>"; + $self->{options}{'_default_inline'} .= " <phrase>"; + + # pob; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <pob>"; + $self->{options}{'_default_inline'} .= " <pob>"; + + # postcode; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <postcode>"; + $self->{options}{'_default_inline'} .= " <postcode>"; + + # preface; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <preface>"; + $self->{options}{'_default_break'} .= " <preface>"; + + # prefaceinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <prefaceinfo>"; + $self->{options}{'_default_placeholder'} .= " <prefaceinfo>"; + + # primary; contains text; + $self->{options}{'_default_translated'} .= " <primary>"; + $self->{options}{'_default_break'} .= " <primary>"; + + # primaryie; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <primaryie>"; + $self->{options}{'_default_break'} .= " <primaryie>"; + + # printhistory; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <printhistory>"; + $self->{options}{'_default_break'} .= " <printhistory>"; + + # procedure; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <procedure>"; + $self->{options}{'_default_placeholder'} .= " <procedure>"; + + # production; doesnot contain text; + # NOTE: it might be better to have the production as verbatim + # Keeping the constrainst inline to have it close to the + # lhs or rhs. + $self->{options}{'_default_untranslated'} .= " <production>"; + $self->{options}{'_default_break'} .= " <production>"; + + # productionrecap; does not contain text; like production + $self->{options}{'_default_untranslated'} .= " <productionrecap>"; + $self->{options}{'_default_break'} .= " <productionrecap>"; + + # productionset; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <productionset>"; + $self->{options}{'_default_placeholder'} .= " <productionset>"; + + # productname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <productname>"; + $self->{options}{'_default_inline'} .= " <productname>"; + + # productnumber; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <productnumber>"; + $self->{options}{'_default_inline'} .= " <productnumber>"; + + # programlisting; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " W<programlisting>"; + $self->{options}{'_default_placeholder'} .= " <programlisting>"; + + # programlistingco; contains text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <programlistingco>"; + $self->{options}{'_default_placeholder'} .= " <programlistingco>"; + + # prompt; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <prompt>"; + $self->{options}{'_default_inline'} .= " <prompt>"; + + # property; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <property>"; + $self->{options}{'_default_inline'} .= " <property>"; + + # pubdate; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <pubdate>"; + $self->{options}{'_default_inline'} .= " <pubdate>"; + + # publisher; does not contain text; Formatted inline or as a displayed block + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " <publisher>"; + $self->{options}{'_default_inline'} .= " <publisher>"; + + # publishername; contains text; Formatted inline or as a displayed block + $self->{options}{'_default_translated'} .= " <publishername>"; + $self->{options}{'_default_inline'} .= " <publishername>"; + +# QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ + + # qandadiv; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <qandadiv>"; + $self->{options}{'_default_break'} .= " <qandadiv>"; + + # qandaentry; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <qandaentry>"; + $self->{options}{'_default_break'} .= " <qandaentry>"; + + # qandaset; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <qandaset>"; + $self->{options}{'_default_break'} .= " <qandaset>"; + + # question; does not contain text; + $self->{options}{'_default_untranslated'} .= " <question>"; + $self->{options}{'_default_break'} .= " <question>"; + + # quote; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <quote>"; + $self->{options}{'_default_inline'} .= " <quote>"; + +# RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR + + # refclass; contains text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_translated'} .= " <refclass>"; + $self->{options}{'_default_break'} .= " <refclass>"; + + # refdescriptor; contains text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_translated'} .= " <refdescriptor>"; + $self->{options}{'_default_break'} .= " <refdescriptor>"; + + # refentry; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <refentry>"; + $self->{options}{'_default_break'} .= " <refentry>"; + + # refentryinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <refentryinfo>"; + $self->{options}{'_default_placeholder'} .= " <refentryinfo>"; + + # refentrytitle; contains text; Formatted as a displayed block +# FIXME: do not seems to be a block + $self->{options}{'_default_translated'} .= " <refentrytitle>"; + $self->{options}{'_default_inline'} .= " <refentrytitle>"; + + # reference; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <reference>"; + $self->{options}{'_default_break'} .= " <reference>"; + + # referenceinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <referenceinfo>"; + $self->{options}{'_default_placeholder'} .= " <referenceinfo>"; + + # refmeta; does not contains text; + # NOTE: could be in the inline class + $self->{options}{'_default_untranslated'} .= " <refmeta>"; + $self->{options}{'_default_break'} .= " <refmeta>"; + + # refmiscinfo; contains text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_translated'} .= " <refmiscinfo>"; + $self->{options}{'_default_break'} .= " <refmiscinfo>"; + + # refname; contains text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_translated'} .= " <refname>"; + $self->{options}{'_default_break'} .= " <refname>"; + + # refnamediv; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <refnamediv>"; + $self->{options}{'_default_break'} .= " <refnamediv>"; + + # refpurpose; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <refpurpose>"; + $self->{options}{'_default_inline'} .= " <refpurpose>"; + + # refsect1; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <refsect1>"; + $self->{options}{'_default_break'} .= " <refsect1>"; + + # refsect1info; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <refsect1info>"; + $self->{options}{'_default_placeholder'} .= " <refsect1info>"; + + # refsect2; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <refsect2>"; + $self->{options}{'_default_break'} .= " <refsect2>"; + + # refsect2info; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <refsect2info>"; + $self->{options}{'_default_placeholder'} .= " <refsect2info>"; + + # refsect3; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <refsect3>"; + $self->{options}{'_default_break'} .= " <refsect3>"; + + # refsect3info; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <refsect3info>"; + $self->{options}{'_default_placeholder'} .= " <refsect3info>"; + + # refsection; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <refsection>"; + $self->{options}{'_default_break'} .= " <refsection>"; + + # refsectioninfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <refsectioninfo>"; + $self->{options}{'_default_placeholder'} .= " <refsectioninfo>"; + + # refsynopsisdiv; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <refsynopsisdiv>"; + $self->{options}{'_default_break'} .= " <refsynopsisdiv>"; + + # refsynopsisdivinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <refsynopsisdivinfo>"; + $self->{options}{'_default_placeholder'} .= " <refsynopsisdivinfo>"; + + # releaseinfo; contains text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_translated'} .= " <releaseinfo>"; + $self->{options}{'_default_break'} .= " <releaseinfo>"; + + # remark; contains text; Formatted inline or as a displayed block + $self->{options}{'_default_translated'} .= " <remark>"; + $self->{options}{'_default_inline'} .= " <remark>"; + + # replaceable; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <replaceable>"; + $self->{options}{'_default_inline'} .= " <replaceable>"; + + # returnvalue; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <returnvalue>"; + $self->{options}{'_default_inline'} .= " <returnvalue>"; + + # revdescription; contains text; Formatted inline or as a displayed block + $self->{options}{'_default_translated'} .= " <revdescription>"; + $self->{options}{'_default_break'} .= " <revdescription>"; + + # revhistory; does not contain text; Formatted as a displayed block + $self->{options}{'_default_untranslated'} .= " <revhistory>"; + $self->{options}{'_default_break'} .= " <revhistory>"; + + # revision; does not contain text; + $self->{options}{'_default_untranslated'} .= " <revision>"; + $self->{options}{'_default_break'} .= " <revision>"; + + # revnumber; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <revnumber>"; + $self->{options}{'_default_inline'} .= " <revnumber>"; + + # revremark; contains text; Formatted inline or as a displayed block + $self->{options}{'_default_translated'} .= " <revremark>"; + $self->{options}{'_default_break'} .= " <revremark>"; + + # rhs; contains text; Formatted as a displayed block. + # NOTE: it might be better to have the production as verbatim + # Keeping the constrainst inline to have it close to the + # lhs or rhs. + $self->{options}{'_default_translated'} .= " <rhs>"; + $self->{options}{'_default_break'} .= " <rhs>"; + + # row; does not contain text; + $self->{options}{'_default_untranslated'} .= " <row>"; + $self->{options}{'_default_break'} .= " <row>"; + +# SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS + + # sbr; does not contain text; line break + $self->{options}{'_default_untranslated'} .= " <sbr>"; + $self->{options}{'_default_break'} .= " <sbr>"; + + # screen; contains text; verbatim + $self->{options}{'_default_translated'} .= " W<screen>"; + $self->{options}{'_default_placeholder'} .= " <screen>"; + + # screenco; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <screenco>"; + $self->{options}{'_default_placeholder'} .= " <screenco>"; + + # screeninfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <screeninfo>"; + $self->{options}{'_default_placeholder'} .= " <screeninfo>"; + + # screenshot; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <screenshot>"; + $self->{options}{'_default_placeholder'} .= " <screenshot>"; + + # secondary; contains text; + $self->{options}{'_default_translated'} .= " <secondary>"; + $self->{options}{'_default_break'} .= " <secondary>"; + + # secondaryie; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <secondaryie>"; + $self->{options}{'_default_break'} .= " <secondaryie>"; + + # sect1; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <sect1>"; + $self->{options}{'_default_break'} .= " <sect1>"; + + # sect1info; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <sect1info>"; + $self->{options}{'_default_placeholder'} .= " <sect1info>"; + + # sect2; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <sect2>"; + $self->{options}{'_default_break'} .= " <sect2>"; + + # sect2info; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <sect2info>"; + $self->{options}{'_default_placeholder'} .= " <sect2info>"; + + # sect3; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <sect3>"; + $self->{options}{'_default_break'} .= " <sect3>"; + + # sect3info; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <sect3info>"; + $self->{options}{'_default_placeholder'} .= " <sect3info>"; + + # sect4; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <sect4>"; + $self->{options}{'_default_break'} .= " <sect4>"; + + # sect4info; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <sect4info>"; + $self->{options}{'_default_placeholder'} .= " <sect4info>"; + + # sect5; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <sect5>"; + $self->{options}{'_default_break'} .= " <sect5>"; + + # sect5info; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <sect5info>"; + $self->{options}{'_default_placeholder'} .= " <sect5info>"; + + # section; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <section>"; + $self->{options}{'_default_break'} .= " <section>"; + + # sectioninfo; does not contain text; v3.1 -> v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <sectioninfo>"; + $self->{options}{'_default_placeholder'} .= " <sectioninfo>"; + + # see; contains text; + $self->{options}{'_default_translated'} .= " <see>"; + $self->{options}{'_default_break'} .= " <see>"; + + # seealso; contains text; + $self->{options}{'_default_translated'} .= " <seealso>"; + $self->{options}{'_default_break'} .= " <seealso>"; + + # seealsoie; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <seealsoie>"; + $self->{options}{'_default_break'} .= " <seealsoie>"; + + # seeie; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <seeie>"; + $self->{options}{'_default_break'} .= " <seeie>"; + + # seg; contains text; + $self->{options}{'_default_translated'} .= " <seg>"; + $self->{options}{'_default_break'} .= " <seg>"; + + # seglistitem; does not contain text; + $self->{options}{'_default_untranslated'} .= " <seglistitem>"; + $self->{options}{'_default_break'} .= " <seglistitem>"; + + # segmentedlist; does not contain text; + $self->{options}{'_default_untranslated'} .= " <segmentedlist>"; + $self->{options}{'_default_break'} .= " <segmentedlist>"; + + # segtitle; contains text; + $self->{options}{'_default_translated'} .= " <segtitle>"; + $self->{options}{'_default_break'} .= " <segtitle>"; + + # seriesinfo; does not contain text; + # Removed in v4.0 + $self->{options}{'_default_untranslated'} .= " <seriesinfo>"; + $self->{options}{'_default_placeholder'} .= " <seriesinfo>"; + + # seriesvolnums; contains text; Formatted inline + # NOTE: could be in the break class + $self->{options}{'_default_translated'} .= " <seriesvolnums>"; + $self->{options}{'_default_inline'} .= " <seriesvolnums>"; + + # set; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <set>"; + $self->{options}{'_default_break'} .= " <set>"; + + # setindex; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <setindex>"; + $self->{options}{'_default_break'} .= " <setindex>"; + + # setindexinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <setindexinfo>"; + $self->{options}{'_default_placeholder'} .= " <setindexinfo>"; + + # setinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <setinfo>"; + $self->{options}{'_default_placeholder'} .= " <setinfo>"; + + # sgmltag; contains text; Formatted inline; v4, not in v5 + $self->{options}{'_default_translated'} .= " <sgmltag>"; + $self->{options}{'_default_inline'} .= " <sgmltag>"; + + # shortaffil; contains text; Formatted inline or as a + # displayed block depending on context + $self->{options}{'_default_translated'} .= " <shortaffil>"; + $self->{options}{'_default_inline'} .= " <shortaffil>"; + + # shortcut; does not contain text; Formatted inline + $self->{options}{'_default_untranslated'} .= " <shortcut>"; + $self->{options}{'_default_inline'} .= " <shortcut>"; + + # sidebar; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <sidebar>"; + $self->{options}{'_default_break'} .= " <sidebar>"; + + # sidebarinfo; does not contain text; v4, not in v5 + $self->{options}{'_default_untranslated'} .= " <sidebarinfo>"; + $self->{options}{'_default_placeholder'} .= " <sidebarinfo>"; + + # simpara; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <simpara>"; + $self->{options}{'_default_break'} .= " <simpara>"; + + # simplelist; does not contain text; + $self->{options}{'_default_untranslated'} .= " <simplelist>"; + $self->{options}{'_default_inline'} .= " <simplelist>"; + + # simplemsgentry; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <simplemsgentry>"; + $self->{options}{'_default_break'} .= " <simplemsgentry>"; + + # simplesect; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <simplesect>"; + $self->{options}{'_default_break'} .= " <simplesect>"; + + # spanspec; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <spanspec>"; + $self->{options}{'_default_break'} .= " <spanspec>"; + + # state; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <state>"; + $self->{options}{'_default_inline'} .= " <state>"; + + # step; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <step>"; + $self->{options}{'_default_break'} .= " <step>"; + + # stepalternatives; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <stepalternatives>"; + $self->{options}{'_default_break'} .= " <stepalternatives>"; + + # street; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <street>"; + $self->{options}{'_default_inline'} .= " <street>"; + + # structfield; contains text; Formatted inline; v4, not in v5 + $self->{options}{'_default_translated'} .= " <structfield>"; + $self->{options}{'_default_inline'} .= " <structfield>"; + + # structname; contains text; Formatted inline; v4, not in v5 + $self->{options}{'_default_translated'} .= " <structname>"; + $self->{options}{'_default_inline'} .= " <structname>"; + + # subject; does not contain text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_untranslated'} .= " <subject>"; + $self->{options}{'_default_break'} .= " <subject>"; + + # subjectset; does not contain text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_untranslated'} .= " <subjectset>"; + $self->{options}{'_default_break'} .= " <subjectset>"; + + # subjectterm; contains text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_translated'} .= " <subjectterm>"; + $self->{options}{'_default_break'} .= " <subjectterm>"; + + # subscript; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <subscript>"; + $self->{options}{'_default_inline'} .= " <subscript>"; + + # substeps; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <substeps>"; + $self->{options}{'_default_break'} .= " <substeps>"; + + # subtitle; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <subtitle>"; + $self->{options}{'_default_break'} .= " <subtitle>"; + + # superscript; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <superscript>"; + $self->{options}{'_default_inline'} .= " <superscript>"; + + # surname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <surname>"; + $self->{options}{'_default_inline'} .= " <surname>"; + +#svg:svg + + # symbol; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <symbol>"; + $self->{options}{'_default_inline'} .= " <symbol>"; + + # synopfragment; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <synopfragment>"; + $self->{options}{'_default_placeholder'} .= " <synopfragment>"; + + # synopfragmentref; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <synopfragmentref>"; + $self->{options}{'_default_inline'} .= " <synopfragmentref>"; + + # synopsis; contains text; verbatim + $self->{options}{'_default_translated'} .= " W<synopsis>"; + $self->{options}{'_default_placeholder'} .= " <synopsis>"; + + # systemitem; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <systemitem>"; + $self->{options}{'_default_inline'} .= " <systemitem>"; + +# TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT + + # table; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <table>"; + $self->{options}{'_default_placeholder'} .= " <table>"; + + # tag; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <tag>"; + $self->{options}{'_default_inline'} .= " <tag>"; + + # task; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <task>"; + $self->{options}{'_default_placeholder'} .= " <task>"; + + # taskprerequisites; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <taskprerequisites>"; + $self->{options}{'_default_break'} .= " <taskprerequisites>"; + + # taskrelated; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <taskrelated>"; + $self->{options}{'_default_break'} .= " <taskrelated>"; + + # tasksummary; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <tasksummary>"; + $self->{options}{'_default_break'} .= " <tasksummary>"; + + # tbody; does not contain text; + $self->{options}{'_default_untranslated'} .= " <tbody>"; + $self->{options}{'_default_break'} .= " <tbody>"; + + # td; contains text; + $self->{options}{'_default_translated'} .= " <td>"; + $self->{options}{'_default_break'} .= " <td>"; + + # term; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <term>"; + $self->{options}{'_default_break'} .= " <term>"; + + # termdef; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <termdef>"; + $self->{options}{'_default_inline'} .= " <termdef>"; + + # tertiary; contains text; Suppressed + $self->{options}{'_default_translated'} .= " <tertiary>"; + $self->{options}{'_default_placeholder'} .= " <tertiary>"; + + # tertiaryie; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <tertiaryie>"; + $self->{options}{'_default_break'} .= " <tertiaryie>"; + + # textdata; does not contain text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_untranslated'} .= " <textdata>"; + $self->{options}{'_default_break'} .= " <textdata>"; + $self->{options}{'_default_attributes'}.=' <textdata>fileref'; + + # textobject; does not contain text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_untranslated'} .= " <textobject>"; + $self->{options}{'_default_break'} .= " <textobject>"; + + # tfoot; does not contain text; + $self->{options}{'_default_untranslated'} .= " <tfoot>"; + $self->{options}{'_default_break'} .= " <tfoot>"; + + # tgroup; does not contain text; + $self->{options}{'_default_untranslated'} .= " <tgroup>"; + $self->{options}{'_default_break'} .= " <tgroup>"; + + # th; contains text; + $self->{options}{'_default_translated'} .= " <th>"; + $self->{options}{'_default_break'} .= " <th>"; + + # thead; does not contain text; + $self->{options}{'_default_untranslated'} .= " <thead>"; + $self->{options}{'_default_break'} .= " <thead>"; + + # tip; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <tip>"; + $self->{options}{'_default_break'} .= " <tip>"; + + # title; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <title>"; + $self->{options}{'_default_break'} .= " <title>"; + + # titleabbrev; contains text; Formatted inline or as a displayed block + # NOTE: could be in the inline class + $self->{options}{'_default_translated'} .= " <titleabbrev>"; + $self->{options}{'_default_break'} .= " <titleabbrev>"; + + # toc; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <toc>"; + $self->{options}{'_default_break'} .= " <toc>"; + + # tocback; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <tocback>"; + $self->{options}{'_default_break'} .= " <tocback>"; + + # tocchap; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <tocchap>"; + $self->{options}{'_default_break'} .= " <tocchap>"; + + # tocdiv; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <tocdiv>"; + $self->{options}{'_default_break'} .= " <tocdiv>"; + + # tocentry; contains text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <tocentry>"; + $self->{options}{'_default_break'} .= " <tocentry>"; + + # tocfront; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_translated'} .= " <tocfront>"; + $self->{options}{'_default_break'} .= " <tocfront>"; + + # toclevel1; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <toclevel1>"; + $self->{options}{'_default_break'} .= " <toclevel1>"; + + # toclevel2; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <toclevel2>"; + $self->{options}{'_default_break'} .= " <toclevel2>"; + + # toclevel3; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <toclevel3>"; + $self->{options}{'_default_break'} .= " <toclevel3>"; + + # toclevel4; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <toclevel4>"; + $self->{options}{'_default_break'} .= " <toclevel4>"; + + # toclevel5; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <toclevel5>"; + $self->{options}{'_default_break'} .= " <toclevel5>"; + + # tocpart; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <tocpart>"; + $self->{options}{'_default_break'} .= " <tocpart>"; + + # token; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <token>"; + $self->{options}{'_default_inline'} .= " <token>"; + + # tr; does not contain text; + $self->{options}{'_default_untranslated'} .= " <tr>"; + $self->{options}{'_default_break'} .= " <tr>"; + + # trademark; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <trademark>"; + $self->{options}{'_default_inline'} .= " <trademark>"; + + # type; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <type>"; + $self->{options}{'_default_inline'} .= " <type>"; + +# UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU + + # ulink; contains text; Formatted inline; v4, not in v5 + $self->{options}{'_default_translated'} .= " <ulink>"; + $self->{options}{'_default_inline'} .= " <ulink>"; + + # uri; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <uri>"; + $self->{options}{'_default_inline'} .= " <uri>"; + + # userinput; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <userinput>"; + $self->{options}{'_default_inline'} .= " <userinput>"; + +# VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV + + # varargs; empty element; + $self->{options}{'_default_untranslated'} .= " <varargs>"; + $self->{options}{'_default_inline'} .= " <varargs>"; + + # variablelist; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <variablelist>"; + $self->{options}{'_default_placeholder'} .= " <variablelist>"; + + # varlistentry; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <varlistentry>"; + $self->{options}{'_default_break'} .= " <varlistentry>"; + + # varname; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <varname>"; + $self->{options}{'_default_inline'} .= " <varname>"; + + # videodata; contains text; Formatted inline or as a displayed block + $self->{options}{'_default_untranslated'} .= " <videodata>"; + $self->{options}{'_default_break'} .= " <videodata>"; + $self->{options}{'_default_attributes'}.=' <videodata>fileref'; + + # videoobject; contains text; Formatted inline or as a displayed block + $self->{options}{'_default_untranslated'} .= " <videoobject>"; + $self->{options}{'_default_break'} .= " <videoobject>"; + + # void; empty element; + $self->{options}{'_default_untranslated'} .= " <void>"; + $self->{options}{'_default_inline'} .= " <void>"; + + # volumenum; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <volumenum>"; + $self->{options}{'_default_inline'} .= " <volumenum>"; + +# WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW + + # warning; does not contain text; Formatted as a displayed block. + $self->{options}{'_default_untranslated'} .= " <warning>"; + $self->{options}{'_default_break'} .= " <warning>"; + + # wordasword; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <wordasword>"; + $self->{options}{'_default_inline'} .= " <wordasword>"; + +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + # xref; empty element; + $self->{options}{'_default_untranslated'} .= " <xref>"; + $self->{options}{'_default_inline'} .= " <xref>"; + +# YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY + + # year; contains text; Formatted inline + $self->{options}{'_default_translated'} .= " <year>"; + $self->{options}{'_default_inline'} .= " <year>"; + +# ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ + + $self->{options}{'_default_attributes'}.=' + lang + xml:lang'; + + $self->treat_options; +} diff -r 9e8e5292acaa -r 1c13ed2130a7 tools/po4a/lib/Locale/Po4a/Po.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/po4a/lib/Locale/Po4a/Po.pm Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,1580 @@ +# Locale::Po4a::Po -- manipulation of po files +# $Id: Po.pm,v 1.95 2009-02-28 22:18:39 nekral-guest Exp $ +# +# This program is free software; you may redistribute it and/or modify it +# under the terms of GPL (see COPYING). + +############################################################################ +# Modules and declarations +############################################################################ + +=head1 NAME + +Locale::Po4a::Po - po file manipulation module + +=head1 SYNOPSIS + + use Locale::Po4a::Po; + my $pofile=Locale::Po4a::Po->new(); + + # Read po file + $pofile->read('file.po'); + + # Add an entry + $pofile->push('msgid' => 'Hello', 'msgstr' => 'bonjour', + 'flags' => "wrap", 'reference'=>'file.c:46'); + + # Extract a translation + $pofile->gettext("Hello"); # returns 'bonjour' + + # Write back to a file + $pofile->write('otherfile.po'); + +=head1 DESCRIPTION + +Locale::Po4a::Po is a module that allows you to manipulate message +catalogs. You can load and write from/to a file (which extension is often +I<po>), you can build new entries on the fly or request for the translation +of a string. + +For a more complete description of message catalogs in the po format and +their use, please refer to the documentation of the gettext program. + +This module is part of the PO4A project, which objective is to use po files +(designed at origin to ease the translation of program messages) to +translate everything, including documentation (man page, info manual), +package description, debconf templates, and everything which may benefit +from this. + +=head1 OPTIONS ACCEPTED BY THIS MODULE + +=over 4 + +=item porefs + +This specifies the reference format. It can be one of 'none' to not produce +any reference, 'noline' to not specify the line number, and 'full' to +include complete references. + +=back + +=cut + +use IO::File; + + +require Exporter; + +package Locale::Po4a::Po; +use DynaLoader; + +use Locale::Po4a::Common qw(wrap_msg wrap_mod wrap_ref_mod dgettext); + +use subs qw(makespace); +use vars qw(@ISA @EXPORT_OK); +@ISA = qw(Exporter DynaLoader); +@EXPORT = qw(%debug); +@EXPORT_OK = qw(&move_po_if_needed); + +use Locale::Po4a::TransTractor; +# Try to use a C extension if present. +eval("bootstrap Locale::Po4a::Po $Locale::Po4a::TransTractor::VERSION"); + +use 5.006; +use strict; +use warnings; + +use Carp qw(croak); +use File::Path; # mkdir before write +use File::Copy; # move +use POSIX qw(strftime floor); +use Time::Local; + +use Encode; + +my @known_flags=qw(wrap no-wrap c-format fuzzy); + +our %debug=('canonize' => 0, + 'quote' => 0, + 'escape' => 0, + 'encoding' => 0, + 'filter' => 0); + +=head1 Functions about whole message catalogs + +=over 4 + +=item new() + +Creates a new message catalog. If an argument is provided, it's the name of +a po file we should load. + +=cut + +sub new { + my ($this, $options) = (shift, shift); + my $class = ref($this) || $this; + my $self = {}; + bless $self, $class; + $self->initialize($options); + + my $filename = shift; + $self->read($filename) if defined($filename) && length($filename); + return $self; +} + +# Return the numerical timezone (e.g. +0200) +# Neither the %z nor the %s formats of strftime are portable: +# '%s' is not supported on Solaris and '%z' indicates +# "2006-10-25 19:36E. Europe Standard Time" on MS Windows. +sub timezone { + my @g = gmtime(); + my @l = localtime(); + + my $diff; + $diff = floor(timelocal(@l)/60 +0.5); + $diff -= floor(timelocal(@g)/60 +0.5); + + my $h = floor($diff / 60) + $l[8]; # $l[8] indicates if we are currently + # in a daylight saving time zone + my $m = $diff%60; + + return sprintf "%+03d%02d\n", $h, $m; +} + +sub initialize { + my ($self, $options) = (shift, shift); + my $date = strftime("%Y-%m-%d %H:%M", localtime).timezone(); + chomp $date; +# $options = ref($options) || $options; + + $self->{options}{'porefs'}= 'full'; + $self->{options}{'msgid-bugs-address'}= undef; + $self->{options}{'copyright-holder'}= "Free Software Foundation, Inc."; + $self->{options}{'package-name'}= "PACKAGE"; + $self->{options}{'package-version'}= "VERSION"; + foreach my $opt (keys %$options) { + if ($options->{$opt}) { + die wrap_mod("po4a::po", + dgettext ("po4a", "Unknown option: %s"), $opt) + unless exists $self->{options}{$opt}; + $self->{options}{$opt} = $options->{$opt}; + } + } + $self->{options}{'porefs'} =~ /^(full|noline|none)$/ || + die wrap_mod("po4a::po", + dgettext ("po4a", + "Invalid value for option 'porefs' ('%s' is ". + "not one of 'full', 'noline' or 'none')"), + $self->{options}{'porefs'}); + + $self->{po}=(); + $self->{count}=0; # number of msgids in the PO + # count_doc: number of strings in the document + # (duplicate strings counted multiple times) + $self->{count_doc}=0; + $self->{header_comment}= + " SOME DESCRIPTIVE TITLE\n" + ." Copyright (C) YEAR ". + $self->{options}{'copyright-holder'}."\n" + ." This file is distributed under the same license ". + "as the ".$self->{options}{'package-name'}." package.\n" + ." FIRST AUTHOR <EMAIL\@ADDRESS>, YEAR.\n" + ."\n" + .", fuzzy"; +# $self->header_tag="fuzzy"; + $self->{header}=escape_text("Project-Id-Version: ". + $self->{options}{'package-name'}." ". + $self->{options}{'package-version'}."\n". + ((defined $self->{options}{'msgid-bugs-address'})? + "Report-Msgid-Bugs-To: ".$self->{options}{'msgid-bugs-address'}."\n": + ""). + "POT-Creation-Date: $date\n". + "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n". + "Last-Translator: FULL NAME <EMAIL\@ADDRESS>\n". + "Language-Team: LANGUAGE <LL\@li.org>\n". + "MIME-Version: 1.0\n". + "Content-Type: text/plain; charset=CHARSET\n". + "Content-Transfer-Encoding: ENCODING"); + + $self->{encoder}=find_encoding("ascii"); + + # To make stats about gettext hits + $self->stats_clear(); +} + +=item read($) + +Reads a po file (which name is given as argument). Previously existing +entries in self are not removed, the new ones are added to the end of the +catalog. + +=cut + +sub read { + my $self=shift; + my $filename=shift + or croak wrap_mod("po4a::po", + dgettext("po4a", + "Please provide a non-null filename")); + + my $fh; + if ($filename eq '-') { + $fh=*STDIN; + } else { + open $fh,"<$filename" + or croak wrap_mod("po4a::po", + dgettext("po4a", "Can't read from %s: %s"), + $filename, $!); + } + + ## Read paragraphs line-by-line + my $pofile=""; + my $textline; + while (defined ($textline = <$fh>)) { + $pofile .= $textline; + } +# close INPUT +# or croak (sprintf(dgettext("po4a", +# "Can't close %s after reading: %s"), +# $filename,$!)."\n"); + + my $linenum=0; + + foreach my $msg (split (/\n\n/,$pofile)) { + my ($msgid,$msgstr,$comment,$automatic,$reference,$flags,$buffer); + my ($msgid_plural, $msgstr_plural); + foreach my $line (split (/\n/,$msg)) { + $linenum++; + if ($line =~ /^#\. ?(.*)$/) { # Automatic comment + $automatic .= (defined($automatic) ? "\n" : "").$1; + + } elsif ($line =~ /^#: ?(.*)$/) { # reference + $reference .= (defined($reference) ? "\n" : "").$1; + + } elsif ($line =~ /^#, ?(.*)$/) { # flags + $flags .= (defined($flags) ? "\n" : "").$1; + + } elsif ($line =~ /^#(.*)$/) { # Translator comments + $comment .= (defined($comment) ? "\n" : "").($1||""); + + } elsif ($line =~ /^msgid (".*")$/) { # begin of msgid + $buffer = $1; + + } elsif ($line =~ /^msgid_plural (".*")$/) { + # begin of msgid_plural, end of msgid + + $msgid = $buffer; + $buffer = $1; + + } elsif ($line =~ /^msgstr (".*")$/) { + # begin of msgstr, end of msgid + + $msgid = $buffer; + $buffer = "$1"; + + } elsif ($line =~ /^msgstr\[([0-9]+)\] (".*")$/) { + # begin of msgstr[x], end of msgid_plural or msgstr[x-1] + + # Note: po4a cannot uses plural forms + # (no integer to use the plural form) + # * drop the msgstr[x] where x >= 2 + # * use msgstr[0] as the translation of msgid + # * use msgstr[1] as the translation of msgid_plural + + if ($1 eq "0") { + $msgid_plural = $buffer; + $buffer = "$2"; + } elsif ($1 eq "1") { + $msgstr = $buffer; + $buffer = "$2"; + } elsif ($1 eq "2") { + $msgstr_plural = $buffer; + warn wrap_ref_mod("$filename:$linenum", + "po4a::po", + dgettext("po4a", "Messages with more than 2 plural forms are not supported.")); + } + } elsif ($line =~ /^(".*")$/) { + # continuation of a line + $buffer .= "\n$1"; + + } else { + warn wrap_ref_mod("$filename:$linenum", + "po4a::po", + dgettext("po4a", "Strange line: -->%s<--"), + $line); + } + } + $linenum++; + if (defined $msgid_plural) { + $msgstr_plural=$buffer; + + $msgid = unquote_text($msgid) if (defined($msgid)); + $msgstr = unquote_text($msgstr) if (defined($msgstr)); + + $self->push_raw ('msgid' => $msgid, + 'msgstr' => $msgstr, + 'reference' => $reference, + 'flags' => $flags, + 'comment' => $comment, + 'automatic' => $automatic, + 'plural' => 0); + + $msgid_plural = unquote_text($msgid_plural) + if (defined($msgid_plural)); + $msgstr_plural = unquote_text($msgstr_plural) + if (defined($msgstr_plural)); + + $self->push_raw ('msgid' => $msgid_plural, + 'msgstr' => $msgstr_plural, + 'reference' => $reference, + 'flags' => $flags, + 'comment' => $comment, + 'automatic' => $automatic, + 'plural' => 1); + } else { + $msgstr=$buffer; + + $msgid = unquote_text($msgid) if (defined($msgid)); + $msgstr = unquote_text($msgstr) if (defined($msgstr)); + + $self->push_raw ('msgid' => $msgid, + 'msgstr' => $msgstr, + 'reference' => $reference, + 'flags' => $flags, + 'comment' => $comment, + 'automatic' => $automatic); + } + } +} + +=item write($) + +Writes the current catalog to the given file. + +=cut + +sub write{ + my $self=shift; + my $filename=shift + or croak dgettext("po4a","Can't write to a file without filename")."\n"; + + my $fh; + if ($filename eq '-') { + $fh=\*STDOUT; + } else { + # make sure the directory in which we should write the localized + # file exists + my $dir = $filename; + if ($dir =~ m|/|) { + $dir =~ s|/[^/]*$||; + + File::Path::mkpath($dir, 0, 0755) # Croaks on error + if (length ($dir) && ! -e $dir); + } + open $fh,">$filename" + or croak wrap_mod("po4a::po", + dgettext("po4a", "Can't write to %s: %s"), + $filename, $!); + } + + print $fh "".format_comment($self->{header_comment},"") + if defined($self->{header_comment}) && length($self->{header_comment}); + + print $fh "msgid \"\"\n"; + print $fh "msgstr ".quote_text($self->{header})."\n\n"; + + + my $buf_msgstr_plural; # USed to keep the first msgstr of plural forms + my $first=1; + foreach my $msgid ( sort { ($self->{po}{"$a"}{'pos'}) <=> + ($self->{po}{"$b"}{'pos'}) + } keys %{$self->{po}}) { + my $output=""; + + if ($first) { + $first=0; + } else { + $output .= "\n"; + } + + $output .= format_comment($self->{po}{$msgid}{'comment'},"") + if defined($self->{po}{$msgid}{'comment'}) + && length ($self->{po}{$msgid}{'comment'}); + if ( defined($self->{po}{$msgid}{'automatic'}) + && length ($self->{po}{$msgid}{'automatic'})) { + foreach my $comment (split(/\\n/,$self->{po}{$msgid}{'automatic'})) + { + $output .= format_comment($comment, ". ") + } + } + $output .= format_comment($self->{po}{$msgid}{'type'},". type: ") + if defined($self->{po}{$msgid}{'type'}) + && length ($self->{po}{$msgid}{'type'}); + $output .= format_comment($self->{po}{$msgid}{'reference'},": ") + if defined($self->{po}{$msgid}{'reference'}) + && length ($self->{po}{$msgid}{'reference'}); + $output .= "#, ". join(", ", sort split(/\s+/,$self->{po}{$msgid}{'flags'}))."\n" + if defined($self->{po}{$msgid}{'flags'}) + && length ($self->{po}{$msgid}{'flags'}); + + if (exists $self->{po}{$msgid}{'plural'}) { + if ($self->{po}{$msgid}{'plural'} == 0) { + if ($self->get_charset =~ /^utf-8$/i) { + my $msgstr = Encode::decode_utf8($self->{po}{$msgid}{'msgstr'}); + $msgid = Encode::decode_utf8($msgid); + $output .= Encode::encode_utf8("msgid ".quote_text($msgid)."\n"); + $buf_msgstr_plural = Encode::encode_utf8("msgstr[0] ".quote_text($msgstr)."\n"); + } else { + $output = "msgid ".quote_text($msgid)."\n"; + $buf_msgstr_plural = "msgstr[0] ".quote_text($self->{po}{$msgid}{'msgstr'})."\n"; + } + } elsif ($self->{po}{$msgid}{'plural'} == 1) { +# TODO: there may be only one plural form + if ($self->get_charset =~ /^utf-8$/i) { + my $msgstr = Encode::decode_utf8($self->{po}{$msgid}{'msgstr'}); + $msgid = Encode::decode_utf8($msgid); + $output = Encode::encode_utf8("msgid_plural ".quote_text($msgid)."\n"); + $output .= $buf_msgstr_plural; + $output .= Encode::encode_utf8("msgstr[1] ".quote_text($msgstr)."\n"); + $buf_msgstr_plural = ""; + } else { + $output = "msgid_plural ".quote_text($msgid)."\n"; + $output .= $buf_msgstr_plural; + $output .= "msgstr[1] ".quote_text($self->{po}{$msgid}{'msgstr'})."\n"; + } + } else { + die wrap_msg(dgettext("po4a","Can't write PO files with more than two plural forms.")); + } + } else { + if ($self->get_charset =~ /^utf-8$/i) { + my $msgstr = Encode::decode_utf8($self->{po}{$msgid}{'msgstr'}); + $msgid = Encode::decode_utf8($msgid); + $output .= Encode::encode_utf8("msgid ".quote_text($msgid)."\n"); + $output .= Encode::encode_utf8("msgstr ".quote_text($msgstr)."\n"); + } else { + $output .= "msgid ".quote_text($msgid)."\n"; + $output .= "msgstr ".quote_text($self->{po}{$msgid}{'msgstr'})."\n"; + } + } + + print $fh $output; + } +# print STDERR "$fh"; +# if ($filename ne '-') { +# close $fh +# or croak (sprintf(dgettext("po4a", +# "Can't close %s after writing: %s\n"), +# $filename,$!)); +# } +} + +=item write_if_needed($$) + +Like write, but if the PO or POT file already exists, the object will be +written in a temporary file which will be compared with the existing file +to check that the update is needed (this avoids to change a POT just to +update a line reference or the POT-Creation-Date field). + +=cut + +sub move_po_if_needed { + my ($new_po, $old_po, $backup) = (shift, shift, shift); + my $diff; + + if (-e $old_po) { + my $diff_ignore = "-I'^#:' " + ."-I'^\"POT-Creation-Date:' " + ."-I'^\"PO-Revision-Date:'"; + $diff = qx(diff -q $diff_ignore $old_po $new_po); + if ( $diff eq "" ) { + unlink $new_po + or die wrap_msg(dgettext("po4a","Can't unlink %s: %s."), + $new_po, $!); + # touch the old PO + my ($atime, $mtime) = (time,time); + utime $atime, $mtime, $old_po; + } else { + if ($backup) { + copy $old_po, $old_po."~" + or die wrap_msg(dgettext("po4a","Can't copy %s to %s: %s."), + $old_po, $old_po."~", $!); + } else { + } + move $new_po, $old_po + or die wrap_msg(dgettext("po4a","Can't move %s to %s: %s."), + $new_po, $old_po, $!); + } + } else { + move $new_po, $old_po + or die wrap_msg(dgettext("po4a","Can't move %s to %s: %s."), + $new_po, $old_po, $!); + } +} + +sub write_if_needed { + my $self=shift; + my $filename=shift + or croak dgettext("po4a","Can't write to a file without filename")."\n"; + + if (-e $filename) { + my ($tmp_filename); + (undef,$tmp_filename)=File::Temp->tempfile($filename."XXXX", + DIR => "/tmp", + OPEN => 0, + UNLINK => 0); + $self->write($tmp_filename); + move_po_if_needed($tmp_filename, $filename); + } else { + $self->write($filename); + } +} + +=item gettextize($$) + +This function produces one translated message catalog from two catalogs, an +original and a translation. This process is described in L<po4a(7)|po4a.7>, +section I<Gettextization: how does it work?>. + +=cut + +sub gettextize { + my $this = shift; + my $class = ref($this) || $this; + my ($poorig,$potrans)=(shift,shift); + + my $pores=Locale::Po4a::Po->new(); + + my $please_fail = 0; + my $toobad = dgettext("po4a", + "\nThe gettextization failed (once again). Don't give up, ". + "gettextizing is a subtle art, but this is only needed once ". + "to convert a project to the gorgeous luxus offered by po4a ". + "to translators.". + "\nPlease refer to the po4a(7) documentation, the section ". + "\"HOWTO convert a pre-existing translation to po4a?\" ". + "contains several hints to help you in your task"); + + # Don't fail right now when the entry count does not match. Instead, give + # it a try so that the user can see where we fail (which is probably where + # the problem is). + if ($poorig->count_entries_doc() > $potrans->count_entries_doc()) { + warn wrap_mod("po4a gettextize", dgettext("po4a", + "Original has more strings than the translation (%d>%d). ". + "Please fix it by editing the translated version to add ". + "some dummy entry."), + $poorig->count_entries_doc(), + $potrans->count_entries_doc()); + $please_fail = 1; + } elsif ($poorig->count_entries_doc() < $potrans->count_entries_doc()) { + warn wrap_mod("po4a gettextize", dgettext("po4a", + "Original has less strings than the translation (%d<%d). ". + "Please fix it by removing the extra entry from the ". + "translated file. You may need an addendum (cf po4a(7)) ". + "to reput the chunk in place after gettextization. A ". + "possible cause is that a text duplicated in the original ". + "is not translated the same way each time. Remove one of ". + "the translations, and you're fine."), + $poorig->count_entries_doc(), + $potrans->count_entries_doc()); + $please_fail = 1; + } + + if ( $poorig->get_charset =~ /^utf-8$/i ) { + $potrans->to_utf8; + $pores->set_charset("utf-8"); + } else { + if ($potrans->get_charset eq "CHARSET") { + $pores->set_charset("ascii"); + } else { + $pores->set_charset($potrans->get_charset); + } + } + print "Po character sets:\n". + " original=".$poorig->get_charset."\n". + " translated=".$potrans->get_charset."\n". + " result=".$pores->get_charset."\n" + if $debug{'encoding'}; + + for (my ($o,$t)=(0,0) ; + $o<$poorig->count_entries_doc() && $t<$potrans->count_entries_doc(); + $o++,$t++) { + # + # Extract some informations + + my ($orig,$trans)=($poorig->msgid_doc($o),$potrans->msgid_doc($t)); +# print STDERR "Matches [[$orig]]<<$trans>>\n"; + + my ($reforig,$reftrans)=($poorig->{po}{$orig}{'reference'}, + $potrans->{po}{$trans}{'reference'}); + my ($typeorig,$typetrans)=($poorig->{po}{$orig}{'type'}, + $potrans->{po}{$trans}{'type'}); + + # + # Make sure the type of both string exist + # + die wrap_mod("po4a gettextize", + "Internal error: type of original string number %s ". + "isn't provided", $o) + if ($typeorig eq ''); + + die wrap_mod("po4a gettextize", + "Internal error: type of translated string number %s ". + "isn't provided", $o) + if ($typetrans eq ''); + + # + # Make sure both type are the same + # + if ($typeorig ne $typetrans){ + $pores->write("gettextization.failed.po"); + die wrap_msg(dgettext("po4a", + "po4a gettextization: Structure disparity between ". + "original and translated files:\n". + "msgid (at %s) is of type '%s' while\n". + "msgstr (at %s) is of type '%s'.\n". + "Original text: %s\n". + "Translated text: %s\n". + "(result so far dumped to gettextization.failed.po)"). + "%s", + $reforig, $typeorig, + $reftrans, $typetrans, + $orig, + $trans, + $toobad); + } + + # + # Push the entry + # + my $flags; + if (defined $poorig->{po}{$orig}{'flags'}) { + $flags = $poorig->{po}{$orig}{'flags'}." fuzzy"; + } else { + $flags = "fuzzy"; + } + $pores->push_raw('msgid' => $orig, + 'msgstr' => $trans, + 'flags' => $flags, + 'type' => $typeorig, + 'reference' => $reforig, + 'conflict' => 1, + 'transref' => $potrans->{po}{$trans}{'reference'}) + unless (defined($pores->{po}{$orig}) + and ($pores->{po}{$orig}{'msgstr'} eq $trans)) + # FIXME: maybe we should be smarter about what reference should be + # sent to push_raw. + } + + # make sure we return a useful error message when entry count differ + die "$toobad\n" if $please_fail; + + return $pores; +} + +=item filter($) + +This function extracts a catalog from an existing one. Only the entries having +a reference in the given file will be placed in the resulting catalog. + +This function parses its argument, converts it to a perl function definition, +eval this definition and filter the fields for which this function returns +true. + +I love perl sometimes ;) + +=cut + +sub filter { + my $self=shift; + our $filter=shift; + + my $res; + $res = Locale::Po4a::Po->new(); + + # Parse the filter + our $code="sub apply { return "; + our $pos=0; + our $length = length $filter; + + # explode chars to parts. How to subscript a string in Perl? + our @filter = split(//,$filter); + + sub gloups { + my $fmt=shift; + my $space = ""; + for (1..$pos){ + $space .= ' '; + } + die wrap_msg("$fmt\n$filter\n$space^ HERE"); + } + sub showmethecode { + return unless $debug{'filter'}; + my $fmt=shift; + my $space=""; + for (1..$pos){ + $space .= ' '; + } + print STDERR "$filter\n$space^ $fmt\n";#"$code\n"; + } + + # I dream of a lex in perl :-/ + sub parse_expression { + showmethecode("Begin expression") + if $debug{'filter'}; + + gloups("Begin of expression expected, got '%s'",$filter[$pos]) + unless ($filter[$pos] eq '('); + $pos ++; # pass the '(' + if ($filter[$pos] eq '&') { + # AND + $pos++; + showmethecode("Begin of AND") + if $debug{'filter'}; + $code .= "("; + while (1) { + gloups ("Unfinished AND statement.") + if ($pos == $length); + parse_expression(); + if ($filter[$pos] eq '(') { + $code .= " && "; + } elsif ($filter[$pos] eq ')') { + last; # do not eat that char + } else { + gloups("End of AND or begin of sub-expression expected, got '%s'", $filter[$pos]); + } + } + $code .= ")"; + } elsif ($filter[$pos] eq '|') { + # OR + $pos++; + $code .= "("; + while (1) { + gloups("Unfinished OR statement.") + if ($pos == $length); + parse_expression(); + if ($filter[$pos] eq '(') { + $code .= " || "; + } elsif ($filter[$pos] eq ')') { + last; # do not eat that char + } else { + gloups("End of OR or begin of sub-expression expected, got '%s'",$filter[$pos]); + } + } + $code .= ")"; + } elsif ($filter[$pos] eq '!') { + # NOT + $pos++; + $code .= "(!"; + gloups("Missing sub-expression in NOT statement.") + if ($pos == $length); + parse_expression(); + $code .= ")"; + } else { + # must be an equal. Let's get field and argument + my ($field,$arg,$done); + $field = substr($filter,$pos); + gloups("EQ statement contains no '=' or invalid field name") + unless ($field =~ /([a-z]*)=/i); + $field = lc($1); + $pos += (length $field) + 1; + + # check that we've got a valid field name, + # and the number it referes to + # DO NOT CHANGE THE ORDER + my @names=qw(msgid msgstr reference flags comment automatic); + my $fieldpos; + for ($fieldpos = 0; + $fieldpos < scalar @names && $field ne $names[$fieldpos]; + $fieldpos++) {} + gloups("Invalid field name: %s",$field) + if $fieldpos == scalar @names; # not found + + # Now, get the argument value. It has to be between quotes, + # which can be escaped + # We point right on the first char of the argument + # (first quote already eaten) + my $escaped = 0; + my $quoted = 0; + if ($filter[$pos] eq '"') { + $pos++; + $quoted = 1; + } + showmethecode(($quoted?"Quoted":"Unquoted")." argument of field '$field'") + if $debug{'filter'}; + + while (!$done) { + gloups("Unfinished EQ argument.") + if ($pos == $length); + + if ($quoted) { + if ($filter[$pos] eq '\\') { + if ($escaped) { + $arg .= '\\'; + $escaped = 0; + } else { + $escaped = 1; + } + } elsif ($escaped) { + if ($filter[$pos] eq '"') { + $arg .= '"'; + $escaped = 0; + } else { + gloups("Invalid escape sequence in argument: '\\%s'",$filter[$pos]); + } + } else { + if ($filter[$pos] eq '"') { + $done = 1; + } else { + $arg .= $filter[$pos]; + } + } + } else { + if ($filter[$pos] eq ')') { + # counter the next ++ since we don't want to eat + # this char + $pos--; + $done = 1; + } else { + $arg .= $filter[$pos]; + } + } + $pos++; + } + # and now, add the code to check this equality + $code .= "(\$_[$fieldpos] =~ m/$arg/)"; + + } + showmethecode("End of expression") + if $debug{'filter'}; + gloups("Unfinished statement.") + if ($pos == $length); + gloups("End of expression expected, got '%s'",$filter[$pos]) + unless ($filter[$pos] eq ')'); + $pos++; + } + # And now, launch the beast, finish the function and use eval + # to construct this function. + # Ok, the lack of lexer is a fair price for the eval ;) + parse_expression(); + gloups("Garbage at the end of the expression") + if ($pos != $length); + $code .= "; }"; + print STDERR "CODE = $code\n" + if $debug{'filter'}; + eval $code; + die wrap_mod("po4a::po", dgettext("po4a", "Eval failure: %s"), $@) + if $@; + + for (my $cpt=(0) ; + $cpt<$self->count_entries(); + $cpt++) { + + my ($msgid,$ref,$msgstr,$flags,$type,$comment,$automatic); + + $msgid = $self->msgid($cpt); + $ref=$self->{po}{$msgid}{'reference'}; + + $msgstr= $self->{po}{$msgid}{'msgstr'}; + $flags = $self->{po}{$msgid}{'flags'}; + $type = $self->{po}{$msgid}{'type'}; + $comment = $self->{po}{$msgid}{'comment'}; + $automatic = $self->{po}{$msgid}{'automatic'}; + + # DO NOT CHANGE THE ORDER + $res->push_raw('msgid' => $msgid, + 'msgstr' => $msgstr, + 'flags' => $flags, + 'type' => $type, + 'reference' => $ref, + 'comment' => $comment, + 'automatic' => $automatic) + if (apply($msgid,$msgstr,$ref,$flags,$comment,$automatic)); + } + # delete the apply subroutine + # otherwise it will be redefined. + undef &apply; + return $res; +} + +=item to_utf8() + +Recodes to utf-8 the po's msgstrs. Does nothing if the charset is not +specified in the po file ("CHARSET" value), or if it's already utf-8 or +ascii. + +=cut + +sub to_utf8 { + my $this = shift; + my $charset = $this->get_charset(); + + unless ($charset eq "CHARSET" or + $charset =~ /^ascii$/i or + $charset =~ /^utf-8$/i) { + foreach my $msgid ( keys %{$this->{po}} ) { + Encode::from_to($this->{po}{$msgid}{'msgstr'}, $charset, "utf-8"); + } + $this->set_charset("utf-8"); + } +} + +=back + +=head1 Functions to use a message catalog for translations + +=over 4 + +=item gettext($%) + +Request the translation of the string given as argument in the current catalog. +The function returns the original (untranslated) string if the string was not +found. + +After the string to translate, you can pass a hash of extra +arguments. Here are the valid entries: + +=over + +=item wrap + +boolean indicating whether we can consider that whitespaces in string are +not important. If yes, the function canonizes the string before looking for +a translation, and wraps the result. + +=item wrapcol + +The column at which we should wrap (default: 76). + +=back + +=cut + +sub gettext { + my $self=shift; + my $text=shift; + my (%opt)=@_; + my $res; + + return "" unless defined($text) && length($text); # Avoid returning the header. + my $validoption="reference wrap wrapcol"; + my %validoption; + + map { $validoption{$_}=1 } (split(/ /,$validoption)); + foreach (keys %opt) { + Carp::confess "internal error: unknown arg $_.\n". + "Here are the valid options: $validoption.\n" + unless $validoption{$_}; + } + + $text=canonize($text) + if ($opt{'wrap'}); + + my $esc_text=escape_text($text); + + $self->{gettextqueries}++; + + if ( defined $self->{po}{$esc_text} + and defined $self->{po}{$esc_text}{'msgstr'} + and length $self->{po}{$esc_text}{'msgstr'} + and ( not defined $self->{po}{$esc_text}{'flags'} + or $self->{po}{$esc_text}{'flags'} !~ /fuzzy/)) { + + $self->{gettexthits}++; + $res = unescape_text($self->{po}{$esc_text}{'msgstr'}); + if (defined $self->{po}{$esc_text}{'plural'}) { + if ($self->{po}{$esc_text}{'plural'} eq "0") { + warn wrap_mod("po4a gettextize", dgettext("po4a", + "'%s' is the singular form of a message, ". + "po4a will use the msgstr[0] translation (%s)."), + $esc_text, $res); + } else { + warn wrap_mod("po4a gettextize", dgettext("po4a", + "'%s' is the plural form of a message, ". + "po4a will use the msgstr[1] translation (%s)."), + $esc_text, $res); + } + } + } else { + $res = $text; + } + + if ($opt{'wrap'}) { + if ($self->get_charset =~ /^utf-8$/i) { + $res=Encode::decode_utf8($res); + $res=wrap ($res, $opt{'wrapcol'} || 76); + $res=Encode::encode_utf8($res); + } else { + $res=wrap ($res, $opt{'wrapcol'} || 76); + } + } +# print STDERR "Gettext >>>$text<<<(escaped=$esc_text)=[[[$res]]]\n\n"; + return $res; +} + +=item stats_get() + +Returns statistics about the hit ratio of gettext since the last time that +stats_clear() was called. Please note that it's not the same +statistics than the one printed by msgfmt --statistic. Here, it's statistics +about recent usage of the po file, while msgfmt reports the status of the +file. Example of use: + + [some use of the po file to translate stuff] + + ($percent,$hit,$queries) = $pofile->stats_get(); + print "So far, we found translations for $percent\% ($hit of $queries) of strings.\n"; + +=cut + +sub stats_get() { + my $self=shift; + my ($h,$q)=($self->{gettexthits},$self->{gettextqueries}); + my $p = ($q == 0 ? 100 : int($h/$q*10000)/100); + +# $p =~ s/\.00//; +# $p =~ s/(\..)0/$1/; + + return ( $p,$h,$q ); +} + +=item stats_clear() + +Clears the statistics about gettext hits. + +=cut + +sub stats_clear { + my $self = shift; + $self->{gettextqueries} = 0; + $self->{gettexthits} = 0; +} + +=back + +=head1 Functions to build a message catalog + +=over 4 + +=item push(%) + +Push a new entry at the end of the current catalog. The arguments should +form a hash table. The valid keys are: + +=over 4 + +=item msgid + +the string in original language. + +=item msgstr + +the translation. + +=item reference + +an indication of where this string was found. Example: file.c:46 (meaning +in 'file.c' at line 46). It can be a space-separated list in case of +multiple occurrences. + +=item comment + +a comment added here manually (by the translators). The format here is free. + +=item automatic + +a comment which was automatically added by the string extraction +program. See the I<--add-comments> option of the B<xgettext> program for +more information. + +=item flags + +space-separated list of all defined flags for this entry. + +Valid flags are: c-text, python-text, lisp-text, elisp-text, librep-text, +smalltalk-text, java-text, awk-text, object-pascal-text, ycp-text, +tcl-text, wrap, no-wrap and fuzzy. + +See the gettext documentation for their meaning. + +=item type + +This is mostly an internal argument: it is used while gettextizing +documents. The idea here is to parse both the original and the translation +into a po object, and merge them, using one's msgid as msgid and the +other's msgid as msgstr. To make sure that things get ok, each msgid in po +objects are given a type, based on their structure (like "chapt", "sect1", +"p" and so on in docbook). If the types of strings are not the same, that +means that both files do not share the same structure, and the process +reports an error. + +This information is written as automatic comment in the po file since this +gives to translators some context about the strings to translate. + +=item wrap + +boolean indicating whether whitespaces can be mangled in cosmetic +reformattings. If true, the string is canonized before use. + +This information is written to the po file using the 'wrap' or 'no-wrap' flag. + +=item wrapcol + +The column at which we should wrap (default: 76). + +This information is not written to the po file. + +=back + +=cut + +sub push { + my $self=shift; + my %entry=@_; + + my $validoption="wrap wrapcol type msgid msgstr automatic flags reference"; + my %validoption; + + map { $validoption{$_}=1 } (split(/ /,$validoption)); + foreach (keys %entry) { + Carp::confess "internal error: unknown arg $_.\n". + "Here are the valid options: $validoption.\n" + unless $validoption{$_}; + } + + unless ($entry{'wrap'}) { + $entry{'flags'} .= " no-wrap"; + } + if (defined ($entry{'msgid'})) { + $entry{'msgid'} = canonize($entry{'msgid'}) + if ($entry{'wrap'}); + + $entry{'msgid'} = escape_text($entry{'msgid'}); + } + if (defined ($entry{'msgstr'})) { + $entry{'msgstr'} = canonize($entry{'msgstr'}) + if ($entry{'wrap'}); + + $entry{'msgstr'} = escape_text($entry{'msgstr'}); + } + + $self->push_raw(%entry); +} + +# The same as push(), but assuming that msgid and msgstr are already escaped +sub push_raw { + my $self=shift; + my %entry=@_; + my ($msgid,$msgstr,$reference,$comment,$automatic,$flags,$type,$transref)= + ($entry{'msgid'},$entry{'msgstr'}, + $entry{'reference'},$entry{'comment'},$entry{'automatic'}, + $entry{'flags'},$entry{'type'},$entry{'transref'}); + my $keep_conflict = $entry{'conflict'}; + +# print STDERR "Push_raw\n"; +# print STDERR " msgid=>>>$msgid<<<\n" if $msgid; +# print STDERR " msgstr=[[[$msgstr]]]\n" if $msgstr; +# Carp::cluck " flags=$flags\n" if $flags; + + return unless defined($entry{'msgid'}); + + #no msgid => header definition + unless (length($entry{'msgid'})) { +# if (defined($self->{header}) && $self->{header} =~ /\S/) { +# warn dgettext("po4a","Redefinition of the header. ". +# "The old one will be discarded\n"); +# } FIXME: do that iff the header isn't the default one. + $self->{header}=$msgstr; + $self->{header_comment}=$comment; + my $charset = $self->get_charset; + if ($charset ne "CHARSET") { + $self->{encoder}=find_encoding($charset); + } else { + $self->{encoder}=find_encoding("ascii"); + } + return; + } + + if ($self->{options}{'porefs'} eq "none") { + $reference = ""; + } elsif ($self->{options}{'porefs'} eq "noline") { + $reference =~ s/:[0-9]*/:1/g; + } + + if (defined($self->{po}{$msgid})) { + warn wrap_mod("po4a::po", + dgettext("po4a","msgid defined twice: %s"), + $msgid) + if (0); # FIXME: put a verbose stuff + if ( defined $msgstr + and defined $self->{po}{$msgid}{'msgstr'} + and $self->{po}{$msgid}{'msgstr'} ne $msgstr) { + my $txt=quote_text($msgid); + my ($first,$second)= + (format_comment(". ",$self->{po}{$msgid}{'reference'}). + quote_text($self->{po}{$msgid}{'msgstr'}), + + format_comment(". ",$reference). + quote_text($msgstr)); + + if ($keep_conflict) { + if ($self->{po}{$msgid}{'msgstr'} =~ m/^#-#-#-#-# .* #-#-#-#-#\\n/s) { + $msgstr = $self->{po}{$msgid}{'msgstr'}. + "\\n#-#-#-#-# $transref #-#-#-#-#\\n". + $msgstr; + } else { + $msgstr = "#-#-#-#-# ". + $self->{po}{$msgid}{'transref'}. + " #-#-#-#-#\\n". + $self->{po}{$msgid}{'msgstr'}."\\n". + "#-#-#-#-# $transref #-#-#-#-#\\n". + $msgstr; + } + # Every msgid will have the same list of references. + # Only keep the last list. + $self->{po}{$msgid}{'reference'} = ""; + } else { + warn wrap_msg(dgettext("po4a", + "Translations don't match for:\n". + "%s\n". + "-->First translation:\n". + "%s\n". + " Second translation:\n". + "%s\n". + " Old translation discarded."), + $txt,$first,$second); + } + } + } + if (defined $transref) { + $self->{po}{$msgid}{'transref'} = $transref; + } + if (defined $reference) { + if (defined $self->{po}{$msgid}{'reference'}) { + $self->{po}{$msgid}{'reference'} .= " ".$reference; + } else { + $self->{po}{$msgid}{'reference'} = $reference; + } + } + $self->{po}{$msgid}{'msgstr'} = $msgstr; + $self->{po}{$msgid}{'comment'} = $comment; + $self->{po}{$msgid}{'automatic'} = $automatic; + if (defined($self->{po}{$msgid}{'pos_doc'})) { + $self->{po}{$msgid}{'pos_doc'} .= " ".$self->{count_doc}++; + } else { + $self->{po}{$msgid}{'pos_doc'} = $self->{count_doc}++; + } + unless (defined($self->{po}{$msgid}{'pos'})) { + $self->{po}{$msgid}{'pos'} = $self->{count}++; + } + $self->{po}{$msgid}{'type'} = $type; + $self->{po}{$msgid}{'plural'} = $entry{'plural'} + if defined $entry{'plural'}; + + if (defined($flags)) { + $flags = " $flags "; + $flags =~ s/,/ /g; + foreach my $flag (@known_flags) { + if ($flags =~ /\s$flag\s/) { # if flag to be set + unless ( defined($self->{po}{$msgid}{'flags'}) + && $self->{po}{$msgid}{'flags'} =~ /\b$flag\b/) { + # flag not already set + if (defined $self->{po}{$msgid}{'flags'}) { + $self->{po}{$msgid}{'flags'} .= " ".$flag; + } else { + $self->{po}{$msgid}{'flags'} = $flag; + } + } + } + } + } +# print STDERR "stored ((($msgid)))=>(((".$self->{po}{$msgid}{'msgstr'}.")))\n\n"; + +} + +=back + +=head1 Miscellaneous functions + +=over 4 + +=item count_entries() + +Returns the number of entries in the catalog (without the header). + +=cut + +sub count_entries($) { + my $self=shift; + return $self->{count}; +} + +=item count_entries_doc() + +Returns the number of entries in document. If a string appears multiple times +in the document, it will be counted multiple times + +=cut + +sub count_entries_doc($) { + my $self=shift; + return $self->{count_doc}; +} + +=item msgid($) + +Returns the msgid of the given number. + +=cut + +sub msgid($$) { + my $self=shift; + my $num=shift; + + foreach my $msgid ( keys %{$self->{po}} ) { + return $msgid if ($self->{po}{$msgid}{'pos'} eq $num); + } + return undef; +} + +=item msgid_doc($) + +Returns the msgid with the given position in the document. + +=cut + +sub msgid_doc($$) { + my $self=shift; + my $num=shift; + + foreach my $msgid ( keys %{$self->{po}} ) { + foreach my $pos (split / /, $self->{po}{$msgid}{'pos_doc'}) { + return $msgid if ($pos eq $num); + } + } + return undef; +} + +=item get_charset() + +Returns the character set specified in the po header. If it hasn't been +set, it will return "CHARSET". + +=cut + +sub get_charset() { + my $self=shift; + + $self->{header} =~ /charset=(.*?)[\s\\]/; + + if (defined $1) { + return $1; + } else { + return "CHARSET"; + } +} + +=item set_charset($) + +This sets the character set of the po header to the value specified in its +first argument. If you never call this function (and no file with a specified +character set is read), the default value is left to "CHARSET". This value +doesn't change the behavior of this module, it's just used to fill that field +in the header, and to return it in get_charset(). + +=cut + +sub set_charset() { + my $self=shift; + + my ($newchar,$oldchar); + $newchar = shift; + $oldchar = $self->get_charset(); + + $self->{header} =~ s/$oldchar/$newchar/; + $self->{encoder}=find_encoding($newchar); +} + +#----[ helper functions ]--------------------------------------------------- + +# transforme the string from its po file representation to the form which +# should be used to print it +sub unescape_text { + my $text = shift; + + print STDERR "\nunescape [$text]====" if $debug{'escape'}; + $text = join("",split(/\n/,$text)); + $text =~ s/\\"/"/g; + # unescape newlines + # NOTE on \G: + # The following regular expression introduce newlines. + # Thus, ^ doesn't match all beginnings of lines. + # \G is a zero-width assertion that matches the position + # of the previous substitution with s///g. As every + # substitution ends by a newline, it always matches a + # position just after a newline. + $text =~ s/( # $1: + (\G|[^\\]) # beginning of the line or any char + # different from '\' + (\\\\)* # followed by any even number of '\' + )\\n # and followed by an escaped newline + /$1\n/sgx; # single string, match globally, allow comments + # unescape tabulations + $text =~ s/( # $1: + (\G|[^\\])# beginning of the line or any char + # different from '\' + (\\\\)* # followed by any even number of '\' + )\\t # and followed by an escaped tabulation + /$1\t/mgx; # multilines string, match globally, allow comments + # and unescape the escape character + $text =~ s/\\\\/\\/g; + print STDERR ">$text<\n" if $debug{'escape'}; + + return $text; +} + +# transform the string to its representation as it should be written in po +# files +sub escape_text { + my $text = shift; + + print STDERR "\nescape [$text]====" if $debug{'escape'}; + $text =~ s/\\/\\\\/g; + $text =~ s/"/\\"/g; + $text =~ s/\n/\\n/g; + $text =~ s/\t/\\t/g; + print STDERR ">$text<\n" if $debug{'escape'}; + + return $text; +} + +# put quotes around the string on each lines (without escaping it) +# It does also normalize the text (ie, make sure its representation is wraped +# on the 80th char, but without changing the meaning of the string) +sub quote_text { + my $string = shift; + + return '""' unless defined($string) && length($string); + + print STDERR "\nquote [$string]====" if $debug{'quote'}; + # break lines on newlines, if any + # see unescape_text for an explanation on \G + $string =~ s/( # $1: + (\G|[^\\]) # beginning of the line or any char + # different from '\' + (\\\\)* # followed by any even number of '\' + \\n) # and followed by an escaped newline + /$1\n/sgx; # single string, match globally, allow comments + $string = wrap($string); + my @string = split(/\n/,$string); + $string = join ("\"\n\"",@string); + $string = "\"$string\""; + if (scalar @string > 1 && $string[0] ne '') { + $string = "\"\"\n".$string; + } + + print STDERR ">$string<\n" if $debug{'quote'}; + return $string; +} + +# undo the work of the quote_text function +sub unquote_text { + my $string = shift; + print STDERR "\nunquote [$string]====" if $debug{'quote'}; + $string =~ s/^""\\n//s; + $string =~ s/^"(.*)"$/$1/s; + $string =~ s/"\n"//gm; + # Note: an even number of '\' could precede \\n, but I could not build a + # document to test this + $string =~ s/([^\\])\\n\n/$1!!DUMMYPOPM!!/gm; + $string =~ s|!!DUMMYPOPM!!|\\n|gm; + print STDERR ">$string<\n" if $debug{'quote'}; + return $string; +} + +# canonize the string: write it on only one line, changing consecutive +# whitespace to only one space. +# Warning, it changes the string and should only be called if the string is +# plain text +sub canonize { + my $text=shift; + print STDERR "\ncanonize [$text]====" if $debug{'canonize'}; + $text =~ s/^ *//s; + $text =~ s/^[ \t]+/ /gm; + # if ($text eq "\n"), it messed up the first string (header) + $text =~ s/\n/ /gm if ($text ne "\n"); + $text =~ s/([.)]) +/$1 /gm; + $text =~ s/([^.)]) */$1 /gm; + $text =~ s/ *$//s; + print STDERR ">$text<\n" if $debug{'canonize'}; + return $text; +} + +# wraps the string. We don't use Text::Wrap since it mangles whitespace at +# the end of splited line +sub wrap { + my $text=shift; + return "0" if ($text eq '0'); + my $col=shift || 76; + my @lines=split(/\n/,"$text"); + my $res=""; + my $first=1; + while (defined(my $line=shift @lines)) { + if ($first && length($line) > $col - 10) { + unshift @lines,$line; + $first=0; + next; + } + if (length($line) > $col) { + my $pos=rindex($line," ",$col); + while (substr($line,$pos-1,1) eq '.' && $pos != -1) { + $pos=rindex($line," ",$pos-1); + } + if ($pos == -1) { + # There are no spaces in the first $col chars, pick-up the + # first space + $pos = index($line," "); + } + if ($pos != -1) { + my $end=substr($line,$pos+1); + $line=substr($line,0,$pos+1); + if ($end =~ s/^( +)//) { + $line .= $1; + } + unshift @lines,$end; + } + } + $first=0; + $res.="$line\n"; + } + # Restore the original trailing spaces + $res =~ s/\s+$//s; + if ($text =~ m/(\s+)$/s) { + $res .= $1; + } + return $res; +} + +# outputs properly a '# ... ' line to be put in the po file +sub format_comment { + my $comment=shift; + my $char=shift; + my $result = "#". $char . $comment; + $result =~ s/\n/\n#$char/gs; + $result =~ s/^#$char$/#/gm; + $result .= "\n"; + return $result; +} + + +1; +__END__ + +=back + +=head1 AUTHORS + + Denis Barbier <barbier@linuxfr.org> + Martin Quinson (mquinson#debian.org) + +=cut diff -r 9e8e5292acaa -r 1c13ed2130a7 tools/po4a/lib/Locale/Po4a/TransTractor.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/po4a/lib/Locale/Po4a/TransTractor.pm Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,1100 @@ +#!/usr/bin/perl -w + +require Exporter; + +package Locale::Po4a::TransTractor; +use DynaLoader; + +use 5.006; +use strict; +use warnings; + +use subs qw(makespace); +use vars qw($VERSION @ISA @EXPORT); +$VERSION="0.36"; +@ISA = qw(DynaLoader); +@EXPORT = qw(new process translate + read write readpo writepo + getpoout setpoout); + +# Try to use a C extension if present. +eval("bootstrap Locale::Po4a::TransTractor $VERSION"); + +use Carp qw(croak); +use Locale::Po4a::Po; +use Locale::Po4a::Common; + +use File::Path; # mkdir before write + +use Encode; +use Encode::Guess; + +=head1 NAME + +Locale::Po4a::TransTractor - Generic trans(lator ex)tractor. + +=head1 DESCRIPTION + +The po4a (po for anything) project goal is to ease translations (and more +interestingly, the maintenance of translations) using gettext tools on +areas where they were not expected like documentation. + +This class is the ancestor of every po4a parsers used to parse a document to +search translatable strings, extract them to a po file and replace them by +their translation in the output document. + +More formally, it takes the following arguments as input: + +=over 2 + +=item - + +a document to translate ; + +=item - + +a po file containing the translations to use. + +=back + +As output, it produces: + +=over 2 + +=item - + +another po file, resulting of the extraction of translatable strings from +the input document ; + +=item - + +a translated document, with the same structure than the one in input, but +with all translatable strings replaced with the translations found in the +po file provided in input. + +=back + +Here is a graphical representation of this: + + Input document --\ /---> Output document + \ / (translated) + +-> parse() function -----+ + / \ + Input po --------/ \---> Output po + (extracted) + +=head1 FUNCTIONS YOUR PARSER SHOULD OVERRIDE + +=over 4 + +=item parse() + +This is where all the work takes place: the parsing of input documents, the +generation of output, and the extraction of the translatable strings. This +is pretty simple using the provided functions presented in the section +"INTERNAL FUNCTIONS" below. See also the synopsis, which present an +example. + +This function is called by the process() function bellow, but if you choose +to use the new() function, and to add content manually to your document, +you will have to call this function yourself. + +=item docheader() + +This function returns the header we should add to the produced document, +quoted properly to be a comment in the target language. See the section +"Educating developers about translations", from L<po4a(7)|po4a.7>, for what +it is good for. + +=back + +=cut + +sub docheader {} + +sub parse {} + +=head1 SYNOPSIS + +The following example parses a list of paragraphs beginning with "<p>". For the sake +of simplicity, we assume that the document is well formatted, i.e. that '<p>' +tags are the only tags present, and that this tag is at the very beginning +of each paragraph. + + sub parse { + my $self = shift; + + PARAGRAPH: while (1) { + my ($paragraph,$pararef)=("",""); + my $first=1; + my ($line,$lref)=$self->shiftline(); + while (defined($line)) { + if ($line =~ m/<p>/ && !$first--; ) { + # Not the first time we see <p>. + # Reput the current line in input, + # and put the built paragraph to output + $self->unshiftline($line,$lref); + + # Now that the document is formed, translate it: + # - Remove the leading tag + $paragraph =~ s/^<p>//s; + + # - push to output the leading tag (untranslated) and the + # rest of the paragraph (translated) + $self->pushline( "<p>" + . $document->translate($paragraph,$pararef) + ); + + next PARAGRAPH; + } else { + # Append to the paragraph + $paragraph .= $line; + $pararef = $lref unless(length($pararef)); + } + + # Reinit the loop + ($line,$lref)=$self->shiftline(); + } + # Did not get a defined line? End of input file. + return; + } + } + +Once you've implemented the parse function, you can use your document +class, using the public interface presented in the next section. + +=head1 PUBLIC INTERFACE for scripts using your parser + +=head2 Constructor + +=over 4 + +=item process(%) + +This function can do all you need to do with a po4a document in one +invocation. Its arguments must be packed as a hash. ACTIONS: + +=over 3 + +=item a. + +Reads all the po files specified in po_in_name + +=item b. + +Reads all original documents specified in file_in_name + +=item c. + +Parses the document + +=item d. + +Reads and applies all the addenda specified + +=item e. + +Writes the translated document to file_out_name (if given) + +=item f. + +Writes the extracted po file to po_out_name (if given) + +=back + +ARGUMENTS, beside the ones accepted by new() (with expected type): + +=over 4 + +=item file_in_name (@) + +List of filenames where we should read the input document. + +=item file_in_charset ($) + +Charset used in the input document (if it isn't specified, it will try +to detect it from the input document). + +=item file_out_name ($) + +Filename where we should write the output document. + +=item file_out_charset ($) + +Charset used in the output document (if it isn't specified, it will use +the po file charset). + +=item po_in_name (@) + +List of filenames where we should read the input po files from, containing +the translation which will be used to translate the document. + +=item po_out_name ($) + +Filename where we should write the output po file, containing the strings +extracted from the input document. + +=item addendum (@) + +List of filenames where we should read the addenda from. + +=item addendum_charset ($) + +Charset for the addenda. + +=back + +=item new(%) + +Create a new Po4a document. Accepted options (but be in a hash): + +=over 4 + +=item verbose ($) + +Sets the verbosity. + +=item debug ($) + +Sets the debugging. + +=back + +=cut + +sub process { + ## Determine if we were called via an object-ref or a classname + my $self = shift; + + ## Any remaining arguments are treated as initial values for the + ## hash that is used to represent this object. + my %params = @_; + + # Build the args for new() + my %newparams = (); + foreach (keys %params) { + next if ($_ eq 'po_in_name' || + $_ eq 'po_out_name' || + $_ eq 'file_in_name' || + $_ eq 'file_in_charset' || + $_ eq 'file_out_name' || + $_ eq 'file_out_charset' || + $_ eq 'addendum' || + $_ eq 'addendum_charset'); + $newparams{$_}=$params{$_}; + } + + $self->detected_charset($params{'file_in_charset'}); + $self->{TT}{'file_out_charset'}=$params{'file_out_charset'}; + if (defined($self->{TT}{'file_out_charset'}) and + length($self->{TT}{'file_out_charset'})) { + $self->{TT}{'file_out_encoder'} = find_encoding($self->{TT}{'file_out_charset'}); + } + $self->{TT}{'addendum_charset'}=$params{'addendum_charset'}; + + foreach my $file (@{$params{'po_in_name'}}) { + print STDERR "readpo($file)... " if $self->debug(); + $self->readpo($file); + print STDERR "done.\n" if $self->debug() + } + foreach my $file (@{$params{'file_in_name'}}) { + print STDERR "read($file)..." if $self->debug(); + $self->read($file); + print STDERR "done.\n" if $self->debug(); + } + print STDERR "parse..." if $self->debug(); + $self->parse(); + print STDERR "done.\n" if $self->debug(); + foreach my $file (@{$params{'addendum'}}) { + print STDERR "addendum($file)..." if $self->debug(); + $self->addendum($file) || die "An addendum failed\n"; + print STDERR "done.\n" if $self->debug(); + } + if (defined $params{'file_out_name'}) { + print STDERR "write(".$params{'file_out_name'}.")... " + if $self->debug(); + $self->write($params{'file_out_name'}); + print STDERR "done.\n" if $self->debug(); + } + if (defined $params{'po_out_name'}) { + print STDERR "writepo(".$params{'po_out_name'}.")... " + if $self->debug(); + $self->writepo($params{'po_out_name'}); + print STDERR "done.\n" if $self->debug(); + } + return $self; +} + +sub new { + ## Determine if we were called via an object-ref or a classname + my $this = shift; + my $class = ref($this) || $this; + my $self = { }; + my %options=@_; + ## Bless ourselves into the desired class and perform any initialization + bless $self, $class; + + ## initialize the plugin + # prevent the plugin from croaking on the options intended for Po.pm + $self->{options}{'porefs'} = ''; + # let the plugin parse the options and such + $self->initialize(%options); + + ## Create our private data + my %po_options; + $po_options{'porefs'} = $self->{options}{'porefs'}; + + # private data + $self->{TT}=(); + $self->{TT}{po_in}=Locale::Po4a::Po->new(); + $self->{TT}{po_out}=Locale::Po4a::Po->new(\%po_options); + # Warning, this is an array of array: + # The document is splited on lines, and for each + # [0] is the line content, [1] is the reference [2] the type + $self->{TT}{doc_in}=(); + $self->{TT}{doc_out}=(); + if (defined $options{'verbose'}) { + $self->{TT}{verbose} = $options{'verbose'}; + } + if (defined $options{'debug'}) { + $self->{TT}{debug} = $options{'debug'}; + } + # Input document is in ascii until we prove the opposite (in read()) + $self->{TT}{ascii_input}=1; + # We try not to use utf unless it's forced from the outside (in case the + # document isn't in ascii) + $self->{TT}{utf_mode}=0; + + + return $self; +} + +=back + +=head2 Manipulating document files + +=over 4 + +=item read($) + +Add another input document at the end of the existing one. The argument is +the filename to read. + +Please note that it does not parse anything. You should use the parse() +function when you're done with packing input files into the document. + +=cut + +#' +sub read() { + my $self=shift; + my $filename=shift + or croak wrap_msg(dgettext("po4a", "Can't read from file without having a filename")); + my $linenum=0; + + open INPUT,"<$filename" + or croak wrap_msg(dgettext("po4a", "Can't read from %s: %s"), $filename, $!); + while (defined (my $textline = <INPUT>)) { + $linenum++; + my $ref="$filename:$linenum"; + my @entry=($textline,$ref); + push @{$self->{TT}{doc_in}}, @entry; + + if (!defined($self->{TT}{'file_in_charset'})) { + # Detect if this file has non-ascii characters + if($self->{TT}{ascii_input}) { + my $decoder = guess_encoding($textline); + if (!ref($decoder) or $decoder !~ /Encode::XS=/) { + # We have detected a non-ascii line + $self->{TT}{ascii_input} = 0; + # Save the reference for future error message + $self->{TT}{non_ascii_ref} ||= $ref; + } + } + } + } + close INPUT + or croak wrap_msg(dgettext("po4a", "Can't close %s after reading: %s"), $filename, $!); + +} + +=item write($) + +Write the translated document to the given filename. + +=cut + +sub write { + my $self=shift; + my $filename=shift + or croak wrap_msg(dgettext("po4a", "Can't write to a file without filename")); + + my $fh; + if ($filename eq '-') { + $fh=\*STDOUT; + } else { + # make sure the directory in which we should write the localized file exists + my $dir = $filename; + if ($dir =~ m|/|) { + $dir =~ s|/[^/]*$||; + + File::Path::mkpath($dir, 0, 0755) # Croaks on error + if (length ($dir) && ! -e $dir); + } + open $fh,">$filename" + or croak wrap_msg(dgettext("po4a", "Can't write to %s: %s"), $filename, $!); + } + + map { print $fh $_ } $self->docheader(); + map { print $fh $_ } @{$self->{TT}{doc_out}}; + + if ($filename ne '-') { + close $fh or croak wrap_msg(dgettext("po4a", "Can't close %s after writing: %s"), $filename, $!); + } + +} + +=back + +=head2 Manipulating po files + +=over 4 + +=item readpo($) + +Add the content of a file (which name is passed in argument) to the +existing input po. The old content is not discarded. + +=item writepo($) + +Write the extracted po file to the given filename. + +=item stats() + +Returns some statistics about the translation done so far. Please note that +it's not the same statistics than the one printed by msgfmt +--statistic. Here, it's stats about recent usage of the po file, while +msgfmt reports the status of the file. It is a wrapper to the +Locale::Po4a::Po::stats_get function applied to the input po file. Example +of use: + + [normal use of the po4a document...] + + ($percent,$hit,$queries) = $document->stats(); + print "We found translations for $percent\% ($hit from $queries) of strings.\n"; + +=back + +=cut + +sub getpoout { + return $_[0]->{TT}{po_out}; +} +sub setpoout { + $_[0]->{TT}{po_out} = $_[1]; +} +sub readpo { + $_[0]->{TT}{po_in}->read($_[1]); +} +sub writepo { + $_[0]->{TT}{po_out}->write( $_[1] ); +} +sub stats { + return $_[0]->{TT}{po_in}->stats_get(); +} + +=head2 Manipulating addenda + +=over 4 + +=item addendum($) + +Please refer to L<po4a(7)|po4a.7> for more information on what addenda are, +and how translators should write them. To apply an addendum to the translated +document, simply pass its filename to this function and you are done ;) + +This function returns a non-null integer on error. + +=cut + +# Internal function to read the header. +sub addendum_parse { + my ($filename,$header)=shift; + + my ($errcode,$mode,$position,$boundary,$bmode,$content)= + (1,"","","","",""); + + unless (open (INS, "<$filename")) { + warn wrap_msg(dgettext("po4a", "Can't read from %s: %s"), $filename, $!); + goto END_PARSE_ADDFILE; + } + + unless (defined ($header=<INS>) && $header) { + warn wrap_msg(dgettext("po4a", "Can't read Po4a header from %s."), $filename); + goto END_PARSE_ADDFILE; + } + + unless ($header =~ s/PO4A-HEADER://i) { + warn wrap_msg(dgettext("po4a", "First line of %s does not look like a Po4a header."), $filename); + goto END_PARSE_ADDFILE; + } + foreach my $part (split(/;/,$header)) { + unless ($part =~ m/^\s*([^=]*)=(.*)$/) { + warn wrap_msg(dgettext("po4a", "Syntax error in Po4a header of %s, near \"%s\""), $filename, $part); + goto END_PARSE_ADDFILE; + } + my ($key,$value)=($1,$2); + $key=lc($key); + if ($key eq 'mode') { $mode=lc($value); + } elsif ($key eq 'position') { $position=$value; + } elsif ($key eq 'endboundary') { + $boundary=$value; + $bmode='after'; + } elsif ($key eq 'beginboundary') { + $boundary=$value; + $bmode='before'; + } else { + warn wrap_msg(dgettext("po4a", "Invalid argument in the Po4a header of %s: %s"), $filename, $key); + goto END_PARSE_ADDFILE; + } + } + + unless (length($mode)) { + warn wrap_msg(dgettext("po4a", "The Po4a header of %s does not define the mode."), $filename); + goto END_PARSE_ADDFILE; + } + unless ($mode eq "before" || $mode eq "after") { + warn wrap_msg(dgettext("po4a", "Mode invalid in the Po4a header of %s: should be 'before' or 'after' not %s."), $filename, $mode); + goto END_PARSE_ADDFILE; + } + + unless (length($position)) { + warn wrap_msg(dgettext("po4a", "The Po4a header of %s does not define the position."), $filename); + goto END_PARSE_ADDFILE; + } + unless ($mode eq "before" || length($boundary)) { + warn wrap_msg(dgettext("po4a", "No ending boundary given in the Po4a header, but mode=after.")); + goto END_PARSE_ADDFILE; + } + + while (defined(my $line = <INS>)) { + $content .= $line; + } + close INS; + + $errcode=0; + END_PARSE_ADDFILE: + return ($errcode,$mode,$position,$boundary,$bmode,$content); +} + +sub mychomp { + my ($str) = shift; + chomp($str); + return $str; +} + +sub addendum { + my ($self,$filename) = @_; + + print STDERR "Apply addendum $filename..." if $self->debug(); + unless ($filename) { + warn wrap_msg(dgettext("po4a", + "Can't apply addendum when not given the filename")); + return 0; + } + die wrap_msg(dgettext("po4a", "Addendum %s does not exist."), $filename) + unless -e $filename; + + my ($errcode,$mode,$position,$boundary,$bmode,$content)= + addendum_parse($filename); + return 0 if ($errcode); + + print STDERR "mode=$mode;pos=$position;bound=$boundary;bmode=$bmode;ctn=$content\n" + if $self->debug(); + + # We only recode the addendum if an origin charset is specified, else we + # suppose it's already in the output document's charset + if (defined($self->{TT}{'addendum_charset'}) && + length($self->{TT}{'addendum_charset'})) { + Encode::from_to($content,$self->{TT}{'addendum_charset'}, + $self->get_out_charset); + } + + my $found = scalar grep { /$position/ } @{$self->{TT}{doc_out}}; + if ($found == 0) { + warn wrap_msg(dgettext("po4a", + "No candidate position for the addendum %s."), $filename); + return 0; + } + if ($found > 1) { + warn wrap_msg(dgettext("po4a", + "More than one candidate position found for the addendum %s."), $filename); + return 0; + } + + if ($mode eq "before") { + if ($self->verbose() > 1 || $self->debug() ) { + map { print STDERR wrap_msg(dgettext("po4a", "Addendum '%s' applied before this line: %s"), $filename, $_) if (/$position/); + } @{$self->{TT}{doc_out}}; + } + @{$self->{TT}{doc_out}} = map { /$position/ ? ($content,$_) : $_ + } @{$self->{TT}{doc_out}}; + } else { + my @newres=(); + + do { + # make sure it doesnt whine on empty document + my $line = scalar @{$self->{TT}{doc_out}} ? shift @{$self->{TT}{doc_out}} : ""; + push @newres,$line; + my $outline=mychomp($line); + $outline =~ s/^[ \t]*//; + + if ($line =~ m/$position/) { + while ($line=shift @{$self->{TT}{doc_out}}) { + last if ($line=~/$boundary/); + push @newres,$line; + } + if (defined $line) { + if ($bmode eq 'before') { + print wrap_msg(dgettext("po4a", + "Addendum '%s' applied before this line: %s"), + $filename, $outline) + if ($self->verbose() > 1 || $self->debug()); + push @newres,$content; + push @newres,$line; + } else { + print wrap_msg(dgettext("po4a", + "Addendum '%s' applied after the line: %s."), + $filename, $outline) + if ($self->verbose() > 1 || $self->debug()); + push @newres,$line; + push @newres,$content; + } + } else { + print wrap_msg(dgettext("po4a", "Addendum '%s' applied at the end of the file."), $filename) + if ($self->verbose() > 1 || $self->debug()); + push @newres,$content; + } + } + } while (scalar @{$self->{TT}{doc_out}}); + @{$self->{TT}{doc_out}} = @newres; + } + print STDERR "done.\n" if $self->debug(); + return 1; +} + +=back + +=head1 INTERNAL FUNCTIONS used to write derivated parsers + +=head2 Getting input, providing output + +Four functions are provided to get input and return output. They are very +similar to shift/unshift and push/pop. The first pair is about input, while +the second is about output. Mnemonic: in input, you are interested in the +first line, what shift gives, and in output you want to add your result at +the end, like push does. + +=over 4 + +=item shiftline() + +This function returns the next line of the doc_in to be parsed and its +reference (packed as an array). + +=item unshiftline($$) + +Unshifts a line of the input document and its reference. + +=item pushline($) + +Push a new line to the doc_out. + +=item popline() + +Pop the last pushed line from the doc_out. + +=back + +=cut + +sub shiftline { + my ($line,$ref)=(shift @{$_[0]->{TT}{doc_in}}, + shift @{$_[0]->{TT}{doc_in}}); + return ($line,$ref); +} +sub unshiftline { + my $self = shift; + unshift @{$self->{TT}{doc_in}},@_; +} + +sub pushline { push @{$_[0]->{TT}{doc_out}}, $_[1] if defined $_[1]; } +sub popline { return pop @{$_[0]->{TT}{doc_out}}; } + +=head2 Marking strings as translatable + +One function is provided to handle the text which should be translated. + +=over 4 + +=item translate($$$) + +Mandatory arguments: + +=over 2 + +=item - + +A string to translate + +=item - + +The reference of this string (ie, position in inputfile) + +=item - + +The type of this string (ie, the textual description of its structural role +; used in Locale::Po4a::Po::gettextization() ; see also L<po4a(7)|po4a.7>, +section I<Gettextization: how does it work?>) + +=back + +This function can also take some extra arguments. They must be organized as +a hash. For example: + + $self->translate("string","ref","type", + 'wrap' => 1); + +=over + +=item wrap + +boolean indicating whether we can consider that whitespaces in string are +not important. If yes, the function canonizes the string before looking for +a translation or extracting it, and wraps the translation. + +=item wrapcol + +The column at which we should wrap (default: 76). + +=item comment + +An extra comment to add to the entry. + +=back + +Actions: + +=over 2 + +=item - + +Pushes the string, reference and type to po_out. + +=item - + +Returns the translation of the string (as found in po_in) so that the +parser can build the doc_out. + +=item - + +Handles the charsets to recode the strings before sending them to +po_out and before returning the translations. + +=back + +=back + +=cut + +sub translate { + my $self=shift; + my ($string,$ref,$type)=(shift,shift,shift); + my (%options)=@_; + + # my $validoption="wrap wrapcol"; + # my %validoption; + + return "" unless defined($string) && length($string); + + # map { $validoption{$_}=1 } (split(/ /,$validoption)); + # foreach (keys %options) { + # Carp::confess "internal error: translate() called with unknown arg $_. Valid options: $validoption" + # unless $validoption{$_}; + # } + + my $in_charset; + if ($self->{TT}{ascii_input}) { + $in_charset = "ascii"; + } else { + if (defined($self->{TT}{'file_in_charset'}) and + length($self->{TT}{'file_in_charset'}) and + $self->{TT}{'file_in_charset'} !~ m/ascii/i) { + $in_charset=$self->{TT}{'file_in_charset'}; + } else { + # FYI, the document charset have to be determined *before* we see the first + # string to recode. + die wrap_mod("po4a", dgettext("po4a", "Couldn't determine the input document's charset. Please specify it on the command line. (non-ascii char at %s)"), $self->{TT}{non_ascii_ref}) + } + } + + if ($self->{TT}{po_in}->get_charset ne "CHARSET") { + $string = encode_from_to($string, + $self->{TT}{'file_in_encoder'}, + $self->{TT}{po_in}{encoder}); + } + + if (defined $options{'wrapcol'} && $options{'wrapcol'} < 0) { +# FIXME: should be the parameter given with --width + $options{'wrapcol'} = 76 + $options{'wrapcol'}; + } + my $transstring = $self->{TT}{po_in}->gettext($string, + 'wrap' => $options{'wrap'}||0, + 'wrapcol' => $options{'wrapcol'}); + + if ($self->{TT}{po_in}->get_charset ne "CHARSET") { + my $out_encoder = $self->{TT}{'file_out_encoder'}; + unless (defined $out_encoder) { + $out_encoder = find_encoding($self->get_out_charset) + } + $transstring = encode_from_to($transstring, + $self->{TT}{po_in}{encoder}, + $out_encoder); + } + + # If the input document isn't completely in ascii, we should see what to + # do with the current string + unless ($self->{TT}{ascii_input}) { + my $out_charset = $self->{TT}{po_out}->get_charset; + # We set the output po charset + if ($out_charset eq "CHARSET") { + if ($self->{TT}{utf_mode}) { + $out_charset="utf-8"; + } else { + $out_charset=$in_charset; + } + $self->{TT}{po_out}->set_charset($out_charset); + } + if ( $in_charset !~ /^$out_charset$/i ) { + Encode::from_to($string,$in_charset,$out_charset); + if (defined($options{'comment'}) and length($options{'comment'})) { + Encode::from_to($options{'comment'},$in_charset,$out_charset); + } + } + } + + # the comments provided by the modules are automatic comments from the PO point of view + $self->{TT}{po_out}->push('msgid' => $string, + 'reference' => $ref, + 'type' => $type, + 'automatic' => $options{'comment'}, + 'wrap' => $options{'wrap'}||0, + 'wrapcol' => $options{'wrapcol'}); + +# if ($self->{TT}{po_in}->get_charset ne "CHARSET") { +# Encode::from_to($transstring,$self->{TT}{po_in}->get_charset, +# $self->get_out_charset); +# } + + if ($options{'wrap'}||0) { + $transstring =~ s/( *)$//s; + my $trailing_spaces = $1||""; + $transstring =~ s/ *$//gm; + $transstring .= $trailing_spaces; + } + + return $transstring; +} + +=head2 Misc functions + +=over 4 + +=item verbose() + +Returns if the verbose option was passed during the creation of the +TransTractor. + +=cut + +sub verbose { + if (defined $_[1]) { + $_[0]->{TT}{verbose} = $_[1]; + } else { + return $_[0]->{TT}{verbose} || 0; # undef and 0 have the same meaning, but one generates warnings + } +} + +=item debug() + +Returns if the debug option was passed during the creation of the +TransTractor. + +=cut + +sub debug { + return $_[0]->{TT}{debug}; +} + +=item detected_charset($) + +This tells TransTractor that a new charset (the first argument) has been +detected from the input document. It can usually be read from the document +header. Only the first charset will remain, coming either from the +process() arguments or detected from the document. + +=cut + +sub detected_charset { + my ($self,$charset)=(shift,shift); + unless (defined($self->{TT}{'file_in_charset'}) and + length($self->{TT}{'file_in_charset'}) ) { + $self->{TT}{'file_in_charset'}=$charset; + if (defined $charset) { + $self->{TT}{'file_in_encoder'}=find_encoding($charset); + } + } + + if (defined $self->{TT}{'file_in_charset'} and + length $self->{TT}{'file_in_charset'} and + $self->{TT}{'file_in_charset'} !~ m/ascii/i) { + $self->{TT}{ascii_input}=0; + } +} + +=item get_out_charset() + +This function will return the charset that should be used in the output +document (usually useful to substitute the input document's detected charset +where it has been found). + +It will use the output charset specified in the command line. If it wasn't +specified, it will use the input po's charset, and if the input po has the +default "CHARSET", it will return the input document's charset, so that no +encoding is performed. + +=cut + +sub get_out_charset { + my $self=shift; + my $charset; + + # Use the value specified at the command line + if (defined($self->{TT}{'file_out_charset'}) and + length($self->{TT}{'file_out_charset'})) { + $charset=$self->{TT}{'file_out_charset'}; + } else { + if ($self->{TT}{utf_mode} && $self->{TT}{ascii_input}) { + $charset="utf-8"; + } else { + $charset=$self->{TT}{po_in}->get_charset; + $charset=$self->{TT}{'file_in_charset'} + if $charset eq "CHARSET" and + defined($self->{TT}{'file_in_charset'}) and + length($self->{TT}{'file_in_charset'}); + $charset="ascii" + if $charset eq "CHARSET"; + } + } + return $charset; +} + +=item recode_skipped_text($) + +This function returns the recoded text passed as argument, from the input +document's charset to the output document's one. This isn't needed when +translating a string (translate() recodes everything itself), but it is when +you skip a string from the input document and you want the output document to +be consistent with the global encoding. + +=cut + +sub recode_skipped_text { + my ($self,$text)=(shift,shift); + unless ($self->{TT}{'ascii_input'}) { + if(defined($self->{TT}{'file_in_charset'}) and + length($self->{TT}{'file_in_charset'}) ) { + $text = encode_from_to($text, + $self->{TT}{'file_in_encoder'}, + find_encoding($self->get_out_charset)); + } else { + die wrap_mod("po4a", dgettext("po4a", "Couldn't determine the input document's charset. Please specify it on the command line. (non-ascii char at %s)"), $self->{TT}{non_ascii_ref}) + } + } + return $text; +} + + +# encode_from_to($,$,$) +# +# Encode the given text from one encoding to another one. +# It differs from Encode::from_to because it does not take the name of the +# encoding in argument, but the encoders (as returned by the +# Encode::find_encoding(<name>) method). Thus it permits to save a bunch +# of call to find_encoding. +# +# If the "from" encoding is undefined, it is considered as UTF-8 (or +# ascii). +# If the "to" encoding is undefined, it is considered as UTF-8. +# +sub encode_from_to { + my ($text,$from,$to) = (shift,shift,shift); + + if (not defined $from) { + # for ascii and UTF-8, no conversion needed to get an utf-8 + # string. + } else { + $text = $from->decode($text, 0); + } + + if (not defined $to) { + # Already in UTF-8, no conversion needed + } else { + $text = $to->encode($text, 0); + } + + return $text; +} + +=back + +=head1 FUTURE DIRECTIONS + +One shortcoming of the current TransTractor is that it can't handle +translated document containing all languages, like debconf templates, or +.desktop files. + +To address this problem, the only interface changes needed are: + +=over 2 + +=item - + +take a hash as po_in_name (a list per language) + +=item - + +add an argument to translate to indicate the target language + +=item - + +make a pushline_all function, which would make pushline of its content for +all language, using a map-like syntax: + + $self->pushline_all({ "Description[".$langcode."]=". + $self->translate($line,$ref,$langcode) + }); + +=back + +Will see if it's enough ;) + +=head1 AUTHORS + + Denis Barbier <barbier@linuxfr.org> + Martin Quinson (mquinson#debian.org) + Jordi Vilalta <jvprat@gmail.com> + +=cut + +1; diff -r 9e8e5292acaa -r 1c13ed2130a7 tools/po4a/lib/Locale/Po4a/Xml.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/po4a/lib/Locale/Po4a/Xml.pm Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,1973 @@ +#!/usr/bin/perl + +# Po4a::Xml.pm +# +# extract and translate translatable strings from XML documents. +# +# This code extracts plain text from tags and attributes from generic +# XML documents, and it can be used as a base to build modules for +# XML-based documents. +# +# Copyright (c) 2004 by Jordi Vilalta <jvprat@gmail.com> +# Copyright (c) 2008-2009 by Nicolas François <nicolas.francois@centraliens.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +######################################################################## + +=head1 NAME + +Locale::Po4a::Xml - Convert XML documents and derivates from/to PO files + +=head1 DESCRIPTION + +The po4a (po for anything) project goal is to ease translations (and more +interestingly, the maintenance of translations) using gettext tools on +areas where they were not expected like documentation. + +Locale::Po4a::Xml is a module to help the translation of XML documents into +other [human] languages. It can also be used as a base to build modules for +XML-based documents. + +=cut + +package Locale::Po4a::Xml; + +use 5.006; +use strict; +use warnings; + +require Exporter; +use vars qw(@ISA @EXPORT); +@ISA = qw(Locale::Po4a::TransTractor); +@EXPORT = qw(new initialize @tag_types); + +use Locale::Po4a::TransTractor; +use Locale::Po4a::Common; +use Carp qw(croak); +use File::Basename; +use File::Spec; + +#It will mantain the path from the root tag to the current one +my @path; + +#It will contain a list of external entities and their attached paths +my %entities; + +my @comments; + +sub shiftline { + my $self = shift; + # call Transtractor's shiftline + my ($line,$ref) = $self->SUPER::shiftline(); + return ($line,$ref) if (not defined $line); + + for my $k (keys %entities) { + if ($line =~ m/^(.*?)&$k;(.*)$/s) { + my ($before, $after) = ($1, $2); + my $linenum=0; + my @textentries; + + open (my $in, $entities{$k}) + or croak wrap_mod("po4a::xml", + dgettext("po4a", "Can't read from %s: %s"), + $entities{$k}, $!); + while (defined (my $textline = <$in>)) { + $linenum++; + my $textref=$entities{$k}.":$linenum"; + push @textentries, ($textline,$textref); + } + close $in + or croak wrap_mod("po4a::xml", + dgettext("po4a", "Can't close %s after reading: %s"), + $entities{$k}, $!); + + push @textentries, ($after, $ref); + $line = $before.(shift @textentries); + $ref .= " ".(shift @textentries); + $self->unshiftline(@textentries); + } + } + + return ($line,$ref); +} + +sub read { + my ($self,$filename)=@_; + push @{$self->{DOCPOD}{infile}}, $filename; + $self->Locale::Po4a::TransTractor::read($filename); +} + +sub parse { + my $self=shift; + map {$self->parse_file($_)} @{$self->{DOCPOD}{infile}}; +} + +# @save_holders is a stack of references to ('paragraph', 'translation', +# 'sub_translations', 'open', 'close', 'folded_attributes') hashes, where: +# paragraph is a reference to an array (see paragraph in the +# treat_content() subroutine) of strings followed by +# references. It contains the @paragraph array as it was +# before the processing was interrupted by a tag instroducing +# a placeholder. +# translation is the translation of this level up to now +# sub_translations is a reference to an array of strings containing the +# translations which must replace the placeholders. +# open is the tag which opened the placeholder. +# close is the tag which closed the placeholder. +# folded_attributes is an hash of tags with their attributes (<tag attrs=...> +# strings), referenced by the folded tag id, which should +# replace the <tag po4a-id=id> strings in the current +# translation. +# +# If @save_holders only has 1 holder, then we are not processing the +# content of an holder, we are translating the document. +my @save_holders; + + +# If we are at the bottom of the stack and there is no <placeholder ...> in +# the current translation, we can push the translation in the translated +# document. +# Otherwise, we keep the translation in the current holder. +sub pushline { + my ($self, $line) = (shift, shift); + + my $holder = $save_holders[$#save_holders]; + my $translation = $holder->{'translation'}; + $translation .= $line; + + while ( %{$holder->{folded_attributes}} + and $translation =~ m/^(.*)<([^>]+?)\s+po4a-id=([0-9]+)>(.*)$/s) { + my $begin = $1; + my $tag = $2; + my $id = $3; + my $end = $4; + if (defined $holder->{folded_attributes}->{$id}) { + # TODO: check if the tag is the same + $translation = $begin.$holder->{folded_attributes}->{$id}.$end; + delete $holder->{folded_attributes}->{$id}; + } else { + # TODO: It will be hard to identify the location. + # => find a way to retrieve the reference. + die wrap_mod("po4a::xml", dgettext("po4a", "'po4a-id=%d' in the translation does not exist in the original string (or 'po4a-id=%d' used twice in the translation)."), $id, $id); + } + } +# TODO: check that %folded_attributes is empty at some time +# => in translate_paragraph? + + if ( ($#save_holders > 0) + or ($translation =~ m/<placeholder\s+type="[^"]+"\s+id="(\d+)"\s*\/>/s)) { + $holder->{'translation'} = $translation; + } else { + $self->SUPER::pushline($translation); + $holder->{'translation'} = ''; + } +} + +=head1 TRANSLATING WITH PO4A::XML + +This module can be used directly to handle generic XML documents. This will +extract all tag's content, and no attributes, since it's where the text is +written in most XML based documents. + +There are some options (described in the next section) that can customize +this behavior. If this doesn't fit to your document format you're encouraged +to write your own module derived from this, to describe your format's details. +See the section "Writing derivate modules" below, for the process description. + +=cut + +# +# Parse file and translate it +# +sub parse_file { + my ($self,$filename) = @_; + my $eof = 0; + + while (!$eof) { + # We get all the text until the next breaking tag (not + # inline) and translate it + $eof = $self->treat_content; + if (!$eof) { + # And then we treat the following breaking tag + $eof = $self->treat_tag; + } + } +} + +=head1 OPTIONS ACCEPTED BY THIS MODULE + +The global debug option causes this module to show the excluded strings, in +order to see if it skips something important. + +These are this module's particular options: + +=over 4 + +=item B<nostrip> + +Prevents it to strip the spaces around the extracted strings. + +=item B<wrap> + +Canonizes the string to translate, considering that whitespaces are not +important, and wraps the translated document. This option can be overridden +by custom tag options. See the "tags" option below. + +=item B<caseinsensitive> + +It makes the tags and attributes searching to work in a case insensitive +way. If it's defined, it will treat E<lt>BooKE<gt>laNG and E<lt>BOOKE<gt>Lang as E<lt>bookE<gt>lang. + +=item B<includeexternal> + +When defined, external entities are included in the generated (translated) +document, and for the extraction of strings. If it's not defined, you +will have to translate external entities separately as independent +documents. + +=item B<ontagerror> + +This option defines the behavior of the module when it encounter a invalid +Xml syntax (a closing tag which does not match the last opening tag, or a +tag's attribute without value). +It can take the following values: + +=over + +=item I<fail> + +This is the default value. +The module will exit with an error. + +=item I<warn> + +The module will continue, and will issue a warning. + +=item I<silent> + +The module will continue without any warnings. + +=back + +Be careful when using this option. +It is generally recommended to fix the input file. + +=item B<tagsonly> + +Extracts only the specified tags in the "tags" option. Otherwise, it +will extract all the tags except the ones specified. + +Note: This option is deprecated. + +=item B<doctype> + +String that will try to match with the first line of the document's doctype +(if defined). If it doesn't, a warning will indicate that the document +might be of a bad type. + +=item B<tags> + +Space-separated list of tags you want to translate or skip. By default, +the specified tags will be excluded, but if you use the "tagsonly" option, +the specified tags will be the only ones included. The tags must be in the +form E<lt>aaaE<gt>, but you can join some (E<lt>bbbE<gt>E<lt>aaaE<gt>) to say that the content of +the tag E<lt>aaaE<gt> will only be translated when it's into a E<lt>bbbE<gt> tag. + +You can also specify some tag options putting some characters in front of +the tag hierarchy. For example, you can put 'w' (wrap) or 'W' (don't wrap) +to override the default behavior specified by the global "wrap" option. + +Example: WE<lt>chapterE<gt>E<lt>titleE<gt> + +Note: This option is deprecated. +You should use the B<translated> and B<untranslated> options instead. + +=item B<attributes> + +Space-separated list of tag's attributes you want to translate. You can +specify the attributes by their name (for example, "lang"), but you can +prefix it with a tag hierarchy, to specify that this attribute will only be +translated when it's into the specified tag. For example: E<lt>bbbE<gt>E<lt>aaaE<gt>lang +specifies that the lang attribute will only be translated if it's into an +E<lt>aaaE<gt> tag, and it's into a E<lt>bbbE<gt> tag. + +=item B<foldattributes> + +Do not translate attributes in inline tags. +Instead, replace all attributes of a tag by po4a-id=<id>. + +This is useful when attributes shall not be translated, as this simplifies the +strings for translators, and avoids typos. + +=item B<break> + +Space-separated list of tags which should break the sequence. +By default, all tags break the sequence. + +The tags must be in the form <aaa>, but you can join some +(<bbb><aaa>), if a tag (<aaa>) should only be considered +when it's into another tag (<bbb>). + +=item B<inline> + +Space-separated list of tags which should be treated as inline. +By default, all tags break the sequence. + +The tags must be in the form <aaa>, but you can join some +(<bbb><aaa>), if a tag (<aaa>) should only be considered +when it's into another tag (<bbb>). + +=item B<placeholder> + +Space-separated list of tags which should be treated as placeholders. +Placeholders do not break the sequence, but the content of placeholders is +translated separately. + +The location of the placeholder in its blocks will be marked with a string +similar to: + + <placeholder type=\"footnote\" id=\"0\"/> + +The tags must be in the form <aaa>, but you can join some +(<bbb><aaa>), if a tag (<aaa>) should only be considered +when it's into another tag (<bbb>). + +=item B<nodefault> + +Space separated list of tags that the module should not try to set by +default in any category. + +=item B<cpp> + +Support C preprocessor directives. +When this option is set, po4a will consider preprocessor directives as +paragraph separators. +This is important if the XML file must be preprocessed because otherwise +the directives may be inserted in the middle of lines if po4a consider it +belong to the current paragraph, and they won't be recognized by the +preprocessor. +Note: the preprocessor directives must only appear between tags +(they must not break a tag). + +=item B<translated> + +Space-separated list of tags you want to translate. + +The tags must be in the form <aaa>, but you can join some +(<bbb><aaa>), if a tag (<aaa>) should only be considered +when it's into another tag (<bbb>). + +You can also specify some tag options putting some characters in front of +the tag hierarchy. For example, you can put 'w' (wrap) or 'W' (don't wrap) +to overide the default behavior specified by the global "wrap" option. + +Example: WE<lt>chapterE<gt>E<lt>titleE<gt> + +=item B<untranslated> + +Space-separated list of tags you do not want to translate. + +The tags must be in the form <aaa>, but you can join some +(<bbb><aaa>), if a tag (<aaa>) should only be considered +when it's into another tag (<bbb>). + +=item B<defaulttranslateoption> + +The default categories for tags that are not in any of the translated, +untranslated, break, inline, or placeholder. + +This is a set of letters: + +=over + +=item I<w> + +Tags should be translated and content can be re-wrapped. + +=item I<W> + +Tags should be translated and content should not be re-wrapped. + +=item I<i> + +Tags should be translated inline. + +=item I<p> + +Tags should be translated as placeholders. + +=back + +=back + +=cut +# TODO: defaulttranslateoption +# w => indicate that it is only valid for translatable tags and do not +# care about inline/break/placeholder? +# ... + +sub initialize { + my $self = shift; + my %options = @_; + + # Reset the path + @path = (); + + # Initialize the stack of holders + my @paragraph = (); + my @sub_translations = (); + my %folded_attributes; + my %holder = ('paragraph' => \@paragraph, + 'translation' => "", + 'sub_translations' => \@sub_translations, + 'folded_attributes' => \%folded_attributes); + @save_holders = (\%holder); + + $self->{options}{'nostrip'}=0; + $self->{options}{'wrap'}=0; + $self->{options}{'caseinsensitive'}=0; + $self->{options}{'tagsonly'}=0; + $self->{options}{'tags'}=''; + $self->{options}{'break'}=''; + $self->{options}{'translated'}=''; + $self->{options}{'untranslated'}=''; + $self->{options}{'defaulttranslateoption'}=''; + $self->{options}{'attributes'}=''; + $self->{options}{'foldattributes'}=0; + $self->{options}{'inline'}=''; + $self->{options}{'placeholder'}=''; + $self->{options}{'doctype'}=''; + $self->{options}{'nodefault'}=''; + $self->{options}{'includeexternal'}=0; + $self->{options}{'ontagerror'}="fail"; + $self->{options}{'cpp'}=0; + + $self->{options}{'verbose'}=''; + $self->{options}{'debug'}=''; + + foreach my $opt (keys %options) { + if ($options{$opt}) { + die wrap_mod("po4a::xml", + dgettext("po4a", "Unknown option: %s"), $opt) + unless exists $self->{options}{$opt}; + $self->{options}{$opt} = $options{$opt}; + } + } + # Default options set by modules. Forbidden for users. + $self->{options}{'_default_translated'}=''; + $self->{options}{'_default_untranslated'}=''; + $self->{options}{'_default_break'}=''; + $self->{options}{'_default_inline'}=''; + $self->{options}{'_default_placeholder'}=''; + $self->{options}{'_default_attributes'}=''; + + #It will maintain the list of the translatable tags + $self->{tags}=(); + $self->{translated}=(); + $self->{untranslated}=(); + #It will maintain the list of the translatable attributes + $self->{attributes}=(); + #It will maintain the list of the breaking tags + $self->{break}=(); + #It will maintain the list of the inline tags + $self->{inline}=(); + #It will maintain the list of the placeholder tags + $self->{placeholder}=(); + #list of the tags that must not be set in the tags or inline category + #by this module or sub-module (unless specified in an option) + $self->{nodefault}=(); + + $self->treat_options; +} + +=head1 WRITING DERIVATE MODULES + +=head2 DEFINE WHAT TAGS AND ATTRIBUTES TO TRANSLATE + +The simplest customization is to define which tags and attributes you want +the parser to translate. This should be done in the initialize function. +First you should call the main initialize, to get the command-line options, +and then, append your custom definitions to the options hash. If you want +to treat some new options from command line, you should define them before +calling the main initialize: + + $self->{options}{'new_option'}=''; + $self->SUPER::initialize(%options); + $self->{options}{'_default_translated'}.=' <p> <head><title>'; + $self->{options}{'attributes'}.=' <p>lang id'; + $self->{options}{'_default_inline'}.=' <br>'; + $self->treat_options; + +You should use the B<_default_inline>, B<_default_break>, +B<_default_placeholder>, B<_default_translated>, B<_default_untranslated>, +and B<_default_attributes> options in derivated modules. This allow users +to override the default behavior defined in your module with command line +options. + +=head2 OVERRIDING THE found_string FUNCTION + +Another simple step is to override the function "found_string", which +receives the extracted strings from the parser, in order to translate them. +There you can control which strings you want to translate, and perform +transformations to them before or after the translation itself. + +It receives the extracted text, the reference on where it was, and a hash +that contains extra information to control what strings to translate, how +to translate them and to generate the comment. + +The content of these options depends on the kind of string it is (specified in an +entry of this hash): + +=over + +=item type="tag" + +The found string is the content of a translatable tag. The entry "tag_options" +contains the option characters in front of the tag hierarchy in the module +"tags" option. + +=item type="attribute" + +Means that the found string is the value of a translatable attribute. The +entry "attribute" has the name of the attribute. + +=back + +It must return the text that will replace the original in the translated +document. Here's a basic example of this function: + + sub found_string { + my ($self,$text,$ref,$options)=@_; + $text = $self->translate($text,$ref,"type ".$options->{'type'}, + 'wrap'=>$self->{options}{'wrap'}); + return $text; + } + +There's another simple example in the new Dia module, which only filters +some strings. + +=cut + +sub found_string { + my ($self,$text,$ref,$options)=@_; + + if ($text =~ m/^\s*$/s) { + return $text; + } + + my $comment; + my $wrap = $self->{options}{'wrap'}; + + if ($options->{'type'} eq "tag") { + $comment = "Content of: ".$self->get_path; + + if($options->{'tag_options'} =~ /w/) { + $wrap = 1; + } + if($options->{'tag_options'} =~ /W/) { + $wrap = 0; + } + } elsif ($options->{'type'} eq "attribute") { + $comment = "Attribute '".$options->{'attribute'}."' of: ".$self->get_path; + } elsif ($options->{'type'} eq "CDATA") { + $comment = "CDATA"; + $wrap = 0; + } else { + die wrap_ref_mod($ref, "po4a::xml", dgettext("po4a", "Internal error: unknown type identifier '%s'."), $options->{'type'}); + } + $text = $self->translate($text,$ref,$comment,'wrap'=>$wrap, comment => $options->{'comments'}); + return $text; +} + +=head2 MODIFYING TAG TYPES (TODO) + +This is a more complex one, but it enables a (almost) total customization. +It's based in a list of hashes, each one defining a tag type's behavior. The +list should be sorted so that the most general tags are after the most +concrete ones (sorted first by the beginning and then by the end keys). To +define a tag type you'll have to make a hash with the following keys: + +=over 4 + +=item beginning + +Specifies the beginning of the tag, after the "E<lt>". + +=item end + +Specifies the end of the tag, before the "E<gt>". + +=item breaking + +It says if this is a breaking tag class. A non-breaking (inline) tag is one +that can be taken as part of the content of another tag. It can take the +values false (0), true (1) or undefined. If you leave this undefined, you'll +have to define the f_breaking function that will say whether a concrete tag of +this class is a breaking tag or not. + +=item f_breaking + +It's a function that will tell if the next tag is a breaking one or not. It +should be defined if the "breaking" option is not. + +=item f_extract + +If you leave this key undefined, the generic extraction function will have to +extract the tag itself. It's useful for tags that can have other tags or +special structures in them, so that the main parser doesn't get mad. This +function receives a boolean that says if the tag should be removed from the +input stream or not. + +=item f_translate + +This function receives the tag (in the get_string_until() format) and returns +the translated tag (translated attributes or all needed transformations) as a +single string. + +=back + +=cut + +##### Generic XML tag types #####' + +our @tag_types = ( + { beginning => "!--#", + end => "--", + breaking => 0, + f_extract => \&tag_extract_comment, + f_translate => \&tag_trans_comment}, + { beginning => "!--", + end => "--", + breaking => 0, + f_extract => \&tag_extract_comment, + f_translate => \&tag_trans_comment}, + { beginning => "?xml", + end => "?", + breaking => 1, + f_translate => \&tag_trans_xmlhead}, + { beginning => "?", + end => "?", + breaking => 1, + f_translate => \&tag_trans_procins}, + { beginning => "!DOCTYPE", + end => "", + breaking => 1, + f_extract => \&tag_extract_doctype, + f_translate => \&tag_trans_doctype}, + { beginning => "![CDATA[", + end => "", + breaking => 1, + f_extract => \&CDATA_extract, + f_translate => \&CDATA_trans}, + { beginning => "/", + end => "", + f_breaking => \&tag_break_close, + f_translate => \&tag_trans_close}, + { beginning => "", + end => "/", + f_breaking => \&tag_break_alone, + f_translate => \&tag_trans_alone}, + { beginning => "", + end => "", + f_breaking => \&tag_break_open, + f_translate => \&tag_trans_open} +); + +sub tag_extract_comment { + my ($self,$remove)=(shift,shift); + my ($eof,@tag)=$self->get_string_until('-->',{include=>1,remove=>$remove}); + return ($eof,@tag); +} + +sub tag_trans_comment { + my ($self,@tag)=@_; + return $self->join_lines(@tag); +} + +sub tag_trans_xmlhead { + my ($self,@tag)=@_; + + # We don't have to translate anything from here: throw away references + my $tag = $self->join_lines(@tag); + $tag =~ /encoding=(("|')|)(.*?)(\s|\2)/s; + my $in_charset=$3; + $self->detected_charset($in_charset); + my $out_charset=$self->get_out_charset; + + if (defined $in_charset) { + $tag =~ s/$in_charset/$out_charset/; + } else { + if ($tag =~ m/standalone/) { + $tag =~ s/(standalone)/encoding="$out_charset" $1/; + } else { + $tag.= " encoding=\"$out_charset\""; + } + } + + return $tag; +} + +sub tag_trans_procins { + my ($self,@tag)=@_; + return $self->join_lines(@tag); +} + +sub tag_extract_doctype { + my ($self,$remove)=(shift,shift); + + # Check if there is an internal subset (between []). + my ($eof,@tag)=$self->get_string_until('>',{include=>1,unquoted=>1}); + my $parity = 0; + my $paragraph = ""; + map { $parity = 1 - $parity; $paragraph.= $parity?$_:""; } @tag; + my $found = 0; + if ($paragraph =~ m/<.*\[.*</s) { + $found = 1 + } + + if (not $found) { + ($eof,@tag)=$self->get_string_until('>',{include=>1,remove=>$remove,unquoted=>1}); + } else { + ($eof,@tag)=$self->get_string_until(']\s*>',{include=>1,remove=>$remove,unquoted=>1,regex=>1}); + } + return ($eof,@tag); +} + +sub tag_trans_doctype { +# This check is not really reliable. There are system and public +# identifiers. Only the public one could be checked reliably. + my ($self,@tag)=@_; + if (defined $self->{options}{'doctype'} ) { + my $doctype = $self->{options}{'doctype'}; + if ( $tag[0] !~ /\Q$doctype\E/i ) { + warn wrap_ref_mod($tag[1], "po4a::xml", dgettext("po4a", "Bad document type. '%s' expected. You can fix this warning with a -o doctype option, or ignore this check with -o doctype=\"\"."), $doctype); + } + } + my $i = 0; + my $basedir = $tag[1]; + $basedir =~ s/:[0-9]+$//; + $basedir = dirname($basedir); + + while ( $i < $#tag ) { + my $t = $tag[$i]; + my $ref = $tag[$i+1]; + if ( $t =~ /^(\s*<!ENTITY\s+)(.*)$/is ) { + my $part1 = $1; + my $part2 = $2; + my $includenow = 0; + my $file = 0; + my $name = ""; + if ($part2 =~ /^(%\s+)(.*)$/s ) { + $part1.= $1; + $part2 = $2; + $includenow = 1; + } + $part2 =~ /^(\S+)(\s+)(.*)$/s; + $name = $1; + $part1.= $1.$2; + $part2 = $3; + if ( $part2 =~ /^(SYSTEM\s+)(.*)$/is ) { + $part1.= $1; + $part2 = $2; + $file = 1; + if ($self->{options}{'includeexternal'}) { + $entities{$name} = $part2; + $entities{$name} =~ s/^"?(.*?)".*$/$1/s; + $entities{$name} = File::Spec->catfile($basedir, $entities{$name}); + } + } + if ((not $file) and (not $includenow)) { + if ($part2 =~ m/^\s*(["'])(.*)\1(\s*>.*)$/s) { + my $comment = "Content of the $name entity"; + my $quote = $1; + my $text = $2; + $part2 = $3; + $text = $self->translate($text, + $ref, + $comment, + 'wrap'=>1); + $t = $part1."$quote$text$quote$part2"; + } + } +# print $part1."\n"; +# print $name."\n"; +# print $part2."\n"; + } + $tag[$i] = $t; + $i += 2; + } + return $self->join_lines(@tag); +} + +sub tag_break_close { + my ($self,@tag)=@_; + my $struct = $self->get_path; + my $options = $self->get_translate_options($struct); + if ($options =~ m/[ip]/) { + return 0; + } else { + return 1; + } +} + +sub tag_trans_close { + my ($self,@tag)=@_; + my $name = $self->get_tag_name(@tag); + + my $test = pop @path; + if (!defined($test) || $test ne $name ) { + my $ontagerror = $self->{options}{'ontagerror'}; + if ($ontagerror eq "warn") { + warn wrap_ref_mod($tag[1], "po4a::xml", dgettext("po4a", "Unexpected closing tag </%s> found. The main document may be wrong. Continuing..."), $name); + } elsif ($ontagerror ne "silent") { + die wrap_ref_mod($tag[1], "po4a::xml", dgettext("po4a", "Unexpected closing tag </%s> found. The main document may be wrong."), $name); + } + } + return $self->join_lines(@tag); +} + +sub CDATA_extract { + my ($self,$remove)=(shift,shift); + my ($eof, @tag) = $self->get_string_until(']]>',{include=>1,unquoted=>0,remove=>$remove}); + + return ($eof, @tag); +} + +sub CDATA_trans { + my ($self,@tag)=@_; + return $self->found_string($self->join_lines(@tag), + $tag[1], + {'type' => "CDATA"}); +} + +sub tag_break_alone { + my ($self,@tag)=@_; + my $struct = $self->get_path($self->get_tag_name(@tag)); + if ($self->get_translate_options($struct) =~ m/i/) { + return 0; + } else { + return 1; + } +} + +sub tag_trans_alone { + my ($self,@tag)=@_; + my $name = $self->get_tag_name(@tag); + push @path, $name; + + $name = $self->treat_attributes(@tag); + + pop @path; + return $name; +} + +sub tag_break_open { + my ($self,@tag)=@_; + my $struct = $self->get_path($self->get_tag_name(@tag)); + my $options = $self->get_translate_options($struct); + if ($options =~ m/[ip]/) { + return 0; + } else { + return 1; + } +} + +sub tag_trans_open { + my ($self,@tag)=@_; + my $name = $self->get_tag_name(@tag); + push @path, $name; + + $name = $self->treat_attributes(@tag); + + return $name; +} + +##### END of Generic XML tag types ##### + +=head1 INTERNAL FUNCTIONS used to write derivated parsers + +=head2 WORKING WITH TAGS + +=over 4 + +=item get_path() + +This function returns the path to the current tag from the document's root, +in the form E<lt>htmlE<gt>E<lt>bodyE<gt>E<lt>pE<gt>. + +An additional array of tags (without brackets) can be passed in argument. +These path elements are added to the end of the current path. + +=cut + +sub get_path { + my $self = shift; + my @add = @_; + if ( @path > 0 or @add > 0 ) { + return "<".join("><",@path,@add).">"; + } else { + return "outside any tag (error?)"; + } +} + +=item tag_type() + +This function returns the index from the tag_types list that fits to the next +tag in the input stream, or -1 if it's at the end of the input file. + +=cut + +sub tag_type { + my $self = shift; + my ($line,$ref) = $self->shiftline(); + my ($match1,$match2); + my $found = 0; + my $i = 0; + + if (!defined($line)) { return -1; } + + $self->unshiftline($line,$ref); + my ($eof,@lines) = $self->get_string_until(">",{include=>1,unquoted=>1}); + my $line2 = $self->join_lines(@lines); + while (!$found && $i < @tag_types) { + ($match1,$match2) = ($tag_types[$i]->{beginning},$tag_types[$i]->{end}); + if ($line =~ /^<\Q$match1\E/) { + if (!defined($tag_types[$i]->{f_extract})) { +#print substr($line2,length($line2)-1-length($match2),1+length($match2))."\n"; + if (defined($line2) and $line2 =~ /\Q$match2\E>$/) { + $found = 1; +#print "YES: <".$match1." ".$match2.">\n"; + } else { +#print "NO: <".$match1." ".$match2.">\n"; + $i++; + } + } else { + $found = 1; + } + } else { + $i++; + } + } + if (!$found) { + #It should never enter here, unless you undefine the most + #general tags (as <...>) + die "po4a::xml: Unknown tag type: ".$line."\n"; + } else { + return $i; + } +} + +=item extract_tag($$) + +This function returns the next tag from the input stream without the beginning +and end, in an array form, to maintain the references from the input file. It +has two parameters: the type of the tag (as returned by tag_type) and a +boolean, that indicates if it should be removed from the input stream. + +=cut + +sub extract_tag { + my ($self,$type,$remove) = (shift,shift,shift); + my ($match1,$match2) = ($tag_types[$type]->{beginning},$tag_types[$type]->{end}); + my ($eof,@tag); + if (defined($tag_types[$type]->{f_extract})) { + ($eof,@tag) = &{$tag_types[$type]->{f_extract}}($self,$remove); + } else { + ($eof,@tag) = $self->get_string_until($match2.">",{include=>1,remove=>$remove,unquoted=>1}); + } + $tag[0] =~ /^<\Q$match1\E(.*)$/s; + $tag[0] = $1; + $tag[$#tag-1] =~ /^(.*)\Q$match2\E>$/s; + $tag[$#tag-1] = $1; + return ($eof,@tag); +} + +=item get_tag_name(@) + +This function returns the name of the tag passed as an argument, in the array +form returned by extract_tag. + +=cut + +sub get_tag_name { + my ($self,@tag)=@_; + $tag[0] =~ /^(\S*)/; + return $1; +} + +=item breaking_tag() + +This function returns a boolean that says if the next tag in the input stream +is a breaking tag or not (inline tag). It leaves the input stream intact. + +=cut + +sub breaking_tag { + my $self = shift; + my $break; + + my $type = $self->tag_type; + if ($type == -1) { return 0; } + +#print "TAG TYPE = ".$type."\n"; + $break = $tag_types[$type]->{breaking}; + if (!defined($break)) { + # This tag's breaking depends on its content + my ($eof,@lines) = $self->extract_tag($type,0); + $break = &{$tag_types[$type]->{f_breaking}}($self,@lines); + } +#print "break = ".$break."\n"; + return $break; +} + +=item treat_tag() + +This function translates the next tag from the input stream. Using each +tag type's custom translation functions. + +=cut + +sub treat_tag { + my $self = shift; + my $type = $self->tag_type; + + my ($match1,$match2) = ($tag_types[$type]->{beginning},$tag_types[$type]->{end}); + my ($eof,@lines) = $self->extract_tag($type,1); + + $lines[0] =~ /^(\s*)(.*)$/s; + my $space1 = $1; + $lines[0] = $2; + $lines[$#lines-1] =~ /^(.*?)(\s*)$/s; + my $space2 = $2; + $lines[$#lines-1] = $1; + + # Calling this tag type's specific handling (translation of + # attributes...) + my $line = &{$tag_types[$type]->{f_translate}}($self,@lines); + $self->pushline("<".$match1.$space1.$line.$space2.$match2.">"); + return $eof; +} + +=item tag_in_list($@) + +This function returns a string value that says if the first argument (a tag +hierarchy) matches any of the tags from the second argument (a list of tags +or tag hierarchies). If it doesn't match, it returns 0. Else, it returns the +matched tag's options (the characters in front of the tag) or 1 (if that tag +doesn't have options). + +=back + +=cut +sub tag_in_list ($$$) { + my ($self,$path,$list) = @_; + if ($self->{options}{'caseinsensitive'}) { + $path = lc $path; + } + + while (1) { + if (defined $list->{$path}) { + if (length $list->{$path}) { + return $list->{$path}; + } else { + return 1; + } + } + last unless ($path =~ m/</); + $path =~ s/^<.*?>//; + } + + return 0; +} + +=head2 WORKING WITH ATTRIBUTES + +=over 4 + +=item treat_attributes(@) + +This function handles the translation of the tags' attributes. It receives the tag +without the beginning / end marks, and then it finds the attributes, and it +translates the translatable ones (specified by the module option "attributes"). +This returns a plain string with the translated tag. + +=back + +=cut + +sub treat_attributes { + my ($self,@tag)=@_; + + $tag[0] =~ /^(\S*)(.*)/s; + my $text = $1; + $tag[0] = $2; + + while (@tag) { + my $complete = 1; + + $text .= $self->skip_spaces(\@tag); + if (@tag) { + # Get the attribute's name + $complete = 0; + + $tag[0] =~ /^([^\s=]+)(.*)/s; + my $name = $1; + my $ref = $tag[1]; + $tag[0] = $2; + $text .= $name; + $text .= $self->skip_spaces(\@tag); + if (@tag) { + # Get the '=' + if ($tag[0] =~ /^=(.*)/s) { + $tag[0] = $1; + $text .= "="; + $text .= $self->skip_spaces(\@tag); + if (@tag) { + # Get the value + my $value=""; + $ref=$tag[1]; + my $quot=substr($tag[0],0,1); + if ($quot ne "\"" and $quot ne "'") { + # Unquoted value + $quot=""; + $tag[0] =~ /^(\S+)(.*)/s; + $value = $1; + $tag[0] = $2; + } else { + # Quoted value + $text .= $quot; + $tag[0] =~ /^\Q$quot\E(.*)/s; + $tag[0] = $1; + while ($tag[0] !~ /\Q$quot\E/) { + $value .= $tag[0]; + shift @tag; + shift @tag; + } + $tag[0] =~ /^(.*?)\Q$quot\E(.*)/s; + $value .= $1; + $tag[0] = $2; + } + $complete = 1; + if ($self->tag_in_list($self->get_path.$name,$self->{attributes})) { + $text .= $self->found_string($value, $ref, { type=>"attribute", attribute=>$name }); + } else { + print wrap_ref_mod($ref, "po4a::xml", dgettext("po4a", "Content of attribute %s excluded: %s"), $self->get_path.$name, $value) + if $self->debug(); + $text .= $self->recode_skipped_text($value); + } + $text .= $quot; + } + } + } + + unless ($complete) { + my $ontagerror = $self->{options}{'ontagerror'}; + if ($ontagerror eq "warn") { + warn wrap_ref_mod($ref, "po4a::xml", dgettext ("po4a", "Bad attribute syntax. Continuing...")); + } elsif ($ontagerror ne "silent") { + die wrap_ref_mod($ref, "po4a::xml", dgettext ("po4a", "Bad attribute syntax")); + } + } + } + } + return $text; +} + +# Returns an empty string if the content in the $path should not be +# translated. +# +# Otherwise, returns the set of options for translation: +# w: the content shall be re-wrapped +# W: the content shall not be re-wrapped +# i: the tag shall be inlined +# p: a placeholder shall replace the tag (and its content) +# +# A translatable inline tag in an untranslated tag is treated as a translatable breaking tag. +my %translate_options_cache; +sub get_translate_options { + my $self = shift; + my $path = shift; + + if (defined $translate_options_cache{$path}) { + return $translate_options_cache{$path}; + } + + my $options = ""; + my $translate = 0; + my $usedefault = 1; + + my $inlist = 0; + my $tag = $self->get_tag_from_list($path, $self->{tags}); + if (defined $tag) { + $inlist = 1; + } + if ($self->{options}{'tagsonly'} eq $inlist) { + $usedefault = 0; + if (defined $tag) { + $options = $tag; + $options =~ s/<.*$//; + } else { + if ($self->{options}{'wrap'}) { + $options = "w"; + } else { + $options = "W"; + } + } + $translate = 1; + } + +# TODO: a less precise set of tags should not override a more precise one + # The tags and tagsonly options are deprecated. + # The translated and untranslated options have an higher priority. + $tag = $self->get_tag_from_list($path, $self->{translated}); + if (defined $tag) { + $usedefault = 0; + $options = $tag; + $options =~ s/<.*$//; + $translate = 1; + } + + if ($translate and $options !~ m/w/i) { + $options .= ($self->{options}{'wrap'})?"w":"W"; + } + + if (not defined $tag) { + $tag = $self->get_tag_from_list($path, $self->{untranslated}); + if (defined $tag) { + $usedefault = 0; + $options = ""; + $translate = 0; + } + } + + $tag = $self->get_tag_from_list($path, $self->{inline}); + if (defined $tag) { + $usedefault = 0; + $options .= "i"; + } else { + $tag = $self->get_tag_from_list($path, $self->{placeholder}); + if (defined $tag) { + $usedefault = 0; + $options .= "p"; + } + } + + if ($usedefault) { + $options = $self->{options}{'defaulttranslateoption'}; + } + + # A translatable inline tag in an untranslated tag is treated as a + # translatable breaking tag. + if ($options =~ m/i/) { + my $ppath = $path; + $ppath =~ s/<[^>]*>$//; + my $poptions = $self->get_translate_options ($ppath); + if ($poptions eq "") { + $options =~ s/i//; + } + } + + if ($options =~ m/i/ and $self->{options}{'foldattributes'}) { + $options .= "f"; + } + + $translate_options_cache{$path} = $options; + return $options; +} + + +# Return the tag (or biggest set of tags) of a list which matches with the +# given path. +# +# The tag (or set of tags) is returned with its options. +# +# If no tags could match the path, undef is returned. +sub get_tag_from_list ($$$) { + my ($self,$path,$list) = @_; + if ($self->{options}{'caseinsensitive'}) { + $path = lc $path; + } + + while (1) { + if (defined $list->{$path}) { + return $list->{$path}.$path; + } + last unless ($path =~ m/</); + $path =~ s/^<.*?>//; + } + + return undef; +} + + + +sub treat_content { + my $self = shift; + my $blank=""; + # Indicates if the paragraph will have to be translated + my $translate = ""; + + my ($eof,@paragraph)=$self->get_string_until('<',{remove=>1}); + + while (!$eof and !$self->breaking_tag) { + NEXT_TAG: + my @text; + my $type = $self->tag_type; + my $f_extract = $tag_types[$type]->{'f_extract'}; + if ( defined($f_extract) + and $f_extract eq \&tag_extract_comment) { + # Remove the content of the comments + ($eof, @text) = $self->extract_tag($type,1); + $text[$#text-1] .= "\0"; + if ($tag_types[$type]->{'beginning'} eq "!--#") { + $text[0] = "#".$text[0]; + } + push @comments, @text; + } else { + my ($tmpeof, @tag) = $self->extract_tag($type,0); + # Append the found inline tag + ($eof,@text)=$self->get_string_until('>', + {include=>1, + remove=>1, + unquoted=>1}); + # Append or remove the opening/closing tag from + # the tag path + if ($tag_types[$type]->{'end'} eq "") { + if ($tag_types[$type]->{'beginning'} eq "") { + # Opening inline tag + my $cur_tag_name = $self->get_tag_name(@tag); + my $t_opts = $self->get_translate_options($self->get_path($cur_tag_name)); + if ($t_opts =~ m/p/) { + # We enter a new holder. + # Append a <placeholder ...> tag to the current + # paragraph, and save the @paragraph in the + # current holder. + my $last_holder = $save_holders[$#save_holders]; + my $placeholder_str = "<placeholder type=\"".$cur_tag_name."\" id=\"".($#{$last_holder->{'sub_translations'}}+1)."\"/>"; + push @paragraph, ($placeholder_str, $text[1]); + my @saved_paragraph = @paragraph; + + $last_holder->{'paragraph'} = \@saved_paragraph; + + # Then we must push a new holder + my @new_paragraph = (); + my @sub_translations = (); + my %folded_attributes; + my %new_holder = ('paragraph' => \@new_paragraph, + 'open' => $text[0], + 'translation' => "", + 'close' => undef, + 'sub_translations' => \@sub_translations, + 'folded_attributes' => \%folded_attributes); + push @save_holders, \%new_holder; + @text = (); + + # The current @paragraph + # (for the current holder) + # is empty. + @paragraph = (); + } elsif ($t_opts =~ m/f/) { + my $tag_full = $self->join_lines(@text); + my $tag_ref = $text[1]; + if ($tag_full =~ m/^<\s*\S+\s+\S.*>$/s) { + my $holder = $save_holders[$#save_holders]; + my $id = 0; + foreach (keys %{$holder->{folded_attributes}}) { + $id = $_ + 1 if ($_ >= $id); + } + $holder->{folded_attributes}->{$id} = $tag_full; + + @text = ("<$cur_tag_name po4a-id=$id>", $tag_ref); + } + } + push @path, $cur_tag_name; + } elsif ($tag_types[$type]->{'beginning'} eq "/") { + # Closing inline tag + + # Check if this is closing the + # last opening tag we detected. + my $test = pop @path; + my $name = $self->get_tag_name(@tag); + if (!defined($test) || + $test ne $name ) { + my $ontagerror = $self->{options}{'ontagerror'}; + if ($ontagerror eq "warn") { + warn wrap_ref_mod($tag[1], "po4a::xml", dgettext("po4a", "Unexpected closing tag </%s> found. The main document may be wrong. Continuing..."), $name); + } elsif ($ontagerror ne "silent") { + die wrap_ref_mod($tag[1], "po4a::xml", dgettext("po4a", "Unexpected closing tag </%s> found. The main document may be wrong."), $name); + } + } + + if ($self->get_translate_options($self->get_path($self->get_tag_name(@tag))) =~ m/p/) { + # This closes the current holder. + + push @path, $self->get_tag_name(@tag); + # Now translate this paragraph if needed. + # This will call pushline and append the + # translation to the current holder's translation. + $self->translate_paragraph(@paragraph); + pop @path; + + # Now that this holder is closed, we can remove + # the holder from the stack. + my $holder = pop @save_holders; + # We need to keep the translation of this holder + my $translation = $holder->{'open'}.$holder->{'translation'}.$text[0]; + # FIXME: @text could be multilines. + + @text = (); + + # Then we store the translation in the previous + # holder's sub_translations array + my $previous_holder = $save_holders[$#save_holders]; + push @{$previous_holder->{'sub_translations'}}, $translation; + # We also need to restore the @paragraph array, as + # it was before we encountered the holder. + @paragraph = @{$previous_holder->{'paragraph'}}; + } + } + } + push @paragraph, @text; + } + + # Next tag + ($eof,@text)=$self->get_string_until('<',{remove=>1}); + if ($#text > 0) { + # Check if text (extracted after the inline tag) + # has to be translated + push @paragraph, @text; + } + } + + # This strips the extracted strings + # (only if you don't specify the 'nostrip' option, and if the + # paragraph can be re-wrapped) + $translate = $self->get_translate_options($self->get_path); + if (!$self->{options}{'nostrip'} and $translate !~ m/W/) { + my $clean = 0; + # Clean the beginning + while (!$clean and $#paragraph > 0) { + $paragraph[0] =~ /^(\s*)(.*)/s; + my $match = $1; + if ($paragraph[0] eq $match) { + if ($match ne "") { + $self->pushline($match); + } + shift @paragraph; + shift @paragraph; + } else { + $paragraph[0] = $2; + if ($match ne "") { + $self->pushline($match); + } + $clean = 1; + } + } + $clean = 0; + # Clean the end + while (!$clean and $#paragraph > 0) { + $paragraph[$#paragraph-1] =~ /^(.*?)(\s*)$/s; + my $match = $2; + if ($paragraph[$#paragraph-1] eq $match) { + if ($match ne "") { + $blank = $match.$blank; + } + pop @paragraph; + pop @paragraph; + } else { + $paragraph[$#paragraph-1] = $1; + if ($match ne "") { + $blank = $match.$blank; + } + $clean = 1; + } + } + } + + # Translate the string when needed + # This will either push the translation in the translated document or + # in the current holder translation. + $self->translate_paragraph(@paragraph); + + # Push the trailing blanks + if ($blank ne "") { + $self->pushline($blank); + } + return $eof; +} + +# Translate a @paragraph array of (string, reference). +# The $translate argument indicates if the strings must be translated or +# just pushed +sub translate_paragraph { + my $self = shift; + my @paragraph = @_; + my $translate = $self->get_translate_options($self->get_path); + + while ( (scalar @paragraph) + and ($paragraph[0] =~ m/^\s*\n/s)) { + $self->pushline($paragraph[0]); + shift @paragraph; + shift @paragraph; + } + + my $comments; + while (@comments) { + my ($comment,$eoc); + do { + my ($t,$l) = (shift @comments, shift @comments); + $t =~ s/\n?(\0)?$//; + $eoc = $1; + $comment .= "\n" if defined $comment; + $comment .= $t; + } until ($eoc); + $comments .= "\n" if defined $comments; + $comments .= $comment; + $self->pushline("<!--".$comment."-->\n") if defined $comment; + } + @comments = (); + + if ($self->{options}{'cpp'}) { + my @tmp = @paragraph; + @paragraph = (); + while (@tmp) { + my ($t,$l) = (shift @tmp, shift @tmp); + # #include can be followed by a filename between + # <> brackets. In that case, the argument won't be + # handled in the same call to translate_paragraph. + # Thus do not try to match "include ". + if ($t =~ m/^#[ \t]*(if |endif|undef |include|else|ifdef |ifndef |define )/si) { + if (@paragraph) { + $self->translate_paragraph(@paragraph); + @paragraph = (); + $self->pushline("\n"); + } + $self->pushline($t); + } else { + push @paragraph, ($t,$l); + } + } + } + + my $para = $self->join_lines(@paragraph); + if ( length($para) > 0 ) { + if ($translate ne "") { + # This tag should be translated + $self->pushline($self->found_string( + $para, + $paragraph[1], { + type=>"tag", + tag_options=>$translate, + comments=>$comments + })); + } else { + # Inform that this tag isn't translated in debug mode + print wrap_ref_mod($paragraph[1], "po4a::xml", dgettext ("po4a", "Content of tag %s excluded: %s"), $self->get_path, $para) + if $self->debug(); + $self->pushline($self->recode_skipped_text($para)); + } + } + # Now the paragraph is fully translated. + # If we have all the holders' translation, we can replace the + # placeholders by their translations. + # We must wait to have all the translations because the holders are + # numbered. + { + my $holder = $save_holders[$#save_holders]; + my $translation = $holder->{'translation'}; + + # Count the number of <placeholder ...> in $translation + my $count = 0; + my $str = $translation; + while ( (defined $str) + and ($str =~ m/^.*?<placeholder\s+type="[^"]+"\s+id="(\d+)"\s*\/>(.*)$/s)) { + $count += 1; + $str = $2; + if ($holder->{'sub_translations'}->[$1] =~ m/<placeholder\s+type="[^"]+"\s+id="(\d+)"\s*\/>/s) { + $count = -1; + last; + } + } + + if ( (defined $translation) + and (scalar(@{$holder->{'sub_translations'}}) == $count)) { + # OK, all the holders of the current paragraph are + # closed (and translated). + # Replace them by their translation. + while ($translation =~ m/^(.*?)<placeholder\s+type="[^"]+"\s+id="(\d+)"\s*\/>(.*)$/s) { + # FIXME: we could also check that + # * the holder exists + # * all the holders are used + $translation = $1.$holder->{'sub_translations'}->[$2].$3; + } + # We have our translation + $holder->{'translation'} = $translation; + # And there is no need for any holder in it. + my @sub_translations = (); + $holder->{'sub_translations'} = \@sub_translations; + } + } + +} + + + +=head2 WORKING WITH THE MODULE OPTIONS + +=over 4 + +=item treat_options() + +This function fills the internal structures that contain the tags, attributes +and inline data with the options of the module (specified in the command-line +or in the initialize function). + +=back + +=cut + +sub treat_options { + my $self = shift; + + if ($self->{options}{'caseinsensitive'}) { + $self->{options}{'nodefault'} = lc $self->{options}{'nodefault'}; + $self->{options}{'tags'} = lc $self->{options}{'tags'}; + $self->{options}{'break'} = lc $self->{options}{'break'}; + $self->{options}{'_default_break'} = lc $self->{options}{'_default_break'}; + $self->{options}{'translated'} = lc $self->{options}{'translated'}; + $self->{options}{'_default_translated'} = lc $self->{options}{'_default_translated'}; + $self->{options}{'untranslated'} = lc $self->{options}{'untranslated'}; + $self->{options}{'_default_untranslated'} = lc $self->{options}{'_default_untranslated'}; + $self->{options}{'attributes'} = lc $self->{options}{'attributes'}; + $self->{options}{'_default_attributes'} = lc $self->{options}{'_default_attributes'}; + $self->{options}{'inline'} = lc $self->{options}{'inline'}; + $self->{options}{'_default_inline'} = lc $self->{options}{'_default_inline'}; + $self->{options}{'placeholder'} = lc $self->{options}{'placeholder'}; + $self->{options}{'_default_placeholder'} = lc $self->{options}{'_default_placeholder'}; + } + + $self->{options}{'nodefault'} =~ /^\s*(.*)\s*$/s; + my %list_nodefault; + foreach (split(/\s+/s,$1)) { + $list_nodefault{$_} = 1; + } + $self->{nodefault} = \%list_nodefault; + + $self->{options}{'tags'} =~ /^\s*(.*)\s*$/s; + if (length $self->{options}{'tags'}) { + warn wrap_mod("po4a::xml", + dgettext("po4a", + "The '%s' option is deprecated. Please use the translated/untranslated and/or break/inline/placeholder categories."), "tags"); + } + foreach (split(/\s+/s,$1)) { + $_ =~ m/^(.*?)(<.*)$/; + $self->{tags}->{$2} = $1 || ""; + } + + if ($self->{options}{'tagsonly'}) { + warn wrap_mod("po4a::xml", + dgettext("po4a", + "The '%s' option is deprecated. Please use the translated/untranslated and/or break/inline/placeholder categories."), "tagsonly"); + } + + $self->{options}{'break'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{break}->{$2} = $1 || ""; + } + $self->{options}{'_default_break'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{break}->{$2} = $1 || "" + unless $list_nodefault{$2} + or defined $self->{break}->{$2}; + } + + $self->{options}{'translated'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{translated}->{$2} = $1 || ""; + } + $self->{options}{'_default_translated'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{translated}->{$2} = $1 || "" + unless $list_nodefault{$2} + or defined $self->{translated}->{$2}; + } + + $self->{options}{'untranslated'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{untranslated}->{$2} = $1 || ""; + } + $self->{options}{'_default_untranslated'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{untranslated}->{$2} = $1 || "" + unless $list_nodefault{$2} + or defined $self->{untranslated}->{$2}; + } + + $self->{options}{'attributes'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + if ($tag =~ m/^(.*?)(<.*)$/) { + $self->{attributes}->{$2} = $1 || ""; + } else { + $self->{attributes}->{$tag} = ""; + } + } + $self->{options}{'_default_attributes'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + if ($tag =~ m/^(.*?)(<.*)$/) { + $self->{attributes}->{$2} = $1 || "" + unless $list_nodefault{$2} + or defined $self->{attributes}->{$2}; + } else { + $self->{attributes}->{$tag} = "" + unless $list_nodefault{$tag} + or defined $self->{attributes}->{$tag}; + } + } + + my @list_inline; + $self->{options}{'inline'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{inline}->{$2} = $1 || ""; + } + $self->{options}{'_default_inline'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{inline}->{$2} = $1 || "" + unless $list_nodefault{$2} + or defined $self->{inline}->{$2}; + } + + $self->{options}{'placeholder'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{placeholder}->{$2} = $1 || ""; + } + $self->{options}{'_default_placeholder'} =~ /^\s*(.*)\s*$/s; + foreach my $tag (split(/\s+/s,$1)) { + $tag =~ m/^(.*?)(<.*)$/; + $self->{placeholder}->{$2} = $1 || "" + unless $list_nodefault{$2} + or defined $self->{placeholder}->{$2}; + } + + # There should be no translated and untranslated tags + foreach my $tag (keys %{$self->{translated}}) { + die wrap_mod("po4a::xml", + dgettext("po4a", + "Tag '%s' both in the %s and %s categories."), $tag, "translated", "untranslated") + if defined $self->{untranslated}->{$tag}; + } + # There should be no inline, break, and placeholder tags + foreach my $tag (keys %{$self->{inline}}) { + die wrap_mod("po4a::xml", + dgettext("po4a", + "Tag '%s' both in the %s and %s categories."), $tag, "inline", "break") + if defined $self->{break}->{$tag}; + die wrap_mod("po4a::xml", + dgettext("po4a", + "Tag '%s' both in the %s and %s categories."), $tag, "inline", "placeholder") + if defined $self->{placeholder}->{$tag}; + } + foreach my $tag (keys %{$self->{break}}) { + die wrap_mod("po4a::xml", + dgettext("po4a", + "Tag '%s' both in the %s and %s categories."), $tag, "break", "placeholder") + if defined $self->{placeholder}->{$tag}; + } +} + +=head2 GETTING TEXT FROM THE INPUT DOCUMENT + +=over + +=item get_string_until($%) + +This function returns an array with the lines (and references) from the input +document until it finds the first argument. The second argument is an options +hash. Value 0 means disabled (the default) and 1, enabled. + +The valid options are: + +=over 4 + +=item include + +This makes the returned array to contain the searched text + +=item remove + +This removes the returned stream from the input + +=item unquoted + +This ensures that the searched text is outside any quotes + +=back + +=cut + +sub get_string_until { + my ($self,$search) = (shift,shift); + my $options = shift; + my ($include,$remove,$unquoted, $regex) = (0,0,0,0); + + if (defined($options->{include})) { $include = $options->{include}; } + if (defined($options->{remove})) { $remove = $options->{remove}; } + if (defined($options->{unquoted})) { $unquoted = $options->{unquoted}; } + if (defined($options->{regex})) { $regex = $options->{regex}; } + + my ($line,$ref) = $self->shiftline(); + my (@text,$paragraph); + my ($eof,$found) = (0,0); + + $search = "\Q$search\E" unless $regex; + while (defined($line) and !$found) { + push @text, ($line,$ref); + $paragraph .= $line; + if ($unquoted) { + if ( $paragraph =~ /^((\".*?\")|(\'.*?\')|[^\"\'])*$search/s ) { + $found = 1; + } + } else { + if ( $paragraph =~ /$search/s ) { + $found = 1; + } + } + if (!$found) { + ($line,$ref)=$self->shiftline(); + } + } + + if (!defined($line)) { $eof = 1; } + + if ( $found ) { + $line = ""; + if($unquoted) { + $paragraph =~ /^(?:(?:\".*?\")|(?:\'.*?\')|[^\"\'])*?$search(.*)$/s; + $line = $1; + $text[$#text-1] =~ s/\Q$line\E$//s; + } else { + $paragraph =~ /$search(.*)$/s; + $line = $1; + $text[$#text-1] =~ s/\Q$line\E$//s; + } + if(!$include) { + $text[$#text-1] =~ /^(.*)($search.*)$/s; + $text[$#text-1] = $1; + $line = $2.$line; + } + if (defined($line) and ($line ne "")) { + $self->unshiftline ($line,$text[$#text]); + } + } + if (!$remove) { + $self->unshiftline (@text); + } + + #If we get to the end of the file, we return the whole paragraph + return ($eof,@text); +} + +=item skip_spaces(\@) + +This function receives as argument the reference to a paragraph (in the format +returned by get_string_until), skips his heading spaces and returns them as +a simple string. + +=cut + +sub skip_spaces { + my ($self,$pstring)=@_; + my $space=""; + + while (@$pstring and (@$pstring[0] =~ /^(\s+)(.*)$/s or @$pstring[0] eq "")) { + if (@$pstring[0] ne "") { + $space .= $1; + @$pstring[0] = $2; + } + + if (@$pstring[0] eq "") { + shift @$pstring; + shift @$pstring; + } + } + return $space; +} + +=item join_lines(@) + +This function returns a simple string with the text from the argument array +(discarding the references). + +=cut + +sub join_lines { + my ($self,@lines)=@_; + my ($line,$ref); + my $text = ""; + while ($#lines > 0) { + ($line,$ref) = (shift @lines,shift @lines); + $text .= $line; + } + return $text; +} + +=back + +=head1 STATUS OF THIS MODULE + +This module can translate tags and attributes. + +=head1 TODO LIST + +DOCTYPE (ENTITIES) + +There is a minimal support for the translation of entities. They are +translated as a whole, and tags are not taken into account. Multilines +entities are not supported and entities are always rewrapped during the +translation. + +MODIFY TAG TYPES FROM INHERITED MODULES +(move the tag_types structure inside the $self hash?) + +=head1 SEE ALSO + +L<po4a(7)|po4a.7>, L<Locale::Po4a::TransTractor(3pm)|Locale::Po4a::TransTractor>. + +=head1 AUTHORS + + Jordi Vilalta <jvprat@gmail.com> + Nicolas François <nicolas.francois@centraliens.net> + +=head1 COPYRIGHT AND LICENSE + + Copyright (c) 2004 by Jordi Vilalta <jvprat@gmail.com> + Copyright (c) 2008-2009 by Nicolas François <nicolas.francois@centraliens.net> + +This program is free software; you may redistribute it and/or modify it +under the terms of GPL (see the COPYING file). + +=cut + +1; diff -r 9e8e5292acaa -r 1c13ed2130a7 tools/po4a/po4a-translate --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/po4a/po4a-translate Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,257 @@ +#! /usr/bin/env perl +eval 'exec perl -S $0 ${1+"$@"}' + if $running_under_some_shell; + +# po4a-translate -- translate doc files using a message catalog(ie, po file) +# $Id: po4a-translate,v 1.41 2009-03-07 12:33:10 nekral-guest Exp $ +# +# Copyright 2002, 2003, 2004 by Martin Quinson (mquinson#debian.org) +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of GPL (see COPYING). + +=head1 NAME + +po4a-translate - convert a po file back to documentation format + +=head1 SYNOPSIS + +po4a-translate -f E<lt>fmtE<gt> -m E<lt>master.docE<gt> -p E<lt>XX.poE<gt> -l E<lt>XX.docE<gt> + +(XX.doc is the output, all others are inputs) + +=head1 DESCRIPTION + +The po4a (po for anything) project goal is to ease translations (and more +interestingly, the maintenance of translations) using gettext tools on +areas where they were not expected like documentation. + +The C<po4a-translate> script is in charge of converting the translation +(which was done in a po file) under the documentation format back. The +provided C<po> file should be the translation of the C<pot> file which were +produced by po4a-gettextize(1). + +=head1 OPTIONS + +=over 4 + +=item -f, --format + +Format of the documentation you want to handle. Use the --help-format +option to see the list of available formats. + +=item -a, --addendum + +Add a file to the resulting file (to put translator's name or a section +"About this translation", for example). The first line of the file to insert +should be a PO4A header indicating where it should be added (see section +I<HOWTO add extra text to translations> in po4a(7)). + +=item -A, --addendum-charset + +Charset of the addenda. Note that all the addenda should be in the same +charset. + +=item -m, --master + +File containing the master document to translate. + +=item -M, --master-charset + +Charset of the file containing the document to translate. + +=item -l, --localized + +File where the localized (translated) document should be written. + +=item -L, --localized-charset + +Charset of the file containing the localized document. + +=item -p, --po + +File from which the message catalog should be read. + +=item -o, --option + +Extra option(s) to pass to the format plugin. Specify each option in the +'name=value' format. See the documentation of each plugin for more +information about the valid options and their meanings. + +=item -k, --keep + +Minimal threshold for translation percentage to keep (ie, write) the +resulting file (default: 80). Ie, by default, files have to be translated +at at least 80% to get written. + +=item -w, --width + +Column at which we should wrap the resulting file. + +=item -h, --help + +Show a short help message. + +=item --help-format + +List the documentation format understood by po4a. + +=item -V, --version + +Display the version of the script and exit. + +=item -v, --verbose + +Increase the verbosity of the program. + +=item -d, --debug + +Output some debugging information. + +=back + +=head1 Adding content (beside translations) to generated files + +To add some extra content to the generated document beside what you +translated (like the name of the translator, or a "about this translation" +section), you should use the C<--addendum> option. + +The first line of the addendum must be a header indicating where to put +it in the document (it can be before or after a given part of the +document). The rest of the file will be added verbatim to the resulting +file without further processing. + +Note that if po4a-translate fails to add one of the given files, it discards +the whole translation (because the missing file could be the one indicating +the author, what would prevent the users to contact him to report bugs in +the translation). + +The header has a pretty rigid syntax. For more information on how to use +this feature and how it works, please refer to the po4a(7) man page. + +=head1 SEE ALSO + +L<po4a(7)>, L<po4a-gettextize(1)>, L<po4a-updatepo(1)>, L<po4a-normalize(1)>. + + +=head1 AUTHORS + + Denis Barbier <barbier@linuxfr.org> + Martin Quinson (mquinson#debian.org) + +=head1 COPYRIGHT AND LICENSE + +Copyright 2002, 2003, 2004 by SPI, inc. + +This program is free software; you may redistribute it and/or modify it +under the terms of GPL (see the COPYING file). + +=cut + +use 5.006; +use strict; +use warnings; + +use Locale::Po4a::Chooser; +use Locale::Po4a::TransTractor; +use Locale::Po4a::Common; + +use Pod::Usage qw(pod2usage); +use Getopt::Long qw(GetOptions); + +Locale::Po4a::Common::textdomain("po4a"); + +sub show_version { + Locale::Po4a::Common::show_version("po4a-translate"); + exit 0; +} + + +Getopt::Long::Configure('no_auto_abbrev','no_ignore_case'); +my ($outfile,$width,$threshold)=('-',80,80); +my ($help,$help_fmt,@verbose,$debug,@addfiles,$format,@options); +my ($master_filename,$po_filename); +my ($mastchar,$locchar,$addchar); +GetOptions( + 'help|h' => \$help, + 'help-format' => \$help_fmt, + + 'master|m=s' => \$master_filename, + 'localized|l=s' => \$outfile, + 'po|p=s' => \$po_filename, + 'addendum|a=s' => \@addfiles, + 'format|f=s' => \$format, + + 'master-charset|M=s' => \$mastchar, + 'localized-charset|L=s' => \$locchar, + 'addendum-charset|A=s' => \$addchar, + + 'option|o=s' => \@options, + + 'width|w=s' => \$width, + 'verbose|v' => \@verbose, + 'debug|d' => \$debug, + 'keep|k=s' => \$threshold, + + 'version|V' => \&show_version +) or pod2usage(); + +$help && pod2usage(-verbose => 1, -exitval => 0); +$help_fmt && Locale::Po4a::Chooser::list(0); + +(defined($master_filename) && length($master_filename))||pod2usage(); +(defined($po_filename) && length($po_filename)) ||pod2usage(); +-e $master_filename || die wrap_msg(gettext("File %s does not exist."), $master_filename); +-e $po_filename || die wrap_msg(gettext("File %s does not exist."), $po_filename); + +my (@pos,@masters); +push @pos,$po_filename; +push @masters,$master_filename; + +my %options = ( + "verbose" => scalar @verbose, + "debug" => $debug); + +foreach (@options) { + if (m/^([^=]*)=(.*)$/) { + $options{$1}="$2"; + } else { + $options{$_}=1; + } +} +# parser +my $doc=Locale::Po4a::Chooser::new($format,%options); + + +# Prepare the document to be used as translator, but not parser +$doc->process('po_in_name' => \@pos, + 'file_in_name' => \@masters, + 'file_in_charset' => $mastchar, + 'file_out_charset' => $locchar, + 'addendum_charset' => $addchar); + +my ($percent,$hit,$queries) = $doc->stats(); +my $error=0; + +print STDERR wrap_msg(gettext("%s is %s%% translated (%s of %s strings)."), + $master_filename, $percent, $hit, $queries) + if (scalar @verbose) && ($percent>=$threshold); + + +if ($percent<$threshold) { + print STDERR wrap_msg(gettext("Discard the translation of %s (only %s%% translated; need %s%%)."), + $master_filename, $percent, $threshold); + unlink($outfile) if (-e $outfile); +} else { + foreach my $add (@addfiles) { + unless ($doc->addendum($add)) { + unlink($outfile) if (-e $outfile); + die wrap_msg(gettext("Discard the translation of %s (addendum %s does not apply)."), + $master_filename, $add); + } + } + $doc->write($outfile); +} + +1; + diff -r 9e8e5292acaa -r 1c13ed2130a7 tools/po4a/po4a-updatepo --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/po4a/po4a-updatepo Mon Mar 30 16:23:33 2009 +0800 @@ -0,0 +1,235 @@ +#! /usr/bin/env perl +eval 'exec perl -S $0 ${1+"$@"}' + if $running_under_some_shell; + +# pod-updatepo -- Update the po translation of POD data. +# $Id: po4a-updatepo,v 1.44 2009-03-07 12:33:10 nekral-guest Exp $ +# +# Copyright 2002, 2003, 2004 by Martin Quinson (mquinson#debian.org) +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of GPL (see COPYING). + +=head1 NAME + +po4a-updatepo - update the translation (in po format) of documentation + +=head1 SYNOPSIS + +po4a-updatepo -f E<lt>fmtE<gt> (-m E<lt>master.docE<gt>)+ (-p E<lt>XX.poE<gt>)+ + +(XX.po are the outputs, all others are inputs) + +=head1 DESCRIPTION + +The po4a (po for anything) project goal is to ease translations (and more +interestingly, the maintenance of translations) using gettext tools on +areas where they were not expected like documentation. + +The C<po4a-updatepo> script is in charge of updating po files to make +them reflect the changes made to the original documentation file. For that, +it converts the documentation file to a pot file, and call L<msgmerge(1)> +on this new pot and on the provided po files. + +It is possible to give more than one po file (if you want to update several +languages at once), and several documentation files (if you want to store +the translations of several documents in the same po file). + +If the master document has non-ascii characters, it will convert the po files +to utf-8 (if they weren't already), in order to allow non-standard characters +in a culture independent way. + +=head1 COMMAND-LINE OPTIONS + +=over 4 + +=item -f, --format + +Format of the documentation you want to handle. Use the --help-format +option to see the list of available formats. + +=item -m, --master + +File(s) containing the master document to translate. + +=item -M, --master-charset + +Charset of the files containing the document to translate. Note that all +files must have the same charset. + +=item -p, --po + +Po file(s) to update. If these files do not exist, they are created by +C<po4a-updatepo>. + +=item -o, --option + +Extra option(s) to pass to the format plugin and other po4a internal module. +Specify each option in the 'name=value' format. See the documentation of +each plugin for more information about the valid options and their meanings. + +=item --previous + +This option adds '--previous' to the options passed to msgmerge. +It requires gettext 0.16 or later. + +=item --msgmerge-opt options + +Extra options for msgmerge. + +=item -h, --help + +Show a short help message. + +=item --help-format + +List the documentation format handled by po4a. + +=item -V, --version + +Display the version of the script and exit. + +=item -v, --verbose + +Increase the verbosity of the program. + +=item -d, --debug + +Output some debugging information. + +=back + +=head1 SEE ALSO + +L<po4a(7)>, L<po4a-gettextize(1)>, L<po4a-translate(1)>, L<po4a-normalize(1)>. + +=head1 AUTHORS + + Denis Barbier <barbier@linuxfr.org> + Martin Quinson (mquinson#debian.org) + +=head1 COPYRIGHT AND LICENSE + +Copyright 2002, 2003, 2004, 2005 by SPI, inc. + +This program is free software; you may redistribute it and/or modify it +under the terms of GPL (see the COPYING file). + +=cut + +use 5.006; +use strict; +use warnings; + +use Getopt::Long qw(GetOptions); +use Locale::Po4a::Po; + +use Locale::Po4a::Chooser; +use Locale::Po4a::TransTractor; +use Locale::Po4a::Common; + +use Pod::Usage qw(pod2usage); + +use File::Temp; + +Locale::Po4a::Common::textdomain('po4a'); + +sub show_version { + Locale::Po4a::Common::show_version("po4a-updatepo"); + exit 0; +} + + +# init commandline parser +Getopt::Long::config('bundling', 'no_getopt_compat', 'no_auto_abbrev'); + +# Parse our options +my (@masterfiles,@pofiles); +my ($help,$help_fmt,$verbose,$debug,$format,@options); +my $mastchar; +my $previous; +my $msgmerge_opt = ""; +GetOptions('help|h' => \$help, + 'help-format' => \$help_fmt, + + 'master|m=s' => \@masterfiles, + 'po|p=s' => \@pofiles, + 'format|f=s' => \$format, + + 'master-charset|M=s' => \$mastchar, + + 'option|o=s' => \@options, + + 'previous' => \$previous, + 'msgmerge-opt=s' => \$msgmerge_opt, + + 'verbose|v' => \$verbose, + 'debug|d' => \$debug, + 'version|V' => \&show_version) + or pod2usage(); + +$help && pod2usage (-verbose => 1, -exitval => 0); +$help_fmt && Locale::Po4a::Chooser::list(0); +pod2usage () if scalar @masterfiles < 1 || scalar @pofiles < 1; + +$msgmerge_opt .= " --previous" if $previous; + +my %options = ( + "verbose" => $verbose, + "debug" => $debug); + +foreach (@options) { + if (m/^([^=]*)=(.*)$/) { + $options{$1}="$2"; + } else { + $options{$_}=1; + } +} + +# parser +my ($doc)=Locale::Po4a::Chooser::new($format,%options); + +map { -e $_ || die wrap_msg(gettext("File %s does not exist."), $_) } @masterfiles; +map { die wrap_msg(gettext("po4a-updatepo can't take the input po from stdin.")) + if $_ eq '-' && !-e '-'} @pofiles; + +my ($pot_filename); +(undef,$pot_filename)=File::Temp->tempfile("po4a-updatepoXXXX", + DIR => "/tmp", + SUFFIX => ".pot", + OPEN => 0, + UNLINK => 0) + or die wrap_msg(gettext("Can't create a temporary pot file: %s"), $!); + + +print STDERR wrap_msg(gettext("Parse input files... ")) if $verbose; + +$doc->{TT}{utf_mode} = 1; + +$doc->process('file_in_name' => \@masterfiles, + 'file_in_charset' => $mastchar, + 'po_out_name' => $pot_filename, + 'debug' => $debug, + 'verbose' => $verbose); + +print STDERR wrap_msg(gettext("done.")) if $verbose; + + +while (my $po_filename=shift @pofiles) { + if (-e $po_filename) { + print STDERR wrap_msg(gettext("Updating %s:"), $po_filename) + if $verbose; + my $cmd = "msgmerge $msgmerge_opt -U $po_filename $pot_filename"; + system ($cmd) == 0 + or die wrap_msg(gettext("Error while running msgmerge: %s"), $!); + system "msgfmt --statistics -v -o /dev/null $po_filename" + if $verbose; + } else { + print STDERR wrap_msg(gettext("Creating %s:"), $po_filename) + if $verbose; + system ("cp",$pot_filename,$po_filename) == 0 + or die wrap_msg(gettext("Error while copying the po file: %s"), $!); + } +} + +unlink($pot_filename); diff -r 9e8e5292acaa -r 1c13ed2130a7 xsl/all-ids.xsl --- a/xsl/all-ids.xsl Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- Prepare an ASCII dump file of all IDs, and the pages in which - they live, for loading into a database. Assumes one-level chunked - HTML output, with each chunk containing either a chapter or - sect1. --> - -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - version="1.0"> - - <xsl:output method="text"/> - <xsl:strip-space elements="title"/> - - <xsl:template match="/"> - <xsl:for-each select="//preface|//chapter|//appendix|//bibliography|//sect1"> - <xsl:variable name="id"> - <xsl:choose> - <xsl:when test="local-name(.)='sect1'"> - <xsl:value-of select="../@id"/> - </xsl:when> - <xsl:otherwise> - <xsl:value-of select="@id"/> - </xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="sectitle"> - <xsl:value-of select="normalize-space(./title)"/> - </xsl:variable> - <xsl:for-each select=".//para[@id]|.//programlisting[@id]|.//screen[@id]"> - <xsl:value-of select="@id"/> - <xsl:text>|</xsl:text> - <xsl:copy-of select="$id"/> - <xsl:text>|</xsl:text> - <xsl:copy-of select="$sectitle"/> - <xsl:text> </xsl:text> - </xsl:for-each> - </xsl:for-each> - </xsl:template> - -</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 xsl/base-html-stylesheet.xsl --- a/xsl/base-html-stylesheet.xsl Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> - - <xsl:param name="html.stylesheet">/support/styles.css</xsl:param> - <xsl:param name="toc.section.depth">3</xsl:param> - <xsl:param name="annotate.toc">0</xsl:param> - - <xsl:param name="generate.id.attributes" select="1"></xsl:param> - <xsl:param name="header.rule" select="0"></xsl:param> - <xsl:param name="footer.rule" select="0"></xsl:param> - <xsl:param name="html.cleanup" select="1"></xsl:param> - <xsl:param name="admon.style"><xsl:text></xsl:text></xsl:param> - <xsl:param name="admon.graphics" select="1"></xsl:param> - <xsl:param name="admon.graphics.path">/support/figs/</xsl:param> - - <xsl:template match="sect1" mode="toc"> - <xsl:param name="toc-context" select="."/> - <xsl:call-template name="subtoc"> - <xsl:with-param name="toc-context" select="$toc-context"/> - <xsl:with-param name="nodes" - select="sect2|refentry|bridgehead[$bridgehead.in.toc != 0]"/> - </xsl:call-template> - </xsl:template> - - <xsl:template match="sect2" mode="toc"> - <xsl:param name="toc-context" select="."/> - - <xsl:call-template name="subtoc"> - <xsl:with-param name="toc-context" select="$toc-context"/> - <xsl:with-param name="nodes" - select="sect3|refentry|bridgehead[$bridgehead.in.toc != 0]"/> - </xsl:call-template> - </xsl:template> - - <!-- Add id attributes to <p> tags. This is mostly a copy of the - base XSL. --> - <xsl:template name="paragraph"> - <xsl:param name="class" select="''"/> - <xsl:param name="content"/> - - <xsl:variable name="p"> - <p> - <xsl:call-template name="dir"/> - <xsl:if test="$class != ''"> - <xsl:apply-templates select="." mode="class.attribute"> - <xsl:with-param name="class" select="$class"/> - </xsl:apply-templates> - </xsl:if> - <!-- Here we go. --> - <xsl:if test="$generate.id.attributes != 0"> - <xsl:attribute name="id"> - <xsl:call-template name="object.id"/> - </xsl:attribute> - </xsl:if> - <xsl:copy-of select="$content"/> - </p> - </xsl:variable> - - <xsl:choose> - <xsl:when test="$html.cleanup != 0"> - <xsl:call-template name="unwrap.p"> - <xsl:with-param name="p" select="$p"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <xsl:copy-of select="$p"/> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <!-- Add id attributes to <programlisting> and <screen> tags. Once - again, this is mostly a copy of the base XSL, although rather - trimmed down. --> - <xsl:template match="programlisting|screen"> - <xsl:param name="suppress-numbers" select="'0'"/> - - <xsl:call-template name="anchor"/> - - <pre> - <!-- Here we go. --> - <xsl:if test="$generate.id.attributes != 0"> - <xsl:attribute name="id"> - <xsl:call-template name="object.id"/> - </xsl:attribute> - </xsl:if> - - <xsl:apply-templates select="." mode="class.attribute"/> - <xsl:call-template name="apply-highlighting"/> - </pre> - </xsl:template> - - <!-- The default stylesheet generates a little TOC at the beginning - of each qandaset. Uh, no thanks. --> - <xsl:template name="process.qanda.toc"/> - - <xsl:template name="user.header.navigation"> - <div class="navheader"><h2 class="booktitle"><a href="/">Mercurial: The Definitive Guide</a> <span class="authors">by Bryan O'Sullivan</span></h2></div> - </xsl:template> - - <xsl:template name="user.head.content"> - <link rel="alternate" type="application/atom+xml" title="Comments" - href="/feeds/comments/"/> - <link rel="shortcut icon" type="image/png" href="/support/figs/favicon.png"/> - <script type="text/javascript" src="/support/jquery-min.js"></script> - <script type="text/javascript" src="/support/form.js"></script> - <script type="text/javascript" src="/support/hsbook.js"></script> - </xsl:template> - - <xsl:template name="user.footer.content"> - <div class="hgfooter"> - <p><img src="/support/figs/rss.png"/> Want to stay up to date? Subscribe to the comment feed for <a id="chapterfeed" class="feed" href="/feeds/comments/">this chapter</a>, or the <a class="feed" href="/feeds/comments/">entire book</a>.</p> - <p>Copyright 2006, 2007, 2008, 2009 Bryan O'Sullivan. - Icons by <a href="mailto:mattahan@gmail.com">Paul Davey</a> aka <a href="http://mattahan.deviantart.com/">Mattahan</a>.</p> - </div> - </xsl:template> - - <xsl:template name="user.footer.navigation"> - <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script> - <script type="text/javascript">_uacct = "UA-1805907-3"; urchinTracker();</script> - </xsl:template> -</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 xsl/chunk-stylesheet.xsl --- a/xsl/chunk-stylesheet.xsl Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> - - <xsl:import href="system-xsl/html/chunk.xsl"/> - <xsl:include href="base-html-stylesheet.xsl"/> - - <!-- PARAMETER REFERENCE: --> - <!-- http://docbook.sourceforge.net/release/xsl/current/doc/html/ --> - - <!-- Uncomment this to enable auto-numbering of sections --> - <!-- xsl:param name="section.autolabel" select="1" / --> - <xsl:param name="chunker.output.encoding">UTF-8</xsl:param> - <xsl:param name="use.id.as.filename" select="1"/> - <xsl:param name="chunk.first.sections" select="0"/> - <xsl:param name="chunk.section.depth" select="0"/> - <xsl:param name="chunk.quietly" select="0"/> - -</xsl:stylesheet> diff -r 9e8e5292acaa -r 1c13ed2130a7 xsl/dtd-profile.xsl --- a/xsl/dtd-profile.xsl Fri Mar 27 00:41:15 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> - <xsl:import href="system-xsl/profiling/profile.xsl"></xsl:import> - - <!-- For some reason, xsltproc omits the DTD from the file it - outputs. Add a sensible one back in, because otherwise xmllint - won't validate profiled documents. --> - - <xsl:template match="/"> - <xsl:text disable-output-escaping="yes"><![CDATA[ -<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" - "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> - ]]></xsl:text> - <xsl:apply-templates select="." mode="profile"/> - </xsl:template> -</xsl:stylesheet>