##// END OF EJS Templates
convert: specify unit for ui.progress when operating on files
av6 -
r28470:80bd110d default
parent child Browse files
Show More
@@ -1,608 +1,608
1 1 # convcmd - convert extension commands definition
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7 from __future__ import absolute_import
8 8
9 9 import os
10 10 import shlex
11 11 import shutil
12 12
13 13 from mercurial import (
14 14 encoding,
15 15 error,
16 16 hg,
17 17 util,
18 18 )
19 19 from mercurial.i18n import _
20 20
21 21 from . import (
22 22 bzr,
23 23 common,
24 24 cvs,
25 25 darcs,
26 26 filemap,
27 27 git,
28 28 gnuarch,
29 29 hg as hgconvert,
30 30 monotone,
31 31 p4,
32 32 subversion,
33 33 )
34 34
35 35 mapfile = common.mapfile
36 36 MissingTool = common.MissingTool
37 37 NoRepo = common.NoRepo
38 38 SKIPREV = common.SKIPREV
39 39
40 40 bzr_source = bzr.bzr_source
41 41 convert_cvs = cvs.convert_cvs
42 42 convert_git = git.convert_git
43 43 darcs_source = darcs.darcs_source
44 44 gnuarch_source = gnuarch.gnuarch_source
45 45 mercurial_sink = hgconvert.mercurial_sink
46 46 mercurial_source = hgconvert.mercurial_source
47 47 monotone_source = monotone.monotone_source
48 48 p4_source = p4.p4_source
49 49 svn_sink = subversion.svn_sink
50 50 svn_source = subversion.svn_source
51 51
52 52 orig_encoding = 'ascii'
53 53
54 54 def recode(s):
55 55 if isinstance(s, unicode):
56 56 return s.encode(orig_encoding, 'replace')
57 57 else:
58 58 return s.decode('utf-8').encode(orig_encoding, 'replace')
59 59
60 60 def mapbranch(branch, branchmap):
61 61 '''
62 62 >>> bmap = {'default': 'branch1'}
63 63 >>> for i in ['', None]:
64 64 ... mapbranch(i, bmap)
65 65 'branch1'
66 66 'branch1'
67 67 >>> bmap = {'None': 'branch2'}
68 68 >>> for i in ['', None]:
69 69 ... mapbranch(i, bmap)
70 70 'branch2'
71 71 'branch2'
72 72 >>> bmap = {'None': 'branch3', 'default': 'branch4'}
73 73 >>> for i in ['None', '', None, 'default', 'branch5']:
74 74 ... mapbranch(i, bmap)
75 75 'branch3'
76 76 'branch4'
77 77 'branch4'
78 78 'branch4'
79 79 'branch5'
80 80 '''
81 81 # If branch is None or empty, this commit is coming from the source
82 82 # repository's default branch and destined for the default branch in the
83 83 # destination repository. For such commits, using a literal "default"
84 84 # in branchmap below allows the user to map "default" to an alternate
85 85 # default branch in the destination repository.
86 86 branch = branchmap.get(branch or 'default', branch)
87 87 # At some point we used "None" literal to denote the default branch,
88 88 # attempt to use that for backward compatibility.
89 89 if (not branch):
90 90 branch = branchmap.get(str(None), branch)
91 91 return branch
92 92
93 93 source_converters = [
94 94 ('cvs', convert_cvs, 'branchsort'),
95 95 ('git', convert_git, 'branchsort'),
96 96 ('svn', svn_source, 'branchsort'),
97 97 ('hg', mercurial_source, 'sourcesort'),
98 98 ('darcs', darcs_source, 'branchsort'),
99 99 ('mtn', monotone_source, 'branchsort'),
100 100 ('gnuarch', gnuarch_source, 'branchsort'),
101 101 ('bzr', bzr_source, 'branchsort'),
102 102 ('p4', p4_source, 'branchsort'),
103 103 ]
104 104
105 105 sink_converters = [
106 106 ('hg', mercurial_sink),
107 107 ('svn', svn_sink),
108 108 ]
109 109
110 110 def convertsource(ui, path, type, revs):
111 111 exceptions = []
112 112 if type and type not in [s[0] for s in source_converters]:
113 113 raise error.Abort(_('%s: invalid source repository type') % type)
114 114 for name, source, sortmode in source_converters:
115 115 try:
116 116 if not type or name == type:
117 117 return source(ui, path, revs), sortmode
118 118 except (NoRepo, MissingTool) as inst:
119 119 exceptions.append(inst)
120 120 if not ui.quiet:
121 121 for inst in exceptions:
122 122 ui.write("%s\n" % inst)
123 123 raise error.Abort(_('%s: missing or unsupported repository') % path)
124 124
125 125 def convertsink(ui, path, type):
126 126 if type and type not in [s[0] for s in sink_converters]:
127 127 raise error.Abort(_('%s: invalid destination repository type') % type)
128 128 for name, sink in sink_converters:
129 129 try:
130 130 if not type or name == type:
131 131 return sink(ui, path)
132 132 except NoRepo as inst:
133 133 ui.note(_("convert: %s\n") % inst)
134 134 except MissingTool as inst:
135 135 raise error.Abort('%s\n' % inst)
136 136 raise error.Abort(_('%s: unknown repository type') % path)
137 137
138 138 class progresssource(object):
139 139 def __init__(self, ui, source, filecount):
140 140 self.ui = ui
141 141 self.source = source
142 142 self.filecount = filecount
143 143 self.retrieved = 0
144 144
145 145 def getfile(self, file, rev):
146 146 self.retrieved += 1
147 147 self.ui.progress(_('getting files'), self.retrieved,
148 item=file, total=self.filecount)
148 item=file, total=self.filecount, unit=_('files'))
149 149 return self.source.getfile(file, rev)
150 150
151 151 def targetfilebelongstosource(self, targetfilename):
152 152 return self.source.targetfilebelongstosource(targetfilename)
153 153
154 154 def lookuprev(self, rev):
155 155 return self.source.lookuprev(rev)
156 156
157 157 def close(self):
158 158 self.ui.progress(_('getting files'), None)
159 159
160 160 class converter(object):
161 161 def __init__(self, ui, source, dest, revmapfile, opts):
162 162
163 163 self.source = source
164 164 self.dest = dest
165 165 self.ui = ui
166 166 self.opts = opts
167 167 self.commitcache = {}
168 168 self.authors = {}
169 169 self.authorfile = None
170 170
171 171 # Record converted revisions persistently: maps source revision
172 172 # ID to target revision ID (both strings). (This is how
173 173 # incremental conversions work.)
174 174 self.map = mapfile(ui, revmapfile)
175 175
176 176 # Read first the dst author map if any
177 177 authorfile = self.dest.authorfile()
178 178 if authorfile and os.path.exists(authorfile):
179 179 self.readauthormap(authorfile)
180 180 # Extend/Override with new author map if necessary
181 181 if opts.get('authormap'):
182 182 self.readauthormap(opts.get('authormap'))
183 183 self.authorfile = self.dest.authorfile()
184 184
185 185 self.splicemap = self.parsesplicemap(opts.get('splicemap'))
186 186 self.branchmap = mapfile(ui, opts.get('branchmap'))
187 187
188 188 def parsesplicemap(self, path):
189 189 """ check and validate the splicemap format and
190 190 return a child/parents dictionary.
191 191 Format checking has two parts.
192 192 1. generic format which is same across all source types
193 193 2. specific format checking which may be different for
194 194 different source type. This logic is implemented in
195 195 checkrevformat function in source files like
196 196 hg.py, subversion.py etc.
197 197 """
198 198
199 199 if not path:
200 200 return {}
201 201 m = {}
202 202 try:
203 203 fp = open(path, 'r')
204 204 for i, line in enumerate(fp):
205 205 line = line.splitlines()[0].rstrip()
206 206 if not line:
207 207 # Ignore blank lines
208 208 continue
209 209 # split line
210 210 lex = shlex.shlex(line, posix=True)
211 211 lex.whitespace_split = True
212 212 lex.whitespace += ','
213 213 line = list(lex)
214 214 # check number of parents
215 215 if not (2 <= len(line) <= 3):
216 216 raise error.Abort(_('syntax error in %s(%d): child parent1'
217 217 '[,parent2] expected') % (path, i + 1))
218 218 for part in line:
219 219 self.source.checkrevformat(part)
220 220 child, p1, p2 = line[0], line[1:2], line[2:]
221 221 if p1 == p2:
222 222 m[child] = p1
223 223 else:
224 224 m[child] = p1 + p2
225 225 # if file does not exist or error reading, exit
226 226 except IOError:
227 227 raise error.Abort(_('splicemap file not found or error reading %s:')
228 228 % path)
229 229 return m
230 230
231 231
232 232 def walktree(self, heads):
233 233 '''Return a mapping that identifies the uncommitted parents of every
234 234 uncommitted changeset.'''
235 235 visit = heads
236 236 known = set()
237 237 parents = {}
238 238 numcommits = self.source.numcommits()
239 239 while visit:
240 240 n = visit.pop(0)
241 241 if n in known:
242 242 continue
243 243 if n in self.map:
244 244 m = self.map[n]
245 245 if m == SKIPREV or self.dest.hascommitfrommap(m):
246 246 continue
247 247 known.add(n)
248 248 self.ui.progress(_('scanning'), len(known), unit=_('revisions'),
249 249 total=numcommits)
250 250 commit = self.cachecommit(n)
251 251 parents[n] = []
252 252 for p in commit.parents:
253 253 parents[n].append(p)
254 254 visit.append(p)
255 255 self.ui.progress(_('scanning'), None)
256 256
257 257 return parents
258 258
259 259 def mergesplicemap(self, parents, splicemap):
260 260 """A splicemap redefines child/parent relationships. Check the
261 261 map contains valid revision identifiers and merge the new
262 262 links in the source graph.
263 263 """
264 264 for c in sorted(splicemap):
265 265 if c not in parents:
266 266 if not self.dest.hascommitforsplicemap(self.map.get(c, c)):
267 267 # Could be in source but not converted during this run
268 268 self.ui.warn(_('splice map revision %s is not being '
269 269 'converted, ignoring\n') % c)
270 270 continue
271 271 pc = []
272 272 for p in splicemap[c]:
273 273 # We do not have to wait for nodes already in dest.
274 274 if self.dest.hascommitforsplicemap(self.map.get(p, p)):
275 275 continue
276 276 # Parent is not in dest and not being converted, not good
277 277 if p not in parents:
278 278 raise error.Abort(_('unknown splice map parent: %s') % p)
279 279 pc.append(p)
280 280 parents[c] = pc
281 281
282 282 def toposort(self, parents, sortmode):
283 283 '''Return an ordering such that every uncommitted changeset is
284 284 preceded by all its uncommitted ancestors.'''
285 285
286 286 def mapchildren(parents):
287 287 """Return a (children, roots) tuple where 'children' maps parent
288 288 revision identifiers to children ones, and 'roots' is the list of
289 289 revisions without parents. 'parents' must be a mapping of revision
290 290 identifier to its parents ones.
291 291 """
292 292 visit = sorted(parents)
293 293 seen = set()
294 294 children = {}
295 295 roots = []
296 296
297 297 while visit:
298 298 n = visit.pop(0)
299 299 if n in seen:
300 300 continue
301 301 seen.add(n)
302 302 # Ensure that nodes without parents are present in the
303 303 # 'children' mapping.
304 304 children.setdefault(n, [])
305 305 hasparent = False
306 306 for p in parents[n]:
307 307 if p not in self.map:
308 308 visit.append(p)
309 309 hasparent = True
310 310 children.setdefault(p, []).append(n)
311 311 if not hasparent:
312 312 roots.append(n)
313 313
314 314 return children, roots
315 315
316 316 # Sort functions are supposed to take a list of revisions which
317 317 # can be converted immediately and pick one
318 318
319 319 def makebranchsorter():
320 320 """If the previously converted revision has a child in the
321 321 eligible revisions list, pick it. Return the list head
322 322 otherwise. Branch sort attempts to minimize branch
323 323 switching, which is harmful for Mercurial backend
324 324 compression.
325 325 """
326 326 prev = [None]
327 327 def picknext(nodes):
328 328 next = nodes[0]
329 329 for n in nodes:
330 330 if prev[0] in parents[n]:
331 331 next = n
332 332 break
333 333 prev[0] = next
334 334 return next
335 335 return picknext
336 336
337 337 def makesourcesorter():
338 338 """Source specific sort."""
339 339 keyfn = lambda n: self.commitcache[n].sortkey
340 340 def picknext(nodes):
341 341 return sorted(nodes, key=keyfn)[0]
342 342 return picknext
343 343
344 344 def makeclosesorter():
345 345 """Close order sort."""
346 346 keyfn = lambda n: ('close' not in self.commitcache[n].extra,
347 347 self.commitcache[n].sortkey)
348 348 def picknext(nodes):
349 349 return sorted(nodes, key=keyfn)[0]
350 350 return picknext
351 351
352 352 def makedatesorter():
353 353 """Sort revisions by date."""
354 354 dates = {}
355 355 def getdate(n):
356 356 if n not in dates:
357 357 dates[n] = util.parsedate(self.commitcache[n].date)
358 358 return dates[n]
359 359
360 360 def picknext(nodes):
361 361 return min([(getdate(n), n) for n in nodes])[1]
362 362
363 363 return picknext
364 364
365 365 if sortmode == 'branchsort':
366 366 picknext = makebranchsorter()
367 367 elif sortmode == 'datesort':
368 368 picknext = makedatesorter()
369 369 elif sortmode == 'sourcesort':
370 370 picknext = makesourcesorter()
371 371 elif sortmode == 'closesort':
372 372 picknext = makeclosesorter()
373 373 else:
374 374 raise error.Abort(_('unknown sort mode: %s') % sortmode)
375 375
376 376 children, actives = mapchildren(parents)
377 377
378 378 s = []
379 379 pendings = {}
380 380 while actives:
381 381 n = picknext(actives)
382 382 actives.remove(n)
383 383 s.append(n)
384 384
385 385 # Update dependents list
386 386 for c in children.get(n, []):
387 387 if c not in pendings:
388 388 pendings[c] = [p for p in parents[c] if p not in self.map]
389 389 try:
390 390 pendings[c].remove(n)
391 391 except ValueError:
392 392 raise error.Abort(_('cycle detected between %s and %s')
393 393 % (recode(c), recode(n)))
394 394 if not pendings[c]:
395 395 # Parents are converted, node is eligible
396 396 actives.insert(0, c)
397 397 pendings[c] = None
398 398
399 399 if len(s) != len(parents):
400 400 raise error.Abort(_("not all revisions were sorted"))
401 401
402 402 return s
403 403
404 404 def writeauthormap(self):
405 405 authorfile = self.authorfile
406 406 if authorfile:
407 407 self.ui.status(_('writing author map file %s\n') % authorfile)
408 408 ofile = open(authorfile, 'w+')
409 409 for author in self.authors:
410 410 ofile.write("%s=%s\n" % (author, self.authors[author]))
411 411 ofile.close()
412 412
413 413 def readauthormap(self, authorfile):
414 414 afile = open(authorfile, 'r')
415 415 for line in afile:
416 416
417 417 line = line.strip()
418 418 if not line or line.startswith('#'):
419 419 continue
420 420
421 421 try:
422 422 srcauthor, dstauthor = line.split('=', 1)
423 423 except ValueError:
424 424 msg = _('ignoring bad line in author map file %s: %s\n')
425 425 self.ui.warn(msg % (authorfile, line.rstrip()))
426 426 continue
427 427
428 428 srcauthor = srcauthor.strip()
429 429 dstauthor = dstauthor.strip()
430 430 if self.authors.get(srcauthor) in (None, dstauthor):
431 431 msg = _('mapping author %s to %s\n')
432 432 self.ui.debug(msg % (srcauthor, dstauthor))
433 433 self.authors[srcauthor] = dstauthor
434 434 continue
435 435
436 436 m = _('overriding mapping for author %s, was %s, will be %s\n')
437 437 self.ui.status(m % (srcauthor, self.authors[srcauthor], dstauthor))
438 438
439 439 afile.close()
440 440
441 441 def cachecommit(self, rev):
442 442 commit = self.source.getcommit(rev)
443 443 commit.author = self.authors.get(commit.author, commit.author)
444 444 commit.branch = mapbranch(commit.branch, self.branchmap)
445 445 self.commitcache[rev] = commit
446 446 return commit
447 447
448 448 def copy(self, rev):
449 449 commit = self.commitcache[rev]
450 450 full = self.opts.get('full')
451 451 changes = self.source.getchanges(rev, full)
452 452 if isinstance(changes, basestring):
453 453 if changes == SKIPREV:
454 454 dest = SKIPREV
455 455 else:
456 456 dest = self.map[changes]
457 457 self.map[rev] = dest
458 458 return
459 459 files, copies, cleanp2 = changes
460 460 pbranches = []
461 461 if commit.parents:
462 462 for prev in commit.parents:
463 463 if prev not in self.commitcache:
464 464 self.cachecommit(prev)
465 465 pbranches.append((self.map[prev],
466 466 self.commitcache[prev].branch))
467 467 self.dest.setbranch(commit.branch, pbranches)
468 468 try:
469 469 parents = self.splicemap[rev]
470 470 self.ui.status(_('spliced in %s as parents of %s\n') %
471 471 (_(' and ').join(parents), rev))
472 472 parents = [self.map.get(p, p) for p in parents]
473 473 except KeyError:
474 474 parents = [b[0] for b in pbranches]
475 475 if len(pbranches) != 2:
476 476 cleanp2 = set()
477 477 if len(parents) < 3:
478 478 source = progresssource(self.ui, self.source, len(files))
479 479 else:
480 480 # For an octopus merge, we end up traversing the list of
481 481 # changed files N-1 times. This tweak to the number of
482 482 # files makes it so the progress bar doesn't overflow
483 483 # itself.
484 484 source = progresssource(self.ui, self.source,
485 485 len(files) * (len(parents) - 1))
486 486 newnode = self.dest.putcommit(files, copies, parents, commit,
487 487 source, self.map, full, cleanp2)
488 488 source.close()
489 489 self.source.converted(rev, newnode)
490 490 self.map[rev] = newnode
491 491
492 492 def convert(self, sortmode):
493 493 try:
494 494 self.source.before()
495 495 self.dest.before()
496 496 self.source.setrevmap(self.map)
497 497 self.ui.status(_("scanning source...\n"))
498 498 heads = self.source.getheads()
499 499 parents = self.walktree(heads)
500 500 self.mergesplicemap(parents, self.splicemap)
501 501 self.ui.status(_("sorting...\n"))
502 502 t = self.toposort(parents, sortmode)
503 503 num = len(t)
504 504 c = None
505 505
506 506 self.ui.status(_("converting...\n"))
507 507 for i, c in enumerate(t):
508 508 num -= 1
509 509 desc = self.commitcache[c].desc
510 510 if "\n" in desc:
511 511 desc = desc.splitlines()[0]
512 512 # convert log message to local encoding without using
513 513 # tolocal() because the encoding.encoding convert()
514 514 # uses is 'utf-8'
515 515 self.ui.status("%d %s\n" % (num, recode(desc)))
516 516 self.ui.note(_("source: %s\n") % recode(c))
517 517 self.ui.progress(_('converting'), i, unit=_('revisions'),
518 518 total=len(t))
519 519 self.copy(c)
520 520 self.ui.progress(_('converting'), None)
521 521
522 522 if not self.ui.configbool('convert', 'skiptags'):
523 523 tags = self.source.gettags()
524 524 ctags = {}
525 525 for k in tags:
526 526 v = tags[k]
527 527 if self.map.get(v, SKIPREV) != SKIPREV:
528 528 ctags[k] = self.map[v]
529 529
530 530 if c and ctags:
531 531 nrev, tagsparent = self.dest.puttags(ctags)
532 532 if nrev and tagsparent:
533 533 # write another hash correspondence to override the
534 534 # previous one so we don't end up with extra tag heads
535 535 tagsparents = [e for e in self.map.iteritems()
536 536 if e[1] == tagsparent]
537 537 if tagsparents:
538 538 self.map[tagsparents[0][0]] = nrev
539 539
540 540 bookmarks = self.source.getbookmarks()
541 541 cbookmarks = {}
542 542 for k in bookmarks:
543 543 v = bookmarks[k]
544 544 if self.map.get(v, SKIPREV) != SKIPREV:
545 545 cbookmarks[k] = self.map[v]
546 546
547 547 if c and cbookmarks:
548 548 self.dest.putbookmarks(cbookmarks)
549 549
550 550 self.writeauthormap()
551 551 finally:
552 552 self.cleanup()
553 553
554 554 def cleanup(self):
555 555 try:
556 556 self.dest.after()
557 557 finally:
558 558 self.source.after()
559 559 self.map.close()
560 560
561 561 def convert(ui, src, dest=None, revmapfile=None, **opts):
562 562 global orig_encoding
563 563 orig_encoding = encoding.encoding
564 564 encoding.encoding = 'UTF-8'
565 565
566 566 # support --authors as an alias for --authormap
567 567 if not opts.get('authormap'):
568 568 opts['authormap'] = opts.get('authors')
569 569
570 570 if not dest:
571 571 dest = hg.defaultdest(src) + "-hg"
572 572 ui.status(_("assuming destination %s\n") % dest)
573 573
574 574 destc = convertsink(ui, dest, opts.get('dest_type'))
575 575
576 576 try:
577 577 srcc, defaultsort = convertsource(ui, src, opts.get('source_type'),
578 578 opts.get('rev'))
579 579 except Exception:
580 580 for path in destc.created:
581 581 shutil.rmtree(path, True)
582 582 raise
583 583
584 584 sortmodes = ('branchsort', 'datesort', 'sourcesort', 'closesort')
585 585 sortmode = [m for m in sortmodes if opts.get(m)]
586 586 if len(sortmode) > 1:
587 587 raise error.Abort(_('more than one sort mode specified'))
588 588 if sortmode:
589 589 sortmode = sortmode[0]
590 590 else:
591 591 sortmode = defaultsort
592 592
593 593 if sortmode == 'sourcesort' and not srcc.hasnativeorder():
594 594 raise error.Abort(_('--sourcesort is not supported by this data source')
595 595 )
596 596 if sortmode == 'closesort' and not srcc.hasnativeclose():
597 597 raise error.Abort(_('--closesort is not supported by this data source'))
598 598
599 599 fmap = opts.get('filemap')
600 600 if fmap:
601 601 srcc = filemap.filemap_source(ui, srcc, fmap)
602 602 destc.setfilemapmode(True)
603 603
604 604 if not revmapfile:
605 605 revmapfile = destc.revmapfile()
606 606
607 607 c = converter(ui, srcc, destc, revmapfile, opts)
608 608 c.convert(sortmode)
@@ -1,144 +1,144
1 1 #require svn svn-bindings
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > convert =
6 6 > EOF
7 7
8 8 $ svnadmin create svn-repo
9 9 $ svnadmin load -q svn-repo < "$TESTDIR/svn/encoding.svndump"
10 10
11 11 Convert while testing all possible outputs
12 12
13 13 $ hg --debug convert svn-repo A-hg --config progress.debug=1
14 14 initializing destination A-hg repository
15 15 reparent to file://*/svn-repo (glob)
16 16 run hg sink pre-conversion action
17 17 scanning source...
18 18 found trunk at 'trunk'
19 19 found tags at 'tags'
20 20 found branches at 'branches'
21 21 found branch branch\xc3\xa9 at 5 (esc)
22 22 found branch branch\xc3\xa9e at 6 (esc)
23 23 scanning: 1/4 revisions (25.00%)
24 24 reparent to file://*/svn-repo/trunk (glob)
25 25 fetching revision log for "/trunk" from 4 to 0
26 26 parsing revision 4 (2 changes)
27 27 parsing revision 3 (4 changes)
28 28 parsing revision 2 (3 changes)
29 29 parsing revision 1 (3 changes)
30 30 no copyfrom path, don't know what to do.
31 31 '/branches' is not under '/trunk', ignoring
32 32 '/tags' is not under '/trunk', ignoring
33 33 scanning: 2/4 revisions (50.00%)
34 34 reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
35 35 fetching revision log for "/branches/branch\xc3\xa9" from 5 to 0 (esc)
36 36 parsing revision 5 (1 changes)
37 37 reparent to file://*/svn-repo (glob)
38 38 reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
39 39 found parent of branch /branches/branch\xc3\xa9 at 4: /trunk (esc)
40 40 scanning: 3/4 revisions (75.00%)
41 41 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
42 42 fetching revision log for "/branches/branch\xc3\xa9e" from 6 to 0 (esc)
43 43 parsing revision 6 (1 changes)
44 44 reparent to file://*/svn-repo (glob)
45 45 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
46 46 found parent of branch /branches/branch\xc3\xa9e at 5: /branches/branch\xc3\xa9 (esc)
47 47 scanning: 4/4 revisions (100.00%)
48 48 scanning: 5/4 revisions (125.00%)
49 49 scanning: 6/4 revisions (150.00%)
50 50 sorting...
51 51 converting...
52 52 5 init projA
53 53 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@1
54 54 converting: 0/6 revisions (0.00%)
55 55 committing changelog
56 56 4 hello
57 57 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@2
58 58 converting: 1/6 revisions (16.67%)
59 59 reparent to file://*/svn-repo/trunk (glob)
60 60 scanning paths: /trunk/\xc3\xa0 0/3 (0.00%) (esc)
61 61 scanning paths: /trunk/\xc3\xa0/e\xcc\x81 1/3 (33.33%) (esc)
62 62 scanning paths: /trunk/\xc3\xa9 2/3 (66.67%) (esc)
63 63 committing files:
64 64 \xc3\xa0/e\xcc\x81 (esc)
65 getting files: \xc3\xa0/e\xcc\x81 1/2 (50.00%) (esc)
65 getting files: \xc3\xa0/e\xcc\x81 1/2 files (50.00%) (esc)
66 66 \xc3\xa9 (esc)
67 getting files: \xc3\xa9 2/2 (100.00%) (esc)
67 getting files: \xc3\xa9 2/2 files (100.00%) (esc)
68 68 committing manifest
69 69 committing changelog
70 70 3 copy files
71 71 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@3
72 72 converting: 2/6 revisions (33.33%)
73 73 scanning paths: /trunk/\xc3\xa0 0/4 (0.00%) (esc)
74 74 gone from -1
75 75 reparent to file://*/svn-repo (glob)
76 76 reparent to file://*/svn-repo/trunk (glob)
77 77 scanning paths: /trunk/\xc3\xa8 1/4 (25.00%) (esc)
78 78 copied to \xc3\xa8 from \xc3\xa9@2 (esc)
79 79 scanning paths: /trunk/\xc3\xa9 2/4 (50.00%) (esc)
80 80 gone from -1
81 81 reparent to file://*/svn-repo (glob)
82 82 reparent to file://*/svn-repo/trunk (glob)
83 83 scanning paths: /trunk/\xc3\xb9 3/4 (75.00%) (esc)
84 84 mark /trunk/\xc3\xb9 came from \xc3\xa0:2 (esc)
85 getting files: \xc3\xa0/e\xcc\x81 1/4 (25.00%) (esc)
86 getting files: \xc3\xa9 2/4 (50.00%) (esc)
85 getting files: \xc3\xa0/e\xcc\x81 1/4 files (25.00%) (esc)
86 getting files: \xc3\xa9 2/4 files (50.00%) (esc)
87 87 committing files:
88 88 \xc3\xa8 (esc)
89 getting files: \xc3\xa8 3/4 (75.00%) (esc)
89 getting files: \xc3\xa8 3/4 files (75.00%) (esc)
90 90 \xc3\xa8: copy \xc3\xa9:6b67ccefd5ce6de77e7ead4f5292843a0255329f (esc)
91 91 \xc3\xb9/e\xcc\x81 (esc)
92 getting files: \xc3\xb9/e\xcc\x81 4/4 (100.00%) (esc)
92 getting files: \xc3\xb9/e\xcc\x81 4/4 files (100.00%) (esc)
93 93 \xc3\xb9/e\xcc\x81: copy \xc3\xa0/e\xcc\x81:a9092a3d84a37b9993b5c73576f6de29b7ea50f6 (esc)
94 94 committing manifest
95 95 committing changelog
96 96 2 remove files
97 97 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@4
98 98 converting: 3/6 revisions (50.00%)
99 99 scanning paths: /trunk/\xc3\xa8 0/2 (0.00%) (esc)
100 100 gone from -1
101 101 reparent to file://*/svn-repo (glob)
102 102 reparent to file://*/svn-repo/trunk (glob)
103 103 scanning paths: /trunk/\xc3\xb9 1/2 (50.00%) (esc)
104 104 gone from -1
105 105 reparent to file://*/svn-repo (glob)
106 106 reparent to file://*/svn-repo/trunk (glob)
107 getting files: \xc3\xa8 1/2 (50.00%) (esc)
108 getting files: \xc3\xb9/e\xcc\x81 2/2 (100.00%) (esc)
107 getting files: \xc3\xa8 1/2 files (50.00%) (esc)
108 getting files: \xc3\xb9/e\xcc\x81 2/2 files (100.00%) (esc)
109 109 committing files:
110 110 committing manifest
111 111 committing changelog
112 112 1 branch to branch?
113 113 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/branches/branch?@5
114 114 converting: 4/6 revisions (66.67%)
115 115 reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
116 116 scanning paths: /branches/branch\xc3\xa9 0/1 (0.00%) (esc)
117 117 committing changelog
118 118 0 branch to branch?e
119 119 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/branches/branch?e@6
120 120 converting: 5/6 revisions (83.33%)
121 121 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
122 122 scanning paths: /branches/branch\xc3\xa9e 0/1 (0.00%) (esc)
123 123 committing changelog
124 124 reparent to file://*/svn-repo (glob)
125 125 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
126 126 reparent to file://*/svn-repo (glob)
127 127 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
128 128 updating tags
129 129 committing files:
130 130 .hgtags
131 131 committing manifest
132 132 committing changelog
133 133 run hg sink post-conversion action
134 134 $ cd A-hg
135 135 $ hg up
136 136 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
137 137
138 138 Check tags are in UTF-8
139 139
140 140 $ cat .hgtags
141 141 e94e4422020e715add80525e8f0f46c9968689f1 branch\xc3\xa9e (esc)
142 142 f7e66f98380ed1e53a797c5c7a7a2616a7ab377d branch\xc3\xa9 (esc)
143 143
144 144 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now