diff --git a/CHANGELOG.md b/CHANGELOG.md index b806514e..d09fc5fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## New Features +- `rad clone` now supports the flag `--bare` which works analoguously to + `git clone --bare`. + +## Fixed Bugs + +## 1.4.0 + +## Release Highlights + +## Deprecations + +## New Features + - `rad cob log` now supports the arguments `--from` and `--to` which can be used to range over particular operations on a COB. diff --git a/crates/radicle-cli/examples/rad-clone-bare.md b/crates/radicle-cli/examples/rad-clone-bare.md new file mode 100644 index 00000000..95c651b3 --- /dev/null +++ b/crates/radicle-cli/examples/rad-clone-bare.md @@ -0,0 +1,81 @@ +To create a local bare 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 --scope followed --bare +✓ Seeding policy updated for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji with scope 'followed' +Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from the network, found [..] potential seed(s). +✓ Target met: [..] seed(s) +✓ Creating checkout in ./heartwood.. +✓ Remote alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi added +✓ Remote-tracking branch alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master created for z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi +✓ Repository successfully cloned under [..]/heartwood/ +╭────────────────────────────────────╮ +│ heartwood │ +│ Radicle Heartwood Protocol & Stack │ +│ 0 issues · 0 patches │ +╰────────────────────────────────────╯ +Run `cd ./heartwood` to go to the repository directory. +``` + +We can now have a look at the new directory that was created from the cloned +repository: + +``` +$ cd heartwood +$ ls +FETCH_HEAD +HEAD +config +description +hooks +info +objects +refs +``` + +As expected, some `git` commands fail: +``` (stderr) (fail) +$ git status +fatal: this operation must be run in a work tree +``` + +Let's check that the remote tracking branch was setup correctly: + +``` +$ git branch --remotes + alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master + rad/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 +alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (fetch) +alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (push) +rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji (fetch) +rad rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (push) +``` + +Let's check the last commit! + +``` +$ git log -n 1 +commit f2de534b5e81d7c6e2dcaf58c3dd91573c0a0354 +Author: anonymous +Date: Mon Jan 1 14:39:16 2018 +0000 + + Second commit +``` + +Cloned repositories show up in `rad ls`: +``` +$ rad ls --seeded +╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Name RID Visibility Head Description │ +├───────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ heartwood rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji public f2de534 Radicle Heartwood Protocol & Stack │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +``` diff --git a/crates/radicle-cli/src/commands/clone.rs b/crates/radicle-cli/src/commands/clone.rs index 142ea0a8..9c3beac5 100644 --- a/crates/radicle-cli/src/commands/clone.rs +++ b/crates/radicle-cli/src/commands/clone.rs @@ -46,6 +46,7 @@ Usage Options + --bare Make a bare repository --scope Follow scope: `followed` or `all` (default: all) -s, --seed Clone from this seed (may be specified multiple times) --timeout Timeout for fetching repository (default: 9) @@ -64,6 +65,7 @@ pub struct Options { scope: Scope, /// Sync settings. sync: SyncSettings, + bare: bool, } impl Args for Options { @@ -75,6 +77,7 @@ impl Args for Options { let mut scope = Scope::All; let mut sync = SyncSettings::default(); let mut directory = None; + let mut bare = false; while let Some(arg) = parser.next()? { match arg { @@ -99,6 +102,9 @@ impl Args for Options { // We keep this flag here for consistency though it doesn't have any effect, // since the command is fully non-interactive. } + Long("bare") => { + bare = true; + } Long("help") | Short('h') => { return Err(Error::Help.into()); } @@ -125,6 +131,7 @@ impl Args for Options { directory, scope, sync, + bare, }, vec![], )) @@ -153,6 +160,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { options.sync.with_profile(&profile), &mut node, &profile, + options.bare, )? .print_or_success() .ok_or_else(|| anyhow::anyhow!("failed to clone {}", options.id))?; @@ -163,7 +171,11 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { .filter(|id| id != profile.id()) .collect::>(); let default_branch = proj.default_branch().clone(); - let path = working.workdir().unwrap(); // SAFETY: The working copy is not bare. + let path = if !options.bare { + working.workdir().unwrap() + } else { + working.path() + }; // Configure repository and setup tracking for repository delegates. radicle::git::configure_repository(&working)?; @@ -229,6 +241,7 @@ struct Checkout { repository: storage::git::Repository, doc: Doc, project: Project, + bare: bool, } impl Checkout { @@ -236,6 +249,7 @@ impl Checkout { repository: storage::git::Repository, profile: &Profile, directory: Option, + bare: bool, ) -> Result { let rid = repository.rid(); let doc = repository @@ -257,6 +271,7 @@ impl Checkout { repository, doc: doc.doc, project: proj, + bare, }) } @@ -274,7 +289,7 @@ impl Checkout { "Creating checkout in ./{}..", term::format::tertiary(destination.display()) )); - match rad::checkout(self.id, &self.remote, self.path, storage, false) { + match rad::checkout(self.id, &self.remote, self.path, storage, self.bare) { Err(err) => { spinner.message(format!( "Failed to checkout in ./{}", @@ -303,6 +318,7 @@ fn clone( settings: SyncSettings, node: &mut Node, profile: &Profile, + bare: bool, ) -> Result { // Seed repository. if node.seed(id, scope)? { @@ -322,7 +338,7 @@ fn clone( node::sync::FetcherResult::TargetReached(_) => { profile.storage.repository(id).map_or_else( |err| Ok(CloneResult::RepositoryMissing { rid: id, err }), - |repository| Ok(perform_checkout(repository, profile, directory)?), + |repository| Ok(perform_checkout(repository, profile, directory, bare)?), ) } node::sync::FetcherResult::TargetError(failure) => { @@ -330,7 +346,7 @@ fn clone( } } } - Ok(repository) => Ok(perform_checkout(repository, profile, directory)?), + Ok(repository) => Ok(perform_checkout(repository, profile, directory, bare)?), } } @@ -338,8 +354,9 @@ fn perform_checkout( repository: storage::git::Repository, profile: &Profile, directory: Option, + bare: bool, ) -> Result { - Checkout::new(repository, profile, directory).map_or_else( + Checkout::new(repository, profile, directory, bare).map_or_else( |failure| Ok(CloneResult::Failure(failure)), |checkout| checkout.run(&profile.storage), ) diff --git a/crates/radicle-cli/tests/commands.rs b/crates/radicle-cli/tests/commands.rs index c9ae4ef8..c72c37f9 100644 --- a/crates/radicle-cli/tests/commands.rs +++ b/crates/radicle-cli/tests/commands.rs @@ -1155,6 +1155,26 @@ fn rad_clone() { test("examples/rad-clone.md", working, Some(&bob.home), []).unwrap(); } +#[test] +fn rad_clone_bare() { + let mut environment = Environment::new(); + let mut alice = environment.node("alice"); + let bob = environment.node("bob"); + let working = environment.tempdir().join("working"); + + // Setup a test project. + let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack"); + + let mut alice = alice.spawn(); + let mut bob = bob.spawn(); + // Prevent Alice from fetching Bob's fork, as we're not testing that and it may cause errors. + alice.handle.seed(acme, Scope::Followed).unwrap(); + + bob.connect(&alice).converge([&alice]); + + test("examples/rad-clone-bare.md", working, Some(&bob.home), []).unwrap(); +} + #[test] fn rad_clone_directory() { let mut environment = Environment::new();