[PATCH 2 of 2] rebase: only pick branches without obsolete changeset with -b (issue5300)
Jun Wu
quark at fb.com
Thu Aug 31 15:09:12 EDT 2017
Excerpts from Denis Laxalde's message of 2017-08-30 15:54:15 +0200:
> # HG changeset patch
> # User Denis Laxalde <denis at laxalde.org>
> # Date 1504025723 -7200
> # Tue Aug 29 18:55:23 2017 +0200
> # Node ID 092bccbfdc5d29fe5fe2f79c18d49bd842437707
> # Parent 28e449777fb7452e569292184a18f358186248a3
> rebase: only pick branches without obsolete changeset with -b (issue5300)
>
> When trying to rebase the following graph with -b 24, the command will abort
> because "this rebase will cause divergence from: 21".
>
> @ 24
> |
> o 23
> |
> | o 22 (orphan)
> | |
> | x 21 (rewritten as 23)
> |/
> o 20
This example is incomplete. If there is "-d 22", nothing breaks since only
23 and 24 will be rebased. Adding an ancestor is important:
@ 24
|
o 23
|
| o 22 (orphan)
| |
| x 21 (rewritten as 23)
|/
o 20
|
| o 19
|/
o 18
Then "hg rebase -b 24 -d 19". The rebaseset will include both 21 and 23.
This is not "-b" specific. It also affects "-r 21+23" or "-s 20".
A previous discussion and proposed solutions can be found at:
https://www.mercurial-scm.org/wiki/CEDRebase.
It seems your approach is similar to "Option 2 (skip troublemakers)". I
think it could be formalized by:
- Make it generic - work with -s and -r
- Revise the revset (see below)
- Add more tests about corner cases (see below)
- Respect "rebaseskipobsolete" config option
- Print a message about rebase is doing (maybe "unexpected") things
> By computing the set of revisions to rebase excluding branches with changesets
> that would get divergent, we let the rebase proceed (and rebase 20::24 in the
> example above) while leaving already unstable branches (21::) behind. The
> reason for leaving unstable things behind is that when the user explicitly
> specifies the --base, we know which part of the graph they're interested in.
>
> diff --git a/hgext/rebase.py b/hgext/rebase.py
> --- a/hgext/rebase.py
> +++ b/hgext/rebase.py
> @@ -755,6 +755,8 @@ def _definesets(ui, repo, destf=None, sr
> roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs))
>
> rebaseset = repo.revs('%ld::', roots)
> + if obsolete.isenabled(repo, obsolete.allowunstableopt):
> + rebaseset -= repo.revs('only(obsolete(), (%ld))::', base)
This seems to also select innocent ancestors of 'obsolete()':
o D
|
x C <- part of obsolete()
|
o B <- will be selected (probably shouldn't)
|
o A <- base
Not all "obsolete()" revisions should be skipped, only those with successors
in the same rebaseset. Obsoleted revisions without successors should not
have their children removed. Obsoleted revisions with a unique successor
outside the current rebaseset worth the divergence warning.
Could you also add tests about those corner cases?
> if not rebaseset:
> # transform to list because smartsets are not comparable to
> diff --git a/tests/test-rebase-obsolete.t b/tests/test-rebase-obsolete.t
> --- a/tests/test-rebase-obsolete.t
> +++ b/tests/test-rebase-obsolete.t
Tip: You can use drawdag to write tests. That makes review easier.
I had to modify your test change and stop in the middle to investigate
obsolete markers. drawdag examples can be found in this test file.
> [...]
More information about the Mercurial-devel
mailing list