// 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 crate::common::TestEnvironment;use crate::common::create_commit_with_files; #[test]fn test_file_delete() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); create_commit_with_files( &work_dir, "base", &[], &[ ("file", "base\n"), ("dir/a", "a\n"), ("dir/b", "b\n"), ("notes.txt", "notes\n"), ("data.txt", "data\n"), ("keep", "keep\n"), ], ); // The child doesn't touch `file`, so it inherits its deletion from `base`. create_commit_with_files(&work_dir, "child", &["base"], &[("other", "child\n")]); let setup_opid = work_dir.current_operation_id(); // The file is deleted from the revision, and descendants are rebased. let output = work_dir.run_jj(["file", "delete", "-r=base", "file"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Rebased 1 descendant commits. Working copy (@) now at: zsuskuln 69c03f6b child | child Parent commit (@-) : rlvkpnrz 0f03ba3b base | base Added 0 files, modified 0 files, removed 1 files [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=base"]).normalize_backslash(), @r" data.txt dir/a dir/b keep notes.txt [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=child"]).normalize_backslash(), @r" data.txt dir/a dir/b keep notes.txt other [EOF] "); // With --restore-descendants, descendants keep their content. work_dir.run_jj(["op", "restore", &setup_opid]).success(); let output = work_dir.run_jj(["file", "delete", "-r=base", "--restore-descendants", "file"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Rebased 1 descendant commits (while preserving their content). Working copy (@) now at: zsuskuln 178385e9 child | child Parent commit (@-) : rlvkpnrz 53605aea base | base [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=base"]).normalize_backslash(), @r" data.txt dir/a dir/b keep notes.txt [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=child"]).normalize_backslash(), @r" data.txt dir/a dir/b file keep notes.txt other [EOF] "); // Multiple paths, directories, and filesets can be deleted at once work_dir.run_jj(["op", "restore", &setup_opid]).success(); let output = work_dir.run_jj(["file", "delete", "-r=base", "file", "dir", "glob:*.txt"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Rebased 1 descendant commits. Working copy (@) now at: zsuskuln ea53444d child | child Parent commit (@-) : rlvkpnrz dce80445 base | base Added 0 files, modified 0 files, removed 5 files [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=base"]), @r" keep [EOF] "); // Unmatched paths are reported, but matched paths are still deleted work_dir.run_jj(["op", "restore", &setup_opid]).success(); let output = work_dir.run_jj(["file", "delete", "-r=base", "file", "nonexistent"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No matching entries for paths: nonexistent Rebased 1 descendant commits. Working copy (@) now at: zsuskuln 1ac20d8f child | child Parent commit (@-) : rlvkpnrz 5676c4df base | base Added 0 files, modified 0 files, removed 1 files [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=base"]).normalize_backslash(), @r" data.txt dir/a dir/b keep notes.txt [EOF] "); // Nothing happens if no paths match work_dir.run_jj(["op", "restore", &setup_opid]).success(); let opid = work_dir.current_operation_id(); let output = work_dir.run_jj(["file", "delete", "-r=base", "nonexistent"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No matching entries for paths: nonexistent Nothing changed. [EOF] "); assert_eq!(work_dir.current_operation_id(), opid);} #[test]fn test_file_delete_conflict() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); create_commit_with_files(&work_dir, "base", &[], &[("file", "base\n")]); create_commit_with_files(&work_dir, "left", &["base"], &[("file", "left\n")]); create_commit_with_files(&work_dir, "right", &["base"], &[("file", "right\n")]); create_commit_with_files(&work_dir, "conflict", &["left", "right"], &[]); work_dir.run_jj(["new", "conflict"]).success(); // Deleting a conflicted file removes the conflict let output = work_dir.run_jj(["file", "delete", "-r=conflict", "file"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Rebased 1 descendant commits. Working copy (@) now at: znkkpsqq 59c14e97 (empty) (no description set) Parent commit (@-) : vruxwmqv 06df9ed5 conflict | conflict Added 0 files, modified 0 files, removed 1 files [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["debug", "tree", "-r=conflict"]), @"");}
// 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 crate::common::TestEnvironment;
use crate::common::create_commit_with_files;
#[test]
fn test_file_delete() {
let test_env = TestEnvironment::default();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
create_commit_with_files(
&work_dir,
"base",
&[],
&[
("file", "base\n"),
("dir/a", "a\n"),
("dir/b", "b\n"),
("notes.txt", "notes\n"),
("data.txt", "data\n"),
("keep", "keep\n"),
],
);
// The child doesn't touch `file`, so it inherits its deletion from `base`.
create_commit_with_files(&work_dir, "child", &["base"], &[("other", "child\n")]);
let setup_opid = work_dir.current_operation_id();
// The file is deleted from the revision, and descendants are rebased.
let output = work_dir.run_jj(["file", "delete", "-r=base", "file"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
Rebased 1 descendant commits.
Working copy (@) now at: zsuskuln 69c03f6b child | child
Parent commit (@-) : rlvkpnrz 0f03ba3b base | base
Added 0 files, modified 0 files, removed 1 files
[EOF]
");
insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=base"]).normalize_backslash(), @r"
data.txt
dir/a
dir/b
keep
notes.txt
[EOF]
");
insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=child"]).normalize_backslash(), @r"
data.txt
dir/a
dir/b
keep
notes.txt
other
[EOF]
");
// With --restore-descendants, descendants keep their content.
work_dir.run_jj(["op", "restore", &setup_opid]).success();
let output = work_dir.run_jj(["file", "delete", "-r=base", "--restore-descendants", "file"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
Rebased 1 descendant commits (while preserving their content).
Working copy (@) now at: zsuskuln 178385e9 child | child
Parent commit (@-) : rlvkpnrz 53605aea base | base
[EOF]
");
insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=base"]).normalize_backslash(), @r"
data.txt
dir/a
dir/b
keep
notes.txt
[EOF]
");
insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=child"]).normalize_backslash(), @r"
data.txt
dir/a
dir/b
file
keep
notes.txt
other
[EOF]
");
// Multiple paths, directories, and filesets can be deleted at once
work_dir.run_jj(["op", "restore", &setup_opid]).success();
let output = work_dir.run_jj(["file", "delete", "-r=base", "file", "dir", "glob:*.txt"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
Rebased 1 descendant commits.
Working copy (@) now at: zsuskuln ea53444d child | child
Parent commit (@-) : rlvkpnrz dce80445 base | base
Added 0 files, modified 0 files, removed 5 files
[EOF]
");
insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=base"]), @r"
keep
[EOF]
");
// Unmatched paths are reported, but matched paths are still deleted
work_dir.run_jj(["op", "restore", &setup_opid]).success();
let output = work_dir.run_jj(["file", "delete", "-r=base", "file", "nonexistent"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
Warning: No matching entries for paths: nonexistent
Rebased 1 descendant commits.
Working copy (@) now at: zsuskuln 1ac20d8f child | child
Parent commit (@-) : rlvkpnrz 5676c4df base | base
Added 0 files, modified 0 files, removed 1 files
[EOF]
");
insta::assert_snapshot!(work_dir.run_jj(["file", "list", "-r=base"]).normalize_backslash(), @r"
data.txt
dir/a
dir/b
keep
notes.txt
[EOF]
");
// Nothing happens if no paths match
work_dir.run_jj(["op", "restore", &setup_opid]).success();
let opid = work_dir.current_operation_id();
let output = work_dir.run_jj(["file", "delete", "-r=base", "nonexistent"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
Warning: No matching entries for paths: nonexistent
Nothing changed.
[EOF]
");
assert_eq!(work_dir.current_operation_id(), opid);
}
#[test]
fn test_file_delete_conflict() {
let test_env = TestEnvironment::default();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
create_commit_with_files(&work_dir, "base", &[], &[("file", "base\n")]);
create_commit_with_files(&work_dir, "left", &["base"], &[("file", "left\n")]);
create_commit_with_files(&work_dir, "right", &["base"], &[("file", "right\n")]);
create_commit_with_files(&work_dir, "conflict", &["left", "right"], &[]);
work_dir.run_jj(["new", "conflict"]).success();
// Deleting a conflicted file removes the conflict
let output = work_dir.run_jj(["file", "delete", "-r=conflict", "file"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
Rebased 1 descendant commits.
Working copy (@) now at: znkkpsqq 59c14e97 (empty) (no description set)
Parent commit (@-) : vruxwmqv 06df9ed5 conflict | conflict
Added 0 files, modified 0 files, removed 1 files
[EOF]
");
insta::assert_snapshot!(work_dir.run_jj(["debug", "tree", "-r=conflict"]), @"");
}