hgext/evolve.py
branchstable
changeset 1518 bca3fce56b2c
parent 1517 a1f239a93c94
child 1519 c15d6168412f
equal deleted inserted replaced
1511:91b6a30424a3 1518:bca3fce56b2c
    18       this feature,
    18       this feature,
    19     - improves some aspect of the early implementation in Mercurial core
    19     - improves some aspect of the early implementation in Mercurial core
    20 '''
    20 '''
    21 
    21 
    22 __version__ = '5.2.0'
    22 __version__ = '5.2.0'
    23 testedwith = '3.3.3 3.4.1'
    23 testedwith = '3.4.3 3.5.2 3.6'
    24 buglink = 'http://bz.selenic.com/'
    24 buglink = 'http://bz.selenic.com/'
    25 
    25 
    26 
    26 
    27 evolutionhelptext = """
    27 evolutionhelptext = """
    28 Obsolescence markers make it possible to mark changesets that have been
    28 Obsolescence markers make it possible to mark changesets that have been
    69 import errno
    69 import errno
    70 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
    70 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
    71 
    71 
    72 import mercurial
    72 import mercurial
    73 from mercurial import util
    73 from mercurial import util
       
    74 from mercurial import repair
    74 
    75 
    75 try:
    76 try:
    76     from mercurial import obsolete
    77     from mercurial import obsolete
    77     if not obsolete._enabled:
    78     if not obsolete._enabled:
    78         obsolete._enabled = True
    79         obsolete._enabled = True
   803     """Return (nodeid, created) where nodeid is the identifier of the
   804     """Return (nodeid, created) where nodeid is the identifier of the
   804     changeset generated by the rewrite process, and created is True if
   805     changeset generated by the rewrite process, and created is True if
   805     nodeid was actually created. If created is False, nodeid
   806     nodeid was actually created. If created is False, nodeid
   806     references a changeset existing before the rewrite call.
   807     references a changeset existing before the rewrite call.
   807     """
   808     """
   808     if len(old.parents()) > 1: #XXX remove this unecessary limitation.
   809     wlock = lock = tr = None
   809         raise error.Abort(_('cannot amend merge changesets'))
   810     try:
   810     base = old.p1()
   811         wlock = repo.wlock()
   811     updatebookmarks = _bookmarksupdater(repo, old.node())
   812         lock = repo.lock()
   812 
   813         tr = repo.transaction('rewrite')
   813     # commit a new version of the old changeset, including the update
   814         if len(old.parents()) > 1: #XXX remove this unecessary limitation.
   814     # collect all files which might be affected
   815             raise error.Abort(_('cannot amend merge changesets'))
   815     files = set(old.files())
   816         base = old.p1()
   816     for u in updates:
   817         updatebookmarks = _bookmarksupdater(repo, old.node(), tr)
   817         files.update(u.files())
   818 
   818 
   819         # commit a new version of the old changeset, including the update
   819     # Recompute copies (avoid recording a -> b -> a)
   820         # collect all files which might be affected
   820     copied = copies.pathcopies(base, head)
   821         files = set(old.files())
   821 
   822         for u in updates:
   822 
   823             files.update(u.files())
   823     # prune files which were reverted by the updates
   824 
   824     def samefile(f):
   825         # Recompute copies (avoid recording a -> b -> a)
   825         if f in head.manifest():
   826         copied = copies.pathcopies(base, head)
   826             a = head.filectx(f)
   827 
   827             if f in base.manifest():
   828 
   828                 b = base.filectx(f)
   829         # prune files which were reverted by the updates
   829                 return (a.data() == b.data()
   830         def samefile(f):
   830                         and a.flags() == b.flags())
   831             if f in head.manifest():
       
   832                 a = head.filectx(f)
       
   833                 if f in base.manifest():
       
   834                     b = base.filectx(f)
       
   835                     return (a.data() == b.data()
       
   836                             and a.flags() == b.flags())
       
   837                 else:
       
   838                     return False
   831             else:
   839             else:
   832                 return False
   840                 return f not in base.manifest()
   833         else:
   841         files = [f for f in files if not samefile(f)]
   834             return f not in base.manifest()
   842         # commit version of these files as defined by head
   835     files = [f for f in files if not samefile(f)]
   843         headmf = head.manifest()
   836     # commit version of these files as defined by head
   844         def filectxfn(repo, ctx, path):
   837     headmf = head.manifest()
   845             if path in headmf:
   838     def filectxfn(repo, ctx, path):
   846                 fctx = head[path]
   839         if path in headmf:
   847                 flags = fctx.flags()
   840             fctx = head[path]
   848                 mctx = memfilectx(repo, fctx.path(), fctx.data(),
   841             flags = fctx.flags()
   849                                   islink='l' in flags,
   842             mctx = memfilectx(repo, fctx.path(), fctx.data(),
   850                                   isexec='x' in flags,
   843                               islink='l' in flags,
   851                                   copied=copied.get(path))
   844                               isexec='x' in flags,
   852                 return mctx
   845                               copied=copied.get(path))
   853             return None
   846             return mctx
   854 
   847         return None
   855         message = cmdutil.logmessage(repo.ui, commitopts)
   848 
   856         if not message:
   849     message = cmdutil.logmessage(repo.ui, commitopts)
   857             message = old.description()
   850     if not message:
   858 
   851         message = old.description()
   859         user = commitopts.get('user') or old.user()
   852 
   860         date = commitopts.get('date') or None # old.date()
   853     user = commitopts.get('user') or old.user()
   861         extra = dict(commitopts.get('extra', old.extra()))
   854     date = commitopts.get('date') or None # old.date()
   862         extra['branch'] = head.branch()
   855     extra = dict(commitopts.get('extra', {}))
   863 
   856     extra['branch'] = head.branch()
   864         new = context.memctx(repo,
   857 
   865                              parents=newbases,
   858     new = context.memctx(repo,
   866                              text=message,
   859                          parents=newbases,
   867                              files=files,
   860                          text=message,
   868                              filectxfn=filectxfn,
   861                          files=files,
   869                              user=user,
   862                          filectxfn=filectxfn,
   870                              date=date,
   863                          user=user,
   871                              extra=extra)
   864                          date=date,
   872 
   865                          extra=extra)
   873         if commitopts.get('edit'):
   866 
   874             new._text = cmdutil.commitforceeditor(repo, new, [])
   867     if commitopts.get('edit'):
   875         revcount = len(repo)
   868         new._text = cmdutil.commitforceeditor(repo, new, [])
   876         newid = repo.commitctx(new)
   869     revcount = len(repo)
   877         new = repo[newid]
   870     newid = repo.commitctx(new)
   878         created = len(repo) != revcount
   871     new = repo[newid]
   879         updatebookmarks(newid)
   872     created = len(repo) != revcount
   880 
   873     updatebookmarks(newid)
   881         tr.close()
   874 
   882         return newid, created
   875     return newid, created
   883     finally:
       
   884         lockmod.release(lock, wlock, tr)
   876 
   885 
   877 class MergeFailure(util.Abort):
   886 class MergeFailure(util.Abort):
   878     pass
   887     pass
   879 
   888 
   880 def relocate(repo, orig, dest, keepbranch=False):
   889 def relocate(repo, orig, dest, keepbranch=False):
   933             if r[-1]:  #some conflict
   942             if r[-1]:  #some conflict
   934                 raise util.Abort(
   943                 raise util.Abort(
   935                         'unresolved merge conflicts (see hg help resolve)')
   944                         'unresolved merge conflicts (see hg help resolve)')
   936             if commitmsg is None:
   945             if commitmsg is None:
   937                 commitmsg = orig.description()
   946                 commitmsg = orig.description()
   938             extra = {'rebase_source': orig.hex()}
   947             extra = dict(orig.extra())
       
   948             if 'branch' in extra:
       
   949                 del extra['branch']
       
   950             extra['rebase_source'] = orig.hex()
   939 
   951 
   940             backup = repo.ui.backupconfig('phases', 'new-commit')
   952             backup = repo.ui.backupconfig('phases', 'new-commit')
   941             try:
   953             try:
   942                 targetphase = max(orig.phase(), phases.draft)
   954                 targetphase = max(orig.phase(), phases.draft)
   943                 repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
   955                 repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase')
   947             finally:
   959             finally:
   948                 repo.ui.restoreconfig(backup)
   960                 repo.ui.restoreconfig(backup)
   949         except util.Abort, exc:
   961         except util.Abort, exc:
   950             repo.dirstate.beginparentchange()
   962             repo.dirstate.beginparentchange()
   951             repo.setparents(repo['.'].node(), nullid)
   963             repo.setparents(repo['.'].node(), nullid)
   952             repo.dirstate.write()
   964             writedirstate(repo.dirstate, tr)
   953             # fix up dirstate for copies and renames
   965             # fix up dirstate for copies and renames
   954             copies.duplicatecopies(repo, dest.rev(), orig.p1().rev())
   966             copies.duplicatecopies(repo, dest.rev(), orig.p1().rev())
   955             repo.dirstate.endparentchange()
   967             repo.dirstate.endparentchange()
   956             class LocalMergeFailure(MergeFailure, exc.__class__):
   968             class LocalMergeFailure(MergeFailure, exc.__class__):
   957                 pass
   969                 pass
   969             for book in oldbookmarks:
   981             for book in oldbookmarks:
   970                 repo._bookmarks[book] = dest.node()
   982                 repo._bookmarks[book] = dest.node()
   971         for book in destbookmarks: # restore bookmark that rebase move
   983         for book in destbookmarks: # restore bookmark that rebase move
   972             repo._bookmarks[book] = dest.node()
   984             repo._bookmarks[book] = dest.node()
   973         if oldbookmarks or destbookmarks:
   985         if oldbookmarks or destbookmarks:
   974             repo._bookmarks.write()
   986             repo._bookmarks.recordchange(tr)
   975         tr.close()
   987         tr.close()
   976     finally:
   988     finally:
   977         tr.release()
   989         tr.release()
   978     return nodenew
   990     return nodenew
   979 
   991 
   980 def _bookmarksupdater(repo, oldid):
   992 def _bookmarksupdater(repo, oldid, tr):
   981     """Return a callable update(newid) updating the current bookmark
   993     """Return a callable update(newid) updating the current bookmark
   982     and bookmarks bound to oldid to newid.
   994     and bookmarks bound to oldid to newid.
   983     """
   995     """
   984     def updatebookmarks(newid):
   996     def updatebookmarks(newid):
   985         dirty = False
   997         dirty = False
   987         if oldbookmarks:
   999         if oldbookmarks:
   988             for b in oldbookmarks:
  1000             for b in oldbookmarks:
   989                 repo._bookmarks[b] = newid
  1001                 repo._bookmarks[b] = newid
   990             dirty = True
  1002             dirty = True
   991         if dirty:
  1003         if dirty:
   992             repo._bookmarks.write()
  1004             repo._bookmarks.recordchange(tr)
   993     return updatebookmarks
  1005     return updatebookmarks
   994 
  1006 
   995 ### bookmarks api compatibility layer ###
  1007 ### bookmarks api compatibility layer ###
   996 def bmdeactivate(repo):
  1008 def bmdeactivate(repo):
   997     try:
  1009     try:
  1007 def bmactive(repo):
  1019 def bmactive(repo):
  1008     try:
  1020     try:
  1009         return repo._activebookmark
  1021         return repo._activebookmark
  1010     except AttributeError:
  1022     except AttributeError:
  1011         return repo._bookmarkcurrent
  1023         return repo._bookmarkcurrent
       
  1024 
       
  1025 ### dirstate compatibility layer < hg 3.6
       
  1026 
       
  1027 def writedirstate(dirstate, tr):
       
  1028     if dirstate.write.func_defaults is not None: # mercurial 3.6 and above
       
  1029         return dirstate.write(tr)
       
  1030     return dirstate.write()
       
  1031 
       
  1032 
  1012 
  1033 
  1013 ### new command
  1034 ### new command
  1014 #############################
  1035 #############################
  1015 metadataopts = [
  1036 metadataopts = [
  1016     ('d', 'date', '',
  1037     ('d', 'date', '',
  1079     synopsis = '(DEPRECATED)'
  1100     synopsis = '(DEPRECATED)'
  1080     if len(entry) > 2:
  1101     if len(entry) > 2:
  1081         fn, opts, _syn = entry
  1102         fn, opts, _syn = entry
  1082     else:
  1103     else:
  1083         fn, opts, = entry
  1104         fn, opts, = entry
  1084     deprecationwarning = _('%s have been deprecated in favor of %s\n' % (
  1105     deprecationwarning = _('%s have been deprecated in favor of %s\n') % (
  1085         oldalias, newalias))
  1106         oldalias, newalias)
  1086     def newfn(*args, **kwargs):
  1107     def newfn(*args, **kwargs):
  1087         ui = args[0]
  1108         ui = args[0]
  1088         ui.warn(deprecationwarning)
  1109         ui.warn(deprecationwarning)
  1089         util.checksignature(fn)(*args, **kwargs)
  1110         util.checksignature(fn)(*args, **kwargs)
  1090     newfn.__doc__  = deprecationwarning
  1111     newfn.__doc__  = deprecationwarning
  1498     ordering.extend(sorted(dependencies))
  1519     ordering.extend(sorted(dependencies))
  1499     return ordering
  1520     return ordering
  1500 
  1521 
  1501 @command('^evolve|stabilize|solve',
  1522 @command('^evolve|stabilize|solve',
  1502     [('n', 'dry-run', False,
  1523     [('n', 'dry-run', False,
  1503         'do not perform actions, just print what would be done'),
  1524         _('do not perform actions, just print what would be done')),
  1504      ('', 'confirm', False,
  1525      ('', 'confirm', False,
  1505         'ask for confirmation before performing the action'),
  1526         _('ask for confirmation before performing the action')),
  1506     ('A', 'any', False, 'also consider troubled changesets unrelated to current working directory'),
  1527     ('A', 'any', False, _('also consider troubled changesets unrelated to current working directory')),
  1507     ('r', 'rev', [], 'solves troubles of these revisions'),
  1528     ('r', 'rev', [], _('solves troubles of these revisions')),
  1508     ('', 'bumped', False, 'solves only bumped changesets'),
  1529     ('', 'bumped', False, _('solves only bumped changesets')),
  1509     ('', 'divergent', False, 'solves only divergent changesets'),
  1530     ('', 'divergent', False, _('solves only divergent changesets')),
  1510     ('', 'unstable', False, 'solves only unstable changesets (default)'),
  1531     ('', 'unstable', False, _('solves only unstable changesets (default)')),
  1511     ('a', 'all', False, 'evolve all troubled changesets related to the current '
  1532     ('a', 'all', False, _('evolve all troubled changesets related to the current '
  1512                          'working directory and its descendants'),
  1533                          'working directory and its descendants')),
  1513     ('c', 'continue', False, 'continue an interrupted evolution'),
  1534     ('c', 'continue', False, _('continue an interrupted evolution')),
  1514     ] + mergetoolopts,
  1535     ] + mergetoolopts,
  1515     _('[OPTIONS]...'))
  1536     _('[OPTIONS]...'))
  1516 def evolve(ui, repo, **opts):
  1537 def evolve(ui, repo, **opts):
  1517     """solve troubles in your repository
  1538     """solve troubles in your repository
  1518 
  1539 
  1704                  " trying to stabilize on its parent\n" %
  1725                  " trying to stabilize on its parent\n" %
  1705                  obs)
  1726                  obs)
  1706         obs = obs.parents()[0]
  1727         obs = obs.parents()[0]
  1707         newer = obsolete.successorssets(repo, obs.node())
  1728         newer = obsolete.successorssets(repo, obs.node())
  1708     if len(newer) > 1:
  1729     if len(newer) > 1:
  1709         msg = _("skipping %s: divergent rewriting. can't choose destination\n" % obs)
  1730         msg = _("skipping %s: divergent rewriting. can't choose destination\n") % obs
  1710         ui.write_err(msg)
  1731         ui.write_err(msg)
  1711         return 2
  1732         return 2
  1712     targets = newer[0]
  1733     targets = newer[0]
  1713     assert targets
  1734     assert targets
  1714     if len(targets) > 1:
  1735     if len(targets) > 1:
  1715         msg = _("does not handle split parents yet\n")
  1736         # split target, figure out which one to pick, are they all in line?
  1716         ui.write_err(msg)
  1737         targetrevs = [repo[r].rev() for r in targets]
  1717         return 2
  1738         roots = repo.revs('roots(%ld)', targetrevs)
  1718     target = targets[0]
  1739         heads = repo.revs('heads(%ld)', targetrevs)
       
  1740         if len(roots) > 1 or len(heads) > 1:
       
  1741             msg = "cannot solve split accross two branches\n"
       
  1742             ui.write_err(msg)
       
  1743             return 2
       
  1744         target = repo[heads.first()]
       
  1745     else:
       
  1746         target = targets[0]
  1719     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  1747     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  1720     target = repo[target]
  1748     target = repo[target]
  1721     if not ui.quiet or confirm:
  1749     if not ui.quiet or confirm:
  1722         repo.ui.write(_('move:'))
  1750         repo.ui.write(_('move:'))
  1723         displayer.show(orig)
  1751         displayer.show(orig)
  1748     """Stabilize a bumped changeset"""
  1776     """Stabilize a bumped changeset"""
  1749     repo = repo.unfiltered()
  1777     repo = repo.unfiltered()
  1750     bumped = repo[bumped.rev()]
  1778     bumped = repo[bumped.rev()]
  1751     # For now we deny bumped merge
  1779     # For now we deny bumped merge
  1752     if len(bumped.parents()) > 1:
  1780     if len(bumped.parents()) > 1:
  1753         msg = _('skipping %s : we do not handle merge yet\n' % bumped)
  1781         msg = _('skipping %s : we do not handle merge yet\n') % bumped
  1754         ui.write_err(msg)
  1782         ui.write_err(msg)
  1755         return 2
  1783         return 2
  1756     prec = repo.set('last(allprecursors(%d) and public())', bumped).next()
  1784     prec = repo.set('last(allprecursors(%d) and public())', bumped).next()
  1757     # For now we deny target merge
  1785     # For now we deny target merge
  1758     if len(prec.parents()) > 1:
  1786     if len(prec.parents()) > 1:
  1759         msg = _('skipping: %s: public version is a merge, this not handled yet\n' % prec)
  1787         msg = _('skipping: %s: public version is a merge, this not handled yet\n') % prec
  1760         ui.write_err(msg)
  1788         ui.write_err(msg)
  1761         return 2
  1789         return 2
  1762 
  1790 
  1763     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  1791     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  1764     if not ui.quiet or confirm:
  1792     if not ui.quiet or confirm:
  1776         repo.ui.write('hg commit --msg "bumped update to %s"')
  1804         repo.ui.write('hg commit --msg "bumped update to %s"')
  1777         return 0
  1805         return 0
  1778     if progresscb: progresscb()
  1806     if progresscb: progresscb()
  1779     newid = tmpctx = None
  1807     newid = tmpctx = None
  1780     tmpctx = bumped
  1808     tmpctx = bumped
  1781     bmupdate = _bookmarksupdater(repo, bumped.node())
       
  1782     # Basic check for common parent. Far too complicated and fragile
  1809     # Basic check for common parent. Far too complicated and fragile
  1783     tr = repo.transaction('bumped-stabilize')
  1810     tr = repo.transaction('bumped-stabilize')
       
  1811     bmupdate = _bookmarksupdater(repo, bumped.node(), tr)
  1784     try:
  1812     try:
  1785         if not list(repo.set('parents(%d) and parents(%d)', bumped, prec)):
  1813         if not list(repo.set('parents(%d) and parents(%d)', bumped, prec)):
  1786             # Need to rebase the changeset at the right place
  1814             # Need to rebase the changeset at the right place
  1787             repo.ui.status(
  1815             repo.ui.status(
  1788                 _('rebasing to destination parent: %s\n') % prec.p1())
  1816                 _('rebasing to destination parent: %s\n') % prec.p1())
  1902         displayer.show(divergent)
  1930         displayer.show(divergent)
  1903         ui.write(_('with: '))
  1931         ui.write(_('with: '))
  1904         displayer.show(other)
  1932         displayer.show(other)
  1905         ui.write(_('base: '))
  1933         ui.write(_('base: '))
  1906         displayer.show(base)
  1934         displayer.show(base)
  1907     if confirm and ui.prompt('perform evolve? [Ny]', 'n') != 'y':
  1935     if confirm and ui.prompt(_('perform evolve? [Ny]'), 'n') != 'y':
  1908         raise util.Abort(_('evolve aborted by user'))
  1936         raise util.Abort(_('evolve aborted by user'))
  1909     if dryrun:
  1937     if dryrun:
  1910         ui.write('hg update -c %s &&\n' % divergent)
  1938         ui.write('hg update -c %s &&\n' % divergent)
  1911         ui.write('hg merge %s &&\n' % other)
  1939         ui.write('hg merge %s &&\n' % other)
  1912         ui.write('hg commit -m "auto merge resolving conflict between '
  1940         ui.write('hg commit -m "auto merge resolving conflict between '
  1982 
  2010 
  1983 shorttemplate = '[{rev}] {desc|firstline}\n'
  2011 shorttemplate = '[{rev}] {desc|firstline}\n'
  1984 
  2012 
  1985 @command('^previous',
  2013 @command('^previous',
  1986          [('B', 'move-bookmark', False,
  2014          [('B', 'move-bookmark', False,
  1987              _('Move active bookmark after update')),
  2015              _('move active bookmark after update')),
  1988           ('', 'merge', False, _('bring uncommited change along'))],
  2016           ('', 'merge', False, _('bring uncommitted change along')),
  1989          '[-B]')
  2017           ('n', 'dry-run', False, _('do not perform actions, just print what would be done'))],
       
  2018          '[OPTION]...')
  1990 def cmdprevious(ui, repo, **opts):
  2019 def cmdprevious(ui, repo, **opts):
  1991     """update to parent and display summary lines"""
  2020     """update to parent and display summary lines"""
  1992     wkctx = repo[None]
  2021     wkctx = repo[None]
  1993     wparents = wkctx.parents()
  2022     wparents = wkctx.parents()
       
  2023     dryrunopt = opts['dry_run']
  1994     if len(wparents) != 1:
  2024     if len(wparents) != 1:
  1995         raise util.Abort('merge in progress')
  2025         raise util.Abort('merge in progress')
  1996     if not opts['merge']:
  2026     if not opts['merge']:
  1997         try:
  2027         try:
  1998             cmdutil.bailifchanged(repo)
  2028             cmdutil.bailifchanged(repo)
  2004     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  2034     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  2005     if len(parents) == 1:
  2035     if len(parents) == 1:
  2006         p = parents[0]
  2036         p = parents[0]
  2007         bm = bmactive(repo)
  2037         bm = bmactive(repo)
  2008         shouldmove = opts.get('move_bookmark') and bm is not None
  2038         shouldmove = opts.get('move_bookmark') and bm is not None
  2009         ret = hg.update(repo, p.rev())
  2039         if dryrunopt:
  2010         if not ret:
  2040             ui.write('hg update %s;\n' % p.rev())
  2011             wlock = repo.wlock()
  2041             if shouldmove:
  2012             try:
  2042                 ui.write('hg bookmark %s -r %s;\n' % (bm, p.rev()))
  2013                 if shouldmove:
  2043         else:
  2014                     repo._bookmarks[bm] = p.node()
  2044             ret = hg.update(repo, p.rev())
  2015                     repo._bookmarks.write()
  2045             if not ret:
  2016                 else:
  2046                 wlock = repo.wlock()
  2017                     bmdeactivate(repo)
  2047                 try:
  2018             finally:
  2048                     if shouldmove:
  2019                 wlock.release()
  2049                         repo._bookmarks[bm] = p.node()
       
  2050                         repo._bookmarks.write()
       
  2051                     else:
       
  2052                         bmdeactivate(repo)
       
  2053                 finally:
       
  2054                     wlock.release()
  2020         displayer.show(p)
  2055         displayer.show(p)
  2021         return 0
  2056         return 0
  2022     else:
  2057     else:
  2023         for p in parents:
  2058         for p in parents:
  2024             displayer.show(p)
  2059             displayer.show(p)
  2025         ui.warn(_('multiple parents, explicitly update to one\n'))
  2060         ui.warn(_('multiple parents, explicitly update to one\n'))
  2026         return 1
  2061         return 1
  2027 
  2062 
  2028 @command('^next',
  2063 @command('^next',
  2029          [('B', 'move-bookmark', False,
  2064          [('B', 'move-bookmark', False,
  2030              _('Move active bookmark after update')),
  2065              _('move active bookmark after update')),
  2031           ('', 'merge', False, _('bring uncommited change along')),
  2066           ('', 'merge', False, _('bring uncommitted change along')),
  2032           ('', 'evolve', False, _('evolve the next changeset if necessary'))],
  2067           ('', 'evolve', False, _('evolve the next changeset if necessary')),
  2033          '[-B]')
  2068           ('n', 'dry-run', False, _('do not perform actions, just print what would be done'))],
       
  2069          '[OPTION]...')
  2034 def cmdnext(ui, repo, **opts):
  2070 def cmdnext(ui, repo, **opts):
  2035     """update to next child
  2071     """update to next child
  2036 
  2072 
  2037     You can use the --evolve flag to get unstable children evolved on demand.
  2073     You can use the --evolve flag to get unstable children evolved on demand.
  2038 
  2074 
  2039     The summary line of the destination is displayed for clarity"""
  2075     The summary line of the destination is displayed for clarity"""
  2040     wkctx = repo[None]
  2076     wkctx = repo[None]
  2041     wparents = wkctx.parents()
  2077     wparents = wkctx.parents()
       
  2078     dryrunopt = opts['dry_run']
  2042     if len(wparents) != 1:
  2079     if len(wparents) != 1:
  2043         raise util.Abort('merge in progress')
  2080         raise util.Abort('merge in progress')
  2044     if not opts['merge']:
  2081     if not opts['merge']:
  2045         try:
  2082         try:
  2046             cmdutil.bailifchanged(repo)
  2083             cmdutil.bailifchanged(repo)
  2052     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  2089     displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate})
  2053     if len(children) == 1:
  2090     if len(children) == 1:
  2054         c = children[0]
  2091         c = children[0]
  2055         bm = bmactive(repo)
  2092         bm = bmactive(repo)
  2056         shouldmove = opts.get('move_bookmark') and bm is not None
  2093         shouldmove = opts.get('move_bookmark') and bm is not None
  2057         ret = hg.update(repo, c.rev())
  2094         if dryrunopt:
  2058         if not ret:
  2095             ui.write('hg update %s;\n' % c.rev())
  2059             wlock = repo.wlock()
  2096             if shouldmove:
  2060             try:
  2097                 ui.write('hg bookmark %s -r %s;\n' % (bm, c.rev()))
  2061                 if shouldmove:
  2098         else:
  2062                     repo._bookmarks[bm] = c.node()
  2099             ret = hg.update(repo, c.rev())
  2063                     repo._bookmarks.write()
  2100             if not ret:
  2064                 else:
  2101                 wlock = repo.wlock()
  2065                     bmdeactivate(repo)
  2102                 try:
  2066             finally:
  2103                     if shouldmove:
  2067                 wlock.release()
  2104                         repo._bookmarks[bm] = c.node()
       
  2105                         repo._bookmarks.write()
       
  2106                     else:
       
  2107                         bmdeactivate(repo)
       
  2108                 finally:
       
  2109                     wlock.release()
  2068         displayer.show(c)
  2110         displayer.show(c)
  2069         result = 0
  2111         result = 0
  2070     elif children:
  2112     elif children:
  2071         ui.warn("ambigious next changeset:\n")
  2113         ui.warn("ambigious next changeset:\n")
  2072         for c in children:
  2114         for c in children:
  2081                 msg = _('(%i unstable changesets to be evolved here, '
  2123                 msg = _('(%i unstable changesets to be evolved here, '
  2082                         'do you want --evolve?)\n')
  2124                         'do you want --evolve?)\n')
  2083                 ui.warn(msg % len(aspchildren))
  2125                 ui.warn(msg % len(aspchildren))
  2084             result = 1
  2126             result = 1
  2085         elif 1 < len(aspchildren):
  2127         elif 1 < len(aspchildren):
  2086             ui.warn("ambigious next (unstable) changeset:\n")
  2128             ui.warn(_("ambigious next (unstable) changeset:\n"))
  2087             for c in aspchildren:
  2129             for c in aspchildren:
  2088                 displayer.show(repo[c])
  2130                 displayer.show(repo[c])
  2089             ui.warn(_('(run "hg evolve --rev REV" on one of them)\n'))
  2131             ui.warn(_('(run "hg evolve --rev REV" on one of them)\n'))
  2090             return 1
  2132             return 1
  2091         else:
  2133         else:
  2092             cmdutil.bailifchanged(repo)
  2134             cmdutil.bailifchanged(repo)
  2093             result = _solveone(ui, repo, repo[aspchildren[0]], False,
  2135             result = _solveone(ui, repo, repo[aspchildren[0]], dryrunopt,
  2094                                False, lambda:None, category='unstable')
  2136                                False, lambda:None, category='unstable')
  2095             if not result:
  2137             if not result:
  2096                 ui.status(_('working directory now at %s\n') % repo['.'])
  2138                 ui.status(_('working directory now at %s\n') % repo['.'])
  2097             return result
  2139             return result
  2098         return 1
  2140         return 1
  2113     for m, n in marks.iteritems():
  2155     for m, n in marks.iteritems():
  2114         if m != mark and n == repo[mark].node():
  2156         if m != mark and n == repo[mark].node():
  2115             uniquebm = False
  2157             uniquebm = False
  2116             break
  2158             break
  2117     if uniquebm:
  2159     if uniquebm:
  2118         rsrevs = repo.revs("ancestors(bookmark(%s)) - "
  2160         if util.safehasattr(repair, 'stripbmrevset'):
  2119                            "ancestors(head() and not bookmark(%s)) - "
  2161             rsrevs = repair.stripbmrevset(repo, mark)
  2120                            "ancestors(bookmark() and not bookmark(%s)) - "
  2162         else:
  2121                            "obsolete()",
  2163             rsrevs = repo.revs("ancestors(bookmark(%s)) - "
  2122                            mark, mark, mark)
  2164                                "ancestors(head() and not bookmark(%s)) - "
       
  2165                                "ancestors(bookmark() and not bookmark(%s)) - "
       
  2166                                "obsolete()",
       
  2167                                mark, mark, mark)
  2123         revs = set(revs)
  2168         revs = set(revs)
  2124         revs.update(set(rsrevs))
  2169         revs.update(set(rsrevs))
  2125         revs = sorted(revs)
  2170         revs = sorted(revs)
  2126     return marks, revs
  2171     return marks, revs
  2127 
  2172 
  2155     [('n', 'new', [], _("successor changeset (DEPRECATED)")),
  2200     [('n', 'new', [], _("successor changeset (DEPRECATED)")),
  2156      ('s', 'succ', [], _("successor changeset")),
  2201      ('s', 'succ', [], _("successor changeset")),
  2157      ('r', 'rev', [], _("revisions to prune")),
  2202      ('r', 'rev', [], _("revisions to prune")),
  2158      ('k', 'keep', None, _("does not modify working copy during prune")),
  2203      ('k', 'keep', None, _("does not modify working copy during prune")),
  2159      ('', 'biject', False, _("do a 1-1 map between rev and successor ranges")),
  2204      ('', 'biject', False, _("do a 1-1 map between rev and successor ranges")),
       
  2205      ('', 'fold', False, _("record a fold (multiple precursors, one successors)")),
       
  2206      ('', 'split', False, _("record a split (on precursor, multiple successors)")),
  2160      ('B', 'bookmark', '', _("remove revs only reachable from given"
  2207      ('B', 'bookmark', '', _("remove revs only reachable from given"
  2161                              " bookmark"))] + metadataopts,
  2208                              " bookmark"))] + metadataopts,
  2162     _('[OPTION] [-r] REV...'))
  2209     _('[OPTION] [-r] REV...'))
  2163     # -U  --noupdate option to prevent wc update and or bookmarks update ?
  2210     # -U  --noupdate option to prevent wc update and or bookmarks update ?
  2164 def cmdprune(ui, repo, *revs, **opts):
  2211 def cmdprune(ui, repo, *revs, **opts):
  2177 
  2224 
  2178     You can use the ``--biject`` option to specify a 1-1 (bijection) between
  2225     You can use the ``--biject`` option to specify a 1-1 (bijection) between
  2179     revisions to prune and successor changesets. This option may be removed in
  2226     revisions to prune and successor changesets. This option may be removed in
  2180     a future release (with the functionality absorbed automatically).
  2227     a future release (with the functionality absorbed automatically).
  2181 
  2228 
       
  2229     If you specify multiple revisions in --succ, you are recording a "split"
       
  2230     and have to acknowledge it by usng --split. The same logic apply when you
       
  2231     prune multiple changesets with a single successors, this will record a
       
  2232     "fold" requires a --fold flag.
  2182     """
  2233     """
  2183     revs = scmutil.revrange(repo, list(revs) + opts.get('rev'))
  2234     revs = scmutil.revrange(repo, list(revs) + opts.get('rev'))
  2184     succs = opts['new'] + opts['succ']
  2235     succs = opts['new'] + opts['succ']
  2185     bookmark = opts.get('bookmark')
  2236     bookmark = opts.get('bookmark')
  2186     metadata = _getmetadata(**opts)
  2237     metadata = _getmetadata(**opts)
  2187     biject = opts.get('biject')
  2238     biject = opts.get('biject')
       
  2239     fold = opts.get('fold')
       
  2240     split = opts.get('split')
       
  2241 
       
  2242     options = [o for o in ('biject', 'fold', 'split') if opts.get(o)]
       
  2243     if 1 < len(options):
       
  2244         raise util.Abort(_("can only specify one of %s") % ', '.join(options))
  2188 
  2245 
  2189     if bookmark:
  2246     if bookmark:
  2190         marks,revs = _reachablefrombookmark(repo, revs, bookmark)
  2247         marks,revs = _reachablefrombookmark(repo, revs, bookmark)
  2191         if not revs:
  2248         if not revs:
  2192             # no revisions to prune - delete bookmark immediately
  2249             # no revisions to prune - delete bookmark immediately
  2222         sucs.sort()
  2279         sucs.sort()
  2223         sucs = tuple(repo[n] for n in sucs)
  2280         sucs = tuple(repo[n] for n in sucs)
  2224         if not biject and len(sucs) > 1 and len(precs) > 1:
  2281         if not biject and len(sucs) > 1 and len(precs) > 1:
  2225             msg = "Can't use multiple successors for multiple precursors"
  2282             msg = "Can't use multiple successors for multiple precursors"
  2226             raise util.Abort(msg)
  2283             raise util.Abort(msg)
  2227 
  2284         elif biject and len(sucs) != len(precs):
  2228         if biject and len(sucs) != len(precs):
       
  2229             msg = "Can't use %d successors for %d precursors" \
  2285             msg = "Can't use %d successors for %d precursors" \
  2230                 % (len(sucs), len(precs))
  2286                 % (len(sucs), len(precs))
  2231             raise util.Abort(msg)
  2287             raise util.Abort(msg)
  2232 
  2288         elif (len(precs) == 1 and len(sucs) > 1) and not split:
  2233         relations = [(p, sucs) for p in precs]
  2289             msg = "please add --split if you want to do a split"
  2234         if biject:
  2290             raise util.Abort(msg)
       
  2291         elif len(sucs) == 1 and len(precs) > 1 and not fold:
       
  2292             msg = "please add --fold if you want to do a fold"
       
  2293             raise util.Abort(msg)
       
  2294         elif biject:
  2235             relations = [(p, (s,)) for p, s in zip(precs, sucs)]
  2295             relations = [(p, (s,)) for p, s in zip(precs, sucs)]
       
  2296         else:
       
  2297             relations = [(p, sucs) for p in precs]
  2236 
  2298 
  2237         wdp = repo['.']
  2299         wdp = repo['.']
  2238 
  2300 
  2239         if len(sucs) == 1 and len(precs) == 1 and wdp in precs:
  2301         if len(sucs) == 1 and len(precs) == 1 and wdp in precs:
  2240             # '.' killed, so update to the successor
  2302             # '.' killed, so update to the successor
  2264                 # reset files that only changed in the dirstate too
  2326                 # reset files that only changed in the dirstate too
  2265                 dirstate = repo.dirstate
  2327                 dirstate = repo.dirstate
  2266                 dirchanges = [f for f in dirstate if dirstate[f] != 'n']
  2328                 dirchanges = [f for f in dirstate if dirstate[f] != 'n']
  2267                 changedfiles.extend(dirchanges)
  2329                 changedfiles.extend(dirchanges)
  2268                 repo.dirstate.rebuild(newnode.node(), newnode.manifest(), changedfiles)
  2330                 repo.dirstate.rebuild(newnode.node(), newnode.manifest(), changedfiles)
  2269                 repo.dirstate.write()
  2331                 writedirstate(dirstate, tr)
  2270             else:
  2332             else:
  2271                 bookactive = bmactive(repo)
  2333                 bookactive = bmactive(repo)
  2272                 # Active bookmark that we don't want to delete (with -B option)
  2334                 # Active bookmark that we don't want to delete (with -B option)
  2273                 # we deactivate and move it before the update and reactivate it
  2335                 # we deactivate and move it before the update and reactivate it
  2274                 # after
  2336                 # after
  2301             #
  2363             #
  2302             # but then revset took a lazy arrow in the knee and became much
  2364             # but then revset took a lazy arrow in the knee and became much
  2303             # slower. The new forms makes as much sense and a much faster.
  2365             # slower. The new forms makes as much sense and a much faster.
  2304             for dest in ctx.ancestors():
  2366             for dest in ctx.ancestors():
  2305                 if not dest.obsolete():
  2367                 if not dest.obsolete():
  2306                     updatebookmarks = _bookmarksupdater(repo, ctx.node())
  2368                     updatebookmarks = _bookmarksupdater(repo, ctx.node(), tr)
  2307                     updatebookmarks(dest.node())
  2369                     updatebookmarks(dest.node())
  2308                     break
  2370                     break
  2309 
  2371 
  2310         tr.close()
  2372         tr.close()
  2311     finally:
  2373     finally:
  2486         if old.phase() == phases.public:
  2548         if old.phase() == phases.public:
  2487             raise util.Abort(_("cannot rewrite immutable changeset"))
  2549             raise util.Abort(_("cannot rewrite immutable changeset"))
  2488         if len(old.parents()) > 1:
  2550         if len(old.parents()) > 1:
  2489             raise util.Abort(_("cannot uncommit merge changeset"))
  2551             raise util.Abort(_("cannot uncommit merge changeset"))
  2490         oldphase = old.phase()
  2552         oldphase = old.phase()
  2491         updatebookmarks = _bookmarksupdater(repo, old.node())
       
  2492 
  2553 
  2493 
  2554 
  2494         rev = None
  2555         rev = None
  2495         if opts.get('rev'):
  2556         if opts.get('rev'):
  2496             rev = scmutil.revsingle(repo, opts.get('rev'))
  2557             rev = scmutil.revsingle(repo, opts.get('rev'))
  2503         if disallowunstable and not onahead:
  2564         if disallowunstable and not onahead:
  2504             raise util.Abort(_("cannot uncommit in the middle of a stack"))
  2565             raise util.Abort(_("cannot uncommit in the middle of a stack"))
  2505 
  2566 
  2506         # Recommit the filtered changeset
  2567         # Recommit the filtered changeset
  2507         tr = repo.transaction('uncommit')
  2568         tr = repo.transaction('uncommit')
       
  2569         updatebookmarks = _bookmarksupdater(repo, old.node(), tr)
  2508         newid = None
  2570         newid = None
  2509         includeorexclude = opts.get('include') or opts.get('exclude')
  2571         includeorexclude = opts.get('include') or opts.get('exclude')
  2510         if (pats or includeorexclude or opts.get('all')):
  2572         if (pats or includeorexclude or opts.get('all')):
  2511             match = scmutil.match(old, pats, opts)
  2573             match = scmutil.match(old, pats, opts)
  2512             newid = _commitfiltered(repo, old, match, target=rev)
  2574             newid = _commitfiltered(repo, old, match, target=rev)
  2554             if oldbookmarks:
  2616             if oldbookmarks:
  2555                 repo._bookmarks.write()
  2617                 repo._bookmarks.write()
  2556         return result
  2618         return result
  2557     finally:
  2619     finally:
  2558         lockmod.release(lock, wlock)
  2620         lockmod.release(lock, wlock)
       
  2621 
       
  2622 @command('^split',
       
  2623     [('r', 'rev', [], _("revision to fold")),
       
  2624     ] + commitopts + commitopts2,
       
  2625     _('hg split [OPTION]... [-r] REV'))
       
  2626 def cmdsplit(ui, repo, *revs, **opts):
       
  2627     """Split the current commit using interactive selection (EXPERIMENTAL)
       
  2628 
       
  2629     By default, split the current revision by prompting for all its hunk to be
       
  2630     redistributed into new changesets.
       
  2631 
       
  2632     Use --rev for splitting a given changeset instead.
       
  2633     """
       
  2634     tr = wlock = lock = None
       
  2635     newcommits = []
       
  2636 
       
  2637     revopt = opts.get('rev')
       
  2638     if revopt:
       
  2639         revs = scmutil.revrange(repo, revopt)
       
  2640         if len(revs) != 1:
       
  2641             raise util.Abort(_("you can only specify one revision to split"))
       
  2642         else:
       
  2643             rev = list(revs)[0]
       
  2644     else:
       
  2645         rev = '.'
       
  2646 
       
  2647     try:
       
  2648         wlock = repo.wlock()
       
  2649         lock = repo.lock()
       
  2650         cmdutil.bailifchanged(repo)
       
  2651         tr = repo.transaction('split')
       
  2652         ctx = repo[rev]
       
  2653         r = ctx.rev()
       
  2654         disallowunstable = not obsolete.isenabled(repo,
       
  2655                                                   obsolete.allowunstableopt)
       
  2656         if disallowunstable:
       
  2657             # XXX We should check head revs
       
  2658             if repo.revs("(%d::) - %d", rev, rev):
       
  2659                 raise util.Abort(_("cannot split commit: %s not a head") % ctx)
       
  2660 
       
  2661         if len(ctx.parents()) > 1:
       
  2662             raise util.Abort(_("cannot split merge commits"))
       
  2663         prev = ctx.p1()
       
  2664         bmupdate = _bookmarksupdater(repo, ctx.node(), tr)
       
  2665         bookactive = bmactive(repo)
       
  2666         if bookactive is not None:
       
  2667             repo.ui.status(_("(leaving bookmark %s)\n") % bmactive(repo))
       
  2668         bmdeactivate(repo)
       
  2669         hg.update(repo, prev)
       
  2670 
       
  2671         commands.revert(ui, repo, rev=r, all=True)
       
  2672         def haschanges():
       
  2673             modified, added, removed, deleted = repo.status()[:4]
       
  2674             return modified or added or removed or deleted
       
  2675         while haschanges():
       
  2676             pats = ()
       
  2677             cmdutil.dorecord(ui, repo, commands.commit, 'commit', False,
       
  2678                              cmdutil.recordfilter, *pats, **opts)
       
  2679             # TODO: Does no seem like the best way to do this
       
  2680             # We should make dorecord return the newly created commit
       
  2681             newcommits.append(repo['.'])
       
  2682             if haschanges():
       
  2683                 if ui.prompt('Done splitting? [yN]', default='n') == 'y':
       
  2684                     commands.commit(ui, repo, **opts)
       
  2685                     newcommits.append(repo['.'])
       
  2686                     break
       
  2687             else:
       
  2688                 ui.status("no more change to split\n")
       
  2689 
       
  2690         tip = repo[newcommits[-1]]
       
  2691         bmupdate(tip.node())
       
  2692         if bookactive is not None:
       
  2693             bmactivate(repo, bookactive)
       
  2694         obsolete.createmarkers(repo, [(repo[r], newcommits)])
       
  2695         tr.close()
       
  2696     finally:
       
  2697         lockmod.release(tr, lock, wlock)
       
  2698 
  2559 
  2699 
  2560 @eh.wrapcommand('strip', extension='strip', opts=[
  2700 @eh.wrapcommand('strip', extension='strip', opts=[
  2561     ('', 'bundle', None, _("delete the commit entirely and move it to a "
  2701     ('', 'bundle', None, _("delete the commit entirely and move it to a "
  2562         "backup bundle")),
  2702         "backup bundle")),
  2563     ])
  2703     ])
  2938     cl = local.changelog
  3078     cl = local.changelog
  2939     dag = dagutil.revlogdag(cl)
  3079     dag = dagutil.revlogdag(cl)
  2940     missing = set()
  3080     missing = set()
  2941     common = set()
  3081     common = set()
  2942     undecided = set(probeset)
  3082     undecided = set(probeset)
       
  3083     totalnb = len(undecided)
       
  3084     ui.progress("comparing with other", 0, total=totalnb)
  2943     _takefullsample = setdiscovery._takefullsample
  3085     _takefullsample = setdiscovery._takefullsample
  2944     if remote.capable('_evoext_obshash_1'):
  3086     if remote.capable('_evoext_obshash_1'):
  2945         getremotehash = remote.evoext_obshash1
  3087         getremotehash = remote.evoext_obshash1
  2946         localhash = _obsrelsethashtreefm1(local)
  3088         localhash = _obsrelsethashtreefm1(local)
  2947     else:
  3089     else:
  2955             sample = set(undecided)
  3097             sample = set(undecided)
  2956         else:
  3098         else:
  2957             sample = _takefullsample(dag, undecided, size=fullsamplesize)
  3099             sample = _takefullsample(dag, undecided, size=fullsamplesize)
  2958 
  3100 
  2959         roundtrips += 1
  3101         roundtrips += 1
       
  3102         ui.progress("comparing with other", totalnb - len(undecided),
       
  3103                     total=totalnb)
  2960         ui.debug("query %i; still undecided: %i, sample size is: %i\n"
  3104         ui.debug("query %i; still undecided: %i, sample size is: %i\n"
  2961                  % (roundtrips, len(undecided), len(sample)))
  3105                  % (roundtrips, len(undecided), len(sample)))
  2962         # indices between sample and externalized version must match
  3106         # indices between sample and externalized version must match
  2963         sample = list(sample)
  3107         sample = list(sample)
  2964         remotehash = getremotehash(dag.externalizeall(sample))
  3108         remotehash = getremotehash(dag.externalizeall(sample))
  2974 
  3118 
  2975         undecided.difference_update(missing)
  3119         undecided.difference_update(missing)
  2976         undecided.difference_update(common)
  3120         undecided.difference_update(common)
  2977 
  3121 
  2978 
  3122 
       
  3123     ui.progress("comparing with other", None, total=totalnb)
  2979     result = dag.headsetofconnecteds(common)
  3124     result = dag.headsetofconnecteds(common)
  2980     ui.debug("%d total queries\n" % roundtrips)
  3125     ui.debug("%d total queries\n" % roundtrips)
  2981 
  3126 
  2982     if not result:
  3127     if not result:
  2983         return set([nullid])
  3128         return set([nullid])
  3292 
  3437 
  3293 def _obsrelsethashtree(repo, encodeonemarker):
  3438 def _obsrelsethashtree(repo, encodeonemarker):
  3294     cache = []
  3439     cache = []
  3295     unfi = repo.unfiltered()
  3440     unfi = repo.unfiltered()
  3296     markercache = {}
  3441     markercache = {}
       
  3442     repo.ui.progress("preparing locally", 0, total=len(unfi))
  3297     for i in unfi:
  3443     for i in unfi:
  3298         ctx = unfi[i]
  3444         ctx = unfi[i]
  3299         entry = 0
  3445         entry = 0
  3300         sha = util.sha1()
  3446         sha = util.sha1()
  3301         # add data from p1
  3447         # add data from p1
  3321                 sha.update(m)
  3467                 sha.update(m)
  3322         if entry:
  3468         if entry:
  3323             cache.append((ctx.node(), sha.digest()))
  3469             cache.append((ctx.node(), sha.digest()))
  3324         else:
  3470         else:
  3325             cache.append((ctx.node(), nullid))
  3471             cache.append((ctx.node(), nullid))
       
  3472         repo.ui.progress("preparing locally", i, total=len(unfi))
       
  3473     repo.ui.progress("preparing locally", None)
  3326     return cache
  3474     return cache
  3327 
  3475 
  3328 @command('debugobsrelsethashtree',
  3476 @command('debugobsrelsethashtree',
  3329         [('', 'v0', None, 'hash on marker format "0"'),
  3477         [('', 'v0', None, 'hash on marker format "0"'),
  3330          ('', 'v1', None, 'hash on marker format "1" (default)')
  3478          ('', 'v1', None, 'hash on marker format "1" (default)')
  3366 @command(
  3514 @command(
  3367     'debugobsconvert',
  3515     'debugobsconvert',
  3368     [('', 'new-format', _bestformat, _('Destination format for markers.'))],
  3516     [('', 'new-format', _bestformat, _('Destination format for markers.'))],
  3369     '')
  3517     '')
  3370 def debugobsconvert(ui, repo, new_format):
  3518 def debugobsconvert(ui, repo, new_format):
       
  3519     origmarkers = repo.obsstore._all  # settle version
  3371     if new_format == repo.obsstore._version:
  3520     if new_format == repo.obsstore._version:
  3372         msg = _('New format is the same as the old format, not upgrading!')
  3521         msg = _('New format is the same as the old format, not upgrading!')
  3373         raise util.Abort(msg)
  3522         raise util.Abort(msg)
  3374     f = repo.svfs('obsstore', 'wb', atomictemp=True)
  3523     f = repo.svfs('obsstore', 'wb', atomictemp=True)
  3375     origmarkers = repo.obsstore._all
       
  3376     known = set()
  3524     known = set()
  3377     markers = []
  3525     markers = []
  3378     for m in origmarkers:
  3526     for m in origmarkers:
  3379         # filter out invalid markers
  3527         # filter out invalid markers
  3380         if nullid in m[1]:
  3528         if nullid in m[1]:
  3416     oldcap, args = wireproto.commands['capabilities']
  3564     oldcap, args = wireproto.commands['capabilities']
  3417     def newcap(repo, proto):
  3565     def newcap(repo, proto):
  3418         return capabilities(oldcap, repo, proto)
  3566         return capabilities(oldcap, repo, proto)
  3419     wireproto.commands['capabilities'] = (newcap, args)
  3567     wireproto.commands['capabilities'] = (newcap, args)
  3420 
  3568 
  3421 def _helploader():
  3569 # Mercurial >= 3.6 passes ui
       
  3570 def _helploader(ui=None):
  3422     return help.gettext(evolutionhelptext)
  3571     return help.gettext(evolutionhelptext)
  3423 
  3572 
  3424 @eh.uisetup
  3573 @eh.uisetup
  3425 def _setuphelp(ui):
  3574 def _setuphelp(ui):
  3426     for entry in help.helptable:
  3575     for entry in help.helptable: