diff --git a/lib/src/git.rs b/lib/src/git.rs index ac936ec8c..6be531693 100644 --- a/lib/src/git.rs +++ b/lib/src/git.rs @@ -302,7 +302,10 @@ pub fn import_some_refs( }; return Ok(stats); } - let pinned_heads = itertools::chain( + let pinned_heads = itertools::chain!( + changed_remote_refs + .values() + .flat_map(|(_, new_target)| new_target.added_ids()), pinned_commit_ids(mut_repo.view()), iter::once(mut_repo.store().root_commit_id()), ) diff --git a/lib/tests/test_git.rs b/lib/tests/test_git.rs index 4ae266ed9..3772efedf 100644 --- a/lib/tests/test_git.rs +++ b/lib/tests/test_git.rs @@ -702,6 +702,60 @@ fn test_import_refs_reimport_with_moved_remote_ref() { assert_eq!(*view.heads(), expected_heads); } +#[test] +fn test_import_refs_reimport_with_moved_untracked_remote_ref() { + let settings = testutils::user_settings(); + let git_settings = GitSettings { + auto_local_branch: false, + }; + let test_workspace = TestRepo::init_with_backend(TestRepoBackend::Git); + let repo = &test_workspace.repo; + let git_repo = get_git_repo(repo); + + // The base commit doesn't have a reference. + let remote_ref_name = "refs/remotes/origin/feature"; + let commit_base = empty_git_commit(&git_repo, remote_ref_name, &[]); + let commit_remote_t0 = empty_git_commit(&git_repo, remote_ref_name, &[&commit_base]); + let mut tx = repo.start_transaction(&settings, "test"); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); + tx.mut_repo().rebase_descendants(&settings).unwrap(); + let repo = tx.commit(); + let view = repo.view(); + + assert_eq!(*view.heads(), hashset! { jj_id(&commit_remote_t0) }); + assert_eq!(view.local_branches().count(), 0); + assert_eq!(view.all_remote_branches().count(), 1); + assert_eq!( + view.get_remote_branch("feature", "origin"), + &RemoteRef { + target: RefTarget::normal(jj_id(&commit_remote_t0)), + state: RemoteRefState::New, + }, + ); + + // Move the reference remotely and fetch the changes. + delete_git_ref(&git_repo, remote_ref_name); + let commit_remote_t1 = empty_git_commit(&git_repo, remote_ref_name, &[&commit_base]); + let mut tx = repo.start_transaction(&settings, "test"); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); + tx.mut_repo().rebase_descendants(&settings).unwrap(); + let repo = tx.commit(); + let view = repo.view(); + + // commit_remote_t0 should be abandoned, but commit_base shouldn't because + // it's the ancestor of commit_remote_t1. + assert_eq!(*view.heads(), hashset! { jj_id(&commit_remote_t1) }); + assert_eq!(view.local_branches().count(), 0); + assert_eq!(view.all_remote_branches().count(), 1); + assert_eq!( + view.get_remote_branch("feature", "origin"), + &RemoteRef { + target: RefTarget::normal(jj_id(&commit_remote_t1)), + state: RemoteRefState::New, + }, + ); +} + #[test] fn test_import_refs_reimport_git_head_with_fixed_ref() { // Simulate external `git checkout` in colocated repo, from named branch.