merge with stable
authorAugie Fackler <augie@google.com>
Tue, 04 Dec 2018 17:13:01 -0500
changeset 53585 cb372d09d30a94f220624fe64c5a0dfd20733305
parent 53568 e13ab4acf555daf8fac593127b6a076288551710 (current diff)
parent 53584 47719d7c581f18c1e6c98b05e2f79307c2ea50bd (diff)
child 53586 96be0ecad6485c616fec15ac8debfbadcb6c22a4
push id1079
push usergszorc@mozilla.com
push dateMon, 10 Dec 2018 19:44:59 +0000
merge with stable
hgext/extdiff.py
hgext/rebase.py
mercurial/cext/revlog.c
mercurial/commandserver.py
mercurial/context.py
--- a/.hgsigs
+++ b/.hgsigs
@@ -167,8 +167,9 @@ 6614cac550aea66d19c601e45efd1b7bd08d7c40
 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
+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
--- a/.hgtags
+++ b/.hgtags
@@ -180,8 +180,9 @@ 6614cac550aea66d19c601e45efd1b7bd08d7c40
 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
+1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
--- a/hgext/extdiff.py
+++ b/hgext/extdiff.py
@@ -425,12 +425,13 @@ def uisetup(ui):
                 diffopts = False
         # look for diff arguments in [diff-tools] then [merge-tools]
         if not diffopts:
             args = ui.config('diff-tools', cmd+'.diffargs') or \
                    ui.config('merge-tools', cmd+'.diffargs')
             if args:
                 cmdline += ' ' + args
         command(cmd, extdiffopts[:], _('hg %s [OPTION]... [FILE]...') % cmd,
+                helpcategory=command.CATEGORY_FILE_CONTENTS,
                 inferrepo=True)(savedcmd(path, cmdline))
 
 # tell hggettext to extract docstrings from these functions:
 i18nfunctions = [savedcmd]
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -537,17 +537,17 @@ class rebaseruntime(object):
                                   self.skipped))
             self.state[rev] = dest
         elif self.state[rev] == revtodo:
             ui.status(_('rebasing %s\n') % desc)
             progressfn(ctx)
             p1, p2, base = defineparents(repo, rev, self.destmap,
                                          self.state, self.skipped,
                                          self.obsoletenotrebased)
-            if len(repo[None].parents()) == 2:
+            if not self.inmemory and len(repo[None].parents()) == 2:
                 repo.ui.debug('resuming interrupted rebase\n')
             else:
                 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
                 with ui.configoverride(overrides, 'rebase'):
                     stats = rebasenode(repo, rev, p1, base, self.collapsef,
                                        dest, wctx=self.wctx)
                     if stats.unresolvedcount > 0:
                         if self.inmemory:
@@ -862,17 +862,21 @@ def rebase(ui, repo, **opts):
             # in-memory merge doesn't support conflicts, so if we hit any, abort
             # and re-run as an on-disk merge.
             overrides = {('rebase', 'singletransaction'): True}
             with ui.configoverride(overrides, 'rebase'):
                 return _dorebase(ui, repo, action, opts, inmemory=inmemory)
         except error.InMemoryMergeConflictsError:
             ui.warn(_('hit merge conflicts; re-running rebase without in-memory'
                       ' merge\n'))
-            _dorebase(ui, repo, action='abort', opts={})
+            # TODO: Make in-memory merge not use the on-disk merge state, so
+            # we don't have to clean it here
+            mergemod.mergestate.clean(repo)
+            clearstatus(repo)
+            clearcollapsemsg(repo)
             return _dorebase(ui, repo, action, opts, inmemory=False)
     else:
         return _dorebase(ui, repo, action, opts)
 
 def _dryrunrebase(ui, repo, action, opts):
     rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts)
     confirm = opts.get('confirm')
     if confirm:
--- a/mercurial/cext/revlog.c
+++ b/mercurial/cext/revlog.c
@@ -153,16 +153,22 @@ static const char *index_deref(indexObje
 			inline_scan(self, self->offsets);
 		}
 		return self->offsets[pos];
 	}
 
 	return (const char *)(self->buf.buf) + pos * v1_hdrsize;
 }
 
