rebase: clear merge when aborting before any rebasing (issue4661) stable
authorJordi Gutiérrez Hermoso <jordigh@octave.org>
Sun, 10 May 2015 10:57:24 -0400
branchstable
changeset 25070 bd98d073a34f
parent 25069 01ad8daae5be
child 25075 d1bd0fd07ee6
child 25094 8b99e9a8db05
rebase: clear merge when aborting before any rebasing (issue4661) The check of the inrebase function was not correct, and it failed to consider the situation in which nothing has been rebased yet, *and* the working dir had been updated away from the initial revision. But this is easy to fix. Given the rebase state, we know exactly where we should be standing: on the first unrebased commit. We check that instead. I also took the liberty to rename the function, as "inrebase" doesn't really describe the situation: we could still be in a rebase state yet the user somehow forcibly updated to a different revision. We also check that we're in a merge state, since an interrupted merge is the only "safe" way to interrupt a rebase. If the rebase got interrupted by power loss or whatever (so there's no merge state), it's still safer to not blow away the working directory.
hgext/rebase.py
tests/test-rebase-abort.t
--- a/hgext/rebase.py	Sun May 10 10:02:15 2015 -0400
+++ b/hgext/rebase.py	Sun May 10 10:57:24 2015 -0400
@@ -841,16 +841,21 @@
             raise
         raise util.Abort(_('no rebase in progress'))
 
-def inrebase(repo, originalwd, state):
-    '''check whether the working dir is in an interrupted rebase'''
+def needupdate(repo, state):
+    '''check whether we should `update --clean` away from a merge, or if
+    somehow the working dir got forcibly updated, e.g. by older hg'''
     parents = [p.rev() for p in repo.parents()]
-    if originalwd in parents:
+
+    # Are we in a merge state at all?
+    if len(parents) < 2:
+        return False
+
+    # We should be standing on the first as-of-yet unrebased commit.
+    firstunrebased = min([old for old, new in state.iteritems()
+                          if new == nullrev])
+    if firstunrebased in parents:
         return True
 
-    for newrev in state.itervalues():
-        if newrev in parents:
-            return True
-
     return False
 
 def abort(repo, originalwd, target, state, activebookmark=None):
@@ -877,7 +882,7 @@
 
     if cleanup:
         # Update away from the rebase if necessary
-        if inrebase(repo, originalwd, state):
+        if needupdate(repo, state):
             merge.update(repo, originalwd, False, True, False)
 
         # Strip from the first rebased revision
--- a/tests/test-rebase-abort.t	Sun May 10 10:02:15 2015 -0400
+++ b/tests/test-rebase-abort.t	Sun May 10 10:57:24 2015 -0400
@@ -288,3 +288,36 @@
   new
 
   $ cd ..
+
+On the other hand, make sure we *do* clobber changes whenever we
+haven't somehow managed to update the repo to a different revision
+during a rebase (issue4661)
+
+  $ hg ini yesupdate
+  $ cd yesupdate
+  $ echo "initial data" > foo.txt
+  $ hg add
+  adding foo.txt
+  $ hg ci -m "initial checkin"
+  $ echo "change 1" > foo.txt
+  $ hg ci -m "change 1"
+  $ hg up 0
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo "conflicting change 1" > foo.txt
+  $ hg ci -m "conflicting 1"
+  created new head
+  $ echo "conflicting change 2" > foo.txt
+  $ hg ci -m "conflicting 2"
+
+  $ hg rebase -d 1 --tool 'internal:fail'
+  rebasing 2:e4ea5cdc9789 "conflicting 1"
+  unresolved conflicts (see hg resolve, then hg rebase --continue)
+  [1]
+  $ hg rebase --abort
+  rebase aborted
+  $ hg summary
+  parent: 3:b16646383533 tip
+   conflicting 2
+  branch: default
+  commit: (clean)
+  update: 1 new changesets, 2 branch heads (merge)