Mercurial > hg
changeset 23484:cf3495dfd7ed
rebase: move base calculation from rebasenode() to defineparents()
We want to collect all calculation in one place.
author | Mads Kiilerich <madski@unity3d.com> |
---|---|
date | Wed, 19 Nov 2014 03:38:51 +0100 |
parents | 3805f4b0f5a9 |
children | ccb93e9affc1 |
files | hgext/rebase.py |
diffstat | 1 files changed, 54 insertions(+), 52 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/rebase.py Fri Dec 05 10:53:25 2014 -0800 +++ b/hgext/rebase.py Wed Nov 19 03:38:51 2014 +0100 @@ -370,8 +370,8 @@ if state[rev] == -1: ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, repo[rev])), _('changesets'), total) - p1, p2 = defineparents(repo, rev, target, state, - targetancestors) + p1, p2, base = defineparents(repo, rev, target, state, + targetancestors) storestatus(repo, originalwd, target, state, collapsef, keepf, keepbranchesf, external, activebookmark) if len(repo.parents()) == 2: @@ -380,8 +380,8 @@ try: ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'rebase') - stats = rebasenode(repo, rev, p1, state, collapsef, - target) + stats = rebasenode(repo, rev, p1, base, state, + collapsef, target) if stats and stats[3] > 0: raise error.InterventionRequired( _('unresolved conflicts (see hg ' @@ -414,8 +414,8 @@ ui.note(_('rebase merging completed\n')) if collapsef and not keepopen: - p1, p2 = defineparents(repo, min(state), target, - state, targetancestors) + p1, p2, _base = defineparents(repo, min(state), target, + state, targetancestors) editopt = opts.get('edit') editform = 'rebase.collapse' if collapsemsg: @@ -509,7 +509,8 @@ ', '.join(str(p) for p in sorted(parents)))) def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None): - '''Commit the changes and store useful information in extra. + '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev + but also store useful information in extra. Return node of committed revision.''' try: repo.dirstate.beginparentchange() @@ -539,8 +540,8 @@ repo.dirstate.invalidate() raise -def rebasenode(repo, rev, p1, state, collapse, target): - 'Rebase a single revision' +def rebasenode(repo, rev, p1, base, state, collapse, target): + 'Rebase a single revision rev on top of p1 using base as merge ancestor' # Merge phase # Update to target and merge it with local if repo['.'].rev() != p1: @@ -550,48 +551,6 @@ repo.ui.debug(" already in target\n") repo.dirstate.write() repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev])) - if rev == min(state): - # Case (1) initial changeset of a non-detaching rebase. - # Let the merge mechanism find the base itself. - base = None - elif not repo[rev].p2(): - # 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. - # - # 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. - 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 ' - '(rebasenode called wrong)') if base is not None: repo.ui.debug(" detach base %d:%s\n" % (base, repo[base])) # When collapsing in-place, the parent is the common ancestor, we @@ -660,7 +619,50 @@ p2 = p2n repo.ui.debug(" future parents are %d and %d\n" % (repo[p1].rev(), repo[p2].rev())) - return p1, p2 + + if rev == min(state): + # Case (1) initial changeset of a non-detaching rebase. + # Let the merge mechanism find the base itself. + base = None + elif not repo[rev].p2(): + # 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. + # + # 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. + 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 ' + '(defineparents called wrong)') + return p1, p2, base def isagitpatch(repo, patchname): 'Return true if the given patch is in git format'