1639 lines · 60.0 KB · Rust
RawDownload
// 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"    @  c3a12656d5027825bc69f40e11dc0bb381d7c277    ○  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"    @  59642000f061cf23eb37ab6eecce428afe7824da    ○  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"    @  fd4e130e43068d76ec6eb2c6df01653ea12eccb4    ○  59642000f061cf23eb37ab6eecce428afe7824da git_head()    ○  97358f54806c7cd005ed5ade68a779595efbae7e master initial    ◆  0000000000000000000000000000000000000000    [EOF]    ");    assert!(git_repo.head().unwrap().is_detached());    insta::assert_snapshot!(        git_repo.head_id().unwrap().to_string(),        @"59642000f061cf23eb37ab6eecce428afe7824da"    );} #[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.work_dir().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"    @  230dd059e1b059aefc0da06a2e5a7dbf22362f22    ◆  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 fcdbbd73 (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"    @  fcdbbd731496cae17161cd6be9b6cf1f759655a8    │ ○  993600f1189571af5bbeb492cf657dc7d0fde48a    ├─╯    ◆  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 fcdbbd73 (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 0e146103 (empty) (no description set)    Parent commit (@-)      : kkmpptxz e3e01407 (no description set)    [EOF]    ");    assert!(git_repo.head().unwrap().is_detached());    insta::assert_snapshot!(        git_repo.head_id().unwrap().to_string(),        @"e3e01407bd3539722ae4ffff077700d97c60cb11"    );    insta::assert_snapshot!(get_log_output(&work_dir), @r"    @  0e14610343ef50775f5c44db5aeef19aee45d9ad    ○  e3e01407bd3539722ae4ffff077700d97c60cb11 git_head()    │ ○  993600f1189571af5bbeb492cf657dc7d0fde48a    ├─╯    ◆  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 0e146103 (empty) (no description set)    Parent commit (@-): kkmpptxz e3e01407 (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 10dd328b (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"    @  10dd328bb906e15890e55047740eab2812a3b2f7    │ ○  ef75c0b0dcc9b080e00226908c21316acaa84dc6    │ ○  e3e01407bd3539722ae4ffff077700d97c60cb11 master    ├─╯    │ ○  993600f1189571af5bbeb492cf657dc7d0fde48a    ├─╯    ◆  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 10dd328b (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 101e2723 (empty) (no description set)    Parent commit (@-)      : znkkpsqq fc8af934 (no description set)    [EOF]    ");    insta::assert_snapshot!(get_log_output(&work_dir), @r"    @  101e272377a9daff75358f10dbd078df922fe68c    ○  fc8af9345b0830dcb14716e04cd2af26e2d19f63 git_head()    │ ○  ef75c0b0dcc9b080e00226908c21316acaa84dc6    │ ○  e3e01407bd3539722ae4ffff077700d97c60cb11 master    ├─╯    │ ○  993600f1189571af5bbeb492cf657dc7d0fde48a    ├─╯    ◆  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"    @  b15ef4cdd277d2c63cce6d67c1916f53a36141f7 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"    @  4d2c49a8f8e2f1ba61f48ba79e5f4a5faa6512cf foo    ◆  0000000000000000000000000000000000000000    [EOF]    ");    insta::assert_snapshot!(git_repo        .find_reference("refs/heads/foo")        .unwrap()        .id()        .to_string(), @"4d2c49a8f8e2f1ba61f48ba79e5f4a5faa6512cf");} #[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"    @  15b1d70c5e33b5d2b18383292b85324d5153ffed    ○  47fe984daf66f7bf3ebf31b9cb3513c995afb857 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 15b1d70c (empty) (no description set)    Parent commit (@-)      : qpvuntsm 47fe984d 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"    @  3560559274ab431feea00b7b7e0b9250ecce951f bar    │ ○  1e6f0b403ed2ff9713b5d6b1dc601e4804250cda foo    ├─╯    ○  230dd059e1b059aefc0da06a2e5a7dbf22362f22 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(),        @"3560559274ab431feea00b7b7e0b9250ecce951f"    );    assert!(git_repo.head().unwrap().is_detached());    insta::assert_snapshot!(        git_repo.head_id().unwrap().to_string(),        @"230dd059e1b059aefc0da06a2e5a7dbf22362f22"    );     // 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"    @  096dc80da67094fbaa6683e2a205dddffa31f9a8    │ ○  1e6f0b403ed2ff9713b5d6b1dc601e4804250cda master foo    ├─╯    ○  230dd059e1b059aefc0da06a2e5a7dbf22362f22 git_head()    ◆  0000000000000000000000000000000000000000    [EOF]    ------- stderr -------    Abandoned 1 commits that are no longer reachable.    Working copy  (@) now at: yqosqzyt 096dc80d (empty) (no description set)    Parent commit (@-)      : qpvuntsm 230dd059 (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"    @  65b6b74e08973b88d38404430f119c8c79465250 foo    ○  230dd059e1b059aefc0da06a2e5a7dbf22362f22 git_head()    ◆  0000000000000000000000000000000000000000    [EOF]    ");    insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"    foo: rlvkpnrz 65b6b74e (empty) (no description set)      @git: rlvkpnrz 65b6b74e (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.