cli: add force flag to rad patch checkout
Add a `--force` flag to forcibly checkout the branch to the latest revision, if the branch already exists. Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com> X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
parent
358324883c
commit
30ad7e4d67
|
|
@ -0,0 +1,87 @@
|
|||
A common workflow is to use `rad patch checkout` to view a
|
||||
collaborator's changes. So, first off, we create a patch:
|
||||
|
||||
``` ~alice
|
||||
$ git checkout -b flux-capacitor-power
|
||||
$ touch REQUIREMENTS
|
||||
$ 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
|
||||
```
|
||||
|
||||
``` ~alice (stderr)
|
||||
$ git push rad -o patch.message="Define power requirements" -o patch.message="See details." HEAD:refs/patches
|
||||
✓ Patch 6ff4f09c1b5a81347981f59b02ef43a31a07cdae opened
|
||||
✓ Synced with 1 node(s)
|
||||
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
* [new reference] HEAD -> refs/patches
|
||||
```
|
||||
|
||||
On the other end, Bob uses `rad patch checkout` to view the patch:
|
||||
|
||||
``` ~bob
|
||||
$ cd heartwood
|
||||
$ rad sync -f
|
||||
✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MknSL…StBU8Vi..
|
||||
✓ Fetched repository from 1 seed(s)
|
||||
$ rad patch checkout 6ff4f09
|
||||
✓ Switched to branch patch/6ff4f09
|
||||
✓ Branch patch/6ff4f09 setup to track rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae
|
||||
```
|
||||
|
||||
Meanwhile, we may see some more changes that we need to make, so we
|
||||
add a `README.md`:
|
||||
|
||||
``` ~alice
|
||||
$ touch README.md
|
||||
$ git add README.md
|
||||
$ git commit --message "Add README, just for the fun"
|
||||
[flux-capacitor-power 27857ec] Add README, just for the fun
|
||||
1 file changed, 0 insertions(+), 0 deletions(-)
|
||||
create mode 100644 README.md
|
||||
```
|
||||
|
||||
``` ~alice (stderr)
|
||||
$ git push rad -o patch.message="Add README, just for the fun"
|
||||
✓ Patch 6ff4f09 updated to 0c0942e2ff2488617d950ede15567ca39a29972e
|
||||
✓ Synced with 1 node(s)
|
||||
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
3e674d1..27857ec flux-capacitor-power -> patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae
|
||||
```
|
||||
|
||||
Bob fetches these new changes and can see their branch is now behind:
|
||||
|
||||
``` ~bob (stderr)
|
||||
$ git fetch rad
|
||||
✓ Synced with 1 peer(s)
|
||||
From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
|
||||
3e674d1..27857ec patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae -> rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae
|
||||
```
|
||||
|
||||
``` ~bob
|
||||
$ git status
|
||||
On branch patch/6ff4f09
|
||||
Your branch is behind 'rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae' by 1 commit, and can be fast-forwarded.
|
||||
(use "git pull" to update your local branch)
|
||||
|
||||
nothing to commit, working tree clean
|
||||
```
|
||||
|
||||
If Bob was to run `rad patch checkout` again, their branch would not
|
||||
update to the latest commit. This is because it sees that the branch
|
||||
already exists and does not want overwrite any changes. Bob can choose
|
||||
to use the `--force` (`-f`) flag to ensure that they are looking at
|
||||
the latest changes:
|
||||
|
||||
``` ~bob
|
||||
$ rad patch checkout 6ff4f09 -f
|
||||
✓ Switched to branch patch/6ff4f09
|
||||
✓ Branch patch/6ff4f09 setup to track rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae
|
||||
$ git status
|
||||
On branch patch/6ff4f09
|
||||
Your branch is up to date with 'rad/patches/6ff4f09c1b5a81347981f59b02ef43a31a07cdae'.
|
||||
|
||||
nothing to commit, working tree clean
|
||||
```
|
||||
|
|
@ -85,6 +85,10 @@ Ready options
|
|||
|
||||
--undo Convert a patch back to a draft
|
||||
|
||||
Checkout options
|
||||
|
||||
-f, --force Checkout the head of the revision, even if the branch already exists
|
||||
|
||||
Other options
|
||||
|
||||
-q, --quiet Quiet output
|
||||
|
|
@ -151,6 +155,7 @@ pub enum Operation {
|
|||
},
|
||||
Checkout {
|
||||
revision_id: Rev,
|
||||
force: bool,
|
||||
},
|
||||
Comment {
|
||||
revision_id: Rev,
|
||||
|
|
@ -198,6 +203,7 @@ impl Args for Options {
|
|||
let mut diff = false;
|
||||
let mut undo = false;
|
||||
let mut reply_to: Option<Rev> = None;
|
||||
let mut force = false;
|
||||
|
||||
while let Some(arg) = parser.next()? {
|
||||
match arg {
|
||||
|
|
@ -251,6 +257,11 @@ impl Args for Options {
|
|||
reply_to = Some(rev);
|
||||
}
|
||||
|
||||
// Checkout options
|
||||
Long("force") | Short('f') if op == Some(OperationName::Checkout) => {
|
||||
force = true;
|
||||
}
|
||||
|
||||
// List options.
|
||||
Long("all") => {
|
||||
filter = Filter::all();
|
||||
|
|
@ -340,6 +351,7 @@ impl Args for Options {
|
|||
},
|
||||
OperationName::Checkout => Operation::Checkout {
|
||||
revision_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
|
||||
force,
|
||||
},
|
||||
OperationName::Comment => Operation::Comment {
|
||||
revision_id: patch_id
|
||||
|
|
@ -419,9 +431,14 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
|
||||
delete::run(&patch_id, &profile, &repository)?;
|
||||
}
|
||||
Operation::Checkout { revision_id } => {
|
||||
Operation::Checkout { revision_id, force } => {
|
||||
let revision_id = revision_id.resolve::<radicle::git::Oid>(&repository.backend)?;
|
||||
checkout::run(&patch::RevisionId::from(revision_id), &repository, &workdir)?;
|
||||
checkout::run(
|
||||
&patch::RevisionId::from(revision_id),
|
||||
&repository,
|
||||
&workdir,
|
||||
force,
|
||||
)?;
|
||||
}
|
||||
Operation::Comment {
|
||||
revision_id,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ pub fn run(
|
|||
revision_id: &RevisionId,
|
||||
stored: &Repository,
|
||||
working: &git::raw::Repository,
|
||||
force: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let patches = patch::Patches::open(stored)?;
|
||||
|
||||
|
|
@ -35,18 +36,30 @@ pub fn run(
|
|||
// SAFETY: Patch IDs are valid refstrings.
|
||||
git::refname!("patch").join(RefString::try_from(term::format::cob(&patch_id)).unwrap());
|
||||
|
||||
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()),
|
||||
let commit =
|
||||
match working.find_branch(patch_branch.as_str(), radicle::git::raw::BranchType::Local) {
|
||||
Ok(branch) if !force => branch.get().peel_to_commit()?,
|
||||
Ok(branch) => {
|
||||
let commit = find_patch_commit(revision, stored, working)?;
|
||||
let mut r = branch.into_reference();
|
||||
r.set_target(commit.id(), &format!("force update '{patch_branch}'"))?;
|
||||
commit
|
||||
}
|
||||
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)?;
|
||||
commit
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
if force {
|
||||
let mut opts = radicle::git::raw::build::CheckoutBuilder::new();
|
||||
opts.force();
|
||||
working.checkout_tree(commit.as_object(), Some(&mut opts))?;
|
||||
} else {
|
||||
working.checkout_tree(commit.as_object(), None)?;
|
||||
}
|
||||
working.set_head(&git::refs::workdir::branch(&patch_branch))?;
|
||||
|
||||
|
|
|
|||
|
|
@ -440,6 +440,55 @@ fn rad_patch_checkout() {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rad_patch_checkout_force() {
|
||||
let mut environment = Environment::new();
|
||||
let alice = environment.node(Config::test(Alias::new("alice")));
|
||||
let bob = environment.node(Config::test(Alias::new("bob")));
|
||||
let working = environment.tmp().join("working");
|
||||
let acme = Id::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
|
||||
|
||||
// Setup a test repository.
|
||||
fixtures::repository(working.join("alice"));
|
||||
|
||||
test(
|
||||
"examples/rad-init.md",
|
||||
working.join("alice"),
|
||||
Some(&alice.home),
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut alice = alice.spawn();
|
||||
let mut bob = bob.spawn();
|
||||
|
||||
bob.handle.track_repo(acme, Scope::All).unwrap();
|
||||
alice.connect(&bob).converge([&bob]);
|
||||
|
||||
test(
|
||||
"examples/rad-clone.md",
|
||||
working.join("bob"),
|
||||
Some(&bob.home),
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
formula(&environment.tmp(), "examples/rad-patch-checkout-force.md")
|
||||
.unwrap()
|
||||
.home(
|
||||
"alice",
|
||||
working.join("alice"),
|
||||
[("RAD_HOME", alice.home.path().display())],
|
||||
)
|
||||
.home(
|
||||
"bob",
|
||||
working.join("bob"),
|
||||
[("RAD_HOME", bob.home.path().display())],
|
||||
)
|
||||
.run()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rad_patch_update() {
|
||||
let mut environment = Environment::new();
|
||||
|
|
|
|||
Loading…
Reference in New Issue