hgext/rebase.py
changeset 18447 7159426c8d13
parent 18446 c83d36b81df1
child 18512 22978b82ab4b
equal deleted inserted replaced
18446:c83d36b81df1 18447:7159426c8d13
    21 from mercurial.lock import release
    21 from mercurial.lock import release
    22 from mercurial.i18n import _
    22 from mercurial.i18n import _
    23 import os, errno
    23 import os, errno
    24 
    24 
    25 nullmerge = -2
    25 nullmerge = -2
       
    26 revignored = -3
    26 
    27 
    27 cmdtable = {}
    28 cmdtable = {}
    28 command = cmdutil.command(cmdtable)
    29 command = cmdutil.command(cmdtable)
    29 testedwith = 'internal'
    30 testedwith = 'internal'
    30 
    31 
   390         base = repo[rev].p1().node()
   391         base = repo[rev].p1().node()
   391     # When collapsing in-place, the parent is the common ancestor, we
   392     # When collapsing in-place, the parent is the common ancestor, we
   392     # have to allow merging with it.
   393     # have to allow merging with it.
   393     return merge.update(repo, rev, True, True, False, base, collapse)
   394     return merge.update(repo, rev, True, True, False, base, collapse)
   394 
   395 
       
   396 def nearestrebased(repo, rev, state):
       
   397     """return the nearest ancestors of rev in the rebase result"""
       
   398     rebased = [r for r in state if state[r] > nullmerge]
       
   399     candidates = repo.revs('max(%ld  and (::%d))', rebased, rev)
       
   400     if candidates:
       
   401         return state[candidates[0]]
       
   402     else:
       
   403         return None
       
   404 
   395 def defineparents(repo, rev, target, state, targetancestors):
   405 def defineparents(repo, rev, target, state, targetancestors):
   396     'Return the new parent relationship of the revision that will be rebased'
   406     'Return the new parent relationship of the revision that will be rebased'
   397     parents = repo[rev].parents()
   407     parents = repo[rev].parents()
   398     p1 = p2 = nullrev
   408     p1 = p2 = nullrev
   399 
   409 
   401     if P1n in targetancestors:
   411     if P1n in targetancestors:
   402         p1 = target
   412         p1 = target
   403     elif P1n in state:
   413     elif P1n in state:
   404         if state[P1n] == nullmerge:
   414         if state[P1n] == nullmerge:
   405             p1 = target
   415             p1 = target
       
   416         elif state[P1n] == revignored:
       
   417             p1 = nearestrebased(repo, P1n, state)
       
   418             if p1 is None:
       
   419                 p1 = target
   406         else:
   420         else:
   407             p1 = state[P1n]
   421             p1 = state[P1n]
   408     else: # P1n external
   422     else: # P1n external
   409         p1 = target
   423         p1 = target
   410         p2 = P1n
   424         p2 = P1n
   413         P2n = parents[1].rev()
   427         P2n = parents[1].rev()
   414         # interesting second parent
   428         # interesting second parent
   415         if P2n in state:
   429         if P2n in state:
   416             if p1 == target: # P1n in targetancestors or external
   430             if p1 == target: # P1n in targetancestors or external
   417                 p1 = state[P2n]
   431                 p1 = state[P2n]
       
   432             elif state[P2n] == revignored:
       
   433                 p2 = nearestrebased(repo, P2n, state)
       
   434                 if p2 is None:
       
   435                     # no ancestors rebased yet, detach
       
   436                     p2 = target
   418             else:
   437             else:
   419                 p2 = state[P2n]
   438                 p2 = state[P2n]
   420         else: # P2n external
   439         else: # P2n external
   421             if p2 != nullrev: # P1n external too => rev is a merged revision
   440             if p2 != nullrev: # P1n external too => rev is a merged revision
   422                 raise util.Abort(_('cannot use revision %d as base, result '
   441                 raise util.Abort(_('cannot use revision %d as base, result '
   530                 keep = bool(int(l))
   549                 keep = bool(int(l))
   531             elif i == 5:
   550             elif i == 5:
   532                 keepbranches = bool(int(l))
   551                 keepbranches = bool(int(l))
   533             else:
   552             else:
   534                 oldrev, newrev = l.split(':')
   553                 oldrev, newrev = l.split(':')
   535                 if newrev != str(nullmerge):
   554                 if newrev in (str(nullmerge), str(revignored)):
       
   555                     state[repo[oldrev].rev()] = int(newrev)
       
   556                 else:
   536                     state[repo[oldrev].rev()] = repo[newrev].rev()
   557                     state[repo[oldrev].rev()] = repo[newrev].rev()
   537                 else:
       
   538                     state[repo[oldrev].rev()] = int(newrev)
       
   539         skipped = set()
   558         skipped = set()
   540         # recompute the set of skipped revs
   559         # recompute the set of skipped revs
   541         if not collapse:
   560         if not collapse:
   542             seen = set([target])
   561             seen = set([target])
   543             for old, new in sorted(state.items()):
   562             for old, new in sorted(state.items()):
   656             detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
   675             detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
   657                                                             [root.rev()]))
   676                                                             [root.rev()]))
   658     for r in detachset:
   677     for r in detachset:
   659         if r not in state:
   678         if r not in state:
   660             state[r] = nullmerge
   679             state[r] = nullmerge
       
   680     if len(roots) > 1:
       
   681         # If we have multiple roots, we may have "hole" in the rebase set.
       
   682         # Rebase roots that descend from those "hole" should not be detached as
       
   683         # other root are. We use the special `revignored` to inform rebase that
       
   684         # the revision should be ignored but that `defineparent` should search
       
   685         # a rebase destination that make sense regarding rebaset topology.
       
   686         rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
       
   687         for ignored in set(rebasedomain) - set(rebaseset):
       
   688             state[ignored] = revignored
   661     return repo['.'].rev(), dest.rev(), state
   689     return repo['.'].rev(), dest.rev(), state
   662 
   690 
   663 def clearrebased(ui, repo, state, skipped, collapsedas=None):
   691 def clearrebased(ui, repo, state, skipped, collapsedas=None):
   664     """dispose of rebased revision at the end of the rebase
   692     """dispose of rebased revision at the end of the rebase
   665 
   693