evolve: refactor content-divergence resolution logic
> What is the case we are looking at?
This is about refactoring the part of content-div resolution logic where it
decides which cset should be relocated and where.
> What is a "topologicial common ancestors" vs a "greatest common ancestors"?
`tca` is an ancestor which we can decide/find by looking at the at graph
visually for e.g
```
c3(*) c4(*)
| |
c2(x) c1(x)
c5 | /
\ | /
c0
```
(c5 is the successor of c2 and c1)
now here,
`tca` of c3 and c4 is: c0
`gca` of c3 and c4 is: c5
> What is the new top-level logic/behavior that makes it better?
The old code had some unnecessary edge cases just because we were using `gca`,
since it can point to a revision that is not a topological ancestor.
For e.g see b779b40f996e
Eventually, the code around this was getting messy unnecessarily. So I looked
into it and found a simple and more robust approach.
And in new code, it is simple and straightforward (and easy to understand),
where we handle the following 4 cases when solving content-div:
1) when both are on the same parent
=> (no need to do anything special, and simply proceed)
2) both are on the different parent but a) `tca` is the parent of one of them
or b) there is no non-obsolete revision between `tca` and one of the
divergent cset.
=> (relocate one to the other side and proceed)
3) both are on different parents and `tca` is not the parent of any of them and
there is at least one non-obsolete cset between tca and both the divergent
cset i.e (tca::div1) and (tca::div2) both the ranges have at least one non-obs
revision.
=> (this is the case which we don't handle yet, but the solution would be to
prompt the user to choose an evolve destination.)
4) both are in the parent-child relation
=> (both are merged and new cset will be based on the successor of `tca`)
Changes in test-evolve-issue5958.t demonstrate that new code also covered case4
because in a resolution of "two divergent csets with parent-child relation"
there should be one cset as a result and no orphan revs (as you can see there
was an orphan before this patch).
Testing topics on cases when we have multiple topics based on top
of other.
$ . "$TESTDIR/testlib/topic_setup.sh"
Setup
$ cat << EOF >> $HGRCPATH
> [experimental]
> evolution = all
> [ui]
> interactive = True
> logtemplate = {rev} - \{{get(namespaces, "topics")}} {node|short} {desc} ({phase})\n
> [extensions]
> show =
> EOF
$ echo "evolve=$(echo $(dirname $TESTDIR))/hgext3rd/evolve/" >> $HGRCPATH
Test to make sure `hg evolve` don't solve troubles out of current stack:
------------------------------------------------------------------------
$ hg init repo1
$ cd repo1
$ for ch in a b c; do
> echo $ch > $ch
> hg ci -Am "added "$ch --topic foo
> done;
adding a
active topic 'foo' grew its first changeset
(see 'hg help topics' for more information)
adding b
adding c
$ echo d > d
$ hg ci -Am "added d" --topic bar
adding d
active topic 'bar' grew its first changeset
(see 'hg help topics' for more information)
$ hg up -r "desc('added c')"
> echo cc >> c
switching to topic foo
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg amend
1 new orphan changesets
$ hg log -G
@ 4 - {foo} 0cc68cbf943a added c (draft)
|
| * 3 - {bar} 94b12ff0f44a added d (draft)
| |
| x 2 - {foo} 9c315cf1e7de added c (draft)
|/
o 1 - {foo} ead01932caf0 added b (draft)
|
o 0 - {foo} 853c9ec0849e added a (draft)
$ hg stack
### topic: foo
### target: default (branch)
s3@ added c (current)
s2: added b
s1: added a
As expected, evolve should deny to evolve here as there is no troubled csets in current stack:
$ hg evolve --all
nothing to evolve on current working copy parent
(1 other orphan in the repository, do you want --any or --rev)
[2]