comparison mercurial/scmutil.py @ 33331:4bae3c117b57

scmutil: make cleanupnodes delete divergent bookmarks cleanupnodes takes care of bookmark movement, and bookmark movement could cause bookmark divergent resolution as a side effect. This patch adds such bookmark divergent resolution logic so future rebase migration will be easier. The revset is carefully written to be equivalent to what rebase does today. Although I think it might make sense to remove divergent bookmarks more aggressively, for example: F book@1 | E book@2 | | D book | | | C |/ B book@3 | A When rebase -s C -d E, "book@1" will be removed, "book@3" will be kept, and the end result is: D book | C | F | E book@2 (?) | B book@3 | A The question is should we keep book@2? The current logic keeps it. If we choose not to (makes some sense to me), the "deleterevs" revset could be simplified to "newnode % oldnode". For now, I just make it compatible with the existing behavior. If we want to make the "deleterevs" revset simpler, we can always do it in the future.
author Jun Wu <quark@fb.com>
date Mon, 26 Jun 2017 13:13:51 -0700
parents ba43e5ee9c6d
children 967ac37f3d45
comparison
equal deleted inserted replaced
33330:ba43e5ee9c6d 33331:4bae3c117b57
565 ui.note(_('creating directory: %s\n') % origbackupdir) 565 ui.note(_('creating directory: %s\n') % origbackupdir)
566 util.makedirs(origbackupdir) 566 util.makedirs(origbackupdir)
567 567
568 return fullorigpath + ".orig" 568 return fullorigpath + ".orig"
569 569
570 class _containsnode(object):
571 """proxy __contains__(node) to container.__contains__ which accepts revs"""
572
573 def __init__(self, repo, revcontainer):
574 self._torev = repo.changelog.rev
575 self._revcontains = revcontainer.__contains__
576
577 def __contains__(self, node):
578 return self._revcontains(self._torev(node))
579
570 def cleanupnodes(repo, mapping, operation): 580 def cleanupnodes(repo, mapping, operation):
571 """do common cleanups when old nodes are replaced by new nodes 581 """do common cleanups when old nodes are replaced by new nodes
572 582
573 That includes writing obsmarkers or stripping nodes, and moving bookmarks. 583 That includes writing obsmarkers or stripping nodes, and moving bookmarks.
574 (we might also want to move working directory parent in the future) 584 (we might also want to move working directory parent in the future)
581 591
582 with repo.transaction('cleanup') as tr: 592 with repo.transaction('cleanup') as tr:
583 # Move bookmarks 593 # Move bookmarks
584 bmarks = repo._bookmarks 594 bmarks = repo._bookmarks
585 bmarkchanged = False 595 bmarkchanged = False
596 allnewnodes = [n for ns in mapping.values() for n in ns]
586 for oldnode, newnodes in mapping.items(): 597 for oldnode, newnodes in mapping.items():
587 oldbmarks = repo.nodebookmarks(oldnode) 598 oldbmarks = repo.nodebookmarks(oldnode)
588 if not oldbmarks: 599 if not oldbmarks:
589 continue 600 continue
601 from . import bookmarks # avoid import cycle
590 bmarkchanged = True 602 bmarkchanged = True
591 if len(newnodes) > 1: 603 if len(newnodes) > 1:
592 heads = list(repo.set('heads(%ln)', newnodes)) 604 # usually a split, take the one with biggest rev number
593 if len(heads) != 1: 605 newnode = next(repo.set('max(%ln)', newnodes)).node()
594 raise error.ProgrammingError(
595 'cannot figure out bookmark movement')
596 newnode = heads[0].node()
597 elif len(newnodes) == 0: 606 elif len(newnodes) == 0:
598 # move bookmark backwards 607 # move bookmark backwards
599 roots = list(repo.set('max((::%n) - %ln)', oldnode, 608 roots = list(repo.set('max((::%n) - %ln)', oldnode,
600 list(mapping))) 609 list(mapping)))
601 if roots: 610 if roots:
604 newnode = nullid 613 newnode = nullid
605 else: 614 else:
606 newnode = newnodes[0] 615 newnode = newnodes[0]
607 repo.ui.debug('moving bookmarks %r from %s to %s\n' % 616 repo.ui.debug('moving bookmarks %r from %s to %s\n' %
608 (oldbmarks, hex(oldnode), hex(newnode))) 617 (oldbmarks, hex(oldnode), hex(newnode)))
618 # Delete divergent bookmarks being parents of related newnodes
619 deleterevs = repo.revs('parents(roots(%ln & (::%n))) - parents(%n)',
620 allnewnodes, newnode, oldnode)
621 deletenodes = _containsnode(repo, deleterevs)
609 for name in oldbmarks: 622 for name in oldbmarks:
610 bmarks[name] = newnode 623 bmarks[name] = newnode
624 bookmarks.deletedivergent(repo, deletenodes, name)
611 if bmarkchanged: 625 if bmarkchanged:
612 bmarks.recordchange(tr) 626 bmarks.recordchange(tr)
613 627
614 # Obsolete or strip nodes 628 # Obsolete or strip nodes
615 if obsolete.isenabled(repo, obsolete.createmarkersopt): 629 if obsolete.isenabled(repo, obsolete.createmarkersopt):