##// END OF EJS Templates
convert: fix convert dropping p2 contents during filemap merge...
Durham Goode -
r26037:a75d2453 default
parent child Browse files
Show More
@@ -1,568 +1,616 b''
1 1 # hg.py - hg backend for convert extension
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
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
8 8 # Notes for hg->hg conversion:
9 9 #
10 10 # * Old versions of Mercurial didn't trim the whitespace from the ends
11 11 # of commit messages, but new versions do. Changesets created by
12 12 # those older versions, then converted, may thus have different
13 13 # hashes for changesets that are otherwise identical.
14 14 #
15 15 # * Using "--config convert.hg.saverev=true" will make the source
16 16 # identifier to be stored in the converted revision. This will cause
17 17 # the converted revision to have a different identity than the
18 18 # source.
19 19
20 20
21 21 import os, time, cStringIO
22 22 from mercurial.i18n import _
23 23 from mercurial.node import bin, hex, nullid
24 24 from mercurial import hg, util, context, bookmarks, error, scmutil, exchange
25 25 from mercurial import phases
26 from mercurial import merge as mergemod
26 27
27 28 from common import NoRepo, commit, converter_source, converter_sink, mapfile
28 29
29 30 import re
30 31 sha1re = re.compile(r'\b[0-9a-f]{12,40}\b')
31 32
32 33 class mercurial_sink(converter_sink):
33 34 def __init__(self, ui, path):
34 35 converter_sink.__init__(self, ui, path)
35 36 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
36 37 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
37 38 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
38 39 self.lastbranch = None
39 40 if os.path.isdir(path) and len(os.listdir(path)) > 0:
40 41 try:
41 42 self.repo = hg.repository(self.ui, path)
42 43 if not self.repo.local():
43 44 raise NoRepo(_('%s is not a local Mercurial repository')
44 45 % path)
45 46 except error.RepoError as err:
46 47 ui.traceback()
47 48 raise NoRepo(err.args[0])
48 49 else:
49 50 try:
50 51 ui.status(_('initializing destination %s repository\n') % path)
51 52 self.repo = hg.repository(self.ui, path, create=True)
52 53 if not self.repo.local():
53 54 raise NoRepo(_('%s is not a local Mercurial repository')
54 55 % path)
55 56 self.created.append(path)
56 57 except error.RepoError:
57 58 ui.traceback()
58 59 raise NoRepo(_("could not create hg repository %s as sink")
59 60 % path)
60 61 self.lock = None
61 62 self.wlock = None
62 63 self.filemapmode = False
63 64 self.subrevmaps = {}
64 65
65 66 def before(self):
66 67 self.ui.debug('run hg sink pre-conversion action\n')
67 68 self.wlock = self.repo.wlock()
68 69 self.lock = self.repo.lock()
69 70
70 71 def after(self):
71 72 self.ui.debug('run hg sink post-conversion action\n')
72 73 if self.lock:
73 74 self.lock.release()
74 75 if self.wlock:
75 76 self.wlock.release()
76 77
77 78 def revmapfile(self):
78 79 return self.repo.join("shamap")
79 80
80 81 def authorfile(self):
81 82 return self.repo.join("authormap")
82 83
83 84 def setbranch(self, branch, pbranches):
84 85 if not self.clonebranches:
85 86 return
86 87
87 88 setbranch = (branch != self.lastbranch)
88 89 self.lastbranch = branch
89 90 if not branch:
90 91 branch = 'default'
91 92 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
92 93 if pbranches:
93 94 pbranch = pbranches[0][1]
94 95 else:
95 96 pbranch = 'default'
96 97
97 98 branchpath = os.path.join(self.path, branch)
98 99 if setbranch:
99 100 self.after()
100 101 try:
101 102 self.repo = hg.repository(self.ui, branchpath)
102 103 except Exception:
103 104 self.repo = hg.repository(self.ui, branchpath, create=True)
104 105 self.before()
105 106
106 107 # pbranches may bring revisions from other branches (merge parents)
107 108 # Make sure we have them, or pull them.
108 109 missings = {}
109 110 for b in pbranches:
110 111 try:
111 112 self.repo.lookup(b[0])
112 113 except Exception:
113 114 missings.setdefault(b[1], []).append(b[0])
114 115
115 116 if missings:
116 117 self.after()
117 118 for pbranch, heads in sorted(missings.iteritems()):
118 119 pbranchpath = os.path.join(self.path, pbranch)
119 120 prepo = hg.peer(self.ui, {}, pbranchpath)
120 121 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
121 122 exchange.pull(self.repo, prepo,
122 123 [prepo.lookup(h) for h in heads])
123 124 self.before()
124 125
125 126 def _rewritetags(self, source, revmap, data):
126 127 fp = cStringIO.StringIO()
127 128 for line in data.splitlines():
128 129 s = line.split(' ', 1)
129 130 if len(s) != 2:
130 131 continue
131 132 revid = revmap.get(source.lookuprev(s[0]))
132 133 if not revid:
133 134 if s[0] == hex(nullid):
134 135 revid = s[0]
135 136 else:
136 137 continue
137 138 fp.write('%s %s\n' % (revid, s[1]))
138 139 return fp.getvalue()
139 140
140 141 def _rewritesubstate(self, source, data):
141 142 fp = cStringIO.StringIO()
142 143 for line in data.splitlines():
143 144 s = line.split(' ', 1)
144 145 if len(s) != 2:
145 146 continue
146 147
147 148 revid = s[0]
148 149 subpath = s[1]
149 150 if revid != hex(nullid):
150 151 revmap = self.subrevmaps.get(subpath)
151 152 if revmap is None:
152 153 revmap = mapfile(self.ui,
153 154 self.repo.wjoin(subpath, '.hg/shamap'))
154 155 self.subrevmaps[subpath] = revmap
155 156
156 157 # It is reasonable that one or more of the subrepos don't
157 158 # need to be converted, in which case they can be cloned
158 159 # into place instead of converted. Therefore, only warn
159 160 # once.
160 161 msg = _('no ".hgsubstate" updates will be made for "%s"\n')
161 162 if len(revmap) == 0:
162 163 sub = self.repo.wvfs.reljoin(subpath, '.hg')
163 164
164 165 if self.repo.wvfs.exists(sub):
165 166 self.ui.warn(msg % subpath)
166 167
167 168 newid = revmap.get(revid)
168 169 if not newid:
169 170 if len(revmap) > 0:
170 171 self.ui.warn(_("%s is missing from %s/.hg/shamap\n") %
171 172 (revid, subpath))
172 173 else:
173 174 revid = newid
174 175
175 176 fp.write('%s %s\n' % (revid, subpath))
176 177
177 178 return fp.getvalue()
178 179
180 def _calculatemergedfiles(self, source, p1ctx, p2ctx):
181 """Calculates the files from p2 that we need to pull in when merging p1
182 and p2, given that the merge is coming from the given source.
183
184 This prevents us from losing files that only exist in the target p2 and
185 that don't come from the source repo (like if you're merging multiple
186 repositories together).
187 """
188 anc = [p1ctx.ancestor(p2ctx)]
189 # Calculate what files are coming from p2
190 actions, diverge, rename = mergemod.calculateupdates(
191 self.repo, p1ctx, p2ctx, anc,
192 True, # branchmerge
193 True, # force
194 False, # partial
195 False, # acceptremote
196 False, # followcopies
197 )
198
199 for file, (action, info, msg) in actions.iteritems():
200 if source.targetfilebelongstosource(file):
201 # If the file belongs to the source repo, ignore the p2
202 # since it will be covered by the existing fileset.
203 continue
204
205 # If the file requires actual merging, abort. We don't have enough
206 # context to resolve merges correctly.
207 if action in ['m', 'dm', 'cd', 'dc']:
208 raise util.Abort(_("unable to convert merge commit "
209 "since target parents do not merge cleanly (file "
210 "%s, parents %s and %s)") % (file, p1ctx,
211 p2ctx))
212 elif action == 'k':
213 # 'keep' means nothing changed from p1
214 continue
215 else:
216 # Any other change means we want to take the p2 version
217 yield file
218
179 219 def putcommit(self, files, copies, parents, commit, source, revmap, full,
180 220 cleanp2):
181 221 files = dict(files)
182 222
183 223 def getfilectx(repo, memctx, f):
184 if p2ctx and f in cleanp2 and f not in copies:
224 if p2ctx and f in p2files and f not in copies:
185 225 self.ui.debug('reusing %s from p2\n' % f)
186 226 return p2ctx[f]
187 227 try:
188 228 v = files[f]
189 229 except KeyError:
190 230 return None
191 231 data, mode = source.getfile(f, v)
192 232 if data is None:
193 233 return None
194 234 if f == '.hgtags':
195 235 data = self._rewritetags(source, revmap, data)
196 236 if f == '.hgsubstate':
197 237 data = self._rewritesubstate(source, data)
198 238 return context.memfilectx(self.repo, f, data, 'l' in mode,
199 239 'x' in mode, copies.get(f))
200 240
201 241 pl = []
202 242 for p in parents:
203 243 if p not in pl:
204 244 pl.append(p)
205 245 parents = pl
206 246 nparents = len(parents)
207 247 if self.filemapmode and nparents == 1:
208 248 m1node = self.repo.changelog.read(bin(parents[0]))[0]
209 249 parent = parents[0]
210 250
211 251 if len(parents) < 2:
212 252 parents.append(nullid)
213 253 if len(parents) < 2:
214 254 parents.append(nullid)
215 255 p2 = parents.pop(0)
216 256
217 257 text = commit.desc
218 258
219 259 sha1s = re.findall(sha1re, text)
220 260 for sha1 in sha1s:
221 261 oldrev = source.lookuprev(sha1)
222 262 newrev = revmap.get(oldrev)
223 263 if newrev is not None:
224 264 text = text.replace(sha1, newrev[:len(sha1)])
225 265
226 266 extra = commit.extra.copy()
227 267
228 268 sourcename = self.repo.ui.config('convert', 'hg.sourcename')
229 269 if sourcename:
230 270 extra['convert_source'] = sourcename
231 271
232 272 for label in ('source', 'transplant_source', 'rebase_source',
233 273 'intermediate-source'):
234 274 node = extra.get(label)
235 275
236 276 if node is None:
237 277 continue
238 278
239 279 # Only transplant stores its reference in binary
240 280 if label == 'transplant_source':
241 281 node = hex(node)
242 282
243 283 newrev = revmap.get(node)
244 284 if newrev is not None:
245 285 if label == 'transplant_source':
246 286 newrev = bin(newrev)
247 287
248 288 extra[label] = newrev
249 289
250 290 if self.branchnames and commit.branch:
251 291 extra['branch'] = commit.branch
252 292 if commit.rev and commit.saverev:
253 293 extra['convert_revision'] = commit.rev
254 294
255 295 while parents:
256 296 p1 = p2
257 297 p2 = parents.pop(0)
298 p1ctx = self.repo[p1]
258 299 p2ctx = None
259 300 if p2 != nullid:
260 301 p2ctx = self.repo[p2]
261 302 fileset = set(files)
262 303 if full:
263 304 fileset.update(self.repo[p1])
264 305 fileset.update(self.repo[p2])
306
307 if p2ctx:
308 p2files = set(cleanp2)
309 for file in self._calculatemergedfiles(source, p1ctx, p2ctx):
310 p2files.add(file)
311 fileset.add(file)
312
265 313 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
266 314 getfilectx, commit.author, commit.date, extra)
267 315
268 316 # We won't know if the conversion changes the node until after the
269 317 # commit, so copy the source's phase for now.
270 318 self.repo.ui.setconfig('phases', 'new-commit',
271 319 phases.phasenames[commit.phase], 'convert')
272 320
273 321 tr = self.repo.transaction("convert")
274 322
275 323 try:
276 324 node = hex(self.repo.commitctx(ctx))
277 325
278 326 # If the node value has changed, but the phase is lower than
279 327 # draft, set it back to draft since it hasn't been exposed
280 328 # anywhere.
281 329 if commit.rev != node:
282 330 ctx = self.repo[node]
283 331 if ctx.phase() < phases.draft:
284 332 phases.retractboundary(self.repo, tr, phases.draft,
285 333 [ctx.node()])
286 334 tr.close()
287 335 finally:
288 336 tr.release()
289 337
290 338 text = "(octopus merge fixup)\n"
291 339 p2 = node
292 340
293 341 if self.filemapmode and nparents == 1:
294 342 man = self.repo.manifest
295 343 mnode = self.repo.changelog.read(bin(p2))[0]
296 344 closed = 'close' in commit.extra
297 345 if not closed and not man.cmp(m1node, man.revision(mnode)):
298 346 self.ui.status(_("filtering out empty revision\n"))
299 347 self.repo.rollback(force=True)
300 348 return parent
301 349 return p2
302 350
303 351 def puttags(self, tags):
304 352 try:
305 353 parentctx = self.repo[self.tagsbranch]
306 354 tagparent = parentctx.node()
307 355 except error.RepoError:
308 356 parentctx = None
309 357 tagparent = nullid
310 358
311 359 oldlines = set()
312 360 for branch, heads in self.repo.branchmap().iteritems():
313 361 for h in heads:
314 362 if '.hgtags' in self.repo[h]:
315 363 oldlines.update(
316 364 set(self.repo[h]['.hgtags'].data().splitlines(True)))
317 365 oldlines = sorted(list(oldlines))
318 366
319 367 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
320 368 if newlines == oldlines:
321 369 return None, None
322 370
323 371 # if the old and new tags match, then there is nothing to update
324 372 oldtags = set()
325 373 newtags = set()
326 374 for line in oldlines:
327 375 s = line.strip().split(' ', 1)
328 376 if len(s) != 2:
329 377 continue
330 378 oldtags.add(s[1])
331 379 for line in newlines:
332 380 s = line.strip().split(' ', 1)
333 381 if len(s) != 2:
334 382 continue
335 383 if s[1] not in oldtags:
336 384 newtags.add(s[1].strip())
337 385
338 386 if not newtags:
339 387 return None, None
340 388
341 389 data = "".join(newlines)
342 390 def getfilectx(repo, memctx, f):
343 391 return context.memfilectx(repo, f, data, False, False, None)
344 392
345 393 self.ui.status(_("updating tags\n"))
346 394 date = "%s 0" % int(time.mktime(time.gmtime()))
347 395 extra = {'branch': self.tagsbranch}
348 396 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
349 397 [".hgtags"], getfilectx, "convert-repo", date,
350 398 extra)
351 399 node = self.repo.commitctx(ctx)
352 400 return hex(node), hex(tagparent)
353 401
354 402 def setfilemapmode(self, active):
355 403 self.filemapmode = active
356 404
357 405 def putbookmarks(self, updatedbookmark):
358 406 if not len(updatedbookmark):
359 407 return
360 408
361 409 self.ui.status(_("updating bookmarks\n"))
362 410 destmarks = self.repo._bookmarks
363 411 for bookmark in updatedbookmark:
364 412 destmarks[bookmark] = bin(updatedbookmark[bookmark])
365 413 destmarks.write()
366 414
367 415 def hascommitfrommap(self, rev):
368 416 # the exact semantics of clonebranches is unclear so we can't say no
369 417 return rev in self.repo or self.clonebranches
370 418
371 419 def hascommitforsplicemap(self, rev):
372 420 if rev not in self.repo and self.clonebranches:
373 421 raise util.Abort(_('revision %s not found in destination '
374 422 'repository (lookups with clonebranches=true '
375 423 'are not implemented)') % rev)
376 424 return rev in self.repo
377 425
378 426 class mercurial_source(converter_source):
379 427 def __init__(self, ui, path, revs=None):
380 428 converter_source.__init__(self, ui, path, revs)
381 429 if revs and len(revs) > 1:
382 430 raise util.Abort(_("mercurial source does not support specifying "
383 431 "multiple revisions"))
384 432 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
385 433 self.ignored = set()
386 434 self.saverev = ui.configbool('convert', 'hg.saverev', False)
387 435 try:
388 436 self.repo = hg.repository(self.ui, path)
389 437 # try to provoke an exception if this isn't really a hg
390 438 # repo, but some other bogus compatible-looking url
391 439 if not self.repo.local():
392 440 raise error.RepoError
393 441 except error.RepoError:
394 442 ui.traceback()
395 443 raise NoRepo(_("%s is not a local Mercurial repository") % path)
396 444 self.lastrev = None
397 445 self.lastctx = None
398 446 self._changescache = None, None
399 447 self.convertfp = None
400 448 # Restrict converted revisions to startrev descendants
401 449 startnode = ui.config('convert', 'hg.startrev')
402 450 hgrevs = ui.config('convert', 'hg.revs')
403 451 if hgrevs is None:
404 452 if startnode is not None:
405 453 try:
406 454 startnode = self.repo.lookup(startnode)
407 455 except error.RepoError:
408 456 raise util.Abort(_('%s is not a valid start revision')
409 457 % startnode)
410 458 startrev = self.repo.changelog.rev(startnode)
411 459 children = {startnode: 1}
412 460 for r in self.repo.changelog.descendants([startrev]):
413 461 children[self.repo.changelog.node(r)] = 1
414 462 self.keep = children.__contains__
415 463 else:
416 464 self.keep = util.always
417 465 if revs:
418 466 self._heads = [self.repo[revs[0]].node()]
419 467 else:
420 468 self._heads = self.repo.heads()
421 469 else:
422 470 if revs or startnode is not None:
423 471 raise util.Abort(_('hg.revs cannot be combined with '
424 472 'hg.startrev or --rev'))
425 473 nodes = set()
426 474 parents = set()
427 475 for r in scmutil.revrange(self.repo, [hgrevs]):
428 476 ctx = self.repo[r]
429 477 nodes.add(ctx.node())
430 478 parents.update(p.node() for p in ctx.parents())
431 479 self.keep = nodes.__contains__
432 480 self._heads = nodes - parents
433 481
434 482 def changectx(self, rev):
435 483 if self.lastrev != rev:
436 484 self.lastctx = self.repo[rev]
437 485 self.lastrev = rev
438 486 return self.lastctx
439 487
440 488 def parents(self, ctx):
441 489 return [p for p in ctx.parents() if p and self.keep(p.node())]
442 490
443 491 def getheads(self):
444 492 return [hex(h) for h in self._heads if self.keep(h)]
445 493
446 494 def getfile(self, name, rev):
447 495 try:
448 496 fctx = self.changectx(rev)[name]
449 497 return fctx.data(), fctx.flags()
450 498 except error.LookupError:
451 499 return None, None
452 500
453 501 def getchanges(self, rev, full):
454 502 ctx = self.changectx(rev)
455 503 parents = self.parents(ctx)
456 504 if full or not parents:
457 505 files = copyfiles = ctx.manifest()
458 506 if parents:
459 507 if self._changescache[0] == rev:
460 508 m, a, r = self._changescache[1]
461 509 else:
462 510 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
463 511 if not full:
464 512 files = m + a + r
465 513 copyfiles = m + a
466 514 # getcopies() is also run for roots and before filtering so missing
467 515 # revlogs are detected early
468 516 copies = self.getcopies(ctx, parents, copyfiles)
469 517 cleanp2 = set()
470 518 if len(parents) == 2:
471 519 cleanp2.update(self.repo.status(parents[1].node(), ctx.node(),
472 520 clean=True).clean)
473 521 changes = [(f, rev) for f in files if f not in self.ignored]
474 522 changes.sort()
475 523 return changes, copies, cleanp2
476 524
477 525 def getcopies(self, ctx, parents, files):
478 526 copies = {}
479 527 for name in files:
480 528 if name in self.ignored:
481 529 continue
482 530 try:
483 531 copysource, _copynode = ctx.filectx(name).renamed()
484 532 if copysource in self.ignored:
485 533 continue
486 534 # Ignore copy sources not in parent revisions
487 535 found = False
488 536 for p in parents:
489 537 if copysource in p:
490 538 found = True
491 539 break
492 540 if not found:
493 541 continue
494 542 copies[name] = copysource
495 543 except TypeError:
496 544 pass
497 545 except error.LookupError as e:
498 546 if not self.ignoreerrors:
499 547 raise
500 548 self.ignored.add(name)
501 549 self.ui.warn(_('ignoring: %s\n') % e)
502 550 return copies
503 551
504 552 def getcommit(self, rev):
505 553 ctx = self.changectx(rev)
506 554 parents = [p.hex() for p in self.parents(ctx)]
507 555 crev = rev
508 556
509 557 return commit(author=ctx.user(),
510 558 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
511 559 desc=ctx.description(), rev=crev, parents=parents,
512 560 branch=ctx.branch(), extra=ctx.extra(),
513 561 sortkey=ctx.rev(), saverev=self.saverev,
514 562 phase=ctx.phase())
515 563
516 564 def gettags(self):
517 565 # This will get written to .hgtags, filter non global tags out.
518 566 tags = [t for t in self.repo.tagslist()
519 567 if self.repo.tagtype(t[0]) == 'global']
520 568 return dict([(name, hex(node)) for name, node in tags
521 569 if self.keep(node)])
522 570
523 571 def getchangedfiles(self, rev, i):
524 572 ctx = self.changectx(rev)
525 573 parents = self.parents(ctx)
526 574 if not parents and i is None:
527 575 i = 0
528 576 changes = [], ctx.manifest().keys(), []
529 577 else:
530 578 i = i or 0
531 579 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
532 580 changes = [[f for f in l if f not in self.ignored] for l in changes]
533 581
534 582 if i == 0:
535 583 self._changescache = (rev, changes)
536 584
537 585 return changes[0] + changes[1] + changes[2]
538 586
539 587 def converted(self, rev, destrev):
540 588 if self.convertfp is None:
541 589 self.convertfp = open(self.repo.join('shamap'), 'a')
542 590 self.convertfp.write('%s %s\n' % (destrev, rev))
543 591 self.convertfp.flush()
544 592
545 593 def before(self):
546 594 self.ui.debug('run hg source pre-conversion action\n')
547 595
548 596 def after(self):
549 597 self.ui.debug('run hg source post-conversion action\n')
550 598
551 599 def hasnativeorder(self):
552 600 return True
553 601
554 602 def hasnativeclose(self):
555 603 return True
556 604
557 605 def lookuprev(self, rev):
558 606 try:
559 607 return hex(self.repo.lookup(rev))
560 608 except (error.RepoError, error.LookupError):
561 609 return None
562 610
563 611 def getbookmarks(self):
564 612 return bookmarks.listbookmarks(self.repo)
565 613
566 614 def checkrevformat(self, revstr, mapname='splicemap'):
567 615 """ Mercurial, revision string is a 40 byte hex """
568 616 self.checkhexformat(revstr, mapname)
@@ -1,673 +1,731 b''
1 1
2 2 $ HGMERGE=true; export HGMERGE
3 3 $ echo '[extensions]' >> $HGRCPATH
4 4 $ echo 'convert =' >> $HGRCPATH
5 5 $ glog()
6 6 > {
7 7 > hg log -G --template '{rev} "{desc}" files: {files}\n' "$@"
8 8 > }
9 9 $ hg init source
10 10 $ cd source
11 11 $ echo foo > foo
12 12 $ echo baz > baz
13 13 $ mkdir -p dir/subdir
14 14 $ echo dir/file >> dir/file
15 15 $ echo dir/file2 >> dir/file2
16 16 $ echo dir/file3 >> dir/file3 # to be corrupted in rev 0
17 17 $ echo dir/subdir/file3 >> dir/subdir/file3
18 18 $ echo dir/subdir/file4 >> dir/subdir/file4
19 19 $ hg ci -d '0 0' -qAm '0: add foo baz dir/'
20 20 $ echo bar > bar
21 21 $ echo quux > quux
22 22 $ echo dir/file4 >> dir/file4 # to be corrupted in rev 1
23 23 $ hg copy foo copied
24 24 $ hg ci -d '1 0' -qAm '1: add bar quux; copy foo to copied'
25 25 $ echo >> foo
26 26 $ hg ci -d '2 0' -m '2: change foo'
27 27 $ hg up -qC 1
28 28 $ echo >> bar
29 29 $ echo >> quux
30 30 $ hg ci -d '3 0' -m '3: change bar quux'
31 31 created new head
32 32 $ hg up -qC 2
33 33 $ hg merge -qr 3
34 34 $ echo >> bar
35 35 $ echo >> baz
36 36 $ hg ci -d '4 0' -m '4: first merge; change bar baz'
37 37 $ echo >> bar
38 38 $ echo 1 >> baz
39 39 $ echo >> quux
40 40 $ hg ci -d '5 0' -m '5: change bar baz quux'
41 41 $ hg up -qC 4
42 42 $ echo >> foo
43 43 $ echo 2 >> baz
44 44 $ hg ci -d '6 0' -m '6: change foo baz'
45 45 created new head
46 46 $ hg up -qC 5
47 47 $ hg merge -qr 6
48 48 $ echo >> bar
49 49 $ hg ci -d '7 0' -m '7: second merge; change bar'
50 50 $ echo >> foo
51 51 $ hg ci -m '8: change foo'
52 52 $ glog
53 53 @ 8 "8: change foo" files: foo
54 54 |
55 55 o 7 "7: second merge; change bar" files: bar baz
56 56 |\
57 57 | o 6 "6: change foo baz" files: baz foo
58 58 | |
59 59 o | 5 "5: change bar baz quux" files: bar baz quux
60 60 |/
61 61 o 4 "4: first merge; change bar baz" files: bar baz
62 62 |\
63 63 | o 3 "3: change bar quux" files: bar quux
64 64 | |
65 65 o | 2 "2: change foo" files: foo
66 66 |/
67 67 o 1 "1: add bar quux; copy foo to copied" files: bar copied dir/file4 quux
68 68 |
69 69 o 0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/file3 dir/subdir/file3 dir/subdir/file4 foo
70 70
71 71
72 72 final file versions in this repo:
73 73
74 74 $ hg manifest --debug
75 75 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
76 76 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
77 77 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
78 78 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir/file
79 79 75e6d3f8328f5f6ace6bf10b98df793416a09dca 644 dir/file2
80 80 e96dce0bc6a217656a3a410e5e6bec2c4f42bf7c 644 dir/file3
81 81 6edd55f559cdce67132b12ca09e09cee08b60442 644 dir/file4
82 82 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir/subdir/file3
83 83 57a1c1511590f3de52874adfa04effe8a77d64af 644 dir/subdir/file4
84 84 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
85 85 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
86 86 $ hg debugrename copied
87 87 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
88 88
89 89 $ cd ..
90 90
91 91
92 92 Test interaction with startrev and verify that changing it is handled properly:
93 93
94 94 $ > empty
95 95 $ hg convert --filemap empty source movingstart --config convert.hg.startrev=3 -r4
96 96 initializing destination movingstart repository
97 97 scanning source...
98 98 sorting...
99 99 converting...
100 100 1 3: change bar quux
101 101 0 4: first merge; change bar baz
102 102 $ hg convert --filemap empty source movingstart
103 103 scanning source...
104 104 sorting...
105 105 converting...
106 106 3 5: change bar baz quux
107 107 2 6: change foo baz
108 108 1 7: second merge; change bar
109 109 warning: af455ce4166b3c9c88e6309c2b9332171dcea595 parent 61e22ca76c3b3e93df20338c4e02ce286898e825 is missing
110 110 warning: cf908b3eeedc301c9272ebae931da966d5b326c7 parent 59e1ab45c888289513b7354484dac8a88217beab is missing
111 111 0 8: change foo
112 112
113 113
114 114 splitrepo tests
115 115
116 116 $ splitrepo()
117 117 > {
118 118 > msg="$1"
119 119 > files="$2"
120 120 > opts=$3
121 121 > echo "% $files: $msg"
122 122 > prefix=`echo "$files" | sed -e 's/ /-/g'`
123 123 > fmap="$prefix.fmap"
124 124 > repo="$prefix.repo"
125 125 > for i in $files; do
126 126 > echo "include $i" >> "$fmap"
127 127 > done
128 128 > hg -q convert $opts --filemap "$fmap" --datesort source "$repo"
129 129 > hg up -q -R "$repo"
130 130 > glog -R "$repo"
131 131 > hg -R "$repo" manifest --debug
132 132 > }
133 133 $ splitrepo 'skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd' foo
134 134 % foo: skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd
135 135 @ 3 "8: change foo" files: foo
136 136 |
137 137 o 2 "6: change foo baz" files: foo
138 138 |
139 139 o 1 "2: change foo" files: foo
140 140 |
141 141 o 0 "0: add foo baz dir/" files: foo
142 142
143 143 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
144 144 $ splitrepo 'merges are not merges anymore' bar
145 145 % bar: merges are not merges anymore
146 146 @ 4 "7: second merge; change bar" files: bar
147 147 |
148 148 o 3 "5: change bar baz quux" files: bar
149 149 |
150 150 o 2 "4: first merge; change bar baz" files: bar
151 151 |
152 152 o 1 "3: change bar quux" files: bar
153 153 |
154 154 o 0 "1: add bar quux; copy foo to copied" files: bar
155 155
156 156 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
157 157 $ splitrepo '1st merge is not a merge anymore; 2nd still is' baz
158 158 % baz: 1st merge is not a merge anymore; 2nd still is
159 159 @ 4 "7: second merge; change bar" files: baz
160 160 |\
161 161 | o 3 "6: change foo baz" files: baz
162 162 | |
163 163 o | 2 "5: change bar baz quux" files: baz
164 164 |/
165 165 o 1 "4: first merge; change bar baz" files: baz
166 166 |
167 167 o 0 "0: add foo baz dir/" files: baz
168 168
169 169 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz
170 170 $ splitrepo 'we add additional merges when they are interesting' 'foo quux'
171 171 % foo quux: we add additional merges when they are interesting
172 172 @ 8 "8: change foo" files: foo
173 173 |
174 174 o 7 "7: second merge; change bar" files:
175 175 |\
176 176 | o 6 "6: change foo baz" files: foo
177 177 | |
178 178 o | 5 "5: change bar baz quux" files: quux
179 179 |/
180 180 o 4 "4: first merge; change bar baz" files:
181 181 |\
182 182 | o 3 "3: change bar quux" files: quux
183 183 | |
184 184 o | 2 "2: change foo" files: foo
185 185 |/
186 186 o 1 "1: add bar quux; copy foo to copied" files: quux
187 187 |
188 188 o 0 "0: add foo baz dir/" files: foo
189 189
190 190 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
191 191 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
192 192 $ splitrepo 'partial conversion' 'bar quux' '-r 3'
193 193 % bar quux: partial conversion
194 194 @ 1 "3: change bar quux" files: bar quux
195 195 |
196 196 o 0 "1: add bar quux; copy foo to copied" files: bar quux
197 197
198 198 b79105bedc55102f394e90a789c9c380117c1b4a 644 bar
199 199 db0421cc6b685a458c8d86c7d5c004f94429ea23 644 quux
200 200 $ splitrepo 'complete the partial conversion' 'bar quux'
201 201 % bar quux: complete the partial conversion
202 202 @ 4 "7: second merge; change bar" files: bar
203 203 |
204 204 o 3 "5: change bar baz quux" files: bar quux
205 205 |
206 206 o 2 "4: first merge; change bar baz" files: bar
207 207 |
208 208 o 1 "3: change bar quux" files: bar quux
209 209 |
210 210 o 0 "1: add bar quux; copy foo to copied" files: bar quux
211 211
212 212 9463f52fe115e377cf2878d4fc548117211063f2 644 bar
213 213 bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux
214 214 $ rm -r foo.repo
215 215 $ splitrepo 'partial conversion' 'foo' '-r 3'
216 216 % foo: partial conversion
217 217 @ 0 "0: add foo baz dir/" files: foo
218 218
219 219 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
220 220 $ splitrepo 'complete the partial conversion' 'foo'
221 221 % foo: complete the partial conversion
222 222 @ 3 "8: change foo" files: foo
223 223 |
224 224 o 2 "6: change foo baz" files: foo
225 225 |
226 226 o 1 "2: change foo" files: foo
227 227 |
228 228 o 0 "0: add foo baz dir/" files: foo
229 229
230 230 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
231 231 $ splitrepo 'copied file; source not included in new repo' copied
232 232 % copied: copied file; source not included in new repo
233 233 @ 0 "1: add bar quux; copy foo to copied" files: copied
234 234
235 235 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 copied
236 236 $ hg --cwd copied.repo debugrename copied
237 237 copied not renamed
238 238 $ splitrepo 'copied file; source included in new repo' 'foo copied'
239 239 % foo copied: copied file; source included in new repo
240 240 @ 4 "8: change foo" files: foo
241 241 |
242 242 o 3 "6: change foo baz" files: foo
243 243 |
244 244 o 2 "2: change foo" files: foo
245 245 |
246 246 o 1 "1: add bar quux; copy foo to copied" files: copied
247 247 |
248 248 o 0 "0: add foo baz dir/" files: foo
249 249
250 250 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied
251 251 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo
252 252 $ hg --cwd foo-copied.repo debugrename copied
253 253 copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd
254 254
255 255 verify the top level 'include .' if there is no other includes:
256 256
257 257 $ echo "exclude something" > default.fmap
258 258 $ hg convert -q --filemap default.fmap -r1 source dummydest2
259 259 $ hg -R dummydest2 log --template '{rev} {node|short} {desc|firstline}\n'
260 260 1 61e22ca76c3b 1: add bar quux; copy foo to copied
261 261 0 c085cf2ee7fe 0: add foo baz dir/
262 262
263 263 $ echo "include somethingelse" >> default.fmap
264 264 $ hg convert -q --filemap default.fmap -r1 source dummydest3
265 265 $ hg -R dummydest3 log --template '{rev} {node|short} {desc|firstline}\n'
266 266
267 267 $ echo "include ." >> default.fmap
268 268 $ hg convert -q --filemap default.fmap -r1 source dummydest4
269 269 $ hg -R dummydest4 log --template '{rev} {node|short} {desc|firstline}\n'
270 270 1 61e22ca76c3b 1: add bar quux; copy foo to copied
271 271 0 c085cf2ee7fe 0: add foo baz dir/
272 272
273 273 ensure that the filemap contains duplicated slashes (issue3612)
274 274
275 275 $ cat > renames.fmap <<EOF
276 276 > include dir
277 277 > exclude dir/file2
278 278 > rename dir dir2//dir3
279 279 > include foo
280 280 > include copied
281 281 > rename foo foo2/
282 282 > rename copied ./copied2
283 283 > exclude dir/subdir
284 284 > include dir/subdir/file3
285 285 > EOF
286 286 $ rm source/.hg/store/data/dir/file3.i
287 287 $ rm source/.hg/store/data/dir/file4.i
288 288 $ hg -q convert --filemap renames.fmap --datesort source dummydest
289 289 abort: data/dir/file3.i@e96dce0bc6a2: no match found!
290 290 [255]
291 291 $ hg -q convert --filemap renames.fmap --datesort --config convert.hg.ignoreerrors=1 source renames.repo
292 292 ignoring: data/dir/file3.i@e96dce0bc6a2: no match found
293 293 ignoring: data/dir/file4.i@6edd55f559cd: no match found
294 294 $ hg up -q -R renames.repo
295 295 $ glog -R renames.repo
296 296 @ 4 "8: change foo" files: foo2
297 297 |
298 298 o 3 "6: change foo baz" files: foo2
299 299 |
300 300 o 2 "2: change foo" files: foo2
301 301 |
302 302 o 1 "1: add bar quux; copy foo to copied" files: copied2
303 303 |
304 304 o 0 "0: add foo baz dir/" files: dir2/dir3/file dir2/dir3/subdir/file3 foo2
305 305
306 306 $ hg -R renames.repo verify
307 307 checking changesets
308 308 checking manifests
309 309 crosschecking files in changesets and manifests
310 310 checking files
311 311 4 files, 5 changesets, 7 total revisions
312 312
313 313 $ hg -R renames.repo manifest --debug
314 314 d43feacba7a4f1f2080dde4a4b985bd8a0236d46 644 copied2
315 315 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir2/dir3/file
316 316 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir2/dir3/subdir/file3
317 317 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo2
318 318 $ hg --cwd renames.repo debugrename copied2
319 319 copied2 renamed from foo2:2ed2a3912a0b24502043eae84ee4b279c18b90dd
320 320
321 321 copied:
322 322
323 323 $ hg --cwd source cat copied
324 324 foo
325 325
326 326 copied2:
327 327
328 328 $ hg --cwd renames.repo cat copied2
329 329 foo
330 330
331 331 filemap errors
332 332
333 333 $ cat > errors.fmap <<EOF
334 334 > include dir/ # beware that comments changes error line numbers!
335 335 > exclude /dir
336 336 > rename dir//dir /dir//dir/ "out of sync"
337 337 > include
338 338 > EOF
339 339 $ hg -q convert --filemap errors.fmap source errors.repo
340 340 errors.fmap:3: superfluous / in include '/dir'
341 341 errors.fmap:3: superfluous / in rename '/dir'
342 342 errors.fmap:4: unknown directive 'out of sync'
343 343 errors.fmap:5: path to exclude is missing
344 344 abort: errors in filemap
345 345 [255]
346 346
347 347 test branch closing revision pruning if branch is pruned
348 348
349 349 $ hg init branchpruning
350 350 $ cd branchpruning
351 351 $ hg branch foo
352 352 marked working directory as branch foo
353 353 (branches are permanent and global, did you want a bookmark?)
354 354 $ echo a > a
355 355 $ hg ci -Am adda
356 356 adding a
357 357 $ hg ci --close-branch -m closefoo
358 358 $ hg up 0
359 359 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
360 360 $ hg branch empty
361 361 marked working directory as branch empty
362 362 (branches are permanent and global, did you want a bookmark?)
363 363 $ hg ci -m emptybranch
364 364 $ hg ci --close-branch -m closeempty
365 365 $ hg up 0
366 366 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 367 $ hg branch default
368 368 marked working directory as branch default
369 369 (branches are permanent and global, did you want a bookmark?)
370 370 $ echo b > b
371 371 $ hg ci -Am addb
372 372 adding b
373 373 $ hg ci --close-branch -m closedefault
374 374 $ cat > filemap <<EOF
375 375 > include b
376 376 > EOF
377 377 $ cd ..
378 378 $ hg convert branchpruning branchpruning-hg1
379 379 initializing destination branchpruning-hg1 repository
380 380 scanning source...
381 381 sorting...
382 382 converting...
383 383 5 adda
384 384 4 closefoo
385 385 3 emptybranch
386 386 2 closeempty
387 387 1 addb
388 388 0 closedefault
389 389 $ glog -R branchpruning-hg1
390 390 _ 5 "closedefault" files:
391 391 |
392 392 o 4 "addb" files: b
393 393 |
394 394 | _ 3 "closeempty" files:
395 395 | |
396 396 | o 2 "emptybranch" files:
397 397 |/
398 398 | _ 1 "closefoo" files:
399 399 |/
400 400 o 0 "adda" files: a
401 401
402 402
403 403 exercise incremental conversion at the same time
404 404
405 405 $ hg convert -r0 --filemap branchpruning/filemap branchpruning branchpruning-hg2
406 406 initializing destination branchpruning-hg2 repository
407 407 scanning source...
408 408 sorting...
409 409 converting...
410 410 0 adda
411 411 $ hg convert -r4 --filemap branchpruning/filemap branchpruning branchpruning-hg2
412 412 scanning source...
413 413 sorting...
414 414 converting...
415 415 0 addb
416 416 $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2
417 417 scanning source...
418 418 sorting...
419 419 converting...
420 420 3 closefoo
421 421 2 emptybranch
422 422 1 closeempty
423 423 0 closedefault
424 424 $ glog -R branchpruning-hg2
425 425 _ 1 "closedefault" files:
426 426 |
427 427 o 0 "addb" files: b
428 428
429 429
430 430 Test rebuilding of map with unknown revisions in shamap - it used to crash
431 431
432 432 $ cd branchpruning
433 433 $ hg up -r 2
434 434 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
435 435 $ hg merge 4
436 436 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 437 (branch merge, don't forget to commit)
438 438 $ hg ci -m 'merging something'
439 439 $ cd ..
440 440 $ echo "53792d18237d2b64971fa571936869156655338d 6d955580116e82c4b029bd30f321323bae71a7f0" >> branchpruning-hg2/.hg/shamap
441 441 $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2 --debug --config progress.debug=true
442 442 run hg source pre-conversion action
443 443 run hg sink pre-conversion action
444 444 scanning source...
445 445 scanning: 1 revisions
446 446 sorting...
447 447 converting...
448 448 0 merging something
449 449 source: 2503605b178fe50e8fbbb0e77b97939540aa8c87
450 450 converting: 0/1 revisions (0.00%)
451 451 unknown revmap source: 53792d18237d2b64971fa571936869156655338d
452 452 run hg sink post-conversion action
453 453 run hg source post-conversion action
454 454
455 455
456 456 filemap rename undoing revision rename
457 457
458 458 $ hg init renameundo
459 459 $ cd renameundo
460 460 $ echo 1 > a
461 461 $ echo 1 > c
462 462 $ hg ci -qAm add
463 463 $ hg mv -q a b/a
464 464 $ hg mv -q c b/c
465 465 $ hg ci -qm rename
466 466 $ echo 2 > b/a
467 467 $ echo 2 > b/c
468 468 $ hg ci -qm modify
469 469 $ cd ..
470 470
471 471 $ echo "rename b ." > renameundo.fmap
472 472 $ hg convert --filemap renameundo.fmap renameundo renameundo2
473 473 initializing destination renameundo2 repository
474 474 scanning source...
475 475 sorting...
476 476 converting...
477 477 2 add
478 478 1 rename
479 479 filtering out empty revision
480 480 repository tip rolled back to revision 0 (undo convert)
481 481 0 modify
482 482 $ glog -R renameundo2
483 483 o 1 "modify" files: a c
484 484 |
485 485 o 0 "add" files: a c
486 486
487 487
488 488
489 489 test merge parents/empty merges pruning
490 490
491 491 $ glog()
492 492 > {
493 493 > hg log -G --template '{rev}:{node|short}@{branch} "{desc}" files: {files}\n' "$@"
494 494 > }
495 495
496 496 test anonymous branch pruning
497 497
498 498 $ hg init anonymousbranch
499 499 $ cd anonymousbranch
500 500 $ echo a > a
501 501 $ echo b > b
502 502 $ hg ci -Am add
503 503 adding a
504 504 adding b
505 505 $ echo a >> a
506 506 $ hg ci -m changea
507 507 $ hg up 0
508 508 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
509 509 $ echo b >> b
510 510 $ hg ci -m changeb
511 511 created new head
512 512 $ hg up 1
513 513 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
514 514 $ hg merge
515 515 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
516 516 (branch merge, don't forget to commit)
517 517 $ hg ci -m merge
518 518 $ cd ..
519 519
520 520 $ cat > filemap <<EOF
521 521 > include a
522 522 > EOF
523 523 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg
524 524 initializing destination anonymousbranch-hg repository
525 525 scanning source...
526 526 sorting...
527 527 converting...
528 528 3 add
529 529 2 changea
530 530 1 changeb
531 531 0 merge
532 532 $ glog -R anonymousbranch
533 533 @ 3:c71d5201a498@default "merge" files:
534 534 |\
535 535 | o 2:607eb44b17f9@default "changeb" files: b
536 536 | |
537 537 o | 1:1f60ea617824@default "changea" files: a
538 538 |/
539 539 o 0:0146e6129113@default "add" files: a b
540 540
541 541 $ glog -R anonymousbranch-hg
542 542 o 1:cda818e7219b@default "changea" files: a
543 543 |
544 544 o 0:c334dc3be0da@default "add" files: a
545 545
546 546 $ cat anonymousbranch-hg/.hg/shamap
547 547 0146e6129113dba9ac90207cfdf2d7ed35257ae5 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
548 548 1f60ea61782421edf8d051ff4fcb61b330f26a4a cda818e7219b5f7f3fb9f49780054ed6a1905ec3
549 549 607eb44b17f9348cd5cbd26e16af87ba77b0b037 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916
550 550 c71d5201a498b2658d105a6bf69d7a0df2649aea cda818e7219b5f7f3fb9f49780054ed6a1905ec3
551 551
552 552 $ cat > filemap <<EOF
553 553 > include b
554 554 > EOF
555 555 $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg2
556 556 initializing destination anonymousbranch-hg2 repository
557 557 scanning source...
558 558 sorting...
559 559 converting...
560 560 3 add
561 561 2 changea
562 562 1 changeb
563 563 0 merge
564 564 $ glog -R anonymousbranch
565 565 @ 3:c71d5201a498@default "merge" files:
566 566 |\
567 567 | o 2:607eb44b17f9@default "changeb" files: b
568 568 | |
569 569 o | 1:1f60ea617824@default "changea" files: a
570 570 |/
571 571 o 0:0146e6129113@default "add" files: a b
572 572
573 573 $ glog -R anonymousbranch-hg2
574 574 o 1:62dd350b0df6@default "changeb" files: b
575 575 |
576 576 o 0:4b9ced861657@default "add" files: b
577 577
578 578 $ cat anonymousbranch-hg2/.hg/shamap
579 579 0146e6129113dba9ac90207cfdf2d7ed35257ae5 4b9ced86165703791653059a1db6ed864630a523
580 580 1f60ea61782421edf8d051ff4fcb61b330f26a4a 4b9ced86165703791653059a1db6ed864630a523
581 581 607eb44b17f9348cd5cbd26e16af87ba77b0b037 62dd350b0df695f7d2c82a02e0499b16fd790f22
582 582 c71d5201a498b2658d105a6bf69d7a0df2649aea 62dd350b0df695f7d2c82a02e0499b16fd790f22
583 583
584 584 test named branch pruning
585 585
586 586 $ hg init namedbranch
587 587 $ cd namedbranch
588 588 $ echo a > a
589 589 $ echo b > b
590 590 $ hg ci -Am add
591 591 adding a
592 592 adding b
593 593 $ echo a >> a
594 594 $ hg ci -m changea
595 595 $ hg up 0
596 596 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
597 597 $ hg branch foo
598 598 marked working directory as branch foo
599 599 (branches are permanent and global, did you want a bookmark?)
600 600 $ echo b >> b
601 601 $ hg ci -m changeb
602 602 $ hg up default
603 603 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
604 604 $ hg merge foo
605 605 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
606 606 (branch merge, don't forget to commit)
607 607 $ hg ci -m merge
608 608 $ cd ..
609 609
610 610 $ cat > filemap <<EOF
611 611 > include a
612 612 > EOF
613 613 $ hg convert --filemap filemap namedbranch namedbranch-hg
614 614 initializing destination namedbranch-hg repository
615 615 scanning source...
616 616 sorting...
617 617 converting...
618 618 3 add
619 619 2 changea
620 620 1 changeb
621 621 0 merge
622 622 $ glog -R namedbranch
623 623 @ 3:73899bcbe45c@default "merge" files:
624 624 |\
625 625 | o 2:8097982d19fc@foo "changeb" files: b
626 626 | |
627 627 o | 1:1f60ea617824@default "changea" files: a
628 628 |/
629 629 o 0:0146e6129113@default "add" files: a b
630 630
631 631 $ glog -R namedbranch-hg
632 632 o 1:cda818e7219b@default "changea" files: a
633 633 |
634 634 o 0:c334dc3be0da@default "add" files: a
635 635
636 636
637 637 $ cd namedbranch
638 638 $ hg --config extensions.mq= strip tip
639 639 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
640 640 saved backup bundle to $TESTTMP/namedbranch/.hg/strip-backup/73899bcbe45c-92adf160-backup.hg (glob)
641 641 $ hg up foo
642 642 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
643 643 $ hg merge default
644 644 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
645 645 (branch merge, don't forget to commit)
646 646 $ hg ci -m merge
647 647 $ cd ..
648 648
649 649 $ hg convert --filemap filemap namedbranch namedbranch-hg2
650 650 initializing destination namedbranch-hg2 repository
651 651 scanning source...
652 652 sorting...
653 653 converting...
654 654 3 add
655 655 2 changea
656 656 1 changeb
657 657 0 merge
658 658 $ glog -R namedbranch
659 659 @ 3:e1959de76e1b@foo "merge" files:
660 660 |\
661 661 | o 2:8097982d19fc@foo "changeb" files: b
662 662 | |
663 663 o | 1:1f60ea617824@default "changea" files: a
664 664 |/
665 665 o 0:0146e6129113@default "add" files: a b
666 666
667 667 $ glog -R namedbranch-hg2
668 668 o 2:dcf314454667@foo "merge" files:
669 669 |\
670 670 | o 1:cda818e7219b@default "changea" files: a
671 671 |/
672 672 o 0:c334dc3be0da@default "add" files: a
673 673
674 $ cd ..
675
676 test converting merges into a repo that contains other files
677
678 $ hg init merge-test1
679 $ cd merge-test1
680 $ touch a && hg commit -Aqm a
681 $ hg up -q null
682 $ touch b && hg commit -Aqm b
683 $ hg merge -q 0 && hg commit -qm merge
684 $ cd ..
685 $ hg init merge-test2
686 $ cd merge-test2
687 $ mkdir converted
688 $ touch converted/a && hg commit -Aqm 'a'
689 $ touch x && hg commit -Aqm 'x'
690 $ cd ..
691 $ hg log -G -T '{node}' -R merge-test1
692 @ ea7c1a7ae9588677a715ce4f204cd89c28d5471f
693 |\
694 | o d7486e00c6f1b633dcadc0582f78006d805c7a0f
695 |
696 o 3903775176ed42b1458a6281db4a0ccf4d9f287a
697
698 $ hg log -G -T '{node}' -R merge-test2
699 @ 34f1aa7da42559bae87920880b522d47b3ddbc0d
700 |
701 o e01a12b07b4fdfd61ff90a2a1b4560a7a776f323
702
703 - Build a shamap where the target converted/a is in on top of an unrelated
704 - change to 'x'. This simulates using convert to merge several repositories
705 - together.
706 $ cat >> merge-test2/.hg/shamap <<EOF
707 > 3903775176ed42b1458a6281db4a0ccf4d9f287a 34f1aa7da42559bae87920880b522d47b3ddbc0d
708 > EOF
709 $ cat >> merge-test-filemap <<EOF
710 > rename . converted/
711 > EOF
712 $ hg convert --filemap merge-test-filemap merge-test1 merge-test2 --traceback
713 scanning source...
714 sorting...
715 converting...
716 1 b
717 0 merge
718 $ hg -R merge-test2 manifest -r tip
719 converted/a
720 converted/b
721 x
722 $ hg -R merge-test2 log -G -T '{node}\n{files % "{file}\n"}'
723 o 4b5e2f0218d3442a0c14892b18685bf9c8059c4a
724 |\
725 | o 214325dd2e4cff981dcf00cb120cd39e1ea36dcc
726 | converted/b
727 @ 34f1aa7da42559bae87920880b522d47b3ddbc0d
728 | x
729 o e01a12b07b4fdfd61ff90a2a1b4560a7a776f323
730 converted/a
731
General Comments 0
You need to be logged in to leave comments. Login now