diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1098,7 +1098,8 @@ class localrepository(object): aftertrans(renames), self.store.createmode, validator=validate, - releasefn=releasefn) + releasefn=releasefn, + checkambigfiles=_cachedfiles) tr.changes['revs'] = set() tr.changes['obsmarkers'] = set() @@ -1164,7 +1165,8 @@ class localrepository(object): vfsmap = {'': self.svfs, 'plain': self.vfs,} transaction.rollback(self.svfs, vfsmap, "journal", - self.ui.warn) + self.ui.warn, + checkambigfiles=_cachedfiles) self.invalidate() return True else: @@ -1220,7 +1222,8 @@ class localrepository(object): parents = self.dirstate.parents() self.destroying() vfsmap = {'plain': self.vfs, '': self.svfs} - transaction.rollback(self.svfs, vfsmap, 'undo', ui.warn) + transaction.rollback(self.svfs, vfsmap, 'undo', ui.warn, + checkambigfiles=_cachedfiles) if self.vfs.exists('undo.bookmarks'): self.vfs.rename('undo.bookmarks', 'bookmarks', checkambig=True) if self.svfs.exists('undo.phaseroots'): diff --git a/mercurial/transaction.py b/mercurial/transaction.py --- a/mercurial/transaction.py +++ b/mercurial/transaction.py @@ -44,11 +44,12 @@ def active(func): return _active def _playback(journal, report, opener, vfsmap, entries, backupentries, - unlink=True): + unlink=True, checkambigfiles=None): for f, o, _ignore in entries: if o or not unlink: + checkambig = checkambigfiles and (f, '') in checkambigfiles try: - fp = opener(f, 'a', checkambig=True) + fp = opener(f, 'a', checkambig=checkambig) fp.truncate(o) fp.close() except IOError: @@ -101,7 +102,8 @@ def _playback(journal, report, opener, v class transaction(object): def __init__(self, report, opener, vfsmap, journalname, undoname=None, - after=None, createmode=None, validator=None, releasefn=None): + after=None, createmode=None, validator=None, releasefn=None, + checkambigfiles=None): """Begin a new transaction Begins a new transaction that allows rolling back writes in the event of @@ -110,6 +112,10 @@ class transaction(object): * `after`: called after the transaction has been committed * `createmode`: the mode of the journal file that will be created * `releasefn`: called after releasing (with transaction and result) + + `checkambigfiles` is a set of (path, vfs-location) tuples, + which determine whether file stat ambiguity should be avoided + for corresponded files. """ self.count = 1 self.usages = 1 @@ -137,6 +143,10 @@ class transaction(object): releasefn = lambda tr, success: None self.releasefn = releasefn + self.checkambigfiles = set() + if checkambigfiles: + self.checkambigfiles.update(checkambigfiles) + # A dict dedicated to precisely tracking the changes introduced in the # transaction. self.changes = {} @@ -564,7 +574,8 @@ class transaction(object): # Prevent double usage and help clear cycles. self._abortcallback = None _playback(self.journal, self.report, self.opener, self._vfsmap, - self.entries, self._backupentries, False) + self.entries, self._backupentries, False, + checkambigfiles=self.checkambigfiles) self.report(_("rollback completed\n")) except BaseException: self.report(_("rollback failed - please run hg recover\n")) @@ -573,7 +584,7 @@ class transaction(object): self.releasefn(self, False) # notify failure of transaction self.releasefn = None # Help prevent cycles. -def rollback(opener, vfsmap, file, report): +def rollback(opener, vfsmap, file, report, checkambigfiles=None): """Rolls back the transaction contained in the given file Reads the entries in the specified file, and the corresponding @@ -584,6 +595,10 @@ def rollback(opener, vfsmap, file, repor file\0offset pairs, delimited by newlines. The corresponding '*.backupfiles' file should contain a list of file\0backupfile pairs, delimited by \0. + + `checkambigfiles` is a set of (path, vfs-location) tuples, + which determine whether file stat ambiguity should be avoided at + restoring corresponded files. """ entries = [] backupentries = [] @@ -615,4 +630,5 @@ def rollback(opener, vfsmap, file, repor report(_("journal was created by a different version of " "Mercurial\n")) - _playback(file, report, opener, vfsmap, entries, backupentries) + _playback(file, report, opener, vfsmap, entries, backupentries, + checkambigfiles=checkambigfiles) diff --git a/tests/test-mq-qpush-fail.t b/tests/test-mq-qpush-fail.t --- a/tests/test-mq-qpush-fail.t +++ b/tests/test-mq-qpush-fail.t @@ -39,8 +39,9 @@ test qpush on empty series > from mercurial import extensions, transaction > def wrapplayback(orig, > journal, report, opener, vfsmap, entries, backupentries, - > unlink=True): - > orig(journal, report, opener, vfsmap, entries, backupentries, unlink) + > unlink=True, checkambigfiles=None): + > orig(journal, report, opener, vfsmap, entries, backupentries, unlink, + > checkambigfiles) > # Touching files truncated at "transaction.abort" causes > # forcible re-loading invalidated filecache properties > # (including repo.changelog)