diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -11,7 +11,7 @@ import peer, changegroup, subrepo, pushk import changelog, dirstate, filelog, manifest, context, bookmarks, phases import lock as lockmod import transaction, store, encoding, exchange, bundle2 -import scmutil, util, extensions, hook, error, revset +import scmutil, util, extensions, hook, error, revset, cmdutil import match as matchmod import merge as mergemod import tags as tagsmod @@ -1084,20 +1084,22 @@ class localrepository(object): lock.release() def rollback(self, dryrun=False, force=False): - wlock = lock = None + wlock = lock = dsguard = None try: wlock = self.wlock() lock = self.lock() if self.svfs.exists("undo"): - return self._rollback(dryrun, force) + dsguard = cmdutil.dirstateguard(self, 'rollback') + + return self._rollback(dryrun, force, dsguard) else: self.ui.warn(_("no rollback information available\n")) return 1 finally: - release(lock, wlock) + release(dsguard, lock, wlock) @unfilteredmethod # Until we get smarter cache management - def _rollback(self, dryrun, force): + def _rollback(self, dryrun, force, dsguard): ui = self.ui try: args = self.vfs.read('undo.desc').splitlines() @@ -1140,6 +1142,9 @@ class localrepository(object): parentgone = (parents[0] not in self.changelog.nodemap or parents[1] not in self.changelog.nodemap) if parentgone: + # prevent dirstateguard from overwriting already restored one + dsguard.close() + self.vfs.rename('undo.dirstate', 'dirstate') try: branch = self.vfs.read('undo.branch') diff --git a/tests/test-import.t b/tests/test-import.t --- a/tests/test-import.t +++ b/tests/test-import.t @@ -428,6 +428,25 @@ patches: import patch1 patch2; rollback working directory now based on revision 0 $ hg --cwd b parents --template 'parent: {rev}\n' parent: 0 + +Test that "hg rollback" doesn't restore dirstate to one at the +beginning of the rollbacked transaction in not-"parent-gone" case. + +invoking pretxncommit hook will cause marking '.hg/dirstate' as a file +to be restored at rollbacking, after DirstateTransactionPlan (see wiki +page for detail). + + $ hg --cwd b branch -q foobar + $ hg --cwd b commit -m foobar + $ hg --cwd b update 0 -q + $ hg --cwd b import ../patch1 ../patch2 --config hooks.pretxncommit=true + applying ../patch1 + applying ../patch2 + $ hg --cwd b update -q 1 + $ hg --cwd b rollback -q + $ hg --cwd b parents --template 'parent: {rev}\n' + parent: 1 + $ rm -r b