cli: Check for branch on checkout

The `rad patch checkout` command would blindly create a branch when
being executed. If there was a branch already existing and user had
committed to that branch, switched without updating the patch, and
then switched back, then they would lose the commit on that branch --
the original commit of the patch would be taken instead.

Fix this by first checking if the branch existed beforehand, and
setting the workspace to use that branch's commit.

Add a test to ensure that this works as expected.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
Fintan Halpenny 2023-10-23 13:56:18 +01:00 committed by cloudhead
parent 90f3a37a08
commit 7e3c7a7ae0
No known key found for this signature in database
3 changed files with 105 additions and 4 deletions

View File

@ -0,0 +1,72 @@
We may want to work on top of an existing patch and this where `rad
patch checkout` comes into play. So, first we will create a patch to
set up the workflow.
```
$ git checkout -b flux-capacitor-power
$ touch REQUIREMENTS
```
Here the instructions are added to the project's README for 1.21 gigawatts and
commit the changes to git.
```
$ git add REQUIREMENTS
$ git commit -v -m "Define power requirements"
[flux-capacitor-power 3e674d1] Define power requirements
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 REQUIREMENTS
```
Once the code is ready, we open (or create) a patch with our changes for the project.
``` (stderr)
$ git push rad -o patch.message="Define power requirements" -o patch.message="See details." HEAD:refs/patches
✓ Patch a8926643a8f6a65bc386b0131621994000485d4d opened
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
* [new reference] HEAD -> refs/patches
```
Now, let's checkout the patch that we just created:
```
$ rad patch checkout a892664
✓ Switched to branch patch/a892664
✓ Branch patch/a892664 setup to track rad/patches/a8926643a8f6a65bc386b0131621994000485d4d
```
Now, let's add a README too!
```
$ touch README.md
$ git add README.md
$ git commit --message "Add README, just for the fun"
[patch/a892664 27857ec] Add README, just for the fun
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md
```
But maybe we first wanted to rebase `master` so we ended up being on
that branch:
``` (stderr)
$ git checkout master
Switched to branch 'master'
```
We can be safe in the knowledge that our changes on the
`patch/a892664` branch are still safe:
```
$ rad patch checkout a892664
✓ Switched to branch patch/a892664
```
We can now finish off the update:
``` (stderr)
$ git push rad -o patch.message="Add README, just for the fun"
✓ Patch a892664 updated to 8d8aa0887a11f2a37fa8ed0d5723efa96fd727ed
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
3e674d1..27857ec patch/a892664 -> patches/a8926643a8f6a65bc386b0131621994000485d4d
```

View File

@ -34,11 +34,20 @@ pub fn run(
let patch_branch =
// SAFETY: Patch IDs are valid refstrings.
git::refname!("patch").join(RefString::try_from(term::format::cob(&patch_id)).unwrap());
let commit = find_patch_commit(revision, stored, working)?;
// Create patch branch and switch to it.
working.branch(patch_branch.as_str(), &commit, true)?;
working.checkout_tree(commit.as_object(), None)?;
match working.find_branch(patch_branch.as_str(), radicle::git::raw::BranchType::Local) {
Ok(branch) => {
let commit = branch.get().peel_to_commit()?;
working.checkout_tree(commit.as_object(), None)?;
}
Err(e) if radicle::git::is_not_found_err(&e) => {
let commit = find_patch_commit(revision, stored, working)?;
// Create patch branch and switch to it.
working.branch(patch_branch.as_str(), &commit, true)?;
working.checkout_tree(commit.as_object(), None)?;
}
Err(e) => return Err(e.into()),
}
working.set_head(&git::refs::workdir::branch(&patch_branch))?;
spinner.message(format!(

View File

@ -410,6 +410,26 @@ fn rad_patch() {
test("examples/rad-patch.md", working.path(), Some(home), []).unwrap();
}
#[test]
fn rad_patch_checkout() {
let mut environment = Environment::new();
let profile = environment.profile("alice");
let working = tempfile::tempdir().unwrap();
let home = &profile.home;
// Setup a test repository.
fixtures::repository(working.path());
test("examples/rad-init.md", working.path(), Some(home), []).unwrap();
test(
"examples/rad-patch-checkout.md",
working.path(),
Some(home),
[],
)
.unwrap();
}
#[test]
fn rad_patch_update() {
let mut environment = Environment::new();