From patchwork Thu Jan 14 19:19:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: histedit: handle obsolete commits unknown to histedit state From: Kostia Balytskyi X-Patchwork-Id: 12763 Message-Id: <5a36c6cdb955ffb1f8b4.1452799181@ikostia-mbp.dhcp.thefacebook.com> To: Date: Thu, 14 Jan 2016 11:19:41 -0800 # HG changeset patch # User Kostia Balytskyi # Date 1452727707 28800 # Wed Jan 13 15:28:27 2016 -0800 # Node ID 5a36c6cdb955ffb1f8b4c2f26d369b3d331c0492 # Parent 443848eece189002c542339dc1cf84f49a94c824 histedit: handle obsolete commits unknown to histedit state This fix is intended to solve issue4800. It takes sets of final and new commits from histedit's state and replaces them with their successor sets. diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1362,6 +1362,27 @@ tmpnodes = allsuccs & replaced return newnodes, tmpnodes +def nonobsoletesuccessors(repo, nodes): + """find all non-obsolete successors for each of the nodes + + This fails if any of the nodes has more than one successor + set, e.g. if it diverged at some point and then became obsolete. + """ + result = [] + for cl in nodes: + succset = obsolete.successorssets(repo, cl) + if len(succset) > 1: + # successorsset for diverged changeset + # weird situation that should not happen while + # editing history, indicates an error + msg = _("diverged obsolete changeset found " + + "among nodes in histedit: %s") + raise error.Abort(msg % node.hex(cl)) + elif len(succset) == 1: + # non-divergent successor set + result += succset[0] + # else: changeset has been pruned, nothing needs to be done + return result def processreplacement(state): """process the list of replacements to return @@ -1408,11 +1429,13 @@ # turn `final` into list (topologically sorted) nm = state.repo.changelog.nodemap for prec, succs in final.items(): + succs = nonobsoletesuccessors(state.repo, succs) final[prec] = sorted(succs, key=nm.get) # computed topmost element (necessary for bookmark) if new: - newtopmost = sorted(new, key=state.repo.changelog.rev)[-1] + nonobsoletenew = nonobsoletesuccessors(state.repo, new) + newtopmost = sorted(nonobsoletenew, key=state.repo.changelog.rev)[-1] elif not final: # Nothing rewritten at all. we won't need `newtopmost` # It is the same as `oldtopmost` and `processreplacement` know it @@ -1422,7 +1445,7 @@ r = state.repo.changelog.rev newtopmost = state.repo[sorted(final, key=r)[0]].p1().node() - return final, tmpnodes, new, newtopmost + return final, tmpnodes, nonobsoletenew, newtopmost def movebookmarks(ui, repo, mapping, oldtopmost, newtopmost): """Move bookmark from old to newly created node"""