hgbook

view en/appA-svn.xml @ 1106:aed0e9396b14

2.8.1 zh translation
author Zhaoping Sun <zhaopingsun@gmail.com>
date Thu Dec 10 13:49:35 2009 -0500 (2009-12-10)
parents 3edacbff2b43
children
line source
1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
3 <appendix id="svn">
4 <?dbhtml filename="migrating-to-mercurial.html"?>
5 <title>Migrating to Mercurial</title>
7 <para id="x_6e1">A common way to test the waters with a new revision control
8 tool is to experiment with switching an existing project, rather
9 than starting a new project from scratch.</para>
11 <para id="x_6e2">In this appendix, we discuss how to import a project's history
12 into Mercurial, and what to look out for if you are used to a
13 different revision control system.</para>
15 <sect1>
16 <title>Importing history from another system</title>
18 <para id="x_6e3">Mercurial ships with an extension named
19 <literal>convert</literal>, which can import project history
20 from most popular revision control systems. At the time this
21 book was written, it could import history from the following
22 systems:</para>
23 <itemizedlist>
24 <listitem>
25 <para id="x_6e4">Subversion</para>
26 </listitem>
27 <listitem>
28 <para id="x_6e5">CVS</para>
29 </listitem>
30 <listitem>
31 <para id="x_6e6">git</para>
32 </listitem>
33 <listitem>
34 <para id="x_6e7">Darcs</para>
35 </listitem>
36 <listitem>
37 <para id="x_6e8">Bazaar</para>
38 </listitem>
39 <listitem>
40 <para id="x_6e9">Monotone</para>
41 </listitem>
42 <listitem>
43 <para id="x_6ea">GNU Arch</para>
44 </listitem>
45 <listitem>
46 <para id="x_6eb">Mercurial</para>
47 </listitem>
48 </itemizedlist>
50 <para id="x_6ec">(To see why Mercurial itself is supported as a source, see
51 <xref linkend="svn.filemap"/>.)</para>
53 <para id="x_6ed">You can enable the extension in the usual way, by editing
54 your <filename>~/.hgrc</filename> file.</para>
56 <programlisting>[extensions]
57 convert =</programlisting>
59 <para id="x_6ee">This will make a <command>hg convert</command> command
60 available. The command is easy to use. For instance, this
61 command will import the Subversion history for the Nose unit
62 testing framework into Mercurial.</para>
64 <screen><prompt>$</prompt> <userinput>hg convert http://python-nose.googlecode.com/svn/trunk</userinput></screen>
66 <para id="x_6ef">The <literal>convert</literal> extension operates
67 incrementally. In other words, after you have run <command>hg
68 convert</command> once, running it again will import any new
69 revisions committed after the first run began. Incremental
70 conversion will only work if you run <command>hg
71 convert</command> in the same Mercurial repository that you
72 originally used, because the <literal>convert</literal>
73 extension saves some private metadata in a
74 non-revision-controlled file named
75 <filename>.hg/shamap</filename> inside the target
76 repository.</para>
78 <para id="x_707">When you want to start making changes using Mercurial, it's
79 best to clone the tree in which you are doing your conversions,
80 and leave the original tree for future incremental conversions.
81 This is the safest way to let you pull and merge future commits
82 from the source revision control system into your newly active
83 Mercurial project.</para>
85 <sect2>
86 <title>Converting multiple branches</title>
88 <para id="x_708">The <command>hg convert</command> command given above
89 converts only the history of the <literal>trunk</literal>
90 branch of the Subversion repository. If we instead use the
91 URL <literal>http://python-nose.googlecode.com/svn</literal>,
92 Mercurial will automatically detect the
93 <literal>trunk</literal>, <literal>tags</literal> and
94 <literal>branches</literal> layout that Subversion projects
95 usually use, and it will import each as a separate Mercurial
96 branch.</para>
98 <para id="x_709">By default, each Subversion branch imported into Mercurial
99 is given a branch name. After the conversion completes, you
100 can get a list of the active branch names in the Mercurial
101 repository using <command>hg branches -a</command>. If you
102 would prefer to import the Subversion branches without names,
103 pass the <option>--config
104 convert.hg.usebranchnames=false</option> option to
105 <command>hg convert</command>.</para>
107 <para id="x_70a">Once you have converted your tree, if you want to follow
108 the usual Mercurial practice of working in a tree that
109 contains a single branch, you can clone that single branch
110 using <command>hg clone -r mybranchname</command>.</para>
111 </sect2>
113 <sect2>
114 <title>Mapping user names</title>
116 <para id="x_6f0">Some revision control tools save only short usernames with
117 commits, and these can be difficult to interpret. The norm
118 with Mercurial is to save a committer's name and email
119 address, which is much more useful for talking to them after
120 the fact.</para>
122 <para id="x_6f1">If you are converting a tree from a revision control
123 system that uses short names, you can map those names to
124 longer equivalents by passing a <option>--authors</option>
125 option to <command>hg convert</command>. This option accepts
126 a file name that should contain entries of the following
127 form.</para>
129 <programlisting>arist = Aristotle &lt;aristotle@phil.example.gr&gt;
130 soc = Socrates &lt;socrates@phil.example.gr&gt;</programlisting>
132 <para id="x_6f2">Whenever <literal>convert</literal> encounters a commit
133 with the username <literal>arist</literal> in the source
134 repository, it will use the name <literal>Aristotle
135 &lt;aristotle@phil.example.gr&gt;</literal> in the converted
136 Mercurial revision. If no match is found for a name, it is
137 used verbatim.</para>
138 </sect2>
140 <sect2 id="svn.filemap">
141 <title>Tidying up the tree</title>
143 <para id="x_6f3">Not all projects have pristine history. There may be a
144 directory that should never have been checked in, a file that
145 is too big, or a whole hierarchy that needs to be
146 refactored.</para>
148 <para id="x_6f4">The <literal>convert</literal> extension supports the idea
149 of a <quote>file map</quote> that can reorganize the files and
150 directories in a project as it imports the project's history.
151 This is useful not only when importing history from other
152 revision control systems, but also to prune or refactor a
153 Mercurial tree.</para>
155 <para id="x_6f5">To specify a file map, use the <option>--filemap</option>
156 option and supply a file name. A file map contains lines of the
157 following forms.</para>
159 <programlisting># This is a comment.
160 # Empty lines are ignored.
162 include path/to/file
164 exclude path/to/file
166 rename from/some/path to/some/other/place
167 </programlisting>
169 <para id="x_6f6">The <literal>include</literal> directive causes a file, or
170 all files under a directory, to be included in the destination
171 repository. This also excludes all other files and dirs not
172 explicitely included. The <literal>exclude</literal>
173 directive causes files or directories to be omitted, and
174 others not explicitly mentioned to be included.</para>
176 <para id="x_6f7">To move a file or directory from one location to another,
177 use the <literal>rename</literal> directive. If you need to
178 move a file or directory from a subdirectory into the root of
179 the repository, use <literal>.</literal> as the second
180 argument to the <literal>rename</literal> directive.</para>
181 </sect2>
183 <sect2>
184 <title>Improving Subversion conversion performance</title>
186 <para id="x_70b">You will often need several attempts before you hit the
187 perfect combination of user map, file map, and other
188 conversion parameters. Converting a Subversion repository
189 over an access protocol like <literal>ssh</literal> or
190 <literal>http</literal> can proceed thousands of times more
191 slowly than Mercurial is capable of actually operating, due to
192 network delays. This can make tuning that perfect conversion
193 recipe very painful.</para>
195 <para id="x_70c">The <ulink
196 url="http://svn.collab.net/repos/svn/trunk/notes/svnsync.txt"><command>svnsync</command></ulink>
197 command can greatly speed up the conversion of a Subversion
198 repository. It is a read-only mirroring program for
199 Subversion repositories. The idea is that you create a local
200 mirror of your Subversion tree, then convert the mirror into a
201 Mercurial repository.</para>
203 <para id="x_70d">Suppose we want to convert the Subversion repository for
204 the popular Memcached project into a Mercurial tree. First,
205 we create a local Subversion repository.</para>
207 <screen><prompt>$</prompt> <userinput>svnadmin create memcached-mirror</userinput></screen>
209 <para id="x_70e">Next, we set up a Subversion hook that
210 <command>svnsync</command> needs.</para>
212 <screen><prompt>$</prompt> <userinput>echo '#!/bin/sh' > memcached-mirror/hooks/pre-revprop-change</userinput>
213 <prompt>$</prompt> <userinput>chmod +x memcached-mirror/hooks/pre-revprop-change</userinput></screen>
215 <para id="x_70f">We then initialize <command>svnsync</command> in this
216 repository.</para>
218 <screen><prompt>$</prompt> <userinput>svnsync --init file://`pwd`/memcached-mirror \
219 http://code.sixapart.com/svn/memcached</userinput></screen>
221 <para id="x_710">Our next step is to begin the <command>svnsync</command>
222 mirroring process.</para>
224 <screen><prompt>$</prompt> <userinput>svnsync sync file://`pwd`/memcached-mirror</userinput></screen>
226 <para id="x_711">Finally, we import the history of our local Subversion
227 mirror into Mercurial.</para>
229 <screen><prompt>$</prompt> <userinput>hg convert memcached-mirror</userinput></screen>
231 <para id="x_712">We can use this process incrementally if the Subversion
232 repository is still in use. We run <command>svnsync</command>
233 to pull new changes into our mirror, then <command>hg
234 convert</command> to import them into our Mercurial
235 tree.</para>
237 <para id="x_713">There are two advantages to doing a two-stage import with
238 <command>svnsync</command>. The first is that it uses more
239 efficient Subversion network syncing code than <command>hg
240 convert</command>, so it transfers less data over the
241 network. The second is that the import from a local
242 Subversion tree is so fast that you can tweak your conversion
243 setup repeatedly without having to sit through a painfully
244 slow network-based conversion process each time.</para>
245 </sect2>
246 </sect1>
248 <sect1>
249 <title>Migrating from Subversion</title>
251 <para id="x_6f8">Subversion is currently the most popular open source
252 revision control system. Although there are many differences
253 between Mercurial and Subversion, making the transition from
254 Subversion to Mercurial is not particularly difficult. The two
255 have similar command sets and generally uniform
256 interfaces.</para>
258 <sect2>
259 <title>Philosophical differences</title>
261 <para id="x_6f9">The fundamental difference between Subversion and
262 Mercurial is of course that Subversion is centralized, while
263 Mercurial is distributed. Since Mercurial stores all of a
264 project's history on your local drive, it only needs to
265 perform a network access when you want to explicitly
266 communicate with another repository. In contrast, Subversion
267 stores very little information locally, and the client must
268 thus contact its server for many common operations.</para>
270 <para id="x_6fa">Subversion more or less gets away without a well-defined
271 notion of a branch: which portion of a server's namespace
272 qualifies as a branch is a matter of convention, with the
273 software providing no enforcement. Mercurial treats a
274 repository as the unit of branch management.</para>
276 <sect3>
277 <title>Scope of commands</title>
279 <para id="x_6fb">Since Subversion doesn't know what parts of its
280 namespace are really branches, it treats most commands as
281 requests to operate at and below whatever directory you are
282 currently visiting. For instance, if you run <command>svn
283 log</command>, you'll get the history of whatever part of
284 the tree you're looking at, not the tree as a whole.</para>
286 <para id="x_6fc">Mercurial's commands behave differently, by defaulting
287 to operating over an entire repository. Run <command>hg
288 log</command> and it will tell you the history of the
289 entire tree, no matter what part of the working directory
290 you're visiting at the time. If you want the history of
291 just a particular file or directory, simply supply it by
292 name, e.g. <command>hg log src</command>.</para>
294 <para id="x_6fd">From my own experience, this difference in default
295 behaviors is probably the most likely to trip you up if you
296 have to switch back and forth frequently between the two
297 tools.</para>
298 </sect3>
300 <sect3>
301 <title>Multi-user operation and safety</title>
303 <para id="x_6fe">With Subversion, it is normal (though slightly frowned
304 upon) for multiple people to collaborate in a single branch.
305 If Alice and Bob are working together, and Alice commits
306 some changes to their shared branch, Bob must update his
307 client's view of the branch before he can commit. Since at
308 this time he has no permanent record of the changes he has
309 made, he can corrupt or lose his modifications during and
310 after his update.</para>
312 <para id="x_6ff">Mercurial encourages a commit-then-merge model instead.
313 Bob commits his changes locally before pulling changes from,
314 or pushing them to, the server that he shares with Alice.
315 If Alice pushed her changes before Bob tries to push his, he
316 will not be able to push his changes until he pulls hers,
317 merges with them, and commits the result of the merge. If
318 he makes a mistake during the merge, he still has the option
319 of reverting to the commit that recorded his changes.</para>
321 <para id="x_700">It is worth emphasizing that these are the common ways
322 of working with these tools. Subversion supports a safer
323 work-in-your-own-branch model, but it is cumbersome enough
324 in practice to not be widely used. Mercurial can support
325 the less safe mode of allowing changes to be pulled in and
326 merged on top of uncommitted edits, but this is considered
327 highly unusual.</para>
328 </sect3>
330 <sect3>
331 <title>Published vs local changes</title>
333 <para id="x_701">A Subversion <command>svn commit</command> command
334 immediately publishes changes to a server, where they can be
335 seen by everyone who has read access.</para>
337 <para id="x_702">With Mercurial, commits are always local, and must be
338 published via a <command>hg push</command> command
339 afterwards.</para>
341 <para id="x_703">Each approach has its advantages and disadvantages. The
342 Subversion model means that changes are published, and hence
343 reviewable and usable, immediately. On the other hand, this
344 means that a user must have commit access to a repository in
345 order to use the software in a normal way, and commit access
346 is not lightly given out by most open source
347 projects.</para>
349 <para id="x_704">The Mercurial approach allows anyone who can clone a
350 repository to commit changes without the need for someone
351 else's permission, and they can then publish their changes
352 and continue to participate however they see fit. The
353 distinction between committing and pushing does open up the
354 possibility of someone committing changes to their laptop
355 and walking away for a few days having forgotten to push
356 them, which in rare cases might leave collaborators
357 temporarily stuck.</para>
358 </sect3>
359 </sect2>
361 <sect2>
362 <title>Quick reference</title>
364 <table>
365 <title>Subversion commands and Mercurial equivalents</title>
366 <tgroup cols="3">
367 <thead>
368 <row>
369 <entry>Subversion</entry>
370 <entry>Mercurial</entry>
371 <entry>Notes</entry>
372 </row>
373 </thead>
374 <tbody>
375 <row>
376 <entry><command>svn add</command></entry>
377 <entry><command>hg add</command></entry>
378 <entry></entry>
379 </row>
380 <row>
381 <entry><command>svn blame</command></entry>
382 <entry><command>hg annotate</command></entry>
383 <entry></entry>
384 </row>
385 <row>
386 <entry><command>svn cat</command></entry>
387 <entry><command>hg cat</command></entry>
388 <entry></entry>
389 </row>
390 <row>
391 <entry><command>svn checkout</command></entry>
392 <entry><command>hg clone</command></entry>
393 <entry></entry>
394 </row>
395 <row>
396 <entry><command>svn cleanup</command></entry>
397 <entry>n/a</entry>
398 <entry>No cleanup needed</entry>
399 </row>
400 <row>
401 <entry><command>svn commit</command></entry>
402 <entry><command>hg commit</command>; <command>hg
403 push</command></entry>
404 <entry><command>hg push</command> publishes after
405 commit</entry>
406 </row>
407 <row>
408 <entry><command>svn copy</command></entry>
409 <entry><command>hg clone</command></entry>
410 <entry>To create a new branch</entry>
411 </row>
412 <row>
413 <entry><command>svn copy</command></entry>
414 <entry><command>hg copy</command></entry>
415 <entry>To copy files or directories</entry>
416 </row>
417 <row>
418 <entry><command>svn delete</command> (<command>svn
419 remove</command>)</entry>
420 <entry><command>hg remove</command></entry>
421 <entry></entry>
422 </row>
423 <row>
424 <entry><command>svn diff</command></entry>
425 <entry><command>hg diff</command></entry>
426 <entry></entry>
427 </row>
428 <row>
429 <entry><command>svn export</command></entry>
430 <entry><command>hg archive</command></entry>
431 <entry></entry>
432 </row>
433 <row>
434 <entry><command>svn help</command></entry>
435 <entry><command>hg help</command></entry>
436 <entry></entry>
437 </row>
438 <row>
439 <entry><command>svn import</command></entry>
440 <entry><command>hg addremove</command>; <command>hg
441 commit</command></entry>
442 <entry></entry>
443 </row>
444 <row>
445 <entry><command>svn info</command></entry>
446 <entry><command>hg parents</command></entry>
447 <entry>Shows what revision is checked out</entry>
448 </row>
449 <row>
450 <entry><command>svn info</command></entry>
451 <entry><command>hg showconfig
452 paths.parent</command></entry>
453 <entry>Shows what URL is checked out</entry>
454 </row>
455 <row>
456 <entry><command>svn list</command></entry>
457 <entry><command>hg manifest</command></entry>
458 <entry></entry>
459 </row>
460 <row>
461 <entry><command>svn log</command></entry>
462 <entry><command>hg log</command></entry>
463 <entry></entry>
464 </row>
465 <row>
466 <entry><command>svn merge</command></entry>
467 <entry><command>hg merge</command></entry>
468 <entry></entry>
469 </row>
470 <row>
471 <entry><command>svn mkdir</command></entry>
472 <entry>n/a</entry>
473 <entry>Mercurial does not track directories</entry>
474 </row>
475 <row>
476 <entry><command>svn move</command> (<command>svn
477 rename</command>)</entry>
478 <entry><command>hg rename</command></entry>
479 <entry></entry>
480 </row>
481 <row>
482 <entry><command>svn resolved</command></entry>
483 <entry><command>hg resolve -m</command></entry>
484 <entry></entry>
485 </row>
486 <row>
487 <entry><command>svn revert</command></entry>
488 <entry><command>hg revert</command></entry>
489 <entry></entry>
490 </row>
491 <row>
492 <entry><command>svn status</command></entry>
493 <entry><command>hg status</command></entry>
494 <entry></entry>
495 </row>
496 <row>
497 <entry><command>svn update</command></entry>
498 <entry><command>hg pull -u</command></entry>
499 <entry></entry>
500 </row>
501 </tbody>
502 </tgroup>
503 </table>
504 </sect2>
505 </sect1>
507 <sect1>
508 <title>Useful tips for newcomers</title>
510 <para id="x_705">Under some revision control systems, printing a diff for a
511 single committed revision can be painful. For instance, with
512 Subversion, to see what changed in revision 104654, you must
513 type <command>svn diff -r104653:104654</command>. Mercurial
514 eliminates the need to type the revision ID twice in this common
515 case. For a plain diff, <command>hg export 104654</command>. For
516 a log message followed by a diff, <command>hg log -r104654
517 -p</command>.</para>
519 <para id="x_706">When you run <command>hg status</command> without any
520 arguments, it prints the status of the entire tree, with paths
521 relative to the root of the repository. This makes it tricky to
522 copy a file name from the output of <command>hg status</command>
523 into the command line. If you supply a file or directory name
524 to <command>hg status</command>, it will print paths relative to
525 your current location instead. So to get tree-wide status from
526 <command>hg status</command>, with paths that are relative to
527 your current directory and not the root of the repository, feed
528 the output of <command>hg root</command> into <command>hg
529 status</command>. You can easily do this as follows on a
530 Unix-like system:</para>
532 <screen><prompt>$</prompt> <userinput>hg status `hg root`</userinput></screen>
533 </sect1>
534 </appendix>
536 <!--
537 local variables:
538 sgml-parent-document: ("00book.xml" "book" "appendix")
539 end:
540 -->