Mercurial > hg-stable
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): |