diff en/ch04-daily.xml @ 749:7e7c47481e4f

Oops, this is the real merge for my hg's oddity
author Dongsheng Song <dongsheng.song@gmail.com>
date Fri, 20 Mar 2009 16:43:35 +0800
parents en/ch05-daily.xml@cfdb601a3c8b
children 1c13ed2130a7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/en/ch04-daily.xml	Fri Mar 20 16:43:35 2009 +0800
@@ -0,0 +1,544 @@
+<!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
+
+<chapter id="chap.daily">
+  <?dbhtml filename="mercurial-in-daily-use.html"?>
+  <title>Mercurial in daily use</title>
+
+  <sect1>
+    <title>Telling Mercurial which files to track</title>
+
+    <para id="x_1a3">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.</para>
+
+    <para id="x_1a4">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>.</para>
+
+      &interaction.daily.files.add;
+
+    <para id="x_1a5">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.)</para>
+
+    <para id="x_1a6">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.</para>
+
+    <sect2>
+      <title>Explicit versus implicit file naming</title>
+
+      <para id="x_1a7">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>.</para>
+
+      &interaction.daily.files.add-dir;
+
+      <para id="x_1a8">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.</para>
+
+      <para id="x_1a9">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.</para>
+
+      <para id="x_1aa">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.</para>
+
+    </sect2>
+    <sect2>
+      <title>Aside: Mercurial tracks files, not directories</title>
+
+      <para id="x_1ab">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.</para>
+
+      <para id="x_1ac">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.</para>
+
+      <para id="x_1ad">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.</para>
+
+&interaction.daily.files.hidden;
+
+      <para id="x_1ae">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.</para>
+
+    </sect2>
+  </sect1>
+  <sect1>
+    <title>How to stop tracking a file</title>
+
+    <para id="x_1af">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>.</para>
+
+    &interaction.daily.files.remove;
+
+    <para id="x_1b0">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.</para>
+
+    <sect2>
+      <title>Removing a file does not affect its history</title>
+
+      <para id="x_1b1">It is important to understand that removing a file has
+	only two effects.</para>
+      <itemizedlist>
+	<listitem><para id="x_1b2">It removes the current version of the file
+	    from the working directory.</para>
+	</listitem>
+	<listitem><para id="x_1b3">It stops Mercurial from tracking changes to
+	    the file, from the time of the next commit.</para>
+	</listitem></itemizedlist>
+      <para id="x_1b4">Removing a file <emphasis>does not</emphasis> in any way
+	alter the <emphasis>history</emphasis> of the file.</para>
+
+      <para id="x_1b5">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.</para>
+
+    </sect2>
+    <sect2>
+      <title>Missing files</title>
+
+      <para id="x_1b6">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.</para>
+
+      &interaction.daily.files.missing;
+
+      <para id="x_1b7">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.</para>
+
+      &interaction.daily.files.remove-after;
+
+      <para id="x_1b8">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.</para>
+
+&interaction.daily.files.recover-missing;
+
+    </sect2>
+    <sect2>
+      <title>Aside: why tell Mercurial explicitly to remove a
+	file?</title>
+
+      <para id="x_1b9">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.</para>
+
+    </sect2>
+    <sect2>
+      <title>Useful shorthand&emdash;adding and removing files in one
+	step</title>
+
+      <para id="x_1ba">Mercurial offers a combination command, <command
+	  role="hg-cmd">hg addremove</command>, that adds untracked
+	files and marks missing files as removed.</para>
+
+      &interaction.daily.files.addremove;
+
+      <para id="x_1bb">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.</para>
+
+      &interaction.daily.files.commit-addremove;
+
+    </sect2>
+  </sect1>
+  <sect1>
+    <title>Copying files</title>
+
+    <para id="x_1bc">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.</para>
+
+    <sect2>
+      <title>The results of copying during a merge</title>
+
+      <para id="x_1bd">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.</para>
+
+      &interaction.daily.copy.init;
+
+      <para id="x_1be">We need to do some work in
+	parallel, so that we'll have something to merge.  So let's
+	clone our repository.</para>
+
+      &interaction.daily.copy.clone;
+
+      <para id="x_1bf">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.</para>
+
+      &interaction.daily.copy.copy;
+
+      <para id="x_1c0">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.</para>
+
+      &interaction.daily.copy.status;
+
+      <para id="x_1c1">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>.</para>
+
+      &interaction.daily.copy.status-copy;
+
+      <para id="x_1c2">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.</para>
+
+      &interaction.daily.copy.other;
+
+      <para id="x_1c3">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>.</para>
+
+      &interaction.daily.copy.merge;
+
+    </sect2>
+    <sect2 id="sec.daily.why-copy">
+      <title>Why should changes follow copies?</title>
+
+      <para id="x_1c4">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.</para>
+
+      <para id="x_1c5">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.</para>
+
+      <para id="x_1c6">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.</para>
+
+      <para id="x_1c7">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.</para>
+
+      <para id="x_1c8">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.</para>
+
+      <para id="x_1c9">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.</para>
+
+      <para id="x_1ca">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.</para>
+
+    </sect2>
+    <sect2>
+      <title>How to make changes <emphasis>not</emphasis> follow a
+	copy</title>
+
+      <para id="x_1cb">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.</para>
+
+    </sect2>
+    <sect2>
+      <title>Behaviour of the <command role="hg-cmd">hg copy</command>
+	command</title>
+
+      <para id="x_1cc">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.)</para>
+
+      <para id="x_1cd">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.</para>
+
+      &interaction.daily.copy.simple;
+      
+      <para id="x_1ce">If the destination is a directory, Mercurial copies its
+	sources into that directory.</para>
+
+      &interaction.daily.copy.dir-dest;
+
+      <para id="x_1cf">Copying a directory is
+	recursive, and preserves the directory structure of the
+	source.</para>
+
+      &interaction.daily.copy.dir-src;
+
+      <para id="x_1d0">If the source and destination are both directories, the
+	source tree is recreated in the destination directory.</para>
+
+	&interaction.daily.copy.dir-src-dest;
+
+      <para id="x_1d1">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>.</para>
+
+      &interaction.daily.copy.after;
+
+    </sect2>
+  </sect1>
+  <sect1>
+    <title>Renaming files</title>
+
+    <para id="x_1d2">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.</para>
+
+    <para id="x_1d3">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.</para>
+
+      &interaction.daily.rename.rename;
+
+    <para id="x_1d4">The <command role="hg-cmd">hg status</command> command shows
+      the newly copied file as added, and the copied-from file as
+      removed.</para>
+
+    &interaction.daily.rename.status;
+
+    <para id="x_1d5">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.</para>
+
+    &interaction.daily.rename.status-copy;
+
+    <para id="x_1d6">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.</para>
+
+    <sect2>
+      <title>Renaming files and merging changes</title>
+
+      <para id="x_1d7">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.</para>
+
+      <para id="x_1d8">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.)</para>
+
+      <para id="x_1d9">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.</para>
+
+    </sect2>
+    <sect2>
+      <title>Divergent renames and merging</title>
+
+      <para id="x_1da">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.</para>
+
+      &interaction.rename.divergent.clone;
+
+      <para id="x_1db">Anne renames the file to <filename>bar</filename>.</para>
+
+      &interaction.rename.divergent.rename.anne;
+
+      <para id="x_1dc">Meanwhile, Bob renames it to
+	<filename>quux</filename>.</para>
+
+	&interaction.rename.divergent.rename.bob;
+
+      <para id="x_1dd">I like to think of this as a conflict because each
+	developer has expressed different intentions about what the
+	file ought to be named.</para>
+
+      <para id="x_1de">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.</para>
+
+      &interaction.rename.divergent.merge;
+
+      <para id="x_1df">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.</para>
+
+    </sect2>
+    <sect2>
+      <title>Convergent renames and merging</title>
+
+      <para id="x_1e0">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.</para>
+
+    </sect2>
+    <sect2>
+      <title>Other name-related corner cases</title>
+
+      <para id="x_1e1">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>.</para>
+
+      &interaction.issue29.go;
+
+    </sect2>
+  </sect1>
+  <sect1>
+    <title>Recovering from mistakes</title>
+
+    <para id="x_1e2">Mercurial has some useful commands that will help you to
+      recover from some common mistakes.</para>
+
+    <para id="x_1e3">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.</para>
+
+    <para id="x_1e4">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.</para>
+
+    <para id="x_1e5">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"/>.</para>
+
+  </sect1>
+</chapter>
+
+<!--
+local variables: 
+sgml-parent-document: ("00book.xml" "book" "chapter")
+end:
+-->