Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
cli/examples: Introduce a suite of merge and revert tests for patch.destination
Adrian Duke committed 7 days ago
commit d7be2f278e54f5ae062cc3e4117dadf1e8a80b71
parent caee776c388ffac2ea55cc9d1e3d7fa108ca6df5
8 files changed +699 -0
added crates/radicle-cli/examples/rad-patch-merge-default-branch.md
@@ -0,0 +1,55 @@
+
# Merging patches into the default branch
+

+
We create a feature branch and open a patch without specifying a target branch.
+

+
``` (stderr)
+
$ git checkout -b feature/1
+
Switched to a new branch 'feature/1'
+
$ touch FEATURE.md
+
$ git add FEATURE.md
+
```
+
```
+
$ git commit -m "Add new feature"
+
[feature/1 [..]] Add new feature
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push -o patch.message="Add new feature" rad HEAD:refs/patches
+
✓ Patch [..] opened
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new reference]   HEAD -> refs/patches
+
```
+

+
Now, Alice merges the feature into the `master` branch and pushes it.
+

+
``` (stderr)
+
$ git checkout master
+
Switched to branch 'master'
+
```
+
```
+
$ git merge feature/1
+
Updating [..]
+
Fast-forward
+
 FEATURE.md | 0
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push rad master
+
✓ Patch [..] merged
+
✓ Canonical reference refs/heads/master updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
   [..]..[..]  master -> master
+
```
+

+
Finally, we verify that the patch has been successfully marked as merged.
+

+
```
+
$ rad patch list --merged
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ✓  [..]  Add new feature  alice   (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
added crates/radicle-cli/examples/rad-patch-merge-into-canonical-ref-branch.md
@@ -0,0 +1,96 @@
+
# Merging patches into non-default canonical branches
+

+
First, we update the identity document to add a canonical reference rule for a new `accepted` branch, allowing delegates to merge into it.
+

+
```
+
$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+
[..]
+
```
+

+
Now, let's create the `accepted` branch and push it to the repository so it becomes a tracked canonical reference:
+

+
``` (stderr)
+
$ git checkout -b accepted
+
Switched to a new branch 'accepted'
+
```
+

+
```
+
$ git commit --allow-empty -m "Initialize accepted branch"
+
[accepted [..]] Initialize accepted branch
+
```
+

+
``` (stderr)
+
$ git push rad accepted
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new branch]      accepted -> accepted
+
```
+

+
Next, we create a feature branch and open a patch. We use the `patch.destination` push option to explicitly state that this patch is intended for `refs/heads/accepted` rather than the default branch (`master`).
+

+
``` (stderr)
+
$ git checkout -b feature/1
+
Switched to a new branch 'feature/1'
+
$ touch FEATURE.md
+
$ git add FEATURE.md
+
```
+

+
```
+
$ git commit -m "Add new feature"
+
[feature/1 [..]] Add new feature
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+

+
``` (stderr)
+
$ git push -o patch.message="Add new feature" -o patch.destination="refs/heads/accepted" rad HEAD:refs/patches
+
✓ Patch [..] opened
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new reference]   HEAD -> refs/patches
+
```
+

+
We can verify the patch is open:
+

+
```
+
$ rad patch
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ●  [..]  Add new feature  alice   (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
+

+
Now, Alice merges the feature into the `accepted` branch and pushes it. Because `accepted` is a valid canonical reference and Alice is a delegate, the remote helper should detect the merge and update the patch status.
+

+
``` (stderr)
+
$ git checkout accepted
+
Switched to branch 'accepted'
+
```
+

+
```
+
$ git merge feature/1
+
Updating [..]
+
Fast-forward
+
 FEATURE.md | 0
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+

+
``` (stderr)
+
$ git push rad accepted
+
✓ Patch [..] merged
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
   [..]..[..]  accepted -> accepted
+
```
+

+
Finally, we verify that the patch has been successfully marked as merged, even though it wasn't merged into the default branch.
+

