pub mod merge;
pub mod new;
pub mod unmerge;
use std::collections::HashSet;
use git2::Repository;
use anyhow::{Result, bail};
use crate::core::msg;
use crate::core::repo;
pub(crate) fn warn_if_hidden(repo: &Repository, name: &str) {
let pattern =
repo::hide_branch_pattern(repo).unwrap_or_else(|| repo::DEFAULT_HIDE_PATTERN.to_string());
if !pattern.is_empty() && name.starts_with(&pattern) {
msg::warn(&format!(
"Branch `{}` is hidden from status by default. Use `--all` to show it.",
name
));
}
}
pub(crate) fn should_weave(
info: &repo::RepoInfo,
repo: &Repository,
commit_hash: &str,
) -> Result<bool> {
let head_oid = repo::head_oid(repo)?;
let branch_oid = git2::Oid::from_str(commit_hash)?;
let merge_base_oid = info.upstream.merge_base_oid;
if branch_oid == merge_base_oid {
return Ok(false);
}
if branch_oid == head_oid {
return Ok(true);
}
if !is_on_first_parent_line(repo, head_oid, merge_base_oid, branch_oid)? {
return Ok(false);
}
Ok(true)
}
pub fn is_on_first_parent_line(
repo: &Repository,
from: git2::Oid,
stop: git2::Oid,
target: git2::Oid,
) -> Result<bool> {
let mut current = from;
let mut visited: HashSet<git2::Oid> = HashSet::new();
loop {
if current == stop {
return Ok(false);
}
if !visited.insert(current) {
bail!("cycle detected in commit graph at {}", current);
}
let commit = repo.find_commit(current)?;
let first_parent = match commit.parent_id(0) {
Ok(oid) => oid,
Err(_) => return Ok(false), };
if first_parent == target {
return Ok(true);
}
current = first_parent;
}
}
#[cfg(test)]
#[path = "new_test.rs"]
mod new_tests;
#[cfg(test)]
#[path = "unmerge_test.rs"]
mod unmerge_tests;
#[cfg(test)]
#[path = "merge_test.rs"]
mod merge_tests;