hgext/evolve.py
changeset 1547 425c0700aabd
parent 1536 9afe9e0191a1
child 1554 59f5bb1f1877
equal deleted inserted replaced
1546:69a0d60f9c99 1547:425c0700aabd
   122 elif gboptslist is not None:
   122 elif gboptslist is not None:
   123     oldmemfilectx = context.memfilectx
   123     oldmemfilectx = context.memfilectx
   124     def memfilectx(repo, *args, **kwargs):
   124     def memfilectx(repo, *args, **kwargs):
   125         return oldmemfilectx(*args, **kwargs)
   125         return oldmemfilectx(*args, **kwargs)
   126 else:
   126 else:
   127     raise ImportError('evolve needs version %s or above' % min(testedwith.split()))
   127     raise ImportError('evolve needs version %s or above' %
       
   128                       min(testedwith.split()))
   128 
   129 
   129 aliases, entry = cmdutil.findcmd('commit', commands.table)
   130 aliases, entry = cmdutil.findcmd('commit', commands.table)
   130 hasinteractivemode = any(['interactive' in e for e in entry[1]])
   131 hasinteractivemode = any(['interactive' in e for e in entry[1]])
   131 if hasinteractivemode:
   132 if hasinteractivemode:
   132     interactiveopt = [['i', 'interactive', None, _('use interactive mode')]]
   133     interactiveopt = [['i', 'interactive', None, _('use interactive mode')]]
   413         for cmd in evolvecommands:
   414         for cmd in evolvecommands:
   414             matchingevolvecommands = [e for e in cmdtable.keys() if cmd in e]
   415             matchingevolvecommands = [e for e in cmdtable.keys() if cmd in e]
   415             if not matchingevolvecommands:
   416             if not matchingevolvecommands:
   416                 raise error.Abort(_('unknown command: %s') % cmd)
   417                 raise error.Abort(_('unknown command: %s') % cmd)
   417             elif len(matchingevolvecommands) > 1:
   418             elif len(matchingevolvecommands) > 1:
   418                 raise error.Abort(_('ambiguous command specification: "%s" matches %r')
   419                 msg = _('ambiguous command specification: "%s" matches %r')
   419                                   % (cmd, matchingevolvecommands))
   420                 raise error.Abort(msg % (cmd, matchingevolvecommands))
   420             else:
   421             else:
   421                 whitelist.add(matchingevolvecommands[0])
   422                 whitelist.add(matchingevolvecommands[0])
   422         for disabledcmd in set(cmdtable) - whitelist:
   423         for disabledcmd in set(cmdtable) - whitelist:
   423             del cmdtable[disabledcmd]
   424             del cmdtable[disabledcmd]
   424 
   425 
   745 def push(orig, repo, *args, **opts):
   746 def push(orig, repo, *args, **opts):
   746     """Add a hint for "hg evolve" when troubles make push fails
   747     """Add a hint for "hg evolve" when troubles make push fails
   747     """
   748     """
   748     try:
   749     try:
   749         return orig(repo, *args, **opts)
   750         return orig(repo, *args, **opts)
   750     except util.Abort, ex:
   751     except error.Abort as ex:
   751         hint = _("use 'hg evolve' to get a stable history "
   752         hint = _("use 'hg evolve' to get a stable history "
   752                  "or --force to ignore warnings")
   753                  "or --force to ignore warnings")
   753         if (len(ex.args) >= 1
   754         if (len(ex.args) >= 1
   754             and ex.args[0].startswith('push includes ')
   755             and ex.args[0].startswith('push includes ')
   755             and ex.hint is None):
   756             and ex.hint is None):
   787     try:
   788     try:
   788         rebase = extensions.find('rebase')
   789         rebase = extensions.find('rebase')
   789         if rebase:
   790         if rebase:
   790             extensions.wrapcommand(rebase.cmdtable, 'rebase', warnobserrors)
   791             extensions.wrapcommand(rebase.cmdtable, 'rebase', warnobserrors)
   791     except KeyError:
   792     except KeyError:
   792         pass  # rebase not found
   793         pass # rebase not found
   793     try:
   794     try:
   794         histedit = extensions.find('histedit')
   795         histedit = extensions.find('histedit')
   795         if histedit:
   796         if histedit:
   796             extensions.wrapcommand(histedit.cmdtable, 'histedit', warnobserrors)
   797             extensions.wrapcommand(histedit.cmdtable, 'histedit', warnobserrors)
   797     except KeyError:
   798     except KeyError:
   798         pass  # rebase not found
   799         pass # rebase not found
   799 
   800 
   800 #####################################################################
   801 #####################################################################
   801 ### Old Evolve extension content                                  ###
   802 ### Old Evolve extension content                                  ###
   802 #####################################################################
   803 #####################################################################
   803 
   804 
   890         tr.close()
   891         tr.close()
   891         return newid, created
   892         return newid, created
   892     finally:
   893     finally:
   893         lockmod.release(lock, wlock, tr)
   894         lockmod.release(lock, wlock, tr)
   894 
   895 
   895 class MergeFailure(util.Abort):
   896 class MergeFailure(error.Abort):
   896     pass
   897     pass
   897 
   898 
   898 def relocate(repo, orig, dest, keepbranch=False):
   899 def relocate(repo, orig, dest, keepbranch=False):
   899     """rewrite <rev> on dest"""
   900     """rewrite <rev> on dest"""
   900     if orig.rev() == dest.rev():
   901     if orig.rev() == dest.rev():
   901         raise util.Abort(_('tried to relocate a node on top of itself'),
   902         raise error.Abort(_('tried to relocate a node on top of itself'),
   902                          hint=_("This shouldn't happen. If you still "
   903                          hint=_("This shouldn't happen. If you still "
   903                                 "need to move changesets, please do so "
   904                                 "need to move changesets, please do so "
   904                                 "manually with nothing to rebase - working "
   905                                 "manually with nothing to rebase - working "
   905                                 "directory parent is also destination"))
   906                                 "directory parent is also destination"))
   906 
   907 
   907     if not orig.p2().rev() == node.nullrev:
   908     if not orig.p2().rev() == node.nullrev:
   908         raise util.Abort(
   909         raise error.Abort(
   909             'no support for evolving merge changesets yet',
   910             'no support for evolving merge changesets yet',
   910             hint="Redo the merge and use `hg prune <old> --succ <new>` to obsolete the old one")
   911             hint="Redo the merge and use `hg prune <old> --succ <new>` "
       
   912                  "to obsolete the old one")
   911     destbookmarks = repo.nodebookmarks(dest.node())
   913     destbookmarks = repo.nodebookmarks(dest.node())
   912     nodesrc = orig.node()
   914     nodesrc = orig.node()
   913     destphase = repo[nodesrc].phase()
   915     destphase = repo[nodesrc].phase()
   914     commitmsg = orig.description()
   916     commitmsg = orig.description()
   915 
   917 
   947             bmdeactivate(repo)
   949             bmdeactivate(repo)
   948             if keepbranch:
   950             if keepbranch:
   949                 repo.dirstate.setbranch(orig.branch())
   951                 repo.dirstate.setbranch(orig.branch())
   950             r = merge.graft(repo, orig, orig.p1(), ['local', 'graft'])
   952             r = merge.graft(repo, orig, orig.p1(), ['local', 'graft'])
   951             if r[-1]:  #some conflict
   953             if r[-1]:  #some conflict
   952                 raise util.Abort(
   954                 raise error.Abort(
   953                         'unresolved merge conflicts (see hg help resolve)')
   955                         'unresolved merge conflicts (see hg help resolve)')
   954             if commitmsg is None:
   956             if commitmsg is None:
   955                 commitmsg = orig.description()
   957                 commitmsg = orig.description()
   956             extra = dict(orig.extra())
   958             extra = dict(orig.extra())
   957             if 'branch' in extra:
   959             if 'branch' in extra:
   965                 # Commit might fail if unresolved files exist
   967                 # Commit might fail if unresolved files exist
   966                 nodenew = repo.commit(text=commitmsg, user=orig.user(),
   968                 nodenew = repo.commit(text=commitmsg, user=orig.user(),
   967                                       date=orig.date(), extra=extra)
   969                                       date=orig.date(), extra=extra)
   968             finally:
   970             finally:
   969                 repo.ui.restoreconfig(backup)
   971                 repo.ui.restoreconfig(backup)
   970         except util.Abort, exc:
   972         except error.Abort as exc:
   971             repo.dirstate.beginparentchange()
   973             repo.dirstate.beginparentchange()
   972             repo.setparents(repo['.'].node(), nullid)
   974             repo.setparents(repo['.'].node(), nullid)
   973             writedirstate(repo.dirstate, tr)
   975             writedirstate(repo.dirstate, tr)
   974             # fix up dirstate for copies and renames
   976             # fix up dirstate for copies and renames
   975             copies.duplicatecopies(repo, dest.rev(), orig.p1().rev())
   977             copies.duplicatecopies(repo, dest.rev(), orig.p1().rev())
  1153                     parents = tuple(p.node() for p in ctx.parents())
  1155                     parents = tuple(p.node() for p in ctx.parents())
  1154                     before = len(store._all)
  1156                     before = len(store._all)
  1155                     store.create(tr, mark[0], mark[1], mark[2], marks[3],
  1157                     store.create(tr, mark[0], mark[1], mark[2], marks[3],
  1156                                  parents=parents)
  1158                                  parents=parents)
  1157                     if len(store._all) - before:
  1159                     if len(store._all) - before:
  1158                         ui.write('created new markers for %i\n' % rev)
  1160                         ui.write(_('created new markers for %i\n') % rev)
  1159             ui.progress(pgop, idx, total=pgtotal)
  1161             ui.progress(pgop, idx, total=pgtotal)
  1160         tr.close()
  1162         tr.close()
  1161         ui.progress(pgop, None)
  1163         ui.progress(pgop, None)
  1162     finally:
  1164     finally:
  1163         lockmod.release(tr, lock, wlock)
  1165         lockmod.release(tr, lock, wlock)
  1183 
  1185 
  1184     """print statistic about obsolescence markers in the repo"""
  1186     """print statistic about obsolescence markers in the repo"""
  1185     store = repo.obsstore
  1187     store = repo.obsstore
  1186     unfi = repo.unfiltered()
  1188     unfi = repo.unfiltered()
  1187     nm = unfi.changelog.nodemap
  1189     nm = unfi.changelog.nodemap
  1188     ui.write('markers total:              %9i\n' % len(store._all))
  1190     ui.write(_('markers total:              %9i\n') % len(store._all))
  1189     sucscount = [0, 0 , 0, 0]
  1191     sucscount = [0, 0 , 0, 0]
  1190     known = 0
  1192     known = 0
  1191     parentsdata = 0
  1193     parentsdata = 0
  1192     metakeys = {}
  1194     metakeys = {}
  1193     # node -> cluster mapping
  1195     # node -> cluster mapping
  1194     #   a cluster is a (set(nodes), set(markers)) tuple
  1196     #   a cluster is a (set(nodes), set(markers)) tuple
  1195     clustersmap = {}
  1197     clustersmap = {}
  1196     # same data using parent information
  1198     # same data using parent information
  1197     pclustersmap= {}
  1199     pclustersmap = {}
  1198     for mark in store:
  1200     for mark in store:
  1199         if mark[0] in nm:
  1201         if mark[0] in nm:
  1200             known += 1
  1202             known += 1
  1201         nbsucs = len(mark[1])
  1203         nbsucs = len(mark[1])
  1202         sucscount[min(nbsucs, 3)] += 1
  1204         sucscount[min(nbsucs, 3)] += 1
  1225     # same with parent data
  1227     # same with parent data
  1226     for c in pclustersmap.values():
  1228     for c in pclustersmap.values():
  1227         fc = (frozenset(c[0]), frozenset(c[1]))
  1229         fc = (frozenset(c[0]), frozenset(c[1]))
  1228         for n in fc[0]:
  1230         for n in fc[0]:
  1229             pclustersmap[n] = fc
  1231             pclustersmap[n] = fc
  1230     ui.write('    for known precursors:   %9i\n' % known)
  1232     ui.write(('    for known precursors:   %9i\n' % known))
  1231     ui.write('    with parents data:      %9i\n' % parentsdata)
  1233     ui.write(('    with parents data:      %9i\n' % parentsdata))
  1232     # successors data
  1234     # successors data
  1233     ui.write('markers with no successors: %9i\n' % sucscount[0])
  1235     ui.write(('markers with no successors: %9i\n' % sucscount[0]))
  1234     ui.write('              1 successors: %9i\n' % sucscount[1])
  1236     ui.write(('              1 successors: %9i\n' % sucscount[1]))
  1235     ui.write('              2 successors: %9i\n' % sucscount[2])
  1237     ui.write(('              2 successors: %9i\n' % sucscount[2]))
  1236     ui.write('    more than 2 successors: %9i\n' % sucscount[3])
  1238     ui.write(('    more than 2 successors: %9i\n' % sucscount[3]))
  1237     # meta data info
  1239     # meta data info
  1238     ui.write('    available  keys:\n')
  1240     ui.write(('    available  keys:\n'))
  1239     for key in sorted(metakeys):
  1241     for key in sorted(metakeys):
  1240         ui.write('    %15s:        %9i\n' % (key, metakeys[key]))
  1242         ui.write(('    %15s:        %9i\n' % (key, metakeys[key])))
  1241 
  1243 
  1242     allclusters = list(set(clustersmap.values()))
  1244     allclusters = list(set(clustersmap.values()))
  1243     allclusters.sort(key=lambda x: len(x[1]))
  1245     allclusters.sort(key=lambda x: len(x[1]))
  1244     ui.write('disconnected clusters:      %9i\n' % len(allclusters))
  1246     ui.write(('disconnected clusters:      %9i\n' % len(allclusters)))
  1245 
  1247 
  1246     ui.write('        any known node:     %9i\n'
  1248     ui.write('        any known node:     %9i\n'
  1247              % len([c for c in allclusters
  1249              % len([c for c in allclusters
  1248                     if [n for n in c[0] if nm.get(n) is not None]]))
  1250                     if [n for n in c[0] if nm.get(n) is not None]]))
  1249     if allclusters:
  1251     if allclusters:
  1250         nbcluster = len(allclusters)
  1252         nbcluster = len(allclusters)
  1251         ui.write('        smallest length:    %9i\n' % len(allclusters[0][1]))
  1253         ui.write(('        smallest length:    %9i\n' % len(allclusters[0][1])))
  1252         ui.write('        longer length:      %9i\n' % len(allclusters[-1][1]))
  1254         ui.write(('        longer length:      %9i\n'
       
  1255                  % len(allclusters[-1][1])))
  1253         median = len(allclusters[nbcluster//2][1])
  1256         median = len(allclusters[nbcluster//2][1])
  1254         ui.write('        median length:      %9i\n' % median)
  1257         ui.write(('        median length:      %9i\n' % median))
  1255         mean = sum(len(x[1]) for x in allclusters) // nbcluster
  1258         mean = sum(len(x[1]) for x in allclusters) // nbcluster
  1256         ui.write('        mean length:        %9i\n' % mean)
  1259         ui.write(('        mean length:        %9i\n' % mean))
  1257     allpclusters = list(set(pclustersmap.values()))
  1260     allpclusters = list(set(pclustersmap.values()))
  1258     allpclusters.sort(key=lambda x: len(x[1]))
  1261     allpclusters.sort(key=lambda x: len(x[1]))
  1259     ui.write('    using parents data:     %9i\n' % len(allpclusters))
  1262     ui.write(('    using parents data:     %9i\n' % len(allpclusters)))
  1260     ui.write('        any known node:     %9i\n'
  1263     ui.write('        any known node:     %9i\n'
  1261              % len([c for c in allclusters
  1264              % len([c for c in allclusters
  1262                     if [n for n in c[0] if nm.get(n) is not None]]))
  1265                     if [n for n in c[0] if nm.get(n) is not None]]))
  1263     if allpclusters:
  1266     if allpclusters:
  1264         nbcluster = len(allpclusters)
  1267         nbcluster = len(allpclusters)
  1265         ui.write('        smallest length:    %9i\n' % len(allpclusters[0][1]))
  1268         ui.write(('        smallest length:    %9i\n'
  1266         ui.write('        longer length:      %9i\n' % len(allpclusters[-1][1]))
  1269                  % len(allpclusters[0][1])))
       
  1270         ui.write(('        longer length:      %9i\n'
       
  1271                  % len(allpclusters[-1][1])))
  1267         median = len(allpclusters[nbcluster//2][1])
  1272         median = len(allpclusters[nbcluster//2][1])
  1268         ui.write('        median length:      %9i\n' % median)
  1273         ui.write(('        median length:      %9i\n' % median))
  1269         mean = sum(len(x[1]) for x in allpclusters) // nbcluster
  1274         mean = sum(len(x[1]) for x in allpclusters) // nbcluster
  1270         ui.write('        mean length:        %9i\n' % mean)
  1275         ui.write(('        mean length:        %9i\n' % mean))
  1271 
  1276 
  1272 def _solveone(ui, repo, ctx, dryrun, confirm, progresscb, category):
  1277 def _solveone(ui, repo, ctx, dryrun, confirm, progresscb, category):
  1273     """Resolve the troubles affecting one revision"""
  1278     """Resolve the troubles affecting one revision"""
  1274     wlock = lock = tr = None
  1279     wlock = lock = tr = None
  1275     try:
  1280     try:
  1364         if othertroubles:
  1369         if othertroubles:
  1365             hint = hintmap['+'.join(othertroubles)]
  1370             hint = hintmap['+'.join(othertroubles)]
  1366         else:
  1371         else:
  1367             l = len(troubled[targetcat])
  1372             l = len(troubled[targetcat])
  1368             if l:
  1373             if l:
  1369                 hint = (_("%d other %s in the repository, do you want --any or --rev")
  1374                 hint = _("%d other %s in the repository, do you want --any "
  1370                         % (l, targetcat))
  1375                         "or --rev") % (l, targetcat)
  1371             else:
  1376             else:
  1372                 othertroubles = []
  1377                 othertroubles = []
  1373                 for cat in unselectedcategories:
  1378                 for cat in unselectedcategories:
  1374                     if troubled[cat]:
  1379                     if troubled[cat]:
  1375                         othertroubles.append(cat)
  1380                         othertroubles.append(cat)
  1386     else:
  1391     else:
  1387         return 1
  1392         return 1
  1388 
  1393 
  1389 def _cleanup(ui, repo, startnode, showprogress):
  1394 def _cleanup(ui, repo, startnode, showprogress):
  1390     if showprogress:
  1395     if showprogress:
  1391         ui.progress('evolve', None)
  1396         ui.progress(_('evolve'), None)
  1392     if repo['.'] != startnode:
  1397     if repo['.'] != startnode:
  1393         ui.status(_('working directory is now at %s\n') % repo['.'])
  1398         ui.status(_('working directory is now at %s\n') % repo['.'])
  1394 
  1399 
  1395 class MultipleSuccessorsError(RuntimeError):
  1400 class MultipleSuccessorsError(RuntimeError):
  1396     """Exception raised by _singlesuccessor when multiple sucessors sets exists
  1401     """Exception raised by _singlesuccessor when multiple sucessors sets exists
  1439     for r in revs:
  1444     for r in revs:
  1440         dependencies[r] = set()
  1445         dependencies[r] = set()
  1441         for p in repo[r].parents():
  1446         for p in repo[r].parents():
  1442             try:
  1447             try:
  1443                 succ = _singlesuccessor(repo, p)
  1448                 succ = _singlesuccessor(repo, p)
  1444             except MultipleSuccessorsError, exc:
  1449             except MultipleSuccessorsError as exc:
  1445                 dependencies[r] = exc.successorssets
  1450                 dependencies[r] = exc.successorssets
  1446                 continue
  1451                 continue
  1447             if succ in revs:
  1452             if succ in revs:
  1448                 dependencies[r].add(succ)
  1453                 dependencies[r].add(succ)
  1449                 rdependencies[succ].add(r)
  1454                 rdependencies[succ].add(r)
  1473     if allopt or revopt:
  1478     if allopt or revopt:
  1474         revs = repo.revs(targetcat+'()')
  1479         revs = repo.revs(targetcat+'()')
  1475         if revopt:
  1480         if revopt:
  1476             revs = scmutil.revrange(repo, revopt) & revs
  1481             revs = scmutil.revrange(repo, revopt) & revs
  1477         elif not anyopt and targetcat == 'unstable':
  1482         elif not anyopt and targetcat == 'unstable':
  1478             revs = set(_aspiringdescendant(repo, repo.revs('(.::) - obsolete()::')))
  1483             revs = set(_aspiringdescendant(repo,
       
  1484                                            repo.revs('(.::) - obsolete()::')))
  1479         if targetcat == 'divergent':
  1485         if targetcat == 'divergent':
  1480             # Pick one divergent per group of divergents
  1486             # Pick one divergent per group of divergents
  1481             revs = _dedupedivergents(repo, revs)
  1487             revs = _dedupedivergents(repo, revs)
  1482     elif anyopt:
  1488     elif anyopt:
  1483         revs = repo.revs('first(%s())' % (targetcat))
  1489         revs = repo.revs('first(%s())' % (targetcat))
  1531 @command('^evolve|stabilize|solve',
  1537 @command('^evolve|stabilize|solve',
  1532     [('n', 'dry-run', False,
  1538     [('n', 'dry-run', False,
  1533         _('do not perform actions, just print what would be done')),
  1539         _('do not perform actions, just print what would be done')),
  1534      ('', 'confirm', False,
  1540      ('', 'confirm', False,
  1535         _('ask for confirmation before performing the action')),
  1541         _('ask for confirmation before performing the action')),
  1536     ('A', 'any', False, _('also consider troubled changesets unrelated to current working directory')),
  1542     ('A', 'any', False,
       
  1543         _('also consider troubled changesets unrelated to current working '
       
  1544           'directory')),
  1537     ('r', 'rev', [], _('solves troubles of these revisions')),
  1545     ('r', 'rev', [], _('solves troubles of these revisions')),
  1538     ('', 'bumped', False, _('solves only bumped changesets')),
  1546     ('', 'bumped', False, _('solves only bumped changesets')),
  1539     ('', 'divergent', False, _('solves only divergent changesets')),
  1547     ('', 'divergent', False, _('solves only divergent changesets')),
  1540     ('', 'unstable', False, _('solves only unstable changesets (default)')),
  1548     ('', 'unstable', False, _('solves only unstable changesets (default)')),
  1541     ('a', 'all', False, _('evolve all troubled changesets related to the current '
  1549     ('a', 'all', False, _('evolve all troubled changesets related to the '
  1542                          'working directory and its descendants')),
  1550                           'current  working directory and its descendants')),
  1543     ('c', 'continue', False, _('continue an interrupted evolution')),
  1551     ('c', 'continue', False, _('continue an interrupted evolution')),
  1544     ] + mergetoolopts,
  1552     ] + mergetoolopts,
  1545     _('[OPTIONS]...'))
  1553     _('[OPTIONS]...'))
  1546 def evolve(ui, repo, **opts):
  1554 def evolve(ui, repo, **opts):
  1547     """solve troubled changesets in your repository
  1555     """solve troubled changesets in your repository
  1548 
  1556 
  1549     Modifying history can lead to various types of troubled changesets: unstable,
  1557     Modifying history can lead to various types of troubled changesets:
  1550     bumped, or divergent. The evolve command resolves your troubles by executing one
  1558     unstable, bumped, or divergent. The evolve command resolves your troubles
  1551     of the following actions:
  1559     by executing one of the following actions:
  1552 
  1560 
  1553     - update working copy to a successor
  1561     - update working copy to a successor
  1554     - rebase an unstable changeset
  1562     - rebase an unstable changeset
  1555     - extract the desired changes from a bumped changeset
  1563     - extract the desired changes from a bumped changeset
  1556     - fuse divergent changesets back together
  1564     - fuse divergent changesets back together
  1557 
  1565 
  1558     If you pass no arguments, evolve works in automatic mode: it will execute a
  1566     If you pass no arguments, evolve works in automatic mode: it will execute a
  1559     single action to reduce instability related to your working copy. There are two
  1567     single action to reduce instability related to your working copy. There are
  1560     cases for this action. First, if the parent of your working copy is obsolete,
  1568     two cases for this action. First, if the parent of your working copy is
  1561     evolve updates to the parent's successor. Second, if the working copy parent is
  1569     obsolete, evolve updates to the parent's successor. Second, if the working
  1562     not obsolete but has obsolete predecessors, then evolve determines if there is an
  1570     copy parent is not obsolete but has obsolete predecessors, then evolve
  1563     unstable changeset that can be rebased onto the working copy parent in order to
  1571     determines if there is an unstable changeset that can be rebased onto the
  1564     reduce instability. If so, evolve rebases that changeset. If not, evolve refuses
  1572     working copy parent in order to reduce instability.
  1565     to guess your intention, and gives a hint about what you might want to do next.
  1573     If so, evolve rebases that changeset. If not, evolve refuses to guess your
       
  1574     intention, and gives a hint about what you might want to do next.
  1566 
  1575 
  1567     Any time evolve creates a changeset, it updates the working copy to the new
  1576     Any time evolve creates a changeset, it updates the working copy to the new
  1568     changeset. (Currently, every successful evolve operation involves an update as
  1577     changeset. (Currently, every successful evolve operation involves an update
  1569     well; this may change in future.)
  1578     as well; this may change in future.)
  1570 
  1579 
  1571     Automatic mode only handles common use cases. For example, it avoids taking
  1580     Automatic mode only handles common use cases. For example, it avoids taking
  1572     action in the case of ambiguity, and it ignores unstable changesets that are not
  1581     action in the case of ambiguity, and it ignores unstable changesets that
  1573     related to your working copy. It also refuses to solve bumped or divergent
  1582     are not related to your working copy.
  1574     changesets unless you explicity request such behavior (see below).
  1583     It also refuses to solve bumped or divergent changesets unless you explicity
       
  1584     request such behavior (see below).
  1575 
  1585 
  1576     Eliminating all instability around your working copy may require multiple
  1586     Eliminating all instability around your working copy may require multiple
  1577     invocations of :hg:`evolve`. Alternately, use ``--all`` to recursively select and
  1587     invocations of :hg:`evolve`. Alternately, use ``--all`` to recursively
  1578     evolve all unstable changesets that can be rebased onto the working copy parent.
  1588     select and evolve all unstable changesets that can be rebased onto the
       
  1589     working copy parent.
  1579     This is more powerful than successive invocations, since ``--all`` handles
  1590     This is more powerful than successive invocations, since ``--all`` handles
  1580     ambiguous cases (e.g. unstable changesets with multiple children) by evolving all
  1591     ambiguous cases (e.g. unstable changesets with multiple children) by
  1581     branches.
  1592     evolving all branches.
  1582 
  1593 
  1583     When your repository cannot be handled by automatic mode, you might need to use
  1594     When your repository cannot be handled by automatic mode, you might need to
  1584     ``--rev`` to specify a changeset to evolve. For example, if you have an unstable
  1595     use ``--rev`` to specify a changeset to evolve. For example, if you have
  1585     changeset that is not related to the working copy parent, you could use ``--rev``
  1596     an unstable changeset that is not related to the working copy parent,
  1586     to evolve it. Or, if some changeset has multiple unstable children, evolve in
  1597     you could use ``--rev`` to evolve it. Or, if some changeset has multiple
  1587     automatic mode refuses to guess which one to evolve; you have to use ``--rev``
  1598     unstable children, evolve in automatic mode refuses to guess which one to
  1588     in that case.
  1599     evolve; you have to use ``--rev`` in that case.
  1589 
  1600 
  1590     Alternately, ``--any`` makes evolve search for the next evolvable changeset
  1601     Alternately, ``--any`` makes evolve search for the next evolvable changeset
  1591     regardless of whether it is related to the working copy parent.
  1602     regardless of whether it is related to the working copy parent.
  1592 
  1603 
  1593     You can supply multiple revisions to evolve multiple troubled changesets in a
  1604     You can supply multiple revisions to evolve multiple troubled changesets
  1594     single invocation. In revset terms, ``--any`` is equivalent to ``--rev
  1605     in a single invocation. In revset terms, ``--any`` is equivalent to ``--rev
  1595     first(unstable())``. ``--rev`` and ``--all`` are mutually exclusive, as are
  1606     first(unstable())``. ``--rev`` and ``--all`` are mutually exclusive, as are
  1596     ``--rev`` and ``--any``.
  1607     ``--rev`` and ``--any``.
  1597 
  1608 
  1598     ``hg evolve --any --all`` is useful for cleaning up instability across all
  1609     ``hg evolve --any --all`` is useful for cleaning up instability across all
  1599     branches, letting evolve figure out the appropriate order and destination.
  1610     branches, letting evolve figure out the appropriate order and destination.
  1600 
  1611 
  1601     When you have troubled changesets that are not unstable, :hg:`evolve` refuses to
  1612     When you have troubled changesets that are not unstable, :hg:`evolve`
  1602     consider them unless you specify the category of trouble you wish to resolve,
  1613     refuses to consider them unless you specify the category of trouble you
  1603     with ``--bumped`` or ``--divergent``. These options are currently mutually
  1614     wish to resolve, with ``--bumped`` or ``--divergent``. These options are
  1604     exclusive with each other and with ``--unstable`` (the default). You can combine
  1615     currently mutually exclusive with each other and with ``--unstable``
  1605     ``--bumped`` or ``--divergent`` with ``--rev``, ``--all``, or ``--any``.
  1616     (the default). You can combine ``--bumped`` or ``--divergent`` with
       
  1617     ``--rev``, ``--all``, or ``--any``.
  1606 
  1618 
  1607     """
  1619     """
  1608 
  1620 
  1609     # Options
  1621     # Options
  1610     contopt = opts['continue']
  1622     contopt = opts['continue']
  1617     troublecategories = ['bumped', 'divergent', 'unstable']
  1629     troublecategories = ['bumped', 'divergent', 'unstable']
  1618     specifiedcategories = [t for t in troublecategories if opts[t]]
  1630     specifiedcategories = [t for t in troublecategories if opts[t]]
  1619     targetcat = 'unstable'
  1631     targetcat = 'unstable'
  1620     if 1 < len(specifiedcategories):
  1632     if 1 < len(specifiedcategories):
  1621         msg = _('cannot specify more than one trouble category to solve (yet)')
  1633         msg = _('cannot specify more than one trouble category to solve (yet)')
  1622         raise util.Abort(msg)
  1634         raise error.Abort(msg)
  1623     elif len(specifiedcategories) == 1:
  1635     elif len(specifiedcategories) == 1:
  1624         targetcat = specifiedcategories[0]
  1636         targetcat = specifiedcategories[0]
  1625     elif repo['.'].obsolete():
  1637     elif repo['.'].obsolete():
  1626         displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  1638         displayer = cmdutil.show_changeset(ui, repo,
       
  1639                                            {'template': shorttemplate})
  1627         # no args and parent is obsolete, update to successors
  1640         # no args and parent is obsolete, update to successors
  1628         try:
  1641         try:
  1629             ctx = repo[_singlesuccessor(repo, repo['.'])]
  1642             ctx = repo[_singlesuccessor(repo, repo['.'])]
  1630         except MultipleSuccessorsError, exc:
  1643         except MultipleSuccessorsError as exc:
  1631             repo.ui.write_err('parent is obsolete with multiple successors:\n')
  1644             repo.ui.write_err('parent is obsolete with multiple successors:\n')
  1632             for ln in exc.successorssets:
  1645             for ln in exc.successorssets:
  1633                 for n in ln:
  1646                 for n in ln:
  1634                     displayer.show(repo[n])
  1647                     displayer.show(repo[n])
  1635             return 2
  1648             return 2
  1654     count = allopt and len(troubled) or 1
  1667     count = allopt and len(troubled) or 1
  1655     showprogress = allopt
  1668     showprogress = allopt
  1656 
  1669 
  1657     def progresscb():
  1670     def progresscb():
  1658         if revopt or allopt:
  1671         if revopt or allopt:
  1659             ui.progress('evolve', seen, unit='changesets', total=count)
  1672             ui.progress(_('evolve'), seen, unit='changesets', total=count)
  1660 
  1673 
  1661     # Continuation handling
  1674     # Continuation handling
  1662     if contopt:
  1675     if contopt:
  1663         if anyopt:
  1676         if anyopt:
  1664             raise util.Abort('cannot specify both "--any" and "--continue"')
  1677             raise error.Abort('cannot specify both "--any" and "--continue"')
  1665         if allopt:
  1678         if allopt:
  1666             raise util.Abort('cannot specify both "--all" and "--continue"')
  1679             raise error.Abort('cannot specify both "--all" and "--continue"')
  1667         graftcmd = commands.table['graft'][0]
  1680         graftcmd = commands.table['graft'][0]
  1668         return graftcmd(ui, repo, old_obsolete=True, **{'continue': True})
  1681         return graftcmd(ui, repo, old_obsolete=True, **{'continue': True})
  1669     cmdutil.bailifchanged(repo)
  1682     cmdutil.bailifchanged(repo)
  1670 
  1683 
  1671 
  1684 
  1672     if revopt and allopt:
  1685     if revopt and allopt:
  1673         raise util.Abort('cannot specify both "--rev" and "--all"')
  1686         raise error.Abort('cannot specify both "--rev" and "--all"')
  1674     if revopt and anyopt:
  1687     if revopt and anyopt:
  1675         raise util.Abort('cannot specify both "--rev" and "--any"')
  1688         raise error.Abort('cannot specify both "--rev" and "--any"')
  1676 
  1689 
  1677     revs = _selectrevs(repo, allopt, revopt, anyopt, targetcat)
  1690     revs = _selectrevs(repo, allopt, revopt, anyopt, targetcat)
  1678 
  1691 
  1679     if not revs:
  1692     if not revs:
  1680         return _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat)
  1693         return _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat)
  1751     obs = orig.parents()[0]
  1764     obs = orig.parents()[0]
  1752     if not obs.obsolete() and len(orig.parents()) == 2:
  1765     if not obs.obsolete() and len(orig.parents()) == 2:
  1753         obs = orig.parents()[1] # second parent is obsolete ?
  1766         obs = orig.parents()[1] # second parent is obsolete ?
  1754 
  1767 
  1755     if not obs.obsolete():
  1768     if not obs.obsolete():
  1756         ui.warn("cannot solve instability of %s, skipping\n" % orig)
  1769         ui.warn(_("cannot solve instability of %s, skipping\n") % orig)
  1757         return False
  1770         return False
  1758     newer = obsolete.successorssets(repo, obs.node())
  1771     newer = obsolete.successorssets(repo, obs.node())
  1759     # search of a parent which is not killed
  1772     # search of a parent which is not killed
  1760     while not newer or newer == [()]:
  1773     while not newer or newer == [()]:
  1761         ui.debug("stabilize target %s is plain dead,"
  1774         ui.debug("stabilize target %s is plain dead,"
  1762                  " trying to stabilize on its parent\n" %
  1775                  " trying to stabilize on its parent\n" %
  1763                  obs)
  1776                  obs)
  1764         obs = obs.parents()[0]
  1777         obs = obs.parents()[0]
  1765         newer = obsolete.successorssets(repo, obs.node())
  1778         newer = obsolete.successorssets(repo, obs.node())
  1766     if len(newer) > 1:
  1779     if len(newer) > 1:
  1767         msg = _("skipping %s: divergent rewriting. can't choose destination\n") % obs
  1780         msg = _("skipping %s: divergent rewriting. can't choose "
       
  1781                 "destination\n") % obs
  1768         ui.write_err(msg)
  1782         ui.write_err(msg)
  1769         return 2
  1783         return 2
  1770     targets = newer[0]
  1784     targets = newer[0]
  1771     assert targets
  1785     assert targets
  1772     if len(targets) > 1:
  1786     if len(targets) > 1:
  1787         repo.ui.write(_('move:'))
  1801         repo.ui.write(_('move:'))
  1788         displayer.show(orig)
  1802         displayer.show(orig)
  1789         repo.ui.write(_('atop:'))
  1803         repo.ui.write(_('atop:'))
  1790         displayer.show(target)
  1804         displayer.show(target)
  1791     if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y':
  1805     if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y':
  1792             raise util.Abort(_('evolve aborted by user'))
  1806             raise error.Abort(_('evolve aborted by user'))
  1793     if progresscb: progresscb()
  1807     if progresscb: progresscb()
  1794     todo = 'hg rebase -r %s -d %s\n' % (orig, target)
  1808     todo = 'hg rebase -r %s -d %s\n' % (orig, target)
  1795     if dryrun:
  1809     if dryrun:
  1796         repo.ui.write(todo)
  1810         repo.ui.write(todo)
  1797     else:
  1811     else:
  1819         ui.write_err(msg)
  1833         ui.write_err(msg)
  1820         return 2
  1834         return 2
  1821     prec = repo.set('last(allprecursors(%d) and public())', bumped).next()
  1835     prec = repo.set('last(allprecursors(%d) and public())', bumped).next()
  1822     # For now we deny target merge
  1836     # For now we deny target merge
  1823     if len(prec.parents()) > 1:
  1837     if len(prec.parents()) > 1:
  1824         msg = _('skipping: %s: public version is a merge, this not handled yet\n') % prec
  1838         msg = _('skipping: %s: public version is a merge, '
       
  1839                 'this is not handled yet\n') % prec
  1825         ui.write_err(msg)
  1840         ui.write_err(msg)
  1826         return 2
  1841         return 2
  1827 
  1842 
  1828     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  1843     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  1829     if not ui.quiet or confirm:
  1844     if not ui.quiet or confirm:
  1830         repo.ui.write(_('recreate:'))
  1845         repo.ui.write(_('recreate:'))
  1831         displayer.show(bumped)
  1846         displayer.show(bumped)
  1832         repo.ui.write(_('atop:'))
  1847         repo.ui.write(_('atop:'))
  1833         displayer.show(prec)
  1848         displayer.show(prec)
  1834     if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y':
  1849     if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y':
  1835         raise util.Abort(_('evolve aborted by user'))
  1850         raise error.Abort(_('evolve aborted by user'))
  1836     if dryrun:
  1851     if dryrun:
  1837         todo = 'hg rebase --rev %s --dest %s;\n' % (bumped, prec.p1())
  1852         todo = 'hg rebase --rev %s --dest %s;\n' % (bumped, prec.p1())
  1838         repo.ui.write(todo)
  1853         repo.ui.write(todo)
  1839         repo.ui.write('hg update %s;\n' % prec)
  1854         repo.ui.write(('hg update %s;\n' % prec))
  1840         repo.ui.write('hg revert --all --rev %s;\n' % bumped)
  1855         repo.ui.write(('hg revert --all --rev %s;\n' % bumped))
  1841         repo.ui.write('hg commit --msg "bumped update to %s"')
  1856         repo.ui.write(('hg commit --msg "bumped update to %s"'))
  1842         return 0
  1857         return 0
  1843     if progresscb: progresscb()
  1858     if progresscb: progresscb()
  1844     newid = tmpctx = None
  1859     newid = tmpctx = None
  1845     tmpctx = bumped
  1860     tmpctx = bumped
  1846     # Basic check for common parent. Far too complicated and fragile
  1861     # Basic check for common parent. Far too complicated and fragile
  1924     repo = repo.unfiltered()
  1939     repo = repo.unfiltered()
  1925     divergent = repo[divergent.rev()]
  1940     divergent = repo[divergent.rev()]
  1926     base, others = divergentdata(divergent)
  1941     base, others = divergentdata(divergent)
  1927     if len(others) > 1:
  1942     if len(others) > 1:
  1928         othersstr = "[%s]" % (','.join([str(i) for i in others]))
  1943         othersstr = "[%s]" % (','.join([str(i) for i in others]))
  1929         msg = _("skipping %d:divergent with a changeset that got splitted into multiple ones:\n"
  1944         msg = _("skipping %d:divergent with a changeset that got splitted"
       
  1945                 " into multiple ones:\n"
  1930                  "|[%s]\n"
  1946                  "|[%s]\n"
  1931                  "| This is not handled by automatic evolution yet\n"
  1947                  "| This is not handled by automatic evolution yet\n"
  1932                  "| You have to fallback to manual handling with commands "
  1948                  "| You have to fallback to manual handling with commands "
  1933                  "such as:\n"
  1949                  "such as:\n"
  1934                  "| - hg touch -D\n"
  1950                  "| - hg touch -D\n"
  1935                  "| - hg prune\n"
  1951                  "| - hg prune\n"
  1936                  "| \n"
  1952                  "| \n"
  1937                  "| You should contact your local evolution Guru for help.\n"
  1953                  "| You should contact your local evolution Guru for help.\n"
  1938                  % (divergent, othersstr))
  1954                  ) % (divergent, othersstr)
  1939         ui.write_err(msg)
  1955         ui.write_err(msg)
  1940         return 2
  1956         return 2
  1941     other = others[0]
  1957     other = others[0]
  1942     if len(other.parents()) > 1:
  1958     if len(other.parents()) > 1:
  1943         msg = _("skipping %s: divergent changeset can't be a merge (yet)\n" % divergent)
  1959         msg = _("skipping %s: divergent changeset can't be "
       
  1960                 "a merge (yet)\n") % divergent
  1944         ui.write_err(msg)
  1961         ui.write_err(msg)
  1945         hint = _("You have to fallback to solving this by hand...\n"
  1962         hint = _("You have to fallback to solving this by hand...\n"
  1946                  "| This probably means redoing the merge and using \n"
  1963                  "| This probably means redoing the merge and using \n"
  1947                  "| `hg prune` to kill older version.\n")
  1964                  "| `hg prune` to kill older version.\n")
  1948         ui.write_err(hint)
  1965         ui.write_err(hint)
  1949         return 2
  1966         return 2
  1950     if other.p1() not in divergent.parents():
  1967     if other.p1() not in divergent.parents():
  1951         msg = _("skipping %s: have a different parent than %s (not handled yet)\n") % (divergent, other)
  1968         msg = _("skipping %s: have a different parent than %s "
       
  1969                 "(not handled yet)\n") % (divergent, other)
  1952         hint = _("| %(d)s, %(o)s are not based on the same changeset.\n"
  1970         hint = _("| %(d)s, %(o)s are not based on the same changeset.\n"
  1953                  "| With the current state of its implementation, \n"
  1971                  "| With the current state of its implementation, \n"
  1954                  "| evolve does not work in that case.\n"
  1972                  "| evolve does not work in that case.\n"
  1955                  "| rebase one of them next to the other and run \n"
  1973                  "| rebase one of them next to the other and run \n"
  1956                  "| this command again.\n"
  1974                  "| this command again.\n"
  1957                  "| - either: hg rebase --dest 'p1(%(d)s)' -r %(o)s\n"
  1975                  "| - either: hg rebase --dest 'p1(%(d)s)' -r %(o)s\n"
  1958                  "| - or:     hg rebase --dest 'p1(%(o)s)' -r %(d)s\n"
  1976                  "| - or:     hg rebase --dest 'p1(%(o)s)' -r %(d)s\n"
  1959                  % {'d': divergent, 'o': other})
  1977                  ) % {'d': divergent, 'o': other}
  1960         ui.write_err(msg)
  1978         ui.write_err(msg)
  1961         ui.write_err(hint)
  1979         ui.write_err(hint)
  1962         return 2
  1980         return 2
  1963 
  1981 
  1964     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  1982     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  1968         ui.write(_('with: '))
  1986         ui.write(_('with: '))
  1969         displayer.show(other)
  1987         displayer.show(other)
  1970         ui.write(_('base: '))
  1988         ui.write(_('base: '))
  1971         displayer.show(base)
  1989         displayer.show(base)
  1972     if confirm and ui.prompt(_('perform evolve? [Ny]'), 'n') != 'y':
  1990     if confirm and ui.prompt(_('perform evolve? [Ny]'), 'n') != 'y':
  1973         raise util.Abort(_('evolve aborted by user'))
  1991         raise error.Abort(_('evolve aborted by user'))
  1974     if dryrun:
  1992     if dryrun:
  1975         ui.write('hg update -c %s &&\n' % divergent)
  1993         ui.write(('hg update -c %s &&\n' % divergent))
  1976         ui.write('hg merge %s &&\n' % other)
  1994         ui.write(('hg merge %s &&\n' % other))
  1977         ui.write('hg commit -m "auto merge resolving conflict between '
  1995         ui.write(('hg commit -m "auto merge resolving conflict between '
  1978                  '%s and %s"&&\n' % (divergent, other))
  1996                  '%s and %s"&&\n' % (divergent, other)))
  1979         ui.write('hg up -C %s &&\n' % base)
  1997         ui.write(('hg up -C %s &&\n' % base))
  1980         ui.write('hg revert --all --rev tip &&\n')
  1998         ui.write(('hg revert --all --rev tip &&\n'))
  1981         ui.write('hg commit -m "`hg log -r %s --template={desc}`";\n'
  1999         ui.write(('hg commit -m "`hg log -r %s --template={desc}`";\n'
  1982                  % divergent)
  2000                  % divergent))
  1983         return
  2001         return
  1984     if divergent not in repo[None].parents():
  2002     if divergent not in repo[None].parents():
  1985         repo.ui.status(_('updating to "local" conflict\n'))
  2003         repo.ui.status(_('updating to "local" conflict\n'))
  1986         hg.update(repo, divergent.rev())
  2004         hg.update(repo, divergent.rev())
  1987     repo.ui.note(_('merging divergent changeset\n'))
  2005     repo.ui.note(_('merging divergent changeset\n'))
  1996     hg._showstats(repo, stats)
  2014     hg._showstats(repo, stats)
  1997     if stats[3]:
  2015     if stats[3]:
  1998         repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
  2016         repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
  1999                          "or 'hg update -C .' to abandon\n"))
  2017                          "or 'hg update -C .' to abandon\n"))
  2000     if stats[3] > 0:
  2018     if stats[3] > 0:
  2001         raise util.Abort('merge conflict between several amendments '
  2019         raise error.Abort('merge conflict between several amendments '
  2002             '(this is not automated yet)',
  2020             '(this is not automated yet)',
  2003             hint="""/!\ You can try:
  2021             hint="""/!\ You can try:
  2004 /!\ * manual merge + resolve => new cset X
  2022 /!\ * manual merge + resolve => new cset X
  2005 /!\ * hg up to the parent of the amended changeset (which are named W and Z)
  2023 /!\ * hg up to the parent of the amended changeset (which are named W and Z)
  2006 /!\ * hg revert --all -r X
  2024 /!\ * hg revert --all -r X
  2041         newer = obsolete.successorssets(ctx._repo, base.node())
  2059         newer = obsolete.successorssets(ctx._repo, base.node())
  2042         # drop filter and solution including the original ctx
  2060         # drop filter and solution including the original ctx
  2043         newer = [n for n in newer if n and ctx.node() not in n]
  2061         newer = [n for n in newer if n and ctx.node() not in n]
  2044         if newer:
  2062         if newer:
  2045             return base, tuple(ctx._repo[o] for o in newer[0])
  2063             return base, tuple(ctx._repo[o] for o in newer[0])
  2046     raise util.Abort("base of divergent changeset %s not found" % ctx,
  2064     raise error.Abort("base of divergent changeset %s not found" % ctx,
  2047                      hint='this case is not yet handled')
  2065                      hint='this case is not yet handled')
  2048 
  2066 
  2049 
  2067 
  2050 
  2068 
  2051 shorttemplate = '[{rev}] {desc|firstline}\n'
  2069 shorttemplate = '[{rev}] {desc|firstline}\n'
  2052 
  2070 
  2053 @command('^previous',
  2071 @command('^previous',
  2054          [('B', 'move-bookmark', False,
  2072          [('B', 'move-bookmark', False,
  2055              _('move active bookmark after update')),
  2073              _('move active bookmark after update')),
  2056           ('', 'merge', False, _('bring uncommitted change along')),
  2074           ('', 'merge', False, _('bring uncommitted change along')),
  2057           ('n', 'dry-run', False, _('do not perform actions, just print what would be done'))],
  2075           ('n', 'dry-run', False,
       
  2076              _('do not perform actions, just print what would be done'))],
  2058          '[OPTION]...')
  2077          '[OPTION]...')
  2059 def cmdprevious(ui, repo, **opts):
  2078 def cmdprevious(ui, repo, **opts):
  2060     """update to parent and display summary lines"""
  2079     """update to parent and display summary lines"""
  2061     wkctx = repo[None]
  2080     wkctx = repo[None]
  2062     wparents = wkctx.parents()
  2081     wparents = wkctx.parents()
  2063     dryrunopt = opts['dry_run']
  2082     dryrunopt = opts['dry_run']
  2064     if len(wparents) != 1:
  2083     if len(wparents) != 1:
  2065         raise util.Abort('merge in progress')
  2084         raise error.Abort('merge in progress')
  2066     if not opts['merge']:
  2085     if not opts['merge']:
  2067         try:
  2086         try:
  2068             cmdutil.bailifchanged(repo)
  2087             cmdutil.bailifchanged(repo)
  2069         except error.Abort, exc:
  2088         except error.Abort as exc:
  2070             exc.hint = _('do you want --merge?')
  2089             exc.hint = _('do you want --merge?')
  2071             raise
  2090             raise
  2072 
  2091 
  2073     parents = wparents[0].parents()
  2092     parents = wparents[0].parents()
  2074     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  2093     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  2075     if len(parents) == 1:
  2094     if len(parents) == 1:
  2076         p = parents[0]
  2095         p = parents[0]
  2077         bm = bmactive(repo)
  2096         bm = bmactive(repo)
  2078         shouldmove = opts.get('move_bookmark') and bm is not None
  2097         shouldmove = opts.get('move_bookmark') and bm is not None
  2079         if dryrunopt:
  2098         if dryrunopt:
  2080             ui.write('hg update %s;\n' % p.rev())
  2099             ui.write(('hg update %s;\n' % p.rev()))
  2081             if shouldmove:
  2100             if shouldmove:
  2082                 ui.write('hg bookmark %s -r %s;\n' % (bm, p.rev()))
  2101                 ui.write(('hg bookmark %s -r %s;\n' % (bm, p.rev())))
  2083         else:
  2102         else:
  2084             ret = hg.update(repo, p.rev())
  2103             ret = hg.update(repo, p.rev())
  2085             if not ret:
  2104             if not ret:
  2086                 wlock = repo.wlock()
  2105                 wlock = repo.wlock()
  2087                 try:
  2106                 try:
  2103 @command('^next',
  2122 @command('^next',
  2104          [('B', 'move-bookmark', False,
  2123          [('B', 'move-bookmark', False,
  2105              _('move active bookmark after update')),
  2124              _('move active bookmark after update')),
  2106           ('', 'merge', False, _('bring uncommitted change along')),
  2125           ('', 'merge', False, _('bring uncommitted change along')),
  2107           ('', 'evolve', False, _('evolve the next changeset if necessary')),
  2126           ('', 'evolve', False, _('evolve the next changeset if necessary')),
  2108           ('n', 'dry-run', False, _('do not perform actions, just print what would be done'))],
  2127           ('n', 'dry-run', False,
  2109          '[OPTION]...')
  2128               _('do not perform actions, just print what would be done'))],
       
  2129               '[OPTION]...')
  2110 def cmdnext(ui, repo, **opts):
  2130 def cmdnext(ui, repo, **opts):
  2111     """update to next child
  2131     """update to next child
  2112 
  2132 
  2113     You can use the --evolve flag to get unstable children evolved on demand.
  2133     You can use the --evolve flag to get unstable children evolved on demand.
  2114 
  2134 
  2115     The summary line of the destination is displayed for clarity"""
  2135     The summary line of the destination is displayed for clarity"""
  2116     wkctx = repo[None]
  2136     wkctx = repo[None]
  2117     wparents = wkctx.parents()
  2137     wparents = wkctx.parents()
  2118     dryrunopt = opts['dry_run']
  2138     dryrunopt = opts['dry_run']
  2119     if len(wparents) != 1:
  2139     if len(wparents) != 1:
  2120         raise util.Abort('merge in progress')
  2140         raise error.Abort('merge in progress')
  2121     if not opts['merge']:
  2141     if not opts['merge']:
  2122         try:
  2142         try:
  2123             cmdutil.bailifchanged(repo)
  2143             cmdutil.bailifchanged(repo)
  2124         except error.Abort, exc:
  2144         except error.Abort as exc:
  2125             exc.hint = _('do you want --merge?')
  2145             exc.hint = _('do you want --merge?')
  2126             raise
  2146             raise
  2127 
  2147 
  2128     children = [ctx for ctx in wparents[0].children() if not ctx.obsolete()]
  2148     children = [ctx for ctx in wparents[0].children() if not ctx.obsolete()]
  2129     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  2149     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  2130     if len(children) == 1:
  2150     if len(children) == 1:
  2131         c = children[0]
  2151         c = children[0]
  2132         bm = bmactive(repo)
  2152         bm = bmactive(repo)
  2133         shouldmove = opts.get('move_bookmark') and bm is not None
  2153         shouldmove = opts.get('move_bookmark') and bm is not None
  2134         if dryrunopt:
  2154         if dryrunopt:
  2135             ui.write('hg update %s;\n' % c.rev())
  2155             ui.write(('hg update %s;\n' % c.rev()))
  2136             if shouldmove:
  2156             if shouldmove:
  2137                 ui.write('hg bookmark %s -r %s;\n' % (bm, c.rev()))
  2157                 ui.write(('hg bookmark %s -r %s;\n' % (bm, c.rev())))
  2138         else:
  2158         else:
  2139             ret = hg.update(repo, c.rev())
  2159             ret = hg.update(repo, c.rev())
  2140             if not ret:
  2160             if not ret:
  2141                 wlock = repo.wlock()
  2161                 wlock = repo.wlock()
  2142                 try:
  2162                 try:
  2148                 finally:
  2168                 finally:
  2149                     wlock.release()
  2169                     wlock.release()
  2150         displayer.show(c)
  2170         displayer.show(c)
  2151         result = 0
  2171         result = 0
  2152     elif children:
  2172     elif children:
  2153         ui.warn("ambigious next changeset:\n")
  2173         ui.warn(_("ambigious next changeset:\n"))
  2154         for c in children:
  2174         for c in children:
  2155             displayer.show(c)
  2175             displayer.show(c)
  2156         ui.warn(_('explicitly update to one of them\n'))
  2176         ui.warn(_('explicitly update to one of them\n'))
  2157         result = 1
  2177         result = 1
  2158     else:
  2178     else:
  2184     """filter revisions and bookmarks reachable from the given bookmark
  2204     """filter revisions and bookmarks reachable from the given bookmark
  2185     yoinked from mq.py
  2205     yoinked from mq.py
  2186     """
  2206     """
  2187     marks = repo._bookmarks
  2207     marks = repo._bookmarks
  2188     if mark not in marks:
  2208     if mark not in marks:
  2189         raise util.Abort(_("bookmark '%s' not found") % mark)
  2209         raise error.Abort(_("bookmark '%s' not found") % mark)
  2190 
  2210 
  2191     # If the requested bookmark is not the only one pointing to a
  2211     # If the requested bookmark is not the only one pointing to a
  2192     # a revision we have to only delete the bookmark and not strip
  2212     # a revision we have to only delete the bookmark and not strip
  2193     # anything. revsets cannot detect that case.
  2213     # anything. revsets cannot detect that case.
  2194     uniquebm = True
  2214     uniquebm = True
  2240     [('n', 'new', [], _("successor changeset (DEPRECATED)")),
  2260     [('n', 'new', [], _("successor changeset (DEPRECATED)")),
  2241      ('s', 'succ', [], _("successor changeset")),
  2261      ('s', 'succ', [], _("successor changeset")),
  2242      ('r', 'rev', [], _("revisions to prune")),
  2262      ('r', 'rev', [], _("revisions to prune")),
  2243      ('k', 'keep', None, _("does not modify working copy during prune")),
  2263      ('k', 'keep', None, _("does not modify working copy during prune")),
  2244      ('', 'biject', False, _("do a 1-1 map between rev and successor ranges")),
  2264      ('', 'biject', False, _("do a 1-1 map between rev and successor ranges")),
  2245      ('', 'fold', False, _("record a fold (multiple precursors, one successors)")),
  2265      ('', 'fold', False,
  2246      ('', 'split', False, _("record a split (on precursor, multiple successors)")),
  2266         _("record a fold (multiple precursors, one successors)")),
       
  2267      ('', 'split', False,
       
  2268         _("record a split (on precursor, multiple successors)")),
  2247      ('B', 'bookmark', '', _("remove revs only reachable from given"
  2269      ('B', 'bookmark', '', _("remove revs only reachable from given"
  2248                              " bookmark"))] + metadataopts,
  2270                              " bookmark"))] + metadataopts,
  2249     _('[OPTION] [-r] REV...'))
  2271     _('[OPTION] [-r] REV...'))
  2250     # -U  --noupdate option to prevent wc update and or bookmarks update ?
  2272     # -U  --noupdate option to prevent wc update and or bookmarks update ?
  2251 def cmdprune(ui, repo, *revs, **opts):
  2273 def cmdprune(ui, repo, *revs, **opts):
  2279     fold = opts.get('fold')
  2301     fold = opts.get('fold')
  2280     split = opts.get('split')
  2302     split = opts.get('split')
  2281 
  2303 
  2282     options = [o for o in ('biject', 'fold', 'split') if opts.get(o)]
  2304     options = [o for o in ('biject', 'fold', 'split') if opts.get(o)]
  2283     if 1 < len(options):
  2305     if 1 < len(options):
  2284         raise util.Abort(_("can only specify one of %s") % ', '.join(options))
  2306         raise error.Abort(_("can only specify one of %s") % ', '.join(options))
  2285 
  2307 
  2286     if bookmark:
  2308     if bookmark:
  2287         marks,revs = _reachablefrombookmark(repo, revs, bookmark)
  2309         marks, revs = _reachablefrombookmark(repo, revs, bookmark)
  2288         if not revs:
  2310         if not revs:
  2289             # no revisions to prune - delete bookmark immediately
  2311             # no revisions to prune - delete bookmark immediately
  2290             _deletebookmark(repo, marks, bookmark)
  2312             _deletebookmark(repo, marks, bookmark)
  2291 
  2313 
  2292     if not revs:
  2314     if not revs:
  2293         raise util.Abort(_('nothing to prune'))
  2315         raise error.Abort(_('nothing to prune'))
  2294 
  2316 
  2295     wlock = lock = tr = None
  2317     wlock = lock = tr = None
  2296     try:
  2318     try:
  2297         wlock = repo.wlock()
  2319         wlock = repo.wlock()
  2298         lock = repo.lock()
  2320         lock = repo.lock()
  2302         revs.sort()
  2324         revs.sort()
  2303         for p in revs:
  2325         for p in revs:
  2304             cp = repo[p]
  2326             cp = repo[p]
  2305             if not cp.mutable():
  2327             if not cp.mutable():
  2306                 # note: createmarkers() would have raised something anyway
  2328                 # note: createmarkers() would have raised something anyway
  2307                 raise util.Abort('cannot prune immutable changeset: %s' % cp,
  2329                 raise error.Abort('cannot prune immutable changeset: %s' % cp,
  2308                                  hint='see "hg help phases" for details')
  2330                                  hint='see "hg help phases" for details')
  2309             precs.append(cp)
  2331             precs.append(cp)
  2310         if not precs:
  2332         if not precs:
  2311             raise util.Abort('nothing to prune')
  2333             raise error.Abort('nothing to prune')
  2312 
  2334 
  2313         if not obsolete.isenabled(repo, obsolete.allowunstableopt):
  2335         if not obsolete.isenabled(repo, obsolete.allowunstableopt):
  2314             if repo.revs("(%ld::) - %ld", revs, revs):
  2336             if repo.revs("(%ld::) - %ld", revs, revs):
  2315                 raise util.Abort(_("cannot prune in the middle of a stack"))
  2337                 raise error.Abort(_("cannot prune in the middle of a stack"))
  2316 
  2338 
  2317         # defines successors changesets
  2339         # defines successors changesets
  2318         sucs = scmutil.revrange(repo, succs)
  2340         sucs = scmutil.revrange(repo, succs)
  2319         sucs.sort()
  2341         sucs.sort()
  2320         sucs = tuple(repo[n] for n in sucs)
  2342         sucs = tuple(repo[n] for n in sucs)
  2321         if not biject and len(sucs) > 1 and len(precs) > 1:
  2343         if not biject and len(sucs) > 1 and len(precs) > 1:
  2322             msg = "Can't use multiple successors for multiple precursors"
  2344             msg = "Can't use multiple successors for multiple precursors"
  2323             raise util.Abort(msg)
  2345             raise error.Abort(msg)
  2324         elif biject and len(sucs) != len(precs):
  2346         elif biject and len(sucs) != len(precs):
  2325             msg = "Can't use %d successors for %d precursors" \
  2347             msg = "Can't use %d successors for %d precursors" \
  2326                 % (len(sucs), len(precs))
  2348                 % (len(sucs), len(precs))
  2327             raise util.Abort(msg)
  2349             raise error.Abort(msg)
  2328         elif (len(precs) == 1 and len(sucs) > 1) and not split:
  2350         elif (len(precs) == 1 and len(sucs) > 1) and not split:
  2329             msg = "please add --split if you want to do a split"
  2351             msg = "please add --split if you want to do a split"
  2330             raise util.Abort(msg)
  2352             raise error.Abort(msg)
  2331         elif len(sucs) == 1 and len(precs) > 1 and not fold:
  2353         elif len(sucs) == 1 and len(precs) > 1 and not fold:
  2332             msg = "please add --fold if you want to do a fold"
  2354             msg = "please add --fold if you want to do a fold"
  2333             raise util.Abort(msg)
  2355             raise error.Abort(msg)
  2334         elif biject:
  2356         elif biject:
  2335             relations = [(p, (s,)) for p, s in zip(precs, sucs)]
  2357             relations = [(p, (s,)) for p, s in zip(precs, sucs)]
  2336         else:
  2358         else:
  2337             relations = [(p, sucs) for p in precs]
  2359             relations = [(p, sucs) for p in precs]
  2338 
  2360 
  2358                 # only reset the dirstate for files that would actually change
  2380                 # only reset the dirstate for files that would actually change
  2359                 # between the working context and uctx
  2381                 # between the working context and uctx
  2360                 descendantrevs = repo.revs("%d::." % newnode.rev())
  2382                 descendantrevs = repo.revs("%d::." % newnode.rev())
  2361                 changedfiles = []
  2383                 changedfiles = []
  2362                 for rev in descendantrevs:
  2384                 for rev in descendantrevs:
  2363                     # blindly reset the files, regardless of what actually changed
  2385                     # blindly reset the files, regardless of what actually
       
  2386                     # changed
  2364                     changedfiles.extend(repo[rev].files())
  2387                     changedfiles.extend(repo[rev].files())
  2365 
  2388 
  2366                 # reset files that only changed in the dirstate too
  2389                 # reset files that only changed in the dirstate too
  2367                 dirstate = repo.dirstate
  2390                 dirstate = repo.dirstate
  2368                 dirchanges = [f for f in dirstate if dirstate[f] != 'n']
  2391                 dirchanges = [f for f in dirstate if dirstate[f] != 'n']
  2369                 changedfiles.extend(dirchanges)
  2392                 changedfiles.extend(dirchanges)
  2370                 repo.dirstate.rebuild(newnode.node(), newnode.manifest(), changedfiles)
  2393                 repo.dirstate.rebuild(newnode.node(), newnode.manifest(),
       
  2394                                       changedfiles)
  2371                 writedirstate(dirstate, tr)
  2395                 writedirstate(dirstate, tr)
  2372             else:
  2396             else:
  2373                 bookactive = bmactive(repo)
  2397                 bookactive = bmactive(repo)
  2374                 # Active bookmark that we don't want to delete (with -B option)
  2398                 # Active bookmark that we don't want to delete (with -B option)
  2375                 # we deactivate and move it before the update and reactivate it
  2399                 # we deactivate and move it before the update and reactivate it
  2579     try:
  2603     try:
  2580         wlock = repo.wlock()
  2604         wlock = repo.wlock()
  2581         lock = repo.lock()
  2605         lock = repo.lock()
  2582         wctx = repo[None]
  2606         wctx = repo[None]
  2583         if len(wctx.parents()) <= 0:
  2607         if len(wctx.parents()) <= 0:
  2584             raise util.Abort(_("cannot uncommit null changeset"))
  2608             raise error.Abort(_("cannot uncommit null changeset"))
  2585         if len(wctx.parents()) > 1:
  2609         if len(wctx.parents()) > 1:
  2586             raise util.Abort(_("cannot uncommit while merging"))
  2610             raise error.Abort(_("cannot uncommit while merging"))
  2587         old = repo['.']
  2611         old = repo['.']
  2588         if old.phase() == phases.public:
  2612         if old.phase() == phases.public:
  2589             raise util.Abort(_("cannot rewrite immutable changeset"))
  2613             raise error.Abort(_("cannot rewrite immutable changeset"))
  2590         if len(old.parents()) > 1:
  2614         if len(old.parents()) > 1:
  2591             raise util.Abort(_("cannot uncommit merge changeset"))
  2615             raise error.Abort(_("cannot uncommit merge changeset"))
  2592         oldphase = old.phase()
  2616         oldphase = old.phase()
  2593 
  2617 
  2594 
  2618 
  2595         rev = None
  2619         rev = None
  2596         if opts.get('rev'):
  2620         if opts.get('rev'):
  2597             rev = scmutil.revsingle(repo, opts.get('rev'))
  2621             rev = scmutil.revsingle(repo, opts.get('rev'))
  2598             ctx = repo[None]
  2622             ctx = repo[None]
  2599             if ctx.p1() == rev or ctx.p2() == rev:
  2623             if ctx.p1() == rev or ctx.p2() == rev:
  2600                 raise util.Abort(_("cannot uncommit to parent changeset"))
  2624                 raise error.Abort(_("cannot uncommit to parent changeset"))
  2601 
  2625 
  2602         onahead = old.rev() in repo.changelog.headrevs()
  2626         onahead = old.rev() in repo.changelog.headrevs()
  2603         disallowunstable = not obsolete.isenabled(repo, obsolete.allowunstableopt)
  2627         disallowunstable = not obsolete.isenabled(repo,
       
  2628                                                   obsolete.allowunstableopt)
  2604         if disallowunstable and not onahead:
  2629         if disallowunstable and not onahead:
  2605             raise util.Abort(_("cannot uncommit in the middle of a stack"))
  2630             raise error.Abort(_("cannot uncommit in the middle of a stack"))
  2606 
  2631 
  2607         # Recommit the filtered changeset
  2632         # Recommit the filtered changeset
  2608         tr = repo.transaction('uncommit')
  2633         tr = repo.transaction('uncommit')
  2609         updatebookmarks = _bookmarksupdater(repo, old.node(), tr)
  2634         updatebookmarks = _bookmarksupdater(repo, old.node(), tr)
  2610         newid = None
  2635         newid = None
  2611         includeorexclude = opts.get('include') or opts.get('exclude')
  2636         includeorexclude = opts.get('include') or opts.get('exclude')
  2612         if (pats or includeorexclude or opts.get('all')):
  2637         if (pats or includeorexclude or opts.get('all')):
  2613             match = scmutil.match(old, pats, opts)
  2638             match = scmutil.match(old, pats, opts)
  2614             newid = _commitfiltered(repo, old, match, target=rev)
  2639             newid = _commitfiltered(repo, old, match, target=rev)
  2615         if newid is None:
  2640         if newid is None:
  2616             raise util.Abort(_('nothing to uncommit'),
  2641             raise error.Abort(_('nothing to uncommit'),
  2617                              hint=_("use --all to uncommit all files"))
  2642                              hint=_("use --all to uncommit all files"))
  2618         # Move local changes on filtered changeset
  2643         # Move local changes on filtered changeset
  2619         obsolete.createmarkers(repo, [(old, (repo[newid],))])
  2644         obsolete.createmarkers(repo, [(old, (repo[newid],))])
  2620         phases.retractboundary(repo, tr, oldphase, [newid])
  2645         phases.retractboundary(repo, tr, oldphase, [newid])
  2621         repo.dirstate.beginparentchange()
  2646         repo.dirstate.beginparentchange()
  2676 
  2701 
  2677     revopt = opts.get('rev')
  2702     revopt = opts.get('rev')
  2678     if revopt:
  2703     if revopt:
  2679         revs = scmutil.revrange(repo, revopt)
  2704         revs = scmutil.revrange(repo, revopt)
  2680         if len(revs) != 1:
  2705         if len(revs) != 1:
  2681             raise util.Abort(_("you can only specify one revision to split"))
  2706             raise error.Abort(_("you can only specify one revision to split"))
  2682         else:
  2707         else:
  2683             rev = list(revs)[0]
  2708             rev = list(revs)[0]
  2684     else:
  2709     else:
  2685         rev = '.'
  2710         rev = '.'
  2686 
  2711 
  2694         disallowunstable = not obsolete.isenabled(repo,
  2719         disallowunstable = not obsolete.isenabled(repo,
  2695                                                   obsolete.allowunstableopt)
  2720                                                   obsolete.allowunstableopt)
  2696         if disallowunstable:
  2721         if disallowunstable:
  2697             # XXX We should check head revs
  2722             # XXX We should check head revs
  2698             if repo.revs("(%d::) - %d", rev, rev):
  2723             if repo.revs("(%d::) - %d", rev, rev):
  2699                 raise util.Abort(_("cannot split commit: %s not a head") % ctx)
  2724                 raise error.Abort(_("cannot split commit: %s not a head") % ctx)
  2700 
  2725 
  2701         if len(ctx.parents()) > 1:
  2726         if len(ctx.parents()) > 1:
  2702             raise util.Abort(_("cannot split merge commits"))
  2727             raise error.Abort(_("cannot split merge commits"))
  2703         prev = ctx.p1()
  2728         prev = ctx.p1()
  2704         bmupdate = _bookmarksupdater(repo, ctx.node(), tr)
  2729         bmupdate = _bookmarksupdater(repo, ctx.node(), tr)
  2705         bookactive = bmactive(repo)
  2730         bookactive = bmactive(repo)
  2706         if bookactive is not None:
  2731         if bookactive is not None:
  2707             repo.ui.status(_("(leaving bookmark %s)\n") % bmactive(repo))
  2732             repo.ui.status(_("(leaving bookmark %s)\n") % bmactive(repo))
  2727                 if ui.prompt('Done splitting? [yN]', default='n') == 'y':
  2752                 if ui.prompt('Done splitting? [yN]', default='n') == 'y':
  2728                     commands.commit(ui, repo, **opts)
  2753                     commands.commit(ui, repo, **opts)
  2729                     newcommits.append(repo['.'])
  2754                     newcommits.append(repo['.'])
  2730                     break
  2755                     break
  2731             else:
  2756             else:
  2732                 ui.status("no more change to split\n")
  2757                 ui.status(_("no more change to split\n"))
  2733 
  2758 
  2734         tip = repo[newcommits[-1]]
  2759         tip = repo[newcommits[-1]]
  2735         bmupdate(tip.node())
  2760         bmupdate(tip.node())
  2736         if bookactive is not None:
  2761         if bookactive is not None:
  2737             bmactivate(repo, bookactive)
  2762             bmactivate(repo, bookactive)
  2771      ('D', 'duplicate', False,
  2796      ('D', 'duplicate', False,
  2772       'do not mark the new revision as successor of the old one')],
  2797       'do not mark the new revision as successor of the old one')],
  2773     # allow to choose the seed ?
  2798     # allow to choose the seed ?
  2774     _('[-r] revs'))
  2799     _('[-r] revs'))
  2775 def touch(ui, repo, *revs, **opts):
  2800 def touch(ui, repo, *revs, **opts):
  2776     """create successors that are identical to their predecessors except for the changeset ID
  2801     """create successors that are identical to their predecessors except
       
  2802     for the changeset ID
  2777 
  2803 
  2778     This is used to "resurrect" changesets
  2804     This is used to "resurrect" changesets
  2779     """
  2805     """
  2780     duplicate = opts['duplicate']
  2806     duplicate = opts['duplicate']
  2781     revs = list(revs)
  2807     revs = list(revs)
  2785     revs = scmutil.revrange(repo, revs)
  2811     revs = scmutil.revrange(repo, revs)
  2786     if not revs:
  2812     if not revs:
  2787         ui.write_err('no revision to touch\n')
  2813         ui.write_err('no revision to touch\n')
  2788         return 1
  2814         return 1
  2789     if not duplicate and repo.revs('public() and %ld', revs):
  2815     if not duplicate and repo.revs('public() and %ld', revs):
  2790         raise util.Abort("can't touch public revision")
  2816         raise error.Abort("can't touch public revision")
  2791     wlock = lock = tr = None
  2817     wlock = lock = tr = None
  2792     try:
  2818     try:
  2793         wlock = repo.wlock()
  2819         wlock = repo.wlock()
  2794         lock = repo.lock()
  2820         lock = repo.lock()
  2795         tr = repo.transaction('touch')
  2821         tr = repo.transaction('touch')
  2863          hg fold foo::@ --exact
  2889          hg fold foo::@ --exact
  2864     """
  2890     """
  2865     revs = list(revs)
  2891     revs = list(revs)
  2866     revs.extend(opts['rev'])
  2892     revs.extend(opts['rev'])
  2867     if not revs:
  2893     if not revs:
  2868         raise util.Abort(_('no revisions specified'))
  2894         raise error.Abort(_('no revisions specified'))
  2869 
  2895 
  2870     revs = scmutil.revrange(repo, revs)
  2896     revs = scmutil.revrange(repo, revs)
  2871 
  2897 
  2872     if not opts['exact']:
  2898     if not opts['exact']:
  2873         # Try to extend given revision starting from the working directory
  2899         # Try to extend given revision starting from the working directory
  2874         extrevs = repo.revs('(%ld::.) or (.::%ld)', revs, revs)
  2900         extrevs = repo.revs('(%ld::.) or (.::%ld)', revs, revs)
  2875         discardedrevs = [r for r in revs if r not in extrevs]
  2901         discardedrevs = [r for r in revs if r not in extrevs]
  2876         if discardedrevs:
  2902         if discardedrevs:
  2877             raise util.Abort(_("cannot fold non-linear revisions"),
  2903             raise error.Abort(_("cannot fold non-linear revisions"),
  2878                                hint=_("given revisions are unrelated to parent "
  2904                                hint=_("given revisions are unrelated to parent "
  2879                                       "of working directory"))
  2905                                       "of working directory"))
  2880         revs = extrevs
  2906         revs = extrevs
  2881 
  2907 
  2882     if len(revs) == 1:
  2908     if len(revs) == 1:
  2883         ui.write_err(_('single revision specified, nothing to fold\n'))
  2909         ui.write_err(_('single revision specified, nothing to fold\n'))
  2884         return 1
  2910         return 1
  2885 
  2911 
  2886     roots = repo.revs('roots(%ld)', revs)
  2912     roots = repo.revs('roots(%ld)', revs)
  2887     if len(roots) > 1:
  2913     if len(roots) > 1:
  2888         raise util.Abort(_("cannot fold non-linear revisions "
  2914         raise error.Abort(_("cannot fold non-linear revisions "
  2889                            "(multiple roots given)"))
  2915                            "(multiple roots given)"))
  2890     root = repo[roots.first()]
  2916     root = repo[roots.first()]
  2891     if root.phase() <= phases.public:
  2917     if root.phase() <= phases.public:
  2892         raise util.Abort(_("cannot fold public revisions"))
  2918         raise error.Abort(_("cannot fold public revisions"))
  2893     heads = repo.revs('heads(%ld)', revs)
  2919     heads = repo.revs('heads(%ld)', revs)
  2894     if len(heads) > 1:
  2920     if len(heads) > 1:
  2895         raise util.Abort(_("cannot fold non-linear revisions "
  2921         raise error.Abort(_("cannot fold non-linear revisions "
  2896                            "(multiple heads given)"))
  2922                            "(multiple heads given)"))
  2897     head = repo[heads.first()]
  2923     head = repo[heads.first()]
  2898     disallowunstable = not obsolete.isenabled(repo, obsolete.allowunstableopt)
  2924     disallowunstable = not obsolete.isenabled(repo, obsolete.allowunstableopt)
  2899     if disallowunstable:
  2925     if disallowunstable:
  2900         if repo.revs("(%ld::) - %ld", revs, revs):
  2926         if repo.revs("(%ld::) - %ld", revs, revs):
  2901             raise util.Abort(_("cannot fold chain not ending with a head "\
  2927             raise error.Abort(_("cannot fold chain not ending with a head "\
  2902                                "or with branching"))
  2928                                "or with branching"))
  2903     wlock = lock = None
  2929     wlock = lock = None
  2904     try:
  2930     try:
  2905         wlock = repo.wlock()
  2931         wlock = repo.wlock()
  2906         lock = repo.lock()
  2932         lock = repo.lock()
  2918                          (c.rev(), c.description()) for c in allctx]
  2944                          (c.rev(), c.description()) for c in allctx]
  2919                 commitopts['message'] =  "\n".join(msgs)
  2945                 commitopts['message'] =  "\n".join(msgs)
  2920                 commitopts['edit'] = True
  2946                 commitopts['edit'] = True
  2921 
  2947 
  2922             newid, unusedvariable = rewrite(repo, root, allctx, head,
  2948             newid, unusedvariable = rewrite(repo, root, allctx, head,
  2923                                             [root.p1().node(), root.p2().node()],
  2949                                             [root.p1().node(),
       
  2950                                              root.p2().node()],
  2924                                             commitopts=commitopts)
  2951                                             commitopts=commitopts)
  2925             phases.retractboundary(repo, tr, targetphase, [newid])
  2952             phases.retractboundary(repo, tr, targetphase, [newid])
  2926             obsolete.createmarkers(repo, [(ctx, (repo[newid],))
  2953             obsolete.createmarkers(repo, [(ctx, (repo[newid],))
  2927                                  for ctx in allctx])
  2954                                  for ctx in allctx])
  2928             tr.close()
  2955             tr.close()
  3026 
  3053 
  3027         common = []
  3054         common = []
  3028         obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
  3055         obsexcmsg(repo.ui, "looking for common markers in %i nodes\n"
  3029                            % len(revs))
  3056                            % len(revs))
  3030         commonrevs = list(unfi.revs('::%ln', pushop.outgoing.commonheads))
  3057         commonrevs = list(unfi.revs('::%ln', pushop.outgoing.commonheads))
  3031         common = findcommonobsmarkers(pushop.ui, unfi, pushop.remote, commonrevs)
  3058         common = findcommonobsmarkers(pushop.ui, unfi, pushop.remote,
       
  3059                                       commonrevs)
  3032 
  3060 
  3033         revs = list(unfi.revs('%ld - (::%ln)', revs, common))
  3061         revs = list(unfi.revs('%ld - (::%ln)', revs, common))
  3034         nodes = [cl.node(r) for r in revs]
  3062         nodes = [cl.node(r) for r in revs]
  3035         if nodes:
  3063         if nodes:
  3036             obsexcmsg(repo.ui, "computing markers relevant to %i nodes\n"
  3064             obsexcmsg(repo.ui, "computing markers relevant to %i nodes\n"
  3058         return discocapabilities(oldcap, repo, proto)
  3086         return discocapabilities(oldcap, repo, proto)
  3059     wireproto.commands['capabilities'] = (newcap, args)
  3087     wireproto.commands['capabilities'] = (newcap, args)
  3060     wireproto.commands['evoext_obshash'] = (srv_obshash, 'nodes')
  3088     wireproto.commands['evoext_obshash'] = (srv_obshash, 'nodes')
  3061     wireproto.commands['evoext_obshash1'] = (srv_obshash1, 'nodes')
  3089     wireproto.commands['evoext_obshash1'] = (srv_obshash1, 'nodes')
  3062     if getattr(exchange, '_pushdiscoveryobsmarkers', None) is None:
  3090     if getattr(exchange, '_pushdiscoveryobsmarkers', None) is None:
  3063         ui.warn('evolve: your mercurial version is too old\n'
  3091         ui.warn(_('evolve: your mercurial version is too old\n'
  3064                 'evolve: (running in degraded mode, push will includes all markers)\n')
  3092                   'evolve: (running in degraded mode, push will '
       
  3093                   'includes all markers)\n'))
  3065     else:
  3094     else:
  3066         olddisco = exchange.pushdiscoverymapping['obsmarker']
  3095         olddisco = exchange.pushdiscoverymapping['obsmarker']
  3067         def newdisco(pushop):
  3096         def newdisco(pushop):
  3068             _pushdiscoveryobsmarkers(olddisco, pushop)
  3097             _pushdiscoveryobsmarkers(olddisco, pushop)
  3069         exchange.pushdiscoverymapping['obsmarker'] = newdisco
  3098         exchange.pushdiscoverymapping['obsmarker'] = newdisco
  3086 
  3115 
  3087 def srv_obshash(repo, proto, nodes):
  3116 def srv_obshash(repo, proto, nodes):
  3088     return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes)))
  3117     return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes)))
  3089 
  3118 
  3090 def srv_obshash1(repo, proto, nodes):
  3119 def srv_obshash1(repo, proto, nodes):
  3091     return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes), version=1))
  3120     return wireproto.encodelist(_obshash(repo, wireproto.decodelist(nodes),
       
  3121                                 version=1))
  3092 
  3122 
  3093 @eh.addattr(localrepo.localpeer, 'evoext_obshash')
  3123 @eh.addattr(localrepo.localpeer, 'evoext_obshash')
  3094 def local_obshash(peer, nodes):
  3124 def local_obshash(peer, nodes):
  3095     return _obshash(peer._repo, nodes)
  3125     return _obshash(peer._repo, nodes)
  3096 
  3126 
  3123     dag = dagutil.revlogdag(cl)
  3153     dag = dagutil.revlogdag(cl)
  3124     missing = set()
  3154     missing = set()
  3125     common = set()
  3155     common = set()
  3126     undecided = set(probeset)
  3156     undecided = set(probeset)
  3127     totalnb = len(undecided)
  3157     totalnb = len(undecided)
  3128     ui.progress("comparing with other", 0, total=totalnb)
  3158     ui.progress(_("comparing with other"), 0, total=totalnb)
  3129     _takefullsample = setdiscovery._takefullsample
  3159     _takefullsample = setdiscovery._takefullsample
  3130     if remote.capable('_evoext_obshash_1'):
  3160     if remote.capable('_evoext_obshash_1'):
  3131         getremotehash = remote.evoext_obshash1
  3161         getremotehash = remote.evoext_obshash1
  3132         localhash = _obsrelsethashtreefm1(local)
  3162         localhash = _obsrelsethashtreefm1(local)
  3133     else:
  3163     else:
  3141             sample = set(undecided)
  3171             sample = set(undecided)
  3142         else:
  3172         else:
  3143             sample = _takefullsample(dag, undecided, size=fullsamplesize)
  3173             sample = _takefullsample(dag, undecided, size=fullsamplesize)
  3144 
  3174 
  3145         roundtrips += 1
  3175         roundtrips += 1
  3146         ui.progress("comparing with other", totalnb - len(undecided),
  3176         ui.progress(_("comparing with other"), totalnb - len(undecided),
  3147                     total=totalnb)
  3177                     total=totalnb)
  3148         ui.debug("query %i; still undecided: %i, sample size is: %i\n"
  3178         ui.debug("query %i; still undecided: %i, sample size is: %i\n"
  3149                  % (roundtrips, len(undecided), len(sample)))
  3179                  % (roundtrips, len(undecided), len(sample)))
  3150         # indices between sample and externalized version must match
  3180         # indices between sample and externalized version must match
  3151         sample = list(sample)
  3181         sample = list(sample)
  3162 
  3192 
  3163         undecided.difference_update(missing)
  3193         undecided.difference_update(missing)
  3164         undecided.difference_update(common)
  3194         undecided.difference_update(common)
  3165 
  3195 
  3166 
  3196 
  3167     ui.progress("comparing with other", None, total=totalnb)
  3197     ui.progress(_("comparing with other"), None, total=totalnb)
  3168     result = dag.headsetofconnecteds(common)
  3198     result = dag.headsetofconnecteds(common)
  3169     ui.debug("%d total queries\n" % roundtrips)
  3199     ui.debug("%d total queries\n" % roundtrips)
  3170 
  3200 
  3171     if not result:
  3201     if not result:
  3172         return set([nullid])
  3202         return set([nullid])
  3226             remote.evoext_pushobsmarkers_0(obsdata)
  3256             remote.evoext_pushobsmarkers_0(obsdata)
  3227             obsexcprg(repo.ui, None)
  3257             obsexcprg(repo.ui, None)
  3228         else:
  3258         else:
  3229             rslts = []
  3259             rslts = []
  3230             remotedata = _pushkeyescape(markers).items()
  3260             remotedata = _pushkeyescape(markers).items()
  3231             totalbytes = sum(len(d) for k,d in remotedata)
  3261             totalbytes = sum(len(d) for k, d in remotedata)
  3232             sentbytes = 0
  3262             sentbytes = 0
  3233             obsexcmsg(repo.ui, "pushing %i obsolescence markers in %i pushkey payload (%i bytes)\n"
  3263             obsexcmsg(repo.ui, "pushing %i obsolescence markers in %i "
  3234                                 % (len(markers), len(remotedata), totalbytes),
  3264                                "pushkey payload (%i bytes)\n"
       
  3265                                % (len(markers), len(remotedata), totalbytes),
  3235                       True)
  3266                       True)
  3236             for key, data in remotedata:
  3267             for key, data in remotedata:
  3237                 obsexcprg(repo.ui, sentbytes, item=key, unit="bytes",
  3268                 obsexcprg(repo.ui, sentbytes, item=key, unit="bytes",
  3238                           total=totalbytes)
  3269                           total=totalbytes)
  3239                 rslts.append(remote.pushkey('obsolete', key, '', data))
  3270                 rslts.append(remote.pushkey('obsolete', key, '', data))
  3271 
  3302 
  3272         for l in vals[1].splitlines(True):
  3303         for l in vals[1].splitlines(True):
  3273             if l.strip():
  3304             if l.strip():
  3274                 self.ui.status(_('remote: '), l)
  3305                 self.ui.status(_('remote: '), l)
  3275         return vals[0]
  3306         return vals[0]
  3276     except socket.error, err:
  3307     except socket.error as err:
  3277         if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
  3308         if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
  3278             raise util.Abort(_('push failed: %s') % err.args[1])
  3309             raise error.Abort(_('push failed: %s') % err.args[1])
  3279         raise util.Abort(err.args[1])
  3310         raise error.Abort(err.args[1])
  3280 
  3311 
  3281 @eh.wrapfunction(localrepo.localrepository, '_restrictcapabilities')
  3312 @eh.wrapfunction(localrepo.localrepository, '_restrictcapabilities')
  3282 def local_pushobsmarker_capabilities(orig, repo, caps):
  3313 def local_pushobsmarker_capabilities(orig, repo, caps):
  3283     caps = orig(repo, caps)
  3314     caps = orig(repo, caps)
  3284     caps.add('_evoext_pushobsmarkers_0')
  3315     caps.add('_evoext_pushobsmarkers_0')
  3333     gboptsmap['evo_obscommon'] = 'nodes'
  3364     gboptsmap['evo_obscommon'] = 'nodes'
  3334 
  3365 
  3335 @eh.wrapfunction(exchange, '_pullbundle2extraprepare')
  3366 @eh.wrapfunction(exchange, '_pullbundle2extraprepare')
  3336 def _addobscommontob2pull(orig, pullop, kwargs):
  3367 def _addobscommontob2pull(orig, pullop, kwargs):
  3337     ret = orig(pullop, kwargs)
  3368     ret = orig(pullop, kwargs)
  3338     if 'obsmarkers' in kwargs and pullop.remote.capable('_evoext_getbundle_obscommon'):
  3369     if ('obsmarkers' in kwargs and
       
  3370         pullop.remote.capable('_evoext_getbundle_obscommon')):
  3339         boundaries = _buildpullobsmarkersboundaries(pullop)
  3371         boundaries = _buildpullobsmarkersboundaries(pullop)
  3340         common = boundaries['common']
  3372         common = boundaries['common']
  3341         if common != [nullid]:
  3373         if common != [nullid]:
  3342             kwargs['evo_obscommon'] = common
  3374             kwargs['evo_obscommon'] = common
  3343     return ret
  3375     return ret
  3446     current = 0
  3478     current = 0
  3447     data = StringIO()
  3479     data = StringIO()
  3448     ui = self.ui
  3480     ui = self.ui
  3449     obsexcprg(ui, current, unit="bytes", total=length)
  3481     obsexcprg(ui, current, unit="bytes", total=length)
  3450     while current < length:
  3482     while current < length:
  3451         readsize = min(length-current, chunk)
  3483         readsize = min(length - current, chunk)
  3452         data.write(f.read(readsize))
  3484         data.write(f.read(readsize))
  3453         current += readsize
  3485         current += readsize
  3454         obsexcprg(ui, current, unit="bytes", total=length)
  3486         obsexcprg(ui, current, unit="bytes", total=length)
  3455     obsexcprg(ui, None)
  3487     obsexcprg(ui, None)
  3456     data.seek(0)
  3488     data.seek(0)
  3481 
  3513 
  3482 def _obsrelsethashtree(repo, encodeonemarker):
  3514 def _obsrelsethashtree(repo, encodeonemarker):
  3483     cache = []
  3515     cache = []
  3484     unfi = repo.unfiltered()
  3516     unfi = repo.unfiltered()
  3485     markercache = {}
  3517     markercache = {}
  3486     repo.ui.progress("preparing locally", 0, total=len(unfi))
  3518     repo.ui.progress(_("preparing locally"), 0, total=len(unfi))
  3487     for i in unfi:
  3519     for i in unfi:
  3488         ctx = unfi[i]
  3520         ctx = unfi[i]
  3489         entry = 0
  3521         entry = 0
  3490         sha = util.sha1()
  3522         sha = util.sha1()
  3491         # add data from p1
  3523         # add data from p1
  3511                 sha.update(m)
  3543                 sha.update(m)
  3512         if entry:
  3544         if entry:
  3513             cache.append((ctx.node(), sha.digest()))
  3545             cache.append((ctx.node(), sha.digest()))
  3514         else:
  3546         else:
  3515             cache.append((ctx.node(), nullid))
  3547             cache.append((ctx.node(), nullid))
  3516         repo.ui.progress("preparing locally", i, total=len(unfi))
  3548         repo.ui.progress(_("preparing locally"), i, total=len(unfi))
  3517     repo.ui.progress("preparing locally", None)
  3549     repo.ui.progress(_("preparing locally"), None)
  3518     return cache
  3550     return cache
  3519 
  3551 
  3520 @command('debugobsrelsethashtree',
  3552 @command('debugobsrelsethashtree',
  3521         [('', 'v0', None, 'hash on marker format "0"'),
  3553         [('', 'v0', None, 'hash on marker format "0"'),
  3522          ('', 'v1', None, 'hash on marker format "1" (default)')
  3554          ('', 'v1', None, 'hash on marker format "1" (default)')] , _(''))
  3523          ,] , _(''))
       
  3524 def debugobsrelsethashtree(ui, repo, v0=False, v1=False):
  3555 def debugobsrelsethashtree(ui, repo, v0=False, v1=False):
  3525     """display Obsolete markers, Relevant Set, Hash Tree
  3556     """display Obsolete markers, Relevant Set, Hash Tree
  3526     changeset-node obsrelsethashtree-node
  3557     changeset-node obsrelsethashtree-node
  3527 
  3558 
  3528     It computed form the "orsht" of its parent and markers
  3559     It computed form the "orsht" of its parent and markers
  3529     relevant to the changeset itself."""
  3560     relevant to the changeset itself."""
  3530     if v0 and v1:
  3561     if v0 and v1:
  3531         raise util.Abort('cannot only specify one format')
  3562         raise error.Abort('cannot only specify one format')
  3532     elif v0:
  3563     elif v0:
  3533         treefunc = _obsrelsethashtreefm0
  3564         treefunc = _obsrelsethashtreefm0
  3534     else:
  3565     else:
  3535         treefunc = _obsrelsethashtreefm1
  3566         treefunc = _obsrelsethashtreefm1
  3536 
  3567 
  3549     """
  3580     """
  3550     if 'debugobsconvert' in sys.argv:
  3581     if 'debugobsconvert' in sys.argv:
  3551         return
  3582         return
  3552     for mark in markers:
  3583     for mark in markers:
  3553         if node.nullid in mark[1]:
  3584         if node.nullid in mark[1]:
  3554             raise util.Abort(_('bad obsolescence marker detected: '
  3585             raise error.Abort(_('bad obsolescence marker detected: '
  3555                                'invalid successors nullid'),
  3586                                'invalid successors nullid'),
  3556                              hint=_('You should run `hg debugobsconvert`'))
  3587                              hint=_('You should run `hg debugobsconvert`'))
  3557 
  3588 
  3558 @command(
  3589 @command(
  3559     'debugobsconvert',
  3590     'debugobsconvert',
  3561     '')
  3592     '')
  3562 def debugobsconvert(ui, repo, new_format):
  3593 def debugobsconvert(ui, repo, new_format):
  3563     origmarkers = repo.obsstore._all  # settle version
  3594     origmarkers = repo.obsstore._all  # settle version
  3564     if new_format == repo.obsstore._version:
  3595     if new_format == repo.obsstore._version:
  3565         msg = _('New format is the same as the old format, not upgrading!')
  3596         msg = _('New format is the same as the old format, not upgrading!')
  3566         raise util.Abort(msg)
  3597         raise error.Abort(msg)
  3567     f = repo.svfs('obsstore', 'wb', atomictemp=True)
  3598     f = repo.svfs('obsstore', 'wb', atomictemp=True)
  3568     known = set()
  3599     known = set()
  3569     markers = []
  3600     markers = []
  3570     for m in origmarkers:
  3601     for m in origmarkers:
  3571         # filter out invalid markers
  3602         # filter out invalid markers