git: add tests that simulate external checkout/amend in colocated repo

I'm going to change the behavior of _without_ref() case to mitigate #1042.
This commit is contained in:
Yuya Nishihara 2023-05-10 18:23:30 +09:00
parent aa54fbaa99
commit 66d405fa5f
2 changed files with 141 additions and 0 deletions

View File

@ -312,6 +312,109 @@ fn test_import_refs_reimport_git_head_counts() {
assert!(tx.mut_repo().view().heads().contains(&jj_id(&commit)));
}
#[test]
fn test_import_refs_reimport_git_head_without_ref() {
// Simulate external `git checkout` in colocated repo, from anonymous branch.
let settings = testutils::user_settings();
let git_settings = GitSettings::default();
let test_repo = TestRepo::init(true);
let repo = &test_repo.repo;
let git_repo = repo.store().git_repo().unwrap();
// First, HEAD points to commit1.
let mut tx = repo.start_transaction(&settings, "test");
let commit1 = write_random_commit(tx.mut_repo(), &settings);
let commit2 = write_random_commit(tx.mut_repo(), &settings);
git_repo.set_head_detached(git_id(&commit1)).unwrap();
// Import HEAD.
git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap();
tx.mut_repo().rebase_descendants(&settings).unwrap();
assert!(tx.mut_repo().view().heads().contains(commit1.id()));
assert!(tx.mut_repo().view().heads().contains(commit2.id()));
// Move HEAD to commit2 (by e.g. `git checkout` command)
git_repo.set_head_detached(git_id(&commit2)).unwrap();
// Reimport HEAD, which abandons the old HEAD branch because jj thinks it
// would be rewritten by e.g. `git commit --amend` command.
git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap();
tx.mut_repo().rebase_descendants(&settings).unwrap();
assert!(!tx.mut_repo().view().heads().contains(commit1.id()));
assert!(tx.mut_repo().view().heads().contains(commit2.id()));
}
#[test]
fn test_import_refs_reimport_git_head_with_moved_ref() {
// Simulate external history rewriting in colocated repo.
let settings = testutils::user_settings();
let git_settings = GitSettings::default();
let test_repo = TestRepo::init(true);
let repo = &test_repo.repo;
let git_repo = repo.store().git_repo().unwrap();
// First, both HEAD and main point to commit1.
let mut tx = repo.start_transaction(&settings, "test");
let commit1 = write_random_commit(tx.mut_repo(), &settings);
let commit2 = write_random_commit(tx.mut_repo(), &settings);
git_repo
.reference("refs/heads/main", git_id(&commit1), true, "test")
.unwrap();
git_repo.set_head_detached(git_id(&commit1)).unwrap();
// Import HEAD and main.
git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap();
tx.mut_repo().rebase_descendants(&settings).unwrap();
assert!(tx.mut_repo().view().heads().contains(commit1.id()));
assert!(tx.mut_repo().view().heads().contains(commit2.id()));
// Move both HEAD and main to commit2 (by e.g. `git commit --amend` command)
git_repo
.reference("refs/heads/main", git_id(&commit2), true, "test")
.unwrap();
git_repo.set_head_detached(git_id(&commit2)).unwrap();
// Reimport HEAD and main, which abandons the old HEAD/main branch.
git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap();
tx.mut_repo().rebase_descendants(&settings).unwrap();
assert!(!tx.mut_repo().view().heads().contains(commit1.id()));
assert!(tx.mut_repo().view().heads().contains(commit2.id()));
}
#[test]
fn test_import_refs_reimport_git_head_with_fixed_ref() {
// Simulate external `git checkout` in colocated repo, from named branch.
let settings = testutils::user_settings();
let git_settings = GitSettings::default();
let test_repo = TestRepo::init(true);
let repo = &test_repo.repo;
let git_repo = repo.store().git_repo().unwrap();
// First, both HEAD and main point to commit1.
let mut tx = repo.start_transaction(&settings, "test");
let commit1 = write_random_commit(tx.mut_repo(), &settings);
let commit2 = write_random_commit(tx.mut_repo(), &settings);
git_repo
.reference("refs/heads/main", git_id(&commit1), true, "test")
.unwrap();
git_repo.set_head_detached(git_id(&commit1)).unwrap();
// Import HEAD and main.
git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap();
tx.mut_repo().rebase_descendants(&settings).unwrap();
assert!(tx.mut_repo().view().heads().contains(commit1.id()));
assert!(tx.mut_repo().view().heads().contains(commit2.id()));
// Move only HEAD to commit2 (by e.g. `git checkout` command)
git_repo.set_head_detached(git_id(&commit2)).unwrap();
// Reimport HEAD, which shouldn't abandon the old HEAD branch.
git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap();
tx.mut_repo().rebase_descendants(&settings).unwrap();
assert!(tx.mut_repo().view().heads().contains(commit1.id()));
assert!(tx.mut_repo().view().heads().contains(commit2.id()));
}
#[test]
fn test_import_refs_reimport_all_from_root_removed() {
// Test that if a chain of commits all the way from the root gets unreferenced,

View File

@ -267,6 +267,44 @@ fn test_git_colocated_fetch_deleted_branch() {
"###);
}
#[test]
fn test_git_colocated_external_checkout() {
let test_env = TestEnvironment::default();
let repo_path = test_env.env_root().join("repo");
let git_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_env.jj_cmd_success(&repo_path, &["new", "-m=B", "root"]);
test_env.jj_cmd_success(&repo_path, &["new"]);
// Checked out anonymous branch
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ 53637cd508ff02427dd78eca98f5b2450a6370ce
66f4d1806ae41bd604f69155dece64062a0056cf
a86754f975f953fa25da4265764adc0c62e9ce6b master
0000000000000000000000000000000000000000
"###);
// Check out another branch by external command
git_repo
.set_head_detached(
git_repo
.find_reference("refs/heads/master")
.unwrap()
.target()
.unwrap(),
)
.unwrap();
// The old HEAD branch gets abandoned because jj thinks it has been rewritten.
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@ 0521ce3b8c4e29aab79f3c750e2845dcbc4c3874
a86754f975f953fa25da4265764adc0c62e9ce6b master
0000000000000000000000000000000000000000
"###);
}
#[test]
fn test_git_colocated_squash_undo() {
let test_env = TestEnvironment::default();