+/*
+ * Get parents of the given rev.
+ *
+ * The specified rev must be valid and must not be nullrev. A returned
+ * parent revision may be nullrev, but is guaranteed to be in valid range.
+ */
 static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
                                     int maxrev)
 {
 	if (rev >= self->length) {
 		long tmp;
 		PyObject *tuple =
 		    PyList_GET_ITEM(self->added, rev - self->length);
 		if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 5), &tmp)) {
@@ -175,17 +181,17 @@ static inline int index_get_parents(inde
 		ps[1] = (int)tmp;
 	} else {
 		const char *data = index_deref(self, rev);
 		ps[0] = getbe32(data + 24);
 		ps[1] = getbe32(data + 28);
 	}
 	/* If index file is corrupted, ps[] may point to invalid revisions. So
 	 * there is a risk of buffer overflow to trust them unconditionally. */
-	if (ps[0] > maxrev || ps[1] > maxrev) {
+	if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
 		PyErr_SetString(PyExc_ValueError, "parent out of range");
 		return -1;
 	}
 	return 0;
 }
 
 static inline int64_t index_get_start(indexObject *self, Py_ssize_t rev)
 {
@@ -2683,16 +2689,26 @@ rustlazyancestors_init(indexObject *inde
                        int (*)(indexObject *, Py_ssize_t, int *, int),
                        /* intrevs vector */
                        Py_ssize_t initrevslen, long *initrevs, long stoprev,
                        int inclusive);
 void rustlazyancestors_drop(rustlazyancestorsObject *self);
 int rustlazyancestors_next(rustlazyancestorsObject *self);
 int rustlazyancestors_contains(rustlazyancestorsObject *self, long rev);
 
+static int index_get_parents_checked(indexObject *self, Py_ssize_t rev, int *ps,
+                                     int maxrev)
+{
+	if (rev < 0 || rev >= index_length(self)) {
+		PyErr_SetString(PyExc_ValueError, "rev out of range");
+		return -1;
+	}
+	return index_get_parents(self, rev, ps, maxrev);
+}
+
 /* CPython instance methods */
 static int rustla_init(rustlazyancestorsObject *self, PyObject *args)
 {
 	PyObject *initrevsarg = NULL;
 	PyObject *inclusivearg = NULL;
 	long stoprev = 0;
 	long *initrevs = NULL;
 	int inclusive = 0;
@@ -2724,17 +2740,18 @@ static int rustla_init(rustlazyancestors
 	}
 	if (PyErr_Occurred())
 		goto bail;
 
 	self->iter = rustlazyancestors_init(index, index_get_parents, linit,
 	                                    initrevs, stoprev, inclusive);
 	if (self->iter == NULL) {
 		/* if this is because of GraphError::ParentOutOfRange
-		 * index_get_parents() has already set the proper ValueError */
+		 * index_get_parents_checked() has already set the proper
+		 * ValueError */
 		goto bail;
 	}
 
 	free(initrevs);
 	return 0;
 
 bail:
 	free(initrevs);
--- a/mercurial/commandserver.py
+++ b/mercurial/commandserver.py
@@ -521,17 +521,25 @@ class unixforkingservice(object):
             if not exiting and h.shouldexit():
                 # clients can no longer connect() to the domain socket, so
                 # we stop queuing new requests.
                 # for requests that are queued (connect()-ed, but haven't been
                 # accept()-ed), handle them before exit. otherwise, clients
                 # waiting for recv() will receive ECONNRESET.
                 self._unlinksocket()
                 exiting = True
-            ready = selector.select(timeout=h.pollinterval)
+            try:
+                ready = selector.select(timeout=h.pollinterval)
+            except OSError as inst:
+                # selectors2 raises ETIMEDOUT if timeout exceeded while
+                # handling signal interrupt. That's probably wrong, but
+                # we can easily get around it.
+                if inst.errno != errno.ETIMEDOUT:
+                    raise
+                ready = []
             if not ready:
                 # only exit if we completed all queued requests
                 if exiting:
                     break
                 continue
             try:
                 conn, _addr = self._sock.accept()
             except socket.error as inst:
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -1838,16 +1838,21 @@ class overlayworkingctx(committablectx):
             if self._cache[path]['exists']:
                 return self._cache[path]['flags']
             else:
                 raise error.ProgrammingError("No such file or directory: %s" %
                                              self._path)
         else:
             return self._wrappedctx[path].flags()
 
+    def __contains__(self, key):
+        if key in self._cache:
+            return self._cache[key]['exists']
+        return key in self.p1()
+
     def _existsinparent(self, path):
         try:
             # ``commitctx` raises a ``ManifestLookupError`` if a path does not
             # exist, unlike ``workingctx``, which returns a ``workingfilectx``
             # with an ``exists()`` function.
             self._wrappedctx[path]
             return True
         except error.ManifestLookupError:
@@ -1872,29 +1877,29 @@ class overlayworkingctx(committablectx):
                                   "%s." % (path, component,
                                            self.p1().rev()))
 
         # Test that each new directory to be created to write this path from p2
         # is not a file in p1.
         components = path.split('/')
         for i in pycompat.xrange(len(components)):
             component = "/".join(components[0:i])
-            if component in self.p1() and self._cache[component]['exists']:
+            if component in self:
                 fail(path, component)
 
         # Test the other direction -- that this path from p2 isn't a directory
-        # in p1 (test that p1 doesn't any paths matching `path/*`).
-        match = matchmod.match('/', '', [path + '/'], default=b'relpath')
+        # in p1 (test that p1 doesn't have any paths matching `path/*`).
+        match = self.match(pats=[path + '/'], default=b'path')
         matches = self.p1().manifest().matches(match)
         mfiles = matches.keys()
         if len(mfiles) > 0:
             if len(mfiles) == 1 and mfiles[0] == path:
                 return
             # omit the files which are deleted in current IMM wctx
-            mfiles = [m for m in mfiles if self._cache[m]['exists']]
+            mfiles = [m for m in mfiles if m in self]
             if not mfiles:
                 return
             raise error.Abort("error: file '%s' cannot be written because "
                               " '%s/' is a folder in %s (containing %d "
                               "entries: %s)"
                               % (path, path, self.p1(), len(mfiles),
                                  ', '.join(mfiles)))
 
--- a/mercurial/thirdparty/selectors2.py
+++ b/mercurial/thirdparty/selectors2.py
@@ -703,17 +703,17 @@ else:
                 # Also test for the Windows equivalent of EINTR.
                 is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and
                                                            errcode == errno.WSAEINTR))
 
                 if is_interrupt:
                     if expires is not None:
                         current_time = monotonic()
                         if current_time > expires:
