dirstate: wrap setparent calls with begin/endparentchange (issue4353)
This wraps all the locations of dirstate.setparent with the appropriate
begin/endparentchange calls. This will prevent exceptions during those calls
from causing incoherent dirstates (issue4353).
--- a/hgext/histedit.py Fri Sep 05 11:34:29 2014 -0700
+++ b/hgext/histedit.py Fri Sep 05 11:36:20 2014 -0700
@@ -221,6 +221,7 @@
cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
stats = None
else:
+ repo.dirstate.beginparentchange()
try:
# ui.forcemerge is an internal variable, do not document
repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
@@ -230,6 +231,7 @@
finally:
repo.ui.setconfig('ui', 'forcemerge', '', 'histedit')
repo.setparents(wcpar, node.nullid)
+ repo.dirstate.endparentchange()
repo.dirstate.write()
# fix up dirstate for copies and renames
cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
--- a/hgext/mq.py Fri Sep 05 11:34:29 2014 -0700
+++ b/hgext/mq.py Fri Sep 05 11:36:20 2014 -0700
@@ -816,12 +816,14 @@
merged.append(f)
else:
removed.append(f)
+ repo.dirstate.beginparentchange()
for f in removed:
repo.dirstate.remove(f)
for f in merged:
repo.dirstate.merge(f)
p1, p2 = repo.dirstate.parents()
repo.setparents(p1, merge)
+ repo.dirstate.endparentchange()
if all_files and '.hgsubstate' in all_files:
wctx = repo[None]
@@ -1451,7 +1453,7 @@
if keepchanges and tobackup:
raise util.Abort(_("local changes found, refresh first"))
self.backup(repo, tobackup)
-
+ repo.dirstate.beginparentchange()
for f in a:
util.unlinkpath(repo.wjoin(f), ignoremissing=True)
repo.dirstate.drop(f)
@@ -1460,6 +1462,7 @@
repo.wwrite(f, fctx.data(), fctx.flags())
repo.dirstate.normal(f)
repo.setparents(qp, nullid)
+ repo.dirstate.endparentchange()
for patch in reversed(self.applied[start:end]):
self.ui.status(_("popping %s\n") % patch.name)
del self.applied[start:end]
@@ -1599,6 +1602,7 @@
bmlist = repo[top].bookmarks()
try:
+ repo.dirstate.beginparentchange()
if diffopts.git or diffopts.upgrade:
copies = {}
for dst in a:
@@ -1651,6 +1655,7 @@
# assumes strip can roll itself back if interrupted
repo.setparents(*cparents)
+ repo.dirstate.endparentchange()
self.applied.pop()
self.applieddirty = True
strip(self.ui, repo, [top], update=False, backup=False)
--- a/hgext/rebase.py Fri Sep 05 11:34:29 2014 -0700
+++ b/hgext/rebase.py Fri Sep 05 11:36:20 2014 -0700
@@ -366,7 +366,9 @@
editor=editor)
else:
# Skip commit if we are collapsing
+ repo.dirstate.beginparentchange()
repo.setparents(repo[p1].node())
+ repo.dirstate.endparentchange()
newrev = None
# Update the state
if newrev is not None:
@@ -472,7 +474,9 @@
def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None):
'Commit the changes and store useful information in extra'
try:
+ repo.dirstate.beginparentchange()
repo.setparents(repo[p1].node(), repo[p2].node())
+ repo.dirstate.endparentchange()
ctx = repo[rev]
if commitmsg is None:
commitmsg = ctx.description()
--- a/mercurial/cmdutil.py Fri Sep 05 11:34:29 2014 -0700
+++ b/mercurial/cmdutil.py Fri Sep 05 11:36:20 2014 -0700
@@ -659,6 +659,7 @@
n = None
if update:
+ repo.dirstate.beginparentchange()
if p1 != parents[0]:
updatefunc(repo, p1.node())
if p2 != parents[1]:
@@ -698,6 +699,7 @@
n = repo.commit(message, opts.get('user') or user,
opts.get('date') or date, match=m,
editor=editor, force=partial)
+ repo.dirstate.endparentchange()
else:
if opts.get('exact') or opts.get('import_branch'):
branch = branch or 'default'
--- a/mercurial/commands.py Fri Sep 05 11:34:29 2014 -0700
+++ b/mercurial/commands.py Fri Sep 05 11:36:20 2014 -0700
@@ -483,9 +483,11 @@
try:
ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
'backout')
+ repo.dirstate.beginparentchange()
stats = mergemod.update(repo, parent, True, True, False,
node, False)
repo.setparents(op1, op2)
+ repo.dirstate.endparentchange()
hg._showstats(repo, stats)
if stats[3]:
repo.ui.status(_("use 'hg resolve' to retry unresolved "
@@ -2750,7 +2752,9 @@
wlock = repo.wlock()
try:
+ repo.dirstate.beginparentchange()
repo.setparents(r1, r2)
+ repo.dirstate.endparentchange()
finally:
wlock.release()
@@ -3310,10 +3314,12 @@
cont = False
# drop the second merge parent
+ repo.dirstate.beginparentchange()
repo.setparents(current.node(), nullid)
repo.dirstate.write()
# fix up dirstate for copies and renames
cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
+ repo.dirstate.endparentchange()
# commit
node = repo.commit(text=message, user=user,
@@ -3922,6 +3928,7 @@
try:
try:
wlock = repo.wlock()
+ repo.dirstate.beginparentchange()
if not opts.get('no_commit'):
lock = repo.lock()
tr = repo.transaction('import')
@@ -3962,6 +3969,7 @@
tr.close()
if msgs:
repo.savecommitmessage('\n* * *\n'.join(msgs))
+ repo.dirstate.endparentchange()
return ret
except: # re-raises
# wlock.release() indirectly calls dirstate.write(): since
--- a/mercurial/context.py Fri Sep 05 11:34:29 2014 -0700
+++ b/mercurial/context.py Fri Sep 05 11:36:20 2014 -0700
@@ -1173,11 +1173,13 @@
"""
+ self._repo.dirstate.beginparentchange()
for f in self.modified() + self.added():
self._repo.dirstate.normal(f)
for f in self.removed():
self._repo.dirstate.drop(f)
self._repo.dirstate.setparents(node)
+ self._repo.dirstate.endparentchange()
def dirs(self):
return self._repo.dirstate.dirs()
--- a/mercurial/localrepo.py Fri Sep 05 11:34:29 2014 -0700
+++ b/mercurial/localrepo.py Fri Sep 05 11:36:20 2014 -0700
@@ -758,6 +758,7 @@
return self[changeid].parents()
def setparents(self, p1, p2=nullid):
+ self.dirstate.beginparentchange()
copies = self.dirstate.setparents(p1, p2)
pctx = self[p1]
if copies:
@@ -771,6 +772,7 @@
for f, s in sorted(self.dirstate.copies().items()):
if f not in pctx and s not in pctx:
self.dirstate.copy(None, f)
+ self.dirstate.endparentchange()
def filectx(self, path, changeid=None, fileid=None):
"""changeid can be a changeset revision, node, or tag.
--- a/mercurial/merge.py Fri Sep 05 11:34:29 2014 -0700
+++ b/mercurial/merge.py Fri Sep 05 11:36:20 2014 -0700
@@ -1134,6 +1134,7 @@
stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
if not partial:
+ repo.dirstate.beginparentchange()
repo.setparents(fp1, fp2)
recordupdates(repo, actions, branchmerge)
# update completed, clear state
@@ -1141,6 +1142,7 @@
if not branchmerge:
repo.dirstate.setbranch(p2.branch())
+ repo.dirstate.endparentchange()
finally:
wlock.release()