Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cli: add global --ignore-immutable #3578

Merged
merged 1 commit into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* You can check whether Watchman fsmonitor is enabled or installed with the new
`jj debug watchman status` command.

* A new global flag `--ignore-immutable` lets you rewrite immutable commits.

### Fixed bugs

* Revsets now support `\`-escapes in string literal.
Expand Down
23 changes: 22 additions & 1 deletion cli/src/cli_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,17 @@ impl WorkspaceCommandHelper {
&self,
commits: impl IntoIterator<Item = &'a CommitId>,
) -> Result<(), CommandError> {
if self.global_args.ignore_immutable {
let root_id = self.repo().store().root_commit_id();
return if commits.into_iter().contains(root_id) {
Err(user_error(format!(
"The root commit {} is immutable",
short_commit_hash(root_id),
)))
} else {
Ok(())
};
}
let to_rewrite_revset =
RevsetExpression::commits(commits.into_iter().cloned().collect_vec());
let immutable = revset_util::parse_immutable_expression(&self.revset_parse_context())
Expand All @@ -1087,7 +1098,7 @@ impl WorkspaceCommandHelper {
} else {
user_error_with_hint(
format!("Commit {} is immutable", short_commit_hash(&commit_id)),
"Configure the set of immutable commits via \
"Pass `--ignore-immutable` or configure the set of immutable commits via \
`revset-aliases.immutable_heads()`.",
)
};
Expand Down Expand Up @@ -2330,6 +2341,16 @@ pub struct GlobalArgs {
/// implies `--ignore-working-copy`.
#[arg(long, global = true)]
pub ignore_working_copy: bool,
/// Don't prevent rewriting immutable commits
///
/// By default, Jujutsu prevents rewriting commits in the configured set of
/// immutable commits. This option disables that check and lets you rewrite
/// any commit but the root commit.
///
/// This option only affects the check. It does not affect the
/// `immutable_heads()` revset or the `immutable` template keyword.
#[arg(long, global = true)]
pub ignore_immutable: bool,
/// Operation to load the repo at
///
/// Operation to load the repo at. By default, Jujutsu loads the repo at the
Expand Down
4 changes: 4 additions & 0 deletions cli/tests/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ To get started, see the tutorial at https://github.com/martinvonz/jj/blob/main/d

Possible values: `true`, `false`

* `--ignore-immutable` — Don't prevent rewriting immutable commits

Possible values: `true`, `false`

* `--at-operation <AT_OPERATION>` — Operation to load the repo at

Default value: `@`
Expand Down
1 change: 1 addition & 0 deletions cli/tests/test_global_opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ fn test_help() {
Global Options:
-R, --repository <REPOSITORY> Path to repository to operate on
--ignore-working-copy Don't snapshot the working copy, and don't update it
--ignore-immutable Don't prevent rewriting immutable commits
--at-operation <AT_OPERATION> Operation to load the repo at [default: @] [aliases: at-op]
--debug Enable debug logging
--color <WHEN> When to colorize output (always, never, auto)
Expand Down
61 changes: 38 additions & 23 deletions cli/tests/test_immutable_commits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ fn test_rewrite_immutable_generic() {
let stderr = test_env.jj_cmd_failure(&repo_path, &["edit", "main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit c8d4c7ca95d0 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// Cannot rewrite an ancestor of the configured set
let stderr = test_env.jj_cmd_failure(&repo_path, &["edit", "main-"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 46a8dc5175be is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// Cannot rewrite the root commit even with an empty set of immutable commits
test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#);
Expand All @@ -67,6 +67,22 @@ fn test_rewrite_immutable_generic() {
For help, see https://github.com/martinvonz/jj/blob/main/docs/config.md.
"###);

// Can use --ignore-immutable to override
test_env.add_config(r#"revset-aliases."immutable_heads()" = "main""#);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["--ignore-immutable", "edit", "main"]);
insta::assert_snapshot!(stdout, @r###"
"###);
insta::assert_snapshot!(stderr, @r###"
Working copy now at: kkmpptxz c8d4c7ca main | b
Parent commit : qpvuntsm 46a8dc51 a
Added 0 files, modified 1 files, removed 0 files
"###);
// ... but not the root commit
let stderr = test_env.jj_cmd_failure(&repo_path, &["--ignore-immutable", "edit", "root()"]);
insta::assert_snapshot!(stderr, @r###"
Error: The root commit 000000000000 is immutable
"###);

// Mutating the repo works if ref is wrapped in present()
test_env.add_config(
r#"revset-aliases."immutable_heads()" = "present(branch_that_does_not_exist)""#,
Expand All @@ -75,9 +91,8 @@ fn test_rewrite_immutable_generic() {
insta::assert_snapshot!(stdout, @r###"
"###);
insta::assert_snapshot!(stderr, @r###"
Working copy now at: kpqxywon dbce15b4 (empty) (no description set)
Working copy now at: wqnwkozp de8b93b4 (empty) (no description set)
Parent commit : kkmpptxz c8d4c7ca main | b
Added 0 files, modified 1 files, removed 0 files
"###);

// Error if we redefine immutable_heads() with an argument
Expand Down Expand Up @@ -130,118 +145,118 @@ fn test_rewrite_immutable_commands() {
let stderr = test_env.jj_cmd_failure(&repo_path, &["abandon", "main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// chmod
let stderr = test_env.jj_cmd_failure(&repo_path, &["chmod", "-r=main", "x", "file"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// describe
let stderr = test_env.jj_cmd_failure(&repo_path, &["describe", "main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// diffedit
let stderr = test_env.jj_cmd_failure(&repo_path, &["diffedit", "-r=main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// edit
let stderr = test_env.jj_cmd_failure(&repo_path, &["edit", "main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// move --from
let stderr = test_env.jj_cmd_failure(&repo_path, &["move", "--from=main"]);
insta::assert_snapshot!(stderr, @r###"
Warning: `jj move` is deprecated; use `jj squash` instead, which is equivalent
Warning: `jj move` will be removed in a future version, and this will be a hard error
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// move --to
let stderr = test_env.jj_cmd_failure(&repo_path, &["move", "--to=main"]);
insta::assert_snapshot!(stderr, @r###"
Warning: `jj move` is deprecated; use `jj squash` instead, which is equivalent
Warning: `jj move` will be removed in a future version, and this will be a hard error
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// new --insert-before
let stderr = test_env.jj_cmd_failure(&repo_path, &["new", "--insert-before", "main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// new --insert-after parent_of_main
let stderr = test_env.jj_cmd_failure(&repo_path, &["new", "--insert-after", "description(b)"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// parallelize
let stderr = test_env.jj_cmd_failure(&repo_path, &["parallelize", "description(b)", "main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// rebase -s
let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-s=main", "-d=@"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// rebase -b
let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-b=main", "-d=@"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 6e11f430f297 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// rebase -r
let stderr = test_env.jj_cmd_failure(&repo_path, &["rebase", "-r=main", "-d=@"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// resolve
let stderr = test_env.jj_cmd_failure(&repo_path, &["resolve", "-r=description(merge)", "file"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// restore -c
let stderr = test_env.jj_cmd_failure(&repo_path, &["restore", "-c=main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// restore --to
let stderr = test_env.jj_cmd_failure(&repo_path, &["restore", "--to=main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// split
let stderr = test_env.jj_cmd_failure(&repo_path, &["split", "-r=main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// squash
let stderr = test_env.jj_cmd_failure(&repo_path, &["squash", "-r=description(b)"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit c8d4c7ca95d0 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
// unsquash
let stderr = test_env.jj_cmd_failure(&repo_path, &["unsquash", "-r=main"]);
insta::assert_snapshot!(stderr, @r###"
Error: Commit 406c181c04d8 is immutable
Hint: Configure the set of immutable commits via `revset-aliases.immutable_heads()`.
Hint: Pass `--ignore-immutable` or configure the set of immutable commits via `revset-aliases.immutable_heads()`.
"###);
}