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