mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-16 09:11:55 +00:00
a6ef3f0b6c
This adds a new `revset-aliases.immutable_heads()s` config for defining the set of immutable commits. The set is defined as the configured revset, as well as its ancestors, and the root commit commit (even if the configured set is empty). This patch also adds enforcement of the config where we already had checks preventing rewrite of the root commit. The working-copy commit is implicitly assumed to be writable in most cases. Specifically, we won't prevent amending the working copy even if the user includes it in the config but we do prevent `jj edit @` in that case. That seems good enough to me. Maybe we should emit a warning when the working copy is in the set of immutable commits. Maybe we should add support for something more like [Mercurial's phases](https://wiki.mercurial-scm.org/Phases), which is propagated on push and pull. There's already some affordance for that in the view object's `public_heads` field. However, this is simpler, especially since we can't propagate the phase to Git remotes, and seems like a good start. Also, it lets you say that commits authored by other users are immutable, for example. For now, the functionality is in the CLI library. I'm not sure if we want to move it into the library crate. I'm leaning towards letting library users do whatever they want without being restricted by immutable commits. I do think we should move the functionality into a future `ui-lib` or `ui-util` crate. That crate would have most of the functionality in the current `cli_util` module (but in a non-CLI-specific form).
112 lines
4.4 KiB
Rust
112 lines
4.4 KiB
Rust
// 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_edit() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
|
|
let repo_path = test_env.env_root().join("repo");
|
|
std::fs::write(repo_path.join("file1"), "0").unwrap();
|
|
test_env.jj_cmd_success(&repo_path, &["commit", "-m", "first"]);
|
|
test_env.jj_cmd_success(&repo_path, &["describe", "-m", "second"]);
|
|
std::fs::write(repo_path.join("file1"), "1").unwrap();
|
|
|
|
// Errors out without argument
|
|
let stderr = test_env.jj_cmd_cli_error(&repo_path, &["edit"]);
|
|
insta::assert_snapshot!(stderr, @r###"
|
|
error: the following required arguments were not provided:
|
|
<REVISION>
|
|
|
|
Usage: jj edit <REVISION>
|
|
|
|
For more information, try '--help'.
|
|
"###);
|
|
|
|
// Makes the specified commit the working-copy commit
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["edit", "@-"]);
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
Working copy now at: qpvuntsm f41390a5 first
|
|
Parent commit : zzzzzzzz 00000000 (empty) (no description set)
|
|
Added 0 files, modified 1 files, removed 0 files
|
|
"###);
|
|
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
|
◉ b2f7e9c549aa second
|
|
@ f41390a5efbf first
|
|
◉ 000000000000
|
|
"###);
|
|
insta::assert_snapshot!(read_file(&repo_path.join("file1")), @"0");
|
|
|
|
// Changes in the working copy are amended into the commit
|
|
std::fs::write(repo_path.join("file2"), "0").unwrap();
|
|
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
|
Rebased 1 descendant commits onto updated working copy
|
|
◉ 51d937a3eeb4 second
|
|
@ 409306de8f44 first
|
|
◉ 000000000000
|
|
"###);
|
|
}
|
|
|
|
#[test]
|
|
// Windows says "Access is denied" when trying to delete the object file.
|
|
#[cfg(unix)]
|
|
fn test_edit_current_wc_commit_missing() {
|
|
use crate::common::get_stderr_string;
|
|
|
|
// Test that we get a reasonable error message when the current working-copy
|
|
// commit is missing
|
|
let test_env = TestEnvironment::default();
|
|
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
|
|
let repo_path = test_env.env_root().join("repo");
|
|
test_env.jj_cmd_success(&repo_path, &["commit", "-m", "first"]);
|
|
test_env.jj_cmd_success(&repo_path, &["describe", "-m", "second"]);
|
|
test_env.jj_cmd_success(&repo_path, &["edit", "@-"]);
|
|
|
|
let wc_id = test_env.jj_cmd_success(&repo_path, &["log", "--no-graph", "-T=commit_id", "-r=@"]);
|
|
let wc_child_id =
|
|
test_env.jj_cmd_success(&repo_path, &["log", "--no-graph", "-T=commit_id", "-r=@+"]);
|
|
// Make the Git backend fail to read the current working copy commit
|
|
let commit_object_path = repo_path
|
|
.join(".jj")
|
|
.join("repo")
|
|
.join("store")
|
|
.join("git")
|
|
.join("objects")
|
|
.join(&wc_id[..2])
|
|
.join(&wc_id[2..]);
|
|
std::fs::remove_file(commit_object_path).unwrap();
|
|
|
|
// Pass --ignore-working-copy to avoid triggering the error at snapshot time
|
|
let assert = test_env
|
|
.jj_cmd(&repo_path, &["edit", "--ignore-working-copy", &wc_child_id])
|
|
.assert()
|
|
.code(255);
|
|
insta::assert_snapshot!(get_stderr_string(&assert), @r###"
|
|
Internal error: Failed to edit a commit: Current working-copy commit not found: Object 69542c1984c1f9d91f7c6c9c9e6941782c944bd9 of type commit not found: object not found - no match for id (69542c1984c1f9d91f7c6c9c9e6941782c944bd9); class=Odb (9); code=NotFound (-3)
|
|
"###);
|
|
}
|
|
|
|
fn read_file(path: &Path) -> String {
|
|
String::from_utf8(std::fs::read(path).unwrap()).unwrap()
|
|
}
|
|
|
|
fn get_log_output(test_env: &TestEnvironment, cwd: &Path) -> String {
|
|
let template = r#"commit_id.short() ++ " " ++ description"#;
|
|
test_env.jj_cmd_success(cwd, &["log", "-T", template])
|
|
}
|