// Copyright 2023 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. use std::io::Write as _; use indoc::indoc;use testutils::TestResult;use testutils::git; use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir;use crate::common::create_commit; fn add_commit_to_branch(git_repo: &gix::Repository, branch: &str, message: &str) -> gix::ObjectId { // Get current commit ID of the branch if it exists let parents = git_repo .find_reference(&format!("refs/heads/{branch}")) .ok() .and_then(|mut r| r.peel_to_commit().ok()) .map(|c| vec![c.id().detach()]) .unwrap_or_default(); git::add_commit( git_repo, &format!("refs/heads/{branch}"), branch, // filename branch.as_bytes(), // content message, &parents, ) .commit_id} /// Creates a remote Git repo containing a bookmark with the same namefn init_git_remote(test_env: &TestEnvironment, remote: &str) -> gix::Repository { let git_repo_path = test_env.env_root().join(remote); let git_repo = git::init(git_repo_path); add_commit_to_branch(&git_repo, remote, "message"); git_repo} /// Add a remote containing a bookmark with the same namefn add_git_remote( test_env: &TestEnvironment, work_dir: &TestWorkDir, remote: &str,) -> gix::Repository { let repo = init_git_remote(test_env, remote); work_dir .run_jj(["git", "remote", "add", remote, &format!("../{remote}")]) .success(); repo} #[must_use]fn get_bookmark_output(work_dir: &TestWorkDir) -> CommandOutput { // --quiet to suppress deleted bookmarks hint work_dir.run_jj(["bookmark", "list", "--all-remotes", "--quiet"])} #[must_use]fn get_tag_output(work_dir: &TestWorkDir) -> CommandOutput { work_dir.run_jj(["tag", "list", "--all-remotes"])} #[must_use]fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput { let template = indoc! {r#" separate(" ", commit_id.short(), '"' ++ description.first_line() ++ '"', bookmarks, tags, ) ++ "\n" "#}; work_dir.run_jj(["log", "-T", template, "-r", "all()"])} fn clone_git_remote_into( test_env: &TestEnvironment, upstream: &str, fork: &str,) -> gix::Repository { let upstream_path = test_env.env_root().join(upstream); let fork_path = test_env.env_root().join(fork); let fork_repo = git::clone(&fork_path, upstream_path.to_str().unwrap(), Some(upstream)); // create local branch mirroring the upstream let upstream_head = fork_repo .find_reference(&format!("refs/remotes/{upstream}/{upstream}")) .unwrap() .peel_to_id() .unwrap() .detach(); fork_repo .reference( format!("refs/heads/{upstream}"), upstream_head, gix::refs::transaction::PreviousValue::MustNotExist, "create tracking head", ) .unwrap(); fork_repo} #[test]fn test_git_fetch_with_default_config() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "origin"); work_dir.run_jj(["git", "fetch"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" origin@origin: qmyrypzk ab8b299e message [EOF] ");} #[test]fn test_git_fetch_default_remote() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.origin.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "origin"); work_dir.run_jj(["git", "fetch"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" origin: qmyrypzk ab8b299e message @origin: qmyrypzk ab8b299e message [EOF] ");} #[test]fn test_git_fetch_single_remote() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); let output = work_dir.run_jj(["git", "fetch"]); insta::assert_snapshot!(output, @" ------- stderr ------- Hint: Fetching from the only existing remote: rem1 bookmark: rem1@rem1 [new] tracked [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] ");} #[test]fn test_git_fetch_single_remote_all_remotes_flag() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); work_dir.run_jj(["git", "fetch", "--all-remotes"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] ");} #[test]fn test_git_fetch_single_remote_from_arg() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); work_dir .run_jj(["git", "fetch", "--remote", "rem1"]) .success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] ");} #[test]fn test_git_fetch_single_remote_from_config() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); test_env.add_config(r#"git.fetch = "rem1""#); work_dir.run_jj(["git", "fetch"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] ");} #[test]fn test_git_fetch_multiple_remotes() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); work_dir .run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]) .success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] ");} #[test]fn test_git_fetch_with_ignored_refspecs() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let source_repo = init_git_remote(&test_env, "origin"); for branch in [ "main", "foo", "foobar", "foobaz", "bar", "sub/yes", "sub/no", ] { add_commit_to_branch(&source_repo, branch, branch); } let work_dir = test_env.work_dir("repo"); std::fs::OpenOptions::new() .append(true) .open(work_dir.root().join(".jj/repo/store/git/config")) .expect("failed to open config file") .write_all( br#" [remote "origin"] url = ../origin/.git fetch = +refs/heads/main:refs/remotes/origin/main fetch = +refs/heads/sub/*:refs/remotes/origin/sub/* fetch = +refs/heads/foo*:refs/remotes/origin/baz* fetch = +refs/heads/bar*:refs/tags/bar* fetch = refs/heads/bar fetch = ^refs/heads/sub/no "#, ) .expect("failed to update config file"); // Should fetch "main" and "sub/yes" by default let output = work_dir.run_jj(["git", "fetch"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: Ignored refspec `refs/heads/bar` from `origin`: fetch-only refspecs are not supported Warning: Ignored refspec `+refs/heads/bar*:refs/tags/bar*` from `origin`: only refs/remotes/ is supported for fetch destinations Warning: Ignored refspec `+refs/heads/foo*:refs/remotes/origin/baz*` from `origin`: renaming is not supported bookmark: main@origin [new] untracked bookmark: sub/yes@origin [new] untracked [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" main@origin: wlltxvop a437242b main sub/yes@origin: xwxtqxvy 6b64b005 sub/yes [EOF] "); // Can fetch ignored "sub/no" explicitly let output = work_dir.run_jj(["git", "fetch", "--branch=sub/no"]); insta::assert_snapshot!(output, @" ------- stderr ------- bookmark: sub/no@origin [new] untracked [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" main@origin: wlltxvop a437242b main sub/no@origin: tknwmolt f7d8b914 sub/no sub/yes@origin: xwxtqxvy 6b64b005 sub/yes [EOF] "); // Forget "sub/no" without exporting the change to Git work_dir .run_jj(["bookmark", "forget", "--include-remotes", "sub/no"]) .success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" main@origin: wlltxvop a437242b main sub/yes@origin: xwxtqxvy 6b64b005 sub/yes [EOF] "); // Should not import "sub/no" because it is ignored by default let output = work_dir.run_jj(["git", "fetch"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: Ignored refspec `refs/heads/bar` from `origin`: fetch-only refspecs are not supported Warning: Ignored refspec `+refs/heads/bar*:refs/tags/bar*` from `origin`: only refs/remotes/ is supported for fetch destinations Warning: Ignored refspec `+refs/heads/foo*:refs/remotes/origin/baz*` from `origin`: renaming is not supported Nothing changed. [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" main@origin: wlltxvop a437242b main sub/yes@origin: xwxtqxvy 6b64b005 sub/yes [EOF] ");} #[test]fn test_git_fetch_with_glob() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); let output = work_dir.run_jj(["git", "fetch", "--remote", "*"]); insta::assert_snapshot!(output, @" ------- stderr ------- bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] ");} #[test]fn test_git_fetch_with_glob_and_exact_match() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); add_git_remote(&test_env, &work_dir, "upstream1"); add_git_remote(&test_env, &work_dir, "upstream2"); add_git_remote(&test_env, &work_dir, "origin"); let output = work_dir.run_jj(["git", "fetch", "--remote=rem*", "--remote=origin"]); insta::assert_snapshot!(output, @" ------- stderr ------- bookmark: origin@origin [new] untracked bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] ");} #[test]fn test_git_fetch_with_glob_from_config() { let test_env = TestEnvironment::default(); test_env.add_config(r#"git.fetch = "rem*""#); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); add_git_remote(&test_env, &work_dir, "upstream"); let output = work_dir.run_jj(["git", "fetch"]); insta::assert_snapshot!(output, @" ------- stderr ------- bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] ");} #[test]fn test_git_fetch_with_glob_with_no_matching_remotes() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "upstream"); let output = work_dir.run_jj(["git", "fetch", "--remote=rem*"]); insta::assert_snapshot!(output, @" ------- stderr ------- Error: No git remotes to fetch from [EOF] [exit status: 1] "); // No remote should have been fetched as part of the failing transaction insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");} #[test]fn test_git_fetch_all_remotes() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); // add empty [remote "rem3"] section to .git/config, which should be ignored work_dir .run_jj(["git", "remote", "add", "rem3", "../unknown"]) .success(); work_dir .run_jj(["git", "remote", "remove", "rem3"]) .success(); work_dir.run_jj(["git", "fetch", "--all-remotes"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] ");} #[test]fn test_git_fetch_multiple_remotes_from_config() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); test_env.add_config(r#"git.fetch = ["rem1", "rem2"]"#); work_dir.run_jj(["git", "fetch"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] ");} #[test]fn test_git_fetch_no_matching_remote() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: No matching remotes for names: rem1 Error: No git remotes to fetch from [EOF] [exit status: 1] "); let output = work_dir.run_jj(["git", "fetch", "--remote=rem1", "--remote=rem2"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: No matching remotes for names: rem1, rem2 Error: No git remotes to fetch from [EOF] [exit status: 1] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");} #[test]fn test_git_fetch_nonexistent_remote() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: No matching remotes for names: rem2 bookmark: rem1@rem1 [new] untracked [EOF] ");Lines 1–500 of 2303. Load more
// Copyright 2023 The Jujutsu Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::io::Write as _; use indoc::indoc; use testutils::TestResult; use testutils::git; use crate::common::CommandOutput; use crate::common::TestEnvironment; use crate::common::TestWorkDir; use crate::common::create_commit; fn add_commit_to_branch(git_repo: &gix::Repository, branch: &str, message: &str) -> gix::ObjectId { // Get current commit ID of the branch if it exists let parents = git_repo .find_reference(&format!("refs/heads/{branch}")) .ok() .and_then(|mut r| r.peel_to_commit().ok()) .map(|c| vec![c.id().detach()]) .unwrap_or_default(); git::add_commit( git_repo, &format!("refs/heads/{branch}"), branch, // filename branch.as_bytes(), // content message, &parents, ) .commit_id } /// Creates a remote Git repo containing a bookmark with the same name fn init_git_remote(test_env: &TestEnvironment, remote: &str) -> gix::Repository { let git_repo_path = test_env.env_root().join(remote); let git_repo = git::init(git_repo_path); add_commit_to_branch(&git_repo, remote, "message"); git_repo } /// Add a remote containing a bookmark with the same name fn add_git_remote( test_env: &TestEnvironment, work_dir: &TestWorkDir, remote: &str, ) -> gix::Repository { let repo = init_git_remote(test_env, remote); work_dir .run_jj(["git", "remote", "add", remote, &format!("../{remote}")]) .success(); repo } #[must_use] fn get_bookmark_output(work_dir: &TestWorkDir) -> CommandOutput { // --quiet to suppress deleted bookmarks hint work_dir.run_jj(["bookmark", "list", "--all-remotes", "--quiet"]) } #[must_use] fn get_tag_output(work_dir: &TestWorkDir) -> CommandOutput { work_dir.run_jj(["tag", "list", "--all-remotes"]) } #[must_use] fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput { let template = indoc! {r#" separate(" ", commit_id.short(), '"' ++ description.first_line() ++ '"', bookmarks, tags, ) ++ "\n" "#}; work_dir.run_jj(["log", "-T", template, "-r", "all()"]) } fn clone_git_remote_into( test_env: &TestEnvironment, upstream: &str, fork: &str, ) -> gix::Repository { let upstream_path = test_env.env_root().join(upstream); let fork_path = test_env.env_root().join(fork); let fork_repo = git::clone(&fork_path, upstream_path.to_str().unwrap(), Some(upstream)); // create local branch mirroring the upstream let upstream_head = fork_repo .find_reference(&format!("refs/remotes/{upstream}/{upstream}")) .unwrap() .peel_to_id() .unwrap() .detach(); fork_repo .reference( format!("refs/heads/{upstream}"), upstream_head, gix::refs::transaction::PreviousValue::MustNotExist, "create tracking head", ) .unwrap(); fork_repo } #[test] fn test_git_fetch_with_default_config() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "origin"); work_dir.run_jj(["git", "fetch"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" origin@origin: qmyrypzk ab8b299e message [EOF] "); } #[test] fn test_git_fetch_default_remote() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.origin.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "origin"); work_dir.run_jj(["git", "fetch"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" origin: qmyrypzk ab8b299e message @origin: qmyrypzk ab8b299e message [EOF] "); } #[test] fn test_git_fetch_single_remote() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); let output = work_dir.run_jj(["git", "fetch"]); insta::assert_snapshot!(output, @" ------- stderr ------- Hint: Fetching from the only existing remote: rem1 bookmark: rem1@rem1 [new] tracked [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); } #[test] fn test_git_fetch_single_remote_all_remotes_flag() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); work_dir.run_jj(["git", "fetch", "--all-remotes"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); } #[test] fn test_git_fetch_single_remote_from_arg() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); work_dir .run_jj(["git", "fetch", "--remote", "rem1"]) .success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); } #[test] fn test_git_fetch_single_remote_from_config() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); test_env.add_config(r#"git.fetch = "rem1""#); work_dir.run_jj(["git", "fetch"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); } #[test] fn test_git_fetch_multiple_remotes() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); work_dir .run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]) .success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] "); } #[test] fn test_git_fetch_with_ignored_refspecs() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let source_repo = init_git_remote(&test_env, "origin"); for branch in [ "main", "foo", "foobar", "foobaz", "bar", "sub/yes", "sub/no", ] { add_commit_to_branch(&source_repo, branch, branch); } let work_dir = test_env.work_dir("repo"); std::fs::OpenOptions::new() .append(true) .open(work_dir.root().join(".jj/repo/store/git/config")) .expect("failed to open config file") .write_all( br#" [remote "origin"] url = ../origin/.git fetch = +refs/heads/main:refs/remotes/origin/main fetch = +refs/heads/sub/*:refs/remotes/origin/sub/* fetch = +refs/heads/foo*:refs/remotes/origin/baz* fetch = +refs/heads/bar*:refs/tags/bar* fetch = refs/heads/bar fetch = ^refs/heads/sub/no "#, ) .expect("failed to update config file"); // Should fetch "main" and "sub/yes" by default let output = work_dir.run_jj(["git", "fetch"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: Ignored refspec `refs/heads/bar` from `origin`: fetch-only refspecs are not supported Warning: Ignored refspec `+refs/heads/bar*:refs/tags/bar*` from `origin`: only refs/remotes/ is supported for fetch destinations Warning: Ignored refspec `+refs/heads/foo*:refs/remotes/origin/baz*` from `origin`: renaming is not supported bookmark: main@origin [new] untracked bookmark: sub/yes@origin [new] untracked [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" main@origin: wlltxvop a437242b main sub/yes@origin: xwxtqxvy 6b64b005 sub/yes [EOF] "); // Can fetch ignored "sub/no" explicitly let output = work_dir.run_jj(["git", "fetch", "--branch=sub/no"]); insta::assert_snapshot!(output, @" ------- stderr ------- bookmark: sub/no@origin [new] untracked [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" main@origin: wlltxvop a437242b main sub/no@origin: tknwmolt f7d8b914 sub/no sub/yes@origin: xwxtqxvy 6b64b005 sub/yes [EOF] "); // Forget "sub/no" without exporting the change to Git work_dir .run_jj(["bookmark", "forget", "--include-remotes", "sub/no"]) .success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" main@origin: wlltxvop a437242b main sub/yes@origin: xwxtqxvy 6b64b005 sub/yes [EOF] "); // Should not import "sub/no" because it is ignored by default let output = work_dir.run_jj(["git", "fetch"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: Ignored refspec `refs/heads/bar` from `origin`: fetch-only refspecs are not supported Warning: Ignored refspec `+refs/heads/bar*:refs/tags/bar*` from `origin`: only refs/remotes/ is supported for fetch destinations Warning: Ignored refspec `+refs/heads/foo*:refs/remotes/origin/baz*` from `origin`: renaming is not supported Nothing changed. [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" main@origin: wlltxvop a437242b main sub/yes@origin: xwxtqxvy 6b64b005 sub/yes [EOF] "); } #[test] fn test_git_fetch_with_glob() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); let output = work_dir.run_jj(["git", "fetch", "--remote", "*"]); insta::assert_snapshot!(output, @" ------- stderr ------- bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] "); } #[test] fn test_git_fetch_with_glob_and_exact_match() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); add_git_remote(&test_env, &work_dir, "upstream1"); add_git_remote(&test_env, &work_dir, "upstream2"); add_git_remote(&test_env, &work_dir, "origin"); let output = work_dir.run_jj(["git", "fetch", "--remote=rem*", "--remote=origin"]); insta::assert_snapshot!(output, @" ------- stderr ------- bookmark: origin@origin [new] untracked bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] "); } #[test] fn test_git_fetch_with_glob_from_config() { let test_env = TestEnvironment::default(); test_env.add_config(r#"git.fetch = "rem*""#); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); add_git_remote(&test_env, &work_dir, "upstream"); let output = work_dir.run_jj(["git", "fetch"]); insta::assert_snapshot!(output, @" ------- stderr ------- bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] "); } #[test] fn test_git_fetch_with_glob_with_no_matching_remotes() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "upstream"); let output = work_dir.run_jj(["git", "fetch", "--remote=rem*"]); insta::assert_snapshot!(output, @" ------- stderr ------- Error: No git remotes to fetch from [EOF] [exit status: 1] "); // No remote should have been fetched as part of the failing transaction insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); } #[test] fn test_git_fetch_all_remotes() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); // add empty [remote "rem3"] section to .git/config, which should be ignored work_dir .run_jj(["git", "remote", "add", "rem3", "../unknown"]) .success(); work_dir .run_jj(["git", "remote", "remove", "rem3"]) .success(); work_dir.run_jj(["git", "fetch", "--all-remotes"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] "); } #[test] fn test_git_fetch_multiple_remotes_from_config() { let test_env = TestEnvironment::default(); test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'"); test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); test_env.add_config(r#"git.fetch = ["rem1", "rem2"]"#); work_dir.run_jj(["git", "fetch"]).success(); insta::assert_snapshot!(get_bookmark_output(&work_dir), @" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] "); } #[test] fn test_git_fetch_no_matching_remote() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: No matching remotes for names: rem1 Error: No git remotes to fetch from [EOF] [exit status: 1] "); let output = work_dir.run_jj(["git", "fetch", "--remote=rem1", "--remote=rem2"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: No matching remotes for names: rem1, rem2 Error: No git remotes to fetch from [EOF] [exit status: 1] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); } #[test] fn test_git_fetch_nonexistent_remote() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]); insta::assert_snapshot!(output, @" ------- stderr ------- Warning: No matching remotes for names: rem2 bookmark: rem1@rem1 [new] untracked [EOF] ");