jj/tests/test_git_colocated.rs
Ilya Grigoriev 0e2579ee6a Switch graph node to use for commit instead of
This follows up on 5c703aeb03.

The only reason for this change is that, subjectively, the result looks better to me. I'm not sure why, but I couldn't get used to the old symbol in spite of its seeming reasonableness. It felt really bold and heavy.

If people agree, we can wait until we need to update the screenshots for some other reason before merging this. Sorry I didn't figure this out while the discussion about the referenced commit was going on.

I'm not 100% certain how many fonts support each symbol. Please try it out and let me know if it doesn't work for you.

Compare after:

![image](https://user-images.githubusercontent.com/4123047/229251383-563b889d-7233-42e2-a3c5-bf9368a4d1fd.png)

and before:

![image](https://user-images.githubusercontent.com/4123047/229251695-7fd0ff2c-2832-4262-ade5-5120288cccdf.png)
2023-04-02 23:15:37 -07:00

389 lines
15 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 git2::Oid;
use crate::common::{get_stderr_string, TestEnvironment};
pub mod common;
#[test]
fn test_git_colocated() {
let test_env = TestEnvironment::default();
let workspace_root = test_env.env_root().join("repo");
let git_repo = git2::Repository::init(&workspace_root).unwrap();
// Create an initial commit in Git
std::fs::write(workspace_root.join("file"), "contents").unwrap();
git_repo
.index()
.unwrap()
.add_path(Path::new("file"))
.unwrap();
let tree1_oid = git_repo.index().unwrap().write_tree().unwrap();
let tree1 = git_repo.find_tree(tree1_oid).unwrap();
let signature = git2::Signature::new(
"Someone",
"someone@example.com",
&git2::Time::new(1234567890, 60),
)
.unwrap();
git_repo
.commit(
Some("refs/heads/master"),
&signature,
&signature,
"initial",
&tree1,
&[],
)
.unwrap();
insta::assert_snapshot!(
git_repo.head().unwrap().peel_to_commit().unwrap().id().to_string(),
@"e61b6729ff4292870702f2f72b2a60165679ef37"
);
// Import the repo
test_env.jj_cmd_success(&workspace_root, &["init", "--git-repo", "."]);
insta::assert_snapshot!(get_log_output(&test_env, &workspace_root), @r###"
@ 3e9369cd54227eb88455e1834dbc08aad6a16ac4
◉ e61b6729ff4292870702f2f72b2a60165679ef37 master
◉ 0000000000000000000000000000000000000000
"###);
insta::assert_snapshot!(
git_repo.head().unwrap().peel_to_commit().unwrap().id().to_string(),
@"e61b6729ff4292870702f2f72b2a60165679ef37"
);
// Modify the working copy. The working-copy commit should changed, but the Git
// HEAD commit should not
std::fs::write(workspace_root.join("file"), "modified").unwrap();
insta::assert_snapshot!(get_log_output(&test_env, &workspace_root), @r###"
@ b26951a9c6f5c270e4d039880208952fd5faae5e
◉ e61b6729ff4292870702f2f72b2a60165679ef37 master
◉ 0000000000000000000000000000000000000000
"###);
insta::assert_snapshot!(
git_repo.head().unwrap().peel_to_commit().unwrap().id().to_string(),
@"e61b6729ff4292870702f2f72b2a60165679ef37"
);
// Create a new change from jj and check that it's reflected in Git
test_env.jj_cmd_success(&workspace_root, &["new"]);
insta::assert_snapshot!(get_log_output(&test_env, &workspace_root), @r###"
@ 9dbb23ff2ff5e66c43880f1042369d704f7a321e
◉ b26951a9c6f5c270e4d039880208952fd5faae5e
◉ e61b6729ff4292870702f2f72b2a60165679ef37 master
◉ 0000000000000000000000000000000000000000
"###);
insta::assert_snapshot!(
git_repo.head().unwrap().target().unwrap().to_string(),
@"b26951a9c6f5c270e4d039880208952fd5faae5e"
);
}
#[test]
fn test_git_colocated_export_branches_on_snapshot() {
// Checks that we export branches that were changed only because the working
// copy was snapshotted
let test_env = TestEnvironment::default();
let workspace_root = test_env.env_root().join("repo");
let git_repo = git2::Repository::init(&workspace_root).unwrap();
test_env.jj_cmd_success(&workspace_root, &["init", "--git-repo", "."]);
// Create branch pointing to the initial commit
std::fs::write(workspace_root.join("file"), "initial").unwrap();
test_env.jj_cmd_success(&workspace_root, &["branch", "create", "foo"]);
insta::assert_snapshot!(get_log_output(&test_env, &workspace_root), @r###"
@ 438471f3fbf1004298d8fb01eeb13663a051a643 foo
◉ 0000000000000000000000000000000000000000
"###);
// The branch gets updated when we modify the working copy, and it should get
// exported to Git without requiring any other changes
std::fs::write(workspace_root.join("file"), "modified").unwrap();
insta::assert_snapshot!(get_log_output(&test_env, &workspace_root), @r###"
@ fab22d1acf5bb9c5aa48cb2c3dd2132072a359ca foo
◉ 0000000000000000000000000000000000000000
"###);
insta::assert_snapshot!(git_repo
.find_reference("refs/heads/foo")
.unwrap()
.target()
.unwrap()
.to_string(), @"fab22d1acf5bb9c5aa48cb2c3dd2132072a359ca");
}
#[test]
fn test_git_colocated_rebase_on_import() {
let test_env = TestEnvironment::default();
let workspace_root = test_env.env_root().join("repo");
let git_repo = git2::Repository::init(&workspace_root).unwrap();
test_env.jj_cmd_success(&workspace_root, &["init", "--git-repo", "."]);
// Make some changes in jj and check that they're reflected in git
std::fs::write(workspace_root.join("file"), "contents").unwrap();
test_env.jj_cmd_success(&workspace_root, &["commit", "-m", "add a file"]);
std::fs::write(workspace_root.join("file"), "modified").unwrap();
test_env.jj_cmd_success(&workspace_root, &["branch", "set", "master"]);
test_env.jj_cmd_success(&workspace_root, &["commit", "-m", "modify a file"]);
// TODO: We shouldn't need this command here to trigger an import of the
// refs/heads/master we just exported
test_env.jj_cmd_success(&workspace_root, &["st"]);
// Move `master` and HEAD backwards, which should result in commit2 getting
// hidden, and a new working-copy commit at the new position.
let commit2_oid = git_repo
.find_branch("master", git2::BranchType::Local)
.unwrap()
.get()
.target()
.unwrap();
let commit2 = git_repo.find_commit(commit2_oid).unwrap();
let commit1 = commit2.parents().next().unwrap();
git_repo.branch("master", &commit1, true).unwrap();
git_repo.set_head("refs/heads/master").unwrap();
insta::assert_snapshot!(get_log_output(&test_env, &workspace_root), @r###"
@ 7f96185cfbe36341d0f9a86ebfaeab67a5922c7e
◉ 4bcbeaba9a4b309c5f45a8807fbf5499b9714315 master
◉ 0000000000000000000000000000000000000000
"###);
}
#[test]
fn test_git_colocated_branches() {
let test_env = TestEnvironment::default();
let workspace_root = test_env.env_root().join("repo");
let git_repo = git2::Repository::init(&workspace_root).unwrap();
test_env.jj_cmd_success(&workspace_root, &["init", "--git-repo", "."]);
test_env.jj_cmd_success(&workspace_root, &["new", "-m", "foo"]);
test_env.jj_cmd_success(&workspace_root, &["new", "@-", "-m", "bar"]);
insta::assert_snapshot!(get_log_output(&test_env, &workspace_root), @r###"
@ 3560559274ab431feea00b7b7e0b9250ecce951f
│ ◉ 1e6f0b403ed2ff9713b5d6b1dc601e4804250cda
├─╯
◉ 230dd059e1b059aefc0da06a2e5a7dbf22362f22 master
◉ 0000000000000000000000000000000000000000
"###);
// Create a branch in jj. It should be exported to Git even though it points to
// the working- copy commit.
test_env.jj_cmd_success(&workspace_root, &["branch", "set", "master"]);
insta::assert_snapshot!(
git_repo.find_reference("refs/heads/master").unwrap().target().unwrap().to_string(),
@"3560559274ab431feea00b7b7e0b9250ecce951f"
);
insta::assert_snapshot!(
git_repo.head().unwrap().target().unwrap().to_string(),
@"230dd059e1b059aefc0da06a2e5a7dbf22362f22"
);
// Update the branch in Git
git_repo
.reference(
"refs/heads/master",
Oid::from_str("1e6f0b403ed2ff9713b5d6b1dc601e4804250cda").unwrap(),
true,
"test",
)
.unwrap();
insta::assert_snapshot!(get_log_output(&test_env, &workspace_root), @r###"
Working copy now at: eb08b363bb5e (no description set)
@ eb08b363bb5ef8ee549314260488980d7bbe8f63
│ ◉ 1e6f0b403ed2ff9713b5d6b1dc601e4804250cda master
├─╯
◉ 230dd059e1b059aefc0da06a2e5a7dbf22362f22
◉ 0000000000000000000000000000000000000000
"###);
}
#[test]
fn test_git_colocated_conflicting_git_refs() {
let test_env = TestEnvironment::default();
let workspace_root = test_env.env_root().join("repo");
git2::Repository::init(&workspace_root).unwrap();
test_env.jj_cmd_success(&workspace_root, &["init", "--git-repo", "."]);
test_env.jj_cmd_success(&workspace_root, &["branch", "create", "main"]);
let assert = test_env
.jj_cmd(&workspace_root, &["branch", "create", "main/sub"])
.assert()
.success()
.stdout("");
insta::assert_snapshot!(get_stderr_string(&assert), @r###"
Failed to export some branches:
main/sub
Hint: Git doesn't allow a branch name that looks like a parent directory of
another (e.g. `foo` and `foo/bar`). Try to rename the branches that failed to
export or their "parent" branches.
"###);
}
#[test]
fn test_git_colocated_fetch_deleted_branch() {
let test_env = TestEnvironment::default();
let origin_path = test_env.env_root().join("origin");
git2::Repository::init(&origin_path).unwrap();
test_env.jj_cmd_success(&origin_path, &["init", "--git-repo=."]);
test_env.jj_cmd_success(&origin_path, &["describe", "-m=A"]);
test_env.jj_cmd_success(&origin_path, &["branch", "create", "A"]);
test_env.jj_cmd_success(&origin_path, &["new", "-m=B"]);
test_env.jj_cmd_success(&origin_path, &["branch", "create", "B"]);
test_env.jj_cmd_success(&origin_path, &["new", "-m=C"]);
let clone_path = test_env.env_root().join("clone");
git2::Repository::clone(origin_path.to_str().unwrap(), &clone_path).unwrap();
test_env.jj_cmd_success(&clone_path, &["init", "--git-repo=."]);
insta::assert_snapshot!(get_log_output(&test_env, &clone_path), @r###"
@ bc7d08e8de9b7bc248b9358a05e96f1671bbd4d9
◉ e1f4268fabd2c84e880c5eb5bd87e076180fc8e3 B
◉ a86754f975f953fa25da4265764adc0c62e9ce6b A master
◉ 0000000000000000000000000000000000000000
"###);
test_env.jj_cmd_success(&origin_path, &["branch", "delete", "B"]);
let stdout = test_env.jj_cmd_success(&clone_path, &["git", "fetch"]);
insta::assert_snapshot!(stdout, @"");
// TODO: e1f4 should have been abandoned (#864)
insta::assert_snapshot!(get_log_output(&test_env, &clone_path), @r###"
@ bc7d08e8de9b7bc248b9358a05e96f1671bbd4d9
◉ e1f4268fabd2c84e880c5eb5bd87e076180fc8e3
◉ a86754f975f953fa25da4265764adc0c62e9ce6b A master
◉ 0000000000000000000000000000000000000000
"###);
}
#[test]
fn test_git_colocated_squash_undo() {
let test_env = TestEnvironment::default();
let repo_path = test_env.env_root().join("repo");
git2::Repository::init(&repo_path).unwrap();
test_env.jj_cmd_success(&repo_path, &["init", "--git-repo=."]);
test_env.jj_cmd_success(&repo_path, &["ci", "-m=A"]);
// Test the setup
insta::assert_snapshot!(get_log_output_divergence(&test_env, &repo_path), @r###"
@ rlvkpnrzqnoo 8f71e3b6a3be
◉ qpvuntsmwlqt a86754f975f9 A master
◉ zzzzzzzzzzzz 000000000000
"###);
test_env.jj_cmd_success(&repo_path, &["squash"]);
insta::assert_snapshot!(get_log_output_divergence(&test_env, &repo_path), @r###"
@ zsuskulnrvyr f0c12b0396d9
◉ qpvuntsmwlqt 2f376ea1478c A master
◉ zzzzzzzzzzzz 000000000000
"###);
test_env.jj_cmd_success(&repo_path, &["undo"]);
// TODO: There should be no divergence here; 2f376ea1478c should be hidden
// (#922)
insta::assert_snapshot!(get_log_output_divergence(&test_env, &repo_path), @r###"
◉ qpvuntsmwlqt 2f376ea1478c A master !divergence!
│ @ rlvkpnrzqnoo 8f71e3b6a3be
│ ◉ qpvuntsmwlqt a86754f975f9 A !divergence!
├─╯
◉ zzzzzzzzzzzz 000000000000
"###);
}
fn get_log_output_divergence(test_env: &TestEnvironment, repo_path: &Path) -> String {
let template = r###"
separate(" ",
change_id.short(),
commit_id.short(),
description.first_line(),
branches,
if(divergent, "!divergence!"),
)
"###;
test_env.jj_cmd_success(repo_path, &["log", "-T", template])
}
fn get_log_output(test_env: &TestEnvironment, workspace_root: &Path) -> String {
let template = r#"commit_id ++ " " ++ branches"#;
test_env.jj_cmd_success(workspace_root, &["log", "-T", template, "-r=all()"])
}
#[test]
fn test_git_colocated_unreachable_commits() {
let test_env = TestEnvironment::default();
let workspace_root = test_env.env_root().join("repo");
let git_repo = git2::Repository::init(&workspace_root).unwrap();
// Create an initial commit in Git
let empty_tree_oid = git_repo.treebuilder(None).unwrap().write().unwrap();
let tree1 = git_repo.find_tree(empty_tree_oid).unwrap();
let signature = git2::Signature::new(
"Someone",
"someone@example.com",
&git2::Time::new(1234567890, 60),
)
.unwrap();
let oid1 = git_repo
.commit(
Some("refs/heads/master"),
&signature,
&signature,
"initial",
&tree1,
&[],
)
.unwrap();
insta::assert_snapshot!(
git_repo.head().unwrap().peel_to_commit().unwrap().id().to_string(),
@"2ee37513d2b5e549f7478c671a780053614bff19"
);
// Add a second commit in Git
let tree2 = git_repo.find_tree(empty_tree_oid).unwrap();
let signature = git2::Signature::new(
"Someone",
"someone@example.com",
&git2::Time::new(1234567890, 62),
)
.unwrap();
let oid2 = git_repo
.commit(
None,
&signature,
&signature,
"next",
&tree2,
&[&git_repo.find_commit(oid1).unwrap()],
)
.unwrap();
insta::assert_snapshot!(
git_repo.head().unwrap().peel_to_commit().unwrap().id().to_string(),
@"2ee37513d2b5e549f7478c671a780053614bff19"
);
// Import the repo while there is no path to the second commit
test_env.jj_cmd_success(&workspace_root, &["init", "--git-repo", "."]);
insta::assert_snapshot!(get_log_output(&test_env, &workspace_root), @r###"
@ 66ae47cee4f8c28ee8d7e4f5d9401b03c07e22f2
◉ 2ee37513d2b5e549f7478c671a780053614bff19 master
◉ 0000000000000000000000000000000000000000
"###);
insta::assert_snapshot!(
git_repo.head().unwrap().peel_to_commit().unwrap().id().to_string(),
@"2ee37513d2b5e549f7478c671a780053614bff19"
);
// Check that trying to look up the second commit fails gracefully
let stderr = test_env.jj_cmd_failure(&workspace_root, &["show", &oid2.to_string()]);
insta::assert_snapshot!(stderr, @r###"
Error: Revision "8e713ff77b54928dd4a82aaabeca44b1ae91722c" doesn't exist
"###);
}