diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1455,8 +1455,9 @@ class localrepository(object):
             match.explicitdir = vdirs.append
             match.bad = fail
 
-        wlock = self.wlock()
+        wlock = lock = tr = None
         try:
+            wlock = self.wlock()
             wctx = self[None]
             merge = len(wctx.parents()) > 1
 
@@ -1591,23 +1592,26 @@ class localrepository(object):
                 subrepo.writestate(self, newstate)
 
             p1, p2 = self.dirstate.parents()
+            lock = self.lock()
             hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
             try:
                 self.hook("precommit", throw=True, parent1=hookp1,
                           parent2=hookp2)
+                tr = self.transaction('commit')
                 ret = self.commitctx(cctx, True)
             except: # re-raises
                 if edited:
                     self.ui.write(
                         _('note: commit message saved in %s\n') % msgfn)
                 raise
-
             # update bookmarks, dirstate and mergestate
             bookmarks.update(self, [p1, p2], ret)
             cctx.markcommitted(ret)
             ms.reset()
+            tr.close()
+
         finally:
-            wlock.release()
+            lockmod.release(tr, lock, wlock)
 
         def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2):
             # hack for command that use a temporary commit (eg: histedit)
diff --git a/tests/test-fncache.t b/tests/test-fncache.t
--- a/tests/test-fncache.t
+++ b/tests/test-fncache.t
@@ -96,6 +96,7 @@ Non store repo:
   .hg/phaseroots
   .hg/requires
   .hg/undo
+  .hg/undo.backup.dirstate
   .hg/undo.backupfiles
   .hg/undo.bookmarks
   .hg/undo.branch
@@ -132,6 +133,7 @@ Non fncache repo:
   .hg/store/undo
   .hg/store/undo.backupfiles
   .hg/store/undo.phaseroots
+  .hg/undo.backup.dirstate
   .hg/undo.bookmarks
   .hg/undo.branch
   .hg/undo.desc
@@ -223,6 +225,7 @@ Aborting lock does not prevent fncache w
   $ touch y
   $ hg ci -qAm y
   abort: forced lock failure
+  Exception mercurial.error.Abort: Abort('forced lock failure',) in <bound method lock.__del__ of <mercurial.lock.lock object at *>> ignored (glob)
   [255]
   $ cat .hg/store/fncache
   data/y.i
diff --git a/tests/test-hardlinks.t b/tests/test-hardlinks.t
--- a/tests/test-hardlinks.t
+++ b/tests/test-hardlinks.t
@@ -229,6 +229,7 @@ r4 has hardlinks in the working dir (not
   2 r4/.hg/store/undo.backup.phaseroots
   2 r4/.hg/store/undo.backupfiles
   2 r4/.hg/store/undo.phaseroots
+  2 r4/.hg/undo.backup.dirstate
   2 r4/.hg/undo.bookmarks
   2 r4/.hg/undo.branch
   2 r4/.hg/undo.desc
@@ -264,6 +265,7 @@ Update back to revision 11 in r4 should 
   2 r4/.hg/store/undo.backup.phaseroots
   2 r4/.hg/store/undo.backupfiles
   2 r4/.hg/store/undo.phaseroots
+  2 r4/.hg/undo.backup.dirstate
   2 r4/.hg/undo.bookmarks
   2 r4/.hg/undo.branch
   2 r4/.hg/undo.desc
diff --git a/tests/test-histedit-edit.t b/tests/test-histedit-edit.t
--- a/tests/test-histedit-edit.t
+++ b/tests/test-histedit-edit.t
@@ -364,9 +364,9 @@ check saving last-message.txt, at first
   HG: branch 'default'
   HG: added f
   ====
+  note: commit message saved in .hg/last-message.txt
   transaction abort!
   rollback completed
-  note: commit message saved in .hg/last-message.txt
   abort: pretxncommit.unexpectedabort hook exited with status 1
   [255]
   $ cat .hg/last-message.txt
@@ -388,9 +388,9 @@ action)
   HG: user: test
   HG: branch 'default'
   HG: added f
+  note: commit message saved in .hg/last-message.txt
   transaction abort!
   rollback completed
