Submitter | Durham Goode |
---|---|
Date | April 14, 2015, 5:06 p.m. |
Message ID | <75d4d58c15fc9c2f8b3a.1429031215@dev2000.prn2.facebook.com> |
Download | mbox | patch |
Permalink | /patch/8653/ |
State | Accepted |
Delegated to: | Augie Fackler |
Headers | show |
Comments
On Tue, Apr 14, 2015 at 10:06:55AM -0700, Durham Goode wrote: > # HG changeset patch > # User Durham Goode <durham@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@selenic.com > http://selenic.com/mailman/listinfo/mercurial-devel
Patch
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