Mercurial > hg
comparison hgext/rebase.py @ 46632:9989a276712f
errors: use more specific errors in rebase extension
Differential Revision: https://phab.mercurial-scm.org/D9914
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Fri, 29 Jan 2021 16:33:12 -0800 |
parents | 24a32dea6955 |
children | 7ed7b13fc00a |
comparison
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 |