unison/unison-src/transcripts/fix2004.output.md
2021-08-02 11:55:27 -04:00

6.1 KiB

Here's the scenario that can produce bad empty namespace LCAs:

of v4
j1: ... - v1 - v2 - v3 - v4 - v4a - v5 - v6 - v7
                                              /
                                  <empty> - v5a

                               adds of unrelated
j2: ... - v1 - v2 - v3 - v4 - x0 - x1 - x2 - x3
                                            /
                                <empty> - z1


So j1 and j2 have common history up through v4, then j1 deletes some definitions while j2 adds some definitions via shallow merges. These shallow merges then result in the LCA being the empty namespace rather than v4.

First, we create some common history before a fork:

  ☝️  The namespace .a is empty.

.a> alias.term .builtin.Nat.+ delete1

  Done.

.a> alias.term .builtin.Nat.* delete2

  Done.

.a> alias.term .builtin.Nat.drop delete3

  Done.

.a> alias.type .builtin.Nat Delete4

  Done.

Now we fork a2 off of a. a continues on, deleting the terms it added previously and then adding one unrelated term via a merge with little history. It's this short history merge which will become a bad LCA of the empty namespace.

.> fork a a2

  Done.

.a> delete.term delete1

  Name changes:
  
    Original            Changes
    1. a.delete1     ┐  2. a.delete1 (removed)
    3. a2.delete1    │  
    4. builtin.Nat.+ ┘  
  
  Tip: You can use `undo` or `reflog` to undo this change.

.a> delete.term delete2

  Name changes:
  
    Original            Changes
    1. a.delete2     ┐  2. a.delete2 (removed)
    3. a2.delete2    │  
    4. builtin.Nat.* ┘  
  
  Tip: You can use `undo` or `reflog` to undo this change.

.a> delete.term delete3

  Name changes:
  
    Original               Changes
    1. a.delete3        ┐  2. a.delete3 (removed)
    3. a2.delete3       │  
    4. builtin.Nat.drop ┘  
  
  Tip: You can use `undo` or `reflog` to undo this change.

.a> delete.type Delete4

  Name changes:
  
    Original          Changes
    1. a.Delete4   ┐  2. a.Delete4 (removed)
    3. a2.Delete4  │  
    4. builtin.Nat ┘  
  
  Tip: You can use `undo` or `reflog` to undo this change.

  ☝️  The namespace .newbranchA is empty.

.newbranchA> alias.term .builtin.Float.+ dontDelete

  Done.

.> merge newbranchA a

  Here's what's changed in a after the merge:
  
  Added definitions:
  
    1. dontDelete : Float -> Float -> Float
  
  Tip: You can use `todo` to see if this generated any work to
       do in this namespace and `test` to run the tests. Or you
       can use `undo` or `reflog` to undo the results of this
       merge.

.a> find

  1. dontDelete : Float -> Float -> Float
  

Meanwhile, a2 adds some other unrelated terms, some via merging in namespaces with little history. When merging a2 back into a, the deletes from their common history should be respected.

.a2> alias.term .builtin.Text.take keep1

  Done.

.a2> alias.term .builtin.Text.take keep2

  Done.

.a2> alias.term .builtin.Text.take keep3

  Done.

.a2> alias.term .builtin.Text.take keep4

  Done.

.a2> alias.term .builtin.Text.take keep5

  Done.

  ☝️  The namespace .newbranchA2 is empty.

.newbranchA2> alias.term .builtin.Text.take keep6

  Done.

.> merge newbranchA2 a2

  Here's what's changed in a2 after the merge:
  
  Name changes:
  
    Original    Changes
    1. keep1 ┐  2. keep6 (added)
    3. keep2 │  
    4. keep3 │  
    5. keep4 │  
    6. keep5 ┘  
  
  Tip: You can use `todo` to see if this generated any work to
       do in this namespace and `test` to run the tests. Or you
       can use `undo` or `reflog` to undo the results of this
       merge.

.a2> find

  1.  delete1 : Delete4 -> Delete4 -> Delete4
  2.  delete2 : Delete4 -> Delete4 -> Delete4
  3.  delete3 : Delete4 -> Delete4 -> Delete4
  4.  builtin type Delete4
  5.  keep1 : Delete4 -> Text -> Text
  6.  keep2 : Delete4 -> Text -> Text
  7.  keep3 : Delete4 -> Text -> Text
  8.  keep4 : Delete4 -> Text -> Text
  9.  keep5 : Delete4 -> Text -> Text
  10. keep6 : Delete4 -> Text -> Text
  

.> fork a asquash

  Done.

.> merge a2 a

  Here's what's changed in a after the merge:
  
  Added definitions:
  
    1. ┌ keep1 : Delete4 -> Text -> Text
    2. │ keep2 : Delete4 -> Text -> Text
    3. │ keep3 : Delete4 -> Text -> Text
    4. │ keep4 : Delete4 -> Text -> Text
    5. │ keep5 : Delete4 -> Text -> Text
    6. └ keep6 : Delete4 -> Text -> Text
  
  Tip: You can use `todo` to see if this generated any work to
       do in this namespace and `test` to run the tests. Or you
       can use `undo` or `reflog` to undo the results of this
       merge.

.> squash a2 asquash

  Here's what's changed in asquash after the merge:
  
  Added definitions:
  
    1. ┌ keep1 : Delete4 -> Text -> Text
    2. │ keep2 : Delete4 -> Text -> Text
    3. │ keep3 : Delete4 -> Text -> Text
    4. │ keep4 : Delete4 -> Text -> Text
    5. │ keep5 : Delete4 -> Text -> Text
    6. └ keep6 : Delete4 -> Text -> Text
  
  Tip: You can use `todo` to see if this generated any work to
       do in this namespace and `test` to run the tests. Or you
       can use `undo` or `reflog` to undo the results of this
       merge.

At this point, all the things that a has deleted (delete1, delete2, etc) should be deleted in both the merged and squashed results. Let's verify this:

.a> find

  1. dontDelete : Float -> Float -> Float
  2. keep1 : Delete4 -> Text -> Text
  3. keep2 : Delete4 -> Text -> Text
  4. keep3 : Delete4 -> Text -> Text
  5. keep4 : Delete4 -> Text -> Text
  6. keep5 : Delete4 -> Text -> Text
  7. keep6 : Delete4 -> Text -> Text
  

.asquash> find

  1. dontDelete : Float -> Float -> Float
  2. keep1 : Delete4 -> Text -> Text
  3. keep2 : Delete4 -> Text -> Text
  4. keep3 : Delete4 -> Text -> Text
  5. keep4 : Delete4 -> Text -> Text
  6. keep5 : Delete4 -> Text -> Text
  7. keep6 : Delete4 -> Text -> Text
  

.> view a.Delete4

  ⚠️
  
  The following names were not found in the codebase. Check your spelling.
    a.Delete4

.> view asquash.delete1

  ⚠️
  
  The following names were not found in the codebase. Check your spelling.
    asquash.delete1