<div dir="ltr">I just ran into this bug yesterday. Could you mention in what change it was introduced so we know in what range it is broken?<br><br><div class="gmail_quote"><div dir="ltr">On Tue, Mar 15, 2016 at 12:45 PM Laurent Charignon <<a href="mailto:lcharignon@fb.com">lcharignon@fb.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"># HG changeset patch<br>
# User Laurent Charignon <<a href="mailto:lcharignon@fb.com" target="_blank">lcharignon@fb.com</a>><br>
# Date 1458071050 25200<br>
#      Tue Mar 15 12:44:10 2016 -0700<br>
# Node ID 98edf167ea7b101efb2bd1c59db53e46c0fd182a<br>
# Parent  70c2f8a982766b512e9d7f41f2d93fdb92f5481f<br>
rebase: persist rebaseskipobsolete state<br>
<br>
Before this patch, when a rebase aborted, we didn't persist the mapping between<br>
obsolete revisions and their successors.<br>
When running hg rebase --continue, we would crash looking for this non-existing<br>
mapping.<br>
<br>
This patch persists the mapping to disk and restores it from disk to avoid this<br>
issue. A test is added for the special case of plain prune revisions.<br>
<br>
I didn't do a test for the following case as I don't know how to create the<br>
marker between B and B' without using evolve:<br>
<br>
     O C<br>
     |<br>
O B' X B (precursor of B')<br>
|    |<br>
O A  O R (conflicting changes with A)<br>
|    |<br>
|   /<br>
|  /<br>
| /<br>
|/<br>
O<br>
<br>
$ hg rebase -r "R::" -d B' # aborts<br>
$ ... # resolve and mark conflicts<br>
$ hg rebase --continue<br>
<br>
diff --git a/hgext/rebase.py b/hgext/rebase.py<br>
--- a/hgext/rebase.py<br>
+++ b/hgext/rebase.py<br>
@@ -236,6 +236,7 @@ def rebase(ui, repo, **opts):<br>
         # keepopen is not meant for use on the command line, but by<br>
         # other extensions<br>
         keepopen = opts.get('keepopen', False)<br>
+        obsoletenotrebased = {}<br>
<br>
         if opts.get('interactive'):<br>
             try:<br>
@@ -266,7 +267,8 @@ def rebase(ui, repo, **opts):<br>
<br>
             try:<br>
                 (originalwd, target, state, skipped, collapsef, keepf,<br>
-                 keepbranchesf, external, activebookmark) = restorestatus(repo)<br>
+                 keepbranchesf, external, activebookmark,<br>
+                 obsoletenotrebased) = restorestatus(repo)<br>
                 collapsemsg = restorecollapsemsg(repo)<br>
             except error.RepoLookupError:<br>
                 if abortf:<br>
@@ -296,7 +298,6 @@ def rebase(ui, repo, **opts):<br>
                       " unrebased descendants"),<br>
                     hint=_('use --keep to keep original changesets'))<br>
<br>
-            obsoletenotrebased = {}<br>
             if ui.configbool('experimental', 'rebaseskipobsolete',<br>
                              default=True):<br>
                 rebasesetrevs = set(rebaseset)<br>
@@ -397,7 +398,8 @@ def rebase(ui, repo, **opts):<br>
                 p1, p2, base = defineparents(repo, rev, target, state,<br>
                                              targetancestors)<br>
                 storestatus(repo, originalwd, target, state, collapsef, keepf,<br>
-                            keepbranchesf, external, activebookmark)<br>
+                            keepbranchesf, external, activebookmark,<br>
+                            obsoletenotrebased)<br>
                 storecollapsemsg(repo, collapsemsg)<br>
                 if len(repo[None].parents()) == 2:<br>
                     repo.ui.debug('resuming interrupted rebase\n')<br>
@@ -888,7 +890,7 @@ def restorecollapsemsg(repo):<br>
     return collapsemsg<br>
<br>
 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,<br>
-                external, activebookmark):<br>
+                external, activebookmark, obsoletenotrebased):<br>
     'Store the current status to allow recovery'<br>
     f = repo.vfs("rebasestate", "w")<br>
     f.write(repo[originalwd].hex() + '\n')<br>
