hgext/evolve.py
changeset 1107 1c227ecb744d
parent 1097 580a2d838996
parent 1106 6b0cf1b73693
child 1108 87d60434b434
equal deleted inserted replaced
1097:580a2d838996 1107:1c227ecb744d
    20 '''
    20 '''
    21 
    21 
    22 testedwith = ''
    22 testedwith = ''
    23 buglink = 'http://bz.selenic.com/'
    23 buglink = 'http://bz.selenic.com/'
    24 
    24 
    25 import sys
    25 import sys, os
    26 import random
    26 import random
    27 from StringIO import StringIO
    27 from StringIO import StringIO
    28 import struct
    28 import struct
    29 import urllib
    29 import urllib
       
    30 import re
       
    31 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
    30 
    32 
    31 import mercurial
    33 import mercurial
    32 from mercurial import util
    34 from mercurial import util
    33 
    35 
    34 try:
    36 try:
    67 from mercurial.node import nullid
    69 from mercurial.node import nullid
    68 from mercurial import wireproto
    70 from mercurial import wireproto
    69 from mercurial import localrepo
    71 from mercurial import localrepo
    70 from mercurial.hgweb import hgweb_mod
    72 from mercurial.hgweb import hgweb_mod
    71 from mercurial import bundle2
    73 from mercurial import bundle2
       
    74 from mercurial import util
    72 
    75 
    73 cmdtable = {}
    76 cmdtable = {}
    74 command = cmdutil.command(cmdtable)
    77 command = cmdutil.command(cmdtable)
    75 
    78 
    76 _pack = struct.pack
    79 _pack = struct.pack
   374         ui.setconfig('alias', 'olog', "log -r 'precursors(.)' --hidden")
   377         ui.setconfig('alias', 'olog', "log -r 'precursors(.)' --hidden")
   375     if ui.config('alias', 'odiff', None) is None:
   378     if ui.config('alias', 'odiff', None) is None:
   376         ui.setconfig('alias', 'odiff',
   379         ui.setconfig('alias', 'odiff',
   377             "diff --hidden --rev 'limit(precursors(.),1)' --rev .")
   380             "diff --hidden --rev 'limit(precursors(.),1)' --rev .")
   378     if ui.config('alias', 'grab', None) is None:
   381     if ui.config('alias', 'grab', None) is None:
   379         ui.setconfig('alias', 'grab',
   382         if os.name == 'nt':
   380             "! $HG rebase --dest . --rev $@ && $HG up tip")
   383             ui.setconfig('alias', 'grab',
       
   384                 "! " + util.hgexecutable() + " rebase --dest . --rev  && "
       
   385                  + util.hgexecutable() + " up tip")
       
   386         else:
       
   387             ui.setconfig('alias', 'grab',
       
   388                 "! $HG rebase --dest . --rev $@ && $HG up tip")
   381 
   389 
   382 
   390 
   383 ### Troubled revset symbol
   391 ### Troubled revset symbol
   384 
   392 
   385 @eh.revset('troubled')
   393 @eh.revset('troubled')
   774             'no support for evolving merge changesets yet',
   782             'no support for evolving merge changesets yet',
   775             hint="Redo the merge and use `hg prune` to obsolete the old one")
   783             hint="Redo the merge and use `hg prune` to obsolete the old one")
   776     destbookmarks = repo.nodebookmarks(dest.node())
   784     destbookmarks = repo.nodebookmarks(dest.node())
   777     nodesrc = orig.node()
   785     nodesrc = orig.node()
   778     destphase = repo[nodesrc].phase()
   786     destphase = repo[nodesrc].phase()
       
   787     commitmsg = orig.description()
       
   788 
       
   789     cache = {}
       
   790     sha1s = re.findall(sha1re, commitmsg)
       
   791     unfi = repo.unfiltered()
       
   792     for sha1 in sha1s:
       
   793         ctx = None
       
   794         try:
       
   795             ctx = unfi[sha1]
       
   796         except error.RepoLookupError:
       
   797             continue
       
   798 
       
   799         if not ctx.obsolete():
       
   800             continue
       
   801 
       
   802         successors = obsolete.successorssets(repo, ctx.node(), cache)
       
   803 
       
   804         # We can't make any assumptions about how to update the hash if the
       
   805         # cset in question was split or diverged.
       
   806         if len(successors) == 1 and len(successors[0]) == 1:
       
   807             newsha1 = node.hex(successors[0][0])
       
   808             commitmsg = commitmsg.replace(sha1, newsha1[:len(sha1)])
       
   809         else:
       
   810             repo.ui.note(_('The stale commit message reference to %s could '
       
   811                            'not be updated') % sha1)
       
   812 
   779     tr = repo.transaction('relocate')
   813     tr = repo.transaction('relocate')
   780     try:
   814     try:
   781         try:
   815         try:
   782             r = rebase.rebasenode(repo, orig.node(), dest.node(),
   816             r = rebase.rebasenode(repo, orig.node(), dest.node(),
   783                                   {node.nullrev: node.nullrev}, False)
   817                                   {node.nullrev: node.nullrev}, False)
   784             if r[-1]: #some conflict
   818             if r[-1]: #some conflict
   785                 raise util.Abort(
   819                 raise util.Abort(
   786                         'unresolved merge conflicts (see hg help resolve)')
   820                         'unresolved merge conflicts (see hg help resolve)')
   787             cmdutil.duplicatecopies(repo, orig.node(), dest.node())
   821             cmdutil.duplicatecopies(repo, orig.node(), dest.node())
   788             nodenew = rebase.concludenode(repo, orig.node(), dest.node(),
   822             nodenew = rebase.concludenode(repo, orig.node(), dest.node(),
   789                                           node.nullid)
   823                                           node.nullid, commitmsg)
   790         except util.Abort, exc:
   824         except util.Abort, exc:
   791             class LocalMergeFailure(MergeFailure, exc.__class__):
   825             class LocalMergeFailure(MergeFailure, exc.__class__):
   792                 pass
   826                 pass
   793             exc.__class__ = LocalMergeFailure
   827             exc.__class__ = LocalMergeFailure
   794             raise
   828             raise
  1110     allopt = opts['all']
  1144     allopt = opts['all']
  1111     dryrunopt = opts['dry_run']
  1145     dryrunopt = opts['dry_run']
  1112     confirmopt = opts['confirm']
  1146     confirmopt = opts['confirm']
  1113     ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve')
  1147     ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve')
  1114 
  1148 
       
  1149     startnode = repo['.']
       
  1150 
  1115     if contopt:
  1151     if contopt:
  1116         if anyopt:
  1152         if anyopt:
  1117             raise util.Abort('cannot specify both "--any" and "--continue"')
  1153             raise util.Abort('cannot specify both "--any" and "--continue"')
  1118         if allopt:
  1154         if allopt:
  1119             raise util.Abort('cannot specify both "--all" and "--continue"')
  1155             raise util.Abort('cannot specify both "--all" and "--continue"')
  1153 
  1189 
  1154                 if dryrunopt:
  1190                 if dryrunopt:
  1155                     print 'hg update %s' % ctx.rev()
  1191                     print 'hg update %s' % ctx.rev()
  1156                     return 0
  1192                     return 0
  1157                 else:
  1193                 else:
  1158                     return hg.update(repo, ctx.rev())
  1194                     res = hg.update(repo, ctx.rev())
       
  1195                     if ctx != startnode:
       
  1196                         ui.status(_('working directory is now at %s\n') % ctx)
       
  1197                     return res
  1159 
  1198 
  1160         troubled = repo.revs('troubled()')
  1199         troubled = repo.revs('troubled()')
  1161         if troubled:
  1200         if troubled:
  1162             ui.write_err(_('nothing to evolve here\n'))
  1201             ui.write_err(_('nothing to evolve here\n'))
  1163             ui.status(_('(%i troubled changesets, do you want --any ?)\n')
  1202             ui.status(_('(%i troubled changesets, do you want --any ?)\n')
  1186         finally:
  1225         finally:
  1187             lockmod.release(tr, lock, wlock)
  1226             lockmod.release(tr, lock, wlock)
  1188         progresscb()
  1227         progresscb()
  1189         seen += 1
  1228         seen += 1
  1190         if not allopt:
  1229         if not allopt:
       
  1230             if repo['.'] != startnode:
       
  1231                 ui.status(_('working directory is now at %s\n') % repo['.'])
  1191             return result
  1232             return result
  1192         progresscb()
  1233         progresscb()
  1193         tro = _picknexttroubled(ui, repo, anyopt or allopt)
  1234         tro = _picknexttroubled(ui, repo, anyopt or allopt)
  1194 
  1235 
  1195     if allopt:
  1236     if allopt:
  1196         ui.progress('evolve', None)
  1237         ui.progress('evolve', None)
       
  1238 
       
  1239     if repo['.'] != startnode:
       
  1240         ui.status(_('working directory is now at %s\n') % repo['.'])
  1197 
  1241 
  1198 
  1242 
  1199 def _evolveany(ui, repo, tro, dryrunopt, confirmopt, progresscb):
  1243 def _evolveany(ui, repo, tro, dryrunopt, confirmopt, progresscb):
  1200     repo = repo.unfiltered()
  1244     repo = repo.unfiltered()
  1201     tro = repo[tro.rev()]
  1245     tro = repo[tro.rev()]
  1731             ui.status(_('working directory now at %s\n') % newnode)
  1775             ui.status(_('working directory now at %s\n') % newnode)
  1732         # update bookmarks
  1776         # update bookmarks
  1733         if bookmark:
  1777         if bookmark:
  1734             _deletebookmark(ui, marks, bookmark)
  1778             _deletebookmark(ui, marks, bookmark)
  1735         for ctx in repo.unfiltered().set('bookmark() and %ld', precs):
  1779         for ctx in repo.unfiltered().set('bookmark() and %ld', precs):
  1736             ldest = list(repo.set('max((::%d) - obsolete())', ctx))
  1780             # used to be:
  1737             if ldest:
  1781             #
  1738                 dest = ldest[0]
  1782             #   ldest = list(repo.set('max((::%d) - obsolete())', ctx))
  1739                 updatebookmarks = _bookmarksupdater(repo, ctx.node())
  1783             #   if ldest:
  1740                 updatebookmarks(dest.node())
  1784             #      c = ldest[0]
       
  1785             #
       
  1786             # but then revset took a lazy arrow in the knee and became much
       
  1787             # slower. The new forms makes as much sense and a much faster.
       
  1788             for dest in ctx.ancestors():
       
  1789                 if not dest.obsolete():
       
  1790                     updatebookmarks = _bookmarksupdater(repo, ctx.node())
       
  1791                     updatebookmarks(dest.node())
       
  1792                     break
  1741     finally:
  1793     finally:
  1742         lockmod.release(lock, wlock)
  1794         lockmod.release(lock, wlock)
  1743 
  1795 
  1744 @command('amend|refresh',
  1796 @command('amend|refresh',
  1745     [('A', 'addremove', None,
  1797     [('A', 'addremove', None,