+
```
+
$ rad patch list --merged
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ✓  [..]  Add new feature  alice   (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
added crates/radicle-cli/examples/rad-patch-merge-strict-destination.md
@@ -0,0 +1,82 @@
+
# Merging patches has a strict destination
+

+
First, we update the identity document to add a canonical reference rule for a new `accepted` branch.
+

+
```
+
$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+
[..]
+
```
+

+
Now, let's create the `accepted` branch and push it:
+

+
``` (stderr)
+
$ git checkout -b accepted
+
Switched to a new branch 'accepted'
+
```
+
```
+
$ git commit --allow-empty -m "Initialize accepted branch"
+
[accepted [..]] Initialize accepted branch
+
```
+
``` (stderr)
+
$ git push rad accepted
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new branch]      accepted -> accepted
+
```
+

+
Next, we create a feature branch and open a patch. We do *not* specify a destination, so it defaults to `master`.
+

+
``` (stderr)
+
$ git checkout -b feature/1
+
Switched to a new branch 'feature/1'
+
$ touch FEATURE.md
+
$ git add FEATURE.md
+
```
+
```
+
$ git commit -m "Add new feature"
+
[feature/1 [..]] Add new feature
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push -o patch.message="Add new feature" rad HEAD:refs/patches
+
✓ Patch [..] opened
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new reference]   HEAD -> refs/patches
+
```
+

+
Now, Alice merges the feature into the `accepted` branch instead of `master`.
+

+
``` (stderr)
+
$ git checkout accepted
+
Switched to branch 'accepted'
+
```
+
```
+
$ git merge feature/1
+
Updating [..]
+
Fast-forward
+
 FEATURE.md | 0
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push rad accepted
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
   [..]..[..]  accepted -> accepted
+
```
+

+
Because the patch was implicitly targeted for `master`, pushing the commit to `accepted` should not mark it as merged. It should remain open.
+

+
```
+
$ rad patch list --merged
+
Nothing to show.
+
```
+
```
+
$ rad patch list --open
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ●  [..]  Add new feature  alice   (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
added crates/radicle-cli/examples/rad-patch-merge-unauthorized-branch.md
@@ -0,0 +1,97 @@
+
# Merging patches into an unauthorized branch
+

+
First, we update the identity document to add a canonical reference rule for a new `accepted` branch, but we only allow Alice to merge into it.
+

+
``` ~alice
+
$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": ["did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi"] } }' -q
+
[..]
+
```
+

+
Now, let's create the `accepted` branch and push it:
+

+
``` ~alice (stderr)
+
$ git checkout -b accepted
+
Switched to a new branch 'accepted'
+
```
+
``` ~alice
+
$ git commit --allow-empty -m "Initialize accepted branch"
+
[accepted [..]] Initialize accepted branch
+
```
+
``` ~alice (stderr)
+
$ git push rad accepted
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
✓ Synced with 1 seed(s)
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new branch]      accepted -> accepted
+
```
+

+
Next, Bob clones the repository and opens a patch targeting `accepted`.
+

+
``` ~bob
+
$ rad clone rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
+
✓ Creating checkout in ./heartwood..
+
✓ Remote alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi added
+
✓ Remote-tracking branch alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master created for z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
✓ Repository successfully cloned under [..]
+
╭────────────────────────────────────╮
+
│ heartwood                          │
+
│ Radicle Heartwood Protocol & Stack │
+
│ 0 issues · 0 patches               │
+
╰────────────────────────────────────╯
+
Run `cd ./heartwood` to go to the repository directory.
+
```
+
``` ~bob (stderr)
+
$ cd heartwood
+
$ git checkout -b feature/1
+
Switched to a new branch 'feature/1'
+
$ touch FEATURE.md
+
$ git add FEATURE.md
+
```
+
``` ~bob
+
$ git commit -m "Add new feature"
+
[feature/1 [..]] Add new feature
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` ~bob (stderr)
+
$ git push -o patch.message="Add new feature" -o patch.destination="refs/heads/accepted" rad HEAD:refs/patches
+
✓ Patch [..] opened
+
✓ Synced with 1 seed(s)
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
+
 * [new reference]   HEAD -> refs/patches
+
```
+

+
Now, Bob tries to merge the feature into the `accepted` branch and push it.
+

+
``` ~bob (stderr)
+
$ git checkout -t rad/accepted
+
Switched to a new branch 'accepted'
+
```
+
``` ~bob
+
$ git merge feature/1
+
Merge made by the 'ort' strategy.
+
 FEATURE.md | 0
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` ~bob (stderr)
+
$ git push rad accepted
+
✓ Synced with 1 seed(s)
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
+
 * [new branch]      accepted -> accepted
+
```
+

+
Notice that the canonical reference was *not* updated because Bob is not authorized. The patch should remain open.
+

+
``` ~bob
+
$ rad patch list --merged
+
Nothing to show.
+
```
+
``` ~bob
+
$ rad patch list --open
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ●  [..]  Add new feature  bob     (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
added crates/radicle-cli/examples/rad-patch-merge-wrong-branch.md
@@ -0,0 +1,82 @@
+
# Merging patches into the wrong branch
+

+
First, we update the identity document to add a canonical reference rule for a new `accepted` branch.
+

+
```
+
$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+
[..]
+
```
+

+
Now, let's create the `accepted` branch and push it:
+

+
``` (stderr)
+
$ git checkout -b accepted
+
Switched to a new branch 'accepted'
+
```
+
```
+
$ git commit --allow-empty -m "Initialize accepted branch"
+
[accepted [..]] Initialize accepted branch
+
```
+
``` (stderr)
+
$ git push rad accepted
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new branch]      accepted -> accepted
+
```
+

+
Next, we create a feature branch and open a patch targeting `accepted`.
+

+
``` (stderr)
+
$ git checkout -b feature/1
+
Switched to a new branch 'feature/1'
+
$ touch FEATURE.md
+
$ git add FEATURE.md
+
```
+
```
+
$ git commit -m "Add new feature"
+
[feature/1 [..]] Add new feature
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push -o patch.message="Add new feature" -o patch.destination="refs/heads/accepted" rad HEAD:refs/patches
+
✓ Patch [..] opened
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new reference]   HEAD -> refs/patches
+
```
+

+
Now, Alice accidentally merges the feature into the `master` branch instead of `accepted`.
+

+
``` (stderr)
+
$ git checkout master
+
Switched to branch 'master'
+
```
+
```
+
$ git merge feature/1
+
Updating [..]
+
Fast-forward
+
 FEATURE.md | 0
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push rad master
+
✓ Canonical reference refs/heads/master updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
   [..]..[..]  master -> master
