diff options
Diffstat (limited to 'src/repo')
| -rw-r--r-- | src/repo/git/mod.rs | 42 | ||||
| -rw-r--r-- | src/repo/mod.rs | 8 |
2 files changed, 46 insertions, 4 deletions
diff --git a/src/repo/git/mod.rs b/src/repo/git/mod.rs index b88a13f..24b1e1a 100644 --- a/src/repo/git/mod.rs +++ b/src/repo/git/mod.rs @@ -2,12 +2,12 @@ use super::{LocalRepoState, Repo, RepoError}; use anyhow::Context; use gix::{ - bstr::BString, + bstr::{BString, ByteSlice}, refs::{ transaction::{LogChange, PreviousValue, RefEdit}, FullName, }, - remote, Id, ObjectId, Remote, + remote, Id, ObjectId, Reference, Remote, }; use tracing::debug; @@ -33,6 +33,34 @@ impl Repo { return Ok(LocalRepoState::UnbornHead); } + let head = self.repo()?.head().unwrap(); + let branch = head.referent_name().unwrap(); + let default_branch = self.default_branch()?; + + if !branch.as_bstr().contains_str(default_branch) { + return Ok(LocalRepoState::NonDefaultBranch); + } + + let default_ref = self.default_remote_ref()?.into_fully_peeled_id().unwrap(); + + let head_ref = repo + .head_ref() + .map_err(|_| RepoError::NoHead)? + .ok_or(RepoError::NoHead)? + .into_fully_peeled_id() + .unwrap(); + + let unpushed_commits = head_ref + .ancestors() + .with_boundary([default_ref]) + .all() + .unwrap() + .count(); + + if default_ref != head_ref && unpushed_commits > 0 { + return Ok(LocalRepoState::UnpushedCommits(unpushed_commits)); + } + Ok(LocalRepoState::Clean) } } @@ -45,7 +73,7 @@ impl Repo { .context("fetch: failed to find default remote")?) } - pub fn default_branch(&self) -> Result<BString, RepoError> { + pub fn default_remote_ref(&self) -> Result<Reference, RepoError> { let repo = self.repo()?; let remote = self.default_remote()?; let remote_name = remote.name().context("remote does not have name")?; @@ -56,6 +84,14 @@ impl Repo { debug!("got ref to origin: {:?}", origin_ref); + Ok(origin_ref) + } + + pub fn default_branch(&self) -> Result<BString, RepoError> { + let remote = self.default_remote()?; + let remote_name = remote.name().context("remote does not have name")?; + let origin_ref = self.default_remote_ref()?; + if let Some(origin_ref) = origin_ref.target().try_name() { let shortened = origin_ref.shorten().to_string(); diff --git a/src/repo/mod.rs b/src/repo/mod.rs index 538bf31..480a486 100644 --- a/src/repo/mod.rs +++ b/src/repo/mod.rs @@ -8,8 +8,8 @@ use tracing::error; use crate::forge::Project; mod aggregate; -mod repostate; mod git; +mod repostate; pub use aggregate::*; pub use repostate::*; @@ -47,6 +47,8 @@ pub enum RepoError { NoLocalRepo, #[error("local git repo does not have a remote")] NoRemoteFound, + #[error("no head found")] + NoHead, #[error("could not determine default branch based on remote HEAD")] NoDefaultBranch, #[error("repo is not checked out")] @@ -65,6 +67,10 @@ pub enum RepoError { pub enum LocalRepoState { #[error("operation in progress: {0:?}")] InProgress(gix::state::InProgress), + #[error("currently checked out branch is not default")] + NonDefaultBranch, + #[error("{0} unpushed commits")] + UnpushedCommits(usize), #[error("head is detached")] DetachedHead, #[error("head is unborn")] |
