rebase: teach in-memory rebase to not restart with on-disk rebase on conflict
authorMartin von Zweigbergk <martinvonz@google.com>
Fri, 18 Sep 2020 15:03:06 -0700
changeset 45555 feffeb18d412
parent 45554 abad925af2ef
child 45556 03726f5b6092
rebase: teach in-memory rebase to not restart with on-disk rebase on conflict When in-memory rebase runs into conflicts, it redoes the whole rebase operation. This patch teaches it to instead discard just the current `overlayworkingctx` and redo that node on disk. I've tested this by enabling in-memory rebase by default and checking that there are no unexpected differences after this patch. The next step is to make it so that `hg rebase --continue` can use in-memory merge. Differential Revision: https://phab.mercurial-scm.org/D9076
hgext/rebase.py
tests/test-rebase-inmemory.t
--- a/hgext/rebase.py	Thu Sep 24 16:30:17 2020 +0200
+++ b/hgext/rebase.py	Fri Sep 18 15:03:06 2020 -0700
@@ -615,9 +615,49 @@
             else:
                 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
                 with ui.configoverride(overrides, b'rebase'):
-                    rebasenode(
-                        repo, rev, p1, p2, base, self.collapsef, wctx=self.wctx,
-                    )
+                    try:
+                        rebasenode(
+                            repo,
+                            rev,
+                            p1,
+                            p2,
+                            base,
+                            self.collapsef,
+                            wctx=self.wctx,
+                        )
+                    except error.InMemoryMergeConflictsError:
+                        if self.dryrun:
+                            raise error.ConflictResolutionRequired(b'rebase')
+                        if self.collapsef:
+                            # TODO: Make the overlayworkingctx reflected
+                            # in the working copy here instead of re-raising
+                            # so the entire rebase operation is retried.
+                            raise
+                        ui.status(
+                            _(
+                                b"hit merge conflicts; rebasing that "
+                                b"commit again in the working copy\n"
+                            )
+                        )
+                        cmdutil.bailifchanged(repo)
+                        self.inmemory = False
+                        self._assignworkingcopy()
+                        mergemod.update(
+                            repo,
+                            p1,
+                            branchmerge=False,
+                            force=False,
+                            wc=self.wctx,
+                        )
+                        rebasenode(
+                            repo,
+                            rev,
+                            p1,
+                            p2,
+                            base,
+                            self.collapsef,
+                            wctx=self.wctx,
+                        )
             if not self.collapsef:
                 merging = p2 != nullrev
                 editform = cmdutil.mergeeditform(merging, b'rebase')
@@ -1100,7 +1140,7 @@
                 _origrebase(
                     ui, repo, action, opts, rbsrt,
                 )
-        except error.InMemoryMergeConflictsError:
+        except error.ConflictResolutionRequired:
             ui.status(_(b'hit a merge conflict\n'))
             return 1
         except error.Abort:
--- a/tests/test-rebase-inmemory.t	Thu Sep 24 16:30:17 2020 +0200
+++ b/tests/test-rebase-inmemory.t	Fri Sep 18 15:03:06 2020 -0700
@@ -415,8 +415,6 @@
   rebasing 3:055a42cdd887 "d"
   rebasing 4:e860deea161a "e"
   merging e
-  transaction abort!
-  rollback completed
   hit a merge conflict
   [1]
   $ hg diff
@@ -463,12 +461,7 @@
   rebasing 3:055a42cdd887 "d"
   rebasing 4:e860deea161a "e"
   merging e
-  transaction abort!
-  rollback completed
-  hit merge conflicts; re-running rebase without in-memory merge
-  rebasing 2:177f92b77385 "c"
-  rebasing 3:055a42cdd887 "d"
-  rebasing 4:e860deea161a "e"
+  hit merge conflicts; rebasing that commit again in the working copy
   merging e
   warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
   unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
@@ -487,9 +480,9 @@
   rebasing 3:055a42cdd887 "d"
   rebasing 4:e860deea161a "e"
   merging e
+  hit merge conflicts; rebasing that commit again in the working copy
   transaction abort!
   rollback completed
-  hit merge conflicts; re-running rebase without in-memory merge
   abort: uncommitted changes
   [255]
   $ cat a
@@ -859,8 +852,7 @@
   $ hg rebase -r . -d 1 --config ui.merge=internal:merge3
   rebasing 2:fb62b706688e "add b to foo" (tip)
   merging foo
-  hit merge conflicts; re-running rebase without in-memory merge
-  rebasing 2:fb62b706688e "add b to foo" (tip)
+  hit merge conflicts; rebasing that commit again in the working copy
   merging foo
   warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
   unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')
@@ -893,8 +885,7 @@
   $ hg rebase -r 2 -d 1 -t:merge3
   rebasing 2:b4d249fbf8dd "bye from foo"
   merging foo
-  hit merge conflicts; re-running rebase without in-memory merge
-  rebasing 2:b4d249fbf8dd "bye from foo"
+  hit merge conflicts; rebasing that commit again in the working copy
   merging foo
   warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
   unresolved conflicts (see 'hg resolve', then 'hg rebase --continue')