hgbook

changeset 117:6b0f4498569e

Beef up daily routine material. Focus on merge-across-copy.
author Bryan O'Sullivan <bos@serpentine.com>
date Tue Nov 14 15:11:22 2006 -0800 (2006-11-14)
parents ca99f247899e
children 1ee53cb37a99
files en/Makefile en/daily.tex en/examples/daily.files
line diff
     1.1 --- a/en/Makefile	Tue Nov 14 11:42:40 2006 -0800
     1.2 +++ b/en/Makefile	Tue Nov 14 15:11:22 2006 -0800
     1.3 @@ -41,6 +41,7 @@
     1.4  image-svg := $(filter %.svg,$(image-sources))
     1.5  
     1.6  example-sources := \
     1.7 +	daily.copy \
     1.8  	daily.files \
     1.9  	hook.msglen \
    1.10  	hook.simple \
     2.1 --- a/en/daily.tex	Tue Nov 14 11:42:40 2006 -0800
     2.2 +++ b/en/daily.tex	Tue Nov 14 15:11:22 2006 -0800
     2.3 @@ -1,9 +1,7 @@
     2.4  \chapter{Mercurial in daily use}
     2.5  \label{chap:daily}
     2.6  
     2.7 -\section{Routine file management tasks}
     2.8 -
     2.9 -\subsection{Telling Mercurial which files to track}
    2.10 +\section{Telling Mercurial which files to track}
    2.11  
    2.12  Mercurial does not work with files in your repository unless you tell
    2.13  it to manage them.  The \hgcmd{status} command will tell you which
    2.14 @@ -13,29 +11,52 @@
    2.15  To tell Mercurial to track a file, use the \hgcmd{add} command.  Once
    2.16  you have added a file, the entry in the output of \hgcmd{status} for
    2.17  that file changes from ``\texttt{?}'' to ``\texttt{A}''.
    2.18 +\interaction{daily.files.add}
    2.19  
    2.20  After you run a \hgcmd{commit}, the files that you added before the
    2.21  commit will no longer be listed in the output of \hgcmd{status}.  The
    2.22  reason for this is that \hgcmd{status} only tells you about
    2.23 -``interesting'' files by default.  If you have a repository that
    2.24 +``interesting'' files---those that you have modified or told Mercurial
    2.25 +to do something with---by default.  If you have a repository that
    2.26  contains thousands of files, you will rarely want to know about files
    2.27  that Mercurial is tracking, but that have not changed.  (You can still
    2.28  get this information; we'll return to this later.)
    2.29  
    2.30 -\begin{figure}[ht]
    2.31 -  \interaction{daily.files.add}
    2.32 -  \caption{Telling Mercurial to track a file}
    2.33 -  \label{ex:daily:add}
    2.34 -\end{figure}
    2.35 -
    2.36 -Once you add a file, Mercurial will track every change you make to it
    2.37 -until you either remove or rename the file.
    2.38 -
    2.39 -\subsubsection{Aside: Mercurial tracks files, not directories}
    2.40 +Once you add a file, Mercurial doesn't do anything with it
    2.41 +immediately.  Instead, it will take a snapshot of the file's state the
    2.42 +next time you perform a commit.  It will then continue to track the
    2.43 +changes you make to the file every time you commit, until you remove
    2.44 +the file.
    2.45 +
    2.46 +\subsection{Explicit versus implicit file naming}
    2.47 +
    2.48 +A useful behaviour that Mercurial has is that if you pass the name of
    2.49 +a directory to a command, every Mercurial command will treat this as
    2.50 +``I want to operate on every file in this directory and its
    2.51 +subdirectories''.
    2.52 +\interaction{daily.files.add-dir}
    2.53 +Notice in this example that Mercurial printed the names of the files
    2.54 +it added, whereas it didn't do so when we added the file named
    2.55 +\filename{a} in the earlier example.
    2.56 +
    2.57 +What's going on is that in the former case, we explicitly named the
    2.58 +file to add on the command line, so the assumption that Mercurial
    2.59 +makes in such cases is that we know what you were doing, and it
    2.60 +doesn't print any output.
    2.61 +
    2.62 +However, when we \emph{imply} the names of files by giving the name of
    2.63 +a directory, Mercurial takes the extra step of printing the name of
    2.64 +each file that it does something with.  This makes it more clear what
    2.65 +is happening, and reduces the likelihood of a silent and nasty
    2.66 +surprise.  This behaviour is common to most Mercurial commands.
    2.67 +
    2.68 +\subsection{Aside: Mercurial tracks files, not directories}
    2.69  
    2.70  Mercurial does not track directory information.  Instead, it tracks
    2.71 -the path to a file, and creates directories along a path when it needs
    2.72 -to.  This sounds like a trivial distinction, but it has one minor
    2.73 +the path to a file.  Before creating a file, it first creates any
    2.74 +missing directory components of the path.  After it deletes a file, it
    2.75 +then deletes any empty directories that were in the deleted file's
    2.76 +path.  This sounds like a trivial distinction, but it has one minor
    2.77  practical consequence: it is not possible to represent a completely
    2.78  empty directory in Mercurial.
    2.79  
    2.80 @@ -61,68 +82,169 @@
    2.81  Another way to tackle a need for an empty directory is to simply
    2.82  create one in your automated build scripts before they will need it.
    2.83  
    2.84 -\subsection{How to stop tracking a file}
    2.85 -
    2.86 -If you decide that a file no longer belongs in your repository, use
    2.87 +\section{How to stop tracking a file}
    2.88 +
    2.89 +Once you decide that a file no longer belongs in your repository, use
    2.90  the \hgcmd{remove} command; this deletes the file, and tells Mercurial
    2.91  to stop tracking it.  A removed file is represented in the output of
    2.92  \hgcmd{status} with a ``\texttt{R}''.
    2.93 -
    2.94 -You might wonder why Mercurial requires you to explicitly tell it that
    2.95 -you are deleting a file.  Earlier during the development of Mercurial,
    2.96 -you could simply delete a file however you pleased; Mercurial would
    2.97 -notice automatically when you next ran a \hgcmd{commit}, and stop
    2.98 -tracking the file.  In practice, this made it too easy to accidentally
    2.99 -stop Mercurial from tracking a file.
   2.100 +\interaction{daily.files.remove}
   2.101 +
   2.102 +\subsection{Missing files}
   2.103  
   2.104  Mercurial considers a file that you have deleted, but not used
   2.105  \hgcmd{remove} to delete, to be \emph{missing}.  A missing file is
   2.106  represented with ``\texttt{!}'' in the output of \hgcmd{status}.
   2.107 -Other Mercurial commands will not do anything with missing files.
   2.108 -
   2.109 -If you have a missing file in your repository, you can run
   2.110 -\hgcmdargs{remove}{\hgopt{remove}{--after}} later on, to tell
   2.111 -Mercurial that you deleted the file.  If you deleted the file by
   2.112 -accident, use \hgcmdargs{revert}{\emph{filename}} to restore the file
   2.113 -to its last committed state.
   2.114 -
   2.115 -\subsection{Useful shorthand---adding and removing files in one step}
   2.116 +Mercurial commands will not generally do anything with missing files.
   2.117 +\interaction{daily.files.missing}
   2.118 +
   2.119 +If your repository contains a file that \hgcmd{status} reports as
   2.120 +missing, and you want the file to stay gone, you can run
   2.121 +\hgcmdargs{remove}{\hgopt{remove}{--after}} at any time later on, to
   2.122 +tell Mercurial that you really did mean to remove the file.
   2.123 +\interaction{daily.files.remove-after}
   2.124 +
   2.125 +On the other hand, if you deleted the missing file by accident, use
   2.126 +\hgcmdargs{revert}{\emph{filename}} to recover the file.  It will
   2.127 +reappear, in unmodified form.
   2.128 +\interaction{daily.files.recover-missing}
   2.129 +
   2.130 +\subsection{Aside: why tell Mercurial explicitly to 
   2.131 +  remove a file?}
   2.132 +
   2.133 +You might wonder why Mercurial requires you to explicitly tell it that
   2.134 +you are deleting a file.  Early during the development of Mercurial,
   2.135 +it let you delete a file however you pleased; Mercurial would notice
   2.136 +the absence of the file automatically when you next ran a
   2.137 +\hgcmd{commit}, and stop tracking the file.  In practice, this made it
   2.138 +too easy to accidentally remove a file without noticing.
   2.139 +
   2.140 +\subsection{Useful shorthand---adding and removing files
   2.141 +  in one step}
   2.142  
   2.143  Mercurial offers a combination command, \hgcmd{addremove}, that adds
   2.144 -untracked files and marks missing files as removed.  The
   2.145 -\hgcmd{commit} command also provides a \hgopt{commit}{-A} option that
   2.146 -performs an add-and-remove, immediately followed by a commit.  This
   2.147 -lets you replace the following command sequence:
   2.148 -\begin{codesample2}
   2.149 -  hg add
   2.150 -  hg remove --after
   2.151 -  hg commit
   2.152 -\end{codesample2}
   2.153 -with a single command, \hgcmdargs{commit}{\hgopt{commit}{-A}}.
   2.154 -
   2.155 -\subsection{Renaming files}
   2.156 +untracked files and marks missing files as removed.  
   2.157 +\interaction{daily.files.addremove}
   2.158 +The \hgcmd{commit} command also provides a \hgopt{commit}{-A} option
   2.159 +that performs this same add-and-remove, immediately followed by a
   2.160 +commit.
   2.161 +\interaction{daily.files.commit-addremove}
   2.162 +
   2.163 +\section{Copying files}
   2.164 +
   2.165 +Mercurial provides a \hgcmd{copy} command that lets you make a new
   2.166 +copy of a file.  When you copy a file using this command, Mercurial
   2.167 +makes a record of the fact that the new file is a copy of the original
   2.168 +file.  It treats these copied files specially when you merge your work
   2.169 +with someone else's.
   2.170 +
   2.171 +What happens during a merge is that changes ``follow'' a copy.  To
   2.172 +best illustrate what this means, let's create an example.  We'll start
   2.173 +with the usual tiny repository that contains a single file.
   2.174 +\interaction{daily.copy.init}
   2.175 +We need to do some work in parallel, so that we'll have something to
   2.176 +merge.  So let's clone our repository.
   2.177 +\interaction{daily.copy.clone}
   2.178 +Back in our initial repository, let's use the \hgcmd{copy} command to
   2.179 +make a copy of the first file we created.
   2.180 +\interaction{daily.copy.copy}
   2.181 +
   2.182 +If we look at the output of the \hgcmd{status} command afterwards, the
   2.183 +copied file looks just like a normal added file.
   2.184 +\interaction{daily.copy.status}
   2.185 +But if we pass the \hgopt{status}{-C} option to \hgcmd{status}, it
   2.186 +prints another line of output: this is the file that our newly-added
   2.187 +file was copied \emph{from}.
   2.188 +\interaction{daily.copy.status-copy}
   2.189 +
   2.190 +Now, back in the repository we cloned, let's make a change in
   2.191 +parallel.  We'll add a line of content to the original file that we
   2.192 +created.
   2.193 +\interaction{daily.copy.other}
   2.194 +Now we have a modified \filename{file} in this repository.  When we
   2.195 +pull the changes from the first repository, and merge the two heads,
   2.196 +Mercurial will propagate the changes that we made locally to
   2.197 +\filename{file} into its copy, \filename{new-file}.
   2.198 +\interaction{daily.copy.merge}
   2.199 +
   2.200 +\subsection{Why should changes follow copies?}
   2.201 +\label{sec:daily:why-copy}
   2.202 +
   2.203 +This behaviour, of changes to a file propagating out to copies of the
   2.204 +file, might seem esoteric, but in most cases it's highly desirable.
   2.205 +
   2.206 +First of all, remember that this propagation \emph{only} happens when
   2.207 +you merge.  So if you \hgcmd{copy} a file, and subsequently modify the
   2.208 +original file during the normal course of your work, nothing will
   2.209 +happen.
   2.210 +
   2.211 +The second thing to know is that modifications will only propagate
   2.212 +across a copy as long as the repository that you're pulling changes
   2.213 +from \emph{doesn't know} about the copy.
   2.214 +
   2.215 +The reason that Mercurial does this is as follows.  Let's say I make
   2.216 +an important bug fix in a source file, and commit my changes.
   2.217 +Meanwhile, you've decided to \hgcmd{copy} the file in your repository,
   2.218 +without knowing about the bug or having seen the fix, and you have
   2.219 +started hacking on your copy of the file.
   2.220 +
   2.221 +If you pulled and merged my changes, and Mercurial \emph{didn't}
   2.222 +propagate changes across copies, your source file would now contain
   2.223 +the bug, and unless you remembered to propagate the bug fix by hand,
   2.224 +the bug would \emph{remain} in your copy of the file.
   2.225 +
   2.226 +By automatically propagating the change that fixed the bug from the
   2.227 +original file to the copy, Mercurial prevents this class of problem.
   2.228 +To my knowledge, Mercurial is the \emph{only} revision control system
   2.229 +that propagates changes across copies like this.
   2.230 +
   2.231 +Once your change history has a record that the copy and subsequent
   2.232 +merge occurred, there's usually no further need to propagate changes
   2.233 +from the original file to the copied file, and that's why Mercurial
   2.234 +only propagates changes across copies until this point, and no
   2.235 +further.
   2.236 +
   2.237 +\subsection{How to make changes \emph{not} follow a copy}
   2.238 +
   2.239 +If, for some reason, you decide that this business of automatically
   2.240 +propagating changes across copies is not for you, simply use your
   2.241 +system's normal file copy command (on Unix-like systems, that's
   2.242 +\command{cp}) to make a copy of a file, then \hgcmd{add} the new copy
   2.243 +by hand.  Before you do so, though, please do reread
   2.244 +section~\ref{sec:daily:why-copy}, and make an informed decision that
   2.245 +this behaviour is not appropriate to your specific case.
   2.246 +
   2.247 +\subsection{Behaviour of the \hgcmd{copy} command}
   2.248 +
   2.249 +The \hgcmd{copy} command acts similarly to the Unix \command{cp}
   2.250 +command.  The last argument is the \emph{destination}, and all prior
   2.251 +arguments are \emph{sources}.
   2.252 +If you pass it a single file as the source, and the destination
   2.253 +does not exist, it creates a new file with that name.
   2.254 +\interaction{daily.copy.simple}
   2.255 +If the destination is a directory, Mercurial copies its sources into
   2.256 +that directory.
   2.257 +\interaction{daily.copy.dir-dest}
   2.258 +Copying a directory is recursive, and preserves the directory
   2.259 +structure of the source.
   2.260 +\interaction{daily.copy.dir-src}
   2.261 +If the source and destination are both directories, the source tree is
   2.262 +recreated in the destination directory.
   2.263 +\interaction{daily.copy.dir-src-dest}
   2.264 +
   2.265 +\section{Renaming files}
   2.266  
   2.267  To rename a file that is tracked by Mercurial, use the \hgcmd{rename}
   2.268  command.  This command behaves similarly to the Unix \command{mv}
   2.269 -command.  If the last argument is a directory, it moves all prior
   2.270 -arguments into that directory.  Otherwise, it renames a single file or
   2.271 -directory to the name given in the last argument.
   2.272 +command (and in fact you can use the alias \hgcmd{mv} if you wish).
   2.273 +If the last argument is a directory, \hgcmd{rename} moves all files
   2.274 +identified by earlier arguments into that directory.  Otherwise, it
   2.275 +renames a single file or directory to the name given in the last
   2.276 +argument.
   2.277  
   2.278  As with \hgcmd{remove}, you can tell Mercurial about a rename after
   2.279  the fact using the \hgopt{remove}{--after} option.
   2.280  
   2.281 -The na\"{i}ve way to ``rename'' a file is simply to rename the file
   2.282 -yourself, \hgcmd{remove} the old name, and \hgcmd{add} the new name.
   2.283 -However, if you do this, Mercurial will not know that there was any
   2.284 -relationship between the files in question, and it will not be able to
   2.285 -merge
   2.286 -
   2.287 -\subsection{Copying files}
   2.288 -
   2.289 -You can copy a file in two ways using mercurial.  If you simply copy a
   2.290 -file and then \hgcmd{add} the new file, Mercurial will not know that
   2.291 -there was any relationship between the two files.  However, if you 
   2.292 -
   2.293  %%% Local Variables: 
   2.294  %%% mode: latex
   2.295  %%% TeX-master: "00book"
     3.1 --- a/en/examples/daily.files	Tue Nov 14 11:42:40 2006 -0800
     3.2 +++ b/en/examples/daily.files	Tue Nov 14 15:11:22 2006 -0800
     3.3 @@ -2,21 +2,96 @@
     3.4  
     3.5  #$ name: add
     3.6  
     3.7 -hg init a
     3.8 -cd a
     3.9 -echo content > filename
    3.10 -mkdir subdir
    3.11 -echo something > subdir/otherfile
    3.12 +hg init add-example
    3.13 +cd add-example
    3.14 +echo a > a
    3.15  hg status
    3.16 +hg add a
    3.17 +hg status
    3.18 +hg commit -m 'Added one file'
    3.19 +hg status
    3.20 +
    3.21 +#$ name: add-dir
    3.22 +
    3.23 +mkdir b
    3.24 +echo b > b/b
    3.25 +echo c > b/c
    3.26 +mkdir b/d
    3.27 +echo d > b/d/d
    3.28 +hg add b
    3.29 +hg commit -m 'Added all files in subdirectory'
    3.30 +
    3.31 +#$ name:
    3.32 +
    3.33 +cd ..
    3.34  
    3.35  #$ name: hidden
    3.36  
    3.37 +hg init hidden-example
    3.38 +cd hidden-example
    3.39  mkdir empty
    3.40  touch empty/.hidden
    3.41  hg add empty/.hidden
    3.42  hg commit -m 'Manage an empty-looking directory'
    3.43  ls empty
    3.44  cd ..
    3.45 -hg clone a b
    3.46 -ls b
    3.47 -ls b/empty
    3.48 +hg clone hidden-example tmp
    3.49 +ls tmp
    3.50 +ls tmp/empty
    3.51 +
    3.52 +#$ name:
    3.53 +
    3.54 +cd ..
    3.55 +
    3.56 +#$ name: remove
    3.57 +
    3.58 +hg init remove-example
    3.59 +cd remove-example
    3.60 +echo a > a
    3.61 +mkdir b
    3.62 +echo b > b/b
    3.63 +hg add a b
    3.64 +hg commit -m 'Small example for file removal'
    3.65 +hg remove a
    3.66 +hg status
    3.67 +hg remove b
    3.68 +
    3.69 +#$ name:
    3.70 +
    3.71 +cd ..
    3.72 +
    3.73 +#$ name: missing
    3.74 +hg init missing-example
    3.75 +cd missing-example
    3.76 +echo a > a
    3.77 +hg add a
    3.78 +hg commit -m'File about to be missing'
    3.79 +rm a
    3.80 +hg status
    3.81 +
    3.82 +#$ name: remove-after
    3.83 +
    3.84 +hg remove --after a
    3.85 +hg status
    3.86 +
    3.87 +#$ name: recover-missing
    3.88 +hg revert a
    3.89 +cat a
    3.90 +hg status
    3.91 +
    3.92 +#$ name:
    3.93 +
    3.94 +cd ..
    3.95 +
    3.96 +#$ name: addremove
    3.97 +
    3.98 +hg init addremove-example
    3.99 +cd addremove-example
   3.100 +echo a > a
   3.101 +echo b > b
   3.102 +hg addremove
   3.103 +
   3.104 +#$ name: commit-addremove
   3.105 +
   3.106 +echo c > c
   3.107 +hg commit -A -m 'Commit with addremove'