825 lines · 33.1 KB · Rust
RawDownload
// 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 std::path::PathBuf; use crate::common::{get_stderr_string, get_stdout_string, TestEnvironment}; pub mod common; fn set_up() -> (TestEnvironment, PathBuf) {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "--git", "origin"]);    let origin_path = test_env.env_root().join("origin");    let origin_git_repo_path = origin_path        .join(".jj")        .join("repo")        .join("store")        .join("git");     test_env.jj_cmd_ok(&origin_path, &["describe", "-m=description 1"]);    test_env.jj_cmd_ok(&origin_path, &["branch", "create", "branch1"]);    test_env.jj_cmd_ok(&origin_path, &["new", "root()", "-m=description 2"]);    test_env.jj_cmd_ok(&origin_path, &["branch", "create", "branch2"]);    test_env.jj_cmd_ok(&origin_path, &["git", "export"]);     test_env.jj_cmd_ok(        test_env.env_root(),        &[            "git",            "clone",            "--config-toml=git.auto-local-branch=true",            origin_git_repo_path.to_str().unwrap(),            "local",        ],    );    let workspace_root = test_env.env_root().join("local");    (test_env, workspace_root)} #[test]fn test_git_push_nothing() {    let (test_env, workspace_root) = set_up();    // No branches to push yet    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--all"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Nothing changed.    "###);} #[test]fn test_git_push_current_branch() {    let (test_env, workspace_root) = set_up();    test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#);    // Update some branches. `branch1` is not a current branch, but `branch2` and    // `my-branch` are.    test_env.jj_cmd_ok(        &workspace_root,        &["describe", "branch1", "-m", "modified branch1 commit"],    );    test_env.jj_cmd_ok(&workspace_root, &["co", "branch2"]);    test_env.jj_cmd_ok(&workspace_root, &["branch", "set", "branch2"]);    test_env.jj_cmd_ok(&workspace_root, &["branch", "create", "my-branch"]);    test_env.jj_cmd_ok(&workspace_root, &["describe", "-m", "foo"]);    // Check the setup    let stdout = test_env.jj_cmd_success(&workspace_root, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @r###"    branch1: lzmmnrxq 19e00bf6 (empty) modified branch1 commit      @origin (ahead by 1 commits, behind by 1 commits): lzmmnrxq hidden 45a3aa29 (empty) description 1    branch2: yostqsxw 10ee3363 (empty) foo      @origin (behind by 1 commits): rlzusymt 8476341e (empty) description 2    my-branch: yostqsxw 10ee3363 (empty) foo    "###);    // First dry-run. `branch1` should not get pushed.    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--dry-run"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Move branch branch2 from 8476341eb395 to 10ee3363b259      Add branch my-branch to 10ee3363b259    Dry-run requested, not pushing.    "###);    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Move branch branch2 from 8476341eb395 to 10ee3363b259      Add branch my-branch to 10ee3363b259    "###);    let stdout = test_env.jj_cmd_success(&workspace_root, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @r###"    branch1: lzmmnrxq 19e00bf6 (empty) modified branch1 commit      @origin (ahead by 1 commits, behind by 1 commits): lzmmnrxq hidden 45a3aa29 (empty) description 1    branch2: yostqsxw 10ee3363 (empty) foo      @origin: yostqsxw 10ee3363 (empty) foo    my-branch: yostqsxw 10ee3363 (empty) foo      @origin: yostqsxw 10ee3363 (empty) foo    "###);} #[test]fn test_git_push_parent_branch() {    let (test_env, workspace_root) = set_up();    test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#);    test_env.jj_cmd_ok(&workspace_root, &["edit", "branch1"]);    test_env.jj_cmd_ok(        &workspace_root,        &["describe", "-m", "modified branch1 commit"],    );    test_env.jj_cmd_ok(&workspace_root, &["new", "-m", "non-empty description"]);    std::fs::write(workspace_root.join("file"), "file").unwrap();    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Force branch branch1 from 45a3aa29e907 to d47326d59ee1    "###);} #[test]fn test_git_push_no_matching_branch() {    let (test_env, workspace_root) = set_up();    test_env.jj_cmd_ok(&workspace_root, &["new"]);    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    No branches point to the specified revisions.    Nothing changed.    "###);} #[test]fn test_git_push_matching_branch_unchanged() {    let (test_env, workspace_root) = set_up();    test_env.jj_cmd_ok(&workspace_root, &["co", "branch1"]);    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    No branches point to the specified revisions.    Nothing changed.    "###);} /// Test that `jj git push` without arguments pushes a branch to the specified/// remote even if it's already up to date on another remote/// (`remote_branches(remote=<remote>)..@` vs. `remote_branches()..@`).#[test]fn test_git_push_other_remote_has_branch() {    let (test_env, workspace_root) = set_up();    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");    test_env.jj_cmd_ok(        &workspace_root,        &[            "git",            "remote",            "add",            "other",            other_remote_path.to_str().unwrap(),        ],    );    // Modify branch1 and push it to `origin`    test_env.jj_cmd_ok(&workspace_root, &["edit", "branch1"]);    test_env.jj_cmd_ok(&workspace_root, &["describe", "-m=modified"]);    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Force branch branch1 from 45a3aa29e907 to 50421a29358a    "###);    // Since it's already pushed to origin, nothing will happen if push again    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    No branches point to the specified revisions.    Nothing changed.    "###);    // But it will still get pushed to another remote    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--remote=other"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to other:      Add branch branch1 to 50421a29358a    "###);} #[test]fn test_git_push_not_fast_forward() {    let (test_env, workspace_root) = set_up();     // Move branch1 forward on the remote    let origin_path = test_env.env_root().join("origin");    test_env.jj_cmd_ok(&origin_path, &["new", "branch1", "-m=remote"]);    std::fs::write(origin_path.join("remote"), "remote").unwrap();    test_env.jj_cmd_ok(&origin_path, &["branch", "set", "branch1"]);    test_env.jj_cmd_ok(&origin_path, &["git", "export"]);     // Move branch1 forward to another commit locally    test_env.jj_cmd_ok(&workspace_root, &["new", "branch1", "-m=local"]);    std::fs::write(workspace_root.join("local"), "local").unwrap();    test_env.jj_cmd_ok(&workspace_root, &["branch", "set", "branch1"]);     // Pushing should fail    let assert = test_env        .jj_cmd(&workspace_root, &["git", "push"])        .assert()        .code(1);    insta::assert_snapshot!(get_stdout_string(&assert), @"");    insta::assert_snapshot!(get_stderr_string(&assert), @r###"    Branch changes to push to origin:      Move branch branch1 from 45a3aa29e907 to c35839cb8e8c    Error: The push conflicts with changes made on the remote (it is not fast-forwardable).    Hint: Try fetching from the remote, then make the branch point to where you want it to be, and push again.    "###);} #[test]fn test_git_push_locally_created_and_rewritten() {    let (test_env, workspace_root) = set_up();    // Ensure that remote branches aren't tracked automatically    test_env.add_config("git.auto-local-branch = false");     // Push locally-created branch    test_env.jj_cmd_ok(&workspace_root, &["new", "root()", "-mlocal 1"]);    test_env.jj_cmd_ok(&workspace_root, &["branch", "create", "my"]);    let (_stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]);    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Add branch my to fcc999921ce9    "###);     // Rewrite it and push again, which would fail if the pushed branch weren't    // set to "tracking"    test_env.jj_cmd_ok(&workspace_root, &["describe", "-mlocal 2"]);    let stdout = test_env.jj_cmd_success(&workspace_root, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @r###"    branch1: lzmmnrxq 45a3aa29 (empty) description 1      @origin: lzmmnrxq 45a3aa29 (empty) description 1    branch2: rlzusymt 8476341e (empty) description 2      @origin: rlzusymt 8476341e (empty) description 2    my: vruxwmqv bde1d2e4 (empty) local 2      @origin (ahead by 1 commits, behind by 1 commits): vruxwmqv hidden fcc99992 (empty) local 1    "###);    let (_stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]);    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Force branch my from fcc999921ce9 to bde1d2e44b2a    "###);} #[test]fn test_git_push_multiple() {    let (test_env, workspace_root) = set_up();    test_env.jj_cmd_ok(&workspace_root, &["branch", "delete", "branch1"]);    test_env.jj_cmd_ok(        &workspace_root,        &["branch", "set", "--allow-backwards", "branch2"],    );    test_env.jj_cmd_ok(&workspace_root, &["branch", "create", "my-branch"]);    test_env.jj_cmd_ok(&workspace_root, &["describe", "-m", "foo"]);    // Check the setup    let stdout = test_env.jj_cmd_success(&workspace_root, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @r###"    branch1 (deleted)      @origin: lzmmnrxq 45a3aa29 (empty) description 1      (this branch will be *deleted permanently* on the remote on the next `jj git push`. Use `jj branch forget` to prevent this)    branch2: yqosqzyt 15dcdaa4 (empty) foo      @origin (ahead by 1 commits, behind by 1 commits): rlzusymt 8476341e (empty) description 2    my-branch: yqosqzyt 15dcdaa4 (empty) foo    "###);    // First dry-run    let (stdout, stderr) =        test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--all", "--dry-run"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Delete branch branch1 from 45a3aa29e907      Force branch branch2 from 8476341eb395 to 15dcdaa4f12f      Add branch my-branch to 15dcdaa4f12f    Dry-run requested, not pushing.    "###);    // Dry run requesting two specific branches    let (stdout, stderr) = test_env.jj_cmd_ok(        &workspace_root,        &["git", "push", "-b=branch1", "-b=my-branch", "--dry-run"],    );    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Delete branch branch1 from 45a3aa29e907      Add branch my-branch to 15dcdaa4f12f    Dry-run requested, not pushing.    "###);    // Dry run requesting two specific branches twice    let (stdout, stderr) = test_env.jj_cmd_ok(        &workspace_root,        &[            "git",            "push",            "-b=branch1",            "-b=my-branch",            "-b=branch1",            "-b=glob:my-*",            "--dry-run",        ],    );    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Delete branch branch1 from 45a3aa29e907      Add branch my-branch to 15dcdaa4f12f    Dry-run requested, not pushing.    "###);    // Dry run with glob pattern    let (stdout, stderr) = test_env.jj_cmd_ok(        &workspace_root,        &["git", "push", "-b=glob:branch?", "--dry-run"],    );    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Delete branch branch1 from 45a3aa29e907      Force branch branch2 from 8476341eb395 to 15dcdaa4f12f    Dry-run requested, not pushing.    "###);     // Unmatched branch name is error    let stderr = test_env.jj_cmd_failure(&workspace_root, &["git", "push", "-b=foo"]);    insta::assert_snapshot!(stderr, @r###"    Error: No such branch: foo    "###);    let stderr = test_env.jj_cmd_failure(        &workspace_root,        &["git", "push", "-b=foo", "-b=glob:?branch"],    );    insta::assert_snapshot!(stderr, @r###"    Error: No matching branches for patterns: foo, ?branch    "###);     let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--all"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Delete branch branch1 from 45a3aa29e907      Force branch branch2 from 8476341eb395 to 15dcdaa4f12f      Add branch my-branch to 15dcdaa4f12f    "###);    let stdout = test_env.jj_cmd_success(&workspace_root, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @r###"    branch2: yqosqzyt 15dcdaa4 (empty) foo      @origin: yqosqzyt 15dcdaa4 (empty) foo    my-branch: yqosqzyt 15dcdaa4 (empty) foo      @origin: yqosqzyt 15dcdaa4 (empty) foo    "###);    let stdout = test_env.jj_cmd_success(&workspace_root, &["log", "-rall()"]);    insta::assert_snapshot!(stdout, @r###"    @  yqosqzyt test.user@example.com 2001-02-03 04:05:17.000 +07:00 branch2 my-branch 15dcdaa4    │  (empty) foo    │ ◉  rlzusymt test.user@example.com 2001-02-03 04:05:10.000 +07:00 8476341e    ├─╯  (empty) description 2    │ ◉  lzmmnrxq test.user@example.com 2001-02-03 04:05:08.000 +07:00 45a3aa29    ├─╯  (empty) description 1    ◉  zzzzzzzz root() 00000000    "###);} #[test]fn test_git_push_changes() {    let (test_env, workspace_root) = set_up();    test_env.jj_cmd_ok(&workspace_root, &["describe", "-m", "foo"]);    std::fs::write(workspace_root.join("file"), "contents").unwrap();    test_env.jj_cmd_ok(&workspace_root, &["new", "-m", "bar"]);    std::fs::write(workspace_root.join("file"), "modified").unwrap();     let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--change", "@"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Creating branch push-yostqsxwqrlt for revision @    Branch changes to push to origin:      Add branch push-yostqsxwqrlt to 28d7620ea63a    "###);    // test pushing two changes at once    std::fs::write(workspace_root.join("file"), "modified2").unwrap();    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "-c=@", "-c=@-"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Creating branch push-yqosqzytrlsw for revision @-    Branch changes to push to origin:      Force branch push-yostqsxwqrlt from 28d7620ea63a to 48d8c7948133      Add branch push-yqosqzytrlsw to fa16a14170fb    "###);    // specifying the same change twice doesn't break things    std::fs::write(workspace_root.join("file"), "modified3").unwrap();    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "-c=@", "-c=@"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Force branch push-yostqsxwqrlt from 48d8c7948133 to b5f030322b1d    "###);    // Test changing `git.push-branch-prefix`. It causes us to push again.    let (stdout, stderr) = test_env.jj_cmd_ok(        &workspace_root,        &[            "git",            "push",            "--config-toml",            r"git.push-branch-prefix='test-'",            "--change=@",        ],    );    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Creating branch test-yostqsxwqrlt for revision @    Branch changes to push to origin:      Add branch test-yostqsxwqrlt to b5f030322b1d    "###);} #[test]fn test_git_push_revisions() {    let (test_env, workspace_root) = set_up();    test_env.jj_cmd_ok(&workspace_root, &["describe", "-m", "foo"]);    std::fs::write(workspace_root.join("file"), "contents").unwrap();    test_env.jj_cmd_ok(&workspace_root, &["new", "-m", "bar"]);    test_env.jj_cmd_ok(&workspace_root, &["branch", "create", "branch-1"]);    std::fs::write(workspace_root.join("file"), "modified").unwrap();    test_env.jj_cmd_ok(&workspace_root, &["new", "-m", "baz"]);    test_env.jj_cmd_ok(&workspace_root, &["branch", "create", "branch-2a"]);    test_env.jj_cmd_ok(&workspace_root, &["branch", "create", "branch-2b"]);    std::fs::write(workspace_root.join("file"), "modified again").unwrap();     // Push an empty set    let stderr = test_env.jj_cmd_failure(&workspace_root, &["git", "push", "-r=none()"]);    insta::assert_snapshot!(stderr, @r###"    Error: Empty revision set    "###);    // Push a revision with no branches    let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "-r=@--"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    No branches point to the specified revisions.    Nothing changed.    "###);    // Push a revision with a single branch    let (stdout, stderr) =        test_env.jj_cmd_ok(&workspace_root, &["git", "push", "-r=@-", "--dry-run"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Add branch branch-1 to 7decc7932d9c    Dry-run requested, not pushing.    "###);    // Push multiple revisions of which some have branches    let (stdout, stderr) = test_env.jj_cmd_ok(        &workspace_root,        &["git", "push", "-r=@--", "-r=@-", "--dry-run"],    );    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Add branch branch-1 to 7decc7932d9c    Dry-run requested, not pushing.    "###);    // Push a revision with a multiple branches    let (stdout, stderr) =        test_env.jj_cmd_ok(&workspace_root, &["git", "push", "-r=@", "--dry-run"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Add branch branch-2a to 1b45449e18d0      Add branch branch-2b to 1b45449e18d0    Dry-run requested, not pushing.    "###);    // Repeating a commit doesn't result in repeated messages about the branch    let (stdout, stderr) = test_env.jj_cmd_ok(        &workspace_root,        &["git", "push", "-r=@-", "-r=@-", "--dry-run"],    );    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Branch changes to push to origin:      Add branch branch-1 to 7decc7932d9c

Lines 1–500 of 825.