D3959: rebase: add --stop option to stop rebase at any point (issue5206)

khanchi97 (Sushil khanchi) phabricator at mercurial-scm.org
Tue Jul 17 19:43:35 UTC 2018


khanchi97 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Before this patch, during a rebase if you get a point where you can't
  figure out what to do next then either you had to complete your series
  or abandon all the work you have done during this rebase.
  
  Now, with this feature you can stop at any point by keeping the rebased
  csets and mark original csets as obsolete. And if you have not enabled
  evolution extension then you can use --keep option as an alternative
  which will keep original csets too, instead of marking them obsolete.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3959

AFFECTED FILES
  hgext/rebase.py
  tests/test-rebase-obsolete.t

CHANGE DETAILS

diff --git a/tests/test-rebase-obsolete.t b/tests/test-rebase-obsolete.t
--- a/tests/test-rebase-obsolete.t
+++ b/tests/test-rebase-obsolete.t
@@ -15,6 +15,7 @@
   > [extensions]
   > rebase=
   > drawdag=$TESTDIR/drawdag.py
+  > strip=
   > EOF
 
 Setup rebase canonical repo
@@ -1788,3 +1789,155 @@
   |
   o  0:426bada5c675 A
   
+====================
+Test --stop option |
+====================
+  $ cd ..
+  $ hg init rbstop
+  $ cd rbstop
+  $ echo a>a
+  $ hg ci -Aqma
+  $ echo b>b
+  $ hg ci -Aqmb
+  $ echo c>c
+  $ hg ci -Aqmc
+  $ echo d>d
+  $ hg ci -Aqmd
+  $ hg up 0 -q
+  $ echo f>f
+  $ hg ci -Aqmf
+  $ echo D>d
+  $ hg ci -Aqm "conflict with d"
+  $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
+  @  5:00bfc9898aeb test
+  |  conflict with d
+  |
+  o  4:dafd40200f93 test
+  |  f
+  |
+  | o  3:055a42cdd887 test
+  | |  d
+  | |
+  | o  2:177f92b77385 test
+  | |  c
+  | |
+  | o  1:d2ae7f538514 test
+  |/   b
+  |
+  o  0:cb9a9f314b8b test
+     a
+  
+  $ hg rebase -s 1 -d .
+  rebasing 1:d2ae7f538514 "b"
+  rebasing 2:177f92b77385 "c"
+  rebasing 3:055a42cdd887 "d"
+  merging d
+  warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
+  unresolved conflicts (see hg resolve, then hg rebase --continue)
+  [1]
+  $ hg rebase --stop
+  1 new orphan changesets
+  $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
+  @  7:7fffad344617 test
+  |  c
+  |
+  o  6:b15528633407 test
+  |  b
+  |
+  o  5:00bfc9898aeb test
+  |  conflict with d
+  |
+  o  4:dafd40200f93 test
+  |  f
+  |
+  | *  3:055a42cdd887 test
+  | |  d
+  | |
+  | x  2:177f92b77385 test
+  | |  c
+  | |
+  | x  1:d2ae7f538514 test
+  |/   b
+  |
+  o  0:cb9a9f314b8b test
+     a
+  
+Test it abrots if unstable csets is not allowed:
+================================================
+  $ cat >> $HGRCPATH << EOF
+  > [experimental]
+  > evolution.allowunstable=False
+  > EOF
+
+  $ hg strip 6 --no-backup -q
+  $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
+  @  5:00bfc9898aeb test
+  |  conflict with d
+  |
+  o  4:dafd40200f93 test
+  |  f
+  |
+  | o  3:055a42cdd887 test
+  | |  d
+  | |
+  | o  2:177f92b77385 test
+  | |  c
+  | |
+  | o  1:d2ae7f538514 test
+  |/   b
+  |
+  o  0:cb9a9f314b8b test
+     a
+  
+  $ hg rebase -s 1 -d .
+  rebasing 1:d2ae7f538514 "b"
+  rebasing 2:177f92b77385 "c"
+  rebasing 3:055a42cdd887 "d"
+  merging d
+  warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
+  unresolved conflicts (see hg resolve, then hg rebase --continue)
+  [1]
+  $ hg rebase --stop
+  abort: can't remove original changesets with unrebased descendants
+  (either enable evolve extension to allow unstable revisions or use --keep to keep original changesets)
+  [255]
+  $ hg rebase --abort
+  saved backup bundle to $TESTTMP/rbstop/.hg/strip-backup/b15528633407-6eb72b6f-backup.hg
+  rebase aborted
+
+Test --stop when --keep is passed:
+==================================
+  $ hg rebase -s 1 -d . --keep
+  rebasing 1:d2ae7f538514 "b"
+  rebasing 2:177f92b77385 "c"
+  rebasing 3:055a42cdd887 "d"
+  merging d
+  warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
+  unresolved conflicts (see hg resolve, then hg rebase --continue)
+  [1]
+  $ hg rebase --stop
+  $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n"
+  @  7:7fffad344617 test
+  |  c
+  |
+  o  6:b15528633407 test
+  |  b
+  |
+  o  5:00bfc9898aeb test
+  |  conflict with d
+  |
+  o  4:dafd40200f93 test
+  |  f
+  |
+  | o  3:055a42cdd887 test
+  | |  d
+  | |
+  | o  2:177f92b77385 test
+  | |  c
+  | |
+  | o  1:d2ae7f538514 test
+  |/   b
+  |
+  o  0:cb9a9f314b8b test
+     a
+  
diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -347,6 +347,33 @@
             return abort(self.repo, self.originalwd, self.destmap, self.state,
                          activebookmark=self.activebookmark, backup=backup,
                          suppwarns=suppwarns)
