Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 97 additions & 61 deletions asyncgit/src/sync/branch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ use super::{utils::bytes2string, RepoPath};
use crate::{
error::{Error, Result},
sync::{
remotes::get_default_remote_for_push_in_repo,
gix_repo, remotes::get_default_remote_for_push_in_repo,
repository::repo, utils::get_head_repo, CommitId,
},
};
use git2::{Branch, BranchType, Repository};
use gix::remote::Direction;
use scopetime::scope_time;
use std::collections::HashSet;

Expand Down Expand Up @@ -123,76 +124,111 @@ pub fn get_branches_info(
) -> Result<Vec<BranchInfo>> {
scope_time!("get_branches_info");

let repo = repo(repo_path)?;
let gix_repo = gix_repo(repo_path)?;
let platform = gix_repo.references()?;
let head_name = gix_repo.head_name().ok().flatten();

let mut branches_for_display: Vec<_> = if local {
platform
.local_branches()?
.flatten()
.filter_map(|mut branch| {
let branch_name = branch.name();
let name = branch_name.shorten().to_string();
let reference = branch_name.to_owned().to_string();
// TODO:
// Verify that this is sufficiently similar to `git2`’s `is_head` by looking at the
// implementation of `git_branch_is_head`.
let is_head =
head_name.as_ref().is_some_and(|head_name| {
head_name.as_ref() == branch_name
});

let top_commit = branch.peel_to_commit().ok()?;
let upstream = branch.remote_tracking_ref_name(
// TODO:
// Is that correct?
Direction::Fetch,
);

let upstream_branch = match upstream {
Some(Ok(reference)) => Some(UpstreamBranch {
reference: reference.into_owned().to_string(),
}),
_ => None,
};

let remote = branch
.remote_name(
// TODO:
// Is that correct?
Direction::Fetch,
)
.map(|name| name.as_bstr().to_string());

let details = BranchDetails::Local(LocalBranch {
is_head,
has_upstream: upstream_branch.is_some(),
upstream: upstream_branch,
remote,
});

let (filter, remotes_with_tracking) = if local {
(BranchType::Local, HashSet::default())
Some(BranchInfo {
name,
reference,
top_commit_message: top_commit
.message()
.ok()?
.title
.to_string(),
top_commit: top_commit.into(),
details,
})
})
.collect()
} else {
let remotes: HashSet<_> = repo
.branches(Some(BranchType::Local))?
.filter_map(|b| {
let branch = b.ok()?.0;
let upstream = branch.upstream();
upstream
.ok()?
.name_bytes()
.ok()
.map(ToOwned::to_owned)
let remotes_with_tracking: HashSet<_> = platform
.local_branches()?
.flatten()
.filter_map(|branch| {
let upstream = branch.remote_tracking_ref_name(
// TODO:
// Is that correct?
Direction::Fetch,
)?;
Some(upstream.ok()?.into_owned())
})
.collect();
(BranchType::Remote, remotes)
};

let mut branches_for_display: Vec<BranchInfo> = repo
.branches(Some(filter))?
.map(|b| {
let branch = b?.0;
let top_commit = branch.get().peel_to_commit()?;
let reference = bytes2string(branch.get().name_bytes())?;
let upstream = branch.upstream();

let remote = repo
.branch_upstream_remote(&reference)
.ok()
.as_ref()
.and_then(git2::Buf::as_str)
.map(String::from);

let name_bytes = branch.name_bytes()?;
platform
.remote_branches()?
.flatten()
.filter_map(|mut branch| {
let branch_name = branch.name();
let name = branch_name.shorten().to_string();
let reference = branch_name.to_owned().to_string();

let upstream_branch =
upstream.ok().and_then(|upstream| {
bytes2string(upstream.get().name_bytes())
.ok()
.map(|reference| UpstreamBranch { reference })
let details = BranchDetails::Remote(RemoteBranch {
has_tracking: remotes_with_tracking
.contains(branch_name),
});

let details = if local {
BranchDetails::Local(LocalBranch {
is_head: branch.is_head(),
has_upstream: upstream_branch.is_some(),
upstream: upstream_branch,
remote,
let top_commit = branch.peel_to_commit().ok()?;

Some(BranchInfo {
name,
reference,
top_commit_message: top_commit
.message()
.ok()?
.title
.to_string(),
top_commit: top_commit.into(),
details,
})
} else {
BranchDetails::Remote(RemoteBranch {
has_tracking: remotes_with_tracking
.contains(name_bytes),
})
};

Ok(BranchInfo {
name: bytes2string(name_bytes)?,
reference,
top_commit_message: bytes2string(
top_commit.summary_bytes().unwrap_or_default(),
)?,
top_commit: top_commit.id().into(),
details,
})
})
.filter_map(Result::ok)
.collect();
.collect()
};

branches_for_display.sort_by(|a, b| a.name.cmp(&b.name));

Expand Down
9 changes: 5 additions & 4 deletions asyncgit/src/sync/tags.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use super::{get_commits_info, CommitId, RepoPath};
use crate::{error::Result, sync::repository::repo};
use crate::{
error::Result,
sync::{gix_repo, repository::repo},
};
use scopetime::scope_time;
use std::collections::{BTreeMap, HashMap, HashSet};

Expand Down Expand Up @@ -58,9 +61,7 @@ pub fn get_tags(repo_path: &RepoPath) -> Result<Tags> {
}
};

let gix_repo: gix::Repository =
gix::ThreadSafeRepository::discover_with_environment_overrides(repo_path.gitpath())
.map(Into::into)?;
let gix_repo = gix_repo(repo_path)?;
let platform = gix_repo.references()?;
for mut reference in (platform.tags()?).flatten() {
let commit = reference.peel_to_commit();
Expand Down
Loading