-                            raise OSError(errno=errno.ETIMEDOUT)
+                            raise OSError(errno.ETIMEDOUT, 'Connection timed out')
                         if recalc_timeout:
                             if "timeout" in kwargs:
                                 kwargs["timeout"] = expires - current_time
                     continue
                 raise
         return result
 
 
--- a/mercurial/wireprotov2peer.py
+++ b/mercurial/wireprotov2peer.py
@@ -372,35 +372,40 @@ class clienthandler(object):
         else:
             raise error.ProgrammingError(
                 'unhandled action from clientreactor: %s' % action)
 
     def _processresponsedata(self, frame, meta, response):
         # This can raise. The caller can handle it.
         response._onresponsedata(meta['data'])
 
-        # If we got a content redirect response, we want to fetch it and
-        # expose the data as if we received it inline. But we also want to
-        # keep our internal request accounting in order. Our strategy is to
-        # basically put meaningful response handling on pause until EOS occurs
-        # and the stream accounting is in a good state. At that point, we follow
-        # the redirect and replace the response object with its data.
+        # We need to be careful about resolving futures prematurely. If a
+        # response is a redirect response, resolving the future before the
+        # redirect is processed would result in the consumer seeing an
+        # empty stream of objects, since they'd be consuming our
+        # response.objects() instead of the redirect's response.objects().
+        #
+        # Our strategy is to not resolve/finish the request until either
+        # EOS occurs or until the initial response object is fully received.
 
-        redirect = response._redirect
-        handlefuture = False if redirect else True
-
+        # Always react to eos.
         if meta['eos']:
             response._oninputcomplete()
             del self._requests[frame.requestid]
 
-            if redirect:
-                self._followredirect(frame.requestid, redirect)
-                return
+        # Not EOS but we haven't decoded the initial response object yet.
+        # Return and wait for more data.
+        elif not response._seeninitial:
+            return
 
-        if not handlefuture:
+        # The specification says no objects should follow the initial/redirect
+        # object. So it should be safe to handle the redirect object if one is
+        # decoded, without having to wait for EOS.
+        if response._redirect:
+            self._followredirect(frame.requestid, response._redirect)
             return
 
         # If the command has a decoder, we wait until all input has been
         # received before resolving the future. Otherwise we resolve the
         # future immediately.
         if frame.requestid not in self._futures:
             return
 
