##// END OF EJS Templates
convert: fix syncing deletes from p2 merge commit...
Durham Goode -
r26078:5ca58734 default
parent child Browse files
Show More
@@ -1,616 +1,621 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 26 from mercurial import merge as mergemod
27 27
28 28 from common import NoRepo, commit, converter_source, converter_sink, mapfile
29 29
30 30 import re
31 31 sha1re = re.compile(r'\b[0-9a-f]{12,40}\b')
32 32
33 33 class mercurial_sink(converter_sink):
34 34 def __init__(self, ui, path):
35 35 converter_sink.__init__(self, ui, path)
36 36 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
37 37 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
38 38 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
39 39 self.lastbranch = None
40 40 if os.path.isdir(path) and len(os.listdir(path)) > 0:
41 41 try:
42 42 self.repo = hg.repository(self.ui, path)
43 43 if not self.repo.local():
44 44 raise NoRepo(_('%s is not a local Mercurial repository')
45 45 % path)
46 46 except error.RepoError as err:
47 47 ui.traceback()
48 48 raise NoRepo(err.args[0])
49 49 else:
50 50 try:
51 51 ui.status(_('initializing destination %s repository\n') % path)
52 52 self.repo = hg.repository(self.ui, path, create=True)
53 53 if not self.repo.local():
54 54 raise NoRepo(_('%s is not a local Mercurial repository')
55 55 % path)
56 56 self.created.append(path)
57 57 except error.RepoError:
58 58 ui.traceback()
59 59 raise NoRepo(_("could not create hg repository %s as sink")
60 60 % path)
61 61 self.lock = None
62 62 self.wlock = None
63 63 self.filemapmode = False
64 64 self.subrevmaps = {}
65 65
66 66 def before(self):
67 67 self.ui.debug('run hg sink pre-conversion action\n')
68 68 self.wlock = self.repo.wlock()
69 69 self.lock = self.repo.lock()
70 70
71 71 def after(self):
72 72 self.ui.debug('run hg sink post-conversion action\n')
73 73 if self.lock:
74 74 self.lock.release()
75 75 if self.wlock:
76 76 self.wlock.release()
77 77
78 78 def revmapfile(self):
79 79 return self.repo.join("shamap")
80 80
81 81 def authorfile(self):
82 82 return self.repo.join("authormap")
83 83
84 84 def setbranch(self, branch, pbranches):
85 85 if not self.clonebranches:
86 86 return
87 87
88 88 setbranch = (branch != self.lastbranch)
89 89 self.lastbranch = branch
90 90 if not branch:
91 91 branch = 'default'
92 92 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
93 93 if pbranches:
94 94 pbranch = pbranches[0][1]
95 95 else:
96 96 pbranch = 'default'
97 97
98 98 branchpath = os.path.join(self.path, branch)
99 99 if setbranch:
100 100 self.after()
101 101 try:
102 102 self.repo = hg.repository(self.ui, branchpath)
103 103 except Exception:
104 104 self.repo = hg.repository(self.ui, branchpath, create=True)
105 105 self.before()
106 106
107 107 # pbranches may bring revisions from other branches (merge parents)
108 108 # Make sure we have them, or pull them.
109 109 missings = {}
110 110 for b in pbranches:
111 111 try:
112 112 self.repo.lookup(b[0])
113 113 except Exception:
114 114 missings.setdefault(b[1], []).append(b[0])
115 115
116 116 if missings:
117 117 self.after()
118 118 for pbranch, heads in sorted(missings.iteritems()):
119 119 pbranchpath = os.path.join(self.path, pbranch)
120 120 prepo = hg.peer(self.ui, {}, pbranchpath)
121 121 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
122 122 exchange.pull(self.repo, prepo,
123 123 [prepo.lookup(h) for h in heads])
124 124 self.before()
125 125
126 126 def _rewritetags(self, source, revmap, data):
127 127 fp = cStringIO.StringIO()
128 128 for line in data.splitlines():
129 129 s = line.split(' ', 1)
130 130 if len(s) != 2:
131 131 continue
132 132 revid = revmap.get(source.lookuprev(s[0]))
133 133 if not revid:
134 134 if s[0] == hex(nullid):
135 135 revid = s[0]
136 136 else:
137 137 continue
138 138 fp.write('%s %s\n' % (revid, s[1]))
139 139 return fp.getvalue()
140 140
141 141 def _rewritesubstate(self, source, data):
142 142 fp = cStringIO.StringIO()
143 143 for line in data.splitlines():
144 144 s = line.split(' ', 1)
145 145 if len(s) != 2:
146 146 continue
147 147
148 148 revid = s[0]
149 149 subpath = s[1]
150 150 if revid != hex(nullid):
151 151 revmap = self.subrevmaps.get(subpath)
152 152 if revmap is None:
153 153 revmap = mapfile(self.ui,
154 154 self.repo.wjoin(subpath, '.hg/shamap'))
155 155 self.subrevmaps[subpath] = revmap
156 156
157 157 # It is reasonable that one or more of the subrepos don't
158 158 # need to be converted, in which case they can be cloned
159 159 # into place instead of converted. Therefore, only warn
160 160 # once.
161 161 msg = _('no ".hgsubstate" updates will be made for "%s"\n')
162 162 if len(revmap) == 0:
163 163 sub = self.repo.wvfs.reljoin(subpath, '.hg')
164 164
165 165 if self.repo.wvfs.exists(sub):
166 166 self.ui.warn(msg % subpath)
167 167
168 168 newid = revmap.get(revid)
169 169 if not newid:
170 170 if len(revmap) > 0:
171 171 self.ui.warn(_("%s is missing from %s/.hg/shamap\n") %
172 172 (revid, subpath))
173 173 else:
174 174 revid = newid
175 175
176 176 fp.write('%s %s\n' % (revid, subpath))
177 177
178 178 return fp.getvalue()
179 179
180 180 def _calculatemergedfiles(self, source, p1ctx, p2ctx):
181 181 """Calculates the files from p2 that we need to pull in when merging p1
182 182 and p2, given that the merge is coming from the given source.
183 183
184 184 This prevents us from losing files that only exist in the target p2 and
185 185 that don't come from the source repo (like if you're merging multiple
186 186 repositories together).
187 187 """
188 188 anc = [p1ctx.ancestor(p2ctx)]
189 189 # Calculate what files are coming from p2
190 190 actions, diverge, rename = mergemod.calculateupdates(
191 191 self.repo, p1ctx, p2ctx, anc,
192 192 True, # branchmerge
193 193 True, # force
194 194 False, # partial
195 195 False, # acceptremote
196 196 False, # followcopies
197 197 )
198 198
199 199 for file, (action, info, msg) in actions.iteritems():
200 200 if source.targetfilebelongstosource(file):
201 201 # If the file belongs to the source repo, ignore the p2
202 202 # since it will be covered by the existing fileset.
203 203 continue
204 204
205 205 # If the file requires actual merging, abort. We don't have enough
206 206 # context to resolve merges correctly.
207 207 if action in ['m', 'dm', 'cd', 'dc']:
208 208 raise util.Abort(_("unable to convert merge commit "
209 209 "since target parents do not merge cleanly (file "
210 210 "%s, parents %s and %s)") % (file, p1ctx,
211 211 p2ctx))
212 212 elif action == 'k':
213 213 # 'keep' means nothing changed from p1
214 214 continue
215 215 else:
216 216 # Any other change means we want to take the p2 version
217 217 yield file
218 218
219 219 def putcommit(self, files, copies, parents, commit, source, revmap, full,
220 220 cleanp2):
221 221 files = dict(files)
222 222
223 223 def getfilectx(repo, memctx, f):
224 224 if p2ctx and f in p2files and f not in copies:
225 225 self.ui.debug('reusing %s from p2\n' % f)
226 return p2ctx[f]
226 try:
227 return p2ctx[f]
228 except error.ManifestLookupError:
229 # If the file doesn't exist in p2, then we're syncing a
230 # delete, so just return None.
231 return None
227 232 try:
228 233 v = files[f]
229 234 except KeyError:
230 235 return None
231 236 data, mode = source.getfile(f, v)
232 237 if data is None:
233 238 return None
234 239 if f == '.hgtags':
235 240 data = self._rewritetags(source, revmap, data)
236 241 if f == '.hgsubstate':
237 242 data = self._rewritesubstate(source, data)
238 243 return context.memfilectx(self.repo, f, data, 'l' in mode,
239 244 'x' in mode, copies.get(f))
240 245
241 246 pl = []
242 247 for p in parents:
243 248 if p not in pl:
244 249 pl.append(p)
245 250 parents = pl
246 251 nparents = len(parents)
247 252 if self.filemapmode and nparents == 1:
248 253 m1node = self.repo.changelog.read(bin(parents[0]))[0]
249 254 parent = parents[0]
250 255
251 256 if len(parents) < 2:
252 257 parents.append(nullid)
253 258 if len(parents) < 2:
254 259 parents.append(nullid)
255 260 p2 = parents.pop(0)
256 261
257 262 text = commit.desc
258 263
259 264 sha1s = re.findall(sha1re, text)
260 265 for sha1 in sha1s:
261 266 oldrev = source.lookuprev(sha1)
262 267 newrev = revmap.get(oldrev)
263 268 if newrev is not None:
264 269 text = text.replace(sha1, newrev[:len(sha1)])
265 270
266 271 extra = commit.extra.copy()
267 272
268 273 sourcename = self.repo.ui.config('convert', 'hg.sourcename')
269 274 if sourcename:
270 275 extra['convert_source'] = sourcename
271 276
272 277 for label in ('source', 'transplant_source', 'rebase_source',
273 278 'intermediate-source'):
274 279 node = extra.get(label)
275 280
276 281 if node is None:
277 282 continue
278 283
279 284 # Only transplant stores its reference in binary
280 285 if label == 'transplant_source':
281 286 node = hex(node)
282 287
283 288 newrev = revmap.get(node)
284 289 if newrev is not None:
285 290 if label == 'transplant_source':
286 291 newrev = bin(newrev)
287 292
288 293 extra[label] = newrev
289 294
290 295 if self.branchnames and commit.branch:
291 296 extra['branch'] = commit.branch
292 297 if commit.rev and commit.saverev:
293 298 extra['convert_revision'] = commit.rev
294 299
295 300 while parents:
296 301 p1 = p2
297 302 p2 = parents.pop(0)
298 303 p1ctx = self.repo[p1]
299 304 p2ctx = None
300 305 if p2 != nullid:
301 306 p2ctx = self.repo[p2]
302 307 fileset = set(files)
303 308 if full:
304 309 fileset.update(self.repo[p1])
305 310 fileset.update(self.repo[p2])
306 311
307 312 if p2ctx:
308 313 p2files = set(cleanp2)
309 314 for file in self._calculatemergedfiles(source, p1ctx, p2ctx):
310 315 p2files.add(file)
311 316 fileset.add(file)
312 317
313 318 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
314 319 getfilectx, commit.author, commit.date, extra)
315 320
316 321 # We won't know if the conversion changes the node until after the
317 322 # commit, so copy the source's phase for now.
318 323 self.repo.ui.setconfig('phases', 'new-commit',
319 324 phases.phasenames[commit.phase], 'convert')
320 325
321 326 tr = self.repo.transaction("convert")
322 327
323 328 try:
324 329 node = hex(self.repo.commitctx(ctx))
325 330
326 331 # If the node value has changed, but the phase is lower than
327 332 # draft, set it back to draft since it hasn't been exposed
328 333 # anywhere.
329 334 if commit.rev != node:
330 335 ctx = self.repo[node]
331 336 if ctx.phase() < phases.draft:
332 337 phases.retractboundary(self.repo, tr, phases.draft,
333 338 [ctx.node()])
334 339 tr.close()
335 340 finally:
336 341 tr.release()
337 342
338 343 text = "(octopus merge fixup)\n"
339 344 p2 = node
340 345
341 346 if self.filemapmode and nparents == 1:
342 347 man = self.repo.manifest
343 348 mnode = self.repo.changelog.read(bin(p2))[0]
344 349 closed = 'close' in commit.extra
345 350 if not closed and not man.cmp(m1node, man.revision(mnode)):
346 351 self.ui.status(_("filtering out empty revision\n"))
347 352 self.repo.rollback(force=True)
348 353 return parent
349 354 return p2
350 355
351 356 def puttags(self, tags):
352 357 try:
353 358 parentctx = self.repo[self.tagsbranch]
354 359 tagparent = parentctx.node()
355 360 except error.RepoError:
356 361 parentctx = None
357 362 tagparent = nullid
358 363
359 364 oldlines = set()
360 365 for branch, heads in self.repo.branchmap().iteritems():
361 366 for h in heads:
362 367 if '.hgtags' in self.repo[h]:
363 368 oldlines.update(
364 369 set(self.repo[h]['.hgtags'].data().splitlines(True)))
365 370 oldlines = sorted(list(oldlines))
366 371
367 372 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
368 373 if newlines == oldlines:
369 374 return None, None
370 375
371 376 # if the old and new tags match, then there is nothing to update
372 377 oldtags = set()
373 378 newtags = set()
374 379 for line in oldlines:
375 380 s = line.strip().split(' ', 1)
376 381 if len(s) != 2:
377 382 continue
378 383 oldtags.add(s[1])
379 384 for line in newlines:
380 385 s = line.strip().split(' ', 1)
381 386 if len(s) != 2:
382 387 continue
383 388 if s[1] not in oldtags:
384 389 newtags.add(s[1].strip())
385 390
386 391 if not newtags:
387 392 return None, None
388 393
389 394 data = "".join(newlines)
390 395 def getfilectx(repo, memctx, f):
391 396 return context.memfilectx(repo, f, data, False, False, None)
392 397
393 398 self.ui.status(_("updating tags\n"))
394 399 date = "%s 0" % int(time.mktime(time.gmtime()))
395 400 extra = {'branch': self.tagsbranch}
396 401 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
397 402 [".hgtags"], getfilectx, "convert-repo", date,
398 403 extra)
399 404 node = self.repo.commitctx(ctx)
400 405 return hex(node), hex(tagparent)
401 406
402 407 def setfilemapmode(self, active):
403 408 self.filemapmode = active
404 409
405 410 def putbookmarks(self, updatedbookmark):
406 411 if not len(updatedbookmark):
407 412 return
408 413
409 414 self.ui.status(_("updating bookmarks\n"))
410 415 destmarks = self.repo._bookmarks
411 416 for bookmark in updatedbookmark:
412 417 destmarks[bookmark] = bin(updatedbookmark[bookmark])
413 418 destmarks.write()
414 419
415 420 def hascommitfrommap(self, rev):
416 421 # the exact semantics of clonebranches is unclear so we can't say no
417 422 return rev in self.repo or self.clonebranches
418 423
419 424 def hascommitforsplicemap(self, rev):
420 425 if rev not in self.repo and self.clonebranches:
421 426 raise util.Abort(_('revision %s not found in destination '
422 427 'repository (lookups with clonebranches=true '
423 428 'are not implemented)') % rev)
424 429 return rev in self.repo
425 430
426 431 class mercurial_source(converter_source):
427 432 def __init__(self, ui, path, revs=None):
428 433 converter_source.__init__(self, ui, path, revs)
429 434 if revs and len(revs) > 1:
430 435 raise util.Abort(_("mercurial source does not support specifying "
431 436 "multiple revisions"))
432 437 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
433 438 self.ignored = set()
434 439 self.saverev = ui.configbool('convert', 'hg.saverev', False)
435 440 try:
436 441 self.repo = hg.repository(self.ui, path)
437 442 # try to provoke an exception if this isn't really a hg
438 443 # repo, but some other bogus compatible-looking url
439 444 if not self.repo.local():
440 445 raise error.RepoError
441 446 except error.RepoError:
442 447 ui.traceback()
443 448 raise NoRepo(_("%s is not a local Mercurial repository") % path)
444 449 self.lastrev = None
445 450 self.lastctx = None
446 451 self._changescache = None, None
447 452 self.convertfp = None
448 453 # Restrict converted revisions to startrev descendants
449 454 startnode = ui.config('convert', 'hg.startrev')
450 455 hgrevs = ui.config('convert', 'hg.revs')
451 456 if hgrevs is None:
452 457 if startnode is not None:
453 458 try:
454 459 startnode = self.repo.lookup(startnode)
455 460 except error.RepoError:
456 461 raise util.Abort(_('%s is not a valid start revision')
457 462 % startnode)
458 463 startrev = self.repo.changelog.rev(startnode)
459 464 children = {startnode: 1}
460 465 for r in self.repo.changelog.descendants([startrev]):
461 466 children[self.repo.changelog.node(r)] = 1
462 467 self.keep = children.__contains__
463 468 else:
464 469 self.keep = util.always
465 470 if revs:
466 471 self._heads = [self.repo[revs[0]].node()]
467 472 else:
468 473 self._heads = self.repo.heads()
469 474 else:
470 475 if revs or startnode is not None:
471 476 raise util.Abort(_('hg.revs cannot be combined with '
472 477 'hg.startrev or --rev'))
473 478 nodes = set()
474 479 parents = set()
475 480 for r in scmutil.revrange(self.repo, [hgrevs]):
476 481 ctx = self.repo[r]
477 482 nodes.add(ctx.node())
478 483 parents.update(p.node() for p in ctx.parents())
479 484 self.keep = nodes.__contains__
480 485 self._heads = nodes - parents
481 486
482 487 def changectx(self, rev):
483 488 if self.lastrev != rev:
484 489 self.lastctx = self.repo[rev]
485 490 self.lastrev = rev
486 491 return self.lastctx
487 492
488 493 def parents(self, ctx):
489 494 return [p for p in ctx.parents() if p and self.keep(p.node())]
490 495
491 496 def getheads(self):
492 497 return [hex(h) for h in self._heads if self.keep(h)]
493 498
494 499 def getfile(self, name, rev):
495 500 try:
496 501 fctx = self.changectx(rev)[name]
497 502 return fctx.data(), fctx.flags()
498 503 except error.LookupError:
499 504 return None, None
500 505
501 506 def getchanges(self, rev, full):
502 507 ctx = self.changectx(rev)
503 508 parents = self.parents(ctx)
504 509 if full or not parents:
505 510 files = copyfiles = ctx.manifest()
506 511 if parents:
507 512 if self._changescache[0] == rev:
508 513 m, a, r = self._changescache[1]
509 514 else:
510 515 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
511 516 if not full:
512 517 files = m + a + r
513 518 copyfiles = m + a
514 519 # getcopies() is also run for roots and before filtering so missing
515 520 # revlogs are detected early
516 521 copies = self.getcopies(ctx, parents, copyfiles)
517 522 cleanp2 = set()
518 523 if len(parents) == 2:
519 524 cleanp2.update(self.repo.status(parents[1].node(), ctx.node(),
520 525 clean=True).clean)
521 526 changes = [(f, rev) for f in files if f not in self.ignored]
522 527 changes.sort()
523 528 return changes, copies, cleanp2
524 529
525 530 def getcopies(self, ctx, parents, files):
526 531 copies = {}
527 532 for name in files:
528 533 if name in self.ignored:
529 534 continue
530 535 try:
531 536 copysource, _copynode = ctx.filectx(name).renamed()
532 537 if copysource in self.ignored:
533 538 continue
534 539 # Ignore copy sources not in parent revisions
535 540 found = False
536 541 for p in parents:
537 542 if copysource in p:
538 543 found = True
539 544 break
540 545 if not found:
541 546 continue
542 547 copies[name] = copysource
543 548 except TypeError:
544 549 pass
545 550 except error.LookupError as e:
546 551 if not self.ignoreerrors:
547 552 raise
548 553 self.ignored.add(name)
549 554 self.ui.warn(_('ignoring: %s\n') % e)
550 555 return copies
551 556
552 557 def getcommit(self, rev):
553 558 ctx = self.changectx(rev)
554 559 parents = [p.hex() for p in self.parents(ctx)]
555 560 crev = rev
556 561
557 562 return commit(author=ctx.user(),
558 563 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
559 564 desc=ctx.description(), rev=crev, parents=parents,
560 565 branch=ctx.branch(), extra=ctx.extra(),
561 566 sortkey=ctx.rev(), saverev=self.saverev,
562 567 phase=ctx.phase())
563 568
564 569 def gettags(self):
565 570 # This will get written to .hgtags, filter non global tags out.
566 571 tags = [t for t in self.repo.tagslist()
567 572 if self.repo.tagtype(t[0]) == 'global']
568 573 return dict([(name, hex(node)) for name, node in tags
569 574 if self.keep(node)])
570 575
571 576 def getchangedfiles(self, rev, i):
572 577 ctx = self.changectx(rev)
573 578 parents = self.parents(ctx)
574 579 if not parents and i is None:
575 580 i = 0
576 581 changes = [], ctx.manifest().keys(), []
577 582 else:
578 583 i = i or 0
579 584 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
580 585 changes = [[f for f in l if f not in self.ignored] for l in changes]
581 586
582 587 if i == 0:
583 588 self._changescache = (rev, changes)
584 589
585 590 return changes[0] + changes[1] + changes[2]
586 591
587 592 def converted(self, rev, destrev):
588 593 if self.convertfp is None:
589 594 self.convertfp = open(self.repo.join('shamap'), 'a')
590 595 self.convertfp.write('%s %s\n' % (destrev, rev))
591 596 self.convertfp.flush()
592 597
593 598 def before(self):
594 599 self.ui.debug('run hg source pre-conversion action\n')
595 600
596 601 def after(self):
597 602 self.ui.debug('run hg source post-conversion action\n')
598 603
599 604 def hasnativeorder(self):
600 605 return True
601 606
602 607 def hasnativeclose(self):
603 608 return True
604 609
605 610 def lookuprev(self, rev):
606 611 try:
607 612 return hex(self.repo.lookup(rev))
608 613 except (error.RepoError, error.LookupError):
609 614 return None
610 615
611 616 def getbookmarks(self):
612 617 return bookmarks.listbookmarks(self.repo)
613 618
614 619 def checkrevformat(self, revstr, mapname='splicemap'):
615 620 """ Mercurial, revision string is a 40 byte hex """
616 621 self.checkhexformat(revstr, mapname)
@@ -1,731 +1,743 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 674 $ cd ..
675 675
676 676 test converting merges into a repo that contains other files
677 677
678 678 $ hg init merge-test1
679 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
680 $ touch a && hg commit -Aqm 'add a'
681 $ echo a > a && hg commit -Aqm 'edit a'
682 $ hg up -q 0
683 $ touch b && hg commit -Aqm 'add b'
684 $ hg merge -q 1 && hg commit -qm 'merge a & b'
685
684 686 $ cd ..
685 687 $ hg init merge-test2
686 688 $ cd merge-test2
687 689 $ mkdir converted
688 $ touch converted/a && hg commit -Aqm 'a'
689 $ touch x && hg commit -Aqm 'x'
690 $ touch converted/a toberemoved && hg commit -Aqm 'add converted/a & toberemoved'
691 $ touch x && rm toberemoved && hg commit -Aqm 'add x & remove tobremoved'
690 692 $ cd ..
691 $ hg log -G -T '{node}' -R merge-test1
692 @ ea7c1a7ae9588677a715ce4f204cd89c28d5471f
693 $ hg log -G -T '{shortest(node)} {desc}' -R merge-test1
694 @ 1191 merge a & b
693 695 |\
694 | o d7486e00c6f1b633dcadc0582f78006d805c7a0f
695 |
696 o 3903775176ed42b1458a6281db4a0ccf4d9f287a
696 | o 9077 add b
697 | |
698 o | d19f edit a
699 |/
700 o ac82 add a
697 701
698 $ hg log -G -T '{node}' -R merge-test2
699 @ 34f1aa7da42559bae87920880b522d47b3ddbc0d
702 $ hg log -G -T '{shortest(node)} {desc}' -R merge-test2
703 @ 150e add x & remove tobremoved
700 704 |
701 o e01a12b07b4fdfd61ff90a2a1b4560a7a776f323
705 o bbac add converted/a & toberemoved
702 706
703 707 - Build a shamap where the target converted/a is in on top of an unrelated
704 708 - change to 'x'. This simulates using convert to merge several repositories
705 709 - together.
706 710 $ cat >> merge-test2/.hg/shamap <<EOF
707 > 3903775176ed42b1458a6281db4a0ccf4d9f287a 34f1aa7da42559bae87920880b522d47b3ddbc0d
711 > $(hg -R merge-test1 log -r 0 -T '{node}') $(hg -R merge-test2 log -r 0 -T '{node}')
712 > $(hg -R merge-test1 log -r 1 -T '{node}') $(hg -R merge-test2 log -r 1 -T '{node}')
708 713 > EOF
709 714 $ cat >> merge-test-filemap <<EOF
710 715 > rename . converted/
711 716 > EOF
712 717 $ hg convert --filemap merge-test-filemap merge-test1 merge-test2 --traceback
713 718 scanning source...
714 719 sorting...
715 720 converting...
716 1 b
717 0 merge
721 1 add b
722 0 merge a & b
718 723 $ hg -R merge-test2 manifest -r tip
719 724 converted/a
720 725 converted/b
721 726 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
727 $ hg -R merge-test2 log -G -T '{shortest(node)} {desc}\n{files % "- {file}\n"}\n'
728 o 6eaa merge a & b
729 |\ - converted/a
730 | | - toberemoved
731 | |
732 | o 2995 add b
733 | | - converted/b
734 | |
735 @ | 150e add x & remove tobremoved
736 |/ - toberemoved
737 | - x
738 |
739 o bbac add converted/a & toberemoved
740 - converted/a
741 - toberemoved
742
731 743
General Comments 0
You need to be logged in to leave comments. Login now