mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 08:52:12 +00:00
fix(vcs): exclude symbolic aliases from containing branches (#1747)
This commit is contained in:
1 parent
ba9ce1d842
commit
d942f59dcd
6 files changed
+70
-14
No files matched your search
@@ -948,13 +948,11 @@ pub(crate) fn decorations(repo: &gix::Repository) -> IdeResult<HashMap<ObjectId,
|
||||
let platform = repo.references().map_err(gx)?;
|
||||
for reference in platform.all().map_err(gx)? {
|
||||
let Ok(mut reference) = reference else { continue };
|
||||
if reference.target().try_name().is_some() {
|
||||
continue;
|
||||
}
|
||||
let full = reference.name().as_bstr().to_owned();
|
||||
let label = if let Some(n) = full.strip_prefix(b"refs/heads/") {
|
||||
to_string(n.as_bstr())
|
||||
} else if let Some(n) = full.strip_prefix(b"refs/remotes/") {
|
||||
if n.ends_with(b"/HEAD") {
|
||||
continue;
|
||||
}
|
||||
let label = if let Some(n) = full.strip_prefix(b"refs/heads/").or_else(|| full.strip_prefix(b"refs/remotes/")) {
|
||||
to_string(n.as_bstr())
|
||||
} else if let Some(n) = full.strip_prefix(b"refs/tags/") {
|
||||
format!("tag: {}", to_string(n.as_bstr()))
|
||||
|
||||
@@ -910,7 +910,7 @@ impl Repo {
|
||||
let id = commit_id.to_string();
|
||||
let contains = format!("--contains={id}");
|
||||
let branches =
|
||||
cli::run_cancellable(self.root(), &["branch", "-a", &contains, "--format=%(refname:short)"], cancel)?;
|
||||
cli::run_cancellable(self.root(), &["branch", "-a", &contains, refs::DIRECT_BRANCH_FORMAT], cancel)?;
|
||||
let cache_key = format!("{allowed}:{id}");
|
||||
let cached = self.log_signatures.lock().unwrap_or_else(|p| p.into_inner()).get(&cache_key).cloned();
|
||||
let mut details = if let Some(details) = cached {
|
||||
@@ -952,7 +952,7 @@ impl Repo {
|
||||
details
|
||||
};
|
||||
details.containing_branches =
|
||||
branches.stdout_str().lines().filter(|s| !s.ends_with("/HEAD")).map(str::to_string).collect();
|
||||
branches.stdout_str().lines().filter(|s| !s.is_empty()).map(str::to_string).collect();
|
||||
Ok(details)
|
||||
}
|
||||
|
||||
|
||||
@@ -95,9 +95,9 @@ fn branch_at(r: &Repo, commit: &str) -> Option<String> {
|
||||
}
|
||||
["refs/heads", "refs/remotes"].into_iter().find_map(|refs| {
|
||||
let out =
|
||||
run(r.root(), &["for-each-ref", "--points-at", commit, "--format=%(refname:short)", refs], None).ok()?;
|
||||
let names: Vec<String> =
|
||||
out.stdout_str().lines().filter(|l| !l.is_empty() && !l.ends_with("/HEAD")).map(str::to_string).collect();
|
||||
run(r.root(), &["for-each-ref", "--points-at", commit, crate::refs::DIRECT_BRANCH_FORMAT, refs], None)
|
||||
.ok()?;
|
||||
let names: Vec<String> = out.stdout_str().lines().filter(|l| !l.is_empty()).map(str::to_string).collect();
|
||||
match names.as_slice() {
|
||||
[one] => Some(one.clone()),
|
||||
_ => None,
|
||||
|
||||
@@ -4,6 +4,9 @@ use crate::repo::{gx, to_string};
|
||||
use crate::{Branch, BranchInfo, Repo, Stash};
|
||||
use ide_core::IdeResult;
|
||||
|
||||
// Filter symbolic refs before shortening; `refname:short` also strips remote `/HEAD` suffixes.
|
||||
pub(crate) const DIRECT_BRANCH_FORMAT: &str = "--format=%(if)%(symref)%(then)%(else)%(refname:lstrip=2)%(end)";
|
||||
|
||||
pub(crate) fn branch_info(r: &Repo) -> IdeResult<BranchInfo> {
|
||||
let repo = r.gix()?;
|
||||
let head_ref = repo.head_name().map_err(gx)?;
|
||||
@@ -93,6 +96,9 @@ pub(crate) fn branches(r: &Repo) -> IdeResult<Vec<Branch>> {
|
||||
|
||||
for reference in platform.local_branches().map_err(gx)? {
|
||||
let mut reference = reference.map_err(gx)?;
|
||||
if reference.target().try_name().is_some() {
|
||||
continue;
|
||||
}
|
||||
let full = reference.name().to_owned();
|
||||
let Ok(id) = reference.peel_to_id().map(|id| id.detach()) else { continue };
|
||||
let current = head_name.as_ref().is_some_and(|h| h == &full);
|
||||
@@ -118,11 +124,11 @@ pub(crate) fn branches(r: &Repo) -> IdeResult<Vec<Branch>> {
|
||||
}
|
||||
for reference in platform.remote_branches().map_err(gx)? {
|
||||
let mut reference = reference.map_err(gx)?;
|
||||
let full = reference.name().to_owned();
|
||||
// Skip `refs/remotes/<remote>/HEAD` symbolic pointers.
|
||||
if full.as_bstr().ends_with(b"/HEAD") {
|
||||
// Skip symbolic aliases such as `refs/remotes/<remote>/HEAD`.
|
||||
if reference.target().try_name().is_some() {
|
||||
continue;
|
||||
}
|
||||
let full = reference.name().to_owned();
|
||||
let Ok(id) = reference.peel_to_id().map(|id| id.detach()) else { continue };
|
||||
out.push(Branch {
|
||||
name: to_string(full.as_ref().shorten()),
|
||||
|
||||
@@ -149,6 +149,21 @@ fn merge_versions_put_the_users_work_on_the_left() {
|
||||
assert_eq!(repo.merge_sides().unwrap(), MergeSides { branch: Some("topic".into()), ..Default::default() });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rebase_conflict_names_the_remote_branch_without_its_symbolic_aliases() {
|
||||
let fx = diverged();
|
||||
let main = fx.git(&["rev-parse", "main"]);
|
||||
fx.git(&["update-ref", "refs/remotes/origin/main", &main]);
|
||||
fx.git(&["symbolic-ref", "refs/remotes/origin/HEAD", "refs/remotes/origin/main"]);
|
||||
fx.git(&["symbolic-ref", "refs/remotes/origin/alias", "refs/remotes/origin/main"]);
|
||||
fx.git(&["branch", "-D", "main"]);
|
||||
let repo = fx.repo();
|
||||
assert!(repo.rebase("origin/main").is_err());
|
||||
assert_eq!(repo.merge_sides().unwrap().other_branch.as_deref(), Some("origin/main"));
|
||||
let (cancel, out) = quiet();
|
||||
repo.abort_operation(&cancel, &out).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rebase_conflict_then_abort_and_skip() {
|
||||
let fx = diverged();
|
||||
|
||||
@@ -113,6 +113,43 @@ fn lazy_summaries_seek_and_index_survive_refresh_and_restart() {
|
||||
assert_eq!(repo.log_details(&ids[69]).unwrap().signature, "N");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn containing_branches_exclude_symbolic_aliases_but_keep_direct_head_names() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let dir = tmp.path();
|
||||
git(dir, &["init", "-q"]);
|
||||
let tip = commit(dir, "a", "tip");
|
||||
git(dir, &["branch", "topic/HEAD"]);
|
||||
for remote in ["origin", "contributor-742", "issue-739", "issue-765"] {
|
||||
let main = format!("refs/remotes/{remote}/main");
|
||||
git(dir, &["update-ref", &main, &tip]);
|
||||
git(dir, &["symbolic-ref", &format!("refs/remotes/{remote}/HEAD"), &main]);
|
||||
git(dir, &["symbolic-ref", &format!("refs/remotes/{remote}/alias"), &main]);
|
||||
}
|
||||
git(dir, &["update-ref", "refs/remotes/origin/topic/HEAD", &tip]);
|
||||
git(dir, &["symbolic-ref", "refs/heads/local-alias", "refs/heads/main"]);
|
||||
let repo = Repo::discover(dir).unwrap().unwrap();
|
||||
let expected = [
|
||||
"contributor-742/main",
|
||||
"issue-739/main",
|
||||
"issue-765/main",
|
||||
"main",
|
||||
"origin/main",
|
||||
"origin/topic/HEAD",
|
||||
"topic/HEAD",
|
||||
];
|
||||
let mut branches = repo.log_details(&tip).unwrap().containing_branches;
|
||||
branches.sort();
|
||||
assert_eq!(branches, expected);
|
||||
let mut listed: Vec<_> = repo.branches().unwrap().into_iter().map(|b| b.name).collect();
|
||||
listed.sort();
|
||||
assert_eq!(listed, expected);
|
||||
let log = repo.log(&LogQuery::default()).unwrap();
|
||||
let mut labels: Vec<_> = log[0].refs.iter().filter(|r| *r != "HEAD").cloned().collect();
|
||||
labels.sort();
|
||||
assert_eq!(labels, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn followed_history_carries_the_filename_at_each_revision() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
||||
Reference in new issue
Block a user