From 6346931ce2bd8fd3ec87c2b4e83efd02da401589 Mon Sep 17 00:00:00 2001 From: Alexis Sellier Date: Sun, 23 Apr 2023 16:45:07 +0200 Subject: [PATCH] cli: Add canonical remote to `init` and `checkout` Add a remote that points to the canonical upstream. --- .../rad-checkout-repo-config-linux.md | 3 +- .../rad-checkout-repo-config-macos.md | 3 +- radicle-cli/examples/rad-checkout.md | 2 +- radicle-cli/examples/rad-clone.md | 2 +- radicle-cli/examples/rad-remote.md | 12 +--- radicle-cli/examples/workflow/2-cloning.md | 55 +------------------ .../workflow/5-patching-maintainer.md | 6 ++ .../workflow/6-pulling-contributor.md | 39 +++++++++++++ radicle-cli/src/commands/remote/list.rs | 29 ++++------ radicle-cli/src/git.rs | 15 +++-- radicle-cli/src/project.rs | 2 +- radicle-cli/tests/commands.rs | 8 +++ radicle/src/git.rs | 8 ++- radicle/src/rad.rs | 13 +++-- 14 files changed, 98 insertions(+), 99 deletions(-) mode change 100644 => 120000 radicle-cli/examples/workflow/2-cloning.md create mode 100644 radicle-cli/examples/workflow/6-pulling-contributor.md diff --git a/radicle-cli/examples/rad-checkout-repo-config-linux.md b/radicle-cli/examples/rad-checkout-repo-config-linux.md index ff0917c9..c08e8a0a 100644 --- a/radicle-cli/examples/rad-checkout-repo-config-linux.md +++ b/radicle-cli/examples/rad-checkout-repo-config-linux.md @@ -12,8 +12,9 @@ $ cat .git/config filemode = true logallrefupdates = true [remote "rad"] - url = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi + url = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji fetch = +refs/heads/*:refs/remotes/rad/* + pushurl = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi [branch "master"] remote = rad merge = refs/heads/master diff --git a/radicle-cli/examples/rad-checkout-repo-config-macos.md b/radicle-cli/examples/rad-checkout-repo-config-macos.md index 2c2f8b66..e3f25242 100644 --- a/radicle-cli/examples/rad-checkout-repo-config-macos.md +++ b/radicle-cli/examples/rad-checkout-repo-config-macos.md @@ -14,8 +14,9 @@ $ cat .git/config precomposeunicode = true logallrefupdates = true [remote "rad"] - url = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi + url = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji fetch = +refs/heads/*:refs/remotes/rad/* + pushurl = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi [branch "master"] remote = rad merge = refs/heads/master diff --git a/radicle-cli/examples/rad-checkout.md b/radicle-cli/examples/rad-checkout.md index 2b9b2e4f..e51b4199 100644 --- a/radicle-cli/examples/rad-checkout.md +++ b/radicle-cli/examples/rad-checkout.md @@ -32,7 +32,7 @@ Check the remote configuration: ``` $ git remote --verbose -rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (fetch) +rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji (fetch) rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push) ``` diff --git a/radicle-cli/examples/rad-clone.md b/radicle-cli/examples/rad-clone.md index dc35eba4..9469de70 100644 --- a/radicle-cli/examples/rad-clone.md +++ b/radicle-cli/examples/rad-clone.md @@ -36,7 +36,7 @@ We can also take a look at the remotes: ``` $ git remote -v -rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (fetch) +rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji (fetch) rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (push) z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (fetch) z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push) diff --git a/radicle-cli/examples/rad-remote.md b/radicle-cli/examples/rad-remote.md index 51f5261f..d29b60e4 100644 --- a/radicle-cli/examples/rad-remote.md +++ b/radicle-cli/examples/rad-remote.md @@ -9,8 +9,9 @@ Now, we can see that there is a new remote in the list of remotes: ``` $ rad remote list -❲fetch❳ bob z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk -❲fetch❳ rad z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi +bob z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (fetch) +rad the canonical upstream (fetch) +rad z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push) ``` You can see both `bob` and `rad` as remotes. The `rad` remote is our personal remote of the project. @@ -28,10 +29,3 @@ Now, add another time `bob` but without specify the `name`, so we should be able $ rad remote add did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk ✓ Remote bob added with rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk ``` - -and then we remove again remote just added - -``` -$ rad remote rm bob -✓ Remote `bob` removed -``` diff --git a/radicle-cli/examples/workflow/2-cloning.md b/radicle-cli/examples/workflow/2-cloning.md deleted file mode 100644 index 656e473f..00000000 --- a/radicle-cli/examples/workflow/2-cloning.md +++ /dev/null @@ -1,54 +0,0 @@ -To create a local copy of a repository on the radicle network, we use the -`clone` command, followed by the identifier or *RID* of the repository: - -``` -$ rad clone rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji -✓ Tracking relationship established for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji -✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MknSL…StBU8Vi.. -✓ Forking under z6Mkt67…v4N1tRk.. -✓ Creating checkout in ./heartwood.. -✓ Remote z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi created -✓ Remote-tracking branch z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master created for z6MknSL…StBU8Vi -✓ Repository successfully cloned under [..]/heartwood/ -``` - -We can now have a look at the new working copy that was created from the cloned -repository: - -``` -$ cd heartwood -$ ls -README -$ cat README -Hello World! -``` - -Let's check that the remote tracking branch was setup correctly: - -``` -$ git branch --remotes - rad/master - z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master -``` - -The first branch is ours, and the second points to the repository delegate. -We can also take a look at the remotes: - -``` -$ git remote -v -rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (fetch) -rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (push) -z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (fetch) -z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push) -``` - -Finally, let's inspect the last commit! - -``` -$ git log -n 1 -commit f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 -Author: anonymous -Date: Mon Jan 1 14:39:16 2018 +0000 - - Second commit -``` diff --git a/radicle-cli/examples/workflow/2-cloning.md b/radicle-cli/examples/workflow/2-cloning.md new file mode 120000 index 00000000..8e7337ec --- /dev/null +++ b/radicle-cli/examples/workflow/2-cloning.md @@ -0,0 +1 @@ +../rad-clone.md \ No newline at end of file diff --git a/radicle-cli/examples/workflow/5-patching-maintainer.md b/radicle-cli/examples/workflow/5-patching-maintainer.md index b5bd4a00..062dcd32 100644 --- a/radicle-cli/examples/workflow/5-patching-maintainer.md +++ b/radicle-cli/examples/workflow/5-patching-maintainer.md @@ -86,3 +86,9 @@ $ rad patch --merged │ ✓ merged by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) [ ... ]│ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ``` + +To publish our new state to the network, we simply push: + +``` +$ git push +``` diff --git a/radicle-cli/examples/workflow/6-pulling-contributor.md b/radicle-cli/examples/workflow/6-pulling-contributor.md new file mode 100644 index 00000000..3c653d99 --- /dev/null +++ b/radicle-cli/examples/workflow/6-pulling-contributor.md @@ -0,0 +1,39 @@ +Now that the patch is merged, we can update our master branch to the canonical +master, which includes our patch. + +First, we confirm that our master is behind: +``` +$ git rev-parse master +f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 +``` + +Then, we call `rad sync --fetch` to fetch from the maintainer: +``` +$ rad sync --fetch +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MknSL…StBU8Vi.. +✓ Fetched repository from 1 seed(s) +``` + +Now let's checkout `master` and pull the maintainer's changes: +``` +$ git checkout master +Your branch is up to date with 'rad/master'. +$ git pull --all +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 +``` + +Now our master branch is up to date with the maintainer's master: + +``` +$ git rev-parse master +f6484e0f43e48a8983b9b39bf9bd4cd889f1d520 +$ git diff master..z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master +``` diff --git a/radicle-cli/src/commands/remote/list.rs b/radicle-cli/src/commands/remote/list.rs index 1a94798b..55b44c02 100644 --- a/radicle-cli/src/commands/remote/list.rs +++ b/radicle-cli/src/commands/remote/list.rs @@ -3,33 +3,26 @@ use radicle_term::{Element, Table}; use crate::git; use crate::terminal as term; -#[inline] -fn format_direction(d: &git::Direction) -> String { - match d { - git::Direction::Fetch => "fetch".to_owned(), - git::Direction::Push => "push".to_owned(), - } -} - pub fn run(repo: &git::Repository) -> anyhow::Result<()> { let mut table = Table::default(); let remotes = git::rad_remotes(repo)?; for r in remotes { - for spec in r.refspecs() { - let dir = spec.direction(); - let url = r.url.clone(); - let name = r.name.clone(); - let nid_row = url.namespace.map_or( - term::format::dim("This is the canonical upstream".to_string()), - |namespace| term::format::highlight(namespace.to_string()), + for (dir, url) in [("fetch", Some(r.url)), ("push", r.pushurl)] { + let Some(url) = url else { + continue; + }; + let nid = url.namespace.map_or( + term::format::dim("the canonical upstream".to_string()).italic(), + |namespace| term::format::tertiary(namespace.to_string()), ); table.push([ - term::format::badge_positive(format_direction(&dir)), - term::format::highlight(name.to_owned()), - nid_row, + term::format::bold(r.name.clone()), + nid, + term::format::parens(term::format::secondary(dir.to_owned())), ]); } } table.print(); + Ok(()) } diff --git a/radicle-cli/src/git.rs b/radicle-cli/src/git.rs index e547ab1d..26a94617 100644 --- a/radicle-cli/src/git.rs +++ b/radicle-cli/src/git.rs @@ -76,13 +76,10 @@ pub enum RemoteError { pub struct Remote<'a> { pub(crate) name: String, pub(crate) url: radicle::git::Url, - inner: git2::Remote<'a>, -} + pub(crate) pushurl: Option, -impl Remote<'_> { - pub fn refspecs(&self) -> git2::Refspecs { - self.inner.refspecs() - } + #[allow(dead_code)] + inner: git2::Remote<'a>, } impl<'a> TryFrom> for Remote<'a> { @@ -92,10 +89,16 @@ impl<'a> TryFrom> for Remote<'a> { let url = value.url().map_or(Err(RemoteError::MissingUrl), |url| { Ok(radicle::git::Url::from_str(url)?) })?; + let pushurl = value + .pushurl() + .map(radicle::git::Url::from_str) + .transpose()?; let name = value.name().ok_or(RemoteError::MissingName)?; + Ok(Self { name: name.to_owned(), url, + pushurl, inner: value, }) } diff --git a/radicle-cli/src/project.rs b/radicle-cli/src/project.rs index b0ee1d39..4705f413 100644 --- a/radicle-cli/src/project.rs +++ b/radicle-cli/src/project.rs @@ -22,7 +22,7 @@ impl<'a> SetupRemote<'a> { /// Run the setup for the given peer. pub fn run(&self, node: NodeId) -> anyhow::Result> { let url = radicle::git::Url::from(self.project).with_namespace(node); - let mut remote = radicle::git::configure_remote(self.repo, &node.to_string(), &url)?; + let mut remote = radicle::git::configure_remote(self.repo, &node.to_string(), &url, &url)?; // Fetch the refs into the working copy. if self.fetch { diff --git a/radicle-cli/tests/commands.rs b/radicle-cli/tests/commands.rs index a88c918e..7e58eafd 100644 --- a/radicle-cli/tests/commands.rs +++ b/radicle-cli/tests/commands.rs @@ -769,4 +769,12 @@ fn rad_workflow() { [], ) .unwrap(); + + test( + "examples/workflow/6-pulling-contributor.md", + &working.join("bob").join("heartwood"), + Some(&bob.home), + [], + ) + .unwrap(); } diff --git a/radicle/src/git.rs b/radicle/src/git.rs index a8113d0c..2f9358af 100644 --- a/radicle/src/git.rs +++ b/radicle/src/git.rs @@ -375,10 +375,12 @@ pub fn write_tree<'r>( pub fn configure_remote<'r>( repo: &'r git2::Repository, name: &str, - url: &Url, + fetch: &Url, + push: &Url, ) -> Result, git2::Error> { - let fetch = format!("+refs/heads/*:refs/remotes/{name}/*"); - let remote = repo.remote_with_fetch(name, url.to_string().as_str(), &fetch)?; + let fetchspec = format!("+refs/heads/*:refs/remotes/{name}/*"); + let remote = repo.remote_with_fetch(name, fetch.to_string().as_str(), &fetchspec)?; + repo.remote_set_pushurl(name, Some(push.to_string().as_str()))?; Ok(remote) } diff --git a/radicle/src/rad.rs b/radicle/src/rad.rs index ac2e3a11..e27b9ab5 100644 --- a/radicle/src/rad.rs +++ b/radicle/src/rad.rs @@ -70,9 +70,9 @@ pub fn init( })?; let doc = identity::Doc::initial(proj, delegate).verified()?; let (project, _) = Repository::init(&doc, pk, storage, signer)?; - let url = git::Url::from(project.id).with_namespace(*pk); + let url = git::Url::from(project.id); - git::configure_remote(repo, &REMOTE_NAME, &url)?; + git::configure_remote(repo, &REMOTE_NAME, &url, &url.clone().with_namespace(*pk))?; git::push( repo, &REMOTE_NAME, @@ -221,10 +221,15 @@ pub fn checkout, S: storage::ReadStorage>( opts.no_reinit(true).description(project.description()); let repo = git2::Repository::init_opts(path.as_ref(), &opts)?; - let url = git::Url::from(proj).with_namespace(*remote); + let url = git::Url::from(proj); // Configure and fetch all refs from remote. - git::configure_remote(&repo, &REMOTE_NAME, &url)?; + git::configure_remote( + &repo, + &REMOTE_NAME, + &url, + &url.clone().with_namespace(*remote), + )?; git::fetch(&repo, &REMOTE_NAME).map_err(CheckoutError::Fetch)?; {