From 9f164192024ccdafa4ed0264e58b932ba8626924 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Sep 2024 21:47:49 +0200 Subject: [PATCH] git clone: Add depth argument --- CHANGELOG.md | 3 +++ cli/src/commands/git/clone.rs | 7 +++++++ cli/src/commands/git/fetch.rs | 1 + cli/tests/cli-reference@.md.snap | 1 + cli/tests/test_git_clone.rs | 20 ++++++++++++++++++++ lib/src/git.rs | 5 +++++ lib/tests/test_git.rs | 10 ++++++++++ 7 files changed, 47 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0d2cee863..2ea8aa546c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -136,6 +136,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). * Initial support for shallow git repositories has been implemented. However deepening the history of a shallow repository is not yet supported. +* `jj git clone` now accepts a `--depth ` option, which + allows to clone the repository with a given depth. + ### Fixed bugs * Update working copy before reporting changes. This prevents errors during reporting diff --git a/cli/src/commands/git/clone.rs b/cli/src/commands/git/clone.rs index 4c3e1cc135..7761c7ed66 100644 --- a/cli/src/commands/git/clone.rs +++ b/cli/src/commands/git/clone.rs @@ -15,6 +15,7 @@ use std::fs; use std::io; use std::io::Write; +use std::num::NonZeroU32; use std::path::Path; use std::path::PathBuf; @@ -60,6 +61,9 @@ pub struct GitCloneArgs { /// Whether or not to colocate the Jujutsu repo with the git repo #[arg(long)] colocate: bool, + /// Create a shallow clone of the given depth + #[arg(long)] + depth: Option, } fn absolute_git_source(cwd: &Path, source: &str) -> String { @@ -132,6 +136,7 @@ pub fn cmd_git_clone( ui, command, args.colocate, + args.depth, remote_name, &source, &canonical_wc_path, @@ -195,6 +200,7 @@ fn do_git_clone( ui: &mut Ui, command: &CommandHelper, colocate: bool, + depth: Option, remote_name: &str, source: &str, wc_path: &Path, @@ -223,6 +229,7 @@ fn do_git_clone( &[StringPattern::everything()], cb, &command.settings().git_settings(), + depth, ) }) .map_err(|err| match err { diff --git a/cli/src/commands/git/fetch.rs b/cli/src/commands/git/fetch.rs index 7b667b8287..7f5c7389ce 100644 --- a/cli/src/commands/git/fetch.rs +++ b/cli/src/commands/git/fetch.rs @@ -78,6 +78,7 @@ pub fn cmd_git_fetch( &args.branch, cb, &command.settings().git_settings(), + None, ) }) .map_err(|err| match err { diff --git a/cli/tests/cli-reference@.md.snap b/cli/tests/cli-reference@.md.snap index 974b30c9d3..a3c6526ffa 100644 --- a/cli/tests/cli-reference@.md.snap +++ b/cli/tests/cli-reference@.md.snap @@ -984,6 +984,7 @@ The Git repo will be a bare git repo stored inside the `.jj/` directory. Default value: `origin` * `--colocate` — Whether or not to colocate the Jujutsu repo with the git repo +* `--depth ` — Create a shallow clone of the given depth diff --git a/cli/tests/test_git_clone.rs b/cli/tests/test_git_clone.rs index 0ce982e47b..dd5fefb6cf 100644 --- a/cli/tests/test_git_clone.rs +++ b/cli/tests/test_git_clone.rs @@ -557,6 +557,26 @@ fn test_git_clone_trunk_deleted() { "#); } +#[test] +fn test_git_clone_with_depth() { + let test_env = TestEnvironment::default(); + test_env.add_config("git.auto-local-branch = true"); + let git_repo_path = test_env.env_root().join("source"); + let git_repo = git2::Repository::init(git_repo_path).unwrap(); + set_up_non_empty_git_repo(&git_repo); + + // local transport does not support shallow clones so we just test that the + // depth arg is passed on here + let stderr = test_env.jj_cmd_failure( + test_env.env_root(), + &["git", "clone", "--depth", "1", "source", "clone"], + ); + insta::assert_snapshot!(stderr, @r#" + Fetching into new repo in "$TEST_ENV/clone" + Error: shallow fetch is not supported by the local transport; class=Net (12) + "#); +} + fn get_bookmark_output(test_env: &TestEnvironment, repo_path: &Path) -> String { test_env.jj_cmd_success(repo_path, &["bookmark", "list", "--all-remotes"]) } diff --git a/lib/src/git.rs b/lib/src/git.rs index 1517456a5d..b59a3c0436 100644 --- a/lib/src/git.rs +++ b/lib/src/git.rs @@ -21,6 +21,7 @@ use std::collections::HashSet; use std::default::Default; use std::fmt; use std::io::Read; +use std::num::NonZeroU32; use std::path::PathBuf; use std::str; @@ -1244,6 +1245,7 @@ pub fn fetch( branch_names: &[StringPattern], callbacks: RemoteCallbacks<'_>, git_settings: &GitSettings, + depth: Option, ) -> Result { // Perform a `git fetch` on the local git repo, updating the remote-tracking // branches in the git repo. @@ -1260,6 +1262,9 @@ pub fn fetch( fetch_options.proxy_options(proxy_options); let callbacks = callbacks.into_git(); fetch_options.remote_callbacks(callbacks); + if let Some(depth) = depth { + fetch_options.depth(depth.get().try_into().unwrap_or(i32::MAX)); + } // At this point, we are only updating Git's remote tracking branches, not the // local branches. let refspecs: Vec<_> = branch_names diff --git a/lib/tests/test_git.rs b/lib/tests/test_git.rs index 74b8e15e34..4d51d773b2 100644 --- a/lib/tests/test_git.rs +++ b/lib/tests/test_git.rs @@ -2270,6 +2270,7 @@ fn test_fetch_empty_repo() { &[StringPattern::everything()], git::RemoteCallbacks::default(), &git_settings, + None, ) .unwrap(); // No default bookmark and no refs @@ -2296,6 +2297,7 @@ fn test_fetch_initial_commit() { &[StringPattern::everything()], git::RemoteCallbacks::default(), &git_settings, + None, ) .unwrap(); // No default bookmark because the origin repo's HEAD wasn't set @@ -2346,6 +2348,7 @@ fn test_fetch_success() { &[StringPattern::everything()], git::RemoteCallbacks::default(), &git_settings, + None, ) .unwrap(); test_data.repo = tx.commit("test"); @@ -2369,6 +2372,7 @@ fn test_fetch_success() { &[StringPattern::everything()], git::RemoteCallbacks::default(), &git_settings, + None, ) .unwrap(); // The default bookmark is "main" @@ -2426,6 +2430,7 @@ fn test_fetch_prune_deleted_ref() { &[StringPattern::everything()], git::RemoteCallbacks::default(), &git_settings, + None, ) .unwrap(); // Test the setup @@ -2449,6 +2454,7 @@ fn test_fetch_prune_deleted_ref() { &[StringPattern::everything()], git::RemoteCallbacks::default(), &git_settings, + None, ) .unwrap(); assert_eq!(stats.import_stats.abandoned_commits, vec![jj_id(&commit)]); @@ -2476,6 +2482,7 @@ fn test_fetch_no_default_branch() { &[StringPattern::everything()], git::RemoteCallbacks::default(), &git_settings, + None, ) .unwrap(); @@ -2499,6 +2506,7 @@ fn test_fetch_no_default_branch() { &[StringPattern::everything()], git::RemoteCallbacks::default(), &git_settings, + None, ) .unwrap(); // There is no default bookmark @@ -2520,6 +2528,7 @@ fn test_fetch_empty_refspecs() { &[], git::RemoteCallbacks::default(), &git_settings, + None, ) .unwrap(); assert!(tx @@ -2546,6 +2555,7 @@ fn test_fetch_no_such_remote() { &[StringPattern::everything()], git::RemoteCallbacks::default(), &git_settings, + None, ); assert!(matches!(result, Err(GitFetchError::NoSuchRemote(_)))); }