-  note: commit message saved in .hg/last-message.txt
   abort: pretxncommit.unexpectedabort hook exited with status 1
   [255]
 
diff --git a/tests/test-inherit-mode.t b/tests/test-inherit-mode.t
--- a/tests/test-inherit-mode.t
+++ b/tests/test-inherit-mode.t
@@ -83,6 +83,7 @@ new directories are setgid
   00660 ./.hg/store/undo
   00660 ./.hg/store/undo.backupfiles
   00660 ./.hg/store/undo.phaseroots
+  00660 ./.hg/undo.backup.dirstate
   00660 ./.hg/undo.bookmarks
   00660 ./.hg/undo.branch
   00660 ./.hg/undo.desc
diff --git a/tests/test-mq-qfold.t b/tests/test-mq-qfold.t
--- a/tests/test-mq-qfold.t
+++ b/tests/test-mq-qfold.t
@@ -229,9 +229,9 @@ and that combination of '--edit' and '--
   HG: added aa
   HG: changed a
   ====
+  note: commit message saved in .hg/last-message.txt
   transaction abort!
   rollback completed
-  note: commit message saved in .hg/last-message.txt
   qrefresh interrupted while patch was popped! (revert --all, qpush to recover)
   abort: pretxncommit.unexpectedabort hook exited with status 1
   [255]
diff --git a/tests/test-mq-qnew.t b/tests/test-mq-qnew.t
--- a/tests/test-mq-qnew.t
+++ b/tests/test-mq-qnew.t
@@ -299,9 +299,9 @@ Test saving last-message.txt
   HG: branch 'default'
   HG: no files changed
   ====
+  note: commit message saved in .hg/last-message.txt
   transaction abort!
   rollback completed
-  note: commit message saved in .hg/last-message.txt
   abort: pretxncommit.unexpectedabort hook exited with status 1
   [255]
   $ cat .hg/last-message.txt
diff --git a/tests/test-mq-qrefresh-replace-log-message.t b/tests/test-mq-qrefresh-replace-log-message.t
--- a/tests/test-mq-qrefresh-replace-log-message.t
+++ b/tests/test-mq-qrefresh-replace-log-message.t
@@ -185,9 +185,9 @@ Test saving last-message.txt:
   HG: branch 'default'
   HG: added file2
   ====
+  note: commit message saved in .hg/last-message.txt
   transaction abort!
   rollback completed
-  note: commit message saved in .hg/last-message.txt
   qrefresh interrupted while patch was popped! (revert --all, qpush to recover)
   abort: pretxncommit.unexpectedabort hook exited with status 1
   [255]
@@ -228,9 +228,9 @@ external process
   0:25e397dabed2
   A file2
   ====
+  note: commit message saved in .hg/last-message.txt
   transaction abort!
   rollback completed
-  note: commit message saved in .hg/last-message.txt
   qrefresh interrupted while patch was popped! (revert --all, qpush to recover)
   abort: pretxncommit.unexpectedabort hook exited with status 1
   [255]
diff --git a/tests/test-rollback.t b/tests/test-rollback.t
--- a/tests/test-rollback.t
+++ b/tests/test-rollback.t
@@ -113,9 +113,9 @@ same thing, but run $EDITOR
   > echo "another precious commit message" > "$1"
   > __EOF__
   $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg --config hooks.pretxncommit=false commit 2>&1
+  note: commit message saved in .hg/last-message.txt
   transaction abort!
   rollback completed
-  note: commit message saved in .hg/last-message.txt
   abort: pretxncommit hook exited with status * (glob)
   [255]
   $ cat .hg/last-message.txt
diff --git a/tests/test-tag.t b/tests/test-tag.t
--- a/tests/test-tag.t
+++ b/tests/test-tag.t
@@ -272,9 +272,9 @@ regardless of '--message')
   HG: branch 'tag-and-branch-same-name'
   HG: changed .hgtags
   ====
+  note: commit message saved in .hg/last-message.txt
   transaction abort!
   rollback completed
-  note: commit message saved in .hg/last-message.txt
   abort: pretxncommit.unexpectedabort hook exited with status 1
   [255]
   $ cat .hg/last-message.txt