diff --git a/radicle-cli/examples/git/git-push-diverge.md b/radicle-cli/examples/git/git-push-diverge.md index f5a2d44e..7a7f2334 100644 --- a/radicle-cli/examples/git/git-push-diverge.md +++ b/radicle-cli/examples/git/git-push-diverge.md @@ -62,6 +62,7 @@ f2de534 Second commit ``` ``` ~alice RAD_SOCKET=/dev/null (stderr) $ git push rad +✓ Canonical head updated to f6cff86594495e9beccfeda7c20173e55c1dd9fc To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi f2de534..f6cff86 master -> master ``` @@ -79,6 +80,7 @@ We have to use the `allow.rollback` option: ``` ~alice RAD_SOCKET=/dev/null (stderr) $ git push -f -o allow.rollback +✓ Canonical head updated to 319a7dc3b195368ded4b099f8c90bbb80addccd3 To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi + f6cff86...319a7dc master -> master (forced update) ``` diff --git a/radicle-cli/examples/rad-merge-after-update.md b/radicle-cli/examples/rad-merge-after-update.md index 66f58074..5e866ad6 100644 --- a/radicle-cli/examples/rad-merge-after-update.md +++ b/radicle-cli/examples/rad-merge-after-update.md @@ -16,6 +16,7 @@ $ git commit --amend --allow-empty -q -m "Amended change" $ git checkout master -q $ git merge feature/1 -q $ git push rad master +✓ Canonical head updated to 954bcdb5008447ce294a61a21d7eb87afbe7f4a6 To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi f2de534..954bcdb master -> master ``` diff --git a/radicle-cli/examples/rad-merge-no-ff.md b/radicle-cli/examples/rad-merge-no-ff.md index 3a65a6d7..833dc05f 100644 --- a/radicle-cli/examples/rad-merge-no-ff.md +++ b/radicle-cli/examples/rad-merge-no-ff.md @@ -37,6 +37,7 @@ Finally, we push master and expect the patch to be merged. ``` (stderr) RAD_SOCKET=/dev/null $ git push rad master ✓ Patch a1207f6e82700e42cc46c9c38c7786b18cbd2040 merged +✓ Canonical head updated to 737a10cfa29111afeb0d43cf3545cee386b939ec To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi f2de534..737a10c master -> master ``` diff --git a/radicle-cli/examples/rad-merge-via-push.md b/radicle-cli/examples/rad-merge-via-push.md index 3d01aa57..01917f0f 100644 --- a/radicle-cli/examples/rad-merge-via-push.md +++ b/radicle-cli/examples/rad-merge-via-push.md @@ -63,6 +63,7 @@ When we push to `rad/master`, we automatically merge the patches: $ git push rad master ✓ Patch 8357a9f1d61e80309d314491aa754969d9f47d77 merged ✓ Patch a1207f6e82700e42cc46c9c38c7786b18cbd2040 merged +✓ Canonical head updated to d6399c71702b40bae00825b3c444478d06b4e91c To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi f2de534..d6399c7 master -> master ``` diff --git a/radicle-cli/examples/rad-patch-merge-draft.md b/radicle-cli/examples/rad-patch-merge-draft.md index 980f7e74..ee72816d 100644 --- a/radicle-cli/examples/rad-patch-merge-draft.md +++ b/radicle-cli/examples/rad-patch-merge-draft.md @@ -14,6 +14,7 @@ $ git checkout master -q $ git merge feature/1 $ git push rad master ✓ Patch cf29ac6b10141058be66b94a92a81c703b972751 merged +✓ Canonical head updated to 20aa5dde6210796c3a2f04079b42316a31d02689 To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi f2de534..20aa5dd master -> master ``` diff --git a/radicle-cli/examples/workflow/5-patching-maintainer.md b/radicle-cli/examples/workflow/5-patching-maintainer.md index c6a85cda..d25f4757 100644 --- a/radicle-cli/examples/workflow/5-patching-maintainer.md +++ b/radicle-cli/examples/workflow/5-patching-maintainer.md @@ -90,6 +90,7 @@ Fast-forward ``` (stderr) $ git push rad master ✓ Patch 3581e83ad18f5cdd806ab50fa11cfd5dd4e8ae1c merged at revision abb0360 +✓ Canonical head updated to f567f695d25b4e8fb63b5f5ad2a584529826e908 ✓ Synced with 1 node(s) To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi f2de534..f567f69 master -> master diff --git a/radicle-remote-helper/src/push.rs b/radicle-remote-helper/src/push.rs index b5501f94..e8d5d85f 100644 --- a/radicle-remote-helper/src/push.rs +++ b/radicle-remote-helper/src/push.rs @@ -279,8 +279,16 @@ pub fn run( // Sign refs and sync if at least one ref pushed successfully. if !ok.is_empty() { - stored.sign_refs(&signer)?; - stored.set_head()?; + let _ = stored.sign_refs(&signer)?; + let head = stored.set_head()?; + + if head.is_updated() { + eprintln!( + "{} Canonical head updated to {}", + cli::format::positive("✓"), + cli::format::secondary(head.new), + ); + } if !opts.no_sync { // Connect to local node and announce refs to the network. diff --git a/radicle-tools/src/rad-push.rs b/radicle-tools/src/rad-push.rs index 3f0e7eb6..8d686ae8 100644 --- a/radicle-tools/src/rad-push.rs +++ b/radicle-tools/src/rad-push.rs @@ -21,7 +21,7 @@ fn main() -> anyhow::Result<()> { radicle::Node::new(profile.socket()).announce_refs(id)?; - println!("head: {head}"); + println!("head: {}", head.new); println!("ok: {}", sigrefs.signature); Ok(()) diff --git a/radicle-tools/src/rad-set-canonical-refs.rs b/radicle-tools/src/rad-set-canonical-refs.rs index 5d6d6cd0..f1de5cff 100644 --- a/radicle-tools/src/rad-set-canonical-refs.rs +++ b/radicle-tools/src/rad-set-canonical-refs.rs @@ -10,10 +10,10 @@ fn main() -> anyhow::Result<()> { let repo = profile.storage.repository_mut(rid)?; let id_oid = repo.set_identity_head()?; - let branch_oid = repo.set_head()?; + let branch = repo.set_head()?; println!("ok: identity: {id_oid}"); - println!("ok: branch: {branch_oid}"); + println!("ok: branch: {}", branch.new); Ok(()) } diff --git a/radicle/src/storage.rs b/radicle/src/storage.rs index 3e77b241..e8c386ba 100644 --- a/radicle/src/storage.rs +++ b/radicle/src/storage.rs @@ -69,6 +69,21 @@ impl FromIterator for Namespaces { } } +/// Output of [`WriteRepository::set_head`]. +pub struct SetHead { + /// Old branch head. + pub old: Option, + /// New branch head. + pub new: Oid, +} + +impl SetHead { + /// Check if the head was updated. + pub fn is_updated(&self) -> bool { + self.old != Some(self.new) + } +} + /// Repository error. #[derive(Error, Debug)] pub enum RepositoryError { @@ -536,7 +551,7 @@ where pub trait WriteRepository: ReadRepository + SignRepository { /// Set the repository head to the canonical branch. /// This computes the head based on the delegate set. - fn set_head(&self) -> Result; + fn set_head(&self) -> Result; /// Set the repository 'rad/id' to the canonical commit, agreed by quorum. fn set_identity_head(&self) -> Result { let head = self.canonical_identity_head()?; diff --git a/radicle/src/storage/git.rs b/radicle/src/storage/git.rs index 1a585b55..cf5de216 100644 --- a/radicle/src/storage/git.rs +++ b/radicle/src/storage/git.rs @@ -19,8 +19,8 @@ use crate::identity::{Identity, Project}; use crate::storage::refs; use crate::storage::refs::{Refs, SignedRefs, SignedRefsAt}; use crate::storage::{ - Inventory, ReadRepository, ReadStorage, Remote, Remotes, RepositoryError, SignRepository, - WriteRepository, WriteStorage, + Inventory, ReadRepository, ReadStorage, Remote, Remotes, RepositoryError, SetHead, + SignRepository, WriteRepository, WriteStorage, }; pub use crate::git::{ @@ -799,19 +799,27 @@ impl ReadRepository for Repository { } impl WriteRepository for Repository { - fn set_head(&self) -> Result { + fn set_head(&self) -> Result { let head_ref = refname!("HEAD"); - let (branch_ref, head) = self.canonical_head()?; + let old = self + .raw() + .refname_to_id(&head_ref) + .ok() + .map(|oid| oid.into()); + let (branch_ref, new) = self.canonical_head()?; - log::debug!(target: "storage", "Setting ref: {} -> {}", &branch_ref, head); + if old == Some(new) { + return Ok(SetHead { old, new }); + } + log::debug!(target: "storage", "Setting ref: {} -> {}", &branch_ref, new); self.raw() - .reference(&branch_ref, *head, true, "set-local-branch (radicle)")?; + .reference(&branch_ref, *new, true, "set-local-branch (radicle)")?; log::debug!(target: "storage", "Setting ref: {} -> {}", head_ref, branch_ref); self.raw() .reference_symbolic(&head_ref, &branch_ref, true, "set-head (radicle)")?; - Ok(head) + Ok(SetHead { old, new }) } fn set_identity_head_to(&self, commit: Oid) -> Result<(), RepositoryError> { diff --git a/radicle/src/test/storage.rs b/radicle/src/test/storage.rs index 44224347..5f7ccadf 100644 --- a/radicle/src/test/storage.rs +++ b/radicle/src/test/storage.rs @@ -288,7 +288,7 @@ impl WriteRepository for MockRepository { todo!() } - fn set_head(&self) -> Result { + fn set_head(&self) -> Result { todo!() }