changeset 133:1e013fbe35f7

Lots of filename related content. A little more command reference work. Added a script to make sure commands are exhaustively documented.
author Bryan O'Sullivan <bos@serpentine.com>
date Fri, 29 Dec 2006 17:54:14 -0800
parents e1e2f3e0256a
children 0707489b90fd
files en/00book.tex en/99defs.tex en/Makefile en/cmdref.py en/cmdref.tex en/examples/cmdref en/examples/filenames en/filenames.tex
diffstat 8 files changed, 638 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/en/00book.tex	Thu Dec 28 16:45:56 2006 -0800
+++ b/en/00book.tex	Fri Dec 29 17:54:14 2006 -0800
@@ -41,6 +41,7 @@
 \include{tour-merge}
 \include{concepts}
 \include{daily}
+\include{filenames}
 \include{undo}
 \include{hook}
 \include{template}
--- a/en/99defs.tex	Thu Dec 28 16:45:56 2006 -0800
+++ b/en/99defs.tex	Fri Dec 29 17:54:14 2006 -0800
@@ -117,10 +117,13 @@
 \fi
 
 % Reference entry for a command.
-\newcommand{\cmdref}[1]{\section{#1}\label{cmdref:#1}\index{\texttt{#1} command}``\texttt{hg #1}''}
+\newcommand{\cmdref}[2]{\section{\hgcmd{#1}---#2}\label{cmdref:#1}\index{\texttt{#1} command}}
 
-% Reference entry for a command option.
-\newcommand{\optref}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}}
+% Reference entry for a command option with long and short forms.
+\newcommand{\optref}[3]{\subsubsection{\hgopt{#1}{--#3}, also \hgopt{#1}{-#2}}}
+
+% Reference entry for a command option with only long form.
+\newcommand{\loptref}[2]{\subsubsection{\hgopt{#1}{--#2} option}}
 
 %%% Local Variables: 
 %%% mode: latex
--- a/en/Makefile	Thu Dec 28 16:45:56 2006 -0800
+++ b/en/Makefile	Fri Dec 29 17:54:14 2006 -0800
@@ -10,6 +10,7 @@
 	cmdref.tex \
 	concepts.tex \
 	daily.tex \
+	filenames.tex \
 	hook.tex \
 	intro.tex \
 	mq.tex \
@@ -51,10 +52,12 @@
 example-sources := \
 	backout \
 	bisect \
+	cmdref \
 	daily.copy \
 	daily.files \
 	daily.rename \
 	daily.revert \
+	filenames \
 	hook.msglen \
 	hook.simple \
 	hook.ws \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/en/cmdref.py	Fri Dec 29 17:54:14 2006 -0800
@@ -0,0 +1,156 @@
+#!/usr/bin/env python
+
+import getopt
+import itertools
+import os
+import re
+import sys
+
+def usage(exitcode):
+    print >> sys.stderr, ('usage: %s [-H|--hidden] hg_repo' % 
+                          os.path.basename(sys.argv[0]))
+    sys.exit(exitcode)
+
+try:
+    opts, args = getopt.getopt(sys.argv[1:], 'AHh?', ['all', 'help', 'hidden'])
+    opt_all = False
+    opt_hidden = False
+    for o, a in opts:
+        if o in ('-h', '-?', '--help'):
+            usage(0)
+        if o in ('-A', '--all'):
+            opt_all = True
+        if o in ('-H', '--hidden'):
+            opt_hidden = True
+except getopt.GetoptError, err:
+    print >> sys.stderr, 'error:', err
+    usage(1)
+
+try:
+    hg_repo, ltx_file = args
+except ValueError:
+    usage(1)
+
+if not os.path.isfile(os.path.join(hg_repo, 'mercurial', 'commands.py')):
+    print >> sys.stderr, ('error: %r does not contain mercurial code' %
+                          hg_repo)
+    sys.exit(1)
+
+sys.path.insert(0, hg_repo)
+
+from mercurial import commands
+
+def get_commands():
+    seen = {}
+    for name, info in sorted(commands.table.iteritems()):
+        aliases = name.split('|', 1)
+        name = aliases.pop(0).lstrip('^')
+        function, options, synopsis = info
+        seen[name] = {}
+        for shortopt, longopt, arg, desc in options:
+            seen[name][longopt] = shortopt
+    return seen
+
+def cmd_filter((name, aliases, options)):
+    if opt_all:
+        return True
+    if opt_hidden:
+        return name.startswith('debug')
+    return not name.startswith('debug')
+
+def scan(ltx_file):
+    cmdref_re = re.compile(r'^\\cmdref{(?P<cmd>\w+)}')
+    optref_re = re.compile(r'^\\l?optref{(?P<cmd>\w+)}'
+                           r'(?:{(?P<short>[^}])})?'
+                           r'{(?P<long>[^}]+)}')
+
+    seen = {}
+    locs = {}
+    for lnum, line in enumerate(open(ltx_file)):
+        m = cmdref_re.match(line)
+        if m:
+            d = m.groupdict()
+            cmd = d['cmd']
+            seen[cmd] = {}
+            locs[cmd] = lnum + 1
+            continue
+        m = optref_re.match(line)
+        if m:
+            d = m.groupdict()
+            seen[d['cmd']][d['long']] = d['short']
+            continue
+    return seen, locs
+    
+documented, locs = scan(ltx_file)
+known = get_commands()
+
+doc_set = set(documented)
+known_set = set(known)
+
+errors = 0
+
+for nonexistent in sorted(doc_set.difference(known_set)):
+    print >> sys.stderr, ('%s:%d: %r command does not exist' %
+                          (ltx_file, locs[nonexistent], nonexistent))
+    errors += 1
+
+def optcmp(a, b):
+    la, sa = a
+    lb, sb = b
+    sc = cmp(sa, sb)
+    if sc:
+        return sc
+    return cmp(la, lb)
+
+for cmd in doc_set.intersection(known_set):
+    doc_opts = documented[cmd]
+    known_opts = known[cmd]
+    
+    do_set = set(doc_opts)
+    ko_set = set(known_opts)
+
+    for nonexistent in sorted(do_set.difference(ko_set)):
+        print >> sys.stderr, ('%s:%d: %r option to %r command does not exist' %
+                              (ltx_file, locs[cmd], nonexistent, cmd))
+        errors += 1
+
+    def mycmp(la, lb):
+        sa = known_opts[la]
+        sb = known_opts[lb]
+        return optcmp((la, sa), (lb, sb))
+
+    for undocumented in sorted(ko_set.difference(do_set), cmp=mycmp):
+        print >> sys.stderr, ('%s:%d: %r option to %r command not documented' %
+                              (ltx_file, locs[cmd], undocumented, cmd))
+        shortopt = known_opts[undocumented]
+        if shortopt:
+            print '\optref{%s}{%s}{%s}' % (cmd, shortopt, undocumented)
+        else:
+            print '\loptref{%s}{%s}' % (cmd, undocumented)
+        errors += 1
+    sys.stdout.flush()
+
+if errors:
+    sys.exit(1)
+
+sorted_locs = sorted(locs.iteritems(), key=lambda x:x[1])
+
+def next_loc(cmd):
+    for i, (name, loc) in enumerate(sorted_locs):
+        if name >= cmd:
+            return sorted_locs[i-1][1] + 1
+    return loc
+
+for undocumented in sorted(known_set.difference(doc_set)):
+    print >> sys.stderr, ('%s:%d: %r command not documented' %
+                          (ltx_file, next_loc(undocumented), undocumented))
+    print '\cmdref{%s}' % undocumented
+    for longopt, shortopt in sorted(known[undocumented].items(), cmp=optcmp):
+        if shortopt:
+            print '\optref{%s}{%s}{%s}' % (undocumented, shortopt, longopt)
+        else:
+            print '\loptref{%s}{%s}' % (undocumented, longopt)
+    sys.stdout.flush()
+    errors += 1
+
+sys.exit(errors and 1 or 0)
--- a/en/cmdref.tex	Thu Dec 28 16:45:56 2006 -0800
+++ b/en/cmdref.tex	Fri Dec 29 17:54:14 2006 -0800
@@ -1,17 +1,41 @@
 \chapter{Command reference}
 \label{cmdref}
 
-\cmdref{diff}
+\cmdref{add}{add files at the next commit}
+\optref{add}{I}{include}
+\optref{add}{X}{exclude}
+\optref{add}{n}{dry-run}
+
+\cmdref{diff}{print changes in history or working directory}
 
 Show differences between revisions for the specified files or
 directories, using the unified diff format.  For a description of the
 unified diff format, see section~\ref{sec:mq:patch}.
 
-\optref{diff}{-r}{--rev}
+By default, this command does not print diffs for files that Mercurial
+considers to contain binary data.  To control this behaviour, see the
+\hgopt{diff}{-a} and \hgopt{diff}{--git} options.
+
+\subsection{Options}
+
+\loptref{diff}{nodates}
+
+Omit date and time information when printing diff headers.
+
+\optref{diff}{B}{ignore-blank-lines}
 
-Specify a revision to compare.
+Do not print changes that only insert or delete blank lines.  A line
+that contains only whitespace is not considered blank.
+
+\optref{diff}{I}{include}
 
-\optref{diff}{-a}{--text}
+Exclude files and directories whose names match the given patterns.
+
+\optref{diff}{X}{exclude}
+
+Include files and directories whose names match the given patterns.
+
+\optref{diff}{a}{text}
 
 If this option is not specified, \hgcmd{diff} will refuse to print
 diffs for files that it detects as binary. Specifying \hgopt{diff}{-a}
@@ -19,18 +43,37 @@
 all of them.
 
 This option is useful for files that are ``mostly text'' but have a
-few embedded NUL characters.  If you use it on files that are really
-binary, its output will be incomprehensible.
+few embedded NUL characters.  If you use it on files that contain a
+lot of binary data, its output will be incomprehensible.
+
+\optref{diff}{b}{ignore-space-change}
+
+Do not print a line if the only change to that line is in the amount
+of white space it contains.
+
+\optref{diff}{g}{git}
+
+Print \command{git}-compatible diffs.  XXX reference a format
+description.
 
-\subsection{Specifying revisions}
+\optref{diff}{p}{show-function}
 
-The \hgcmd{diff} command accepts up to two \hgopt{diff}{-r} options to
-specify the revisions to compare.
+Display the name of the enclosing function in a hunk header, using a
+simple heuristic.  This functionality is enabled by default, so the
+\hgopt{diff}{-p} option has no effect unless you change the value of
+the \rcitem{diff}{showfunc} config item, as in the following example.
+\interaction{cmdref.diff-p}
+
+\optref{diff}{r}{rev}
+
+Specify one or more revisions to compare.  The \hgcmd{diff} command
+accepts up to two \hgopt{diff}{-r} options to specify the revisions to
+compare.
 
 \begin{enumerate}
 \setcounter{enumi}{0}
-\item Display the differences between the parent of the working
-  directory and the working directory.
+\item Display the differences between the parent revision of the
+  working directory and the working directory.
 \item Display the differences between the specified changeset and the
   working directory.
 \item Display the differences between the two specified changesets.
@@ -53,7 +96,34 @@
 contents.  You cannot reverse the ordering in this way if you are
 diffing against the working directory.
 
-\subsection{Why do the results of \hgcmd{diff} and \hgcmd{status}
+\optref{diff}{w}{ignore-all-space}
+
+\cmdref{version}{print version and copyright information}
+
+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.
+\begin{itemize}
+\item The string ``\texttt{unknown}''. This version of Mercurial was
+  not built in a Mercurial repository, and cannot determine its own
+  version.
+\item A short numeric string, such as ``\texttt{1.1}''. This is a
+  build of a revision of Mercurial that was identified by a specific
+  tag in the repository where it was built.  (This doesn't necessarily
+  mean that you're running an official release; someone else could
+  have added that tag to any revision in the repository where they
+  built Mercurial.)
+\item A hexadecimal string, such as ``\texttt{875489e31abe}''.  This
+  is a build of the given revision of Mercurial.
+\item A hexadecimal string followed by a date, such as
+  ``\texttt{875489e31abe+20070205}''.  This is a build of the given
+  revision of Mercurial, where the build repository contained some
+  local changes that had not been committed.
+\end{itemize}
+
+\subsection{Tips and tricks}
+
+\subsubsection{Why do the results of \hgcmd{diff} and \hgcmd{status}
   differ?}
 \label{cmdref:diff-vs-status}
 
@@ -87,7 +157,7 @@
 \hgopt{diff}{-r} option.  There is no way to print diffs relative to
 both parents.
 
-\subsection{Generating safe binary diffs}
+\subsubsection{Generating safe binary diffs}
 
 If you use the \hgopt{diff}{-a} option to force Mercurial to print
 diffs of files that are either ``mostly text'' or contain lots of
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/en/examples/cmdref	Fri Dec 29 17:54:14 2006 -0800
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+hg init diff
+cd diff
+cat > myfile.c <<EOF
+int myfunc()
+{
+    return 1;
+}
+EOF
+hg ci -Ama
+
+sed -ie 's/return 1/return 10/' myfile.c
+
+#$ name: diff-p
+
+echo '[diff]' >> $HGRC
+echo 'showfunc = False' >> $HGRC
+
+hg diff
+
+hg diff -p
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/en/examples/filenames	Fri Dec 29 17:54:14 2006 -0800
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+hg init a
+cd a
+mkdir -p examples src/watcher
+touch COPYING MANIFEST.in README setup.py
+touch examples/performant.py examples/simple.py
+touch src/main.py src/watcher/_watcher.c src/watcher/watcher.py src/xyzzy.txt
+
+#$ name: files
+
+hg add COPYING README examples/simple.py
+
+#$ name: dirs
+
+hg status src
+
+#$ name: wdir-subdir
+
+cd src
+hg add -n
+hg add -n .
+
+#$ name: wdir-relname
+
+hg status
+hg status `hg root`
+
+#$ name: glob.star
+
+hg add 'glob:*.py'
+
+#$ name: glob.starstar
+
+cd ..
+hg status 'glob:**.py'
+
+#$ name: glob.star-starstar
+
+hg status 'glob:*.py'
+hg status 'glob:**.py'
+
+#$ name: glob.question
+
+hg status 'glob:**.?'
+
+#$ name: glob.range
+
+hg status 'glob:**[nr-t]'
+
+#$ name: glob.group
+
+hg status 'glob:*.{in,py}'
+
+#$ name: filter.include
+
+hg status -I '*.in'
+
+#$ name: filter.exclude
+
+hg status -X '**.py' src
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/en/filenames.tex	Fri Dec 29 17:54:14 2006 -0800
@@ -0,0 +1,306 @@
+\chapter{File names and pattern matching}
+\label{chap:names}
+
+Mercurial provides mechanisms that let you work with file names in a
+consistent and expressive way.
+
+\section{Simple file naming}
+
+Mercurial uses a unified piece of machinery ``under the hood'' to
+handle file names.  Every command behaves uniformly with respect to
+file names.  The way in which commands work with file names is as
+follows.
+
+If you explicitly name real files on the command line, Mercurial works
+with exactly those files, as you would expect.
+\interaction{filenames.files}
+
+When you provide a directory name, Mercurial will interpret this as
+``operate on every file in this directory and its subdirectories''.
+Mercurial traverses the files and subdirectories in a directory in
+alphabetical order.  When it encounters a subdirectory, it will
+traverse that subdirectory before continuing with the current
+directory.
+\interaction{filenames.dirs}
+
+\section{Running commands without any file names}
+
+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.
+\begin{itemize}
+\item Most commands will operate on the entire working directory.
+  This is what the \hgcmd{add} command does, for example.
+\item If the command has effects that are difficult or impossible to
+  reverse, it will force you to explicitly provide at least one name
+  or pattern (see below).  This protects you from accidentally
+  deleting files by running \hgcmd{remove} with no arguments, for
+  example.
+\end{itemize}
+
+It's easy to work around these default behaviours if they don't suit
+you.  If a command normally operates on the whole working directory,
+you can invoke it on just the current directory and its subdirectories
+by giving it the name ``\dirname{.}''.
+\interaction{filenames.wdir-subdir}
+
+Along the same lines, some commands normally print file names relative
+to the root of the repository, even if you're invoking them from a
+subdirectory.  Such a command will print file names relative to your
+subdirectory if you give it explicit names.  Here, we're going to run
+\hgcmd{status} from a subdirectory, and get it to operate on the
+entire working directory while printing file names relative to our
+subdirectory, by passing it the output of the \hgcmd{root} command.
+\interaction{filenames.wdir-relname}
+
+\section{Telling you what's going on}
+
+The \hgcmd{add} example in the preceding section illustrates something
+else that's helpful about Mercurial commands.  If a command operates
+on a file that you didn't name explicitly on the command line, it will
+usually print the name of the file, so that you will not be surprised
+what's going on.
+
+The principle here is of \emph{least surprise}.  If you've exactly
+named a file on the command line, there's no point in repeating it
+back at you.  If Mercurial is acting on a file \emph{implicitly},
+because you provided no names, or a directory, or a pattern (see
+below), it's safest to tell you what it's doing.
+
+For commands that behave this way, you can silence them using the
+\hggopt{-q} option.  You can also get them to print the name of every
+file, even those you've named explicitly, using the \hggopt{-v}
+option.
+
+\section{Using patterns to identify files}
+
+In addition to working with file and directory names, Mercurial lets
+you use \emph{patterns} to identify files.  Mercurial's pattern
+handling is expressive.
+
+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.
+
+To provide a pattern in place of a regular name on the command line,
+the mechanism is simple:
+\begin{codesample2}
+  syntax:patternbody
+\end{codesample2}
+That is, a pattern is identified by a short text string that says what
+kind of pattern this is, followed by a colon, followed by the actual
+pattern.
+
+Mercurial supports two kinds of pattern syntax.  The most frequently
+used is called \texttt{glob}; this is the same kind of pattern
+matching used by the Unix shell, and should be familiar to Windows
+command prompt users, too.  
+
+When Mercurial does automatic pattern matching on Windows, it uses
+\texttt{glob} syntax.  You can thus omit the ``\texttt{glob:}'' prefix
+on Windows, but it's safe to use it, too.
+
+The \texttt{re} syntax is more powerful; it lets you specify patterns
+using regular expressions, also known as regexps.
+
+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.
+
+\subsection{Shell-style \texttt{glob} patterns}
+
+This is an overview of the kinds of patterns you can use when you're
+matching on glob patterns.
+
+The ``\texttt{*}'' character matches any string, within a single
+directory.
+\interaction{filenames.glob.star}
+
+The ``\texttt{**}'' pattern matches any string, and crosses directory
+boundaries.  It's not a standard Unix glob token, but it's accepted by
+several popular Unix shells, and is very useful.
+\interaction{filenames.glob.starstar}
+
+The ``\texttt{?}'' pattern matches any single character.
+\interaction{filenames.glob.question}
+
+The ``\texttt{[}'' character begins a \emph{character class}.  This
+matches any single character within the class.  The class ends with a
+``\texttt{]}'' character.  A class may contain multiple \emph{range}s
+of the form ``\texttt{a-f}'', which is shorthand for
+``\texttt{abcdef}''.
+\interaction{filenames.glob.range}
+If the first character after the ``\texttt{[}'' in a character class
+is a ``\texttt{!}'', it \emph{negates} the class, making it match any
+single character not in the class.
+
+A ``\texttt{\{}'' begins a group of subpatterns, where the whole group
+matches if any subpattern in the group matches.  The ``\texttt{,}''
+character separates subpatterns, and ``\texttt{\}}'' ends the group.
+\interaction{filenames.glob.group}
+
+\subsubsection{Watch out!}
+
+Don't forget that if you want to match a pattern in any directory, you
+should not be using the ``\texttt{*}'' match-any token, as this will
+only match within one directory.  Instead, use the ``\texttt{**}''
+token.  This small example illustrates the difference between the two.
+\interaction{filenames.glob.star-starstar}
+
+\subsection{Regular expression matching with \texttt{re} patterns}
+
+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).
+
+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.
+
+A regexp is matched against an entire file name, relative to the root
+of the repository.  In other words, even if you're already in
+subbdirectory \dirname{foo}, if you want to match files under this
+directory, your pattern must start with ``\texttt{foo/}''.
+
+One thing to note, if you're familiar with Perl-style regexps, is that
+Mercurial's are \emph{rooted}.  That is, a regexp starts matching
+against the beginning of a string; it doesn't look for a match
+anywhere within the string it.  To match anywhere in a string, start
+your pattern with ``\texttt{.*}''.
+
+\section{Filtering files}
+
+Not only does Mercurial give you a variety of ways to specify files;
+it lets you further winnow those files using \emph{filters}.  Commands
+that work with file names accept two filtering options.
+\begin{itemize}
+\item \hggopt{-I}, or \hggopt{--include}, lets you specify a pattern
+  that file names must match in order to be processed.
+\item \hggopt{-X}, or \hggopt{--exclude}, gives you a way to
+  \emph{avoid} processing files, if they match this pattern.
+\end{itemize}
+You can provide multiple \hggopt{-I} and \hggopt{-X} options on the
+command line, and intermix them as you please.  Mercurial interprets
+the patterns you provide using glob syntax by default (but you can use
+regexps if you need to).
+
+You can read a \hggopt{-I} filter as ``process only the files that
+match this filter''.
+\interaction{filenames.filter.include}
+The \hggopt{-X} filter is best read as ``process only the files that
+don't match this pattern''.
+\interaction{filenames.filter.exclude}
+
+\section{Ignoring unwanted files and directories}
+
+XXX.
+
+\section{Case sensitivity}
+\label{sec:names:case}
+
+If you're working in a mixed development environment that contains
+both Linux (or other Unix) systems and Macs or Windows systems, you
+should keep in the back of your mind the knowledge that they treat the
+case (``N'' versus ``n'') of file names in incompatible ways.  This is
+not very likely to affect you, and it's easy to deal with if it does,
+but it could surprise you if you don't know about it.
+
+Operating systems and filesystems differ in the way they handle the
+\emph{case} of characters in file and directory names.  There are
+three common ways to handle case in names.
+\begin{itemize}
+\item Completely case insensitive.  Uppercase and lowercase versions
+  of a letter are treated as identical, both when creating a file and
+  during subsequent accesses.  This is common on older DOS-based
+  systems.
+\item Case preserving, but insensitive.  When a file or directory is
+  created, the case of its name is stored, and can be retrieved and
+  displayed by the operating system.  When an existing file is being
+  looked up, its case is ignored.  This is the standard arrangement on
+  Windows and MacOS.  The names \filename{foo} and \filename{FoO}
+  identify the same file.  This treatment of uppercase and lowercase
+  letters as interchangeable is also referred to as \emph{case
+    folding}.
+\item Case sensitive.  The case of a name is significant at all times.
+  The names \filename{foo} and {FoO} identify different files.  This
+  is the way Linux and Unix systems normally work.
+\end{itemize}
+
+On Unix-like systems, it is possible to have any or all of the above
+ways of handling case in action at once.  For example, if you use a
+USB thumb drive formatted with a FAT32 filesystem on a Linux system,
+Linux will handle names on that filesystem in a case preserving, but
+insensitive, way.
+
+\subsection{Safe, portable repository storage}
+
+Mercurial's repository storage mechanism is \emph{case safe}.  It
+translates file names so that they can be safely stored on both case
+sensitive and case insensitive filesystems.  This means that you can
+use normal file copying tools to transfer a Mercurial repository onto,
+for example, a USB thumb drive, and safely move that drive and
+repository back and forth between a Mac, a PC running Windows, and a
+Linux box.
+
+\subsection{Detecting case conflicts}
+
+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.
+
+An important aspect of this approach is that it is possible to commit
+a changeset on a case sensitive (typically Linux or Unix) filesystem
+that will cause trouble for users on case insensitive (usually Windows
+and MacOS) users.  If a Linux user commits changes to two files, one
+named \filename{myfile.c} and the other named \filename{MyFile.C},
+they will be stored correctly in the repository.  And in the working
+directories of other Linux users, they will be correctly represented
+as separate files.
+
+If a Windows or Mac user pulls this change, they will not initially
+have a problem, because Mercurial's repository storage mechanism is
+case safe.  However, once they try to \hgcmd{update} the working
+directory to that changeset, or \hgcmd{merge} with that changeset,
+Mercurial will spot the conflict between the two file names that the
+filesystem would treat as the same, and forbid the update or merge
+from occurring.
+
+\subsection{Fixing a case conflict}
+
+If you are using Windows or a Mac in a mixed environment where some of
+your collaborators are using Linux or Unix, and Mercurial reports a
+case folding conflict when you try to \hgcmd{update} or \hgcmd{merge},
+the procedure to fix the problem is simple.
+
+Just find a nearby Linux or Unix box, clone the problem repository
+onto it, and use Mercurial's \hgcmd{rename} command to change the
+names of any offending files or directories so that they will no
+longer cause case folding conflicts.  Commit this change, \hgcmd{pull}
+or \hgcmd{push} it across to your Windows or MacOS system, and
+\hgcmd{update} to the revision with the non-conflicting names.
+
+The changeset with case-conflicting names will remain in your
+project's history, and you still won't be able to \hgcmd{update} your
+working directory to that changeset on a Windows or MacOS system, but
+you can continue development unimpeded.
+
+\begin{note}
+  Prior to version~0.9.3, Mercurial did not use a case safe repository
+  storage mechanism, and did not detect case folding conflicts.  If
+  you are using an older version of Mercurial on Windows or MacOS, I
+  strongly recommend that you upgrade.
+\end{note}
+
+%%% Local Variables: 
+%%% mode: latex
+%%% TeX-master: "00book"
+%%% End: