diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/repo/git/mod.rs | 42 | ||||
| -rw-r--r-- | src/repo/mod.rs | 8 | ||||
| -rw-r--r-- | src/update/mod.rs | 28 |
3 files changed, 63 insertions, 15 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")] diff --git a/src/update/mod.rs b/src/update/mod.rs index e5e9f4c..e43f108 100644 --- a/src/update/mod.rs +++ b/src/update/mod.rs @@ -1,5 +1,6 @@ use std::fmt::{Debug, Display}; +use gix::bstr::ByteSlice; use tracing::debug; use crate::{ @@ -43,16 +44,23 @@ impl Repo { let mut progress = gix::progress::Discard {}; - let _fetched = self.fetch()?; - let (remote, head) = self.default_remote_head()?; - debug!("default remote and head: {:?} {:?}", remote, head); - // TODO check out only if the default branch is currently checked out - self.checkout(&remote, head, &mut progress)?; - debug!("finished checkout"); + let fetched = self.fetch()?; - // TODO do not update if there are unpushed commits - self.update_default_branch_ref(&remote, head)?; - debug!("updated default branch reference"); + if fetched { + let (remote, head_id) = self.default_remote_head()?; + debug!("default remote and head: {:?} {:?}", remote, head_id); + + self.checkout(&remote, head_id, &mut progress)?; + debug!("finished checkout"); + + // TODO do not update if there are unpushed commits + self.update_default_branch_ref(&remote, head_id)?; + debug!("updated default branch reference"); + + return Ok(UpdateResult::merged(self.name.clone())); + } + + Ok(UpdateResult::no_changes(self.name.clone())) // let merged = repo.branches(Some(BranchType::Local))? // .filter_map(|x| x.ok()) @@ -77,8 +85,6 @@ impl Repo { // } else { // Ok(UpdateResult::no_changes(self.name.clone())) // } - - Ok(UpdateResult::no_changes(self.name.clone())) } } |
