// 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::fmt::Write as _;use std::path::Path; use testutils::TestResult;use testutils::git; use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir; #[test]fn test_git_colocated() -> TestResult { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); let git_repo = git::init(work_dir.root()); // Create an initial commit in Git let tree_id = git::add_commit( &git_repo, "refs/heads/master", "file", b"contents", "initial", &[], ) .tree_id; git::checkout_tree_index(&git_repo, tree_id); assert_eq!(work_dir.read_file("file"), b"contents"); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); // Import the repo work_dir .run_jj(["git", "init", "--git-repo", "."]) .success(); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 524826059adc6f74de30f6be8f8eb86715d75b62 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master initial ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 97358f54806c7cd005ed5ade68a779595efbae7e [EOF] "); // Modify the working copy. The working-copy commit should changed, but the Git // HEAD commit should not work_dir.write_file("file", "modified"); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 9dfe8c7005c8dff6078ecdfd953c6bfddc633c90 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master initial ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 97358f54806c7cd005ed5ade68a779595efbae7e [EOF] "); // Create a new change from jj and check that it's reflected in Git work_dir.run_jj(["new"]).success(); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 4ddddef596e9d68f729f1be9e1b2cdaaf45bef08 ○ 9dfe8c7005c8dff6078ecdfd953c6bfddc633c90 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master initial ◆ 0000000000000000000000000000000000000000 [EOF] "); assert!(git_repo.head()?.is_detached()); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"9dfe8c7005c8dff6078ecdfd953c6bfddc633c90" ); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 9dfe8c7005c8dff6078ecdfd953c6bfddc633c90 [EOF] "); Ok(())} #[test]fn test_git_colocated_intent_to_add() -> TestResult { let test_env = TestEnvironment::default(); test_env .run_jj_in(".", ["git", "init", "--colocate", "repo"]) .success(); let work_dir = test_env.work_dir("repo"); // A file added directly on top of the root commit should be marked as // intent-to-add work_dir.write_file("file1.txt", "contents"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @"Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file1.txt"); // Previously, this would fail due to the empty blob not being written to the // store when marking files as intent-to-add. work_dir.run_jj(["util", "gc"]).success(); // Another new file should be marked as intent-to-add work_dir.run_jj(["new"]).success(); work_dir.write_file("file2.txt", "contents"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file2.txt "); let op_id_new_file = work_dir.current_operation_id(); // After creating a new commit, it should not longer be marked as intent-to-add work_dir.run_jj(["new"]).success(); work_dir.write_file("file2.txt", "contents"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file2.txt "); // If we edit an existing commit, new files are marked as intent-to-add work_dir.run_jj(["edit", "@-"]).success(); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file2.txt "); // If we remove the added file, it's removed from the index work_dir.remove_file("file2.txt"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @"Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt"); // If we untrack the file, it's removed from the index work_dir .run_jj(["op", "restore", op_id_new_file.as_str()]) .success(); work_dir.write_file(".gitignore", "file2.txt"); work_dir.run_jj(["file", "untrack", "file2.txt"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 .gitignore Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt "); Ok(())} #[test]fn test_git_colocated_new_wc_commit_when_wc_immutable() { let test_env = TestEnvironment::default(); test_env .run_jj_in(".", ["git", "init", "--colocate", "repo"]) .success(); let work_dir = test_env.work_dir("repo"); // Create Git HEAD commit work_dir.write_file("file1", "a\n"); work_dir.run_jj(["new"]).success(); // Prepare working copy that will become immutable work_dir.write_file("file2", "b\n"); work_dir .run_jj(["bookmark", "create", "-r@", "main"]) .success(); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: eb7b8a1f02b8d0915290e1163a3526bfa4e417fa [EOF] "); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 78981922613b ctime=0:0 mtime=0:0 size=0 flags=0 file1 Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file2 "); // Make the working copy immutable and snapshot changes test_env.add_config(r#"revset-aliases."immutable_heads()" = "main""#); work_dir.write_file("file2", "b\nc\n"); work_dir.write_file("file3", "d\n"); let output = work_dir.run_jj(["status"]); insta::assert_snapshot!(output, @" Working copy changes: M file2 A file3 Working copy (@) : mzvwutvl d1b1d7e9 (no description set) Parent commit (@-): rlvkpnrz 1d3e40a3 main | (no description set) [EOF] ------- stderr ------- Warning: The working-copy commit is immutable; a new commit has been created on top of it. [EOF] "); // New working-copy commit is created, and the Git HEAD should be updated let output = work_dir.run_jj(["log", "-r..", "--summary"]); insta::assert_snapshot!(output, @" @ mzvwutvl test.user@example.com 2001-02-03 08:05:11 d1b1d7e9 │ (no description set) │ M file2 │ A file3 ◆ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 main 1d3e40a3 │ (no description set) │ A file2 ◆ qpvuntsm test.user@example.com 2001-02-03 08:05:08 eb7b8a1f │ (no description set) ~ A file1 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 1d3e40a35156c275f7a535fdaa50cb5882d500eb [EOF] "); // file3 should be marked as "intent-to-add" insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 78981922613b ctime=0:0 mtime=0:0 size=0 flags=0 file1 Unconflicted Mode(FILE) 61780798228d ctime=0:0 mtime=0:0 size=0 flags=0 file2 Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file3 ");} #[test]fn test_git_colocated_update_stale_resets_git_head() { let test_env = TestEnvironment::default(); test_env .run_jj_in(".", ["git", "init", "--colocate", "repo"]) .success(); let work_dir = test_env.work_dir("repo"); // A "parent" commit and a "child" working-copy commit on top work_dir.write_file("file1", "a\n"); work_dir.run_jj(["describe", "-m", "parent"]).success(); work_dir.run_jj(["new", "-m", "child"]).success(); work_dir.write_file("file2", "b\n"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: df69548750502d54d6f207b500d25da43ed6fe1e [EOF] "); // From another workspace, amend "parent" directly: this rebases "child" // and makes the default (colocated) workspace stale work_dir .run_jj(["workspace", "add", "--name", "second", "../secondary"]) .success(); let secondary_dir = test_env.work_dir("secondary"); secondary_dir .run_jj(["edit", r#"subject(parent)"#]) .success(); secondary_dir.write_file("file1", "a\nmodified\n"); secondary_dir.run_jj(["status"]).success(); let output = work_dir.run_jj(["workspace", "update-stale"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: kkmpptxz 422aac81 child Parent commit (@-) : qpvuntsm 239acdab parent Added 0 files, modified 1 files, removed 0 files Updated working copy to fresh commit 422aac811963 [EOF] "); // Git HEAD should point to the amended "parent", not the stale one insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 239acdab88e2b438ed43a99471a385d3832190ec [EOF] "); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 76b5eb87f1cb ctime=0:0 mtime=0:0 size=0 flags=0 file1 Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file2 ");} #[test]fn test_git_colocated_unborn_bookmark() -> TestResult { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); let git_repo = git::init(work_dir.root()); // add a file to an (in memory) index let add_file_to_index = |name: &str, data: &str| { let mut index_manager = git::IndexManager::new(&git_repo); index_manager.add_file(name, data.as_bytes()); index_manager.sync_index(); }; // checkout index (i.e., drop the in-memory changes) let checkout_index = || { let mut index = git_repo.open_index().unwrap(); let objects = git_repo.objects.clone(); gix::worktree::state::checkout( &mut index, git_repo.workdir().unwrap(), objects, &gix::progress::Discard, &gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED, gix::worktree::state::checkout::Options::default(), ) .unwrap(); }; // Initially, HEAD isn't set. work_dir .run_jj(["git", "init", "--git-repo", "."]) .success(); assert!(git_repo.head()?.is_unborn()); assert_eq!( git_repo.head_name()?.unwrap().as_bstr(), b"refs/heads/master" ); insta::assert_snapshot!(get_log_output(&work_dir), @" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: (none) [EOF] "); // Stage some change, and check out root. This shouldn't clobber the HEAD. add_file_to_index("file0", ""); let output = work_dir.run_jj(["new", "root()"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: zsuskuln c2934cfb (empty) (no description set) Parent commit (@-) : zzzzzzzz 00000000 (empty) (no description set) Added 0 files, modified 0 files, removed 1 files [EOF] "); assert!(git_repo.head()?.is_unborn()); assert_eq!( git_repo.head_name()?.unwrap().as_bstr(), b"refs/heads/master" ); insta::assert_snapshot!(get_log_output(&work_dir), @" @ c2934cfbfb196d2c473959667beffcc19e71e5e8 │ ○ e6669bb3438ef218fa618e1047a1911d2b3410dd ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: (none) [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @" The working copy has no changes. Working copy (@) : zsuskuln c2934cfb (empty) (no description set) Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) [EOF] "); // Stage some change, and create new HEAD. This shouldn't move the default // bookmark. add_file_to_index("file1", ""); let output = work_dir.run_jj(["new"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: vruxwmqv 2d7a8abb (empty) (no description set) Parent commit (@-) : zsuskuln ff536684 (no description set) [EOF] "); assert!(git_repo.head()?.is_detached()); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"ff5366846b039b25c6c4998fa74dca821c246243" ); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 2d7a8abb601ebf559df4037279e9f2e851a75e63 ○ ff5366846b039b25c6c4998fa74dca821c246243 │ ○ e6669bb3438ef218fa618e1047a1911d2b3410dd ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: ff5366846b039b25c6c4998fa74dca821c246243 [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @" The working copy has no changes. Working copy (@) : vruxwmqv 2d7a8abb (empty) (no description set) Parent commit (@-): zsuskuln ff536684 (no description set) [EOF] "); // Assign the default bookmark. The bookmark is no longer "unborn". work_dir .run_jj(["bookmark", "create", "-r@-", "master"]) .success(); // Stage some change, and check out root again. This should unset the HEAD. // https://github.com/jj-vcs/jj/issues/1495 add_file_to_index("file2", ""); let output = work_dir.run_jj(["new", "root()"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: wqnwkozp 88e8407a (empty) (no description set) Parent commit (@-) : zzzzzzzz 00000000 (empty) (no description set) Added 0 files, modified 0 files, removed 2 files [EOF] "); assert!(git_repo.head()?.is_unborn()); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 88e8407a4f0a5e6f40a7c6c494106764adc00fed │ ○ 2dd7385602e703388fd266b939bba6f57a1439d3 │ ○ ff5366846b039b25c6c4998fa74dca821c246243 master ├─╯ │ ○ e6669bb3438ef218fa618e1047a1911d2b3410dd ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: (none) [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @" The working copy has no changes. Working copy (@) : wqnwkozp 88e8407a (empty) (no description set) Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) [EOF] "); // New snapshot and commit can be created after the HEAD got unset. work_dir.write_file("file3", ""); let output = work_dir.run_jj(["new"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: uyznsvlq 2fb16499 (empty) (no description set) Parent commit (@-) : wqnwkozp bb21bc2d (no description set) [EOF] "); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 2fb16499a987e632407402e38976ed250c939c42 ○ bb21bc2dce2af92973fdd6d42686d77bd16bc466 │ ○ 2dd7385602e703388fd266b939bba6f57a1439d3 │ ○ ff5366846b039b25c6c4998fa74dca821c246243 master ├─╯ │ ○ e6669bb3438ef218fa618e1047a1911d2b3410dd ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: bb21bc2dce2af92973fdd6d42686d77bd16bc466 [EOF] "); Ok(())} #[test]fn test_git_colocated_export_bookmarks_on_snapshot() -> TestResult { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); let git_repo = git::init(work_dir.root()); work_dir .run_jj(["git", "init", "--git-repo", "."]) .success(); Lines 1–500 of 1988. Load more
// 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::fmt::Write as _; use std::path::Path; use testutils::TestResult; use testutils::git; use crate::common::CommandOutput; use crate::common::TestEnvironment; use crate::common::TestWorkDir; #[test] fn test_git_colocated() -> TestResult { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); let git_repo = git::init(work_dir.root()); // Create an initial commit in Git let tree_id = git::add_commit( &git_repo, "refs/heads/master", "file", b"contents", "initial", &[], ) .tree_id; git::checkout_tree_index(&git_repo, tree_id); assert_eq!(work_dir.read_file("file"), b"contents"); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); // Import the repo work_dir .run_jj(["git", "init", "--git-repo", "."]) .success(); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 524826059adc6f74de30f6be8f8eb86715d75b62 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master initial ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 97358f54806c7cd005ed5ade68a779595efbae7e [EOF] "); // Modify the working copy. The working-copy commit should changed, but the Git // HEAD commit should not work_dir.write_file("file", "modified"); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 9dfe8c7005c8dff6078ecdfd953c6bfddc633c90 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master initial ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 97358f54806c7cd005ed5ade68a779595efbae7e [EOF] "); // Create a new change from jj and check that it's reflected in Git work_dir.run_jj(["new"]).success(); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 4ddddef596e9d68f729f1be9e1b2cdaaf45bef08 ○ 9dfe8c7005c8dff6078ecdfd953c6bfddc633c90 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master initial ◆ 0000000000000000000000000000000000000000 [EOF] "); assert!(git_repo.head()?.is_detached()); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"9dfe8c7005c8dff6078ecdfd953c6bfddc633c90" ); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 9dfe8c7005c8dff6078ecdfd953c6bfddc633c90 [EOF] "); Ok(()) } #[test] fn test_git_colocated_intent_to_add() -> TestResult { let test_env = TestEnvironment::default(); test_env .run_jj_in(".", ["git", "init", "--colocate", "repo"]) .success(); let work_dir = test_env.work_dir("repo"); // A file added directly on top of the root commit should be marked as // intent-to-add work_dir.write_file("file1.txt", "contents"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @"Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file1.txt"); // Previously, this would fail due to the empty blob not being written to the // store when marking files as intent-to-add. work_dir.run_jj(["util", "gc"]).success(); // Another new file should be marked as intent-to-add work_dir.run_jj(["new"]).success(); work_dir.write_file("file2.txt", "contents"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file2.txt "); let op_id_new_file = work_dir.current_operation_id(); // After creating a new commit, it should not longer be marked as intent-to-add work_dir.run_jj(["new"]).success(); work_dir.write_file("file2.txt", "contents"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file2.txt "); // If we edit an existing commit, new files are marked as intent-to-add work_dir.run_jj(["edit", "@-"]).success(); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file2.txt "); // If we remove the added file, it's removed from the index work_dir.remove_file("file2.txt"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @"Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt"); // If we untrack the file, it's removed from the index work_dir .run_jj(["op", "restore", op_id_new_file.as_str()]) .success(); work_dir.write_file(".gitignore", "file2.txt"); work_dir.run_jj(["file", "untrack", "file2.txt"]).success(); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 .gitignore Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt "); Ok(()) } #[test] fn test_git_colocated_new_wc_commit_when_wc_immutable() { let test_env = TestEnvironment::default(); test_env .run_jj_in(".", ["git", "init", "--colocate", "repo"]) .success(); let work_dir = test_env.work_dir("repo"); // Create Git HEAD commit work_dir.write_file("file1", "a\n"); work_dir.run_jj(["new"]).success(); // Prepare working copy that will become immutable work_dir.write_file("file2", "b\n"); work_dir .run_jj(["bookmark", "create", "-r@", "main"]) .success(); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: eb7b8a1f02b8d0915290e1163a3526bfa4e417fa [EOF] "); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 78981922613b ctime=0:0 mtime=0:0 size=0 flags=0 file1 Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file2 "); // Make the working copy immutable and snapshot changes test_env.add_config(r#"revset-aliases."immutable_heads()" = "main""#); work_dir.write_file("file2", "b\nc\n"); work_dir.write_file("file3", "d\n"); let output = work_dir.run_jj(["status"]); insta::assert_snapshot!(output, @" Working copy changes: M file2 A file3 Working copy (@) : mzvwutvl d1b1d7e9 (no description set) Parent commit (@-): rlvkpnrz 1d3e40a3 main | (no description set) [EOF] ------- stderr ------- Warning: The working-copy commit is immutable; a new commit has been created on top of it. [EOF] "); // New working-copy commit is created, and the Git HEAD should be updated let output = work_dir.run_jj(["log", "-r..", "--summary"]); insta::assert_snapshot!(output, @" @ mzvwutvl test.user@example.com 2001-02-03 08:05:11 d1b1d7e9 │ (no description set) │ M file2 │ A file3 ◆ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 main 1d3e40a3 │ (no description set) │ A file2 ◆ qpvuntsm test.user@example.com 2001-02-03 08:05:08 eb7b8a1f │ (no description set) ~ A file1 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 1d3e40a35156c275f7a535fdaa50cb5882d500eb [EOF] "); // file3 should be marked as "intent-to-add" insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 78981922613b ctime=0:0 mtime=0:0 size=0 flags=0 file1 Unconflicted Mode(FILE) 61780798228d ctime=0:0 mtime=0:0 size=0 flags=0 file2 Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file3 "); } #[test] fn test_git_colocated_update_stale_resets_git_head() { let test_env = TestEnvironment::default(); test_env .run_jj_in(".", ["git", "init", "--colocate", "repo"]) .success(); let work_dir = test_env.work_dir("repo"); // A "parent" commit and a "child" working-copy commit on top work_dir.write_file("file1", "a\n"); work_dir.run_jj(["describe", "-m", "parent"]).success(); work_dir.run_jj(["new", "-m", "child"]).success(); work_dir.write_file("file2", "b\n"); work_dir.run_jj(["status"]).success(); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: df69548750502d54d6f207b500d25da43ed6fe1e [EOF] "); // From another workspace, amend "parent" directly: this rebases "child" // and makes the default (colocated) workspace stale work_dir .run_jj(["workspace", "add", "--name", "second", "../secondary"]) .success(); let secondary_dir = test_env.work_dir("secondary"); secondary_dir .run_jj(["edit", r#"subject(parent)"#]) .success(); secondary_dir.write_file("file1", "a\nmodified\n"); secondary_dir.run_jj(["status"]).success(); let output = work_dir.run_jj(["workspace", "update-stale"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: kkmpptxz 422aac81 child Parent commit (@-) : qpvuntsm 239acdab parent Added 0 files, modified 1 files, removed 0 files Updated working copy to fresh commit 422aac811963 [EOF] "); // Git HEAD should point to the amended "parent", not the stale one insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: 239acdab88e2b438ed43a99471a385d3832190ec [EOF] "); insta::assert_snapshot!(get_index_state(work_dir.root()), @" Unconflicted Mode(FILE) 76b5eb87f1cb ctime=0:0 mtime=0:0 size=0 flags=0 file1 Unconflicted Mode(FILE) e69de29bb2d1 ctime=0:0 mtime=0:0 size=0 flags=20004000 file2 "); } #[test] fn test_git_colocated_unborn_bookmark() -> TestResult { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); let git_repo = git::init(work_dir.root()); // add a file to an (in memory) index let add_file_to_index = |name: &str, data: &str| { let mut index_manager = git::IndexManager::new(&git_repo); index_manager.add_file(name, data.as_bytes()); index_manager.sync_index(); }; // checkout index (i.e., drop the in-memory changes) let checkout_index = || { let mut index = git_repo.open_index().unwrap(); let objects = git_repo.objects.clone(); gix::worktree::state::checkout( &mut index, git_repo.workdir().unwrap(), objects, &gix::progress::Discard, &gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED, gix::worktree::state::checkout::Options::default(), ) .unwrap(); }; // Initially, HEAD isn't set. work_dir .run_jj(["git", "init", "--git-repo", "."]) .success(); assert!(git_repo.head()?.is_unborn()); assert_eq!( git_repo.head_name()?.unwrap().as_bstr(), b"refs/heads/master" ); insta::assert_snapshot!(get_log_output(&work_dir), @" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: (none) [EOF] "); // Stage some change, and check out root. This shouldn't clobber the HEAD. add_file_to_index("file0", ""); let output = work_dir.run_jj(["new", "root()"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: zsuskuln c2934cfb (empty) (no description set) Parent commit (@-) : zzzzzzzz 00000000 (empty) (no description set) Added 0 files, modified 0 files, removed 1 files [EOF] "); assert!(git_repo.head()?.is_unborn()); assert_eq!( git_repo.head_name()?.unwrap().as_bstr(), b"refs/heads/master" ); insta::assert_snapshot!(get_log_output(&work_dir), @" @ c2934cfbfb196d2c473959667beffcc19e71e5e8 │ ○ e6669bb3438ef218fa618e1047a1911d2b3410dd ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: (none) [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @" The working copy has no changes. Working copy (@) : zsuskuln c2934cfb (empty) (no description set) Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) [EOF] "); // Stage some change, and create new HEAD. This shouldn't move the default // bookmark. add_file_to_index("file1", ""); let output = work_dir.run_jj(["new"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: vruxwmqv 2d7a8abb (empty) (no description set) Parent commit (@-) : zsuskuln ff536684 (no description set) [EOF] "); assert!(git_repo.head()?.is_detached()); insta::assert_snapshot!( git_repo.head_id()?.to_string(), @"ff5366846b039b25c6c4998fa74dca821c246243" ); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 2d7a8abb601ebf559df4037279e9f2e851a75e63 ○ ff5366846b039b25c6c4998fa74dca821c246243 │ ○ e6669bb3438ef218fa618e1047a1911d2b3410dd ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: ff5366846b039b25c6c4998fa74dca821c246243 [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @" The working copy has no changes. Working copy (@) : vruxwmqv 2d7a8abb (empty) (no description set) Parent commit (@-): zsuskuln ff536684 (no description set) [EOF] "); // Assign the default bookmark. The bookmark is no longer "unborn". work_dir .run_jj(["bookmark", "create", "-r@-", "master"]) .success(); // Stage some change, and check out root again. This should unset the HEAD. // https://github.com/jj-vcs/jj/issues/1495 add_file_to_index("file2", ""); let output = work_dir.run_jj(["new", "root()"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: wqnwkozp 88e8407a (empty) (no description set) Parent commit (@-) : zzzzzzzz 00000000 (empty) (no description set) Added 0 files, modified 0 files, removed 2 files [EOF] "); assert!(git_repo.head()?.is_unborn()); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 88e8407a4f0a5e6f40a7c6c494106764adc00fed │ ○ 2dd7385602e703388fd266b939bba6f57a1439d3 │ ○ ff5366846b039b25c6c4998fa74dca821c246243 master ├─╯ │ ○ e6669bb3438ef218fa618e1047a1911d2b3410dd ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: (none) [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @" The working copy has no changes. Working copy (@) : wqnwkozp 88e8407a (empty) (no description set) Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) [EOF] "); // New snapshot and commit can be created after the HEAD got unset. work_dir.write_file("file3", ""); let output = work_dir.run_jj(["new"]); insta::assert_snapshot!(output, @" ------- stderr ------- Working copy (@) now at: uyznsvlq 2fb16499 (empty) (no description set) Parent commit (@-) : wqnwkozp bb21bc2d (no description set) [EOF] "); insta::assert_snapshot!(get_log_output(&work_dir), @" @ 2fb16499a987e632407402e38976ed250c939c42 ○ bb21bc2dce2af92973fdd6d42686d77bd16bc466 │ ○ 2dd7385602e703388fd266b939bba6f57a1439d3 │ ○ ff5366846b039b25c6c4998fa74dca821c246243 master ├─╯ │ ○ e6669bb3438ef218fa618e1047a1911d2b3410dd ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_colocation_status(&work_dir), @" Workspace is currently colocated with Git. Last imported/exported Git HEAD: bb21bc2dce2af92973fdd6d42686d77bd16bc466 [EOF] "); Ok(()) } #[test] fn test_git_colocated_export_bookmarks_on_snapshot() -> TestResult { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); let git_repo = git::init(work_dir.root()); work_dir .run_jj(["git", "init", "--git-repo", "."]) .success();