574 self._revcontains = revcontainer.__contains__ |
574 self._revcontains = revcontainer.__contains__ |
575 |
575 |
576 def __contains__(self, node): |
576 def __contains__(self, node): |
577 return self._revcontains(self._torev(node)) |
577 return self._revcontains(self._torev(node)) |
578 |
578 |
579 def cleanupnodes(repo, replacements, operation): |
579 def cleanupnodes(repo, replacements, operation, moves=None): |
580 """do common cleanups when old nodes are replaced by new nodes |
580 """do common cleanups when old nodes are replaced by new nodes |
581 |
581 |
582 That includes writing obsmarkers or stripping nodes, and moving bookmarks. |
582 That includes writing obsmarkers or stripping nodes, and moving bookmarks. |
583 (we might also want to move working directory parent in the future) |
583 (we might also want to move working directory parent in the future) |
|
584 |
|
585 By default, bookmark moves are calculated automatically from 'replacements', |
|
586 but 'moves' can be used to override that. Also, 'moves' may include |
|
587 additional bookmark moves that should not have associated obsmarkers. |
584 |
588 |
585 replacements is {oldnode: [newnode]} or a iterable of nodes if they do not |
589 replacements is {oldnode: [newnode]} or a iterable of nodes if they do not |
586 have replacements. operation is a string, like "rebase". |
590 have replacements. operation is a string, like "rebase". |
587 """ |
591 """ |
|
592 if not replacements and not moves: |
|
593 return |
|
594 |
|
595 # translate mapping's other forms |
588 if not util.safehasattr(replacements, 'items'): |
596 if not util.safehasattr(replacements, 'items'): |
589 replacements = {n: () for n in replacements} |
597 replacements = {n: () for n in replacements} |
590 |
598 |
591 # Calculate bookmark movements |
599 # Calculate bookmark movements |
592 moves = {} |
600 if moves is None: |
|
601 moves = {} |
593 # Unfiltered repo is needed since nodes in replacements might be hidden. |
602 # Unfiltered repo is needed since nodes in replacements might be hidden. |
594 unfi = repo.unfiltered() |
603 unfi = repo.unfiltered() |
595 for oldnode, newnodes in replacements.items(): |
604 for oldnode, newnodes in replacements.items(): |
|
605 if oldnode in moves: |
|
606 continue |
596 if len(newnodes) > 1: |
607 if len(newnodes) > 1: |
597 # usually a split, take the one with biggest rev number |
608 # usually a split, take the one with biggest rev number |
598 newnode = next(unfi.set('max(%ln)', newnodes)).node() |
609 newnode = next(unfi.set('max(%ln)', newnodes)).node() |
599 elif len(newnodes) == 0: |
610 elif len(newnodes) == 0: |
600 # move bookmark backwards |
611 # move bookmark backwards |
644 torev = unfi.changelog.rev |
655 torev = unfi.changelog.rev |
645 sortfunc = lambda ns: torev(ns[0]) |
656 sortfunc = lambda ns: torev(ns[0]) |
646 rels = [(unfi[n], tuple(unfi[m] for m in s)) |
657 rels = [(unfi[n], tuple(unfi[m] for m in s)) |
647 for n, s in sorted(replacements.items(), key=sortfunc) |
658 for n, s in sorted(replacements.items(), key=sortfunc) |
648 if s or not isobs(n)] |
659 if s or not isobs(n)] |
649 obsolete.createmarkers(repo, rels, operation=operation) |
660 if rels: |
|
661 obsolete.createmarkers(repo, rels, operation=operation) |
650 else: |
662 else: |
651 from . import repair # avoid import cycle |
663 from . import repair # avoid import cycle |
652 repair.delayedstrip(repo.ui, repo, list(replacements), operation) |
664 tostrip = list(replacements) |
|
665 if tostrip: |
|
666 repair.delayedstrip(repo.ui, repo, tostrip, operation) |
653 |
667 |
654 def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None): |
668 def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None): |
655 if opts is None: |
669 if opts is None: |
656 opts = {} |
670 opts = {} |
657 m = matcher |
671 m = matcher |