@@ -453,29 +458,32 @@ class clienthandler(object):
         oldresponse = self._responses[requestid]
         self._responses[requestid] = commandresponse(requestid,
                                                      oldresponse.command,
                                                      fromredirect=True)
 
         self._redirects.append((requestid, res))
 
     def _processredirect(self, rid, res):
-        """Called to continue processing a response from a redirect."""
+        """Called to continue processing a response from a redirect.
+
+        Returns a bool indicating if the redirect is still serviceable.
+        """
         response = self._responses[rid]
 
         try:
             data = res.read(32768)
             response._onresponsedata(data)
 
             # We're at end of stream.
             if not data:
                 response._oninputcomplete()
 
             if rid not in self._futures:
-                return
+                return bool(data)
 
             if response.command not in COMMAND_DECODERS:
                 self._futures[rid].set_result(response.objects())
                 del self._futures[rid]
             elif response._inputcomplete:
                 decoded = COMMAND_DECODERS[response.command](response.objects())
                 self._futures[rid].set_result(decoded)
                 del self._futures[rid]
--- a/tests/test-fuzz-targets.t
+++ b/tests/test-fuzz-targets.t
@@ -1,17 +1,42 @@
 #require test-repo
 
   $ cd $TESTDIR/../contrib/fuzz
 
+which(1) could exit nonzero, but that's fine because we'll still end
+up without a valid executable, so we don't need to check $? here.
+
+  $ if which gmake >/dev/null 2>&1; then
+  >     MAKE=gmake
+  > else
+  >     MAKE=make
+  > fi
+
+  $ havefuzz() {
+  >     cat > $TESTTMP/dummy.cc <<EOF
+  > #include <stdlib.h>
+  > #include <stdint.h>
+  > int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { return 0; }
+  > int main(int argc, char **argv) {
+  >     const char data[] = "asdf";
+  >     return LLVMFuzzerTestOneInput((const uint8_t *)data, 4);
+  > }
+  > EOF
+  >     $CXX $TESTTMP/dummy.cc -o $TESTTMP/dummy \
+  >        -fsanitize=fuzzer-no-link,address || return 1
+  > }
+
 #if clang-libfuzzer
-  $ make -s clean all
+  $ CXX=clang++ havefuzz || exit 80
+  $ $MAKE -s clean all
 #endif
 #if no-clang-libfuzzer clang-6.0
-  $ make -s clean all CC=clang-6.0 CXX=clang++-6.0
+  $ CXX=clang++-6.0 havefuzz || exit 80
+  $ $MAKE -s clean all CC=clang-6.0 CXX=clang++-6.0
 #endif
 #if no-clang-libfuzzer no-clang-6.0
   $ exit 80
 #endif
 
 Just run the fuzzers for five seconds each to verify it works at all.
   $ ./bdiff -max_total_time 5
   $ ./mpatch -max_total_time 5
--- a/tests/test-parseindex.t
+++ b/tests/test-parseindex.t
@@ -128,37 +128,48 @@ Test SEGV caused by bad revision passed 
   $ cd ..
 
 Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
 
   $ mkdir invalidparent
   $ cd invalidparent
 
   $ hg clone --pull -q --config phases.publish=False ../a limit
+  $ hg clone --pull -q --config phases.publish=False ../a neglimit
   $ hg clone --pull -q --config phases.publish=False ../a segv
-  $ rm -R limit/.hg/cache segv/.hg/cache
+  $ rm -R limit/.hg/cache neglimit/.hg/cache segv/.hg/cache
 
   $ "$PYTHON" <<EOF
   > data = open("limit/.hg/store/00changelog.i", "rb").read()
-  > for n, p in [(b'limit', b'\0\0\0\x02'), (b'segv', b'\0\x01\0\0')]:
+  > poisons = [
+  >     (b'limit', b'\0\0\0\x02'),
+  >     (b'neglimit', b'\xff\xff\xff\xfe'),
+  >     (b'segv', b'\0\x01\0\0'),
+  > ]
+  > for n, p in poisons:
   >     # corrupt p1 at rev0 and p2 at rev1
   >     d = data[:24] + p + data[28:127 + 28] + p + data[127 + 32:]
   >     open(n + b"/.hg/store/00changelog.i", "wb").write(d)
   > EOF
 
   $ hg -R limit debugrevlogindex -f1 -c
      rev flag     size   link     p1     p2       nodeid
        0 0000       62      0      2     -1 7c31755bf9b5
        1 0000       65      1      0      2 26333235a41c
 
   $ hg -R limit debugdeltachain -c
       rev  chain# chainlen     prev   delta       size    rawsize  chainsize     ratio   lindist extradist extraratio
         0       1        1       -1    base         63         62         63   1.01613        63         0    0.00000
         1       2        1       -1    base         66         65         66   1.01538        66         0    0.00000
 
