fix ahead/behind count in git status bar

This commit is contained in:
2026-06-04 14:30:57 +02:00
parent 3164873a66
commit 1bbd8fd1b9
2 changed files with 55 additions and 45 deletions
+1
View File
@@ -79,6 +79,7 @@ base64 = "0.22"
gix = { version = "0.84", features = ["max-performance", "parallel", "status", "blob-diff"] }
gix-diff = "0.64"
gix-status = "0.31"
gix-revwalk = "0.32"
# Image processing (Kitty graphics protocol)
image = { version = "0.25", default-features = false, features = ["png", "gif"] }
+58 -49
View File
@@ -1066,65 +1066,74 @@ fn get_git_status(cwd: &str) -> Option<GitStatus> {
return None;
}
// Get ahead/behind against upstream
// Get ahead/behind against upstream using git's configured upstream
let mut ahead = 0usize;
let mut behind = 0usize;
if let Ok(head_id) = repo.head_id() {
if let Ok(head_ref) = repo.find_reference("HEAD") {
if let gix::refs::TargetRef::Symbolic(upstream_name) = head_ref.target() {
let upstream_full = format!("refs/remotes/origin/{}", upstream_name);
if let Ok(upstream_ref) = repo.find_reference(&upstream_full) {
let mut upstream_ref = upstream_ref;
if let Ok(upstream_id) = upstream_ref.peel_to_id() {
let head_id_detached = head_id.detach();
let upstream_id_detached = upstream_id.detach();
// Count ahead: commits reachable from head_id but not from upstream_id
let mut count = 0usize;
let mut seen = std::collections::HashSet::new();
let mut queue = vec![head_id_detached];
while let Some(current) = queue.pop() {
if seen.contains(&current) {
continue;
}
seen.insert(current);
if let Ok(commit) = repo.find_commit(current.clone()) {
for parent_oid in commit.parent_ids() {
let parent_oid_detached = parent_oid.detach();
if parent_oid_detached == upstream_id_detached {
break;
}
if !seen.contains(&parent_oid_detached) {
queue.push(parent_oid_detached);
}
}
}
count += 1;
}
ahead = count;
if let Ok(Some(full_name)) = repo.head_name() {
// Use gix's branch_remote_tracking_ref_name to get the remote tracking branch
if let Some(upstream_result) = repo.branch_remote_tracking_ref_name(full_name.as_ref(), gix::remote::Direction::Fetch) {
if let Ok(upstream_ref_name) = upstream_result {
if let Ok(upstream_ref) = repo.find_reference(upstream_ref_name.as_ref()) {
let mut upstream_ref = upstream_ref;
if let Ok(upstream_id) = upstream_ref.peel_to_id() {
let head_id_detached = head_id.detach();
let upstream_id_detached = upstream_id.detach();
// Count behind: commits reachable from upstream_id but not from head_id
let mut count = 0usize;
let mut seen = std::collections::HashSet::new();
let mut queue = vec![upstream_id_detached];
while let Some(current) = queue.pop() {
if seen.contains(&current) {
continue;
}
seen.insert(current);
if let Ok(commit) = repo.find_commit(current.clone()) {
for parent_oid in commit.parent_ids() {
let parent_oid_detached = parent_oid.detach();
if parent_oid_detached == head_id_detached {
// Find merge base between HEAD and upstream
let mut graph = gix_revwalk::Graph::new(&repo, None);
if let Ok(merge_base_id) = repo.merge_base_with_graph(head_id_detached, upstream_id_detached, &mut graph) {
let merge_base_detached = merge_base_id.detach();
// Count ahead: commits from merge_base to HEAD (exclusive of merge_base)
let mut count = 0usize;
let mut seen = std::collections::HashSet::new();
let mut queue = vec![head_id_detached];
while let Some(current) = queue.pop() {
if seen.contains(&current) {
continue;
}
seen.insert(current);
if current == merge_base_detached {
break;
}
if !seen.contains(&parent_oid_detached) {
queue.push(parent_oid_detached);
if let Ok(commit) = repo.find_commit(current.clone()) {
for parent_oid in commit.parent_ids() {
let parent_oid_detached = parent_oid.detach();
if !seen.contains(&parent_oid_detached) {
queue.push(parent_oid_detached);
}
}
}
count += 1;
}
ahead = count;
// Count behind: commits from merge_base to upstream (exclusive of merge_base)
let mut count = 0usize;
let mut seen = std::collections::HashSet::new();
let mut queue = vec![upstream_id_detached];
while let Some(current) = queue.pop() {
if seen.contains(&current) {
continue;
}
seen.insert(current);
if current == merge_base_detached {
break;
}
if let Ok(commit) = repo.find_commit(current.clone()) {
for parent_oid in commit.parent_ids() {
let parent_oid_detached = parent_oid.detach();
if !seen.contains(&parent_oid_detached) {
queue.push(parent_oid_detached);
}
}
}
count += 1;
}
behind = count;
}
count += 1;
}
behind = count;
}
}
}