diff --git a/cli/src/commit_templater.rs b/cli/src/commit_templater.rs index ad7495a27a..404ef3c034 100644 --- a/cli/src/commit_templater.rs +++ b/cli/src/commit_templater.rs @@ -360,22 +360,26 @@ fn build_branches_index(repo: &dyn Repo) -> RefNamesIndex { let mut index = RefNamesIndex::default(); for (branch_name, branch_target) in repo.view().branches() { let local_target = branch_target.local_target; - let mut unsynced_remote_targets = branch_target - .remote_refs - .iter() - .filter(|&&(_, remote_ref)| remote_ref.target != *local_target) - .peekable(); + let remote_refs = branch_target.remote_refs; + let unsynced_remote_refs = remote_refs.iter().copied().filter(|&(_, remote_ref)| { + !remote_ref.is_tracking() || remote_ref.target != *local_target + }); + let has_unsynced_tracking_refs = || { + remote_refs.iter().any(|&(_, remote_ref)| { + remote_ref.is_tracking() && remote_ref.target != *local_target + }) + }; if local_target.is_present() { let decorated_name = if local_target.has_conflict() { format!("{branch_name}??") - } else if unsynced_remote_targets.peek().is_some() { + } else if has_unsynced_tracking_refs() { format!("{branch_name}*") } else { branch_name.to_owned() }; index.insert(local_target.added_ids(), decorated_name); } - for &(remote_name, remote_ref) in unsynced_remote_targets { + for (remote_name, remote_ref) in unsynced_remote_refs { let decorated_name = if remote_ref.target.has_conflict() { format!("{branch_name}@{remote_name}?") } else { diff --git a/cli/tests/test_branch_command.rs b/cli/tests/test_branch_command.rs index d06df8ea46..6aa5a3503a 100644 --- a/cli/tests/test_branch_command.rs +++ b/cli/tests/test_branch_command.rs @@ -560,7 +560,7 @@ fn test_branch_track_untrack() { main: sptzoqmo 7b33f629 commit 1 "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" - ◉ feature1 feature2@origin main 7b33f6295eda + ◉ feature1 feature1@origin feature2@origin main 7b33f6295eda │ @ 230dd059e1b0 ├─╯ ◉ 000000000000 @@ -586,7 +586,7 @@ fn test_branch_track_untrack() { "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" ◉ feature1@origin feature2@origin main 40dabdaf4abe - │ ◉ feature1* 7b33f6295eda + │ ◉ feature1 7b33f6295eda ├─╯ │ @ 230dd059e1b0 ├─╯ @@ -619,7 +619,7 @@ fn test_branch_track_untrack() { "###); insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###" ◉ feature1@origin feature2@origin feature3 main 3f0f86fa0e57 - │ ◉ feature1* 7b33f6295eda + │ ◉ feature1 7b33f6295eda ├─╯ │ @ 230dd059e1b0 ├─╯ diff --git a/lib/src/revset.rs b/lib/src/revset.rs index 6531a67397..155d62ff30 100644 --- a/lib/src/revset.rs +++ b/lib/src/revset.rs @@ -2035,7 +2035,9 @@ fn collect_branch_symbols(repo: &dyn Repo, include_synced_remotes: bool) -> Vec< .remote_refs .into_iter() .filter(move |&(_, remote_ref)| { - include_synced_remotes || remote_ref.target != *local_target + include_synced_remotes + || !remote_ref.is_tracking() + || remote_ref.target != *local_target }) .map(move |(remote_name, _)| format!("{name}@{remote_name}")); local_symbol.into_iter().chain(remote_symbols) diff --git a/lib/tests/test_revset.rs b/lib/tests/test_revset.rs index 9c4278e66c..ae521bb200 100644 --- a/lib/tests/test_revset.rs +++ b/lib/tests/test_revset.rs @@ -382,11 +382,16 @@ fn test_resolve_symbol_branches() { let settings = testutils::user_settings(); let test_repo = TestRepo::init(); let repo = &test_repo.repo; - let remote_ref = |target| RemoteRef { + let new_remote_ref = |target| RemoteRef { target, - state: RemoteRefState::Tracking, // doesn't matter + state: RemoteRefState::New, }; - let normal_remote_ref = |id: &CommitId| remote_ref(RefTarget::normal(id.clone())); + let tracking_remote_ref = |target| RemoteRef { + target, + state: RemoteRefState::Tracking, + }; + let normal_tracking_remote_ref = + |id: &CommitId| tracking_remote_ref(RefTarget::normal(id.clone())); let mut tx = repo.start_transaction(&settings, "test"); let mut_repo = tx.mut_repo(); @@ -398,9 +403,13 @@ fn test_resolve_symbol_branches() { let commit5 = write_random_commit(mut_repo, &settings); mut_repo.set_local_branch_target("local", RefTarget::normal(commit1.id().clone())); - mut_repo.set_remote_branch("remote", "origin", normal_remote_ref(commit2.id())); + mut_repo.set_remote_branch("remote", "origin", normal_tracking_remote_ref(commit2.id())); mut_repo.set_local_branch_target("local-remote", RefTarget::normal(commit3.id().clone())); - mut_repo.set_remote_branch("local-remote", "origin", normal_remote_ref(commit4.id())); + mut_repo.set_remote_branch( + "local-remote", + "origin", + normal_tracking_remote_ref(commit4.id()), + ); mut_repo.set_local_branch_target( "local-remote@origin", // not a remote branch RefTarget::normal(commit5.id().clone()), @@ -408,12 +417,17 @@ fn test_resolve_symbol_branches() { mut_repo.set_remote_branch( "local-remote", "mirror", - remote_ref(mut_repo.get_local_branch("local-remote")), + tracking_remote_ref(mut_repo.get_local_branch("local-remote")), + ); + mut_repo.set_remote_branch( + "local-remote", + "untracked", + new_remote_ref(mut_repo.get_local_branch("local-remote")), ); mut_repo.set_remote_branch( "local-remote", git::REMOTE_NAME_FOR_LOCAL_GIT_REPO, - remote_ref(mut_repo.get_local_branch("local-remote")), + tracking_remote_ref(mut_repo.get_local_branch("local-remote")), ); mut_repo.set_local_branch_target( @@ -426,7 +440,7 @@ fn test_resolve_symbol_branches() { mut_repo.set_remote_branch( "remote-conflicted", "origin", - remote_ref(RefTarget::from_legacy_form( + tracking_remote_ref(RefTarget::from_legacy_form( [commit3.id().clone()], [commit5.id().clone(), commit4.id().clone()], )), @@ -457,6 +471,7 @@ fn test_resolve_symbol_branches() { name: "remote", candidates: [ "local-remote@origin", + "local-remote@untracked", "remote-conflicted@origin", "remote@origin", ], @@ -501,7 +516,9 @@ fn test_resolve_symbol_branches() { // Typo of local/remote branch name: // For "local-emote" (without @remote part), "local-remote@mirror"/"@git" aren't - // suggested since they point to the same target as "local-remote". + // suggested since they point to the same target as "local-remote". OTOH, + // "local-remote@untracked" is suggested because non-tracking branch is + // unrelated to the local branch of the same name. insta::assert_debug_snapshot!( resolve_symbol(mut_repo, "local-emote").unwrap_err(), @r###" NoSuchRevision { @@ -511,6 +528,7 @@ fn test_resolve_symbol_branches() { "local-conflicted", "local-remote", "local-remote@origin", + "local-remote@untracked", ], } "###); @@ -524,6 +542,7 @@ fn test_resolve_symbol_branches() { "local-remote@git", "local-remote@mirror", "local-remote@origin", + "local-remote@untracked", "remote-conflicted@origin", "remote@origin", ], @@ -539,6 +558,7 @@ fn test_resolve_symbol_branches() { "local-remote@git", "local-remote@mirror", "local-remote@origin", + "local-remote@untracked", "remote-conflicted@origin", "remote@origin", ],