mirror of
https://github.com/martinvonz/jj.git
synced 2024-09-11 05:45:30 +03:00
squash: learn --from/--into
flags
This was proposed by @Brixy in https://github.com/martinvonz/jj/discussions/2882 a while ago. There seems to be pretty strong consensus that it's a good idea. I've copied the added test cases from `test_move_command.rs`, just replacing `move` by `squash`, `--to` by `--into`, and deleting the test of a no-arg invocation (`jj move` fails, `jj squash` does not - it defaults to squashing into the parent).
This commit is contained in:
parent
b6655049bc
commit
e6ef217d90
@ -18,6 +18,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
* Graph node symbols are now configurable via `ui.graph.default_node` and `ui.graph.elided_node`.
|
||||
|
||||
* `jj squash` now accepts `--from` and `--into` (mutually exclusive with `-r`).
|
||||
It can thereby be for all use cases where `jj move` can be used.
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
## [0.15.1] - 2024-03-06
|
||||
|
@ -26,12 +26,20 @@ use crate::command_error::{user_error, CommandError};
|
||||
use crate::description_util::{combine_messages, join_message_paragraphs};
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Move changes from a revision into its parent
|
||||
/// Move changes from a revision into another revision
|
||||
///
|
||||
/// After moving the changes into the parent, the child revision will have the
|
||||
/// same content state as before. If that means that the change is now empty
|
||||
/// compared to its parent, it will be abandoned.
|
||||
/// Without `--interactive`, the child change will always be empty.
|
||||
/// With the `-r` option, moves the changes from the specified revision to the
|
||||
/// parent revision. Fails if there are several parent revisions (i.e., the
|
||||
/// given revision is a merge).
|
||||
///
|
||||
/// With the `--from` and/or `--into` options, moves changes from/to the given
|
||||
/// revisions. If either is left out, it defaults to the working-copy commit.
|
||||
/// For example, `jj squash --into @--` moves changes from the working-copy
|
||||
/// commit to the grandparent.
|
||||
///
|
||||
/// If, after moving changes out, the source revision is empty compared to its
|
||||
/// parent(s), it will be abandoned. Without `--interactive`, the source
|
||||
/// revision will always be empty.
|
||||
///
|
||||
/// If the source became empty and both the source and destination had a
|
||||
/// non-empty description, you will be asked for the combined description. If
|
||||
@ -44,6 +52,12 @@ pub(crate) struct SquashArgs {
|
||||
/// Revision to squash into its parent (default: @)
|
||||
#[arg(long, short)]
|
||||
revision: Option<RevisionArg>,
|
||||
/// Revision to squash from (default: @)
|
||||
#[arg(long, conflicts_with = "revision")]
|
||||
from: Option<RevisionArg>,
|
||||
/// Revision to squash into (default: @)
|
||||
#[arg(long, conflicts_with = "revision")]
|
||||
into: Option<RevisionArg>,
|
||||
/// The description to use for squashed revision (don't open editor)
|
||||
#[arg(long = "message", short, value_name = "MESSAGE")]
|
||||
message_paragraphs: Vec<String>,
|
||||
@ -65,12 +79,24 @@ pub(crate) fn cmd_squash(
|
||||
args: &SquashArgs,
|
||||
) -> Result<(), CommandError> {
|
||||
let mut workspace_command = command.workspace_helper(ui)?;
|
||||
let source = workspace_command.resolve_single_rev(args.revision.as_deref().unwrap_or("@"))?;
|
||||
let mut parents = source.parents();
|
||||
if parents.len() != 1 {
|
||||
return Err(user_error("Cannot squash merge commits"));
|
||||
|
||||
let source;
|
||||
let destination;
|
||||
if args.from.is_some() || args.into.is_some() {
|
||||
source = workspace_command.resolve_single_rev(args.from.as_deref().unwrap_or("@"))?;
|
||||
destination = workspace_command.resolve_single_rev(args.into.as_deref().unwrap_or("@"))?;
|
||||
if source.id() == destination.id() {
|
||||
return Err(user_error("Source and destination cannot be the same"));
|
||||
}
|
||||
} else {
|
||||
source = workspace_command.resolve_single_rev(args.revision.as_deref().unwrap_or("@"))?;
|
||||
let mut parents = source.parents();
|
||||
if parents.len() != 1 {
|
||||
return Err(user_error("Cannot squash merge commits"));
|
||||
}
|
||||
destination = parents.pop().unwrap();
|
||||
}
|
||||
let destination = parents.pop().unwrap();
|
||||
|
||||
let matcher = workspace_command.matcher_from_values(&args.paths)?;
|
||||
let diff_selector =
|
||||
workspace_command.diff_selector(ui, args.tool.as_deref(), args.interactive)?;
|
||||
@ -87,7 +113,7 @@ pub(crate) fn cmd_squash(
|
||||
matcher.as_ref(),
|
||||
&diff_selector,
|
||||
description,
|
||||
args.revision.is_none(),
|
||||
args.revision.is_none() && args.from.is_none() && args.into.is_none(),
|
||||
&args.paths,
|
||||
)?;
|
||||
tx.finish(ui, tx_description)?;
|
||||
|
@ -133,7 +133,7 @@ repository.
|
||||
* `show` — Show commit description and changes in a revision
|
||||
* `sparse` — Manage which paths from the working-copy commit are present in the working copy
|
||||
* `split` — Split a revision in two
|
||||
* `squash` — Move changes from a revision into its parent
|
||||
* `squash` — Move changes from a revision into another revision
|
||||
* `status` — Show high-level repo status
|
||||
* `tag` — Manage tags
|
||||
* `util` — Infrequently used commands such as for generating shell completions
|
||||
@ -1684,9 +1684,13 @@ If the change you split had a description, you will be asked to enter a change d
|
||||
|
||||
## `jj squash`
|
||||
|
||||
Move changes from a revision into its parent
|
||||
Move changes from a revision into another revision
|
||||
|
||||
After moving the changes into the parent, the child revision will have the same content state as before. If that means that the change is now empty compared to its parent, it will be abandoned. Without `--interactive`, the child change will always be empty.
|
||||
With the `-r` option, moves the changes from the specified revision to the parent revision. Fails if there are several parent revisions (i.e., the given revision is a merge).
|
||||
|
||||
With the `--from` and/or `--into` options, moves changes from/to the given revisions. If either is left out, it defaults to the working-copy commit. For example, `jj squash --into @--` moves changes from the working-copy commit to the grandparent.
|
||||
|
||||
If, after moving changes out, the source revision is empty compared to its parent(s), it will be abandoned. Without `--interactive`, the source revision will always be empty.
|
||||
|
||||
If the source became empty and both the source and destination had a non-empty description, you will be asked for the combined description. If either was empty, then the other one will be used.
|
||||
|
||||
@ -1701,6 +1705,8 @@ If a working-copy commit gets abandoned, it will be given a new, empty commit. T
|
||||
###### **Options:**
|
||||
|
||||
* `-r`, `--revision <REVISION>` — Revision to squash into its parent (default: @)
|
||||
* `--from <FROM>` — Revision to squash from (default: @)
|
||||
* `--into <INTO>` — Revision to squash into (default: @)
|
||||
* `-m`, `--message <MESSAGE>` — The description to use for squashed revision (don't open editor)
|
||||
* `-i`, `--interactive` — Interactively choose which parts to squash
|
||||
|
||||
|
@ -264,6 +264,324 @@ fn test_squash_partial() {
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_squash_from_to() {
|
||||
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");
|
||||
|
||||
// Create history like this:
|
||||
// F
|
||||
// |
|
||||
// E C
|
||||
// | |
|
||||
// D B
|
||||
// |/
|
||||
// A
|
||||
//
|
||||
// When moving changes between e.g. C and F, we should not get unrelated changes
|
||||
// from B and D.
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "a"]);
|
||||
std::fs::write(repo_path.join("file1"), "a\n").unwrap();
|
||||
std::fs::write(repo_path.join("file2"), "a\n").unwrap();
|
||||
std::fs::write(repo_path.join("file3"), "a\n").unwrap();
|
||||
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "b"]);
|
||||
std::fs::write(repo_path.join("file3"), "b\n").unwrap();
|
||||
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "c"]);
|
||||
std::fs::write(repo_path.join("file1"), "c\n").unwrap();
|
||||
test_env.jj_cmd_ok(&repo_path, &["edit", "a"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "d"]);
|
||||
std::fs::write(repo_path.join("file3"), "d\n").unwrap();
|
||||
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "e"]);
|
||||
std::fs::write(repo_path.join("file2"), "e\n").unwrap();
|
||||
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "f"]);
|
||||
std::fs::write(repo_path.join("file2"), "f\n").unwrap();
|
||||
// Test the setup
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ 0d7353584003 f
|
||||
◉ e9515f21068c e
|
||||
◉ bdd835cae844 d
|
||||
│ ◉ caa4d0b23201 c
|
||||
│ ◉ 55171e33db26 b
|
||||
├─╯
|
||||
◉ 3db0a2f5b535 a
|
||||
◉ 000000000000
|
||||
"###);
|
||||
|
||||
// Errors out if source and destination are the same
|
||||
let stderr = test_env.jj_cmd_failure(&repo_path, &["squash", "--into", "@"]);
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Error: Source and destination cannot be the same
|
||||
"###);
|
||||
|
||||
// Can squash from sibling, which results in the source being abandoned
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "c"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Working copy now at: kmkuslsw 5337fca9 f | (no description set)
|
||||
Parent commit : znkkpsqq e9515f21 e | (no description set)
|
||||
Added 0 files, modified 1 files, removed 0 files
|
||||
"###);
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ 5337fca918e8 f
|
||||
◉ e9515f21068c e
|
||||
◉ bdd835cae844 d
|
||||
│ ◉ 55171e33db26 b c
|
||||
├─╯
|
||||
◉ 3db0a2f5b535 a
|
||||
◉ 000000000000
|
||||
"###);
|
||||
// The change from the source has been applied
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
c
|
||||
"###);
|
||||
// File `file2`, which was not changed in source, is unchanged
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
f
|
||||
"###);
|
||||
|
||||
// Can squash from ancestor
|
||||
test_env.jj_cmd_ok(&repo_path, &["undo"]);
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "@--"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Working copy now at: kmkuslsw 66ff309f f | (no description set)
|
||||
Parent commit : znkkpsqq 16f4e7c4 e | (no description set)
|
||||
"###);
|
||||
// The change has been removed from the source (the change pointed to by 'd'
|
||||
// became empty and was abandoned)
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ 66ff309f65e8 f
|
||||
◉ 16f4e7c4886f e
|
||||
│ ◉ caa4d0b23201 c
|
||||
│ ◉ 55171e33db26 b
|
||||
├─╯
|
||||
◉ 3db0a2f5b535 a d
|
||||
◉ 000000000000
|
||||
"###);
|
||||
// The change from the source has been applied (the file contents were already
|
||||
// "f", as is typically the case when moving changes from an ancestor)
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
f
|
||||
"###);
|
||||
|
||||
// Can squash from descendant
|
||||
test_env.jj_cmd_ok(&repo_path, &["undo"]);
|
||||
let (stdout, stderr) =
|
||||
test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "e", "--into", "d"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Rebased 1 descendant commits
|
||||
Working copy now at: kmkuslsw b4f8051d f | (no description set)
|
||||
Parent commit : vruxwmqv f74c102f d e | (no description set)
|
||||
"###);
|
||||
// The change has been removed from the source (the change pointed to by 'e'
|
||||
// became empty and was abandoned)
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ b4f8051d8466 f
|
||||
◉ f74c102ff29a d e
|
||||
│ ◉ caa4d0b23201 c
|
||||
│ ◉ 55171e33db26 b
|
||||
├─╯
|
||||
◉ 3db0a2f5b535 a
|
||||
◉ 000000000000
|
||||
"###);
|
||||
// The change from the source has been applied
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "d"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
e
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_squash_from_to_partial() {
|
||||
let mut 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");
|
||||
|
||||
// Create history like this:
|
||||
// C
|
||||
// |
|
||||
// D B
|
||||
// |/
|
||||
// A
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "a"]);
|
||||
std::fs::write(repo_path.join("file1"), "a\n").unwrap();
|
||||
std::fs::write(repo_path.join("file2"), "a\n").unwrap();
|
||||
std::fs::write(repo_path.join("file3"), "a\n").unwrap();
|
||||
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "b"]);
|
||||
std::fs::write(repo_path.join("file3"), "b\n").unwrap();
|
||||
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "c"]);
|
||||
std::fs::write(repo_path.join("file1"), "c\n").unwrap();
|
||||
std::fs::write(repo_path.join("file2"), "c\n").unwrap();
|
||||
test_env.jj_cmd_ok(&repo_path, &["edit", "a"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
||||
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "d"]);
|
||||
std::fs::write(repo_path.join("file3"), "d\n").unwrap();
|
||||
// Test the setup
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ bdd835cae844 d
|
||||
│ ◉ 5028db694b6b c
|
||||
│ ◉ 55171e33db26 b
|
||||
├─╯
|
||||
◉ 3db0a2f5b535 a
|
||||
◉ 000000000000
|
||||
"###);
|
||||
|
||||
let edit_script = test_env.set_up_fake_diff_editor();
|
||||
|
||||
// If we don't make any changes in the diff-editor, the whole change is moved
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "-i", "--from", "c"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Working copy now at: vruxwmqv 71b69e43 d | (no description set)
|
||||
Parent commit : qpvuntsm 3db0a2f5 a | (no description set)
|
||||
Added 0 files, modified 2 files, removed 0 files
|
||||
"###);
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ 71b69e433fbc d
|
||||
│ ◉ 55171e33db26 b c
|
||||
├─╯
|
||||
◉ 3db0a2f5b535 a
|
||||
◉ 000000000000
|
||||
"###);
|
||||
// The changes from the source has been applied
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
c
|
||||
"###);
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
c
|
||||
"###);
|
||||
// File `file3`, which was not changed in source, is unchanged
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file3"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
d
|
||||
"###);
|
||||
|
||||
// Can squash only part of the change in interactive mode
|
||||
test_env.jj_cmd_ok(&repo_path, &["undo"]);
|
||||
std::fs::write(&edit_script, "reset file2").unwrap();
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "-i", "--from", "c"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Working copy now at: vruxwmqv 63f1a6e9 d | (no description set)
|
||||
Parent commit : qpvuntsm 3db0a2f5 a | (no description set)
|
||||
Added 0 files, modified 1 files, removed 0 files
|
||||
"###);
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ 63f1a6e96edb d
|
||||
│ ◉ d027c6e3e6bc c
|
||||
│ ◉ 55171e33db26 b
|
||||
├─╯
|
||||
◉ 3db0a2f5b535 a
|
||||
◉ 000000000000
|
||||
"###);
|
||||
// The selected change from the source has been applied
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
c
|
||||
"###);
|
||||
// The unselected change from the source has not been applied
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
a
|
||||
"###);
|
||||
// File `file3`, which was changed in source's parent, is unchanged
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file3"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
d
|
||||
"###);
|
||||
|
||||
// Can squash only part of the change from a sibling in non-interactive mode
|
||||
test_env.jj_cmd_ok(&repo_path, &["undo"]);
|
||||
// Clear the script so we know it won't be used
|
||||
std::fs::write(&edit_script, "").unwrap();
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "c", "file1"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Working copy now at: vruxwmqv 17c2e663 d | (no description set)
|
||||
Parent commit : qpvuntsm 3db0a2f5 a | (no description set)
|
||||
Added 0 files, modified 1 files, removed 0 files
|
||||
"###);
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ 17c2e6632cc5 d
|
||||
│ ◉ 6a3ae047a03e c
|
||||
│ ◉ 55171e33db26 b
|
||||
├─╯
|
||||
◉ 3db0a2f5b535 a
|
||||
◉ 000000000000
|
||||
"###);
|
||||
// The selected change from the source has been applied
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
c
|
||||
"###);
|
||||
// The unselected change from the source has not been applied
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
a
|
||||
"###);
|
||||
// File `file3`, which was changed in source's parent, is unchanged
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file3"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
d
|
||||
"###);
|
||||
|
||||
// Can squash only part of the change from a descendant in non-interactive mode
|
||||
test_env.jj_cmd_ok(&repo_path, &["undo"]);
|
||||
// Clear the script so we know it won't be used
|
||||
std::fs::write(&edit_script, "").unwrap();
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(
|
||||
&repo_path,
|
||||
&["squash", "--from", "c", "--into", "b", "file1"],
|
||||
);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Rebased 1 descendant commits
|
||||
"###);
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
◉ 21253406d416 c
|
||||
◉ e1cf08aae711 b
|
||||
│ @ bdd835cae844 d
|
||||
├─╯
|
||||
◉ 3db0a2f5b535 a
|
||||
◉ 000000000000
|
||||
"###);
|
||||
// The selected change from the source has been applied
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file1", "-r", "b"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
c
|
||||
"###);
|
||||
// The unselected change from the source has not been applied
|
||||
let stdout = test_env.jj_cmd_success(&repo_path, &["print", "file2", "-r", "b"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
a
|
||||
"###);
|
||||
|
||||
// If we specify only a non-existent file, then the move still succeeds and
|
||||
// creates unchanged commits.
|
||||
test_env.jj_cmd_ok(&repo_path, &["undo"]);
|
||||
let (stdout, stderr) =
|
||||
test_env.jj_cmd_ok(&repo_path, &["squash", "--from", "c", "nonexistent"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Working copy now at: vruxwmqv b670567d d | (no description set)
|
||||
Parent commit : qpvuntsm 3db0a2f5 a | (no description set)
|
||||
"###);
|
||||
}
|
||||
|
||||
fn get_log_output(test_env: &TestEnvironment, repo_path: &Path) -> String {
|
||||
let template = r#"commit_id.short() ++ " " ++ branches"#;
|
||||
test_env.jj_cmd_success(repo_path, &["log", "-T", template])
|
||||
|
Loading…
Reference in New Issue
Block a user