[PATCH 5 of 5] import: wrap a transaction around the whole command

Greg Ward greg-hg at gerg.ca
Sun Oct 2 13:37:34 CDT 2011


# HG changeset patch
# User Greg Ward <greg at gerg.ca>
# Date 1317580468 14400
# Node ID 6fd1ab0c79fd2f1718de84fdb8cdeb9e39ecd1ac
# Parent  6965157abf1cac4a190590acff61d08ef6319d06
import: wrap a transaction around the whole command

Now 'rollback' after 'import' is less surprising: it rolls back all of
the imported changesets, not just the last one. As an extra added
benefit, you don't need 'rollback -f' after 'import --bypass', which
was an undesired side effect of fixing issue2998 (59e8bc22506e)..

Note that this is a different take on issue963, which complained that
rollback after importing multiple patches returned the working dir
parent to the starting point, not to the second-last patch applied.
Since we now rollback the entire import, returning the working dir to
the starting point is entirely logical. So this change also undoes
a732eebf1958, the fix to issue963, and updates its tests accordingly.

Bottom line: rollback after import was weird before issue963,
understandable since the fix for issue963, and even better now.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -3262,7 +3262,7 @@
 
     base = opts["base"]
     strip = opts["strip"]
-    wlock = lock = None
+    wlock = lock = tr = None
     msgs = []
 
     def checkexact(repo, n, nodeid):
@@ -3333,9 +3333,6 @@
                                     opts.get('date') or date, match=m,
                                     editor=cmdutil.commiteditor)
                     checkexact(repo, n, nodeid)
-                    # Force a dirstate write so that the next transaction
-                    # backups an up-to-date file.
-                    repo.dirstate.write()
             else:
                 if opts.get('exact') or opts.get('import_branch'):
                     branch = branch or 'default'
@@ -3369,6 +3366,7 @@
     try:
         wlock = repo.wlock()
         lock = repo.lock()
+        tr = repo.transaction('import')
         parents = repo.parents()
         for patchurl in patches:
             if patchurl == '-':
@@ -3394,9 +3392,18 @@
             if not haspatch:
                 raise util.Abort(_('%s: no diffs found') % patchurl)
 
+        tr.close()
         if msgs:
             repo.savecommitmessage('\n* * *\n'.join(msgs))
+    except:
+        # wlock.release() indirectly calls dirstate.write(): since
+        # we're crashing, we do not want to change the working dir
+        # parent after all, so make sure it writes nothing
+        repo.dirstate.invalidate()
+        raise
     finally:
+        if tr:
+            tr.release()
         release(lock, wlock)
 
 @command('incoming|in',
diff --git a/tests/test-import-bypass.t b/tests/test-import-bypass.t
--- a/tests/test-import-bypass.t
+++ b/tests/test-import-bypass.t
@@ -60,8 +60,8 @@
   |/
   @  0:07f494440405 test 0 0 - default - adda
   
-  $ hg rollback -f
-  repository tip rolled back to revision 1 (undo commit)
+  $ hg rollback
+  repository tip rolled back to revision 1 (undo import)
 
 Test --import-branch
 
@@ -72,8 +72,8 @@
   |
   @  0:07f494440405 test 0 0 - default - adda
   
-  $ hg rollback -f
-  repository tip rolled back to revision 1 (undo commit)
+  $ hg rollback
+  repository tip rolled back to revision 1 (undo import)
 
 Test --strip
 
@@ -94,8 +94,8 @@
   > +a
   > EOF
   applying patch from stdin
-  $ hg rollback -f
-  repository tip rolled back to revision 1 (undo commit)
+  $ hg rollback
+  repository tip rolled back to revision 1 (undo import)
 
 Test unsupported combinations
 
diff --git a/tests/test-import.t b/tests/test-import.t
--- a/tests/test-import.t
+++ b/tests/test-import.t
@@ -365,10 +365,10 @@
   a
   created 6d019af21222
   $ hg --cwd b rollback
-  repository tip rolled back to revision 1 (undo commit)
-  working directory now based on revision 1
+  repository tip rolled back to revision 0 (undo import)
+  working directory now based on revision 0
   $ hg --cwd b parents --template 'parent: {rev}\n'
-  parent: 1
+  parent: 0
   $ rm -r b
 
 
@@ -688,6 +688,7 @@
   adding a
   $ hg ci -m "commit"
   $ cat > a.patch <<EOF
+  > add a, b
   > diff --git a/a b/a
   > --- a/a
   > +++ b/a
@@ -698,9 +699,25 @@
   > EOF
   $ hg import --no-commit a.patch
   applying a.patch
+
+apply a good patch followed by an empty patch (mainly to ensure
+that dirstate is *not* updated when import crashes)
+  $ hg update -q -C .
+  $ rm b
+  $ touch empty.patch
+  $ hg import a.patch empty.patch
+  applying a.patch
+  applying empty.patch
+  transaction abort!
+  rollback completed
+  abort: empty.patch: no diffs found
+  [255]
+  $ hg tip --template '{rev}  {desc|firstline}\n'
+  0  commit
+  $ hg -q status
+  M a
   $ cd ..
 
-
 create file when source is not /dev/null
 
   $ cat > create.patch <<EOF
diff --git a/tests/test-keyword.t b/tests/test-keyword.t
--- a/tests/test-keyword.t
+++ b/tests/test-keyword.t
@@ -825,7 +825,7 @@
   ignore $Id$
 
   $ hg rollback
-  repository tip rolled back to revision 2 (undo commit)
+  repository tip rolled back to revision 2 (undo import)
   working directory now based on revision 2
   $ hg update --clean
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved


More information about the Mercurial-devel mailing list