// Copyright 2022 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 test_case::test_case;use testutils::git; use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir; fn git_repo_dir_for_jj_repo(work_dir: &TestWorkDir<'_>) -> std::path::PathBuf { work_dir .root() .join(".jj") .join("repo") .join("store") .join("git")} fn set_up(test_env: &TestEnvironment) { test_env.run_jj_in(".", ["git", "init", "origin"]).success(); let origin_dir = test_env.work_dir("origin"); let origin_git_repo_path = git_repo_dir_for_jj_repo(&origin_dir); origin_dir .run_jj(["describe", "-m=description 1"]) .success(); origin_dir .run_jj(["bookmark", "create", "-r@", "bookmark1"]) .success(); origin_dir .run_jj(["new", "root()", "-m=description 2"]) .success(); origin_dir .run_jj(["bookmark", "create", "-r@", "bookmark2"]) .success(); origin_dir.run_jj(["git", "export"]).success(); test_env .run_jj_in( ".", [ "git", "clone", "--config=git.auto-local-bookmark=true", origin_git_repo_path.to_str().unwrap(), "local", ], ) .success();} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_push_nothing(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } // Show the setup. `insta` has trouble if this is done inside `set_up()` insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" bookmark1: xtvrqkyv d13ecdbd (empty) description 1 @origin: xtvrqkyv d13ecdbd (empty) description 1 bookmark2: rlzusymt 8476341e (empty) description 2 @origin: rlzusymt 8476341e (empty) description 2 [EOF] "); } // No bookmarks to push yet let output = work_dir.run_jj(["git", "push", "--all"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Nothing changed. [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_push_current_bookmark(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); // Update some bookmarks. `bookmark1` is not a current bookmark, but // `bookmark2` and `my-bookmark` are. work_dir .run_jj(["describe", "bookmark1", "-m", "modified bookmark1 commit"]) .success(); work_dir.run_jj(["new", "bookmark2"]).success(); work_dir .run_jj(["bookmark", "set", "bookmark2", "-r@"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "my-bookmark"]) .success(); work_dir.run_jj(["describe", "-m", "foo"]).success(); // Check the setup insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" bookmark1: xtvrqkyv 0f8dc656 (empty) modified bookmark1 commit @origin (ahead by 1 commits, behind by 1 commits): xtvrqkyv hidden d13ecdbd (empty) description 1 bookmark2: yostqsxw bc7610b6 (empty) foo @origin (behind by 1 commits): rlzusymt 8476341e (empty) description 2 my-bookmark: yostqsxw bc7610b6 (empty) foo [EOF] "); } // First dry-run. `bookmark1` should not get pushed. let output = work_dir.run_jj(["git", "push", "--allow-new", "--dry-run"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move forward bookmark bookmark2 from 8476341eb395 to bc7610b65a91 Add bookmark my-bookmark to bc7610b65a91 Dry-run requested, not pushing. [EOF] "); } let output = work_dir.run_jj(["git", "push", "--allow-new"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move forward bookmark bookmark2 from 8476341eb395 to bc7610b65a91 Add bookmark my-bookmark to bc7610b65a91 [EOF] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" bookmark1: xtvrqkyv 0f8dc656 (empty) modified bookmark1 commit @origin (ahead by 1 commits, behind by 1 commits): xtvrqkyv hidden d13ecdbd (empty) description 1 bookmark2: yostqsxw bc7610b6 (empty) foo @origin: yostqsxw bc7610b6 (empty) foo my-bookmark: yostqsxw bc7610b6 (empty) foo @origin: yostqsxw bc7610b6 (empty) foo [EOF] "); } // Try pushing backwards work_dir .run_jj([ "bookmark", "set", "bookmark2", "-rbookmark2-", "--allow-backwards", ]) .success(); // This behavior is a strangeness of our definition of the default push revset. // We could consider changing it. let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@ Nothing changed. [EOF] "); } // We can move a bookmark backwards let output = work_dir.run_jj(["git", "push", "-bbookmark2"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move backward bookmark bookmark2 from bc7610b65a91 to 8476341eb395 [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_push_parent_bookmark(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); work_dir.run_jj(["edit", "bookmark1"]).success(); work_dir .run_jj(["describe", "-m", "modified bookmark1 commit"]) .success(); work_dir .run_jj(["new", "-m", "non-empty description"]) .success(); work_dir.write_file("file", "file"); let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move sideways bookmark bookmark1 from d13ecdbda2a2 to e612d524a5c6 [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_push_no_matching_bookmark(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } work_dir.run_jj(["new"]).success(); let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@ Nothing changed. [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_push_matching_bookmark_unchanged(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } work_dir.run_jj(["new", "bookmark1"]).success(); let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@ Nothing changed. [EOF] "); }} /// Test that `jj git push` without arguments pushes a bookmark to the specified/// remote even if it's already up to date on another remote/// (`remote_bookmarks(remote=<remote>)..@` vs. `remote_bookmarks()..@`).#[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_push_other_remote_has_bookmark(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); // Create another remote (but actually the same) let other_remote_path = test_env .env_root() .join("origin") .join(".jj") .join("repo") .join("store") .join("git"); work_dir .run_jj([ "git", "remote", "add", "other", other_remote_path.to_str().unwrap(), ]) .success(); // Modify bookmark1 and push it to `origin` work_dir.run_jj(["edit", "bookmark1"]).success(); work_dir.run_jj(["describe", "-m=modified"]).success(); let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move sideways bookmark bookmark1 from d13ecdbda2a2 to a657f1b61b94 [EOF] "); } // Since it's already pushed to origin, nothing will happen if push again let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@ Nothing changed. [EOF] "); } // The bookmark was moved on the "other" remote as well (since it's actually the // same remote), but `jj` is not aware of that since it thinks this is a // different remote. So, the push should fail. // // But it succeeds! That's because the bookmark is created at the same location // as it is on the remote. This would also work for a descendant. // // TODO: Saner test? let output = work_dir.run_jj(["git", "push", "--allow-new", "--remote=other"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to other: Add bookmark bookmark1 to a657f1b61b94 [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_push_forward_unexpectedly_moved(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } // Move bookmark1 forward on the remote let origin_dir = test_env.work_dir("origin"); origin_dir .run_jj(["new", "bookmark1", "-m=remote"]) .success(); origin_dir.write_file("remote", "remote"); origin_dir .run_jj(["bookmark", "set", "bookmark1", "-r@"]) .success(); origin_dir.run_jj(["git", "export"]).success(); // Move bookmark1 forward to another commit locally work_dir.run_jj(["new", "bookmark1", "-m=local"]).success(); work_dir.write_file("local", "local"); work_dir .run_jj(["bookmark", "set", "bookmark1", "-r@"]) .success(); // Pushing should fail let output = work_dir.run_jj(["git", "push"]); if subprocess { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move forward bookmark bookmark1 from d13ecdbda2a2 to 6750425ff51c Error: Failed to push some bookmarks Hint: The following references unexpectedly moved on the remote: refs/heads/bookmark1 (reason: stale info) Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again. [EOF] [exit status: 1] "); } else { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move forward bookmark bookmark1 from d13ecdbda2a2 to 6750425ff51c Error: Failed to push some bookmarks Hint: The following references unexpectedly moved on the remote: refs/heads/bookmark1 Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again. [EOF] [exit status: 1] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_push_sideways_unexpectedly_moved(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } // Move bookmark1 forward on the remote let origin_dir = test_env.work_dir("origin"); origin_dir .run_jj(["new", "bookmark1", "-m=remote"]) .success(); origin_dir.write_file("remote", "remote"); origin_dir .run_jj(["bookmark", "set", "bookmark1", "-r@"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&origin_dir), @r" bookmark1: vruxwmqv 80284bec remote @git (behind by 1 commits): qpvuntsm d13ecdbd (empty) description 1 bookmark2: zsuskuln 8476341e (empty) description 2 @git: zsuskuln 8476341e (empty) description 2 [EOF] "); } origin_dir.run_jj(["git", "export"]).success(); // Move bookmark1 sideways to another commit locally work_dir.run_jj(["new", "root()", "-m=local"]).success(); work_dir.write_file("local", "local"); work_dir .run_jj(["bookmark", "set", "bookmark1", "--allow-backwards", "-r@"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" bookmark1: kmkuslsw 0f8bf988 local @origin (ahead by 1 commits, behind by 1 commits): xtvrqkyv d13ecdbd (empty) description 1 bookmark2: rlzusymt 8476341e (empty) description 2 @origin: rlzusymt 8476341e (empty) description 2 [EOF] "); } let output = work_dir.run_jj(["git", "push"]); if subprocess { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move sideways bookmark bookmark1 from d13ecdbda2a2 to 0f8bf988588e Error: Failed to push some bookmarks Hint: The following references unexpectedly moved on the remote: refs/heads/bookmark1 (reason: stale info) Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again. [EOF] [exit status: 1] "); } else { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move sideways bookmark bookmark1 from d13ecdbda2a2 to 0f8bf988588e Error: Failed to push some bookmarks Hint: The following references unexpectedly moved on the remote: refs/heads/bookmark1 Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again. [EOF] [exit status: 1] "); }} // This tests whether the push checks that the remote bookmarks are in expected// positions.#[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_push_deletion_unexpectedly_moved(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } // Move bookmark1 forward on the remote let origin_dir = test_env.work_dir("origin"); origin_dir .run_jj(["new", "bookmark1", "-m=remote"]) .success(); origin_dir.write_file("remote", "remote"); origin_dir .run_jj(["bookmark", "set", "bookmark1", "-r@"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&origin_dir), @r" bookmark1: vruxwmqv 80284bec remote @git (behind by 1 commits): qpvuntsm d13ecdbd (empty) description 1 bookmark2: zsuskuln 8476341e (empty) description 2 @git: zsuskuln 8476341e (empty) description 2 [EOF] "); } origin_dir.run_jj(["git", "export"]).success(); // Delete bookmark1 locallyLines 1–500 of 2655. Load more
// Copyright 2022 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 test_case::test_case; use testutils::git; use crate::common::CommandOutput; use crate::common::TestEnvironment; use crate::common::TestWorkDir; fn git_repo_dir_for_jj_repo(work_dir: &TestWorkDir<'_>) -> std::path::PathBuf { work_dir .root() .join(".jj") .join("repo") .join("store") .join("git") } fn set_up(test_env: &TestEnvironment) { test_env.run_jj_in(".", ["git", "init", "origin"]).success(); let origin_dir = test_env.work_dir("origin"); let origin_git_repo_path = git_repo_dir_for_jj_repo(&origin_dir); origin_dir .run_jj(["describe", "-m=description 1"]) .success(); origin_dir .run_jj(["bookmark", "create", "-r@", "bookmark1"]) .success(); origin_dir .run_jj(["new", "root()", "-m=description 2"]) .success(); origin_dir .run_jj(["bookmark", "create", "-r@", "bookmark2"]) .success(); origin_dir.run_jj(["git", "export"]).success(); test_env .run_jj_in( ".", [ "git", "clone", "--config=git.auto-local-bookmark=true", origin_git_repo_path.to_str().unwrap(), "local", ], ) .success(); } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_push_nothing(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } // Show the setup. `insta` has trouble if this is done inside `set_up()` insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" bookmark1: xtvrqkyv d13ecdbd (empty) description 1 @origin: xtvrqkyv d13ecdbd (empty) description 1 bookmark2: rlzusymt 8476341e (empty) description 2 @origin: rlzusymt 8476341e (empty) description 2 [EOF] "); } // No bookmarks to push yet let output = work_dir.run_jj(["git", "push", "--all"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Nothing changed. [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_push_current_bookmark(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); // Update some bookmarks. `bookmark1` is not a current bookmark, but // `bookmark2` and `my-bookmark` are. work_dir .run_jj(["describe", "bookmark1", "-m", "modified bookmark1 commit"]) .success(); work_dir.run_jj(["new", "bookmark2"]).success(); work_dir .run_jj(["bookmark", "set", "bookmark2", "-r@"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "my-bookmark"]) .success(); work_dir.run_jj(["describe", "-m", "foo"]).success(); // Check the setup insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" bookmark1: xtvrqkyv 0f8dc656 (empty) modified bookmark1 commit @origin (ahead by 1 commits, behind by 1 commits): xtvrqkyv hidden d13ecdbd (empty) description 1 bookmark2: yostqsxw bc7610b6 (empty) foo @origin (behind by 1 commits): rlzusymt 8476341e (empty) description 2 my-bookmark: yostqsxw bc7610b6 (empty) foo [EOF] "); } // First dry-run. `bookmark1` should not get pushed. let output = work_dir.run_jj(["git", "push", "--allow-new", "--dry-run"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move forward bookmark bookmark2 from 8476341eb395 to bc7610b65a91 Add bookmark my-bookmark to bc7610b65a91 Dry-run requested, not pushing. [EOF] "); } let output = work_dir.run_jj(["git", "push", "--allow-new"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move forward bookmark bookmark2 from 8476341eb395 to bc7610b65a91 Add bookmark my-bookmark to bc7610b65a91 [EOF] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" bookmark1: xtvrqkyv 0f8dc656 (empty) modified bookmark1 commit @origin (ahead by 1 commits, behind by 1 commits): xtvrqkyv hidden d13ecdbd (empty) description 1 bookmark2: yostqsxw bc7610b6 (empty) foo @origin: yostqsxw bc7610b6 (empty) foo my-bookmark: yostqsxw bc7610b6 (empty) foo @origin: yostqsxw bc7610b6 (empty) foo [EOF] "); } // Try pushing backwards work_dir .run_jj([ "bookmark", "set", "bookmark2", "-rbookmark2-", "--allow-backwards", ]) .success(); // This behavior is a strangeness of our definition of the default push revset. // We could consider changing it. let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@ Nothing changed. [EOF] "); } // We can move a bookmark backwards let output = work_dir.run_jj(["git", "push", "-bbookmark2"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move backward bookmark bookmark2 from bc7610b65a91 to 8476341eb395 [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_push_parent_bookmark(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); work_dir.run_jj(["edit", "bookmark1"]).success(); work_dir .run_jj(["describe", "-m", "modified bookmark1 commit"]) .success(); work_dir .run_jj(["new", "-m", "non-empty description"]) .success(); work_dir.write_file("file", "file"); let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move sideways bookmark bookmark1 from d13ecdbda2a2 to e612d524a5c6 [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_push_no_matching_bookmark(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } work_dir.run_jj(["new"]).success(); let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@ Nothing changed. [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_push_matching_bookmark_unchanged(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } work_dir.run_jj(["new", "bookmark1"]).success(); let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@ Nothing changed. [EOF] "); } } /// Test that `jj git push` without arguments pushes a bookmark to the specified /// remote even if it's already up to date on another remote /// (`remote_bookmarks(remote=<remote>)..@` vs. `remote_bookmarks()..@`). #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_push_other_remote_has_bookmark(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); // Create another remote (but actually the same) let other_remote_path = test_env .env_root() .join("origin") .join(".jj") .join("repo") .join("store") .join("git"); work_dir .run_jj([ "git", "remote", "add", "other", other_remote_path.to_str().unwrap(), ]) .success(); // Modify bookmark1 and push it to `origin` work_dir.run_jj(["edit", "bookmark1"]).success(); work_dir.run_jj(["describe", "-m=modified"]).success(); let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move sideways bookmark bookmark1 from d13ecdbda2a2 to a657f1b61b94 [EOF] "); } // Since it's already pushed to origin, nothing will happen if push again let output = work_dir.run_jj(["git", "push"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@ Nothing changed. [EOF] "); } // The bookmark was moved on the "other" remote as well (since it's actually the // same remote), but `jj` is not aware of that since it thinks this is a // different remote. So, the push should fail. // // But it succeeds! That's because the bookmark is created at the same location // as it is on the remote. This would also work for a descendant. // // TODO: Saner test? let output = work_dir.run_jj(["git", "push", "--allow-new", "--remote=other"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to other: Add bookmark bookmark1 to a657f1b61b94 [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_push_forward_unexpectedly_moved(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } // Move bookmark1 forward on the remote let origin_dir = test_env.work_dir("origin"); origin_dir .run_jj(["new", "bookmark1", "-m=remote"]) .success(); origin_dir.write_file("remote", "remote"); origin_dir .run_jj(["bookmark", "set", "bookmark1", "-r@"]) .success(); origin_dir.run_jj(["git", "export"]).success(); // Move bookmark1 forward to another commit locally work_dir.run_jj(["new", "bookmark1", "-m=local"]).success(); work_dir.write_file("local", "local"); work_dir .run_jj(["bookmark", "set", "bookmark1", "-r@"]) .success(); // Pushing should fail let output = work_dir.run_jj(["git", "push"]); if subprocess { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move forward bookmark bookmark1 from d13ecdbda2a2 to 6750425ff51c Error: Failed to push some bookmarks Hint: The following references unexpectedly moved on the remote: refs/heads/bookmark1 (reason: stale info) Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again. [EOF] [exit status: 1] "); } else { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move forward bookmark bookmark1 from d13ecdbda2a2 to 6750425ff51c Error: Failed to push some bookmarks Hint: The following references unexpectedly moved on the remote: refs/heads/bookmark1 Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again. [EOF] [exit status: 1] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_push_sideways_unexpectedly_moved(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } // Move bookmark1 forward on the remote let origin_dir = test_env.work_dir("origin"); origin_dir .run_jj(["new", "bookmark1", "-m=remote"]) .success(); origin_dir.write_file("remote", "remote"); origin_dir .run_jj(["bookmark", "set", "bookmark1", "-r@"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&origin_dir), @r" bookmark1: vruxwmqv 80284bec remote @git (behind by 1 commits): qpvuntsm d13ecdbd (empty) description 1 bookmark2: zsuskuln 8476341e (empty) description 2 @git: zsuskuln 8476341e (empty) description 2 [EOF] "); } origin_dir.run_jj(["git", "export"]).success(); // Move bookmark1 sideways to another commit locally work_dir.run_jj(["new", "root()", "-m=local"]).success(); work_dir.write_file("local", "local"); work_dir .run_jj(["bookmark", "set", "bookmark1", "--allow-backwards", "-r@"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" bookmark1: kmkuslsw 0f8bf988 local @origin (ahead by 1 commits, behind by 1 commits): xtvrqkyv d13ecdbd (empty) description 1 bookmark2: rlzusymt 8476341e (empty) description 2 @origin: rlzusymt 8476341e (empty) description 2 [EOF] "); } let output = work_dir.run_jj(["git", "push"]); if subprocess { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move sideways bookmark bookmark1 from d13ecdbda2a2 to 0f8bf988588e Error: Failed to push some bookmarks Hint: The following references unexpectedly moved on the remote: refs/heads/bookmark1 (reason: stale info) Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again. [EOF] [exit status: 1] "); } else { insta::assert_snapshot!(output, @r" ------- stderr ------- Changes to push to origin: Move sideways bookmark bookmark1 from d13ecdbda2a2 to 0f8bf988588e Error: Failed to push some bookmarks Hint: The following references unexpectedly moved on the remote: refs/heads/bookmark1 Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again. [EOF] [exit status: 1] "); } } // This tests whether the push checks that the remote bookmarks are in expected // positions. #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_push_deletion_unexpectedly_moved(subprocess: bool) { let test_env = TestEnvironment::default(); set_up(&test_env); let work_dir = test_env.work_dir("local"); if !subprocess { test_env.add_config("git.subprocess = false"); } // Move bookmark1 forward on the remote let origin_dir = test_env.work_dir("origin"); origin_dir .run_jj(["new", "bookmark1", "-m=remote"]) .success(); origin_dir.write_file("remote", "remote"); origin_dir .run_jj(["bookmark", "set", "bookmark1", "-r@"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&origin_dir), @r" bookmark1: vruxwmqv 80284bec remote @git (behind by 1 commits): qpvuntsm d13ecdbd (empty) description 1 bookmark2: zsuskuln 8476341e (empty) description 2 @git: zsuskuln 8476341e (empty) description 2 [EOF] "); } origin_dir.run_jj(["git", "export"]).success(); // Delete bookmark1 locally