bos@42: \chapter{Mercurial in daily use} bos@42: \label{chap:daily} bos@42: bos@117: \section{Telling Mercurial which files to track} bos@42: bos@42: Mercurial does not work with files in your repository unless you tell bos@42: it to manage them. The \hgcmd{status} command will tell you which bos@42: files Mercurial doesn't know about; it uses a ``\texttt{?}'' to bos@42: display such files. bos@42: bos@42: To tell Mercurial to track a file, use the \hgcmd{add} command. Once bos@42: you have added a file, the entry in the output of \hgcmd{status} for bos@42: that file changes from ``\texttt{?}'' to ``\texttt{A}''. bos@117: \interaction{daily.files.add} bos@42: bos@42: After you run a \hgcmd{commit}, the files that you added before the bos@42: commit will no longer be listed in the output of \hgcmd{status}. The bos@42: reason for this is that \hgcmd{status} only tells you about bos@117: ``interesting'' files---those that you have modified or told Mercurial bos@117: to do something with---by default. If you have a repository that bos@42: contains thousands of files, you will rarely want to know about files bos@42: that Mercurial is tracking, but that have not changed. (You can still bos@42: get this information; we'll return to this later.) bos@42: bos@117: Once you add a file, Mercurial doesn't do anything with it bos@117: immediately. Instead, it will take a snapshot of the file's state the bos@117: next time you perform a commit. It will then continue to track the bos@117: changes you make to the file every time you commit, until you remove bos@117: the file. bos@117: bos@117: \subsection{Explicit versus implicit file naming} bos@117: bos@117: A useful behaviour that Mercurial has is that if you pass the name of bos@117: a directory to a command, every Mercurial command will treat this as bos@117: ``I want to operate on every file in this directory and its bos@117: subdirectories''. bos@117: \interaction{daily.files.add-dir} bos@117: Notice in this example that Mercurial printed the names of the files bos@117: it added, whereas it didn't do so when we added the file named bos@117: \filename{a} in the earlier example. bos@117: bos@117: What's going on is that in the former case, we explicitly named the bos@117: file to add on the command line, so the assumption that Mercurial bos@117: makes in such cases is that we know what you were doing, and it bos@117: doesn't print any output. bos@117: bos@117: However, when we \emph{imply} the names of files by giving the name of bos@117: a directory, Mercurial takes the extra step of printing the name of bos@117: each file that it does something with. This makes it more clear what bos@117: is happening, and reduces the likelihood of a silent and nasty bos@117: surprise. This behaviour is common to most Mercurial commands. bos@117: bos@117: \subsection{Aside: Mercurial tracks files, not directories} bos@42: bos@42: Mercurial does not track directory information. Instead, it tracks bos@117: the path to a file. Before creating a file, it first creates any bos@117: missing directory components of the path. After it deletes a file, it bos@117: then deletes any empty directories that were in the deleted file's bos@117: path. This sounds like a trivial distinction, but it has one minor bos@42: practical consequence: it is not possible to represent a completely bos@42: empty directory in Mercurial. bos@42: bos@42: Empty directories are rarely useful, and there are unintrusive bos@42: workarounds that you can use to achieve an appropriate effect. The bos@42: developers of Mercurial thus felt that the complexity that would be bos@42: required to manage empty directories was not worth the limited benefit bos@42: this feature would bring. bos@42: bos@42: If you need an empty directory in your repository, there are a few bos@42: ways to achieve this. One is to create a directory, then \hgcmd{add} a bos@42: ``hidden'' file to that directory. On Unix-like systems, any file bos@42: name that begins with a period (``\texttt{.}'') is treated as hidden bos@42: by most commands and GUI tools. This approach is illustrated in bos@43: figure~\ref{ex:daily:hidden}. bos@42: bos@42: \begin{figure}[ht] bos@43: \interaction{daily.files.hidden} bos@43: \caption{Simulating an empty directory using a hidden file} bos@43: \label{ex:daily:hidden} bos@42: \end{figure} bos@42: bos@42: Another way to tackle a need for an empty directory is to simply bos@42: create one in your automated build scripts before they will need it. bos@42: bos@117: \section{How to stop tracking a file} bos@117: bos@117: Once you decide that a file no longer belongs in your repository, use bos@42: the \hgcmd{remove} command; this deletes the file, and tells Mercurial bos@43: to stop tracking it. A removed file is represented in the output of bos@43: \hgcmd{status} with a ``\texttt{R}''. bos@117: \interaction{daily.files.remove} bos@117: bos@117: \subsection{Missing files} bos@42: bos@43: Mercurial considers a file that you have deleted, but not used bos@43: \hgcmd{remove} to delete, to be \emph{missing}. A missing file is bos@43: represented with ``\texttt{!}'' in the output of \hgcmd{status}. bos@117: Mercurial commands will not generally do anything with missing files. bos@117: \interaction{daily.files.missing} bos@117: bos@117: If your repository contains a file that \hgcmd{status} reports as bos@117: missing, and you want the file to stay gone, you can run bos@117: \hgcmdargs{remove}{\hgopt{remove}{--after}} at any time later on, to bos@117: tell Mercurial that you really did mean to remove the file. bos@117: \interaction{daily.files.remove-after} bos@117: bos@117: On the other hand, if you deleted the missing file by accident, use bos@117: \hgcmdargs{revert}{\emph{filename}} to recover the file. It will bos@117: reappear, in unmodified form. bos@117: \interaction{daily.files.recover-missing} bos@117: bos@117: \subsection{Aside: why tell Mercurial explicitly to bos@117: remove a file?} bos@117: bos@117: You might wonder why Mercurial requires you to explicitly tell it that bos@117: you are deleting a file. Early during the development of Mercurial, bos@117: it let you delete a file however you pleased; Mercurial would notice bos@117: the absence of the file automatically when you next ran a bos@117: \hgcmd{commit}, and stop tracking the file. In practice, this made it bos@117: too easy to accidentally remove a file without noticing. bos@117: bos@117: \subsection{Useful shorthand---adding and removing files bos@117: in one step} bos@42: bos@43: Mercurial offers a combination command, \hgcmd{addremove}, that adds bos@117: untracked files and marks missing files as removed. bos@117: \interaction{daily.files.addremove} bos@117: The \hgcmd{commit} command also provides a \hgopt{commit}{-A} option bos@117: that performs this same add-and-remove, immediately followed by a bos@117: commit. bos@117: \interaction{daily.files.commit-addremove} bos@117: bos@117: \section{Copying files} bos@117: bos@117: Mercurial provides a \hgcmd{copy} command that lets you make a new bos@117: copy of a file. When you copy a file using this command, Mercurial bos@117: makes a record of the fact that the new file is a copy of the original bos@117: file. It treats these copied files specially when you merge your work bos@117: with someone else's. bos@117: bos@117: What happens during a merge is that changes ``follow'' a copy. To bos@117: best illustrate what this means, let's create an example. We'll start bos@117: with the usual tiny repository that contains a single file. bos@117: \interaction{daily.copy.init} bos@117: We need to do some work in parallel, so that we'll have something to bos@117: merge. So let's clone our repository. bos@117: \interaction{daily.copy.clone} bos@117: Back in our initial repository, let's use the \hgcmd{copy} command to bos@117: make a copy of the first file we created. bos@117: \interaction{daily.copy.copy} bos@117: bos@117: If we look at the output of the \hgcmd{status} command afterwards, the bos@117: copied file looks just like a normal added file. bos@117: \interaction{daily.copy.status} bos@117: But if we pass the \hgopt{status}{-C} option to \hgcmd{status}, it bos@117: prints another line of output: this is the file that our newly-added bos@117: file was copied \emph{from}. bos@117: \interaction{daily.copy.status-copy} bos@117: bos@117: Now, back in the repository we cloned, let's make a change in bos@117: parallel. We'll add a line of content to the original file that we bos@117: created. bos@117: \interaction{daily.copy.other} bos@117: Now we have a modified \filename{file} in this repository. When we bos@117: pull the changes from the first repository, and merge the two heads, bos@117: Mercurial will propagate the changes that we made locally to bos@117: \filename{file} into its copy, \filename{new-file}. bos@117: \interaction{daily.copy.merge} bos@117: bos@117: \subsection{Why should changes follow copies?} bos@117: \label{sec:daily:why-copy} bos@117: bos@117: This behaviour, of changes to a file propagating out to copies of the bos@117: file, might seem esoteric, but in most cases it's highly desirable. bos@117: bos@117: First of all, remember that this propagation \emph{only} happens when bos@117: you merge. So if you \hgcmd{copy} a file, and subsequently modify the bos@117: original file during the normal course of your work, nothing will bos@117: happen. bos@117: bos@117: The second thing to know is that modifications will only propagate bos@117: across a copy as long as the repository that you're pulling changes bos@117: from \emph{doesn't know} about the copy. bos@117: bos@117: The reason that Mercurial does this is as follows. Let's say I make bos@117: an important bug fix in a source file, and commit my changes. bos@117: Meanwhile, you've decided to \hgcmd{copy} the file in your repository, bos@117: without knowing about the bug or having seen the fix, and you have bos@117: started hacking on your copy of the file. bos@117: bos@117: If you pulled and merged my changes, and Mercurial \emph{didn't} bos@117: propagate changes across copies, your source file would now contain bos@117: the bug, and unless you remembered to propagate the bug fix by hand, bos@117: the bug would \emph{remain} in your copy of the file. bos@117: bos@117: By automatically propagating the change that fixed the bug from the bos@117: original file to the copy, Mercurial prevents this class of problem. bos@117: To my knowledge, Mercurial is the \emph{only} revision control system bos@117: that propagates changes across copies like this. bos@117: bos@117: Once your change history has a record that the copy and subsequent bos@117: merge occurred, there's usually no further need to propagate changes bos@117: from the original file to the copied file, and that's why Mercurial bos@117: only propagates changes across copies until this point, and no bos@117: further. bos@117: bos@117: \subsection{How to make changes \emph{not} follow a copy} bos@117: bos@117: If, for some reason, you decide that this business of automatically bos@117: propagating changes across copies is not for you, simply use your bos@117: system's normal file copy command (on Unix-like systems, that's bos@117: \command{cp}) to make a copy of a file, then \hgcmd{add} the new copy bos@117: by hand. Before you do so, though, please do reread bos@117: section~\ref{sec:daily:why-copy}, and make an informed decision that bos@117: this behaviour is not appropriate to your specific case. bos@117: bos@117: \subsection{Behaviour of the \hgcmd{copy} command} bos@117: bos@117: The \hgcmd{copy} command acts similarly to the Unix \command{cp} bos@117: command. The last argument is the \emph{destination}, and all prior bos@117: arguments are \emph{sources}. bos@117: If you pass it a single file as the source, and the destination bos@117: does not exist, it creates a new file with that name. bos@117: \interaction{daily.copy.simple} bos@117: If the destination is a directory, Mercurial copies its sources into bos@117: that directory. bos@117: \interaction{daily.copy.dir-dest} bos@117: Copying a directory is recursive, and preserves the directory bos@117: structure of the source. bos@117: \interaction{daily.copy.dir-src} bos@117: If the source and destination are both directories, the source tree is bos@117: recreated in the destination directory. bos@117: \interaction{daily.copy.dir-src-dest} bos@117: bos@117: \section{Renaming files} bos@43: bos@43: To rename a file that is tracked by Mercurial, use the \hgcmd{rename} bos@43: command. This command behaves similarly to the Unix \command{mv} bos@117: command (and in fact you can use the alias \hgcmd{mv} if you wish). bos@117: If the last argument is a directory, \hgcmd{rename} moves all files bos@117: identified by earlier arguments into that directory. Otherwise, it bos@117: renames a single file or directory to the name given in the last bos@117: argument. bos@43: bos@43: As with \hgcmd{remove}, you can tell Mercurial about a rename after bos@43: the fact using the \hgopt{remove}{--after} option. bos@43: bos@42: %%% Local Variables: bos@42: %%% mode: latex bos@42: %%% TeX-master: "00book" bos@42: %%% End: