mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-03 10:24:28 +00:00
cli: on clone, turn local git remote to absolute path
Otherwise a subsequent git fetch would fail.
This commit is contained in:
parent
d530b34568
commit
a45e00179c
2 changed files with 28 additions and 3 deletions
|
@ -4193,6 +4193,23 @@ fn cmd_git_fetch(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn absolute_git_source(cwd: &Path, source: &str) -> String {
|
||||||
|
// Git appears to turn URL-like source to absolute path if local git directory
|
||||||
|
// exits, and fails because '$PWD/https' is unsupported protocol. Since it would
|
||||||
|
// be tedious to copy the exact git (or libgit2) behavior, we simply assume a
|
||||||
|
// source containing ':' is a URL, SSH remote, or absolute path with Windows
|
||||||
|
// drive letter.
|
||||||
|
if !source.contains(':') && Path::new(source).exists() {
|
||||||
|
// It's less likely that cwd isn't utf-8, so just fall back to original source.
|
||||||
|
cwd.join(source)
|
||||||
|
.into_os_string()
|
||||||
|
.into_string()
|
||||||
|
.unwrap_or_else(|_| source.to_owned())
|
||||||
|
} else {
|
||||||
|
source.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn clone_destination_for_source(source: &str) -> Option<&str> {
|
fn clone_destination_for_source(source: &str) -> Option<&str> {
|
||||||
let destination = source.strip_suffix(".git").unwrap_or(source);
|
let destination = source.strip_suffix(".git").unwrap_or(source);
|
||||||
let destination = destination.strip_suffix('/').unwrap_or(destination);
|
let destination = destination.strip_suffix('/').unwrap_or(destination);
|
||||||
|
@ -4217,11 +4234,11 @@ fn cmd_git_clone(
|
||||||
if command.global_args().repository.is_some() {
|
if command.global_args().repository.is_some() {
|
||||||
return Err(user_error("'--repository' cannot be used with 'git clone'"));
|
return Err(user_error("'--repository' cannot be used with 'git clone'"));
|
||||||
}
|
}
|
||||||
let source = &args.source;
|
let source = absolute_git_source(ui.cwd(), &args.source);
|
||||||
let wc_path_str = args
|
let wc_path_str = args
|
||||||
.destination
|
.destination
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.or_else(|| clone_destination_for_source(source))
|
.or_else(|| clone_destination_for_source(&source))
|
||||||
.ok_or_else(|| user_error("No destination specified and wasn't able to guess it"))?;
|
.ok_or_else(|| user_error("No destination specified and wasn't able to guess it"))?;
|
||||||
let wc_path = ui.cwd().join(wc_path_str);
|
let wc_path = ui.cwd().join(wc_path_str);
|
||||||
let wc_path_existed = wc_path.exists();
|
let wc_path_existed = wc_path.exists();
|
||||||
|
@ -4235,7 +4252,7 @@ fn cmd_git_clone(
|
||||||
fs::create_dir(&wc_path).unwrap();
|
fs::create_dir(&wc_path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let clone_result = do_git_clone(ui, command, source, &wc_path);
|
let clone_result = do_git_clone(ui, command, &source, &wc_path);
|
||||||
if clone_result.is_err() {
|
if clone_result.is_err() {
|
||||||
// Canonicalize because fs::remove_dir_all() doesn't seem to like e.g.
|
// Canonicalize because fs::remove_dir_all() doesn't seem to like e.g.
|
||||||
// `/some/path/.`
|
// `/some/path/.`
|
||||||
|
|
|
@ -50,6 +50,8 @@ fn test_git_clone() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
git_repo.set_head("refs/heads/main").unwrap();
|
git_repo.set_head("refs/heads/main").unwrap();
|
||||||
|
|
||||||
|
// Clone with relative source path
|
||||||
let stdout = test_env.jj_cmd_success(test_env.env_root(), &["git", "clone", "source", "clone"]);
|
let stdout = test_env.jj_cmd_success(test_env.env_root(), &["git", "clone", "source", "clone"]);
|
||||||
insta::assert_snapshot!(stdout, @r###"
|
insta::assert_snapshot!(stdout, @r###"
|
||||||
Fetching into new repo in "$TEST_ENV/clone"
|
Fetching into new repo in "$TEST_ENV/clone"
|
||||||
|
@ -58,6 +60,12 @@ fn test_git_clone() {
|
||||||
"###);
|
"###);
|
||||||
assert!(test_env.env_root().join("clone").join("file").exists());
|
assert!(test_env.env_root().join("clone").join("file").exists());
|
||||||
|
|
||||||
|
// Subsequent fetch should just work even if the source path was relative
|
||||||
|
let stdout = test_env.jj_cmd_success(&test_env.env_root().join("clone"), &["git", "fetch"]);
|
||||||
|
insta::assert_snapshot!(stdout, @r###"
|
||||||
|
Nothing changed.
|
||||||
|
"###);
|
||||||
|
|
||||||
// Try cloning into an existing workspace
|
// Try cloning into an existing workspace
|
||||||
let stderr = test_env.jj_cmd_failure(test_env.env_root(), &["git", "clone", "source", "clone"]);
|
let stderr = test_env.jj_cmd_failure(test_env.env_root(), &["git", "clone", "source", "clone"]);
|
||||||
insta::assert_snapshot!(stderr, @r###"
|
insta::assert_snapshot!(stderr, @r###"
|
||||||
|
|
Loading…
Reference in a new issue