unison/unison-src/transcripts/resolve.output.md
2022-02-14 13:31:57 -06:00

5.5 KiB

Resolving edit conflicts in ucm

The ucm tool tracks edits to hashes in an object called a patch. When patches get merged, sometimes those patches will have conflicting edits. The replace command helps resolve such conflicts.

First, let's make a new namespace, example.resolve:

.> cd example.resolve

  ☝️  The namespace .example.resolve is empty.

Now let's add a term named a.foo:

a.foo = 42

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here's how your codebase would
  change:
  
    ⍟ These new definitions are ok to `add`:
    
      a.foo : Nat

.example.resolve> add

  ⍟ I've added these definitions:
  
    a.foo : Nat

We'll fork the namespace a into a new namespace b, so we can edit the two concurrently.

.example.resolve> fork a b

  Done.

We'll also make a second fork c which we'll use as the target for our patch later.

.example.resolve> fork a c

  Done.

Now let's make a change to foo in the a namespace:

.example.resolve> cd a

foo = 43

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here's how your codebase would
  change:
  
    ⍟ These names already exist. You can `update` them to your
      new definition:
    
      foo : Nat

.example.resolve.a> update

  ⍟ I've updated these names to your new definition:
  
    foo : Nat

And make a different change in the b namespace:

.example.resolve> cd .example.resolve.b

foo = 44

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here's how your codebase would
  change:
  
    ⍟ These names already exist. You can `update` them to your
      new definition:
    
      foo : Nat

.example.resolve.b> update

  ⍟ I've updated these names to your new definition:
  
    foo : Nat

The a and b namespaces now each contain a patch named patch. We can view these:

.example.resolve.b> cd .example.resolve

.example.resolve> view.patch a.patch

  Edited Terms: 1. c.foo -> 2. a.foo
  
  Tip: To remove entries from a patch, use
       delete.term-replacement or delete.type-replacement, as
       appropriate.

.example.resolve> view.patch b.patch

  Edited Terms: 1. c.foo -> 2. b.foo
  
  Tip: To remove entries from a patch, use
       delete.term-replacement or delete.type-replacement, as
       appropriate.

Let's now merge these namespaces into c:

.example.resolve> merge a c

  Here's what's changed in c after the merge:
  
  Updates:
  
    1. foo : Nat
       ↓
    2. foo : Nat
  
  Added definitions:
  
    3. patch patch (added 1 updates)
  
  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.

.example.resolve> merge b c

  Here's what's changed in c after the merge:
  
  New name conflicts:
  
    1. foo#emomp74i93 : Nat
       ↓
    2. ┌ foo#a84tg4er4k : Nat
    3. └ foo#emomp74i93 : Nat
  
  Updates:
  
    4. patch patch (added 1 updates)
  
  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.

  I tried to auto-apply the patch, but couldn't because it
  contained contradictory entries.

The namespace c now has an edit conflict, since the term foo was edited in two different ways.

.example.resolve> cd c

.example.resolve.c> todo

  ❓
  
  These definitions were edited differently in namespaces that
  have been merged into this one. You'll have to tell me what to
  use as the new definition:
  
    The term 1. #qkhkl0n238 was replaced with
      2. foo#a84tg4er4k
      3. foo#emomp74i93

We see that the original hash of a.foo got replaced with two different hashes.

We can resolve this conflict by picking one of the terms as the "winner":

.example.resolve.c> replace 1 2

  Done.

This changes the merged c.patch so that only a single edit remains and resolves the conflict.

.example.resolve.c> view.patch

  Edited Terms: 1. #qkhkl0n238 -> 2. foo#a84tg4er4k
  
  Tip: To remove entries from a patch, use
       delete.term-replacement or delete.type-replacement, as
       appropriate.

We still have a remaining name conflict since it just so happened that both of the definitions in the edits were named foo.

.example.resolve.c> todo

  ❓
  
  The term foo has conflicting definitions:
    1. foo#a84tg4er4k
    2. foo#emomp74i93
  
  Tip: This occurs when merging branches that both independently
       introduce the same name. Use `move.term` or `delete.term`
       to resolve the conflicts.

We can resolve the name conflict by deleting one of the names.

.example.resolve.c> delete.term 2

  Resolved name conflicts:
  
    1. ┌ example.resolve.c.foo#a84tg4er4k : Nat
    2. └ example.resolve.c.foo#emomp74i93 : Nat
       ↓
    3. example.resolve.c.foo#a84tg4er4k : Nat
  
  Name changes:
  
    Original                               Changes
    4. example.resolve.a.foo            ┐  5. example.resolve.c.foo#emomp74i93 (removed)
    6. example.resolve.c.foo#emomp74i93 ┘  
  
  Tip: You can use `undo` or `reflog` to undo this change.

.example.resolve.c> todo

  ✅
  
  No conflicts or edits in progress.

And that's how you resolve edit conflicts with UCM.