+    def _stoprebase(self):
+        """stop the interrupted rebase"""
+        self.restorestatus()
+        if not self.stateobj.exists():
+            raise error.Abort(_("no interrupted rebase found"))
+        allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
+        if not (self.keepf or allowunstable):
+            raise error.Abort(_("can't remove original changesets with"
+                  " unrebased descendants"),
+                hint=_('either enable evolve extension to allow unstable '
+                       'revisions or use --keep to keep original changesets'))
+
+        # update to the last rebased node if any
+        ctx = self.repo[None]
+        pars = [p.node() for p in ctx.parents()]
+        p1 = pars[0]
+        hg.updaterepo(self.repo, p1, overwrite=True)
+
+        # either mark obsolete or keep rebased revisions
+        repo, ui, opts = self.repo, self.ui, self.opts
+        fm = ui.formatter('rebase', opts)
+        fm.startitem()
+        clearrebased(ui, repo, self.destmap, self.state, self.skipped,
+                     collapsedas=None, keepf=self.keepf, fm=fm)
+        clearstatus(self.repo)
+        fm.end()
+        return 0
 
     def _preparenewrebase(self, destmap):
         if not destmap:
@@ -670,6 +697,7 @@
     ('D', 'detach', False, _('(DEPRECATED)')),
     ('i', 'interactive', False, _('(DEPRECATED)')),
     ('t', 'tool', '', _('specify merge tool')),
+    ('', 'stop', False, _('stop interrupted rebase')),
     ('c', 'continue', False, _('continue an interrupted rebase')),
     ('a', 'abort', False, _('abort an interrupted rebase')),
     ('', 'auto-orphans', '', _('automatically rebase orphan revisions '
@@ -800,6 +828,7 @@
     opts = pycompat.byteskwargs(opts)
     inmemory = ui.configbool('rebase', 'experimental.inmemory')
     dryrun = opts.get('dry_run')
+    stop = opts.get('stop')
     if dryrun:
         if opts.get('abort'):
             raise error.Abort(_('cannot specify both --dry-run and --abort'))
@@ -832,6 +861,11 @@
 
     if dryrun:
         return _dryrunrebase(ui, repo, opts)
+    elif stop:
+        #todo: raise error for conflicting options
+        rbsrt = rebaseruntime(repo, ui)
+        with repo.wlock(), repo.lock():
+            return rbsrt._stoprebase()
     elif inmemory:
         try:
             # in-memory merge doesn't support conflicts, so if we hit any, abort



To: khanchi97, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list