diff --git a/radicle-cli/examples/rad-patch.md b/radicle-cli/examples/rad-patch.md index 22e0cdb3..9d7a41d1 100644 --- a/radicle-cli/examples/rad-patch.md +++ b/radicle-cli/examples/rad-patch.md @@ -107,6 +107,7 @@ Now, let's checkout the patch that we just created: ``` $ rad patch checkout 077e4bb ✓ Switched to branch patch/077e4bb +✓ Branch patch/077e4bb setup to track rad/patches/077e4bbe9a6e5546f400ef5951768c37a76f13a4 ``` We can also add a review verdict as such: diff --git a/radicle-cli/examples/workflow/5-patching-maintainer.md b/radicle-cli/examples/workflow/5-patching-maintainer.md index e0603238..8c513c20 100644 --- a/radicle-cli/examples/workflow/5-patching-maintainer.md +++ b/radicle-cli/examples/workflow/5-patching-maintainer.md @@ -58,17 +58,20 @@ way will tell others about the corrections we needed before merging the changes. ``` -$ git checkout patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c -branch 'patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c' set up to track 'bob/patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c'. +$ rad patch checkout 50e29a111972f3b7d2123c5057de5bdf09bc7b1c +✓ Switched to branch patch/50e29a1 +✓ Branch patch/50e29a1 setup to track rad/patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c $ git mv REQUIREMENTS REQUIREMENTS.md -$ git commit --fixup HEAD~ -[patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c f6484e0] fixup! Define power requirements +$ git commit -m "Use markdown for requirements" +[patch/50e29a1 f567f69] Use markdown for requirements 1 file changed, 0 insertions(+), 0 deletions(-) rename REQUIREMENTS => REQUIREMENTS.md (100%) -$ rad patch update --message "Define power requirements" --message "See details." 50e29a111972f3b7d2123c5057de5bdf09bc7b1c -Updating 27857ec -> f6484e0 -1 commit(s) ahead, 0 commit(s) behind -✓ Patch updated to revision a3405e8e174d9660fead6eea1dea5cdd2b728488 +``` +``` (stderr) +$ git push rad -o no-sync -o patch.message="Use markdown for requirements" +✓ Patch 50e29a1 updated to 744c1f0a75b1c42833c9aa32f79cd40443925d66 +To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi + * [new branch] patch/50e29a1 -> patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c ``` Great, all fixed up, lets merge the code. @@ -76,8 +79,8 @@ Great, all fixed up, lets merge the code. ``` $ git checkout master Your branch is up to date with 'rad/master'. -$ git merge patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c -Updating f2de534..f6484e0 +$ git merge patch/50e29a1 +Updating f2de534..f567f69 Fast-forward README.md | 0 REQUIREMENTS.md | 0 @@ -95,20 +98,20 @@ $ rad patch show 50e29a1 │ Title Define power requirements │ │ Patch 50e29a111972f3b7d2123c5057de5bdf09bc7b1c │ │ Author did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk │ -│ Head f6484e0f43e48a8983b9b39bf9bd4cd889f1d520 │ -│ Branches master, patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c │ +│ Head f567f695d25b4e8fb63b5f5ad2a584529826e908 │ +│ Branches master, patch/50e29a1 │ │ Commits up to date │ │ Status merged │ │ │ │ See details. │ ├──────────────────────────────────────────────────────────────────────────────┤ -│ f6484e0 fixup! Define power requirements │ +│ f567f69 Use markdown for requirements │ │ 27857ec Add README, just for the fun │ │ 3e674d1 Define power requirements │ ├──────────────────────────────────────────────────────────────────────────────┤ │ ● opened by bob (z6Mkt67…v4N1tRk) [ ... ] │ │ ↑ updated to 3530243d46a2e7a8e4eac7afcbb17cc7c56b3d29 (27857ec) [ ... ] │ -│ ↑ updated to a3405e8e174d9660fead6eea1dea5cdd2b728488 (f6484e0) [ ... ] │ +│ ↑ updated to 744c1f0a75b1c42833c9aa32f79cd40443925d66 (f567f69) [ ... ] │ │ ✓ merged by (you) (z6MknSL…StBU8Vi) [ ... ] │ ╰──────────────────────────────────────────────────────────────────────────────╯ ``` diff --git a/radicle-cli/examples/workflow/6-pulling-contributor.md b/radicle-cli/examples/workflow/6-pulling-contributor.md index bb61f3fa..c707a1f4 100644 --- a/radicle-cli/examples/workflow/6-pulling-contributor.md +++ b/radicle-cli/examples/workflow/6-pulling-contributor.md @@ -18,22 +18,19 @@ Now let's checkout `master` and pull the maintainer's changes: ``` $ git checkout master Your branch is up to date with 'rad/master'. +``` +``` (stderr) $ git pull --all --ff -Fetching rad -Fetching z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi -Updating f2de534..f6484e0 -Fast-forward - README.md | 0 - REQUIREMENTS.md | 0 - 2 files changed, 0 insertions(+), 0 deletions(-) - create mode 100644 README.md - create mode 100644 REQUIREMENTS.md +From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji + f2de534..f567f69 master -> rad/master +From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi + f2de534..f567f69 master -> z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master ``` Now our master branch is up to date with the maintainer's master: ``` $ git rev-parse master -f6484e0f43e48a8983b9b39bf9bd4cd889f1d520 +f567f695d25b4e8fb63b5f5ad2a584529826e908 $ git diff master..z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master ``` diff --git a/radicle-cli/src/commands/patch/checkout.rs b/radicle-cli/src/commands/patch/checkout.rs index ed4d4d11..be270074 100644 --- a/radicle-cli/src/commands/patch/checkout.rs +++ b/radicle-cli/src/commands/patch/checkout.rs @@ -2,10 +2,10 @@ use anyhow::anyhow; use radicle::cob::patch; use radicle::cob::patch::{Patch, PatchId}; -use radicle::git; use radicle::git::RefString; use radicle::storage::git::Repository; use radicle::storage::ReadRepository; +use radicle::{git, rad}; use crate::terminal as term; @@ -32,10 +32,20 @@ pub fn run( spinner.message(format!( "Switched to branch {}", - term::format::highlight(patch_branch.as_str()) + term::format::highlight(&patch_branch) )); spinner.finish(); + if let Some(branch) = rad::setup_patch_upstream(patch_id, *patch.head(), working)? { + let tracking = branch + .name()? + .ok_or_else(|| anyhow!("failed to create tracking branch: invalid name"))?; + term::success!( + "Branch {} setup to track {}", + term::format::highlight(patch_branch), + term::format::tertiary(tracking) + ); + } Ok(()) } @@ -52,7 +62,6 @@ fn find_patch_commit<'a>( match working.find_commit(patch_head.into()) { Ok(commit) => Ok(commit), Err(e) if git::ext::is_not_found_err(&e) => { - // TODO: Handle case of concurrent revisions. let (_, rev) = patch.latest(); let author = *rev.author().id(); let remote = stored.remote(&author)?; diff --git a/radicle-remote-helper/src/push.rs b/radicle-remote-helper/src/push.rs index 9d9bbe0b..68040ff9 100644 --- a/radicle-remote-helper/src/push.rs +++ b/radicle-remote-helper/src/push.rs @@ -325,34 +325,9 @@ fn patch_open( "Create reference for patch head", )?; - let head = working.head()?; - if head.peel_to_commit()?.id() == commit.id() { - if let Ok(r) = head.resolve() { - let branch = git::raw::Branch::wrap(r); - let name: Option = - branch.name()?.and_then(|b| b.try_into().ok()); + // Setup current branch so that pushing updates the patch. + rad::setup_patch_upstream(&patch, commit.id().into(), working)?; - working.reference( - &git::refs::workdir::patch_upstream(&patch), - commit.id(), - // The patch shouldn't exist yet, and so neither should - // this ref. - false, - "Create remote tracking branch for patch", - )?; - - if let Some(name) = name { - if branch.upstream().is_err() { - git::set_upstream( - working, - &*radicle::rad::REMOTE_NAME, - name.as_str(), - git::refs::workdir::patch(&patch), - )?; - } - } - } - } Ok(()) } Err(e) => Err(e), diff --git a/radicle/src/rad.rs b/radicle/src/rad.rs index 2135ae54..8de07480 100644 --- a/radicle/src/rad.rs +++ b/radicle/src/rad.rs @@ -6,6 +6,7 @@ use std::str::FromStr; use once_cell::sync::Lazy; use thiserror::Error; +use crate::cob::ObjectId; use crate::crypto::{Signer, Verified}; use crate::git; use crate::identity::doc::{DocError, Id}; @@ -317,6 +318,46 @@ pub fn repo(path: impl AsRef) -> Result<(git2::Repository, Id), RemoteErro Ok((repo, id)) } +/// Setup patch upstream branch such that `git push` updates the patch. +pub fn setup_patch_upstream<'a>( + patch: &ObjectId, + patch_head: git::Oid, + working: &'a git::raw::Repository, +) -> Result>, git::ext::Error> { + let head = working.head()?; + + // Don't do anything in case we're not on the patch branch. + if head.peel_to_commit()?.id() != *patch_head { + return Ok(None); + } + let Ok(r) = head.resolve() else { + return Ok(None); + }; + + let branch = git::raw::Branch::wrap(r); + let name: Option = branch.name()?.and_then(|b| b.try_into().ok()); + let remote_branch = git::refs::workdir::patch_upstream(patch); + let remote_branch = working.reference( + &remote_branch, + *patch_head, + true, + "Create remote tracking branch for patch", + )?; + assert!(remote_branch.is_remote()); + + if let Some(name) = name { + if branch.upstream().is_err() { + git::set_upstream( + working, + &*REMOTE_NAME, + name.as_str(), + git::refs::workdir::patch(patch), + )?; + } + } + Ok(Some(git::raw::Branch::wrap(remote_branch))) +} + #[cfg(test)] mod tests { use std::collections::HashMap;