[PATCH 4 of 5 v3] rebase: refactor computerebase to case-by-case handling
Pierre-Yves David
pierre-yves.david at ens-lyon.org
Thu Dec 4 18:26:11 CST 2014
On 12/03/2014 07:12 PM, Mads Kiilerich wrote:
> # HG changeset patch
> # User Mads Kiilerich <madski at unity3d.com>
> # Date 1416364731 -3600
> # Wed Nov 19 03:38:51 2014 +0100
> # Node ID 742988c7a05cb1bd49f9be0f057a9c8ef4e20d95
> # Parent e031c5201577b359af981396957a0b9a9a5f5300
> rebase: refactor computerebase to case-by-case handling
>
> This makes it simpler to review and tweak handling of different cases.
What was wrong with the previous implementation, what makes yours better?
> This implementation was created using the old implementation as black box. It
> started out with how I think it should be, and was tweaked until it matched how
> it actually is. Further tweaking can take us close to where we want to be, step
> by step.
Now that we have the full list of case, are we sure they are all
properly tested? I would makes me more comfortable in such refactoring.
> The only case where the test suite coverage gives different result from
> computerebase is in test-rebase-obsolete.t in a case where None as ancestor
> would give the same ancestor as the one previously explicitly specified.
Why does it change? What does it mean? Is that bad? Why don't we get it
right in the first place?
>
> diff --git a/hgext/rebase.py b/hgext/rebase.py
> --- a/hgext/rebase.py
> +++ b/hgext/rebase.py
> @@ -25,6 +25,7 @@ import os, errno
>
> nullmerge = -2
> revignored = -3
> +outside = -4 # in computerebase: not in state, thus outside rebase set
>
> cmdtable = {}
> command = cmdutil.command(cmdtable)
> @@ -586,88 +587,93 @@ def computerebase(repo, rev, target, sta
> '''Return the merge revisions and new parent relationship of rev rebased
> to target:
> merge parent 1, merge parent 2, ancestor, new parent 1, new parent 2
> +
> + The following table shows how it is - not necessarily how it should be.
> +
> + Rebasing of rev with parents p1 and p2 onto target as rev' is written:
> + m1,m2|a
> + p1',p2'
> +
> + \ p2 null ancestor rebased outside
> + p1 \
> + null target,rev| target,rev|None p2',rev|p2 target,rev|p2
> + target target p2' target
> +
> + ancestor target,rev|Non target,rev|None p2',rev|p2 target,rev|None
> + target target p2' target,p2
> +
> + rebased p1',rev|p1 p1',rev|p1 target,rev|p1 p1',rev|p1
> + p1' p1' p1',p2 p1',p2
> +
> + outside target,rev|p1 target,rev|None p2',rev|p2 abort
> + target target,p1 p2',p1 3 parents
This table is fairly hard to read can we more to a version with:
1) clearer boundary
2) fixed size, aligned value. There is various option for this I think
my currently preferred is using T (target), R (rev), 1 (p1), 2 (p2) and
- (no value, applies for None)
> - # In case of merge, we need to pick the right parent as merge base.
> - #
> - # Imagine we have:
> - # - M: currently rebase revision in this step
> - # - A: one parent of M
> - # - B: second 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
> - #
> - # If we pick B as the base, the merge involves:
> - # - changes from B to M (actual changeset payload)
> - # - changes from B to D (induced by rebase) as D is a rebased
> - # version of B)
> - # Which exactly represent the rebase operation.
> - #
> - # If we pick the 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.
This comment is very useful at explaining the rebase semantic and
internal. It should not be dropped.
> - for p in repo[rev].parents():
> - if state.get(p.rev()) == p1:
> - base = p.rev()
> - break
> - else: # fallback when base not found
> - base = None
> -
> - # Raise because this function is called wrong (see issue 4106)
> - raise AssertionError('no base found to rebase on '
> - '(computerebase called wrong)')
> - return p1, rev, base, p1, p2
> + if p1 == nullrev:
> + if p2 == nullrev:
> + # Currently not possible because 'nothing to rebase from ...'
> + repo.ui.warn(' p1=nullrev, p2=nullrev - untested\n')
> + return target, rev, nullrev, target, nullrev
-1 for using inline returns in such hairy code. Lets make the logic flow
explicit with if/elif/else usage.
I'd trouble to compare the results of all the cases to the table value
(mostly because the table is hard to read). I'm a bit concerned by the
lack of factorization and mistake that can emerge from it, but lets wait
for the next version.
--
Pierre-Yves David
More information about the Mercurial-devel
mailing list