diff --git a/CHANGELOG.md b/CHANGELOG.md index 857eeaf711..79d1034f3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -163,6 +163,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). now materialized in a way that can be parsed correctly. [#3968](https://github.com/jj-vcs/jj/issues/3968) +* Bookmark and remote names written by `jj git clone` to + `revset-aliases.'trunk()'` are now escaped if necessary. + [#5359](https://github.com/jj-vcs/jj/issues/5359) + ## [0.25.0] - 2025-01-01 ### Release highlights diff --git a/cli/src/commands/git/mod.rs b/cli/src/commands/git/mod.rs index 3772e3ebbc..844e363417 100644 --- a/cli/src/commands/git/mod.rs +++ b/cli/src/commands/git/mod.rs @@ -28,6 +28,7 @@ use jj_lib::config::ConfigFile; use jj_lib::config::ConfigSource; use jj_lib::git; use jj_lib::git::UnexpectedGitBackendError; +use jj_lib::revset; use jj_lib::store::Store; use self::clone::cmd_git_clone; @@ -123,6 +124,8 @@ fn write_repository_level_trunk_alias( branch: &str, ) -> Result<(), CommandError> { let mut file = ConfigFile::load_or_empty(ConfigSource::Repo, repo_path.join("config.toml"))?; + let branch = revset::format_symbol(branch); + let remote = revset::format_symbol(remote); file.set_value(["revset-aliases", "trunk()"], format!("{branch}@{remote}")) .expect("initial repo config shouldn't have invalid values"); file.save()?; diff --git a/cli/tests/test_git_clone.rs b/cli/tests/test_git_clone.rs index 030a4cf39b..da191cea8e 100644 --- a/cli/tests/test_git_clone.rs +++ b/cli/tests/test_git_clone.rs @@ -601,6 +601,49 @@ fn test_git_clone_remote_default_bookmark(subprocess: bool) { } } +// A branch with a strange name should get quoted in the config. Windows doesn't +// like the strange name, so we don't run the test there. +#[cfg(unix)] +#[test_case(false; "use git2 for remote calls")] +#[test_case(true; "spawn a git subprocess for remote calls")] +fn test_git_clone_remote_default_bookmark_with_escape(subprocess: bool) { + let test_env = TestEnvironment::default(); + if subprocess { + test_env.add_config("git.subprocess = 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); + // Rename the main branch to something that needs to be escaped + git_repo + .find_reference("refs/heads/main") + .unwrap() + .rename("refs/heads/\"", false, "") + .unwrap(); + + let (_stdout, stderr) = + test_env.jj_cmd_ok(test_env.env_root(), &["git", "clone", "source", "clone"]); + insta::allow_duplicates! { + insta::assert_snapshot!(stderr, @r#" + Fetching into new repo in "$TEST_ENV/clone" + bookmark: "@origin [new] untracked + Setting the revset alias "trunk()" to ""\""@origin" + Working copy now at: sqpuoqvx cad212e1 (empty) (no description set) + Parent commit : mzyxwzks 9f01a0e0 " | message + Added 1 files, modified 0 files, removed 0 files + "#); + } + + // "trunk()" alias should be escaped and quoted + let stdout = test_env.jj_cmd_success( + &test_env.env_root().join("clone"), + &["config", "list", "--repo", "revset-aliases.'trunk()'"], + ); + insta::allow_duplicates! { + insta::assert_snapshot!(stdout, @r#"revset-aliases.'trunk()' = '"\""@origin'"#); + } +} + #[test_case(false; "use git2 for remote calls")] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_clone_ignore_working_copy(subprocess: bool) {