rebase: clarify comment about merge ancestor when rebasing merges
The code for picking a merge ancestor when rebasing merges had a long and
incorrect comment.
The comment would perhaps have been fine as commit message but does
not make the code more readable or maintainable and is a bad
substitute for correct and readable code.
The correct essense of the comment is quite trivial: a merge of an ancestor of
the rebase destination and an 'outside' revision can be rebased as if it was a
linear change, using 'destination ancestor parent' as base and pretty much
ignoring the 'outside' revision.
The code path where the comment is placed is however also used for other kinds
of merge rebases. The comment is thus not really correct and not helpful. I
think it would be better to drop the comment and rewrite the code.
--- a/hgext/rebase.py Mon Jan 05 17:12:04 2015 -0800
+++ b/hgext/rebase.py Sun Jan 04 01:29:07 2015 +0100
@@ -645,17 +645,19 @@
# Case (2) detaching the node with a single parent, use this parent
base = repo[rev].p1().rev()
else:
- # In case of merge, we need to pick the right parent as merge base.
+ # Assuming there is a p1, this is the case where there also is a p2.
+ # We are thus rebasing a merge and need to pick the right merge base.
#
# Imagine we have:
- # - M: currently rebase revision in this step
+ # - M: current rebase revision in this step
# - A: one parent of M
- # - B: second parent of M
+ # - B: other parent of M
# - D: destination of this merge step (p1 var)
#
- # If we are rebasing on D, D is the successors of A or B. The right
- # merge base is the one D succeed to. We pretend it is B for the rest
- # of this comment
+ # Consider the case where D is a descendant of A or B and the other is
+ # 'outside'. In this case, the right merge base is the D ancestor.
+ #
+ # An informal proof, assuming A is 'outside' and B is the D ancestor:
#
# If we pick B as the base, the merge involves:
# - changes from B to M (actual changeset payload)
@@ -663,12 +665,20 @@
# version of B)
# Which exactly represent the rebase operation.
#
- # If we pick the A as the base, the merge involves
+ # If we pick A as the base, the merge involves:
# - changes from A to M (actual changeset payload)
# - changes from A to D (with include changes between unrelated A and B
# plus changes induced by rebase)
# Which does not represent anything sensible and creates a lot of
- # conflicts.
+ # conflicts. A is thus not the right choice - B is.
+ #
+ # Note: The base found in this 'proof' is only correct in the specified
+ # case. This base does not make sense if is not D a descendant of A or B
+ # or if the other is not parent 'outside' (especially not if the other
+ # parent has been rebased). The current implementation does not
+ # make it feasible to consider different cases separately. In these
+ # other cases we currently just leave it to the user to correctly
+ # resolve an impossible merge using a wrong ancestor.
for p in repo[rev].parents():
if state.get(p.rev()) == p1:
base = p.rev()