134 lines
4.5 KiB
Rust
134 lines
4.5 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::{
|
|
bare::GitBare,
|
|
cmd::oid::ObjectId,
|
|
errors::{GitError, GitResult},
|
|
};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct BranchListItem {
|
|
pub name: String,
|
|
pub oid: ObjectId,
|
|
pub is_head: bool,
|
|
pub is_remote: bool,
|
|
pub is_current: bool,
|
|
pub upstream: Option<String>,
|
|
}
|
|
|
|
impl GitBare {
|
|
pub fn branch_list_all(&self) -> GitResult<Vec<BranchListItem>> {
|
|
let repo = self.gix_repo()?;
|
|
let head_name = repo.head_name()?.map(|n| n.shorten().to_string());
|
|
|
|
let mut items = Vec::new();
|
|
let platform = repo.references()?;
|
|
let local_iter = platform.local_branches()?;
|
|
for ref_result in local_iter {
|
|
let reference = ref_result?;
|
|
let name = reference.name().shorten().to_string();
|
|
let is_head = head_name.as_ref() == Some(&name);
|
|
let is_current = is_head;
|
|
|
|
let target = reference.target();
|
|
let target_id = target.try_id().ok_or_else(|| {
|
|
GitError::Internal(
|
|
"local branch has no direct target".to_string(),
|
|
)
|
|
})?;
|
|
let oid = ObjectId::new(target_id.to_hex().to_string());
|
|
let upstream = reference
|
|
.remote_tracking_ref_name(gix::remote::Direction::Fetch)
|
|
.and_then(|r| r.ok())
|
|
.map(|n| n.shorten().to_string());
|
|
|
|
items.push(BranchListItem {
|
|
name,
|
|
oid,
|
|
is_head,
|
|
is_remote: false,
|
|
is_current,
|
|
upstream,
|
|
});
|
|
}
|
|
let remote_iter = platform.remote_branches()?;
|
|
for ref_result in remote_iter {
|
|
let reference = ref_result?;
|
|
let name = reference.name().shorten().to_string();
|
|
let is_head = head_name.as_ref() == Some(&name);
|
|
let is_current = is_head;
|
|
|
|
let target = reference.target();
|
|
let target_id = target.try_id().ok_or_else(|| {
|
|
GitError::Internal(
|
|
"remote branch has no direct target".to_string(),
|
|
)
|
|
})?;
|
|
let oid = ObjectId::new(target_id.to_hex().to_string());
|
|
|
|
items.push(BranchListItem {
|
|
name,
|
|
oid,
|
|
is_head,
|
|
is_remote: true,
|
|
is_current,
|
|
upstream: None,
|
|
});
|
|
}
|
|
|
|
Ok(items)
|
|
}
|
|
|
|
pub fn branch_info(&self, branch: String) -> GitResult<BranchListItem> {
|
|
let repo = self.gix_repo()?;
|
|
let head_name = repo.head_name()?.map(|n| n.shorten().to_string());
|
|
let local_ref_str = format!("refs/heads/{branch}");
|
|
let local_ref = repo.try_find_reference(local_ref_str.as_str())?;
|
|
if let Some(reference) = local_ref {
|
|
let name = reference.name().shorten().to_string();
|
|
let is_head = head_name.as_ref() == Some(&name);
|
|
let target = reference.target();
|
|
let target_id = target.try_id().ok_or_else(|| {
|
|
GitError::Internal("branch has no direct target".to_string())
|
|
})?;
|
|
let oid = ObjectId::new(target_id.to_hex().to_string());
|
|
|
|
let upstream = reference
|
|
.remote_tracking_ref_name(gix::remote::Direction::Fetch)
|
|
.and_then(|r| r.ok())
|
|
.map(|n| n.shorten().to_string());
|
|
|
|
return Ok(BranchListItem {
|
|
name,
|
|
oid,
|
|
is_head,
|
|
is_remote: false,
|
|
is_current: is_head,
|
|
upstream,
|
|
});
|
|
}
|
|
let remote_ref_str = format!("refs/remotes/{branch}");
|
|
let remote_ref = repo.try_find_reference(remote_ref_str.as_str())?;
|
|
if let Some(reference) = remote_ref {
|
|
let name = reference.name().shorten().to_string();
|
|
let is_head = head_name.as_ref() == Some(&name);
|
|
let target = reference.target();
|
|
let target_id = target.try_id().ok_or_else(|| {
|
|
GitError::Internal("branch has no direct target".to_string())
|
|
})?;
|
|
let oid = ObjectId::new(target_id.to_hex().to_string());
|
|
|
|
return Ok(BranchListItem {
|
|
name,
|
|
oid,
|
|
is_head,
|
|
is_remote: true,
|
|
is_current: is_head,
|
|
upstream: None,
|
|
});
|
|
}
|
|
|
|
Err(GitError::RefNotFound(branch))
|
|
}
|
|
}
|