mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-18 23:44:12 +01:00
110 lines
3.5 KiB
Rust
110 lines
3.5 KiB
Rust
use crate::error::Error::GenericError;
|
|
use crate::error::Result;
|
|
use crate::merge::do_merge;
|
|
use crate::repository::open_repo;
|
|
use crate::util::{
|
|
bytes_to_string, get_branch_by_name, get_current_branch, get_default_remote_for_push_in_repo,
|
|
};
|
|
use git2::build::CheckoutBuilder;
|
|
use git2::{BranchType, Repository};
|
|
use log::info;
|
|
use std::path::Path;
|
|
|
|
pub(crate) fn branch_set_upstream_after_push(repo: &Repository, branch_name: &str) -> Result<()> {
|
|
let mut branch = repo.find_branch(branch_name, BranchType::Local)?;
|
|
|
|
if branch.upstream().is_err() {
|
|
let remote = get_default_remote_for_push_in_repo(repo)?;
|
|
let upstream_name = format!("{remote}/{branch_name}");
|
|
branch.set_upstream(Some(upstream_name.as_str()))?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) fn git_checkout_branch(dir: &Path, branch_name: &str, force: bool) -> Result<String> {
|
|
if branch_name.starts_with("origin/") {
|
|
return git_checkout_remote_branch(dir, branch_name, force);
|
|
}
|
|
|
|
let repo = open_repo(dir)?;
|
|
let branch = get_branch_by_name(&repo, branch_name)?;
|
|
let branch_ref = branch.into_reference();
|
|
let branch_tree = branch_ref.peel_to_tree()?;
|
|
|
|
let mut options = CheckoutBuilder::default();
|
|
if force {
|
|
options.force();
|
|
}
|
|
|
|
repo.checkout_tree(branch_tree.as_object(), Some(&mut options))?;
|
|
repo.set_head(branch_ref.name().unwrap())?;
|
|
|
|
Ok(branch_name.to_string())
|
|
}
|
|
|
|
pub(crate) fn git_checkout_remote_branch(dir: &Path, branch_name: &str, force: bool) -> Result<String> {
|
|
let branch_name = branch_name.trim_start_matches("origin/");
|
|
let repo = open_repo(dir)?;
|
|
|
|
let refname = format!("refs/remotes/origin/{}", branch_name);
|
|
let remote_ref = repo.find_reference(&refname)?;
|
|
let commit = remote_ref.peel_to_commit()?;
|
|
|
|
let mut new_branch = repo.branch(branch_name, &commit, false)?;
|
|
let upstream_name = format!("origin/{}", branch_name);
|
|
new_branch.set_upstream(Some(&upstream_name))?;
|
|
|
|
return git_checkout_branch(dir, branch_name, force)
|
|
}
|
|
|
|
pub(crate) fn git_create_branch(dir: &Path, name: &str) -> Result<()> {
|
|
let repo = open_repo(dir)?;
|
|
let head = match repo.head() {
|
|
Ok(h) => h,
|
|
Err(e) if e.code() == git2::ErrorCode::UnbornBranch => {
|
|
let msg = "Cannot create branch when there are no commits";
|
|
return Err(GenericError(msg.into()));
|
|
}
|
|
Err(e) => return Err(e.into()),
|
|
};
|
|
let head = head.peel_to_commit()?;
|
|
|
|
repo.branch(name, &head, false)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) fn git_delete_branch(dir: &Path, name: &str) -> Result<()> {
|
|
let repo = open_repo(dir)?;
|
|
let mut branch = get_branch_by_name(&repo, name)?;
|
|
|
|
if branch.is_head() {
|
|
info!("Deleting head branch");
|
|
let branches = repo.branches(Some(BranchType::Local))?;
|
|
let other_branch = branches.into_iter().filter_map(|b| b.ok()).find(|b| !b.0.is_head());
|
|
let other_branch = match other_branch {
|
|
None => return Err(GenericError("Cannot delete only branch".into())),
|
|
Some(b) => bytes_to_string(b.0.name_bytes()?)?,
|
|
};
|
|
|
|
git_checkout_branch(dir, &other_branch, true)?;
|
|
}
|
|
|
|
branch.delete()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) fn git_merge_branch(dir: &Path, name: &str, _force: bool) -> Result<()> {
|
|
let repo = open_repo(dir)?;
|
|
let local_branch = get_current_branch(&repo)?.unwrap();
|
|
|
|
let commit_to_merge = get_branch_by_name(&repo, name)?.into_reference();
|
|
let commit_to_merge = repo.reference_to_annotated_commit(&commit_to_merge)?;
|
|
|
|
do_merge(&repo, &local_branch, &commit_to_merge)?;
|
|
|
|
Ok(())
|
|
}
|