Mercurial > hg
comparison hgext/rebase.py @ 18444:55aff0c2b73c
rebase: do not invent successor to skipped changeset
When rebase results in an empty a changeset it is "skipped" and no related
changeset is created at all. When we added obsolescence support to rebase (in
fc2a6114f0a0) it seemed a good idea to use its parent successor as the
successors for such dropped changesets. (see old version of the altered test).
This option was chosen because it seems a good way to hint about were the
dropped changeset "intended" to be. Such hint would have been used by automatic
evolution mechanism to rebase potential unstable children.
However, field testing of this version are not conclusive. It very often leads
to the creation of (totally unfounded) evolution divergence. This changeset
changes this behavior and mark skipped changesets as pruned (obsolete without
successors). This prevents the issue and seems semantically better probably a
win for obsolescence reading tool.
See example bellow for details:
User Babar has five changesets of interest:
- O, its current base of development.
- U, the new upstream
- A and C, some development changesets
- B another development changeset independent from A
O - A - B - C
\
U
Babar decides that B is more critical than the A and C and rebase it first
$ hg rebase --rev B --dest U
B is now obsolete (in lower case bellow). Rebase result, B', is its
successors.(note, C is unstable)
O - A - b - C
\
U - B'
Babar is now done with B', and want to rebase the rest of its history:
$ hg rebase --source A --dest B'
hg rebase process A, B and C. B is skipped as all its changes are already contained
in B'.
O - U - B' - A' - C'
Babar have the expected result graph wise, obsolescence marker are as follow:
B -> B' (from first rebase)
A -> A' (from second rebase)
C -> C' (from second rebase)
B -> ?? (from second rebase)
Before this changeset, the last marker is `B -> A'`. This cause two issues:
- This is semantically wrong. B have nothing to do with A'
- B has now two successors sets: (B',) and (A',). We detect a divergent
rewriting. The B' and A' are reported as "divergent" to Babar, confusion
ensues. In addition such divergent situation (divergent changeset are children
to each other) is tricky to solve.
With this changeset the last marker is `B -> ΓΈ`:
- This is semantically better.
- B has a single successors set (B',)
This scenario is added to the tests suite.
author | Pierre-Yves David <pierre-yves.david@ens-lyon.org> |
---|---|
date | Fri, 18 Jan 2013 14:15:32 +0100 |
parents | 100fdc84670f |
children | c83d36b81df1 |
comparison
equal
deleted
inserted
replaced
18443:64848f7fb764 | 18444:55aff0c2b73c |
---|---|
310 | 310 |
311 if not keepf: | 311 if not keepf: |
312 collapsedas = None | 312 collapsedas = None |
313 if collapsef: | 313 if collapsef: |
314 collapsedas = newrev | 314 collapsedas = newrev |
315 clearrebased(ui, repo, state, collapsedas) | 315 clearrebased(ui, repo, state, skipped, collapsedas) |
316 | 316 |
317 if currentbookmarks: | 317 if currentbookmarks: |
318 updatebookmarks(repo, nstate, currentbookmarks, **opts) | 318 updatebookmarks(repo, nstate, currentbookmarks, **opts) |
319 | 319 |
320 clearstatus(repo) | 320 clearstatus(repo) |
658 for r in detachset: | 658 for r in detachset: |
659 if r not in state: | 659 if r not in state: |
660 state[r] = nullmerge | 660 state[r] = nullmerge |
661 return repo['.'].rev(), dest.rev(), state | 661 return repo['.'].rev(), dest.rev(), state |
662 | 662 |
663 def clearrebased(ui, repo, state, collapsedas=None): | 663 def clearrebased(ui, repo, state, skipped, collapsedas=None): |
664 """dispose of rebased revision at the end of the rebase | 664 """dispose of rebased revision at the end of the rebase |
665 | 665 |
666 If `collapsedas` is not None, the rebase was a collapse whose result if the | 666 If `collapsedas` is not None, the rebase was a collapse whose result if the |
667 `collapsedas` node.""" | 667 `collapsedas` node.""" |
668 if obsolete._enabled: | 668 if obsolete._enabled: |
669 markers = [] | 669 markers = [] |
670 for rev, newrev in sorted(state.items()): | 670 for rev, newrev in sorted(state.items()): |
671 if newrev >= 0: | 671 if newrev >= 0: |
672 if collapsedas is not None: | 672 if rev in skipped: |
673 newrev = collapsedas | 673 succs = () |
674 markers.append((repo[rev], (repo[newrev],))) | 674 elif collapsedas is not None: |
675 succs = (repo[collapsedas],) | |
676 else: | |
677 succs = (repo[newrev],) | |
678 markers.append((repo[rev], succs)) | |
675 if markers: | 679 if markers: |
676 obsolete.createmarkers(repo, markers) | 680 obsolete.createmarkers(repo, markers) |
677 else: | 681 else: |
678 rebased = [rev for rev in state if state[rev] != nullmerge] | 682 rebased = [rev for rev in state if state[rev] != nullmerge] |
679 if rebased: | 683 if rebased: |