use super::Repository;
#[derive(Debug)]
#[must_use]
pub struct Branch<'a> {
pub(super) repo: &'a Repository,
pub(super) name: String,
}
impl<'a> Branch<'a> {
pub fn name(&self) -> &str {
&self.name
}
pub fn exists_locally(&self) -> anyhow::Result<bool> {
Ok(self
.repo
.run_command(&[
"rev-parse",
"--verify",
&format!("refs/heads/{}", self.name),
])
.is_ok())
}
pub fn exists(&self) -> anyhow::Result<bool> {
if self.exists_locally()? {
return Ok(true);
}
Ok(!self.remotes()?.is_empty())
}
pub fn remotes(&self) -> anyhow::Result<Vec<String>> {
Ok(self
.repo
.remote_branches()?
.iter()
.filter(|r| r.local_name == self.name)
.map(|r| r.remote_name.clone())
.collect())
}
pub fn upstream(&self) -> anyhow::Result<Option<String>> {
Ok(self
.repo
.local_branch(&self.name)?
.and_then(|b| b.upstream_short.clone()))
}
pub fn unset_upstream(&self) -> anyhow::Result<()> {
self.repo
.run_command(&["branch", "--unset-upstream", &self.name])?;
Ok(())
}
pub fn push_remote(&self) -> Option<String> {
let push_ref = self
.repo
.run_command(&[
"rev-parse",
"--abbrev-ref",
&format!("{}@{{push}}", self.name),
])
.ok()?;
let remote = push_ref.trim().split('/').next()?;
(!remote.is_empty()).then(|| remote.to_string())
}
pub fn push_remote_url(&self) -> Option<String> {
self.repo
.cache
.push_remote_urls
.entry(self.name.clone())
.or_insert_with(|| {
let push_remote = self
.repo
.run_command(&[
"for-each-ref",
"--format=%(push:remotename)",
&format!("refs/heads/{}", self.name),
])
.ok()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())?;
if push_remote.contains("://") || push_remote.starts_with("git@") {
Some(push_remote)
} else {
self.repo.effective_remote_url(&push_remote)
}
})
.clone()
}
}