comparison hgext/rebase.py @ 44341:77bb38be00ea

rebase: always be graft-like, not merge-like, also for merges Rebase works by updating to a commit and then grafting changes on top. However, before this patch, it would actually merge in changes instead of grafting them in in some cases. That is, it would use the common ancestor as base instead of using one of the parents. That seems wrong to me, so I'm changing it so `defineparents()` always returns a value for `base`. This fixes the bad behavior in test-rebase-newancestor.t, which was introduced in 65f215ea3e8e (tests: add test for rebasing merges with ancestors of the rebase destination, 2014-11-30). The difference in test-rebase-dest.t is because the files in the tip revision were A, D, E, F before this patch and A, D, F, G after it. I think both files should ideally be there. Differential Revision: https://phab.mercurial-scm.org/D7907
author Martin von Zweigbergk <martinvonz@google.com>
date Thu, 16 Jan 2020 00:03:19 -0800
parents f546d2170b0f
children b42ce825308e
comparison
equal deleted inserted replaced
44340:6ecc34b31137 44341:77bb38be00ea
1676 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)): 1676 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)):
1677 np = dests[i] 1677 np = dests[i]
1678 elif p in state and state[p] > 0: 1678 elif p in state and state[p] > 0:
1679 np = state[p] 1679 np = state[p]
1680 1680
1681 # "bases" only record "special" merge bases that cannot be
1682 # calculated from changelog DAG (i.e. isancestor(p, np) is False).
1683 # For example:
1684 #
1685 # B' # rebase -s B -d D, when B was rebased to B'. dest for C
1686 # | C # is B', but merge base for C is B, instead of
1687 # D | # changelog.ancestor(C, B') == A. If changelog DAG and
1688 # | B # "state" edges are merged (so there will be an edge from
1689 # |/ # B to B'), the merge base is still ancestor(C, B') in
1690 # A # the merged graph.
1691 #
1692 # Also see https://bz.mercurial-scm.org/show_bug.cgi?id=1950#c8
1693 # which uses "virtual null merge" to explain this situation.
1694 if isancestor(p, np):
1695 bases[i] = nullrev
1696
1697 # If one parent becomes an ancestor of the other, drop the ancestor 1681 # If one parent becomes an ancestor of the other, drop the ancestor
1698 for j, x in enumerate(newps[:i]): 1682 for j, x in enumerate(newps[:i]):
1699 if x == nullrev: 1683 if x == nullrev:
1700 continue 1684 continue
1701 if isancestor(np, x): # CASE-1 1685 if isancestor(np, x): # CASE-1
1752 # A Z 1736 # A Z
1753 # 1737 #
1754 # But our merge base candidates (D and E in above case) could still be 1738 # But our merge base candidates (D and E in above case) could still be
1755 # better than the default (ancestor(F, Z) == null). Therefore still 1739 # better than the default (ancestor(F, Z) == null). Therefore still
1756 # pick one (so choose p1 above). 1740 # pick one (so choose p1 above).
1757 if sum(1 for b in set(bases) if b != nullrev) > 1: 1741 if sum(1 for b in set(bases) if b != nullrev and b not in newps) > 1:
1758 unwanted = [None, None] # unwanted[i]: unwanted revs if choose bases[i] 1742 unwanted = [None, None] # unwanted[i]: unwanted revs if choose bases[i]
1759 for i, base in enumerate(bases): 1743 for i, base in enumerate(bases):
1760 if base == nullrev: 1744 if base == nullrev or base in newps:
1761 continue 1745 continue
1762 # Revisions in the side (not chosen as merge base) branch that 1746 # Revisions in the side (not chosen as merge base) branch that
1763 # might contain "surprising" contents 1747 # might contain "surprising" contents
1764 other_bases = set(bases) - {base} 1748 other_bases = set(bases) - {base}
1765 siderevs = list( 1749 siderevs = list(
1779 repo.revs( 1763 repo.revs(
1780 b'%ld - (::%ld) - %ld', siderevs, merges, rebaseset 1764 b'%ld - (::%ld) - %ld', siderevs, merges, rebaseset
1781 ) 1765 )
1782 ) 1766 )
1783 1767
1784 # Choose a merge base that has a minimal number of unwanted revs. 1768 if any(revs is not None for revs in unwanted):
1785 l, i = min( 1769 # Choose a merge base that has a minimal number of unwanted revs.
1786 (len(revs), i) 1770 l, i = min(
1787 for i, revs in enumerate(unwanted) 1771 (len(revs), i)
1788 if revs is not None 1772 for i, revs in enumerate(unwanted)
1789 ) 1773 if revs is not None
1790
1791 # The merge will include unwanted revisions. Abort now. Revisit this if
1792 # we have a more advanced merge algorithm that handles multiple bases.
1793 if l > 0:
1794 unwanteddesc = _(b' or ').join(
1795 (
1796 b', '.join(b'%d:%s' % (r, repo[r]) for r in revs)
1797 for revs in unwanted
1798 if revs is not None
1799 )
1800 ) 1774 )
1801 raise error.Abort( 1775
1802 _(b'rebasing %d:%s will include unwanted changes from %s') 1776 # The merge will include unwanted revisions. Abort now. Revisit this if
1803 % (rev, repo[rev], unwanteddesc) 1777 # we have a more advanced merge algorithm that handles multiple bases.
1804 ) 1778 if l > 0:
1805 1779 unwanteddesc = _(b' or ').join(
1806 # newps[0] should match merge base if possible. Currently, if newps[i] 1780 (
1807 # is nullrev, the only case is newps[i] and newps[j] (j < i), one is 1781 b', '.join(b'%d:%s' % (r, repo[r]) for r in revs)
1808 # the other's ancestor. In that case, it's fine to not swap newps here. 1782 for revs in unwanted
1809 # (see CASE-1 and CASE-2 above) 1783 if revs is not None
1810 if i != 0: 1784 )
1811 if newps[i] != nullrev: 1785 )
1812 newps[0], newps[i] = newps[i], newps[0] 1786 raise error.Abort(
1813 bases[0], bases[i] = bases[i], bases[0] 1787 _(b'rebasing %d:%s will include unwanted changes from %s')
1788 % (rev, repo[rev], unwanteddesc)
1789 )
1790
1791 # newps[0] should match merge base if possible. Currently, if newps[i]
1792 # is nullrev, the only case is newps[i] and newps[j] (j < i), one is
1793 # the other's ancestor. In that case, it's fine to not swap newps here.
1794 # (see CASE-1 and CASE-2 above)
1795 if i != 0:
1796 if newps[i] != nullrev:
1797 newps[0], newps[i] = newps[i], newps[0]
1798 bases[0], bases[i] = bases[i], bases[0]
1814 1799
1815 # "rebasenode" updates to new p1, use the corresponding merge base. 1800 # "rebasenode" updates to new p1, use the corresponding merge base.
1816 if bases[0] != nullrev: 1801 base = bases[0]
1817 base = bases[0]
1818 else:
1819 base = None
1820 1802
1821 repo.ui.debug(b" future parents are %d and %d\n" % tuple(newps)) 1803 repo.ui.debug(b" future parents are %d and %d\n" % tuple(newps))
1822 1804
1823 return newps[0], newps[1], base 1805 return newps[0], newps[1], base
1824 1806