Show More
@@ -1,68 +1,387 b'' | |||||
1 | #!/bin/sh |
|
|||
2 |
|
||||
3 | cat >> $HGRCPATH <<EOF |
|
|||
4 | [extensions] |
|
|||
5 | convert= |
|
|||
6 | [convert] |
|
|||
7 | hg.saverev=False |
|
|||
8 | EOF |
|
|||
9 |
|
||||
10 | hg help convert |
|
|||
11 |
|
||||
12 | hg init a |
|
|||
13 | cd a |
|
|||
14 | echo a > a |
|
|||
15 | hg ci -d'0 0' -Ama |
|
|||
16 | hg cp a b |
|
|||
17 | hg ci -d'1 0' -mb |
|
|||
18 | hg rm a |
|
|||
19 | hg ci -d'2 0' -mc |
|
|||
20 | hg mv b a |
|
|||
21 | hg ci -d'3 0' -md |
|
|||
22 | echo a >> a |
|
|||
23 | hg ci -d'4 0' -me |
|
|||
24 |
|
||||
25 | cd .. |
|
|||
26 | hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded' |
|
|||
27 | hg --cwd a-hg pull ../a |
|
|||
28 |
|
||||
29 | touch bogusfile |
|
|||
30 | echo % should fail |
|
|||
31 | hg convert a bogusfile |
|
|||
32 |
|
1 | |||
33 | mkdir bogusdir |
|
2 | $ cat >> $HGRCPATH <<EOF | |
34 | chmod 000 bogusdir |
|
3 | > [extensions] | |
35 |
|
4 | > convert= | ||
36 | echo % should fail |
|
5 | > [convert] | |
37 | hg convert a bogusdir |
|
6 | > hg.saverev=False | |
38 |
|
7 | > EOF | ||
39 | echo % should succeed |
|
8 | $ hg help convert | |
40 | chmod 700 bogusdir |
|
9 | hg convert [OPTION]... SOURCE [DEST [REVMAP]] | |
41 | hg convert a bogusdir |
|
10 | ||
42 |
|
11 | convert a foreign SCM repository to a Mercurial one. | ||
43 | echo % test pre and post conversion actions |
|
12 | ||
44 | echo 'include b' > filemap |
|
13 | Accepted source formats [identifiers]: | |
45 | hg convert --debug --filemap filemap a partialb | \ |
|
14 | ||
46 | grep 'run hg' |
|
15 | - Mercurial [hg] | |
|
16 | - CVS [cvs] | |||
|
17 | - Darcs [darcs] | |||
|
18 | - git [git] | |||
|
19 | - Subversion [svn] | |||
|
20 | - Monotone [mtn] | |||
|
21 | - GNU Arch [gnuarch] | |||
|
22 | - Bazaar [bzr] | |||
|
23 | - Perforce [p4] | |||
|
24 | ||||
|
25 | Accepted destination formats [identifiers]: | |||
|
26 | ||||
|
27 | - Mercurial [hg] | |||
|
28 | - Subversion [svn] (history on branches is not preserved) | |||
|
29 | ||||
|
30 | If no revision is given, all revisions will be converted. Otherwise, | |||
|
31 | convert will only import up to the named revision (given in a format | |||
|
32 | understood by the source). | |||
|
33 | ||||
|
34 | If no destination directory name is specified, it defaults to the basename | |||
|
35 | of the source with "-hg" appended. If the destination repository doesn't | |||
|
36 | exist, it will be created. | |||
|
37 | ||||
|
38 | By default, all sources except Mercurial will use --branchsort. Mercurial | |||
|
39 | uses --sourcesort to preserve original revision numbers order. Sort modes | |||
|
40 | have the following effects: | |||
|
41 | ||||
|
42 | --branchsort convert from parent to child revision when possible, which | |||
|
43 | means branches are usually converted one after the other. It | |||
|
44 | generates more compact repositories. | |||
|
45 | --datesort sort revisions by date. Converted repositories have good- | |||
|
46 | looking changelogs but are often an order of magnitude | |||
|
47 | larger than the same ones generated by --branchsort. | |||
|
48 | --sourcesort try to preserve source revisions order, only supported by | |||
|
49 | Mercurial sources. | |||
|
50 | ||||
|
51 | If <REVMAP> isn't given, it will be put in a default location | |||
|
52 | (<dest>/.hg/shamap by default). The <REVMAP> is a simple text file that | |||
|
53 | maps each source commit ID to the destination ID for that revision, like | |||
|
54 | so: | |||
|
55 | ||||
|
56 | <source ID> <destination ID> | |||
|
57 | ||||
|
58 | If the file doesn't exist, it's automatically created. It's updated on | |||
|
59 | each commit copied, so "hg convert" can be interrupted and can be run | |||
|
60 | repeatedly to copy new commits. | |||
|
61 | ||||
|
62 | The authormap is a simple text file that maps each source commit author to | |||
|
63 | a destination commit author. It is handy for source SCMs that use unix | |||
|
64 | logins to identify authors (eg: CVS). One line per author mapping and the | |||
|
65 | line format is: | |||
|
66 | ||||
|
67 | source author = destination author | |||
|
68 | ||||
|
69 | Empty lines and lines starting with a "#" are ignored. | |||
|
70 | ||||
|
71 | The filemap is a file that allows filtering and remapping of files and | |||
|
72 | directories. Each line can contain one of the following directives: | |||
|
73 | ||||
|
74 | include path/to/file-or-dir | |||
|
75 | ||||
|
76 | exclude path/to/file-or-dir | |||
|
77 | ||||
|
78 | rename path/to/source path/to/destination | |||
|
79 | ||||
|
80 | Comment lines start with "#". A specified path matches if it equals the | |||
|
81 | full relative name of a file or one of its parent directories. The | |||
|
82 | "include" or "exclude" directive with the longest matching path applies, | |||
|
83 | so line order does not matter. | |||
|
84 | ||||
|
85 | The "include" directive causes a file, or all files under a directory, to | |||
|
86 | be included in the destination repository, and the exclusion of all other | |||
|
87 | files and directories not explicitly included. The "exclude" directive | |||
|
88 | causes files or directories to be omitted. The "rename" directive renames | |||
|
89 | a file or directory if it is converted. To rename from a subdirectory into | |||
|
90 | the root of the repository, use "." as the path to rename to. | |||
|
91 | ||||
|
92 | The splicemap is a file that allows insertion of synthetic history, | |||
|
93 | letting you specify the parents of a revision. This is useful if you want | |||
|
94 | to e.g. give a Subversion merge two parents, or graft two disconnected | |||
|
95 | series of history together. Each entry contains a key, followed by a | |||
|
96 | space, followed by one or two comma-separated values: | |||
|
97 | ||||
|
98 | key parent1, parent2 | |||
|
99 | ||||
|
100 | The key is the revision ID in the source revision control system whose | |||
|
101 | parents should be modified (same format as a key in .hg/shamap). The | |||
|
102 | values are the revision IDs (in either the source or destination revision | |||
|
103 | control system) that should be used as the new parents for that node. For | |||
|
104 | example, if you have merged "release-1.0" into "trunk", then you should | |||
|
105 | specify the revision on "trunk" as the first parent and the one on the | |||
|
106 | "release-1.0" branch as the second. | |||
|
107 | ||||
|
108 | The branchmap is a file that allows you to rename a branch when it is | |||
|
109 | being brought in from whatever external repository. When used in | |||
|
110 | conjunction with a splicemap, it allows for a powerful combination to help | |||
|
111 | fix even the most badly mismanaged repositories and turn them into nicely | |||
|
112 | structured Mercurial repositories. The branchmap contains lines of the | |||
|
113 | form: | |||
|
114 | ||||
|
115 | original_branch_name new_branch_name | |||
|
116 | ||||
|
117 | where "original_branch_name" is the name of the branch in the source | |||
|
118 | repository, and "new_branch_name" is the name of the branch is the | |||
|
119 | destination repository. No whitespace is allowed in the branch names. This | |||
|
120 | can be used to (for instance) move code in one repository from "default" | |||
|
121 | to a named branch. | |||
|
122 | ||||
|
123 | Mercurial Source | |||
|
124 | ---------------- | |||
|
125 | ||||
|
126 | --config convert.hg.ignoreerrors=False (boolean) | |||
|
127 | ignore integrity errors when reading. Use it to fix Mercurial | |||
|
128 | repositories with missing revlogs, by converting from and to | |||
|
129 | Mercurial. | |||
|
130 | ||||
|
131 | --config convert.hg.saverev=False (boolean) | |||
|
132 | store original revision ID in changeset (forces target IDs to change) | |||
|
133 | ||||
|
134 | --config convert.hg.startrev=0 (hg revision identifier) | |||
|
135 | convert start revision and its descendants | |||
|
136 | ||||
|
137 | CVS Source | |||
|
138 | ---------- | |||
|
139 | ||||
|
140 | CVS source will use a sandbox (i.e. a checked-out copy) from CVS to | |||
|
141 | indicate the starting point of what will be converted. Direct access to | |||
|
142 | the repository files is not needed, unless of course the repository is | |||
|
143 | :local:. The conversion uses the top level directory in the sandbox to | |||
|
144 | find the CVS repository, and then uses CVS rlog commands to find files to | |||
|
145 | convert. This means that unless a filemap is given, all files under the | |||
|
146 | starting directory will be converted, and that any directory | |||
|
147 | reorganization in the CVS sandbox is ignored. | |||
|
148 | ||||
|
149 | The options shown are the defaults. | |||
|
150 | ||||
|
151 | --config convert.cvsps.cache=True (boolean) | |||
|
152 | Set to False to disable remote log caching, for testing and debugging | |||
|
153 | purposes. | |||
|
154 | ||||
|
155 | --config convert.cvsps.fuzz=60 (integer) | |||
|
156 | Specify the maximum time (in seconds) that is allowed between commits | |||
|
157 | with identical user and log message in a single changeset. When very | |||
|
158 | large files were checked in as part of a changeset then the default | |||
|
159 | may not be long enough. | |||
|
160 | ||||
|
161 | --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}' | |||
|
162 | Specify a regular expression to which commit log messages are matched. | |||
|
163 | If a match occurs, then the conversion process will insert a dummy | |||
|
164 | revision merging the branch on which this log message occurs to the | |||
|
165 | branch indicated in the regex. | |||
|
166 | ||||
|
167 | --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}' | |||
|
168 | Specify a regular expression to which commit log messages are matched. | |||
|
169 | If a match occurs, then the conversion process will add the most | |||
|
170 | recent revision on the branch indicated in the regex as the second | |||
|
171 | parent of the changeset. | |||
|
172 | ||||
|
173 | --config hook.cvslog | |||
|
174 | Specify a Python function to be called at the end of gathering the CVS | |||
|
175 | log. The function is passed a list with the log entries, and can | |||
|
176 | modify the entries in-place, or add or delete them. | |||
|
177 | ||||
|
178 | --config hook.cvschangesets | |||
|
179 | Specify a Python function to be called after the changesets are | |||
|
180 | calculated from the the CVS log. The function is passed a list with | |||
|
181 | the changeset entries, and can modify the changesets in-place, or add | |||
|
182 | or delete them. | |||
|
183 | ||||
|
184 | An additional "debugcvsps" Mercurial command allows the builtin changeset | |||
|
185 | merging code to be run without doing a conversion. Its parameters and | |||
|
186 | output are similar to that of cvsps 2.1. Please see the command help for | |||
|
187 | more details. | |||
|
188 | ||||
|
189 | Subversion Source | |||
|
190 | ----------------- | |||
|
191 | ||||
|
192 | Subversion source detects classical trunk/branches/tags layouts. By | |||
|
193 | default, the supplied "svn://repo/path/" source URL is converted as a | |||
|
194 | single branch. If "svn://repo/path/trunk" exists it replaces the default | |||
|
195 | branch. If "svn://repo/path/branches" exists, its subdirectories are | |||
|
196 | listed as possible branches. If "svn://repo/path/tags" exists, it is | |||
|
197 | looked for tags referencing converted branches. Default "trunk", | |||
|
198 | "branches" and "tags" values can be overridden with following options. Set | |||
|
199 | them to paths relative to the source URL, or leave them blank to disable | |||
|
200 | auto detection. | |||
|
201 | ||||
|
202 | --config convert.svn.branches=branches (directory name) | |||
|
203 | specify the directory containing branches | |||
|
204 | ||||
|
205 | --config convert.svn.tags=tags (directory name) | |||
|
206 | specify the directory containing tags | |||
|
207 | ||||
|
208 | --config convert.svn.trunk=trunk (directory name) | |||
|
209 | specify the name of the trunk branch | |||
|
210 | ||||
|
211 | Source history can be retrieved starting at a specific revision, instead | |||
|
212 | of being integrally converted. Only single branch conversions are | |||
|
213 | supported. | |||
|
214 | ||||
|
215 | --config convert.svn.startrev=0 (svn revision number) | |||
|
216 | specify start Subversion revision. | |||
|
217 | ||||
|
218 | Perforce Source | |||
|
219 | --------------- | |||
|
220 | ||||
|
221 | The Perforce (P4) importer can be given a p4 depot path or a client | |||
|
222 | specification as source. It will convert all files in the source to a flat | |||
|
223 | Mercurial repository, ignoring labels, branches and integrations. Note | |||
|
224 | that when a depot path is given you then usually should specify a target | |||
|
225 | directory, because otherwise the target may be named ...-hg. | |||
|
226 | ||||
|
227 | It is possible to limit the amount of source history to be converted by | |||
|
228 | specifying an initial Perforce revision. | |||
|
229 | ||||
|
230 | --config convert.p4.startrev=0 (perforce changelist number) | |||
|
231 | specify initial Perforce revision. | |||
|
232 | ||||
|
233 | Mercurial Destination | |||
|
234 | --------------------- | |||
|
235 | ||||
|
236 | --config convert.hg.clonebranches=False (boolean) | |||
|
237 | dispatch source branches in separate clones. | |||
|
238 | ||||
|
239 | --config convert.hg.tagsbranch=default (branch name) | |||
|
240 | tag revisions branch name | |||
|
241 | ||||
|
242 | --config convert.hg.usebranchnames=True (boolean) | |||
|
243 | preserve branch names | |||
|
244 | ||||
|
245 | options: | |||
|
246 | ||||
|
247 | -s --source-type TYPE source repository type | |||
|
248 | -d --dest-type TYPE destination repository type | |||
|
249 | -r --rev REV import up to target revision REV | |||
|
250 | -A --authormap FILE remap usernames using this file | |||
|
251 | --filemap FILE remap file names using contents of file | |||
|
252 | --splicemap FILE splice synthesized history into place | |||
|
253 | --branchmap FILE change branch names while converting | |||
|
254 | --branchsort try to sort changesets by branches | |||
|
255 | --datesort try to sort changesets by date | |||
|
256 | --sourcesort preserve source changesets order | |||
|
257 | ||||
|
258 | use "hg -v help convert" to show global options | |||
|
259 | $ hg init a | |||
|
260 | $ cd a | |||
|
261 | $ echo a > a | |||
|
262 | $ hg ci -d'0 0' -Ama | |||
|
263 | adding a | |||
|
264 | $ hg cp a b | |||
|
265 | $ hg ci -d'1 0' -mb | |||
|
266 | $ hg rm a | |||
|
267 | $ hg ci -d'2 0' -mc | |||
|
268 | $ hg mv b a | |||
|
269 | $ hg ci -d'3 0' -md | |||
|
270 | $ echo a >> a | |||
|
271 | $ hg ci -d'4 0' -me | |||
|
272 | $ cd .. | |||
|
273 | $ hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded' | |||
|
274 | assuming destination a-hg | |||
|
275 | initializing destination a-hg repository | |||
|
276 | scanning source... | |||
|
277 | sorting... | |||
|
278 | converting... | |||
|
279 | 4 a | |||
|
280 | 3 b | |||
|
281 | 2 c | |||
|
282 | 1 d | |||
|
283 | 0 e | |||
|
284 | $ hg --cwd a-hg pull ../a | |||
|
285 | pulling from ../a | |||
|
286 | searching for changes | |||
|
287 | no changes found | |||
|
288 | $ touch bogusfile | |||
47 |
|
289 | |||
48 | echo % converting empty dir should fail "nicely" |
|
290 | should fail | |
49 | mkdir emptydir |
|
291 | ||
50 | # override $PATH to ensure p4 not visible; use $PYTHON in case we're |
|
292 | $ hg convert a bogusfile | |
51 | # running from a devel copy, not a temp installation |
|
293 | initializing destination bogusfile repository | |
52 | PATH="$BINDIR" $PYTHON "$BINDIR"/hg convert emptydir 2>&1 | sed 's,file://.*/emptydir,.../emptydir,g' |
|
294 | abort: cannot create new bundle repository | |
|
295 | [255] | |||
|
296 | $ mkdir bogusdir | |||
|
297 | $ chmod 000 bogusdir | |||
|
298 | ||||
|
299 | should fail | |||
|
300 | ||||
|
301 | $ hg convert a bogusdir | |||
|
302 | abort: Permission denied: bogusdir | |||
|
303 | [255] | |||
|
304 | ||||
|
305 | should succeed | |||
53 |
|
306 | |||
54 | echo % convert with imaginary source type |
|
307 | $ chmod 700 bogusdir | |
55 | hg convert --source-type foo a a-foo |
|
308 | $ hg convert a bogusdir | |
56 | echo % convert with imaginary sink type |
|
309 | initializing destination bogusdir repository | |
57 | hg convert --dest-type foo a a-foo |
|
310 | scanning source... | |
|
311 | sorting... | |||
|
312 | converting... | |||
|
313 | 4 a | |||
|
314 | 3 b | |||
|
315 | 2 c | |||
|
316 | 1 d | |||
|
317 | 0 e | |||
|
318 | ||||
|
319 | test pre and post conversion actions | |||
|
320 | ||||
|
321 | $ echo 'include b' > filemap | |||
|
322 | $ hg convert --debug --filemap filemap a partialb | \ | |||
|
323 | > grep 'run hg' | |||
|
324 | run hg source pre-conversion action | |||
|
325 | run hg sink pre-conversion action | |||
|
326 | run hg sink post-conversion action | |||
|
327 | run hg source post-conversion action | |||
|
328 | ||||
|
329 | converting empty dir should fail "nicely | |||
|
330 | ||||
|
331 | $ mkdir emptydir | |||
|
332 | ||||
|
333 | override $PATH to ensure p4 not visible; use $PYTHON in case we're | |||
|
334 | running from a devel copy, not a temp installation | |||
58 |
|
335 | |||
59 | echo |
|
336 | $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg convert emptydir | |
60 | echo % "testing: convert must not produce duplicate entries in fncache" |
|
337 | assuming destination emptydir-hg | |
61 | hg convert a b |
|
338 | initializing destination emptydir-hg repository | |
62 | echo % "contents of fncache file:" |
|
339 | emptydir does not look like a CVS checkout | |
63 | cat b/.hg/store/fncache |
|
340 | emptydir does not look like a Git repository | |
|
341 | emptydir does not look like a Subversion repository | |||
|
342 | emptydir is not a local Mercurial repository | |||
|
343 | emptydir does not look like a darcs repository | |||
|
344 | emptydir does not look like a monotone repository | |||
|
345 | emptydir does not look like a GNU Arch repository | |||
|
346 | emptydir does not look like a Bazaar repository | |||
|
347 | cannot find required "p4" tool | |||
|
348 | abort: emptydir: missing or unsupported repository | |||
|
349 | [255] | |||
|
350 | ||||
|
351 | convert with imaginary source type | |||
|
352 | ||||
|
353 | $ hg convert --source-type foo a a-foo | |||
|
354 | initializing destination a-foo repository | |||
|
355 | abort: foo: invalid source repository type | |||
|
356 | [255] | |||
|
357 | ||||
|
358 | convert with imaginary sink type | |||
64 |
|
359 | |||
65 | echo '% test bogus URL' |
|
360 | $ hg convert --dest-type foo a a-foo | |
66 | hg convert -q bzr+ssh://foobar@selenic.com/baz baz |
|
361 | abort: foo: invalid destination repository type | |
|
362 | [255] | |||
|
363 | ||||
|
364 | testing: convert must not produce duplicate entries in fncache | |||
67 |
|
365 | |||
68 | true |
|
366 | $ hg convert a b | |
|
367 | initializing destination b repository | |||
|
368 | scanning source... | |||
|
369 | sorting... | |||
|
370 | converting... | |||
|
371 | 4 a | |||
|
372 | 3 b | |||
|
373 | 2 c | |||
|
374 | 1 d | |||
|
375 | 0 e | |||
|
376 | ||||
|
377 | contents of fncache file: | |||
|
378 | ||||
|
379 | $ cat b/.hg/store/fncache | |||
|
380 | data/a.i | |||
|
381 | data/b.i | |||
|
382 | ||||
|
383 | test bogus URL | |||
|
384 | ||||
|
385 | $ hg convert -q bzr+ssh://foobar@selenic.com/baz baz | |||
|
386 | abort: bzr+ssh://foobar@selenic.com/baz: missing or unsupported repository | |||
|
387 | [255] |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now