diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -13,12 +13,31 @@ For more information: http://www.selenic.com/mercurial/wiki/index.cgi/RebaseProject ''' -from mercurial import util, repair, merge, cmdutil, dispatch, commands, extensions +from mercurial import util, repair, merge, cmdutil, dispatch, commands +from mercurial import extensions, ancestor from mercurial.commands import templateopts from mercurial.node import nullrev from mercurial.i18n import _ import os, errno +def rebasemerge(repo, rev, first=False): + 'return the correct ancestor' + oldancestor = ancestor.ancestor + + def newancestor(a, b, pfunc): + ancestor.ancestor = oldancestor + anc = ancestor.ancestor(a, b, pfunc) + if b == rev: + return repo[rev].parents()[0].rev() + return ancestor.ancestor(a, b, pfunc) + + if not first: + ancestor.ancestor = newancestor + else: + repo.ui.debug(_("First revision, do not change ancestor\n")) + stats = merge.update(repo, rev, True, True, False) + return stats + def rebase(ui, repo, **opts): """move changeset (and descendants) to a different branch @@ -116,10 +135,12 @@ def concludenode(repo, rev, p1, p2, stat """Skip commit if collapsing has been required and rev is not the last revision, commit otherwise """ - repo.dirstate.setparents(repo[p1].node(), repo[p2].node()) + repo.ui.debug(_(" set parents\n")) + if collapse and not last: + repo.dirstate.setparents(repo[p1].node()) + return None - if collapse and not last: - return None + repo.dirstate.setparents(repo[p1].node(), repo[p2].node()) # Commit, record the old nodeid m, a, r = repo.status()[:3] @@ -147,16 +168,25 @@ def concludenode(repo, rev, p1, p2, stat def rebasenode(repo, rev, target, state, skipped, targetancestors, collapse): 'Rebase a single revision' - repo.ui.debug(_("rebasing %d:%s\n") % (rev, repo[rev].node())) + repo.ui.debug(_("rebasing %d:%s\n") % (rev, repo[rev])) p1, p2 = defineparents(repo, rev, target, state, targetancestors) + repo.ui.debug(_(" future parents are %d and %d\n") % (repo[p1].rev(), + repo[p2].rev())) + # Merge phase if len(repo.parents()) != 2: # Update to target and merge it with local - merge.update(repo, p1, False, True, False) + if repo['.'].rev() != repo[p1].rev(): + repo.ui.debug(_(" update to %d:%s\n") % (repo[p1].rev(), repo[p1])) + merge.update(repo, p1, False, True, False) + else: + repo.ui.debug(_(" already in target\n")) repo.dirstate.write() - stats = merge.update(repo, rev, True, False, False) + repo.ui.debug(_(" merge against %d:%s\n") % (repo[rev].rev(), repo[rev])) + first = repo[rev].rev() == repo[min(state)].rev() + stats = rebasemerge(repo, rev, first) if stats[3] > 0: raise util.Abort(_('fix unresolved conflicts with hg resolve then ' diff --git a/tests/test-rebase-collapse b/tests/test-rebase-collapse --- a/tests/test-rebase-collapse +++ b/tests/test-rebase-collapse @@ -41,15 +41,20 @@ createrepo () { createrepo > /dev/null 2>&1 hg glog --template '{rev}: {desc}\n' -echo '% Rebasing' +echo '% Rebasing B onto H' hg up -C 3 hg rebase --collapse 2>&1 | sed 's/\(saving bundle to \).*/\1/' hg glog --template '{rev}: {desc}\n' +echo "Expected A, B, C, D, F, H" +hg manifest createrepo > /dev/null 2>&1 -echo '% Rebasing' +echo +echo '% Rebasing G onto H' hg rebase --base 6 --collapse 2>&1 | sed 's/\(saving bundle to \).*/\1/' hg glog --template '{rev}: {desc}\n' +echo "Expected A, E, F, H" +hg manifest createrepocomplex () { cd $BASE @@ -76,6 +81,7 @@ createrepocomplex () { addcommit "H" 7 } +echo createrepocomplex > /dev/null 2>&1 hg glog --template '{rev}: {desc}\n' @@ -84,8 +90,91 @@ echo '% Rebase and collapse - more than hg rebase -s 2 --collapse echo -echo '% Rebase and collapse' +echo '% Rebase and collapse - E onto H' hg rebase -s 4 --collapse 2>&1 | sed 's/\(saving bundle to \).*/\1/' hg glog --template '{rev}: {desc}\n' +echo "Expected A, B, C, E, F, H" +hg manifest +createrepocomplex () { + cd $BASE + rm -rf a + hg init a + cd a + addcommit "A" 0 + addcommit "B" 1 + + hg up 0 + addcommit "C" 2 + hg merge + commit "D" 3 + + hg up 1 + addcommit "E" 4 + + echo "F" > E + commit "F" 5 + + addcommit "G" 6 + + hg merge + commit "H" 7 + + hg up 0 + addcommit "I" 8 +} + +echo +createrepocomplex > /dev/null 2>&1 +hg glog --template '{rev}: {desc}\n' + +echo +echo '% Rebase and collapse - E onto I' +hg rebase -s 4 --collapse + +echo '% Fix conflict and continue' +echo 'Resolved merge' > E +hg resolve -m E +hg rebase -c 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +hg glog --template '{rev}: {desc}\n' + +echo "Expected A, B, C, E, G, I" +hg manifest + +echo 'Cat E:' +cat E + +createrepocomplex () { + cd $BASE + rm -rf a + hg init a + cd a + addcommit "A" 0 + addcommit "B" 1 + + addcommit "C" 2 + hg up 1 + + addcommit "D" 3 + + hg merge + commit "E" 4 + + hg up 0 + addcommit "F" 5 +} + +echo +createrepocomplex > /dev/null 2>&1 +hg glog --template '{rev}: {desc}\n' + +echo +echo '% Rebase and collapse - B onto F' +hg rebase -s 1 --collapse 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +hg glog --template '{rev}: {desc}\n' + +echo "Expected A, B, C, D, F" +hg manifest exit 0 diff --git a/tests/test-rebase-collapse.out b/tests/test-rebase-collapse.out --- a/tests/test-rebase-collapse.out +++ b/tests/test-rebase-collapse.out @@ -14,7 +14,7 @@ o | 5: F |/ o 0: A -% Rebasing +% Rebasing B onto H 3 files updated, 0 files merged, 2 files removed, 0 files unresolved saving bundle to adding branch @@ -37,7 +37,15 @@ o | 2: F |/ o 0: A -% Rebasing +Expected A, B, C, D, F, H +A +B +C +D +F +H + +% Rebasing G onto H saving bundle to adding branch adding changesets @@ -60,6 +68,12 @@ o 4: F |/ o 0: A +Expected A, E, F, H +A +E +F +H + @ 7: H | | o 6: G @@ -80,7 +94,7 @@ o 0: A % Rebase and collapse - more than one external (fail) abort: unable to collapse, there is more than one external parent -% Rebase and collapse +% Rebase and collapse - E onto H saving bundle to adding branch adding changesets @@ -102,3 +116,104 @@ o / 1: B |/ o 0: A +Expected A, B, C, E, F, H +A +B +C +E +F +H + +@ 8: I +| +| o 7: H +| |\ +| | o 6: G +| | | +| | o 5: F +| | | +| | o 4: E +| | | +| o | 3: D +| |\| +| o | 2: C +|/ / +| o 1: B +|/ +o 0: A + + +% Rebase and collapse - E onto I +merging E +warning: conflicts during merge. +merging E failed! +abort: fix unresolved conflicts with hg resolve then run hg rebase --continue +% Fix conflict and continue +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 3 changes to 3 files +rebase completed +@ 5: Collapsed revision +|\ * E +| | * F +| | * G +| | * H +| o 4: I +| | +o | 3: D +|\ \ +| o | 2: C +| |/ +o / 1: B +|/ +o 0: A + +Expected A, B, C, E, G, I +A +B +C +E +G +I +Cat E: +Resolved merge + +@ 5: F +| +| o 4: E +| |\ +| | o 3: D +| | | +| o | 2: C +| |/ +| o 1: B +|/ +o 0: A + + +% Rebase and collapse - B onto F +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 2 changesets with 4 changes to 4 files +rebase completed +@ 2: Collapsed revision +| * B +| * C +| * D +| * E +o 1: F +| +o 0: A + +Expected A, B, C, D, F +A +B +C +D +F diff --git a/tests/test-rebase-conflicts b/tests/test-rebase-conflicts --- a/tests/test-rebase-conflicts +++ b/tests/test-rebase-conflicts @@ -31,6 +31,10 @@ sed -e 's/c2/l2/' common > common.new mv common.new common hg commit -d '4 0' -u test -m "L2" +echo 'l3' >> extra2 +hg add extra2 +hg commit -d '5 0' -u test -m "L3" + hg glog --template '{rev}: {desc}\n' echo @@ -47,9 +51,28 @@ hg rebase --continue echo echo '% Conclude rebase' -echo 'solved merge' >common +echo 'resolved merge' >common hg resolve -m common hg rebase --continue 2>&1 | cleanoutput +hg glog --template '{rev}: {desc}\n' -hg glog --template '{rev}: {desc}\n' +echo +echo '% Check correctness' +echo ' - Rev. 0' +hg cat -r 0 common + +echo ' - Rev. 1' +hg cat -r 1 common + +echo ' - Rev. 2' +hg cat -r 2 common + +echo ' - Rev. 3' +hg cat -r 3 common + +echo ' - Rev. 4' +hg cat -r 4 common + +echo ' - Rev. 5' +hg cat -r 5 common diff --git a/tests/test-rebase-conflicts.out b/tests/test-rebase-conflicts.out --- a/tests/test-rebase-conflicts.out +++ b/tests/test-rebase-conflicts.out @@ -1,6 +1,8 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved created new head -@ 4: L2 +@ 5: L3 +| +o 4: L2 | o 3: L1 | @@ -29,9 +31,11 @@ adding branch adding changesets adding manifests adding file changes -added 2 changesets with 2 changes to 2 files +added 3 changesets with 3 changes to 3 files rebase completed -@ 4: L2 +@ 5: L3 +| +o 4: L2 | o 3: L1 | @@ -41,3 +45,22 @@ o 1: C2 | o 0: C1 + +% Check correctness + - Rev. 0 +c1 + - Rev. 1 +c1 +c2 + - Rev. 2 +c1 +c2 +c3 + - Rev. 3 +c1 +c2 +c3 + - Rev. 4 +resolved merge + - Rev. 5 +resolved merge