hgext/rebase.py
changeset 46632 9989a276712f
parent 46362 24a32dea6955
child 46677 7ed7b13fc00a
equal deleted inserted replaced
46631:230f73019e49 46632:9989a276712f
   142     # Empty src or already obsoleted - Do not return a destination
   142     # Empty src or already obsoleted - Do not return a destination
   143     if not src or src in obsoleted:
   143     if not src or src in obsoleted:
   144         return smartset.baseset()
   144         return smartset.baseset()
   145     dests = destutil.orphanpossibledestination(repo, src)
   145     dests = destutil.orphanpossibledestination(repo, src)
   146     if len(dests) > 1:
   146     if len(dests) > 1:
   147         raise error.Abort(
   147         raise error.StateError(
   148             _(b"ambiguous automatic rebase: %r could end up on any of %r")
   148             _(b"ambiguous automatic rebase: %r could end up on any of %r")
   149             % (src, dests)
   149             % (src, dests)
   150         )
   150         )
   151     # We have zero or one destination, so we can just return here.
   151     # We have zero or one destination, so we can just return here.
   152     return smartset.baseset(dests)
   152     return smartset.baseset(dests)
   422 
   422 
   423         (self.originalwd, self.destmap, self.state) = result
   423         (self.originalwd, self.destmap, self.state) = result
   424         if self.collapsef:
   424         if self.collapsef:
   425             dests = set(self.destmap.values())
   425             dests = set(self.destmap.values())
   426             if len(dests) != 1:
   426             if len(dests) != 1:
   427                 raise error.Abort(
   427                 raise error.InputError(
   428                     _(b'--collapse does not work with multiple destinations')
   428                     _(b'--collapse does not work with multiple destinations')
   429                 )
   429                 )
   430             destrev = next(iter(dests))
   430             destrev = next(iter(dests))
   431             destancestors = self.repo.changelog.ancestors(
   431             destancestors = self.repo.changelog.ancestors(
   432                 [destrev], inclusive=True
   432                 [destrev], inclusive=True
   467             if self.collapsef:
   467             if self.collapsef:
   468                 branches = set()
   468                 branches = set()
   469                 for rev in self.state:
   469                 for rev in self.state:
   470                     branches.add(repo[rev].branch())
   470                     branches.add(repo[rev].branch())
   471                     if len(branches) > 1:
   471                     if len(branches) > 1:
   472                         raise error.Abort(
   472                         raise error.InputError(
   473                             _(b'cannot collapse multiple named branches')
   473                             _(b'cannot collapse multiple named branches')
   474                         )
   474                         )
   475 
   475 
   476         # Calculate self.obsoletenotrebased
   476         # Calculate self.obsoletenotrebased
   477         obsrevs = _filterobsoleterevs(self.repo, self.state)
   477         obsrevs = _filterobsoleterevs(self.repo, self.state)
  1091     elif action == b'stop':
  1091     elif action == b'stop':
  1092         rbsrt = rebaseruntime(repo, ui)
  1092         rbsrt = rebaseruntime(repo, ui)
  1093         with repo.wlock(), repo.lock():
  1093         with repo.wlock(), repo.lock():
  1094             rbsrt.restorestatus()
  1094             rbsrt.restorestatus()
  1095             if rbsrt.collapsef:
  1095             if rbsrt.collapsef:
  1096                 raise error.Abort(_(b"cannot stop in --collapse session"))
  1096                 raise error.StateError(_(b"cannot stop in --collapse session"))
  1097             allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
  1097             allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
  1098             if not (rbsrt.keepf or allowunstable):
  1098             if not (rbsrt.keepf or allowunstable):
  1099                 raise error.Abort(
  1099                 raise error.StateError(
  1100                     _(
  1100                     _(
  1101                         b"cannot remove original changesets with"
  1101                         b"cannot remove original changesets with"
  1102                         b" unrebased descendants"
  1102                         b" unrebased descendants"
  1103                     ),
  1103                     ),
  1104                     hint=_(
  1104                     hint=_(
  1218                     b"interactive history editing is supported by the "
  1218                     b"interactive history editing is supported by the "
  1219                     b"'histedit' extension (see \"%s\")"
  1219                     b"'histedit' extension (see \"%s\")"
  1220                 )
  1220                 )
  1221                 % help
  1221                 % help
  1222             )
  1222             )
  1223             raise error.Abort(msg)
  1223             raise error.InputError(msg)
  1224 
  1224 
  1225         if rbsrt.collapsemsg and not rbsrt.collapsef:
  1225         if rbsrt.collapsemsg and not rbsrt.collapsef:
  1226             raise error.Abort(_(b'message can only be specified with collapse'))
  1226             raise error.InputError(
       
  1227                 _(b'message can only be specified with collapse')
       
  1228             )
  1227 
  1229 
  1228         if action:
  1230         if action:
  1229             if rbsrt.collapsef:
  1231             if rbsrt.collapsef:
  1230                 raise error.Abort(
  1232                 raise error.InputError(
  1231                     _(b'cannot use collapse with continue or abort')
  1233                     _(b'cannot use collapse with continue or abort')
  1232                 )
  1234                 )
  1233             if action == b'abort' and opts.get(b'tool', False):
  1235             if action == b'abort' and opts.get(b'tool', False):
  1234                 ui.warn(_(b'tool option will be ignored\n'))
  1236                 ui.warn(_(b'tool option will be ignored\n'))
  1235             if action == b'continue':
  1237             if action == b'continue':
  1292     cmdutil.checkunfinished(repo)
  1294     cmdutil.checkunfinished(repo)
  1293     if not inmemory:
  1295     if not inmemory:
  1294         cmdutil.bailifchanged(repo)
  1296         cmdutil.bailifchanged(repo)
  1295 
  1297 
  1296     if ui.configbool(b'commands', b'rebase.requiredest') and not destf:
  1298     if ui.configbool(b'commands', b'rebase.requiredest') and not destf:
  1297         raise error.Abort(
  1299         raise error.InputError(
  1298             _(b'you must specify a destination'),
  1300             _(b'you must specify a destination'),
  1299             hint=_(b'use: hg rebase -d REV'),
  1301             hint=_(b'use: hg rebase -d REV'),
  1300         )
  1302         )
  1301 
  1303 
  1302     dest = None
  1304     dest = None
  1386                     % (b'+'.join(bytes(repo[r]) for r in base), dest)
  1388                     % (b'+'.join(bytes(repo[r]) for r in base), dest)
  1387                 )
  1389                 )
  1388             return None
  1390             return None
  1389 
  1391 
  1390     if wdirrev in rebaseset:
  1392     if wdirrev in rebaseset:
  1391         raise error.Abort(_(b'cannot rebase the working copy'))
  1393         raise error.InputError(_(b'cannot rebase the working copy'))
  1392     rebasingwcp = repo[b'.'].rev() in rebaseset
  1394     rebasingwcp = repo[b'.'].rev() in rebaseset
  1393     ui.log(
  1395     ui.log(
  1394         b"rebase",
  1396         b"rebase",
  1395         b"rebasing working copy parent: %r\n",
  1397         b"rebasing working copy parent: %r\n",
  1396         rebasingwcp,
  1398         rebasingwcp,
  1424                 if size == 1:
  1426                 if size == 1:
  1425                     destmap[r] = destset.first()
  1427                     destmap[r] = destset.first()
  1426                 elif size == 0:
  1428                 elif size == 0:
  1427                     ui.note(_(b'skipping %s - empty destination\n') % repo[r])
  1429                     ui.note(_(b'skipping %s - empty destination\n') % repo[r])
  1428                 else:
  1430                 else:
  1429                     raise error.Abort(
  1431                     raise error.InputError(
  1430                         _(b'rebase destination for %s is not unique') % repo[r]
  1432                         _(b'rebase destination for %s is not unique') % repo[r]
  1431                     )
  1433                     )
  1432 
  1434 
  1433     if dest is not None:
  1435     if dest is not None:
  1434         # single-dest case: assign dest to each rev in rebaseset
  1436         # single-dest case: assign dest to each rev in rebaseset
  1457                 parents.add(p.rev())
  1459                 parents.add(p.rev())
  1458     if not parents:
  1460     if not parents:
  1459         return nullrev
  1461         return nullrev
  1460     if len(parents) == 1:
  1462     if len(parents) == 1:
  1461         return parents.pop()
  1463         return parents.pop()
  1462     raise error.Abort(
  1464     raise error.StateError(
  1463         _(
  1465         _(
  1464             b'unable to collapse on top of %d, there is more '
  1466             b'unable to collapse on top of %d, there is more '
  1465             b'than one external parent: %s'
  1467             b'than one external parent: %s'
  1466         )
  1468         )
  1467         % (max(destancestors), b', '.join(b"%d" % p for p in sorted(parents)))
  1469         % (max(destancestors), b', '.join(b"%d" % p for p in sorted(parents)))
  1657         msg = _(b"this rebase will cause divergences from: %s")
  1659         msg = _(b"this rebase will cause divergences from: %s")
  1658         h = _(
  1660         h = _(
  1659             b"to force the rebase please set "
  1661             b"to force the rebase please set "
  1660             b"experimental.evolution.allowdivergence=True"
  1662             b"experimental.evolution.allowdivergence=True"
  1661         )
  1663         )
  1662         raise error.Abort(msg % (b",".join(divhashes),), hint=h)
  1664         raise error.StateError(msg % (b",".join(divhashes),), hint=h)
  1663 
  1665 
  1664 
  1666 
  1665 def successorrevs(unfi, rev):
  1667 def successorrevs(unfi, rev):
  1666     """yield revision numbers for successors of rev"""
  1668     """yield revision numbers for successors of rev"""
  1667     assert unfi.filtername is None
  1669     assert unfi.filtername is None
  1760         #
  1762         #
  1761         #     C    # rebase -r C -d D
  1763         #     C    # rebase -r C -d D
  1762         #    /|    # None of A and B will be changed to D and rebase fails.
  1764         #    /|    # None of A and B will be changed to D and rebase fails.
  1763         #   A B D
  1765         #   A B D
  1764         if set(newps) == set(oldps) and dest not in newps:
  1766         if set(newps) == set(oldps) and dest not in newps:
  1765             raise error.Abort(
  1767             raise error.InputError(
  1766                 _(
  1768                 _(
  1767                     b'cannot rebase %d:%s without '
  1769                     b'cannot rebase %d:%s without '
  1768                     b'moving at least one of its parents'
  1770                     b'moving at least one of its parents'
  1769                 )
  1771                 )
  1770                 % (rev, repo[rev])
  1772                 % (rev, repo[rev])
  1772 
  1774 
  1773     # Source should not be ancestor of dest. The check here guarantees it's
  1775     # Source should not be ancestor of dest. The check here guarantees it's
  1774     # impossible. With multi-dest, the initial check does not cover complex
  1776     # impossible. With multi-dest, the initial check does not cover complex
  1775     # cases since we don't have abstractions to dry-run rebase cheaply.
  1777     # cases since we don't have abstractions to dry-run rebase cheaply.
  1776     if any(p != nullrev and isancestor(rev, p) for p in newps):
  1778     if any(p != nullrev and isancestor(rev, p) for p in newps):
  1777         raise error.Abort(_(b'source is ancestor of destination'))
  1779         raise error.InputError(_(b'source is ancestor of destination'))
  1778 
  1780 
  1779     # Check if the merge will contain unwanted changes. That may happen if
  1781     # Check if the merge will contain unwanted changes. That may happen if
  1780     # there are multiple special (non-changelog ancestor) merge bases, which
  1782     # there are multiple special (non-changelog ancestor) merge bases, which
  1781     # cannot be handled well by the 3-way merge algorithm. For example:
  1783     # cannot be handled well by the 3-way merge algorithm. For example:
  1782     #
  1784     #
  1834                         b', '.join(b'%d:%s' % (r, repo[r]) for r in revs)
  1836                         b', '.join(b'%d:%s' % (r, repo[r]) for r in revs)
  1835                         for revs in unwanted
  1837                         for revs in unwanted
  1836                         if revs is not None
  1838                         if revs is not None
  1837                     )
  1839                     )
  1838                 )
  1840                 )
  1839                 raise error.Abort(
  1841                 raise error.InputError(
  1840                     _(b'rebasing %d:%s will include unwanted changes from %s')
  1842                     _(b'rebasing %d:%s will include unwanted changes from %s')
  1841                     % (rev, repo[rev], unwanteddesc)
  1843                     % (rev, repo[rev], unwanteddesc)
  1842                 )
  1844                 )
  1843 
  1845 
  1844             # newps[0] should match merge base if possible. Currently, if newps[i]
  1846             # newps[0] should match merge base if possible. Currently, if newps[i]
  1979         result = []
  1981         result = []
  1980         for r in srclist:
  1982         for r in srclist:
  1981             if destmap[r] not in srcset:
  1983             if destmap[r] not in srcset:
  1982                 result.append(r)
  1984                 result.append(r)
  1983         if not result:
  1985         if not result:
  1984             raise error.Abort(_(b'source and destination form a cycle'))
  1986             raise error.InputError(_(b'source and destination form a cycle'))
  1985         srcset -= set(result)
  1987         srcset -= set(result)
  1986         yield result
  1988         yield result
  1987 
  1989 
  1988 
  1990 
  1989 def buildstate(repo, destmap, collapse):
  1991 def buildstate(repo, destmap, collapse):
  1999     # applied patch. But it prevents messing up the working directory when
  2001     # applied patch. But it prevents messing up the working directory when
  2000     # a partially completed rebase is blocked by mq.
  2002     # a partially completed rebase is blocked by mq.
  2001     if b'qtip' in repo.tags():
  2003     if b'qtip' in repo.tags():
  2002         mqapplied = {repo[s.node].rev() for s in repo.mq.applied}
  2004         mqapplied = {repo[s.node].rev() for s in repo.mq.applied}
  2003         if set(destmap.values()) & mqapplied:
  2005         if set(destmap.values()) & mqapplied:
  2004             raise error.Abort(_(b'cannot rebase onto an applied mq patch'))
  2006             raise error.StateError(_(b'cannot rebase onto an applied mq patch'))
  2005 
  2007 
  2006     # Get "cycle" error early by exhausting the generator.
  2008     # Get "cycle" error early by exhausting the generator.
  2007     sortedsrc = list(sortsource(destmap))  # a list of sorted revs
  2009     sortedsrc = list(sortsource(destmap))  # a list of sorted revs
  2008     if not sortedsrc:
  2010     if not sortedsrc:
  2009         raise error.Abort(_(b'no matching revisions'))
  2011         raise error.InputError(_(b'no matching revisions'))
  2010 
  2012 
  2011     # Only check the first batch of revisions to rebase not depending on other
  2013     # Only check the first batch of revisions to rebase not depending on other
  2012     # rebaseset. This means "source is ancestor of destination" for the second
  2014     # rebaseset. This means "source is ancestor of destination" for the second
  2013     # (and following) batches of revisions are not checked here. We rely on
  2015     # (and following) batches of revisions are not checked here. We rely on
  2014     # "defineparents" to do that check.
  2016     # "defineparents" to do that check.
  2015     roots = list(repo.set(b'roots(%ld)', sortedsrc[0]))
  2017     roots = list(repo.set(b'roots(%ld)', sortedsrc[0]))
  2016     if not roots:
  2018     if not roots:
  2017         raise error.Abort(_(b'no matching revisions'))
  2019         raise error.InputError(_(b'no matching revisions'))
  2018 
  2020 
  2019     def revof(r):
  2021     def revof(r):
  2020         return r.rev()
  2022         return r.rev()
  2021 
  2023 
  2022     roots = sorted(roots, key=revof)
  2024     roots = sorted(roots, key=revof)
  2024     emptyrebase = len(sortedsrc) == 1
  2026     emptyrebase = len(sortedsrc) == 1
  2025     for root in roots:
  2027     for root in roots:
  2026         dest = repo[destmap[root.rev()]]
  2028         dest = repo[destmap[root.rev()]]
  2027         commonbase = root.ancestor(dest)
  2029         commonbase = root.ancestor(dest)
  2028         if commonbase == root:
  2030         if commonbase == root:
  2029             raise error.Abort(_(b'source is ancestor of destination'))
  2031             raise error.InputError(_(b'source is ancestor of destination'))
  2030         if commonbase == dest:
  2032         if commonbase == dest:
  2031             wctx = repo[None]
  2033             wctx = repo[None]
  2032             if dest == wctx.p1():
  2034             if dest == wctx.p1():
  2033                 # when rebasing to '.', it will use the current wd branch name
  2035                 # when rebasing to '.', it will use the current wd branch name
  2034                 samebranch = root.branch() == wctx.branch()
  2036                 samebranch = root.branch() == wctx.branch()
  2117     """Call rebase after pull if the latter has been invoked with --rebase"""
  2119     """Call rebase after pull if the latter has been invoked with --rebase"""
  2118     if opts.get('rebase'):
  2120     if opts.get('rebase'):
  2119         if ui.configbool(b'commands', b'rebase.requiredest'):
  2121         if ui.configbool(b'commands', b'rebase.requiredest'):
  2120             msg = _(b'rebase destination required by configuration')
  2122             msg = _(b'rebase destination required by configuration')
  2121             hint = _(b'use hg pull followed by hg rebase -d DEST')
  2123             hint = _(b'use hg pull followed by hg rebase -d DEST')
  2122             raise error.Abort(msg, hint=hint)
  2124             raise error.InputError(msg, hint=hint)
  2123 
  2125 
  2124         with repo.wlock(), repo.lock():
  2126         with repo.wlock(), repo.lock():
  2125             if opts.get('update'):
  2127             if opts.get('update'):
  2126                 del opts['update']
  2128                 del opts['update']
  2127                 ui.debug(
  2129                 ui.debug(
  2174                         # not passing argument to get the bare update behavior
  2176                         # not passing argument to get the bare update behavior
  2175                         # with warning and trumpets
  2177                         # with warning and trumpets
  2176                         commands.update(ui, repo)
  2178                         commands.update(ui, repo)
  2177     else:
  2179     else:
  2178         if opts.get('tool'):
  2180         if opts.get('tool'):
  2179             raise error.Abort(_(b'--tool can only be used with --rebase'))
  2181             raise error.InputError(_(b'--tool can only be used with --rebase'))
  2180         ret = orig(ui, repo, *args, **opts)
  2182         ret = orig(ui, repo, *args, **opts)
  2181 
  2183 
  2182     return ret
  2184     return ret
  2183 
  2185 
  2184 
  2186