# HG changeset patch # User Anton Shestakov # Date 1608635196 -28800 # Node ID e8a43f5929f644413e6928ac9ad6e497858df134 # Parent 668817e8c00728e197a9b1c650ddb6b0e6c0c6b1 rewind: abort when trying to rewind to multiple unrelated predecessors diff -r 668817e8c007 -r e8a43f5929f6 CHANGELOG --- a/CHANGELOG Tue Dec 22 19:03:59 2020 +0800 +++ b/CHANGELOG Tue Dec 22 19:06:36 2020 +0800 @@ -10,6 +10,8 @@ * obslog: clarify the command name in the help, * evolve: add a experimental.evolution.in-memory config for running evolve in memory + * rewind: detect and abort on cases when we rewind to changesets that are + precessors / successors of each other 10.2.0.post1 -- 2021-02-01 -------------------------- diff -r 668817e8c007 -r e8a43f5929f6 hgext3rd/evolve/rewind.py --- a/hgext3rd/evolve/rewind.py Tue Dec 22 19:03:59 2020 +0800 +++ b/hgext3rd/evolve/rewind.py Tue Dec 22 19:06:36 2020 +0800 @@ -192,9 +192,30 @@ if update_target is not None and not opts.get('keep'): ui.status(_(b'working directory is now at %s\n') % repo[b'.']) +def _check_multiple_predecessors(targetnode, successor, targetset): + """ check if a successor of one rewind target is already another target + + An example obsolescence marker tree: + A0 A1 A2 + x - x - o + + When user tries to rewind A2 to both its predecessors with e.g. + `hg rewind --to A0+A1`, this function will at one point be called with + (A0, A1, [A0, A1]) as arguments. In that case it will raise an Abort + and prevent rewind from succeeding. + """ + if successor in targetset: + msg = _(b'not rewinding, %s is a successor of %s') + msg %= (nodemod.short(successor), nodemod.short(targetnode)) + hint = _(b'pick only one of these changesets, possibly with --exact') + raise error.Abort(msg, hint=hint) + def _walk_successors(ui, unfi, targetset): """follow successors of targets and find the latest successors + While doing that, check and abort if there are multiple unrelated + predecessors in targetset. + We also keep track of "source": when we reach a successor by following the obsmarker-graph starting from a certain target, we add `successor: target` pair to `source`. But we don't care about having more than one `target` @@ -218,6 +239,8 @@ # found if e.g. there's a fold (and that is fine). # (Also basic cycle protection.) continue + # TODO: this could be moved to a post-processing stage + _check_multiple_predecessors(targetnode, successor, targetset) source[successor] = current remaining.add(successor) if not markers: diff -r 668817e8c007 -r e8a43f5929f6 tests/test-rewind.t --- a/tests/test-rewind.t Tue Dec 22 19:03:59 2020 +0800 +++ b/tests/test-rewind.t Tue Dec 22 19:06:36 2020 +0800 @@ -867,6 +867,19 @@ summary: c_ROOT + $ hg rewind --hidden --to 'allpredecessors(desc("c_B0"))' --dry-run + abort: not rewinding, a65fceb2324a is a successor of 7e594302a05d + (pick only one of these changesets, possibly with --exact) + [255] + $ hg rewind --hidden --to 'allpredecessors(desc("c_B0"))' --dry-run --exact + abort: not rewinding, a65fceb2324a is a successor of 7e594302a05d + (pick only one of these changesets, possibly with --exact) + [255] + $ hg rewind --hidden --to 'allpredecessors(desc("c_B0"))' --dry-run --as-divergence + abort: not rewinding, a65fceb2324a is a successor of 7e594302a05d + (pick only one of these changesets, possibly with --exact) + [255] + Testing the defaults -------------------- @@ -1247,6 +1260,11 @@ $ hg rewind --from 'desc("AB2")' --dry-run rewinding 7f9a5314ef94 to 2 changesets: 3748b241cad8 16429ed4b6cb + $ hg rewind --hidden --to 'allpredecessors(desc("AB2"))' --dry-run + abort: not rewinding, 3748b241cad8 is a successor of fa8956746c52 + (pick only one of these changesets, possibly with --exact) + [255] + $ cd .. folding with a changeset we rebased onto