+  $ hg -R neglimit debugrevlogindex -f1 -c
+     rev flag     size   link     p1     p2       nodeid
+       0 0000       62      0     -2     -1 7c31755bf9b5
+       1 0000       65      1      0     -2 26333235a41c
+
   $ hg -R segv debugrevlogindex -f1 -c
      rev flag     size   link     p1     p2       nodeid
        0 0000       62      0  65536     -1 7c31755bf9b5
        1 0000       65      1      0  65536 26333235a41c
 
   $ hg -R segv debugdeltachain -c
       rev  chain# chainlen     prev   delta       size    rawsize  chainsize     ratio   lindist extradist extraratio
         0       1        1       -1    base         63         62         63   1.01613        63         0    0.00000
@@ -188,16 +199,22 @@ Test corrupted p1/p2 fields that could c
   > EOF
 
   $ "$PYTHON" test.py limit/.hg/store
   reachableroots: parent out of range
   compute_phases_map_sets: parent out of range
   index_headrevs: parent out of range
   find_gca_candidates: parent out of range
   find_deepest: parent out of range
+  $ "$PYTHON" test.py neglimit/.hg/store
+  reachableroots: parent out of range
+  compute_phases_map_sets: parent out of range
+  index_headrevs: parent out of range
+  find_gca_candidates: parent out of range
+  find_deepest: parent out of range
   $ "$PYTHON" test.py segv/.hg/store
   reachableroots: parent out of range
   compute_phases_map_sets: parent out of range
   index_headrevs: parent out of range
   find_gca_candidates: parent out of range
   find_deepest: parent out of range
 
   $ cd ..
--- a/tests/test-rebase-inmemory.t
+++ b/tests/test-rebase-inmemory.t
@@ -1,10 +1,12 @@
 #require symlink execbit
   $ cat << EOF >> $HGRCPATH
+  > [phases]
+  > publish=False
   > [extensions]
   > amend=
   > rebase=
   > debugdrawdag=$TESTDIR/drawdag.py
   > strip=
   > [rebase]
   > experimental.inmemory=1
   > [diff]
@@ -49,16 +51,17 @@ Rebase a simple DAG:
   o  1: 02952614a83d 'd'
   |
   @  0: b173517d0057 'a'
   
   $ hg cat -r 3 b
   b (no-eol)
   $ hg cat -r 2 c
   c (no-eol)
+  $ cd ..
 
 Case 2:
   $ hg init repo2
   $ cd repo2
   $ hg debugdrawdag <<'EOS'
   > c b
   > |/
   > d
@@ -172,17 +175,17 @@ Test reporting of path conflicts
   | o  2: 09c044d2cb43 'd'
   | |
   | o  1: fc055c3b4d33 'b'
   |/
   o  0: b173517d0057 'a'
   
   $ hg rebase -r . -d 2
   rebasing 4:daf7dfc139cb "a/a" (tip)
-  saved backup bundle to $TESTTMP/repo1/repo2/.hg/strip-backup/daf7dfc139cb-fdbfcf4f-rebase.hg
+  saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/daf7dfc139cb-fdbfcf4f-rebase.hg
 
   $ hg tglog
   @  4: c6ad37a4f250 'a/a'
   |
   | o  3: 844a7de3e617 'c'
   | |
   o |  2: 09c044d2cb43 'd'
   | |
@@ -213,17 +216,17 @@ Test reporting of path conflicts
   o |  2: 09c044d2cb43 'd'
   | |
   o |  1: fc055c3b4d33 'b'
   |/
   o  0: b173517d0057 'a'
   
   $ hg rebase -r . -d 5
   rebasing 7:855e9797387e "added a back!" (tip)
-  saved backup bundle to $TESTTMP/repo1/repo2/.hg/strip-backup/855e9797387e-81ee4c5d-rebase.hg
+  saved backup bundle to $TESTTMP/repo2/.hg/strip-backup/855e9797387e-81ee4c5d-rebase.hg
 
   $ hg tglog
   @  7: bb3f02be2688 'added a back!'
   |
   | o  6: d14530e5e3e6 'added bar'
   | |
   o |  5: 9b94b9373deb 'added foo'
   |/
