1193 lines · 47.3 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::Path; use crate::common::TestEnvironment; pub mod common; #[test]fn test_branch_multiple_names() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo", "bar"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    warning: Creating multiple branches: foo, bar    "###);    insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"    @  bar foo 230dd059e1b0    ◉   000000000000    "###);     test_env.jj_cmd_ok(&repo_path, &["new"]);    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["branch", "set", "foo", "bar"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    warning: Updating multiple branches: foo, bar    "###);    insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"    @  bar foo 8bb159bc30a9    ◉   230dd059e1b0    ◉   000000000000    "###);     let (stdout, stderr) =        test_env.jj_cmd_ok(&repo_path, &["branch", "delete", "foo", "bar", "foo"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Deleted 2 branches.    "###);    insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"    @   8bb159bc30a9    ◉   230dd059e1b0    ◉   000000000000    "###);} #[test]fn test_branch_at_root() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     let (stdout, stderr) =        test_env.jj_cmd_ok(&repo_path, &["branch", "create", "fred", "-r=root()"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @"");    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["git", "export"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Nothing changed.    Failed to export some branches:      fred: Ref cannot point to the root commit in Git    "###);} #[test]fn test_branch_empty_name() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "create", ""]);    insta::assert_snapshot!(stderr, @r###"    error: a value is required for '<NAMES>...' but none was supplied     For more information, try '--help'.    "###);} #[test]fn test_branch_move() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     let stderr = test_env.jj_cmd_failure(&repo_path, &["branch", "set", "foo"]);    insta::assert_snapshot!(stderr, @r###"    Error: No such branch: foo    Hint: Use `jj branch create` to create it.    "###);     let (_stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo"]);    insta::assert_snapshot!(stderr, @"");     test_env.jj_cmd_ok(&repo_path, &["new"]);    let stderr = test_env.jj_cmd_failure(&repo_path, &["branch", "create", "foo"]);    insta::assert_snapshot!(stderr, @r###"    Error: Branch already exists: foo    Hint: Use `jj branch set` to update it.    "###);     let (_stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["branch", "set", "foo"]);    insta::assert_snapshot!(stderr, @"");     let stderr = test_env.jj_cmd_failure(&repo_path, &["branch", "set", "-r@-", "foo"]);    insta::assert_snapshot!(stderr, @r###"    Error: Refusing to move branch backwards or sideways: foo    Hint: Use --allow-backwards to allow it.    "###);     let (_stdout, stderr) = test_env.jj_cmd_ok(        &repo_path,        &["branch", "set", "-r@-", "--allow-backwards", "foo"],    );    insta::assert_snapshot!(stderr, @"");} #[test]fn test_branch_move_conflicting() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");    let get_log = || {        let template = r#"separate(" ", description.first_line(), branches)"#;        let (stdout, _stderr) = test_env.jj_cmd_ok(&repo_path, &["log", "-T", template]);        stdout    };     test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-mA0"]);    test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-mB0"]);    test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-mC0"]);    test_env.jj_cmd_ok(&repo_path, &["new", "description(A0)", "-mA1"]);     // Set up conflicting branch.    test_env.jj_cmd_ok(        &repo_path,        &["branch", "create", "-rdescription(A0)", "foo"],    );    test_env.jj_cmd_ok(        &repo_path,        &["branch", "create", "--at-op=@-", "-rdescription(B0)", "foo"],    );    insta::assert_snapshot!(get_log(), @r###"    @  A1    ◉  A0 foo??    │ ◉  C0    ├─╯    │ ◉  B0 foo??    ├─╯    ◉    "###);     // Can't move the branch to C0 since it's sibling.    let stderr =        test_env.jj_cmd_failure(&repo_path, &["branch", "set", "-rdescription(C0)", "foo"]);    insta::assert_snapshot!(stderr, @r###"    Error: Refusing to move branch backwards or sideways: foo    Hint: Use --allow-backwards to allow it.    "###);     // Can move the branch to A1 since it's descendant of A0. It's not    // descendant of B0, though.    let (_stdout, stderr) =        test_env.jj_cmd_ok(&repo_path, &["branch", "set", "-rdescription(A1)", "foo"]);    insta::assert_snapshot!(stderr, @"");    insta::assert_snapshot!(get_log(), @r###"    @  A1 foo    ◉  A0    │ ◉  C0    ├─╯    │ ◉  B0    ├─╯    ◉    "###);} #[test]fn test_branch_rename() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     // Set up remote    let git_repo_path = test_env.env_root().join("git-repo");    git2::Repository::init_bare(git_repo_path).unwrap();    test_env.jj_cmd_ok(        &repo_path,        &["git", "remote", "add", "origin", "../git-repo"],    );     let stderr = test_env.jj_cmd_failure(&repo_path, &["branch", "rename", "bnoexist", "blocal"]);    insta::assert_snapshot!(stderr, @r###"    Error: No such branch: bnoexist    "###);     test_env.jj_cmd_ok(&repo_path, &["describe", "-m=commit-0"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "blocal"]);    let (_stdout, stderr) =        test_env.jj_cmd_ok(&repo_path, &["branch", "rename", "blocal", "blocal1"]);    insta::assert_snapshot!(stderr, @"");     test_env.jj_cmd_ok(&repo_path, &["new"]);    test_env.jj_cmd_ok(&repo_path, &["describe", "-m=commit-1"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "bexist"]);    let stderr = test_env.jj_cmd_failure(&repo_path, &["branch", "rename", "blocal1", "bexist"]);    insta::assert_snapshot!(stderr, @r###"    Error: Branch already exists: bexist    "###);     test_env.jj_cmd_ok(&repo_path, &["new"]);    test_env.jj_cmd_ok(&repo_path, &["describe", "-m=commit-2"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "bremote"]);    test_env.jj_cmd_ok(&repo_path, &["git", "push", "-b=bremote"]);    let (_stdout, stderr) =        test_env.jj_cmd_ok(&repo_path, &["branch", "rename", "bremote", "bremote2"]);    insta::assert_snapshot!(stderr, @r###"    warning: Branch bremote has remote branches which will not be renamed    "###);} #[test]fn test_branch_forget_glob() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo-1"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "bar-2"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo-3"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo-4"]);     insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"    @  bar-2 foo-1 foo-3 foo-4 230dd059e1b0    ◉   000000000000    "###);    let (stdout, stderr) =        test_env.jj_cmd_ok(&repo_path, &["branch", "forget", "--glob", "foo-[1-3]"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    --glob has been deprecated. Please prefix the pattern with `glob:` instead.    Forgot 2 branches.    "###);    test_env.jj_cmd_ok(&repo_path, &["undo"]);    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["branch", "forget", "glob:foo-[1-3]"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Forgot 2 branches.    "###);    insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"    @  bar-2 foo-4 230dd059e1b0    ◉   000000000000    "###);     // Forgetting a branch via both explicit name and glob pattern, or with    // multiple glob patterns, shouldn't produce an error.    let (stdout, stderr) = test_env.jj_cmd_ok(        &repo_path,        &["branch", "forget", "foo-4", "--glob", "foo-*", "glob:foo-*"],    );    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    --glob has been deprecated. Please prefix the pattern with `glob:` instead.    "###);    insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"    @  bar-2 230dd059e1b0    ◉   000000000000    "###);     // Malformed glob    let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "forget", "glob:foo-[1-3"]);    insta::assert_snapshot!(stderr, @r###"    error: invalid value 'glob:foo-[1-3' for '[NAMES]...': Pattern syntax error near position 4: invalid range pattern     For more information, try '--help'.    "###);     // We get an error if none of the globs match anything    let stderr = test_env.jj_cmd_failure(        &repo_path,        &["branch", "forget", "glob:bar*", "glob:baz*", "--glob=boom*"],    );    insta::assert_snapshot!(stderr, @r###"    --glob has been deprecated. Please prefix the pattern with `glob:` instead.    Error: No matching branches for patterns: baz*, boom*    "###);} #[test]fn test_branch_delete_glob() {    // Set up a git repo with a branch and a jj repo that has it as a remote.    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");    let git_repo_path = test_env.env_root().join("git-repo");    let git_repo = git2::Repository::init_bare(git_repo_path).unwrap();    let mut tree_builder = git_repo.treebuilder(None).unwrap();    let file_oid = git_repo.blob(b"content").unwrap();    tree_builder        .insert("file", file_oid, git2::FileMode::Blob.into())        .unwrap();    test_env.jj_cmd_ok(        &repo_path,        &["git", "remote", "add", "origin", "../git-repo"],    );     test_env.jj_cmd_ok(&repo_path, &["describe", "-m=commit"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo-1"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "bar-2"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo-3"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo-4"]);    // Push to create remote-tracking branches    test_env.jj_cmd_ok(&repo_path, &["git", "push", "--all"]);     insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"    @  bar-2 foo-1 foo-3 foo-4 6fbf398c2d59    ◉   000000000000    "###);    let (stdout, stderr) =        test_env.jj_cmd_ok(&repo_path, &["branch", "delete", "--glob", "foo-[1-3]"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    --glob has been deprecated. Please prefix the pattern with `glob:` instead.    Deleted 2 branches.    "###);    test_env.jj_cmd_ok(&repo_path, &["undo"]);    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["branch", "delete", "glob:foo-[1-3]"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Deleted 2 branches.    "###);    insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"    @  bar-2 foo-1@origin foo-3@origin foo-4 6fbf398c2d59    ◉   000000000000    "###);     // We get an error if none of the globs match live branches. Unlike `jj branch    // forget`, it's not allowed to delete already deleted branches.    let stderr = test_env.jj_cmd_failure(&repo_path, &["branch", "delete", "--glob=foo-[1-3]"]);    insta::assert_snapshot!(stderr, @r###"    --glob has been deprecated. Please prefix the pattern with `glob:` instead.    Error: No matching branches for patterns: foo-[1-3]    "###);     // Deleting a branch via both explicit name and glob pattern, or with    // multiple glob patterns, shouldn't produce an error.    let (stdout, stderr) = test_env.jj_cmd_ok(        &repo_path,        &["branch", "delete", "foo-4", "--glob", "foo-*", "glob:foo-*"],    );    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    --glob has been deprecated. Please prefix the pattern with `glob:` instead.    "###);    insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"    @  bar-2 foo-1@origin foo-3@origin foo-4@origin 6fbf398c2d59    ◉   000000000000    "###);     // The deleted branches are still there    insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###"    bar-2: qpvuntsm 6fbf398c (empty) commit      @origin: qpvuntsm 6fbf398c (empty) commit    foo-1 (deleted)      @origin: qpvuntsm 6fbf398c (empty) commit      (this branch will be *deleted permanently* on the remote on the next `jj git push`. Use `jj branch forget` to prevent this)    foo-3 (deleted)      @origin: qpvuntsm 6fbf398c (empty) commit      (this branch will be *deleted permanently* on the remote on the next `jj git push`. Use `jj branch forget` to prevent this)    foo-4 (deleted)      @origin: qpvuntsm 6fbf398c (empty) commit      (this branch will be *deleted permanently* on the remote on the next `jj git push`. Use `jj branch forget` to prevent this)    "###);     // Malformed glob    let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "delete", "glob:foo-[1-3"]);    insta::assert_snapshot!(stderr, @r###"    error: invalid value 'glob:foo-[1-3' for '[NAMES]...': Pattern syntax error near position 4: invalid range pattern     For more information, try '--help'.    "###);     // Unknown pattern kind    let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "forget", "whatever:branch"]);    insta::assert_snapshot!(stderr, @r###"    error: invalid value 'whatever:branch' for '[NAMES]...': Invalid string pattern kind "whatever"     For more information, try '--help'.    "###);} #[test]fn test_branch_delete_export() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     test_env.jj_cmd_ok(&repo_path, &["new"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo"]);    test_env.jj_cmd_ok(&repo_path, &["git", "export"]);     test_env.jj_cmd_ok(&repo_path, &["branch", "delete", "foo"]);    let stdout = test_env.jj_cmd_success(&repo_path, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @r###"    foo (deleted)      @git: rlvkpnrz 65b6b74e (empty) (no description set)      (this branch will be deleted from the underlying Git repo on the next `jj git export`)    "###);     test_env.jj_cmd_ok(&repo_path, &["git", "export"]);    let stdout = test_env.jj_cmd_success(&repo_path, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @r###"    "###);} #[test]fn test_branch_forget_export() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     test_env.jj_cmd_ok(&repo_path, &["new"]);    test_env.jj_cmd_ok(&repo_path, &["branch", "create", "foo"]);    let stdout = test_env.jj_cmd_success(&repo_path, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @r###"    foo: rlvkpnrz 65b6b74e (empty) (no description set)    "###);     // Exporting the branch to git creates a local-git tracking branch    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["git", "export"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @"");    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["branch", "forget", "foo"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @"");    // Forgetting a branch deletes local and remote-tracking branches including    // the corresponding git-tracking branch.    let stdout = test_env.jj_cmd_success(&repo_path, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @"");    let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r=foo", "--no-graph"]);    insta::assert_snapshot!(stderr, @r###"    Error: Revision "foo" doesn't exist    "###);     // `jj git export` will delete the branch from git. In a colocated repo,    // this will happen automatically immediately after a `jj branch forget`.    // This is demonstrated in `test_git_colocated_branch_forget` in    // test_git_colocated.rs    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["git", "export"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @"");    let stdout = test_env.jj_cmd_success(&repo_path, &["branch", "list", "--all"]);    insta::assert_snapshot!(stdout, @"");} #[test]fn test_branch_forget_fetched_branch() {    // Much of this test is borrowed from `test_git_fetch_remote_only_branch` in    // test_git_fetch.rs     // Set up a git repo with a branch and a jj repo that has it as a remote.    let test_env = TestEnvironment::default();    test_env.add_config("git.auto-local-branch = true");    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");    let git_repo_path = test_env.env_root().join("git-repo");    let git_repo = git2::Repository::init_bare(git_repo_path).unwrap();    let signature =        git2::Signature::new("Some One", "some.one@example.com", &git2::Time::new(0, 0)).unwrap();    let mut tree_builder = git_repo.treebuilder(None).unwrap();    let file_oid = git_repo.blob(b"content").unwrap();    tree_builder        .insert("file", file_oid, git2::FileMode::Blob.into())        .unwrap();    let tree_oid = tree_builder.write().unwrap();    let tree = git_repo.find_tree(tree_oid).unwrap();    test_env.jj_cmd_ok(        &repo_path,        &["git", "remote", "add", "origin", "../git-repo"],    );    // Create a commit and a branch in the git repo    let first_git_repo_commit = git_repo        .commit(            Some("refs/heads/feature1"),            &signature,            &signature,

Lines 1–500 of 1193.