[PATCH 2 of 2] histedit: store backup file before histedit
Augie Fackler
raf at durin42.com
Wed Apr 15 22:33:12 UTC 2015
On Tue, Apr 14, 2015 at 10:06:55AM -0700, Durham Goode wrote:
> # HG changeset patch
> # User Durham Goode <durham at fb.com>
> # Date 1428140263 25200
> # Sat Apr 04 02:37:43 2015 -0700
> # Node ID 75d4d58c15fc9c2f8b3a5e9db02f7bc77143300e
> # Parent 6289acbbd36ec81eab91ed3b8e32b3354bf8cf84
> histedit: store backup file before histedit
Queued these, thanks.
>
> It's possible for the user to delete some of the commits they started with
> during a histedit, and aborting the histedit doesn't bring them back. Let's
> store a backup bundle so we can always recover the stack of commits from before
> they began.
>
> diff --git a/hgext/histedit.py b/hgext/histedit.py
> --- a/hgext/histedit.py
> +++ b/hgext/histedit.py
> @@ -163,8 +163,10 @@ import sys
> from mercurial import cmdutil
> from mercurial import discovery
> from mercurial import error
> +from mercurial import changegroup
> from mercurial import copies
> from mercurial import context
> +from mercurial import exchange
> from mercurial import extensions
> from mercurial import hg
> from mercurial import node
> @@ -206,6 +208,7 @@ class histeditstate(object):
> self.parentctxnode = parentctxnode
> self.lock = lock
> self.wlock = wlock
> + self.backupfile = None
> if replacements is None:
> self.replacements = []
> else:
> @@ -223,15 +226,17 @@ class histeditstate(object):
> try:
> data = pickle.load(fp)
> parentctxnode, rules, keep, topmost, replacements = data
> + backupfile = None
> except pickle.UnpicklingError:
> data = self._load()
> - parentctxnode, rules, keep, topmost, replacements = data
> + parentctxnode, rules, keep, topmost, replacements, backupfile = data
>
> self.parentctxnode = parentctxnode
> self.rules = rules
> self.keep = keep
> self.topmost = topmost
> self.replacements = replacements
> + self.backupfile = backupfile
>
> def write(self):
> fp = self.repo.vfs('histedit-state', 'w')
> @@ -246,6 +251,7 @@ class histeditstate(object):
> for replacement in self.replacements:
> fp.write('%s%s\n' % (node.hex(replacement[0]), ''.join(node.hex(r)
> for r in replacement[1])))
> + fp.write('%s\n' % self.backupfile)
> fp.close()
>
> def _load(self):
> @@ -288,9 +294,12 @@ class histeditstate(object):
> replacements.append((original, succ))
> index += 1
>
> + backupfile = lines[index]
> + index += 1
> +
> fp.close()
>
> - return parentctxnode, rules, keep, topmost, replacements
> + return parentctxnode, rules, keep, topmost, replacements, backupfile
>
> def clear(self):
> self.repo.vfs.unlink('histedit-state')
> @@ -695,6 +704,16 @@ def _histedit(ui, repo, state, *freeargs
> state.read()
> mapping, tmpnodes, leafs, _ntm = processreplacement(state)
> ui.debug('restore wc to old parent %s\n' % node.short(state.topmost))
> +
> + # Recover our old commits if necessary
> + if not state.topmost in repo and state.backupfile:
> + backupfile = repo.join(state.backupfile)
> + f = hg.openpath(ui, backupfile)
> + gen = exchange.readbundle(ui, f, backupfile)
> + changegroup.addchangegroup(repo, gen, 'histedit',
> + 'bundle:' + backupfile)
> + os.remove(backupfile)
> +
> # check whether we should update away
> parentnodes = [c.node() for c in repo[None].parents()]
> for n in leafs | set([state.parentctxnode]):
> @@ -753,6 +772,13 @@ def _histedit(ui, repo, state, *freeargs
> state.topmost = topmost
> state.replacements = replacements
>
> + # Create a backup so we can always abort completely.
> + backupfile = None
> + if not obsolete.isenabled(repo, obsolete.createmarkersopt):
> + backupfile = repair._bundle(repo, [parentctxnode], [topmost], root,
> + 'histedit')
> + state.backupfile = backupfile
> +
> while state.rules:
> state.write()
> action, ha = state.rules.pop(0)
> 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
> @@ -147,6 +147,34 @@ qnew should fail while we're in the midd
> $ hg cat e
> a
>
> +Stripping necessary commits should not break --abort
> +
> + $ hg histedit 1a60820cd1f6 --commands - 2>&1 << EOF| fixbundle
> + > edit 1a60820cd1f6 wat
> + > pick a5e1ba2f7afb foobaz
> + > pick b5f70786f9b0 g
> + > EOF
> + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
> + Make changes as needed, you may commit or record as needed now.
> + When you are finished, run hg histedit --continue to resume.
> +
> + $ mv .hg/histedit-state .hg/histedit-state.bak
> + $ hg strip -q -r b5f70786f9b0
> + $ mv .hg/histedit-state.bak .hg/histedit-state
> + $ hg histedit --abort
> + adding changesets
> + adding manifests
> + adding file changes
> + added 1 changesets with 1 changes to 3 files
> + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
> + $ hg log -r .
> + changeset: 6:b5f70786f9b0
> + tag: tip
> + user: test
> + date: Thu Jan 01 00:00:00 1970 +0000
> + summary: f
> +
> +
> check histedit_source
>
> $ hg log --debug --rev 5
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
More information about the Mercurial-devel
mailing list