1631 lines · 61.9 KB · Rust
RawDownload
// Copyright 2026 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::TestResult; use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir;use crate::common::create_commit_with_files;use crate::common::force_interactive; // `jj converge` must runs successfully when there are no divergent changes and// prints a message to stderr.#[test]fn test_converge_no_divergence() {    let test_env = TestEnvironment::default();    test_env.run_jj_in(".", ["git", "init", "repo"]).success();    let work_dir = test_env.work_dir("repo");     // Set up commit graph (without divergent changes)    create_commit_with_files(&work_dir, "a", &[], &[("file1", "a")]);    create_commit_with_files(&work_dir, "b", &["a"], &[("file2", "b")]);    create_commit_with_files(&work_dir, "c", &["a"], &[("file3", "c")]);     // Test the setup    insta::assert_snapshot!(get_long_log_output(&work_dir), @r"    @  c  royxmykx  78dcec21 - description: c    │ ○  b  zsuskuln  056564da - description: b    ├─╯    ○  a  rlvkpnrz  3b93fc14 - description: a    ◆    zzzzzzzz  00000000    [EOF]    ");     // Run `jj converge` command and check the output.    let output = work_dir.run_jj(["converge"]).success();    insta::assert_snapshot!(output, @r"    ------- stderr -------    No divergent changes found.    [EOF]    ");} // A simple `jj converge` scenario where there is a single divergent change with// two visible commits. In this setup no user input is required.#[test]fn test_converge_simple() {    let test_env = TestEnvironment::default();    test_env.run_jj_in(".", ["git", "init", "repo"]).success();    let work_dir = test_env.work_dir("repo");     // Set up commit graph with one divergent change (with two visible commits).    create_commit_with_files(&work_dir, "a", &[], &[("file1", "1")]);    create_commit_with_files(&work_dir, "b2", &["a"], &[("file2", "2")]);    create_commit_with_files(&work_dir, "c", &["a"], &[("file3", "3")]);    work_dir.run_jj(["rebase", "-r", "b2", "-o", "c"]).success();    work_dir        .run_jj(["bookmark", "create", "b1", "-r", "at_operation(@-, b2)"])        .success();    create_commit_with_files(&work_dir, "d", &["b1"], &[("file4", "4")]);     // Test the setup: look at the commit graph, commit B is duplicated    insta::assert_snapshot!(get_long_log_output(&work_dir), @r"    @  d  znkkpsqq  bf5126ef - description: d    ○  b1  zsuskuln/1  59a77004 - description: b2    │ ○  b2  zsuskuln/0  2c2bd25d - description: b2    │ ○  c  royxmykx  4343fc61 - description: c    ├─╯    ○  a  rlvkpnrz  e9a731d9 - description: a    ◆    zzzzzzzz  00000000    [EOF]    ");     // Test the setup: look at the evolog    insta::assert_snapshot!(get_evolog(&work_dir, "b2"), @r"    ○  zsuskuln/0 2c2bd25d (divergent) b2    ○  zsuskuln/1 59a77004 (divergent) b2    ○  zsuskuln/2 b2852eb2 (hidden) (empty) b2    [EOF]    ");     // Run `jj converge` command and check the output. In this case no user input is    // needed.    let output = work_dir.run_jj(["converge"]).success();    insta::assert_snapshot!(output, @r"    ------- stderr -------    Found 1 divergent change(s) in the specified revset:    - Change: zsuskulnrvyr with 2 commits:        zsuskuln/0 2c2bd25d b2 | (divergent) b2        zsuskuln/1 59a77004 b1 | (divergent) b2     Attempting to converge change zsuskulnrvyr...     Successfully converged change: created commit 6b1ce5bc4cbe.    Rebased 1 descendants    Working copy  (@) now at: znkkpsqq 696cf5e0 d | d    Parent commit (@-)      : zsuskuln 6b1ce5bc b1 b2 | b2    Added 1 files, modified 0 files, removed 0 files    [EOF]    ");     // Verify the commit graph after converge    insta::assert_snapshot!(get_long_log_output(&work_dir), @r"    @  d  znkkpsqq  696cf5e0 - description: d    ○  b1 b2  zsuskuln  6b1ce5bc - description: b2    ○  c  royxmykx  4343fc61 - description: c    ○  a  rlvkpnrz  e9a731d9 - description: a    ◆    zzzzzzzz  00000000    [EOF]    ");     // Verify the evolution history after converge    insta::assert_snapshot!(get_evolog(&work_dir, "b2"), @r"    ○    zsuskuln 6b1ce5bc b2    ├─╮    ○ │  zsuskuln/1 2c2bd25d (hidden) b2    ├─╯    ○  zsuskuln/2 59a77004 (hidden) b2    ○  zsuskuln/3 b2852eb2 (hidden) (empty) b2    [EOF]    ");} // When there are multiple divergent changes, the command must prompt the user// to select one of them. When running in non-interactive mode (jj converge// --no-interactive) this is not possible.#[test]fn test_converge_two_divergent_changes_in_non_interactive_mode() {    let test_env = TestEnvironment::default();    test_env.run_jj_in(".", ["git", "init", "repo"]).success();    let work_dir = test_env.work_dir("repo");     // Set up: first create a base commit    create_commit_with_files(&work_dir, "a", &[], &[("file1", "1")]);     // Set up: create commit graph with two divergent changes    // First divergent change:    create_commit_with_files(&work_dir, "b2", &["a"], &[("file2", "2")]);    create_commit_with_files(&work_dir, "c", &["a"], &[("file3", "3")]);    work_dir.run_jj(["rebase", "-r", "b2", "-o", "c"]).success();    work_dir        .run_jj(["bookmark", "create", "b1", "-r", "at_operation(@-, b2)"])        .success();    create_commit_with_files(&work_dir, "d", &["b1"], &[("file4", "4")]);     // Second divergent change:    create_commit_with_files(&work_dir, "e2", &["a"], &[("file5", "5")]);    create_commit_with_files(&work_dir, "f", &["a"], &[("file6", "6")]);    work_dir.run_jj(["rebase", "-r", "e2", "-o", "f"]).success();    work_dir        .run_jj(["bookmark", "create", "e1", "-r", "at_operation(@-, e2)"])        .success();    create_commit_with_files(&work_dir, "g", &["e1"], &[("file7", "7")]);     // Test the setup: look at the commit graph (commit B is duplicated and commit E    // is duplicated)    insta::assert_snapshot!(get_long_log_output(&work_dir), @r"    @  g  xznxytkn  46658cae - description: g    ○  e1  kmkuslsw/1  15962bae - description: e2    │ ○  e2  kmkuslsw/0  b54f15d8 - description: e2    │ ○  f  lylxulpl  d50e2761 - description: f    ├─╯    │ ○  b2  zsuskuln/0  2c2bd25d - description: b2    │ ○  c  royxmykx  4343fc61 - description: c    ├─╯    │ ○  d  znkkpsqq  bf5126ef - description: d    │ ○  b1  zsuskuln/1  59a77004 - description: b2    ├─╯    ○  a  rlvkpnrz  e9a731d9 - description: a    ◆    zzzzzzzz  00000000    [EOF]    ");     // Pass --non-interactive to jj converge command.    let output =        work_dir.run_jj_with(|cmd| force_interactive(cmd).args(["converge", "--no-interactive"]));    insta::assert_snapshot!(output, @r"    ------- stderr -------    Found 2 divergent change(s) in the specified revset:    - Change: zsuskulnrvyr with 2 commits:        zsuskuln/0 2c2bd25d b2 | (divergent) b2        zsuskuln/1 59a77004 b1 | (divergent) b2     - Change: kmkuslswpqwq with 2 commits:        kmkuslsw/0 b54f15d8 e2 | (divergent) e2        kmkuslsw/1 15962bae e1 | (divergent) e2     Error: Cannot automatically choose which change to converge    Hint: Run `jj converge` in interactive mode, or specify a revset that resolves to only one change ID    [EOF]    [exit status: 1]    ");     // Note: in the test environment jj commands run in non-interactive (quiet) mode    // by default, so the following also fails but for a different reason: it    // cannot prompt the user    let output = work_dir.run_jj(["converge"]);    insta::assert_snapshot!(output, @r"    ------- stderr -------    Found 2 divergent change(s) in the specified revset:    - Change: zsuskulnrvyr with 2 commits:        zsuskuln/0 2c2bd25d b2 | (divergent) b2        zsuskuln/1 59a77004 b1 | (divergent) b2     - Change: kmkuslswpqwq with 2 commits:        kmkuslsw/0 b54f15d8 e2 | (divergent) e2        kmkuslsw/1 15962bae e1 | (divergent) e2     Choose which change to converge (jj converge only converges one change at a time):    1: zsuskulnrvyr    2: kmkuslswpqwq    q: abort    Error: Cannot prompt for input since the output is not connected to a terminal    [EOF]    [exit status: 1]    ");     // Note: the invocation also fails if stdin is not connected to a terminal    let output = work_dir.run_jj_with(|cmd| force_interactive(cmd).args(["converge"]));    insta::assert_snapshot!(output, @r"    ------- stderr -------    Found 2 divergent change(s) in the specified revset:    - Change: zsuskulnrvyr with 2 commits:        zsuskuln/0 2c2bd25d b2 | (divergent) b2        zsuskuln/1 59a77004 b1 | (divergent) b2     - Change: kmkuslswpqwq with 2 commits:        kmkuslsw/0 b54f15d8 e2 | (divergent) e2        kmkuslsw/1 15962bae e1 | (divergent) e2     Choose which change to converge (jj converge only converges one change at a time):    1: zsuskulnrvyr    2: kmkuslswpqwq    q: abort    Enter the index of the change to converge: Error: Prompt canceled by EOF    [EOF]    [exit status: 1]    ");} // This tests scenarios where there are two divergent changes. The command// prompts the user to choose which change to converge.#[test]fn test_converge_two_divergent_changes() {    let test_env = TestEnvironment::default();    test_env.run_jj_in(".", ["git", "init", "repo"]).success();    let work_dir = test_env.work_dir("repo");     // Set up: first create a base commit    create_commit_with_files(&work_dir, "a", &[], &[("file1", "1")]);     // Set up: create commit graph with two divergent changes    // First divergent change:    create_commit_with_files(&work_dir, "b2", &["a"], &[("file2", "2")]);    create_commit_with_files(&work_dir, "c", &["a"], &[("file3", "3")]);    work_dir.run_jj(["rebase", "-r", "b2", "-o", "c"]).success();    work_dir        .run_jj(["bookmark", "create", "b1", "-r", "at_operation(@-, b2)"])        .success();    create_commit_with_files(&work_dir, "d", &["b1"], &[("file4", "4")]);     // Second divergent change:    create_commit_with_files(&work_dir, "e2", &["a"], &[("file5", "5")]);    create_commit_with_files(&work_dir, "f", &["a"], &[("file6", "6")]);    work_dir.run_jj(["rebase", "-r", "e2", "-o", "f"]).success();    work_dir        .run_jj(["bookmark", "create", "e1", "-r", "at_operation(@-, e2)"])        .success();    create_commit_with_files(&work_dir, "g", &["e1"], &[("file7", "7")]);     // Test the setup: look at the commit graph (commit B is duplicated and commit E    // is duplicated)    insta::assert_snapshot!(get_long_log_output(&work_dir), @r"    @  g  xznxytkn  46658cae - description: g    ○  e1  kmkuslsw/1  15962bae - description: e2    │ ○  e2  kmkuslsw/0  b54f15d8 - description: e2    │ ○  f  lylxulpl  d50e2761 - description: f    ├─╯    │ ○  b2  zsuskuln/0  2c2bd25d - description: b2    │ ○  c  royxmykx  4343fc61 - description: c    ├─╯    │ ○  d  znkkpsqq  bf5126ef - description: d    │ ○  b1  zsuskuln/1  59a77004 - description: b2    ├─╯    ○  a  rlvkpnrz  e9a731d9 - description: a    ◆    zzzzzzzz  00000000    [EOF]    ");     // Test the setup: look at the evolog    insta::assert_snapshot!(get_evolog(&work_dir, "b2"), @r"    ○  zsuskuln/0 2c2bd25d (divergent) b2    ○  zsuskuln/1 59a77004 (divergent) b2    ○  zsuskuln/2 b2852eb2 (hidden) (empty) b2    [EOF]    ");     // Test the setup: look at the evolog    insta::assert_snapshot!(get_evolog(&work_dir, "e2"), @r"    ○  kmkuslsw/0 b54f15d8 (divergent) e2    ○  kmkuslsw/1 15962bae (divergent) e2    ○  kmkuslsw/2 843de29d (hidden) (empty) e2    [EOF]    ");     // If the user chooses to abort the converge operation nothing changes.    let output = work_dir        .run_jj_with(|cmd| force_interactive(cmd).args(["converge"]).write_stdin("q\n"))        .success();     insta::assert_snapshot!(output, @r"    ------- stderr -------    Found 2 divergent change(s) in the specified revset:    - Change: zsuskulnrvyr with 2 commits:        zsuskuln/0 2c2bd25d b2 | (divergent) b2        zsuskuln/1 59a77004 b1 | (divergent) b2     - Change: kmkuslswpqwq with 2 commits:        kmkuslsw/0 b54f15d8 e2 | (divergent) e2        kmkuslsw/1 15962bae e1 | (divergent) e2     Choose which change to converge (jj converge only converges one change at a time):    1: zsuskulnrvyr    2: kmkuslswpqwq    q: abort    Enter the index of the change to converge:      Aborting... nothing changed.    [EOF]    ");     // Run the command again, this time the user chooses the first divergent change.    // This invocation succeeds to automatically converge that change. A hint is    // printed to inform the user that there is still one divergent change    // remaining.    let output = work_dir        .run_jj_with(|cmd| force_interactive(cmd).args(["converge"]).write_stdin("1\n"))        .success();     insta::assert_snapshot!(output, @r"    ------- stderr -------    Found 2 divergent change(s) in the specified revset:    - Change: zsuskulnrvyr with 2 commits:        zsuskuln/0 2c2bd25d b2 | (divergent) b2        zsuskuln/1 59a77004 b1 | (divergent) b2     - Change: kmkuslswpqwq with 2 commits:        kmkuslsw/0 b54f15d8 e2 | (divergent) e2        kmkuslsw/1 15962bae e1 | (divergent) e2     Choose which change to converge (jj converge only converges one change at a time):    1: zsuskulnrvyr    2: kmkuslswpqwq    q: abort    Enter the index of the change to converge:      Attempting to converge change zsuskulnrvyr...     Successfully converged change: created commit ba447f020ee6.    Rebased 1 descendants    Hint: There are still 1 divergent changes remaining in the specified revset, you can run this command again to converge another one.    [EOF]    ");     // Verify the commit graph after converging the first divergent change    insta::assert_snapshot!(get_long_log_output(&work_dir), @r"    @  g  xznxytkn  46658cae - description: g    ○  e1  kmkuslsw/1  15962bae - description: e2    │ ○  e2  kmkuslsw/0  b54f15d8 - description: e2    │ ○  f  lylxulpl  d50e2761 - description: f    ├─╯    │ ○  d  znkkpsqq  b30d892b - description: d    │ ○  b1 b2  zsuskuln  ba447f02 - description: b2    │ ○  c  royxmykx  4343fc61 - description: c    ├─╯    ○  a  rlvkpnrz  e9a731d9 - description: a    ◆    zzzzzzzz  00000000    [EOF]    ");     // Verify the evolution history after converging the first divergent change    insta::assert_snapshot!(get_evolog(&work_dir, "b2"), @r"    ○    zsuskuln ba447f02 b2    ├─╮    ○ │  zsuskuln/1 2c2bd25d (hidden) b2    ├─╯    ○  zsuskuln/2 59a77004 (hidden) b2    ○  zsuskuln/3 b2852eb2 (hidden) (empty) b2    [EOF]    ");     // Run converge a second time to converge the other divergent change    let output = work_dir.run_jj(["converge"]).success();    insta::assert_snapshot!(output, @r"    ------- stderr -------    Found 1 divergent change(s) in the specified revset:    - Change: kmkuslswpqwq with 2 commits:        kmkuslsw/0 b54f15d8 e2 | (divergent) e2        kmkuslsw/1 15962bae e1 | (divergent) e2     Attempting to converge change kmkuslswpqwq...     Successfully converged change: created commit 3f08d00a88c4.    Rebased 1 descendants    Working copy  (@) now at: xznxytkn f9fd4e7e g | g    Parent commit (@-)      : kmkuslsw 3f08d00a e1 e2 | e2    Added 1 files, modified 0 files, removed 0 files    [EOF]    ");     // Verify the commit graph after converging the second divergent change    insta::assert_snapshot!(get_long_log_output(&work_dir), @r"    @  g  xznxytkn  f9fd4e7e - description: g    ○  e1 e2  kmkuslsw  3f08d00a - description: e2    ○  f  lylxulpl  d50e2761 - description: f    │ ○  d  znkkpsqq  b30d892b - description: d    │ ○  b1 b2  zsuskuln  ba447f02 - description: b2    │ ○  c  royxmykx  4343fc61 - description: c    ├─╯    ○  a  rlvkpnrz  e9a731d9 - description: a    ◆    zzzzzzzz  00000000    [EOF]    ");     // Verify the evolution history after converging the second divergent change    insta::assert_snapshot!(get_evolog(&work_dir, "e2"), @r"    ○    kmkuslsw 3f08d00a e2    ├─╮    ○ │  kmkuslsw/1 b54f15d8 (hidden) e2    ├─╯    ○  kmkuslsw/2 15962bae (hidden) e2    ○  kmkuslsw/3 843de29d (hidden) (empty) e2    [EOF]    ");     // There are no more divergent changes now    let output = work_dir.run_jj(["converge"]).success();    insta::assert_snapshot!(output, @r"    ------- stderr -------    No divergent changes found.    [EOF]    ");} // This tests scenarios where the user specifies revisions to converge. More// precisely, the user specifies a revset that is used as the search space for// divergent commits.#[test]fn test_converge_simple_with_revisions_arg() {    let test_env = TestEnvironment::default();    test_env.run_jj_in(".", ["git", "init", "repo"]).success();    let work_dir = test_env.work_dir("repo");     // Set up commit graph with divergent changes    create_commit_with_files(&work_dir, "a", &[], &[("file1", "1")]);    create_commit_with_files(&work_dir, "b2", &["a"], &[("file2", "2")]);    create_commit_with_files(&work_dir, "c", &["a"], &[("file3", "3")]);    work_dir.run_jj(["rebase", "-r", "b2", "-o", "c"]).success();    work_dir        .run_jj(["bookmark", "create", "b1", "-r", "at_operation(@-, b2)"])        .success();    create_commit_with_files(&work_dir, "d", &["b1"], &[("file4", "4")]);     // Test the setup (commit B is duplicated)    insta::assert_snapshot!(get_long_log_output(&work_dir), @r"    @  d  znkkpsqq  bf5126ef - description: d    ○  b1  zsuskuln/1  59a77004 - description: b2    │ ○  b2  zsuskuln/0  2c2bd25d - description: b2    │ ○  c  royxmykx  4343fc61 - description: c    ├─╯    ○  a  rlvkpnrz  e9a731d9 - description: a    ◆    zzzzzzzz  00000000    [EOF]    ");     insta::assert_snapshot!(get_evolog(&work_dir, "b2"), @r"    ○  zsuskuln/0 2c2bd25d (divergent) b2    ○  zsuskuln/1 59a77004 (divergent) b2    ○  zsuskuln/2 b2852eb2 (hidden) (empty) b2    [EOF]    ");     // `-r a::d` resolves to {a, b1, d}. b1 IS a divergent commit, but in that    // revset there are no other commits with that change-id, so by design the    // command does nothing (we could change that in the future).    let output = work_dir.run_jj(["converge", "-r", "a::d"]).success();    insta::assert_snapshot!(output, @r"    ------- stderr -------

Lines 1–500 of 1631.