@@ -898,6 +900,17 @@ def storestatus(repo, originalwd, target<br>
     f.write('%d\n' % int(keep))<br>
     f.write('%d\n' % int(keepbranches))<br>
     f.write('%s\n' % (activebookmark or ''))<br>
+<br>
+    # rebaseskipobsolete lines follow the format:<br>
+    # xOLDHASH:NEWHASH if NEWHASH is nullid, it means no successor<br>
+    for d, v in obsoletenotrebased.iteritems():<br>
+        oldrev = repo[d].hex()<br>
+        if v is not None:<br>
+            newrev = repo[v].hex()<br>
+        else:<br>
+            newrev = hex(nullid)<br>
+        f.write("x%s:%s\n" %(oldrev, newrev))<br>
+<br>
     for d, v in state.iteritems():<br>
         oldrev = repo[d].hex()<br>
         if v >= 0:<br>
@@ -924,6 +937,7 @@ def restorestatus(repo):<br>
     collapse = False<br>
     external = nullrev<br>
     activebookmark = None<br>
+    obsoletenotrebased = {}<br>
     state = {}<br>
<br>
     try:<br>
@@ -945,6 +959,14 @@ def restorestatus(repo):<br>
                 # line 6 is a recent addition, so for backwards compatibility<br>
                 # check that the line doesn't look like the oldrev:newrev lines<br>
                 activebookmark = l<br>
+            elif i >= 7 and (len(l) == 82 and ':' in l and l[0] == 'x'):<br>
+                # line 7 is a recent addition, so for backwards compatibility<br>
+                # check that the line doesn't look like the oldrev:newrev lines<br>
+                oldrev, newrev = l[1:].split(':')<br>
+                if newrev == nullid:<br>
+                    obsoletenotrebased[repo[oldrev].rev()] = None<br>
+                else:<br>
+                    obsoletenotrebased[repo[oldrev].rev()] = repo[newrev].rev()<br>
             else:<br>
                 oldrev, newrev = l.split(':')<br>
                 if newrev in (str(nullmerge), str(revignored),<br>
@@ -977,7 +999,8 @@ def restorestatus(repo):<br>
     repo.ui.debug('rebase status resumed\n')<br>
     _setrebasesetvisibility(repo, state.keys())<br>
     return (originalwd, target, state, skipped,<br>
-            collapse, keep, keepbranches, external, activebookmark)<br>
+            collapse, keep, keepbranches, external, activebookmark,<br>
+            obsoletenotrebased)<br>
<br>
 def needupdate(repo, state):<br>
     '''check whether we should `update --clean` away from a merge, or if<br>
diff --git a/tests/test-rebase-obsolete.t b/tests/test-rebase-obsolete.t<br>
--- a/tests/test-rebase-obsolete.t<br>
+++ b/tests/test-rebase-obsolete.t<br>
@@ -805,3 +805,60 @@ With experimental.allowdivergence=True,<br>
   phases: 8 draft<br>
   divergent: 2 changesets<br>
<br>
+rebase --continue + skipped rev because their successors are in destination<br>
+we make a change in trunk and work on conflicting changes to make rebase abort.<br>
+<br>
+  $ hg log -G -r 17::<br>
+  @  17:61bd55f69bc4 bar foo<br>
+  |<br>
+<br>
+Create the two changes in trunk<br>
+  $ printf "a" > willconflict<br>
+  $ hg add willconflict<br>
+  $ hg commit -m "willconflict first version"<br>
+<br>
+  $ printf "dummy" > C<br>
+  $ hg commit -m "dummy change successor"<br>
+<br>
+Create the changes that we will rebase<br>
+  $ hg update -C 17<br>
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved<br>
+  $ printf "b" > willconflict<br>
+  $ hg add willconflict<br>
+  $ hg commit -m "willconflict second version"<br>
+  created new head<br>
+  $ printf "dummy" > K<br>
+  $ hg add K<br>
+  $ hg commit -m "dummy change"<br>
+  $ printf "dummy" > L<br>
+  $ hg add L<br>
+  $ hg commit -m "dummy change"<br>
+  $ hg debugobsolete `hg log -r ".^" -T '{node}\n'` --config experimental.evolution=all<br>
+<br>
+  $ hg log -G -r 17::<br>
+  @  22:7bdc8a87673d dummy change<br>
+  |<br>
+  x  21:8b31da3c4919 dummy change<br>
+  |<br>
+  o  20:b82fb57ea638 willconflict second version<br>
+  |<br>
+  | o  19:601db7a18f51 dummy change successor<br>
+  | |<br>
+  | o  18:357ddf1602d5 willconflict first version<br>
+  |/<br>
+  o  17:61bd55f69bc4 bar foo<br>
+  |<br>
+  $ hg rebase -r ".^^ + .^ + ." -d 19<br>
+  rebasing 20:b82fb57ea638 "willconflict second version"<br>
+  merging willconflict<br>
+  warning: conflicts while merging willconflict! (edit, then use 'hg resolve --mark')<br>
+  unresolved conflicts (see hg resolve, then hg rebase --continue)<br>
+  [1]<br>
+<br>
+  $ hg resolve --mark willconflict<br>
+  (no more unresolved files)<br>
+  continue: hg rebase --continue<br>
+  $ hg rebase --continue<br>
+  rebasing 20:b82fb57ea638 "willconflict second version"<br>
+  note: not rebasing 21:8b31da3c4919 "dummy change", it has no successor<br>
+  rebasing 22:7bdc8a87673d "dummy change" (tip)<br>
_______________________________________________<br>
Mercurial-devel mailing list<br>
<a href="mailto:Mercurial-devel@mercurial-scm.org" target="_blank">Mercurial-devel@mercurial-scm.org</a><br>
<a href="https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel" rel="noreferrer" target="_blank">https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel</a><br>
</blockquote></div></div>