cli: Add canonical remote to `init` and `checkout`

Add a remote that points to the canonical upstream.
This commit is contained in:
Alexis Sellier 2023-04-23 16:45:07 +02:00
parent d6cebf613f
commit 6346931ce2
No known key found for this signature in database
14 changed files with 98 additions and 99 deletions

View File

@ -12,8 +12,9 @@ $ cat .git/config
filemode = true filemode = true
logallrefupdates = true logallrefupdates = true
[remote "rad"] [remote "rad"]
url = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi url = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
fetch = +refs/heads/*:refs/remotes/rad/* fetch = +refs/heads/*:refs/remotes/rad/*
pushurl = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
[branch "master"] [branch "master"]
remote = rad remote = rad
merge = refs/heads/master merge = refs/heads/master

View File

@ -14,8 +14,9 @@ $ cat .git/config
precomposeunicode = true precomposeunicode = true
logallrefupdates = true logallrefupdates = true
[remote "rad"] [remote "rad"]
url = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi url = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
fetch = +refs/heads/*:refs/remotes/rad/* fetch = +refs/heads/*:refs/remotes/rad/*
pushurl = rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
[branch "master"] [branch "master"]
remote = rad remote = rad
merge = refs/heads/master merge = refs/heads/master

View File

@ -32,7 +32,7 @@ Check the remote configuration:
``` ```
$ git remote --verbose $ git remote --verbose
rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (fetch) rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji (fetch)
rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push) rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push)
``` ```

View File

@ -36,7 +36,7 @@ We can also take a look at the remotes:
``` ```
$ git remote -v $ git remote -v
rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (fetch) rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji (fetch)
rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (push) rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (push)
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (fetch) z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (fetch)
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push) z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push)

View File

@ -9,8 +9,9 @@ Now, we can see that there is a new remote in the list of remotes:
``` ```
$ rad remote list $ rad remote list
fetch bob z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk bob z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (fetch)
fetch rad z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi 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. 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 $ rad remote add did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
✓ Remote bob added with rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk ✓ Remote bob added with rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
``` ```
and then we remove again remote just added
```
$ rad remote rm bob
✓ Remote `bob` removed
```

View File

@ -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 <anonymous@radicle.xyz>
Date: Mon Jan 1 14:39:16 2018 +0000
Second commit
```

View File

@ -0,0 +1 @@
../rad-clone.md

View File

@ -86,3 +86,9 @@ $ rad patch --merged
│ ✓ merged by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) [ ... ]│ │ ✓ merged by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) [ ... ]│
╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯
``` ```
To publish our new state to the network, we simply push:
```
$ git push
```

View File

@ -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
```

View File

@ -3,33 +3,26 @@ use radicle_term::{Element, Table};
use crate::git; use crate::git;
use crate::terminal as term; 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<()> { pub fn run(repo: &git::Repository) -> anyhow::Result<()> {
let mut table = Table::default(); let mut table = Table::default();
let remotes = git::rad_remotes(repo)?; let remotes = git::rad_remotes(repo)?;
for r in remotes { for r in remotes {
for spec in r.refspecs() { for (dir, url) in [("fetch", Some(r.url)), ("push", r.pushurl)] {
let dir = spec.direction(); let Some(url) = url else {
let url = r.url.clone(); continue;
let name = r.name.clone(); };
let nid_row = url.namespace.map_or( let nid = url.namespace.map_or(
term::format::dim("This is the canonical upstream".to_string()), term::format::dim("the canonical upstream".to_string()).italic(),
|namespace| term::format::highlight(namespace.to_string()), |namespace| term::format::tertiary(namespace.to_string()),
); );
table.push([ table.push([
term::format::badge_positive(format_direction(&dir)), term::format::bold(r.name.clone()),
term::format::highlight(name.to_owned()), nid,
nid_row, term::format::parens(term::format::secondary(dir.to_owned())),
]); ]);
} }
} }
table.print(); table.print();
Ok(()) Ok(())
} }

View File

@ -76,13 +76,10 @@ pub enum RemoteError {
pub struct Remote<'a> { pub struct Remote<'a> {
pub(crate) name: String, pub(crate) name: String,
pub(crate) url: radicle::git::Url, pub(crate) url: radicle::git::Url,
inner: git2::Remote<'a>, pub(crate) pushurl: Option<radicle::git::Url>,
}
impl Remote<'_> { #[allow(dead_code)]
pub fn refspecs(&self) -> git2::Refspecs { inner: git2::Remote<'a>,
self.inner.refspecs()
}
} }
impl<'a> TryFrom<git2::Remote<'a>> for Remote<'a> { impl<'a> TryFrom<git2::Remote<'a>> for Remote<'a> {
@ -92,10 +89,16 @@ impl<'a> TryFrom<git2::Remote<'a>> for Remote<'a> {
let url = value.url().map_or(Err(RemoteError::MissingUrl), |url| { let url = value.url().map_or(Err(RemoteError::MissingUrl), |url| {
Ok(radicle::git::Url::from_str(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)?; let name = value.name().ok_or(RemoteError::MissingName)?;
Ok(Self { Ok(Self {
name: name.to_owned(), name: name.to_owned(),
url, url,
pushurl,
inner: value, inner: value,
}) })
} }

View File

@ -22,7 +22,7 @@ impl<'a> SetupRemote<'a> {
/// Run the setup for the given peer. /// Run the setup for the given peer.
pub fn run(&self, node: NodeId) -> anyhow::Result<Option<(Remote, RefString)>> { pub fn run(&self, node: NodeId) -> anyhow::Result<Option<(Remote, RefString)>> {
let url = radicle::git::Url::from(self.project).with_namespace(node); 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. // Fetch the refs into the working copy.
if self.fetch { if self.fetch {

View File

@ -769,4 +769,12 @@ fn rad_workflow() {
[], [],
) )
.unwrap(); .unwrap();
test(
"examples/workflow/6-pulling-contributor.md",
&working.join("bob").join("heartwood"),
Some(&bob.home),
[],
)
.unwrap();
} }

View File

@ -375,10 +375,12 @@ pub fn write_tree<'r>(
pub fn configure_remote<'r>( pub fn configure_remote<'r>(
repo: &'r git2::Repository, repo: &'r git2::Repository,
name: &str, name: &str,
url: &Url, fetch: &Url,
push: &Url,
) -> Result<git2::Remote<'r>, git2::Error> { ) -> Result<git2::Remote<'r>, git2::Error> {
let fetch = format!("+refs/heads/*:refs/remotes/{name}/*"); let fetchspec = format!("+refs/heads/*:refs/remotes/{name}/*");
let remote = repo.remote_with_fetch(name, url.to_string().as_str(), &fetch)?; 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) Ok(remote)
} }

View File

@ -70,9 +70,9 @@ pub fn init<G: Signer, S: WriteStorage>(
})?; })?;
let doc = identity::Doc::initial(proj, delegate).verified()?; let doc = identity::Doc::initial(proj, delegate).verified()?;
let (project, _) = Repository::init(&doc, pk, storage, signer)?; 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( git::push(
repo, repo,
&REMOTE_NAME, &REMOTE_NAME,
@ -221,10 +221,15 @@ pub fn checkout<P: AsRef<Path>, S: storage::ReadStorage>(
opts.no_reinit(true).description(project.description()); opts.no_reinit(true).description(project.description());
let repo = git2::Repository::init_opts(path.as_ref(), &opts)?; 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. // 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)?; git::fetch(&repo, &REMOTE_NAME).map_err(CheckoutError::Fetch)?;
{ {