@@ -232,19 +235,58 @@ Test reporting of path conflicts
   | o  3: 844a7de3e617 'c'
   | |
   o |  2: 09c044d2cb43 'd'
   | |
   o |  1: fc055c3b4d33 'b'
   |/
   o  0: b173517d0057 'a'
   
+  $ mkdir c
+  $ echo c > c/c
+  $ hg add c/c
+  $ hg ci -m 'c/c'
+  $ hg rebase -r . -d 3 -n
+  starting dry-run rebase; repository will not be changed
+  rebasing 8:755f0104af9b "c/c" (tip)
+  abort: error: 'c/c' conflicts with file 'c' in 3.
+  [255]
+  $ hg rebase -r 3 -d . -n
+  starting dry-run rebase; repository will not be changed
+  rebasing 3:844a7de3e617 "c"
+  abort: error: file 'c' cannot be written because  'c/' is a folder in 755f0104af9b (containing 1 entries: c/c)
+  [255]
 
   $ cd ..
 
+Test path auditing (issue5818)
+
+  $ mkdir lib_
+  $ ln -s lib_ lib
+  $ hg init repo
+  $ cd repo
+  $ mkdir -p ".$TESTTMP/lib"
+  $ touch ".$TESTTMP/lib/a"
+  $ hg add ".$TESTTMP/lib/a"
+  $ hg ci -m 'a'
+
+  $ touch ".$TESTTMP/lib/b"
+  $ hg add ".$TESTTMP/lib/b"
+  $ hg ci -m 'b'
+
+  $ hg up -q '.^'
+  $ touch ".$TESTTMP/lib/c"
+  $ hg add ".$TESTTMP/lib/c"
+  $ hg ci -m 'c'
+  created new head
+  $ hg rebase -s 1 -d .
+  rebasing 1:* "b" (glob)
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-rebase.hg (glob)
+  $ cd ..
+
 Test dry-run rebasing
 
   $ hg init repo3
   $ cd repo3
   $ echo a>a
   $ hg ci -Aqma
   $ echo b>b
   $ hg ci -Aqmb
@@ -415,24 +457,63 @@ In-memory rebase that fails due to merge
   $ hg rebase -s 2 -d 7
   rebasing 2:177f92b77385 "c"
   rebasing 3:055a42cdd887 "d"
   rebasing 4:e860deea161a "e"
   merging e
   transaction abort!
   rollback completed
   hit merge conflicts; re-running rebase without in-memory merge
-  rebase aborted
   rebasing 2:177f92b77385 "c"
   rebasing 3:055a42cdd887 "d"
   rebasing 4:e860deea161a "e"
   merging e
   warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
   unresolved conflicts (see hg resolve, then hg rebase --continue)
   [1]
+  $ hg rebase --abort
+  saved backup bundle to $TESTTMP/repo3/.hg/strip-backup/c1e524d4287c-f91f82e1-backup.hg
+  rebase aborted
+
+Retrying without in-memory merge won't lose working copy changes
+  $ cd ..
+  $ hg clone repo3 repo3-dirty -q
+  $ cd repo3-dirty
+  $ echo dirty > a
+  $ hg rebase -s 2 -d 7
+  rebasing 2:177f92b77385 "c"
+  rebasing 3:055a42cdd887 "d"
+  rebasing 4:e860deea161a "e"
+  merging e
+  transaction abort!
+  rollback completed
+  hit merge conflicts; re-running rebase without in-memory merge
+  abort: uncommitted changes
+  [255]
+  $ cat a
+  dirty
+
+Retrying without in-memory merge won't lose merge state
+  $ cd ..
+  $ hg clone repo3 repo3-merge-state -q
+  $ cd repo3-merge-state
+  $ hg merge 4
+  merging e
+  warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
+  2 files updated, 0 files merged, 0 files removed, 1 files unresolved
+  use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
+  [1]
+  $ hg resolve -l
+  U e
+  $ hg rebase -s 2 -d 7
+  rebasing 2:177f92b77385 "c"
+  abort: outstanding merge conflicts
+  [255]
+  $ hg resolve -l
+  U e
 
 ==========================
 Test for --confirm option|
 ==========================
   $ cd ..
   $ hg clone repo3 repo4 -q
   $ cd repo4
   $ hg strip 7 -q