// 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::git; use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir; #[test]fn test_git_colocated() { 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().unwrap().to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); // Import the repo work_dir .run_jj(["git", "init", "--git-repo", "."]) .success(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 524826059adc6f74de30f6be8f8eb86715d75b62 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master git_head() initial ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); // 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), @r" @ f40534d1cfee0e0916dcfbc65c31970b3c705269 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master git_head() initial ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); // 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), @r" @ b369903b66e2dba03f3f6b24433670784f6180d7 ○ f40534d1cfee0e0916dcfbc65c31970b3c705269 git_head() ○ 97358f54806c7cd005ed5ade68a779595efbae7e master initial ◆ 0000000000000000000000000000000000000000 [EOF] "); assert!(git_repo.head().unwrap().is_detached()); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"f40534d1cfee0e0916dcfbc65c31970b3c705269" );} #[test]fn test_git_colocated_intent_to_add() { 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"); // 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()), @r" 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 "); // 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()), @r" 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()), @r" 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()), @r" Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt ");} #[test]fn test_git_colocated_unborn_bookmark() { 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().unwrap().is_unborn()); assert_eq!( git_repo.head_name().unwrap().unwrap().as_bstr(), b"refs/heads/master" ); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [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, @r" ------- stderr ------- Working copy (@) now at: kkmpptxz 2b17ac71 (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().unwrap().is_unborn()); assert_eq!( git_repo.head_name().unwrap().unwrap().as_bstr(), b"refs/heads/master" ); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 2b17ac719c7db025e2514f5708d2b0328fc6b268 │ ○ 1d68db605e7f3722d6869beab15183f0e41fd45c ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @r" The working copy has no changes. Working copy (@) : kkmpptxz 2b17ac71 (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, @r" ------- stderr ------- Working copy (@) now at: royxmykx c5b52bf2 (empty) (no description set) Parent commit (@-) : kkmpptxz 54ca7830 (no description set) [EOF] "); assert!(git_repo.head().unwrap().is_detached()); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"54ca78301ccd2e0da397694ab34160d539a40e86" ); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ c5b52bf20a14ca728cbb2a56b9dffabc266251bd ○ 54ca78301ccd2e0da397694ab34160d539a40e86 git_head() │ ○ 1d68db605e7f3722d6869beab15183f0e41fd45c ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @r" The working copy has no changes. Working copy (@) : royxmykx c5b52bf2 (empty) (no description set) Parent commit (@-): kkmpptxz 54ca7830 (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, @r" ------- stderr ------- Working copy (@) now at: znkkpsqq 2b2f7cb0 (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().unwrap().is_unborn()); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 2b2f7cb00d53f5c0675efb09cbe1a826ce1167a4 │ ○ 6c3d40f5a3260d762cd52a8ff6d09883c88d8db5 │ ○ 54ca78301ccd2e0da397694ab34160d539a40e86 master ├─╯ │ ○ 1d68db605e7f3722d6869beab15183f0e41fd45c ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @r" The working copy has no changes. Working copy (@) : znkkpsqq 2b2f7cb0 (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, @r" ------- stderr ------- Working copy (@) now at: wqnwkozp 4253b9c0 (empty) (no description set) Parent commit (@-) : znkkpsqq b8df84db (no description set) [EOF] "); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 4253b9c0f70fd5287c2af4e96b779da6066757fd ○ b8df84db65f6a75ace38ceebca6ed8be781ec754 git_head() │ ○ 6c3d40f5a3260d762cd52a8ff6d09883c88d8db5 │ ○ 54ca78301ccd2e0da397694ab34160d539a40e86 master ├─╯ │ ○ 1d68db605e7f3722d6869beab15183f0e41fd45c ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] ");} #[test]fn test_git_colocated_export_bookmarks_on_snapshot() { // Checks that we export bookmarks that were changed only because the working // copy was snapshotted 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(); // Create bookmark pointing to the initial commit work_dir.write_file("file", "initial"); work_dir .run_jj(["bookmark", "create", "-r@", "foo"]) .success(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 82a10a4d9ef783fd68b661f40ce10dd80d599d9e foo ◆ 0000000000000000000000000000000000000000 [EOF] "); // The bookmark gets updated when we modify the working copy, and it should get // exported to Git without requiring any other changes work_dir.write_file("file", "modified"); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 00fc09f48ccf5c8b025a0f93b0ec3b0e4294a598 foo ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(git_repo .find_reference("refs/heads/foo") .unwrap() .id() .to_string(), @"00fc09f48ccf5c8b025a0f93b0ec3b0e4294a598");} #[test]fn test_git_colocated_rebase_on_import() { 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(); // Make some changes in jj and check that they're reflected in git work_dir.write_file("file", "contents"); work_dir.run_jj(["commit", "-m", "add a file"]).success(); work_dir.write_file("file", "modified"); work_dir .run_jj(["bookmark", "create", "-r@", "master"]) .success(); work_dir.run_jj(["commit", "-m", "modify a file"]).success(); // TODO: We shouldn't need this command here to trigger an import of the // refs/heads/master we just exported work_dir.run_jj(["st"]).success(); // Move `master` backwards, which should result in commit2 getting hidden, // and the working-copy commit rebased. let parent_commit = git_repo .find_reference("refs/heads/master") .unwrap() .peel_to_commit() .unwrap() .parent_ids() .next() .unwrap() .detach(); git_repo .reference( "refs/heads/master", parent_commit, gix::refs::transaction::PreviousValue::Any, "update ref", ) .unwrap(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ d46583362b91d0e172aec469ea1689995540de81 ○ cbd6c887108743a4abb0919305646a6a914a665e master git_head() add a file ◆ 0000000000000000000000000000000000000000 [EOF] ------- stderr ------- Abandoned 1 commits that are no longer reachable. Rebased 1 descendant commits off of commits rewritten from git Working copy (@) now at: zsuskuln d4658336 (empty) (no description set) Parent commit (@-) : qpvuntsm cbd6c887 master | add a file Added 0 files, modified 1 files, removed 0 files Done importing changes from the underlying Git repo. [EOF] ");} #[test]fn test_git_colocated_bookmarks() { 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(); work_dir.run_jj(["new", "-m", "foo"]).success(); work_dir.run_jj(["new", "@-", "-m", "bar"]).success(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 95e79774f8e7c785fc36da2b798ecfe0dc864e02 bar │ ○ b51ab2e2c88fe2d38bd7ca6946c4d87f281ce7e2 foo ├─╯ ○ e8849ae12c709f2321908879bc724fdb2ab8a781 git_head() ◆ 0000000000000000000000000000000000000000 [EOF] "); // Create a bookmark in jj. It should be exported to Git even though it points // to the working- copy commit. work_dir .run_jj(["bookmark", "create", "-r@", "master"]) .success(); insta::assert_snapshot!( git_repo.find_reference("refs/heads/master").unwrap().target().id().to_string(), @"95e79774f8e7c785fc36da2b798ecfe0dc864e02" ); assert!(git_repo.head().unwrap().is_detached()); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"e8849ae12c709f2321908879bc724fdb2ab8a781" ); // Update the bookmark in Git let target_id = work_dir .run_jj(["log", "--no-graph", "-T=commit_id", "-r=description(foo)"]) .success() .stdout .into_raw(); git_repo .reference( "refs/heads/master", gix::ObjectId::from_hex(target_id.as_bytes()).unwrap(), gix::refs::transaction::PreviousValue::Any, "test", ) .unwrap(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 507c0edcfc028f714f3c7a3027cb141f6610e867 │ ○ b51ab2e2c88fe2d38bd7ca6946c4d87f281ce7e2 master foo ├─╯ ○ e8849ae12c709f2321908879bc724fdb2ab8a781 git_head() ◆ 0000000000000000000000000000000000000000 [EOF] ------- stderr ------- Abandoned 1 commits that are no longer reachable. Working copy (@) now at: yqosqzyt 507c0edc (empty) (no description set) Parent commit (@-) : qpvuntsm e8849ae1 (empty) (no description set) Done importing changes from the underlying Git repo. [EOF] ");} #[test]fn test_git_colocated_bookmark_forget() { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); git::init(work_dir.root()); work_dir .run_jj(["git", "init", "--git-repo", "."]) .success(); work_dir.run_jj(["new"]).success(); work_dir .run_jj(["bookmark", "create", "-r@", "foo"]) .success(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 43444d88b0096888ebfd664c0cf792c9d15e3f14 foo ○ e8849ae12c709f2321908879bc724fdb2ab8a781 git_head() ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" foo: rlvkpnrz 43444d88 (empty) (no description set) @git: rlvkpnrz 43444d88 (empty) (no description set) [EOF] "); let output = work_dir.run_jj(["bookmark", "forget", "--include-remotes", "foo"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Forgot 1 local bookmarks. Forgot 1 remote bookmarks. [EOF] "); // A forgotten bookmark is deleted in the git repo. For a detailed demo // explaining this, see `test_bookmark_forget_export` in // `test_bookmark_command.rs`. insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");} #[test]Lines 1–500 of 1639. 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::git; use crate::common::CommandOutput; use crate::common::TestEnvironment; use crate::common::TestWorkDir; #[test] fn test_git_colocated() { 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().unwrap().to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); // Import the repo work_dir .run_jj(["git", "init", "--git-repo", "."]) .success(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 524826059adc6f74de30f6be8f8eb86715d75b62 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master git_head() initial ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); // 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), @r" @ f40534d1cfee0e0916dcfbc65c31970b3c705269 ○ 97358f54806c7cd005ed5ade68a779595efbae7e master git_head() initial ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"97358f54806c7cd005ed5ade68a779595efbae7e" ); // 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), @r" @ b369903b66e2dba03f3f6b24433670784f6180d7 ○ f40534d1cfee0e0916dcfbc65c31970b3c705269 git_head() ○ 97358f54806c7cd005ed5ade68a779595efbae7e master initial ◆ 0000000000000000000000000000000000000000 [EOF] "); assert!(git_repo.head().unwrap().is_detached()); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"f40534d1cfee0e0916dcfbc65c31970b3c705269" ); } #[test] fn test_git_colocated_intent_to_add() { 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"); // 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()), @r" 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 "); // 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()), @r" 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()), @r" 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()), @r" Unconflicted Mode(FILE) 0839b2e9412b ctime=0:0 mtime=0:0 size=0 flags=0 file1.txt "); } #[test] fn test_git_colocated_unborn_bookmark() { 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().unwrap().is_unborn()); assert_eq!( git_repo.head_name().unwrap().unwrap().as_bstr(), b"refs/heads/master" ); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [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, @r" ------- stderr ------- Working copy (@) now at: kkmpptxz 2b17ac71 (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().unwrap().is_unborn()); assert_eq!( git_repo.head_name().unwrap().unwrap().as_bstr(), b"refs/heads/master" ); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 2b17ac719c7db025e2514f5708d2b0328fc6b268 │ ○ 1d68db605e7f3722d6869beab15183f0e41fd45c ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @r" The working copy has no changes. Working copy (@) : kkmpptxz 2b17ac71 (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, @r" ------- stderr ------- Working copy (@) now at: royxmykx c5b52bf2 (empty) (no description set) Parent commit (@-) : kkmpptxz 54ca7830 (no description set) [EOF] "); assert!(git_repo.head().unwrap().is_detached()); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"54ca78301ccd2e0da397694ab34160d539a40e86" ); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ c5b52bf20a14ca728cbb2a56b9dffabc266251bd ○ 54ca78301ccd2e0da397694ab34160d539a40e86 git_head() │ ○ 1d68db605e7f3722d6869beab15183f0e41fd45c ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @r" The working copy has no changes. Working copy (@) : royxmykx c5b52bf2 (empty) (no description set) Parent commit (@-): kkmpptxz 54ca7830 (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, @r" ------- stderr ------- Working copy (@) now at: znkkpsqq 2b2f7cb0 (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().unwrap().is_unborn()); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 2b2f7cb00d53f5c0675efb09cbe1a826ce1167a4 │ ○ 6c3d40f5a3260d762cd52a8ff6d09883c88d8db5 │ ○ 54ca78301ccd2e0da397694ab34160d539a40e86 master ├─╯ │ ○ 1d68db605e7f3722d6869beab15183f0e41fd45c ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); // Staged change shouldn't persist. checkout_index(); insta::assert_snapshot!(work_dir.run_jj(["status"]), @r" The working copy has no changes. Working copy (@) : znkkpsqq 2b2f7cb0 (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, @r" ------- stderr ------- Working copy (@) now at: wqnwkozp 4253b9c0 (empty) (no description set) Parent commit (@-) : znkkpsqq b8df84db (no description set) [EOF] "); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 4253b9c0f70fd5287c2af4e96b779da6066757fd ○ b8df84db65f6a75ace38ceebca6ed8be781ec754 git_head() │ ○ 6c3d40f5a3260d762cd52a8ff6d09883c88d8db5 │ ○ 54ca78301ccd2e0da397694ab34160d539a40e86 master ├─╯ │ ○ 1d68db605e7f3722d6869beab15183f0e41fd45c ├─╯ ◆ 0000000000000000000000000000000000000000 [EOF] "); } #[test] fn test_git_colocated_export_bookmarks_on_snapshot() { // Checks that we export bookmarks that were changed only because the working // copy was snapshotted 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(); // Create bookmark pointing to the initial commit work_dir.write_file("file", "initial"); work_dir .run_jj(["bookmark", "create", "-r@", "foo"]) .success(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 82a10a4d9ef783fd68b661f40ce10dd80d599d9e foo ◆ 0000000000000000000000000000000000000000 [EOF] "); // The bookmark gets updated when we modify the working copy, and it should get // exported to Git without requiring any other changes work_dir.write_file("file", "modified"); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 00fc09f48ccf5c8b025a0f93b0ec3b0e4294a598 foo ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(git_repo .find_reference("refs/heads/foo") .unwrap() .id() .to_string(), @"00fc09f48ccf5c8b025a0f93b0ec3b0e4294a598"); } #[test] fn test_git_colocated_rebase_on_import() { 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(); // Make some changes in jj and check that they're reflected in git work_dir.write_file("file", "contents"); work_dir.run_jj(["commit", "-m", "add a file"]).success(); work_dir.write_file("file", "modified"); work_dir .run_jj(["bookmark", "create", "-r@", "master"]) .success(); work_dir.run_jj(["commit", "-m", "modify a file"]).success(); // TODO: We shouldn't need this command here to trigger an import of the // refs/heads/master we just exported work_dir.run_jj(["st"]).success(); // Move `master` backwards, which should result in commit2 getting hidden, // and the working-copy commit rebased. let parent_commit = git_repo .find_reference("refs/heads/master") .unwrap() .peel_to_commit() .unwrap() .parent_ids() .next() .unwrap() .detach(); git_repo .reference( "refs/heads/master", parent_commit, gix::refs::transaction::PreviousValue::Any, "update ref", ) .unwrap(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ d46583362b91d0e172aec469ea1689995540de81 ○ cbd6c887108743a4abb0919305646a6a914a665e master git_head() add a file ◆ 0000000000000000000000000000000000000000 [EOF] ------- stderr ------- Abandoned 1 commits that are no longer reachable. Rebased 1 descendant commits off of commits rewritten from git Working copy (@) now at: zsuskuln d4658336 (empty) (no description set) Parent commit (@-) : qpvuntsm cbd6c887 master | add a file Added 0 files, modified 1 files, removed 0 files Done importing changes from the underlying Git repo. [EOF] "); } #[test] fn test_git_colocated_bookmarks() { 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(); work_dir.run_jj(["new", "-m", "foo"]).success(); work_dir.run_jj(["new", "@-", "-m", "bar"]).success(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 95e79774f8e7c785fc36da2b798ecfe0dc864e02 bar │ ○ b51ab2e2c88fe2d38bd7ca6946c4d87f281ce7e2 foo ├─╯ ○ e8849ae12c709f2321908879bc724fdb2ab8a781 git_head() ◆ 0000000000000000000000000000000000000000 [EOF] "); // Create a bookmark in jj. It should be exported to Git even though it points // to the working- copy commit. work_dir .run_jj(["bookmark", "create", "-r@", "master"]) .success(); insta::assert_snapshot!( git_repo.find_reference("refs/heads/master").unwrap().target().id().to_string(), @"95e79774f8e7c785fc36da2b798ecfe0dc864e02" ); assert!(git_repo.head().unwrap().is_detached()); insta::assert_snapshot!( git_repo.head_id().unwrap().to_string(), @"e8849ae12c709f2321908879bc724fdb2ab8a781" ); // Update the bookmark in Git let target_id = work_dir .run_jj(["log", "--no-graph", "-T=commit_id", "-r=description(foo)"]) .success() .stdout .into_raw(); git_repo .reference( "refs/heads/master", gix::ObjectId::from_hex(target_id.as_bytes()).unwrap(), gix::refs::transaction::PreviousValue::Any, "test", ) .unwrap(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 507c0edcfc028f714f3c7a3027cb141f6610e867 │ ○ b51ab2e2c88fe2d38bd7ca6946c4d87f281ce7e2 master foo ├─╯ ○ e8849ae12c709f2321908879bc724fdb2ab8a781 git_head() ◆ 0000000000000000000000000000000000000000 [EOF] ------- stderr ------- Abandoned 1 commits that are no longer reachable. Working copy (@) now at: yqosqzyt 507c0edc (empty) (no description set) Parent commit (@-) : qpvuntsm e8849ae1 (empty) (no description set) Done importing changes from the underlying Git repo. [EOF] "); } #[test] fn test_git_colocated_bookmark_forget() { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); git::init(work_dir.root()); work_dir .run_jj(["git", "init", "--git-repo", "."]) .success(); work_dir.run_jj(["new"]).success(); work_dir .run_jj(["bookmark", "create", "-r@", "foo"]) .success(); insta::assert_snapshot!(get_log_output(&work_dir), @r" @ 43444d88b0096888ebfd664c0cf792c9d15e3f14 foo ○ e8849ae12c709f2321908879bc724fdb2ab8a781 git_head() ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" foo: rlvkpnrz 43444d88 (empty) (no description set) @git: rlvkpnrz 43444d88 (empty) (no description set) [EOF] "); let output = work_dir.run_jj(["bookmark", "forget", "--include-remotes", "foo"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Forgot 1 local bookmarks. Forgot 1 remote bookmarks. [EOF] "); // A forgotten bookmark is deleted in the git repo. For a detailed demo // explaining this, see `test_bookmark_forget_export` in // `test_bookmark_command.rs`. insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); } #[test]