hgext/rebase.py
changeset 35388 dd11df900f7f
parent 35384 b9bdee046cc2
child 35410 83014fa95435
equal deleted inserted replaced
35387:c0c6df81c9bb 35388:dd11df900f7f
   134         desc += ' (%s)' % ' '.join(names)
   134         desc += ' (%s)' % ' '.join(names)
   135     return desc
   135     return desc
   136 
   136 
   137 class rebaseruntime(object):
   137 class rebaseruntime(object):
   138     """This class is a container for rebase runtime state"""
   138     """This class is a container for rebase runtime state"""
   139     def __init__(self, repo, ui, opts=None):
   139     def __init__(self, repo, ui, inmemory=False, opts=None):
   140         if opts is None:
   140         if opts is None:
   141             opts = {}
   141             opts = {}
   142 
   142 
   143         # prepared: whether we have rebasestate prepared or not. Currently it
   143         # prepared: whether we have rebasestate prepared or not. Currently it
   144         # decides whether "self.repo" is unfiltered or not.
   144         # decides whether "self.repo" is unfiltered or not.
   177         # keepopen is not meant for use on the command line, but by
   177         # keepopen is not meant for use on the command line, but by
   178         # other extensions
   178         # other extensions
   179         self.keepopen = opts.get('keepopen', False)
   179         self.keepopen = opts.get('keepopen', False)
   180         self.obsoletenotrebased = {}
   180         self.obsoletenotrebased = {}
   181         self.obsoletewithoutsuccessorindestination = set()
   181         self.obsoletewithoutsuccessorindestination = set()
   182         self.inmemory = opts.get('inmemory', False)
   182         self.inmemory = inmemory
   183 
   183 
   184     @property
   184     @property
   185     def repo(self):
   185     def repo(self):
   186         if self.prepared:
   186         if self.prepared:
   187             return self._repo.unfiltered()
   187             return self._repo.unfiltered()
   643     ('', 'keepbranches', False, _('keep original branch names')),
   643     ('', 'keepbranches', False, _('keep original branch names')),
   644     ('D', 'detach', False, _('(DEPRECATED)')),
   644     ('D', 'detach', False, _('(DEPRECATED)')),
   645     ('i', 'interactive', False, _('(DEPRECATED)')),
   645     ('i', 'interactive', False, _('(DEPRECATED)')),
   646     ('t', 'tool', '', _('specify merge tool')),
   646     ('t', 'tool', '', _('specify merge tool')),
   647     ('c', 'continue', False, _('continue an interrupted rebase')),
   647     ('c', 'continue', False, _('continue an interrupted rebase')),
   648     ('',  'inmemory', False, _('run rebase in-memory (EXPERIMENTAL)')),
       
   649     ('a', 'abort', False, _('abort an interrupted rebase'))] +
   648     ('a', 'abort', False, _('abort an interrupted rebase'))] +
   650     cmdutil.formatteropts,
   649     cmdutil.formatteropts,
   651     _('[-s REV | -b REV] [-d REV] [OPTION]'))
   650     _('[-s REV | -b REV] [-d REV] [OPTION]'))
   652 def rebase(ui, repo, **opts):
   651 def rebase(ui, repo, **opts):
   653     """move changeset (and descendants) to a different branch
   652     """move changeset (and descendants) to a different branch
   755     unexpectedly::
   754     unexpectedly::
   756 
   755 
   757       [rebase]
   756       [rebase]
   758       singletransaction = True
   757       singletransaction = True
   759 
   758 
       
   759     By default, rebase writes to the working copy, but you can configure it to
       
   760     run in-memory for for better performance, and to allow it to run if the
       
   761     working copy is dirty::
       
   762 
       
   763       [rebase]
       
   764       experimental.inmemory = True
       
   765 
   760     Return Values:
   766     Return Values:
   761 
   767 
   762     Returns 0 on success, 1 if nothing to rebase or there are
   768     Returns 0 on success, 1 if nothing to rebase or there are
   763     unresolved conflicts.
   769     unresolved conflicts.
   764 
   770 
   765     """
   771     """
       
   772     inmemory = ui.configbool('rebase', 'experimental.inmemory')
   766     if opts.get('continue') or opts.get('abort'):
   773     if opts.get('continue') or opts.get('abort'):
   767         # in-memory rebase is not compatible with resuming rebases.
   774         # in-memory rebase is not compatible with resuming rebases.
   768         opts['inmemory'] = False
   775         inmemory = False
   769 
   776 
   770     if opts.get('inmemory', False):
   777     if inmemory:
   771         try:
   778         try:
   772             # in-memory merge doesn't support conflicts, so if we hit any, abort
   779             # in-memory merge doesn't support conflicts, so if we hit any, abort
   773             # and re-run as an on-disk merge.
   780             # and re-run as an on-disk merge.
   774             return _origrebase(ui, repo, **opts)
   781             return _origrebase(ui, repo, inmemory=inmemory, **opts)
   775         except error.InMemoryMergeConflictsError:
   782         except error.InMemoryMergeConflictsError:
   776             ui.warn(_('hit merge conflicts; re-running rebase without in-memory'
   783             ui.warn(_('hit merge conflicts; re-running rebase without in-memory'
   777                       ' merge\n'))
   784                       ' merge\n'))
   778             _origrebase(ui, repo, **{'abort': True})
   785             _origrebase(ui, repo, **{'abort': True})
   779             opts['inmemory'] = False
   786             return _origrebase(ui, repo, inmemory=False, **opts)
   780             return _origrebase(ui, repo, **opts)
       
   781     else:
   787     else:
   782         return _origrebase(ui, repo, **opts)
   788         return _origrebase(ui, repo, **opts)
   783 
   789 
   784 def _origrebase(ui, repo, **opts):
   790 def _origrebase(ui, repo, inmemory=False, **opts):
   785     opts = pycompat.byteskwargs(opts)
   791     opts = pycompat.byteskwargs(opts)
   786     if 'inmemory' not in opts:
   792     rbsrt = rebaseruntime(repo, ui, inmemory, opts)
   787         opts['inmemory'] = False
       
   788     rbsrt = rebaseruntime(repo, ui, opts)
       
   789 
   793 
   790     with repo.wlock(), repo.lock():
   794     with repo.wlock(), repo.lock():
   791         # Validate input and define rebasing points
   795         # Validate input and define rebasing points
   792         destf = opts.get('dest', None)
   796         destf = opts.get('dest', None)
   793         srcf = opts.get('source', None)
   797         srcf = opts.get('source', None)
   830 
   834 
   831             retcode = rbsrt._prepareabortorcontinue(abortf)
   835             retcode = rbsrt._prepareabortorcontinue(abortf)
   832             if retcode is not None:
   836             if retcode is not None:
   833                 return retcode
   837                 return retcode
   834         else:
   838         else:
   835             destmap = _definedestmap(ui, repo, destf, srcf, basef, revf,
   839             destmap = _definedestmap(ui, repo, rbsrt, destf, srcf, basef, revf,
   836                                      destspace=destspace,
   840                                      destspace=destspace)
   837                                      opts=opts)
       
   838             rbsrt.inmemory = opts['inmemory']
       
   839             retcode = rbsrt._preparenewrebase(destmap)
   841             retcode = rbsrt._preparenewrebase(destmap)
   840             if retcode is not None:
   842             if retcode is not None:
   841                 return retcode
   843                 return retcode
   842 
   844 
   843         tr = None
   845         tr = None
   852             with util.acceptintervention(dsguard):
   854             with util.acceptintervention(dsguard):
   853                 rbsrt._performrebase(tr)
   855                 rbsrt._performrebase(tr)
   854 
   856 
   855         rbsrt._finishrebase()
   857         rbsrt._finishrebase()
   856 
   858 
   857 def _definedestmap(ui, repo, destf=None, srcf=None, basef=None, revf=None,
   859 def _definedestmap(ui, repo, rbsrt, destf=None, srcf=None, basef=None,
   858                    destspace=None, opts=None):
   860                    revf=None, destspace=None):
   859     """use revisions argument to define destmap {srcrev: destrev}"""
   861     """use revisions argument to define destmap {srcrev: destrev}"""
   860     if revf is None:
   862     if revf is None:
   861         revf = []
   863         revf = []
   862 
   864 
   863     # destspace is here to work around issues with `hg pull --rebase` see
   865     # destspace is here to work around issues with `hg pull --rebase` see
   867     if revf and basef:
   869     if revf and basef:
   868         raise error.Abort(_('cannot specify both a revision and a base'))
   870         raise error.Abort(_('cannot specify both a revision and a base'))
   869     if revf and srcf:
   871     if revf and srcf:
   870         raise error.Abort(_('cannot specify both a revision and a source'))
   872         raise error.Abort(_('cannot specify both a revision and a source'))
   871 
   873 
   872     if not opts['inmemory']:
   874     if not rbsrt.inmemory:
   873         cmdutil.checkunfinished(repo)
   875         cmdutil.checkunfinished(repo)
   874         cmdutil.bailifchanged(repo)
   876         cmdutil.bailifchanged(repo)
   875 
   877 
   876     if ui.configbool('commands', 'rebase.requiredest') and not destf:
   878     if ui.configbool('commands', 'rebase.requiredest') and not destf:
   877         raise error.Abort(_('you must specify a destination'),
   879         raise error.Abort(_('you must specify a destination'),
   953     #
   955     #
   954     # Note that there are cases where this isn't true -- e.g., rebasing large
   956     # Note that there are cases where this isn't true -- e.g., rebasing large
   955     # stacks that include the WCP. However, I'm not yet sure where the cutoff
   957     # stacks that include the WCP. However, I'm not yet sure where the cutoff
   956     # is.
   958     # is.
   957     rebasingwcp = repo['.'].rev() in rebaseset
   959     rebasingwcp = repo['.'].rev() in rebaseset
   958     if opts['inmemory'] and rebasingwcp:
   960     if rbsrt.inmemory and rebasingwcp:
   959         opts['inmemory'] = False
   961         rbsrt.inmemory = False
   960         # Check these since we did not before.
   962         # Check these since we did not before.
   961         cmdutil.checkunfinished(repo)
   963         cmdutil.checkunfinished(repo)
   962         cmdutil.bailifchanged(repo)
   964         cmdutil.bailifchanged(repo)
   963 
   965 
   964     if not destf:
   966     if not destf: