[PATCH 1 of 4] histedit: remove bootstrap dependencies on parentctx
Mateusz Kwapich
mitrandir at fb.com
Mon Feb 2 23:55:19 UTC 2015
# HG changeset patch
# User Mateusz Kwapich <mitrandir at fb.com>
# Date 1421374093 28800
# Thu Jan 15 18:08:13 2015 -0800
# Node ID 497852d2397b0a6f9ad9467c64d3441d912a8924
# Parent 0850d3f920a11370d564d5fe9a67c35fc8c347ba
histedit: remove bootstrap dependencies on parentctx
To make histedit more robust to commits disappearing in between actions, let's
make bootstrapcontinue() not depend on the old parentctx existing.
diff --git a/hgext/histedit.py b/hgext/histedit.py
--- a/hgext/histedit.py
+++ b/hgext/histedit.py
@@ -715,29 +715,29 @@
if os.path.exists(repo.sjoin('undo')):
os.unlink(repo.sjoin('undo'))
-def gatherchildren(repo, ctx):
- # is there any new commit between the expected parent and "."
- #
- # note: does not take non linear new change in account (but previous
- # implementation didn't used them anyway (issue3655)
- newchildren = [c.node() for c in repo.set('(%d::.)', ctx)]
- if ctx.node() != node.nullid:
- if not newchildren:
- # `ctx` should match but no result. This means that
- # currentnode is not a descendant from ctx.
- msg = _('%s is not an ancestor of working directory')
- hint = _('use "histedit --abort" to clear broken state')
- raise util.Abort(msg % ctx, hint=hint)
- newchildren.pop(0) # remove ctx
- return newchildren
+def bootstrapcontinue(ui, state, opts):
+ repo, oldparentctxnode = state.repo, state.parentctxnode
+ action, rulenode = state.rules.pop(0)
+ rulenode = node.bin(rulenode)
+ rulectx = None
+ if rulenode in repo:
+ rulectx = repo[rulenode]
-def bootstrapcontinue(ui, state, opts):
- repo, parentctxnode = state.repo, state.parentctxnode
- parentctx = repo[parentctxnode]
- action, currentnode = state.rules.pop(0)
- ctx = repo[currentnode]
+ # Record new commits between the original parent and the wctx, if any.
+ newchildren = [c.node() for c in repo.set('(%n::. - %n)',
+ oldparentctxnode, oldparentctxnode)]
- newchildren = gatherchildren(repo, parentctx)
+ reusectx = rulectx
+ if not reusectx and action in ('r', 'roll'):
+ # roll is just going to remove the commit anyway, so just use
+ # anything
+ reusectx = repo['.']
+ if not reusectx:
+ raise util.Abort(_("unable to commit pending changes - "
+ "previous commit %s is not available to reuse the commit "
+ "message") % node.short(rulenode))
+
+ parentctxnode = repo['.'].node()
# Commit dirty working directory if necessary
new = None
@@ -745,26 +745,26 @@
if s.modified or s.added or s.removed or s.deleted:
# prepare the message for the commit to comes
if action in ('f', 'fold', 'r', 'roll'):
- message = 'fold-temp-revision %s' % currentnode[:12]
+ message = 'fold-temp-revision %s' % node.short(rulenode)
else:
- message = ctx.description()
+ message = reusectx.description()
editopt = action in ('e', 'edit', 'm', 'mess')
canonaction = {'e': 'edit', 'm': 'mess', 'p': 'pick'}
editform = 'histedit.%s' % canonaction.get(action, action)
editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
- commit = commitfuncfor(repo, ctx)
- new = commit(text=message, user=ctx.user(), date=ctx.date(),
- extra=ctx.extra(), editor=editor)
+ commit = commitfuncfor(repo, reusectx)
+ new = commit(text=message, user=reusectx.user(), date=reusectx.date(),
+ extra=reusectx.extra(), editor=editor)
if new is not None:
newchildren.append(new)
replacements = []
# track replacements
- if ctx.node() not in newchildren:
+ if rulenode not in newchildren:
# note: new children may be empty when the changeset is dropped.
# this happen e.g during conflicting pick where we revert content
# to parent.
- replacements.append((ctx.node(), tuple(newchildren)))
+ replacements.append((rulenode, tuple(newchildren)))
if action in ('f', 'fold', 'r', 'roll'):
if newchildren:
@@ -777,20 +777,26 @@
if action in ('r', 'roll'):
foldopts = foldopts.copy()
foldopts['rollup'] = True
- parentctx, repl = finishfold(ui, repo, parentctx, ctx.node(),
- ctx.description(), new, foldopts,
- newchildren)
+ foldintoctx = None
+ if oldparentctxnode in repo:
+ foldintoctx = repo[oldparentctxnode]
+ else:
+ foldintoctx = repo['.'].parents()[0]
+ parentctx, repl = finishfold(ui, repo, foldintoctx, rulenode,
+ reusectx.description(), new,
+ foldopts, newchildren)
+ parentctxnode = parentctx.node()
replacements.extend(repl)
else:
# newchildren is empty if the fold did not result in any commit
# this happen when all folded change are discarded during the
# merge.
- replacements.append((ctx.node(), (parentctx.node(),)))
+ replacements.append((rulenode, (parentctxnode,)))
elif newchildren:
# otherwise update "parentctx" before proceeding to further operation
- parentctx = repo[newchildren[-1]]
+ parentctxnode = repo[newchildren[-1]].node()
- state.parentctxnode = parentctx.node()
+ state.parentctxnode = parentctxnode
state.replacements.extend(replacements)
return state
diff --git a/tests/test-histedit-arguments.t b/tests/test-histedit-arguments.t
--- a/tests/test-histedit-arguments.t
+++ b/tests/test-histedit-arguments.t
@@ -103,35 +103,6 @@
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg up --quiet
-Run on a revision not descendants of the initial parent
---------------------------------------------------------------------
-
-Test the message shown for inconsistent histedit state, which may be
-created (and forgotten) by Mercurial earlier than 2.7. This emulates
-Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
-temporarily.
-
- $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
- > edit 08d98a8350f3 4 five
- > EOF
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
- reverting alpha
- Make changes as needed, you may commit or record as needed now.
- When you are finished, run hg histedit --continue to resume.
- [1]
-
- $ mv .hg/histedit-state .hg/histedit-state.back
- $ hg update --quiet --clean 2
- $ mv .hg/histedit-state.back .hg/histedit-state
-
- $ hg histedit --continue
- abort: c8e68270e35a is not an ancestor of working directory
- (use "histedit --abort" to clear broken state)
- [255]
-
- $ hg histedit --abort
- $ hg update --quiet --clean
-
Test that missing revisions are detected
---------------------------------------
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
@@ -343,3 +343,5 @@
$ HGEDITOR=true hg histedit --continue
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
saved backup bundle to $TESTTMP/r0/.hg/strip-backup/cb9a9f314b8b-cc5ccb0b-backup.hg (glob)
+
+
diff --git a/tests/test-histedit-obsolete.t b/tests/test-histedit-obsolete.t
--- a/tests/test-histedit-obsolete.t
+++ b/tests/test-histedit-obsolete.t
@@ -457,3 +457,50 @@
abort: cannot edit history that contains merges
[255]
$ cd ..
+
+Run continue on amended parent
+------------------------------
+Test if histedit can succesfully continue after amending initial parent
+in the middle of histedit.
+
+ $ cat > $TESTTMP/histedit-edit-editor.py <<EOF
+ > #!/usr/bin/env python
+ > import sys
+ > filename = sys.argv[1]
+ > with open(filename) as f:
+ > line1 = f.readline()
+ > line2 = f.readline()
+ > line3 = f.readline()
+ > with open(filename, "w") as f:
+ > f.write(line1)
+ > f.write(line2.replace('pick', 'edit'))
+ > f.write(line3)
+ > EOF
+ $ chmod +x $TESTTMP/histedit-edit-editor.py
+
+ $ hg init histedittest
+ $ cd histedittest
+ $ echo "abc" > file1
+ $ echo "123" > file2
+ $ hg add file1 file2
+ $ hg ci -m "initial"
+ $ echo "def" >> file1
+ $ echo "foo" >> file2
+ $ hg ci -m "commit 1"
+ $ echo "456" >> file2
+ $ hg ci -m "commit 2"
+ $ HGEDITOR="$TESTTMP/histedit-edit-editor.py" hg histedit tip~2
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ reverting file1
+ reverting file2
+ Make changes as needed, you may commit or record as needed now.
+ When you are finished, run hg histedit --continue to resume.
+ [1]
+ $ hg commit --amend -m "initial" file1
+ $ hg histedit --continue --traceback --config extensions.histedit=/data/users/mitrandir/hg/hgext/histedit.py
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log
+ 6:911fe08e3eea (draft) commit 2
+ 5:77b81cdf6a31 (draft) commit 1
+ 4:d133778d3f09 (draft) initial
More information about the Mercurial-devel
mailing list