Patchwork [Bug,4344] New: Interrupting a strip at the wrong time can result in an unknown working parent error

login
register
mail settings
Submitter mercurial-bugs@selenic.com
Date Aug. 22, 2014, 5:11 a.m.
Message ID <bug-4344-285@http.bz.selenic.com/>
Download mbox | patch
Permalink /patch/5553/
State Not Applicable
Headers show

Comments

mercurial-bugs@selenic.com - Aug. 22, 2014, 5:11 a.m.
http://bz.selenic.com/show_bug.cgi?id=4344

          Priority: normal
            Bug ID: 4344
                CC: mercurial-devel@selenic.com
          Assignee: bugzilla@selenic.com
           Summary: Interrupting a strip at the wrong time can result in
                    an unknown working parent error
          Severity: bug
    Classification: Unclassified
                OS: All
          Reporter: sid0@fb.com
          Hardware: All
            Status: UNCONFIRMED
           Version: 3.1
         Component: Mercurial
           Product: Mercurial

Interrupting a strip at the wrong time -- e.g. with SIGHUP or Ctrl-C -- can
leave the working copy in a state where the dirstate's parent is unknown.

When we're not stripping tipmost commits, strip computes a list of revs that
need to be popped off along with the revs to strip, called the revs to save.
Strip then has three phases:
(1) bundle revs to strip and revs to save in two separate bundles
(2) remove revs to strip and revs to save in one go
(3) reapply revs to save

If the working directory is currently pointing to one of the revs to save, and
the strip is interrupted after step 2 is done but before step 3 is complete,
the working directory will be left with an unknown parent.

A related issue is that while the bundle of revs to save is left on disk, its
path isn't printed out and there is no way to recover the original revs without
digging into the strip-backup directory. 

The following test change demonstrates the issue. After applying the patch, run
test-strip.t.

Patch

diff --git a/tests/stripfailure.py b/tests/stripfailure.py
new file mode 100644
--- /dev/null
+++ b/tests/stripfailure.py
@@ -0,0 +1,10 @@ 
+from mercurial import changegroup, extensions, util
+
+def wrapaddchangegroup(orig, repo, source, srctype, *args, **kwargs):
+    if (srctype == 'strip'
+        and repo.ui.configbool('stripfailure', 'addchangegroup', False)):
+        raise util.Abort('emulating unexpected addchangegroup abort')
+    return orig(repo, source, srctype, *args, **kwargs)
+
+def reposetup(ui, repo):
+    extensions.wrapfunction(changegroup, 'addchangegroup', wrapaddchangegroup)
diff --git a/tests/test-strip.t b/tests/test-strip.t
--- a/tests/test-strip.t
+++ b/tests/test-strip.t
@@ -1,5 +1,6 @@ 
   $ echo "[extensions]" >> $HGRCPATH
   $ echo "strip=" >> $HGRCPATH
+  $ echo "stripfailure=$TESTDIR/stripfailure.py" >> $HGRCPATH

   $ restore() {
   >     hg unbundle -q .hg/strip-backup/*
@@ -102,6 +103,11 @@ 
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     b

+  $ echo "[stripfailure]" >> $HGRCPATH
+  $ echo "addchangegroup=1" >> $HGRCPATH
+  $ teststrip 4 2
+  $ echo "addchangegroup=0" >> $HGRCPATH
+
   $ teststrip 1 4
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
   % before update 1, strip 4
@@ -363,6 +369,7 @@ 

 strip of applied mq should cleanup status file

+  $ echo "[extensions]" >> $HGRCPATH
   $ echo "mq=" >> $HGRCPATH
   $ hg up -C 3
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved