comparison mercurial/copies.py @ 30203:b94b92f0c683

checkcopies: add logic to handle remotebase As the two _checkcopies passes' ranges are separated by tca, not base, only one of the two passes will actually encounter the base. Pass "remotebase" to the other pass to let it know not to expect passing over the base. This is required for handling a few unusual rename cases.
author Gábor Stefanik <gabor.stefanik@nng.com>
date Tue, 11 Oct 2016 04:25:59 +0200
parents a005c33d0bd7
children 1894c830ee74
comparison
equal deleted inserted replaced
30202:a005c33d0bd7 30203:b94b92f0c683
411 u1u, u2u = _computenonoverlap(repo, c1, c2, m1.filesnotin(mta), 411 u1u, u2u = _computenonoverlap(repo, c1, c2, m1.filesnotin(mta),
412 m2.filesnotin(mta), 412 m2.filesnotin(mta),
413 baselabel='topological common ancestor') 413 baselabel='topological common ancestor')
414 414
415 for f in u1u: 415 for f in u1u:
416 _checkcopies(c1, f, m1, m2, base, tca, limit, data1) 416 _checkcopies(c1, f, m1, m2, base, tca, dirtyc1, limit, data1)
417 417
418 for f in u2u: 418 for f in u2u:
419 _checkcopies(c2, f, m2, m1, base, tca, limit, data2) 419 _checkcopies(c2, f, m2, m1, base, tca, dirtyc2, limit, data2)
420 420
421 copy = dict(data1['copy'].items() + data2['copy'].items()) 421 copy = dict(data1['copy'].items() + data2['copy'].items())
422 fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items()) 422 fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items())
423 423
424 if dirtyc1: 424 if dirtyc1:
458 'incomplete': {}, 458 'incomplete': {},
459 'diverge': bothdiverge, 459 'diverge': bothdiverge,
460 'incompletediverge': bothincompletediverge 460 'incompletediverge': bothincompletediverge
461 } 461 }
462 for f in bothnew: 462 for f in bothnew:
463 _checkcopies(c1, f, m1, m2, base, tca, limit, both1) 463 _checkcopies(c1, f, m1, m2, base, tca, dirtyc1, limit, both1)
464 _checkcopies(c2, f, m2, m1, base, tca, limit, both2) 464 _checkcopies(c2, f, m2, m1, base, tca, dirtyc2, limit, both2)
465 if dirtyc1: 465 if dirtyc1:
466 assert both2['incomplete'] == {} 466 assert both2['incomplete'] == {}
467 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge, 467 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
468 bothincompletediverge) 468 bothincompletediverge)
469 else: 469 else:
588 elif f1r == f2r or f1r < limit or f2r < limit: 588 elif f1r == f2r or f1r < limit or f2r < limit:
589 return False # copy no longer relevant 589 return False # copy no longer relevant
590 except StopIteration: 590 except StopIteration:
591 return False 591 return False
592 592
593 def _checkcopies(ctx, f, m1, m2, base, tca, limit, data): 593 def _checkcopies(ctx, f, m1, m2, base, tca, remotebase, limit, data):
594 """ 594 """
595 check possible copies of f from m1 to m2 595 check possible copies of f from m1 to m2
596 596
597 ctx = starting context for f in m1 597 ctx = starting context for f in m1
598 f = the filename to check (as in m1) 598 f = the filename to check (as in m1)
599 m1 = the source manifest 599 m1 = the source manifest
600 m2 = the destination manifest 600 m2 = the destination manifest
601 base = the changectx used as a merge base 601 base = the changectx used as a merge base
602 tca = topological common ancestor for graft-like scenarios 602 tca = topological common ancestor for graft-like scenarios
603 remotebase = True if base is outside tca::ctx, False otherwise
603 limit = the rev number to not search beyond 604 limit = the rev number to not search beyond
604 data = dictionary of dictionary to store copy data. (see mergecopies) 605 data = dictionary of dictionary to store copy data. (see mergecopies)
605 606
606 note: limit is only an optimization, and there is no guarantee that 607 note: limit is only an optimization, and there is no guarantee that
607 irrelevant revisions will not be limited 608 irrelevant revisions will not be limited
617 # traversed backwards. 618 # traversed backwards.
618 # 619 #
619 # In the case there is both backward and forward renames (before and after 620 # In the case there is both backward and forward renames (before and after
620 # the base) this is more complicated as we must detect a divergence. 621 # the base) this is more complicated as we must detect a divergence.
621 # We use 'backwards = False' in that case. 622 # We use 'backwards = False' in that case.
622 backwards = base != tca and f in mb 623 backwards = not remotebase and base != tca and f in mb
623 getfctx = _makegetfctx(ctx) 624 getfctx = _makegetfctx(ctx)
624 625
625 of = None 626 of = None
626 seen = set([f]) 627 seen = set([f])
627 for oc in getfctx(f, m1[f]).ancestors(): 628 for oc in getfctx(f, m1[f]).ancestors():
650 if cr and (of == f or of == c2.path()): # non-divergent 651 if cr and (of == f or of == c2.path()): # non-divergent
651 if backwards: 652 if backwards:
652 data['copy'][of] = f 653 data['copy'][of] = f
653 elif of in mb: 654 elif of in mb:
654 data['copy'][f] = of 655 data['copy'][f] = of
656 elif remotebase: # special case: a <- b <- a -> b "ping-pong" rename
657 data['copy'][of] = f
658 del data['fullcopy'][f]
659 data['fullcopy'][of] = f
655 else: # divergence w.r.t. graft CA on one side of topological CA 660 else: # divergence w.r.t. graft CA on one side of topological CA
656 for sf in seen: 661 for sf in seen:
657 if sf in mb: 662 if sf in mb:
658 assert sf not in data['diverge'] 663 assert sf not in data['diverge']
659 data['diverge'][sf] = [f, of] 664 data['diverge'][sf] = [f, of]