mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-23 08:18:04 +03:00
Made the fix1250 transcript into a test case
- Tests the cases of the merge behavior we have thought of as specific cases that need to be covered.
This commit is contained in:
parent
441a8341a9
commit
c35ff8f33d
@ -3,48 +3,97 @@
|
||||
.> builtins.merge
|
||||
```
|
||||
|
||||
Start by creating a new namespace with some definitions in it:
|
||||
# How merging works
|
||||
|
||||
Suppose we have two branches, `P1` and `P2`, and a subnamespace, `foo`, which we'll refer to with `P1.foo` , `P2.foo`. This doc explains how `merge(P1,P2)` is computed, including the `merge(P1,P2).foo` subnamespace.
|
||||
|
||||
`LCA(P1,P2)` is the lowest common ancestor of `P1` and `P2`. To compute `merge(P1,P2)`, we:
|
||||
|
||||
1. Compute `LCA(P1,P2)` and do a three way merge of that level of the tree, using the algorithm below. What about the children of `P1` and `P2`? Let's just consider a child namespace `foo`. There are a few cases:
|
||||
1. `P1` and `P2` both have foo as a child namespace. Then `merge(P1,P2).foo == merge(P1.foo, P2.foo)`
|
||||
2. `P1` has `foo` as a child namespace, but `P2` does not (or vice versa). Then we have two subcases:
|
||||
1. `LCA(P1,P2)` has no `foo`. This means that `foo` child namespace was added by `P1`. The merged result for the `foo` subnamespace is just `P1.foo`.
|
||||
2. `LCA(P1,P2)` does have `foo`. This means that `P2` _deleted_ the `foo` subnamespace. The merged result for the `foo` subnamespace is then `merge(P1.foo, cons empty LCA(P1,P2).foo)`. This does a history-preserving delete of all the definitions that existed at the `LCA` point in history.
|
||||
1. Example is like if `P1` added a new definition `foo.bar = 23` after the `LCA`, then `foo.bar` will exist in the merged result, but all the definitions that existed in `foo` at the time of the `LCA` will be deleted in the result.
|
||||
|
||||
### Diff-based 3-way merge algorithm
|
||||
|
||||
Standard 3 way merge algorithm to merge `a` and `b`:
|
||||
|
||||
* Let `lca = LCA(a,b)`
|
||||
* merged result is: `apply(diff(lca,a) <> diff(lca,b), lca)`
|
||||
|
||||
Relies on some diff combining operation `<>`.
|
||||
|
||||
```unison:hide
|
||||
x.foo.bar = 1
|
||||
y.foo.bar = 2
|
||||
foo.w = 2
|
||||
foo.x = 1
|
||||
baz.x = 3
|
||||
quux.x = 4
|
||||
```
|
||||
|
||||
```ucm:hide
|
||||
.base> add
|
||||
```
|
||||
|
||||
We're going to create two copies of `base`, and add some definitions to each, then merge both back into `base`:
|
||||
|
||||
```ucm
|
||||
.base> fork .base .base1
|
||||
.base> fork .base .base2
|
||||
.P0> add
|
||||
```
|
||||
|
||||
Now P0 has 3 sub-namespaces.
|
||||
* foo will be modified definition-wise in each branch
|
||||
* baz will be deleted in the P2 branch and left alone in P1
|
||||
* quux will be deleted in the P2 branch and added to in P1
|
||||
* P1 will add a bar sub-namespace
|
||||
|
||||
```ucm
|
||||
.P0> fork .P0 .P1
|
||||
.P0> fork .P0 .P2
|
||||
```
|
||||
|
||||
```unison:hide
|
||||
z.foo.bar = 2483908
|
||||
foo.y = 2483908
|
||||
bar.y = 383
|
||||
quux.y = 333
|
||||
```
|
||||
|
||||
```ucm
|
||||
.base1> add
|
||||
.P1> add
|
||||
.P1> delete.term foo.w
|
||||
```
|
||||
|
||||
We added to `foo`, `bar` and `baz`, and deleted `foo.w`, which should stay deleted in the merge.
|
||||
|
||||
```unison:hide
|
||||
p.foo.bar = +28348
|
||||
foo.z = +28348
|
||||
```
|
||||
|
||||
```ucm
|
||||
.base2> add
|
||||
.P2> add
|
||||
.P2> delete.namespace baz
|
||||
.P2> delete.namespace quux
|
||||
.P2> find
|
||||
```
|
||||
|
||||
Now we'll try merging `base1` and `base2` back into `base`. We should see the union of all their definitions in the merged version of `base`.
|
||||
We added `foo.z`, deleted whole namespaces `baz` and `quux` which should stay
|
||||
deleted in the merge.
|
||||
|
||||
This should succeed and the resulting namespace should have `x`, `y`, `z`, and `p` in it:
|
||||
Now we'll try merging `P1` and `P2` back into `P0`. We should see the union of all their definitions in the merged version of `P0`.
|
||||
|
||||
This should succeed and the resulting P0 namespace should have `foo`, `bar`
|
||||
and `quux` namespaces.
|
||||
|
||||
```ucm
|
||||
.base> merge .base1
|
||||
.base> ls
|
||||
.base> merge .base2
|
||||
.base> ls
|
||||
.base> view z.foo.bar p.foo.bar
|
||||
.P0> merge .P1
|
||||
.P0> merge .P2
|
||||
.P0> find
|
||||
.P0> view foo.x foo.y foo.z bar.y quux.y
|
||||
```
|
||||
|
||||
```ucm:error
|
||||
.P0> view foo.w
|
||||
```
|
||||
|
||||
```ucm:error
|
||||
.P0> view baz.x
|
||||
```
|
||||
|
||||
```ucm:error
|
||||
.P0> view quux.x
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user