+
```
+

+
Because the patch was explicitly targeted for `accepted`, it should remain open.
+

+
```
+
$ rad patch list --merged
+
Nothing to show.
+
```
+
```
+
$ rad patch list --open
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ●  [..]  Add new feature  alice   (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
added crates/radicle-cli/examples/rad-patch-revert-custom-branch.md
@@ -0,0 +1,108 @@
+
# Reverting a patch on a custom canonical branch
+

+
First, we update the identity document to add a canonical reference rule for a new `accepted` branch.
+

+
```
+
$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+
[..]
+
```
+

+
Now, let's create the `accepted` branch and push it:
+

+
``` (stderr)
+
$ git checkout -b accepted
+
Switched to a new branch 'accepted'
+
```
+
```
+
$ git commit --allow-empty -m "Initialize accepted branch"
+
[accepted [..]] Initialize accepted branch
+
```
+
``` (stderr)
+
$ git push rad accepted
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new branch]      accepted -> accepted
+
```
+

+
Next, we create a feature branch and open a patch targeting `accepted`.
+

+
``` (stderr)
+
$ git checkout -b feature/1
+
Switched to a new branch 'feature/1'
+
$ touch FEATURE.md
+
$ git add FEATURE.md
+
```
+
```
+
$ git commit -m "Add new feature"
+
[feature/1 [..]] Add new feature
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push -o patch.message="Add new feature" -o patch.destination="refs/heads/accepted" rad HEAD:refs/patches
+
✓ Patch [..] opened
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new reference]   HEAD -> refs/patches
+
```
+

+
Alice merges the feature into the `accepted` branch and pushes it.
+

+
``` (stderr)
+
$ git checkout accepted
+
Switched to branch 'accepted'
+
```
+
```
+
$ git merge feature/1
+
Updating [..]
+
Fast-forward
+
 FEATURE.md | 0
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push rad accepted
+
✓ Patch [..] merged
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
   [..]..[..]  accepted -> accepted
+
```
+

+
We verify the patch is merged.
+

+
```
+
$ rad patch list --merged
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ✓  [..]  Add new feature  alice   (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
+

+
Now, Alice realizes she made a mistake and resets the `accepted` branch, dropping the merge commit, and force pushes.
+

+
```
+
$ git reset --hard HEAD~1
+
HEAD is now at [..] Initialize accepted branch
+
```
+
``` (stderr)
+
$ git push rad accepted --force
+
! Patch [..] reverted at revision [..]
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 + [..]...[..] accepted -> accepted (forced update)
+
```
+

+
The patch should now be open again.
+

+
```
+
$ rad patch list --merged
+
Nothing to show.
+
```
+
```
+
$ rad patch list --open
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ●  [..]  Add new feature  alice   (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
added crates/radicle-cli/examples/rad-patch-revert-isolation.md
@@ -0,0 +1,107 @@
+
# Revert isolation (Force-pushing the wrong branch)
+

+
First, we update the identity document to add a canonical reference rule for a new `accepted` branch.
+

+
```
+
$ rad id update --title "Add accepted branch" --payload xyz.radicle.crefs rules '{ "refs/heads/accepted": { "threshold": 1, "allow": "delegates" } }' -q
+
[..]
+
```
+

+
Now, let's create the `accepted` branch and push it:
+

+
``` (stderr)
+
$ git checkout -b accepted
+
Switched to a new branch 'accepted'
+
```
+
```
+
$ git commit --allow-empty -m "Initialize accepted branch"
+
[accepted [..]] Initialize accepted branch
+
```
+
``` (stderr)
+
$ git push rad accepted
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new branch]      accepted -> accepted
+
```
+

+
Next, we create a feature branch and open a patch targeting `accepted`.
+

+
``` (stderr)
+
$ git checkout -b feature/1
+
Switched to a new branch 'feature/1'
+
$ touch FEATURE.md
+
$ git add FEATURE.md
+
```
+
```
+
$ git commit -m "Add new feature"
+
[feature/1 [..]] Add new feature
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push -o patch.message="Add new feature" -o patch.destination="refs/heads/accepted" rad HEAD:refs/patches
+
✓ Patch [..] opened
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 * [new reference]   HEAD -> refs/patches
+
```
+

+
Alice merges the feature into the `accepted` branch and pushes it.
+

+
``` (stderr)
+
$ git checkout accepted
+
Switched to branch 'accepted'
+
```
+
```
+
$ git merge feature/1
+
Updating [..]
+
Fast-forward
+
 FEATURE.md | 0
+
 1 file changed, 0 insertions(+), 0 deletions(-)
+
 create mode 100644 FEATURE.md
+
```
+
``` (stderr)
+
$ git push rad accepted
+
✓ Patch [..] merged
+
✓ Canonical reference refs/heads/accepted updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
   [..]..[..]  accepted -> accepted
+
```
+

+
We verify the patch is merged.
+

+
```
+
$ rad patch list --merged
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ✓  [..]  Add new feature  alice   (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
+

+
Now, Alice switches to `master`, resets it to drop a commit, and force pushes. This simulates a scenario where commits are dropped from a branch *other* than the patch's destination.
+

+
``` (stderr)
+
$ git checkout master
+
Switched to branch 'master'
+
```
+
```
+
$ git reset --hard HEAD~1
+
HEAD is now at [..] Initial commit
+
```
+
``` (stderr)
+
$ git push rad master --force
+
✓ Canonical reference refs/heads/master updated to target commit [..]
+
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
+
 + [..]...[..] master -> master (forced update)
+
```
+

+
Because the patch was merged into `accepted`, dropping commits on `master` should not revert the patch. It should remain merged.
+

+
```
+
$ rad patch list --merged
+
╭───────────────────────────────────────────────────────────────────────────────╮
+
│ ●  ID       Title            Author         Reviews  Head     +   -   Updated │
+
├───────────────────────────────────────────────────────────────────────────────┤
+
│ ✓  [..]  Add new feature  alice   (you)  -        [..]  +0  -0  now     │
+
╰───────────────────────────────────────────────────────────────────────────────╯
+
```
modified crates/radicle-cli/tests/commands/patch.rs
@@ -386,3 +386,75 @@ fn rad_merge_no_ff() {
        .tests(["rad-init", "rad-merge-no-ff"], &alice)
        .unwrap();
}
+

+
#[test]
+
fn rad_patch_merge_into_canonical_ref_branch() {
+
    Environment::alice(["rad-init", "rad-patch-merge-into-canonical-ref-branch"]);
+
}
+

+
#[test]
+
fn rad_patch_merge_default_branch() {
+
    Environment::alice(["rad-init", "rad-patch-merge-default-branch"]);
+
}
+

+
#[test]
+
fn rad_patch_merge_wrong_branch() {
+
    Environment::alice(["rad-init", "rad-patch-merge-wrong-branch"]);
+
}
+

+
#[test]
+
fn rad_patch_merge_unauthorized_branch() {
+
    let mut environment = Environment::new();
+
    let alice = environment.node("alice");
+
    let bob = environment.node("bob");
+
    let acme = RepoId::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
+

+
    environment.repository(&alice);
+

+
    test(
+
        "examples/rad-init.md",
+
        environment.work(&alice),
+
        Some(&alice.home),
+
        [],
+
    )
+
    .unwrap();
+

+
    let mut alice = alice.spawn();
+
    let mut bob = bob.spawn();
+

+
    bob.handle.seed(acme, Scope::All).unwrap();
+
    alice.connect(&bob).converge([&bob]);
+

+
    formula(
+
        &environment.tempdir(),
+
        "examples/rad-patch-merge-unauthorized-branch.md",
+
    )
+
    .unwrap()
+
    .home(
+
        "alice",
+
        environment.work(&alice),
+
        [("RAD_HOME", alice.home.path().display())],
+
    )
+
    .home(
+
        "bob",
+
        environment.work(&bob),
+
        [("RAD_HOME", bob.home.path().display())],
+
    )
+
    .run()
+
    .unwrap();
+
}
+

+
#[test]
+
fn rad_patch_revert_custom_branch() {
+
    Environment::alice(["rad-init", "rad-patch-revert-custom-branch"]);
+
}
+

+
#[test]
+
fn rad_patch_revert_isolation() {
+
    Environment::alice(["rad-init", "rad-patch-revert-isolation"]);
+
}
+

+
#[test]
+
fn rad_patch_merge_strict_destination() {
+
    Environment::alice(["rad-init", "rad-patch-merge-strict-destination"]);
+
}