# HG changeset patch # User Augie Fackler # Date 2018-12-04 22:13:01 # Node ID cb372d09d30a94f220624fe64c5a0dfd20733305 # Parent e13ab4acf555daf8fac593127b6a076288551710 # Parent 47719d7c581f18c1e6c98b05e2f79307c2ea50bd merge with stable diff --git a/.hgsigs b/.hgsigs --- a/.hgsigs +++ b/.hgsigs @@ -172,3 +172,4 @@ ede3bf31fe63677fdf5bd8db687977d4e3d792ed 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAluyfokQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91eWpD/0eu/JfD6SfaT4Ozd2767ojNIW4M9BgcRH/FehFBd/3iQ/YQmaMVd6GmdaagM5YUpD9U+rDK95l8rUstuTglXeKD2SVcDM4Oq9ToyZyp5aizWjkxRxHT60W95G5FQO/tBbs63jfNrVDWDElbkpcn/gUG6JbX+q/S/mKd6WsuwNQC1N4VOWp0OWCmFGBWN7t/DqxGLGEajJM0NB97/r/IV6TzrGtaPf1CXaepDVvZwIIeas/eQgGInyqry7WBSn5sCUq4opIh1UigMABUAgzIZbgTg8NLGSmEgRgk0Vb4K+pLejLLDb5YD7ZwuUCkbd8oJImKQfU6++Ajd70TbNQRvVhMtd15iCtOOjLR+VNkUiDXm0g1U53sREMLdj/+SMJZB6Z18DotdgpaeCmwA/wWijXOdt76xwUKjByioxyQilPrzrWGaoSG4ynjiD2Y+eSRS1DxbpDgt4YEuiVA6U3ay99oW7KkhFjQsUtKl4SJ5SQWiEofvgtb2maNrXkPtKOtNRHhc61v73zYnsxtl2qduC99YOTin90FykD80XvgJZfyow/LICb77MNGwYBsJJMDQ3jG1YyUC2CQsb8wyrWM4TO3tspKAQPyMegUaVtBqw7ZhgiC3OXEes+z+AL5YRSZXALfurXPYbja8M8uGL2TYB3/5bKYvBXxvfmSGIeY6VieQ== 956ec6f1320df26f3133ec40f3de866ea0695fd7 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAlvOG20QHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91eZ+EACb/XfPWaMkwIX54JaFWtL/nVkDcaL8xLVzlI+PxL0ZtHdQTGVQNp5f1BnZU9RKPZ9QOuz+QKNvb4hOOXBwmCi2AAjmTYUqtKThHmOT50ZRICkllY+YlZ3tI6JXRDhh7pSXaus8jBFG/VwuUlVmK5sA2TP+lIJijOgV9rThszfS4Q2I8sBTIaeZS1hyujFxGRO++tjYR+jPuo/98FhqJ5EylVYvKmnflWkOYLFNFqgDI6DQs7Dl+u2nrNAzZJQlgk+1ekd66T3WyK8U3tcFLZGRQ+gpzINH0Syn6USaaE+0nGi4we1hJS8JK0txWyHXJGNZYaWQAC2l1hIBfA38azwVLSe2w9JatXhS3HWByILy8JkEQ2kSo1xTD4mBkszZo/kWZpZRsAWydxCnzhNgKmTJYxASFTTX1mpdX4EzJBOs/++52y1OjVc0Ko0+6vSwxsC6zgIGJx1Os7vVgWHql0XbDmJ1NDdNmz7q5HjFcbNOWScKf6UGcBKV4dpW1w+7CvdoMFHUsVTa2zn6YOki3NEt0GWLXq+0aXbHSw8XETcyunQKjDi9ddKOw0rYGip6EKUKhOILZimQ0lgYRE23RDdT5Tl2D8s66SUuipgP9vGjbMaE/FhO3OAb7406jyCrOVfDis7sK0Hvw074GhIfZUjA4W4Ey2TeExCZHHhBdoPTrg== a91a2837150bdcb27ae76b3646e6c93cd6a15904 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAlvclPMQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91fc0EADF/62jqCARFaQRRcKpobPNBZupwSbnQ7E296ZRwHdZvT8CVGfkWBUIStyh+r8bfmBzzea6d9/SUoRqCoV9rwCXuRbeCZZRMMkqx9IblV3foaIOxyQi0KE2lpzGJAHxPiNxD3czZV4B+P6X2wNmG9OLjmHyQ7o64GvPAJ+Ko/EsND1tkx4qB16mEuEHVxtfaG6hbjgpLekIA3+3xur3E8cWBsNO28HtQBK83r2qURwv6eG3TfkbmiE+Ie5TNC15LPVhAOHVSD7miZdI82uk2063puCKZxIJXsy7EMjHfChTM9c7B4+TdEBjms3y+Byz2EV7kRfjplGOnBbYvfY7qiteTn/22+rLrTTQNkndDN/Sqr1DjwsvxKDeIfsqgXzGQPupLOrGdGf4ILAtA0Reme7VKNN5Px6dNxnjKKwsnSrKTQ7ZcmD+W1LKlL63lBEQvEy+TLmmFLfM2xvvBxL5177AKZrj/8gMUzEi1K2MelDGrasA7OSjTlABoleDvZzVOf1nC0Bv83tFc8FeMHLwNOxkFSsjORvZuIH/G9BYUTAd96iLwQRBxXLOVNitxAOQT+s3hs7JEaUzTHlAY+lNeFAxUujb4H0V40Xgr20O1u7PJ53tzApIrg9JQPgvUXntmRs8fpNo6f3P6Sg8XtaCCHIUAB6qTHiose56llf6bzl66A== +1c8c54cf97256f4468da2eb4dbee24f7f3888e71 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAlwG+eIQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91YqSD/9IAwdaPrOeiT+DVBW2x33oFeY1X1f5CBG/vCJptalOd2QDIsD0ANEzQHmzV25RKD851v155Txt/BPlkuBfO/kg0BbOoqTpGZk+5CcoFWeyhJct2CxtCLdEpyZ/98/htMR4VfWprCX2GHXPjS813l9pebsN3WgBUOc2VaUdHNRoAGsMVgWC5BWwNP4XSA9oixFL/O4aGLQ6pPfP3vmMFySWXWnIN8gUZ4sm53eKaT0QCICAgzFh+GzRd81uACDfoJn1d8RS9GK+h6j8x0crLY5CpQQy8lRVkokvc0h6XK44ofc57p9GHAOfprHY3DbBhD9H6fLAf5raUsqPkLRYVGqhg8bOsBr3vJ56hiXJYOYPZSYXGjnHRcUrgfPVrY+6mPTeCIQMPmWBHwYH5Tc5TLrPuxxCL4wVywqGbfmIVP+WFUikkykAAwuPOZAswxJJOB0gsnnxcApmTeXRznBXyvzscMlWVZiMjzflKRRJ9V5RI4Fdc6n1wQ4vuLSO4AUnIypIsV6ZFAOBuFKH7x6nPG0tP3FYzcICaMOPbxEx3LStnuU+UuEs6TIxM6IiR3LPiiDGZ2BA2gjJhDxQFV8hAl8KDO3LsYuyUQCv3RTAP+YejH21bIXdnwDlNqy8Hrd53rq7jZsdb2pMVvOZZ3VmIu64f+jVkD/r5msDUkQL3M9jwg== diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -185,3 +185,4 @@ ede3bf31fe63677fdf5bd8db687977d4e3d792ed 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8 +1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1 diff --git a/hgext/extdiff.py b/hgext/extdiff.py --- a/hgext/extdiff.py +++ b/hgext/extdiff.py @@ -430,6 +430,7 @@ def uisetup(ui): 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: diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -542,7 +542,7 @@ class rebaseruntime(object): 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', '')} @@ -867,7 +867,11 @@ def rebase(ui, repo, **opts): 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) diff --git a/mercurial/cext/revlog.c b/mercurial/cext/revlog.c --- a/mercurial/cext/revlog.c +++ b/mercurial/cext/revlog.c @@ -158,6 +158,12 @@ static const char *index_deref(indexObje 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) { @@ -180,7 +186,7 @@ static inline int index_get_parents(inde } /* 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; } @@ -2688,6 +2694,16 @@ void rustlazyancestors_drop(rustlazyance 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) { @@ -2729,7 +2745,8 @@ static int rustla_init(rustlazyancestors 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; } diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py --- a/mercurial/commandserver.py +++ b/mercurial/commandserver.py @@ -526,7 +526,15 @@ class unixforkingservice(object): # 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: diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -1843,6 +1843,11 @@ class overlayworkingctx(committablectx): 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 @@ -1877,19 +1882,19 @@ class overlayworkingctx(committablectx): 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 " diff --git a/mercurial/thirdparty/selectors2.py b/mercurial/thirdparty/selectors2.py --- a/mercurial/thirdparty/selectors2.py +++ b/mercurial/thirdparty/selectors2.py @@ -708,7 +708,7 @@ else: 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 diff --git a/mercurial/wireprotov2peer.py b/mercurial/wireprotov2peer.py --- a/mercurial/wireprotov2peer.py +++ b/mercurial/wireprotov2peer.py @@ -377,25 +377,30 @@ class clienthandler(object): # 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 @@ -458,7 +463,10 @@ class clienthandler(object): 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: @@ -470,7 +478,7 @@ class clienthandler(object): 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()) diff --git a/tests/test-fuzz-targets.t b/tests/test-fuzz-targets.t --- a/tests/test-fuzz-targets.t +++ b/tests/test-fuzz-targets.t @@ -2,11 +2,36 @@ $ 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 < #include + > #include + > 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 diff --git a/tests/test-parseindex.t b/tests/test-parseindex.t --- a/tests/test-parseindex.t +++ b/tests/test-parseindex.t @@ -133,12 +133,18 @@ Test corrupted p1/p2 fields that could c $ 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" < 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) @@ -154,6 +160,11 @@ Test corrupted p1/p2 fields that could c 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 @@ -193,6 +204,12 @@ Test corrupted p1/p2 fields that could c 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 diff --git a/tests/test-rebase-inmemory.t b/tests/test-rebase-inmemory.t --- a/tests/test-rebase-inmemory.t +++ b/tests/test-rebase-inmemory.t @@ -1,5 +1,7 @@ #require symlink execbit $ cat << EOF >> $HGRCPATH + > [phases] + > publish=False > [extensions] > amend= > rebase= @@ -54,6 +56,7 @@ Rebase a simple DAG: b (no-eol) $ hg cat -r 2 c c (no-eol) + $ cd .. Case 2: $ hg init repo2 @@ -177,7 +180,7 @@ Test reporting of path conflicts $ 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' @@ -218,7 +221,7 @@ Test reporting of path conflicts $ 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!' @@ -237,9 +240,48 @@ Test reporting of path conflicts |/ 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 @@ -420,7 +462,6 @@ In-memory rebase that fails due to merge 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" @@ -428,6 +469,46 @@ In-memory rebase that fails due to merge 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|