summaryrefslogtreecommitdiffstats
path: root/asyncgit/src/sync/branch/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'asyncgit/src/sync/branch/mod.rs')
-rw-r--r--asyncgit/src/sync/branch/mod.rs1162
1 files changed, 581 insertions, 581 deletions
diff --git a/asyncgit/src/sync/branch/mod.rs b/asyncgit/src/sync/branch/mod.rs
index c3794c28..5b6bee6e 100644
--- a/asyncgit/src/sync/branch/mod.rs
+++ b/asyncgit/src/sync/branch/mod.rs
@@ -6,11 +6,11 @@ pub mod merge_rebase;
pub mod rename;
use super::{
- remotes::get_default_remote_in_repo, utils::bytes2string,
+ remotes::get_default_remote_in_repo, utils::bytes2string,
};
use crate::{
- error::{Error, Result},
- sync::{utils, CommitId},
+ error::{Error, Result},
+ sync::{utils, CommitId},
};
use git2::{Branch, BranchType, Repository};
use scopetime::scope_time;
@@ -19,741 +19,741 @@ use utils::get_head_repo;
/// returns the branch-name head is currently pointing to
/// this might be expensive, see `cached::BranchName`
pub(crate) fn get_branch_name(repo_path: &str) -> Result<String> {
- let repo = utils::repo(repo_path)?;
+ let repo = utils::repo(repo_path)?;
- get_branch_name_repo(&repo)
+ get_branch_name_repo(&repo)
}
/// ditto
pub(crate) fn get_branch_name_repo(
- repo: &Repository,
+ repo: &Repository,
) -> Result<String> {
- scope_time!("get_branch_name_repo");
+ scope_time!("get_branch_name_repo");
- let iter = repo.branches(None)?;
+ let iter = repo.branches(None)?;
- for b in iter {
- let b = b?;
+ for b in iter {
+ let b = b?;
- if b.0.is_head() {
- let name = b.0.name()?.unwrap_or("");
- return Ok(name.into());
- }
- }
+ if b.0.is_head() {
+ let name = b.0.name()?.unwrap_or("");
+ return Ok(name.into());
+ }
+ }
- Err(Error::NoHead)
+ Err(Error::NoHead)
}
///
#[derive(Debug)]
pub struct LocalBranch {
- ///
- pub is_head: bool,
- ///
- pub has_upstream: bool,
- ///
- pub remote: Option<String>,
+ ///
+ pub is_head: bool,
+ ///
+ pub has_upstream: bool,
+ ///
+ pub remote: Option<String>,
}
///
#[derive(Debug)]
pub enum BranchDetails {
- ///
- Local(LocalBranch),
- ///
- Remote,
+ ///
+ Local(LocalBranch),
+ ///
+ Remote,
}
///
#[derive(Debug)]
pub struct BranchInfo {
- ///
- pub name: String,
- ///
- pub reference: String,
- ///
- pub top_commit_message: String,
- ///
- pub top_commit: CommitId,
- ///
- pub details: BranchDetails,
+ ///
+ pub name: String,
+ ///
+ pub reference: String,
+ ///
+ pub top_commit_message: String,
+ ///
+ pub top_commit: CommitId,
+ ///
+ pub details: BranchDetails,
}
impl BranchInfo {
- /// returns details about local branch or None
- pub const fn local_details(&self) -> Option<&LocalBranch> {
- if let BranchDetails::Local(details) = &self.details {
- return Some(details);
- }
-
- None
- }
+ /// returns details about local branch or None
+ pub const fn local_details(&self) -> Option<&LocalBranch> {
+ if let BranchDetails::Local(details) = &self.details {
+ return Some(details);
+ }
+
+ None
+ }
}
///
pub fn validate_branch_name(name: &str) -> Result<bool> {
- scope_time!("validate_branch_name");
+ scope_time!("validate_branch_name");
- let valid = Branch::name_is_valid(name)?;
+ let valid = Branch::name_is_valid(name)?;
- Ok(valid)
+ Ok(valid)
}
/// returns a list of `BranchInfo` with a simple summary on each branch
/// `local` filters for local branches otherwise remote branches will be returned
pub fn get_branches_info(
- repo_path: &str,
- local: bool,
+ repo_path: &str,
+ local: bool,
) -> Result<Vec<BranchInfo>> {
- scope_time!("get_branches_info");
-
- let filter = if local {
- BranchType::Local
- } else {
- BranchType::Remote
- };
-
- let repo = utils::repo(repo_path)?;
- let mut branches_for_display: Vec<BranchInfo> = repo
- .branches(Some(filter))?
- .map(|b| {
- let branch = b?.0;
- let top_commit = branch.get().peel_to_commit()?;
- let reference = bytes2string(branch.get().name_bytes())?;
- let upstream = branch.upstream();
-
- let remote = repo
- .branch_upstream_remote(&reference)
- .ok()
- .as_ref()
- .and_then(git2::Buf::as_str)
- .map(String::from);
-
- let details = if local {
- BranchDetails::Local(LocalBranch {
- is_head: branch.is_head(),
- has_upstream: upstream.is_ok(),
- remote,
- })
- } else {
- BranchDetails::Remote
- };
-
- Ok(BranchInfo {
- name: bytes2string(branch.name_bytes()?)?,
- reference,
- top_commit_message: bytes2string(
- top_commit.summary_bytes().unwrap_or_default(),
- )?,
- top_commit: top_commit.id().into(),
- details,
- })
- })
- .filter_map(Result::ok)
- .collect();
-
- branches_for_display.sort_by(|a, b| a.name.cmp(&b.name));
-
- Ok(branches_for_display)
+ scope_time!("get_branches_info");
+
+ let filter = if local {
+ BranchType::Local
+ } else {
+ BranchType::Remote
+ };
+
+ let repo = utils::repo(repo_path)?;
+ let mut branches_for_display: Vec<BranchInfo> = repo
+ .branches(Some(filter))?
+ .map(|b| {
+ let branch = b?.0;
+ let top_commit = branch.get().peel_to_commit()?;
+ let reference = bytes2string(branch.get().name_bytes())?;
+ let upstream = branch.upstream();
+
+ let remote = repo
+ .branch_upstream_remote(&reference)
+ .ok()
+ .as_ref()
+ .and_then(git2::Buf::as_str)
+ .map(String::from);
+
+ let details = if local {
+ BranchDetails::Local(LocalBranch {
+ is_head: branch.is_head(),
+ has_upstream: upstream.is_ok(),
+ remote,
+ })
+ } else {
+ BranchDetails::Remote
+ };
+
+ Ok(BranchInfo {
+ name: bytes2string(branch.name_bytes()?)?,
+ reference,
+ top_commit_message: bytes2string(
+ top_commit.summary_bytes().unwrap_or_default(),
+ )?,
+ top_commit: top_commit.id().into(),
+ details,
+ })
+ })
+ .filter_map(Result::ok)
+ .collect();
+
+ branches_for_display.sort_by(|a, b| a.name.cmp(&b.name));
+
+ Ok(branches_for_display)
}
///
#[derive(Debug, Default)]
pub struct BranchCompare {
- ///
- pub ahead: usize,
- ///
- pub behind: usize,
+ ///
+ pub ahead: usize,
+ ///
+ pub behind: usize,
}
///
pub(crate) fn branch_set_upstream(
- repo: &Repository,
- branch_name: &str,
+ repo: &Repository,
+ branch_name: &str,
) -> Result<()> {
- scope_time!("branch_set_upstream");
+ scope_time!("branch_set_upstream");
- let mut branch =
- repo.find_branch(branch_name, BranchType::Local)?;
+ let mut branch =
+ repo.find_branch(branch_name, BranchType::Local)?;
- if branch.upstream().is_err() {
- let remote = get_default_remote_in_repo(repo)?;
- let upstream_name = format!("{}/{}", remote, branch_name);
- branch.set_upstream(Some(upstream_name.as_str()))?;
- }
+ if branch.upstream().is_err() {
+ let remote = get_default_remote_in_repo(repo)?;
+ let upstream_name = format!("{}/{}", remote, branch_name);
+ branch.set_upstream(Some(upstream_name.as_str()))?;
+ }
- Ok(())
+ Ok(())
}
/// returns remote of the upstream tracking branch for `branch`
pub fn get_branch_remote(
- repo_path: &str,
- branch: &str,
+ repo_path: &str,
+ branch: &str,
) -> Result<Option<String>> {
- let repo = utils::repo(repo_path)?;
- let branch = repo.find_branch(branch, BranchType::Local)?;
- let reference = bytes2string(branch.get().name_bytes())?;
- let remote_name = repo.branch_upstream_remote(&reference).ok();
- if let Some(remote_name) = remote_name {
- Ok(Some(bytes2string(remote_name.as_ref())?))
- } else {
- Ok(None)
- }
+ let repo = utils::repo(repo_path)?;
+ let branch = repo.find_branch(branch, BranchType::Local)?;
+ let reference = bytes2string(branch.get().name_bytes())?;
+ let remote_name = repo.branch_upstream_remote(&reference).ok();
+ if let Some(remote_name) = remote_name {
+ Ok(Some(bytes2string(remote_name.as_ref())?))
+ } else {
+ Ok(None)
+ }
}
/// returns whether the pull merge strategy is set to rebase
pub fn config_is_pull_rebase(repo_path: &str) -> Result<bool> {
- let repo = utils::repo(repo_path)?;
- let config = repo.config()?;
+ let repo = utils::repo(repo_path)?;
+ let config = repo.config()?;
- if let Ok(rebase) = config.get_entry("pull.rebase") {
- let value =
- rebase.value().map(String::from).unwrap_or_default();
- return Ok(value == "true");
- };
+ if let Ok(rebase) = config.get_entry("pull.rebase") {
+ let value =
+ rebase.value().map(String::from).unwrap_or_default();
+ return Ok(value == "true");
+ };
- Ok(false)
+ Ok(false)
}
///
pub fn branch_compare_upstream(
- repo_path: &str,
- branch: &str,
+ repo_path: &str,
+ branch: &str,
) -> Result<BranchCompare> {
- scope_time!("branch_compare_upstream");
+ scope_time!("branch_compare_upstream");
- let repo = utils::repo(repo_path)?;
+ let repo = utils::repo(repo_path)?;
- let branch = repo.find_branch(branch, BranchType::Local)?;
+ let branch = repo.find_branch(branch, BranchType::Local)?;
- let upstream = branch.upstream()?;
+ let upstream = branch.upstream()?;
- let branch_commit =
- branch.into_reference().peel_to_commit()?.id();
+ let branch_commit =
+ branch.into_reference().peel_to_commit()?.id();
- let upstream_commit =
- upstream.into_reference().peel_to_commit()?.id();
+ let upstream_commit =
+ upstream.into_reference().peel_to_commit()?.id();
- let (ahead, behind) =
- repo.graph_ahead_behind(branch_commit, upstream_commit)?;
+ let (ahead, behind) =
+ repo.graph_ahead_behind(branch_commit, upstream_commit)?;
- Ok(BranchCompare { ahead, behind })
+ Ok(BranchCompare { ahead, behind })
}
/// Modify HEAD to point to a branch then checkout head, does not work if there are uncommitted changes
pub fn checkout_branch(
- repo_path: &str,
- branch_ref: &str,
+ repo_path: &str,
+ branch_ref: &str,
) -> Result<()> {
- scope_time!("checkout_branch");
-
- // This defaults to a safe checkout, so don't delete anything that
- // hasn't been committed or stashed, in this case it will Err
- let repo = utils::repo(repo_path)?;
- let cur_ref = repo.head()?;
- let statuses = repo.statuses(Some(
- git2::StatusOptions::new().include_ignored(false),
- ))?;
-
- if statuses.is_empty() {
- repo.set_head(branch_ref)?;
-
- if let Err(e) = repo.checkout_head(Some(
- git2::build::CheckoutBuilder::new().force(),
- )) {
- // This is safe beacuse cur_ref was just found
- repo.set_head(
- bytes2string(cur_ref.name_bytes())?.as_str(),
- )?;
- return Err(Error::Git(e));
- }
- Ok(())
- } else {
- Err(Error::UncommittedChanges)
- }
+ scope_time!("checkout_branch");
+
+ // This defaults to a safe checkout, so don't delete anything that
+ // hasn't been committed or stashed, in this case it will Err
+ let repo = utils::repo(repo_path)?;
+ let cur_ref = repo.head()?;
+ let statuses = repo.statuses(Some(
+ git2::StatusOptions::new().include_ignored(false),
+ ))?;
+
+ if statuses.is_empty() {
+ repo.set_head(branch_ref)?;
+
+ if let Err(e) = repo.checkout_head(Some(
+ git2::build::CheckoutBuilder::new().force(),
+ )) {
+ // This is safe beacuse cur_ref was just found
+ repo.set_head(
+ bytes2string(cur_ref.name_bytes())?.as_str(),
+ )?;
+ return Err(Error::Git(e));
+ }
+ Ok(())
+ } else {
+ Err(Error::UncommittedChanges)
+ }
}
///
pub fn checkout_remote_branch(
- repo_path: &str,
- branch: &BranchInfo,
+ repo_path: &str,
+ branch: &BranchInfo,
) -> Result<()> {
- scope_time!("checkout_remote_branch");
-
- let repo = utils::repo(repo_path)?;
- let cur_ref = repo.head()?;
-
- if !repo
- .statuses(Some(
- git2::StatusOptions::new().include_ignored(false),
- ))?
- .is_empty()
- {
- return Err(Error::UncommittedChanges);
- }
-
- let name = branch.name.rfind('/').map_or_else(
- || branch.name.clone(),
- |pos| branch.name[pos..].to_string(),
- );
-
- let commit = repo.find_commit(branch.top_commit.into())?;
- let mut new_branch = repo.branch(&name, &commit, false)?;
- new_branch.set_upstream(Some(&branch.name))?;
-
- repo.set_head(
- bytes2string(new_branch.into_reference().name_bytes())?
- .as_str(),
- )?;
-
- if let Err(e) = repo.checkout_head(Some(
- git2::build::CheckoutBuilder::new().force(),
- )) {
- // This is safe beacuse cur_ref was just found
- repo.set_head(bytes2string(cur_ref.name_bytes())?.as_str())?;
- return Err(Error::Git(e));
- }
- Ok(())
+ scope_time!("checkout_remote_branch");
+
+ let repo = utils::repo(repo_path)?;
+ let cur_ref = repo.head()?;
+
+ if !repo
+ .statuses(Some(
+ git2::StatusOptions::new().include_ignored(false),
+ ))?
+ .is_empty()
+ {
+ return Err(Error::UncommittedChanges);
+ }
+
+ let name = branch.name.rfind('/').map_or_else(
+ || branch.name.clone(),
+ |pos| branch.name[pos..].to_string(),
+ );
+
+ let commit = repo.find_commit(branch.top_commit.into())?;
+ let mut new_branch = repo.branch(&name, &commit, false)?;
+ new_branch.set_upstream(Some(&branch.name))?;
+
+ repo.set_head(
+ bytes2string(new_branch.into_reference().name_bytes())?
+ .as_str(),
+ )?;
+
+ if let Err(e) = repo.checkout_head(Some(
+ git2::build::CheckoutBuilder::new().force(),
+ )) {
+ // This is safe beacuse cur_ref was just found
+ repo.set_head(bytes2string(cur_ref.name_bytes())?.as_str())?;
+ return Err(Error::Git(e));
+ }
+ Ok(())
}
/// The user must not be on the branch for the branch to be deleted
pub fn delete_branch(
- repo_path: &str,
- branch_ref: &str,
+ repo_path: &str,
+ branch_ref: &str,
) -> Result<()> {
- scope_time!("delete_branch");
-
- let repo = utils::repo(repo_path)?;
- let branch_as_ref = repo.find_reference(branch_ref)?;
- let mut branch = git2::Branch::wrap(branch_as_ref);
- if branch.is_head() {
- return Err(Error::Generic("You cannot be on the branch you want to delete, switch branch, then delete this branch".to_string()));
- }
- branch.delete()?;
- Ok(())
+ scope_time!("delete_branch");
+
+ let repo = utils::repo(repo_path)?;
+ let branch_as_ref = repo.find_reference(branch_ref)?;
+ let mut branch = git2::Branch::wrap(branch_as_ref);
+ if branch.is_head() {
+ return Err(Error::Generic("You cannot be on the branch you want to delete, switch branch, then delete this branch".to_string()));
+ }
+ branch.delete()?;
+ Ok(())
}
/// creates a new branch pointing to current HEAD commit and updating HEAD to new branch
pub fn create_branch(repo_path: &str, name: &str) -> Result<String> {
- scope_time!("create_branch");
+ scope_time!("create_branch");
- let repo = utils::repo(repo_path)?;
+ let repo = utils::repo(repo_path)?;
- let head_id = get_head_repo(&repo)?;
- let head_commit = repo.find_commit(head_id.into())?;
+ let head_id = get_head_repo(&repo)?;
+ let head_commit = repo.find_commit(head_id.into())?;
- let branch = repo.branch(name, &head_commit, false)?;
- let branch_ref = branch.into_reference();
- let branch_ref_name = bytes2string(branch_ref.name_bytes())?;
- repo.set_head(branch_ref_name.as_str())?;
+ let branch = repo.branch(name, &head_commit, false)?;
+ let branch_ref = branch.into_reference();
+ let branch_ref_name = bytes2string(branch_ref.name_bytes())?;
+ repo.set_head(branch_ref_name.as_str())?;
- Ok(branch_ref_name)
+ Ok(branch_ref_name)
}
#[cfg(test)]
mod tests_branch_name {
- use super::*;
- use crate::sync::tests::{repo_init, repo_init_empty};
-
- #[test]
- fn test_smoke() {
- let (_td, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- assert_eq!(
- get_branch_name(repo_path).unwrap().as_str(),
- "master"
- );
- }
-
- #[test]
- fn test_empty_repo() {
- let (_td, repo) = repo_init_empty().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- assert!(matches!(
- get_branch_name(repo_path),
- Err(Error::NoHead)
- ));
- }
+ use super::*;
+ use crate::sync::tests::{repo_init, repo_init_empty};
+
+ #[test]
+ fn test_smoke() {
+ let (_td, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ assert_eq!(
+ get_branch_name(repo_path).unwrap().as_str(),
+ "master"
+ );
+ }
+
+ #[test]
+ fn test_empty_repo() {
+ let (_td, repo) = repo_init_empty().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ assert!(matches!(
+ get_branch_name(repo_path),
+ Err(Error::NoHead)
+ ));
+ }
}
#[cfg(test)]
mod tests_create_branch {
- use super::*;
- use crate::sync::tests::repo_init;
-
- #[test]
- fn test_smoke() {
- let (_td, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- create_branch(repo_path, "branch1").unwrap();
-
- assert_eq!(
- get_branch_name(repo_path).unwrap().as_str(),
- "branch1"
- );
- }
+ use super::*;
+ use crate::sync::tests::repo_init;
+
+ #[test]
+ fn test_smoke() {
+ let (_td, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ create_branch(repo_path, "branch1").unwrap();
+
+ assert_eq!(
+ get_branch_name(repo_path).unwrap().as_str(),
+ "branch1"
+ );
+ }
}
#[cfg(test)]
mod tests_branch_compare {
- use super::*;
- use crate::sync::tests::repo_init;
+ use super::*;
+ use crate::sync::tests::repo_init;
- #[test]
- fn test_smoke() {
- let (_td, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
+ #[test]
+ fn test_smoke() {
+ let (_td, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
- create_branch(repo_path, "test").unwrap();
+ create_branch(repo_path, "test").unwrap();
- let res = branch_compare_upstream(repo_path, "test");
+ let res = branch_compare_upstream(repo_path, "test");
- assert_eq!(res.is_err(), true);
- }
+ assert_eq!(res.is_err(), true);
+ }
}
#[cfg(test)]
mod tests_branches {
- use super::*;
- use crate::sync::{
- remotes::{get_remotes, push::push},
- rename_branch,
- tests::{
- debug_cmd_print, repo_clone, repo_init, repo_init_bare,
- write_commit_file,
- },
- };
-
- #[test]
- fn test_smoke() {
- let (_td, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- assert_eq!(
- get_branches_info(repo_path, true)
- .unwrap()
- .iter()
- .map(|b| b.name.clone())
- .collect::<Vec<_>>(),
- vec!["master"]
- );
- }
-
- #[test]
- fn test_multiple() {
- let (_td, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- create_branch(repo_path, "test").unwrap();
-
- assert_eq!(
- get_branches_info(repo_path, true)
- .unwrap()
- .iter()
- .map(|b| b.name.clone())
- .collect::<Vec<_>>(),
- vec!["master", "test"]
- );
- }
-
- fn clone_branch_commit_push(target: &str, branch_name: &str) {
- let (dir, repo) = repo_clone(target).unwrap();
- let dir = dir.path().to_str().unwrap();
-
- write_commit_file(&repo, "f1.txt", "foo", "c1");
- rename_branch(dir, "refs/heads/master", branch_name).unwrap();
- push(dir, "origin", branch_name, false, false, None, None)
- .unwrap();
- }
-
- #[test]
- fn test_remotes_of_branches() {
- let (r1_path, _remote1) = repo_init_bare().unwrap();
- let (r2_path, _remote2) = repo_init_bare().unwrap();
- let (_r, repo) = repo_init().unwrap();
-
- let r1_path = r1_path.path().to_str().unwrap();
- let r2_path = r2_path.path().to_str().unwrap();
-
- //Note: create those test branches in our remotes
- clone_branch_commit_push(r1_path, "r1branch");
- clone_branch_commit_push(r2_path, "r2branch");
-
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- //add the remotes
- repo.remote("r1", r1_path).unwrap();
- repo.remote("r2", r2_path).unwrap();
-
- //verify we got the remotes
- let remotes = get_remotes(repo_path).unwrap();
- assert_eq!(
- remotes,
- vec![String::from("r1"), String::from("r2")]
- );
-
- //verify we got only master right now
- let branches = get_branches_info(repo_path, true).unwrap();
- assert_eq!(branches.len(), 1);
- assert_eq!(branches[0].name, String::from("master"));
-
- //pull stuff from the two remotes
- debug_cmd_print(repo_path, "git pull r1");
- debug_cmd_print(repo_path, "git pull r2");
-
- //create local tracking branches
- debug_cmd_print(
- repo_path,
- "git checkout --track r1/r1branch",
- );
- debug_cmd_print(
- repo_path,
- "git checkout --track r2/r2branch",
- );
-
- let branches = get_branches_info(repo_path, true).unwrap();
- assert_eq!(branches.len(), 3);
- assert_eq!(
- branches[1]
- .local_details()
- .unwrap()
- .remote
- .as_ref()
- .unwrap(),
- "r1"
- );
- assert_eq!(
- branches[2]
- .local_details()
- .unwrap()
- .remote
- .as_ref()
- .unwrap(),
- "r2"
- );
-
- assert_eq!(
- get_branch_remote(repo_path, "r1branch")
- .unwrap()
- .unwrap(),
- String::from("r1")
- );
-
- assert_eq!(
- get_branch_remote(repo_path, "r2branch")
- .unwrap()
- .unwrap(),
- String::from("r2")
- );
- }
-
- #[test]
- fn test_branch_remote_no_upstream() {
- let (_r, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- assert_eq!(
- get_branch_remote(repo_path, "master").unwrap(),
- None
- );
- }
-
- #[test]
- fn test_branch_remote_no_branch() {
- let (_r, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- assert!(get_branch_remote(repo_path, "foo").is_err());
- }
+ use super::*;
+ use crate::sync::{
+ remotes::{get_remotes, push::push},
+ rename_branch,
+ tests::{
+ debug_cmd_print, repo_clone, repo_init, repo_init_bare,
+ write_commit_file,
+ },
+ };
+
+ #[test]
+ fn test_smoke() {
+ let (_td, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ assert_eq!(
+ get_branches_info(repo_path, true)
+ .unwrap()
+ .iter()
+ .map(|b| b.name.clone())
+ .collect::<Vec<_>>(),
+ vec!["master"]
+ );
+ }
+
+ #[test]
+ fn test_multiple() {
+ let (_td, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ create_branch(repo_path, "test").unwrap();
+
+ assert_eq!(
+ get_branches_info(repo_path, true)
+ .unwrap()
+ .iter()
+ .map(|b| b.name.clone())
+ .collect::<Vec<_>>(),
+ vec!["master", "test"]
+ );
+ }
+
+ fn clone_branch_commit_push(target: &str, branch_name: &str) {
+ let (dir, repo) = repo_clone(target).unwrap();
+ let dir = dir.path().to_str().unwrap();
+
+ write_commit_file(&repo, "f1.txt", "foo", "c1");
+ rename_branch(dir, "refs/heads/master", branch_name).unwrap();
+ push(dir, "origin", branch_name, false, false, None, None)
+ .unwrap();
+ }
+
+ #[test]
+ fn test_remotes_of_branches() {
+ let (r1_path, _remote1) = repo_init_bare().unwrap();
+ let (r2_path, _remote2) = repo_init_bare().unwrap();
+ let (_r, repo) = repo_init().unwrap();
+
+ let r1_path = r1_path.path().to_str().unwrap();
+ let r2_path = r2_path.path().to_str().unwrap();
+
+ //Note: create those test branches in our remotes
+ clone_branch_commit_push(r1_path, "r1branch");
+ clone_branch_commit_push(r2_path, "r2branch");
+
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ //add the remotes
+ repo.remote("r1", r1_path).unwrap();
+ repo.remote("r2", r2_path).unwrap();
+
+ //verify we got the remotes
+ let remotes = get_remotes(repo_path).unwrap();
+ assert_eq!(
+ remotes,
+ vec![String::from("r1"), String::from("r2")]
+ );
+
+ //verify we got only master right now
+ let branches = get_branches_info(repo_path, true).unwrap();
+ assert_eq!(branches.len(), 1);
+ assert_eq!(branches[0].name, String::from("master"));
+
+ //pull stuff from the two remotes
+ debug_cmd_print(repo_path, "git pull r1");
+ debug_cmd_print(repo_path, "git pull r2");
+
+ //create local tracking branches
+ debug_cmd_print(
+ repo_path,
+ "git checkout --track r1/r1branch",
+ );
+ debug_cmd_print(
+ repo_path,
+ "git checkout --track r2/r2branch",
+ );
+
+ let branches = get_branches_info(repo_path, true).unwrap();
+ assert_eq!(branches.len(), 3);
+ assert_eq!(
+ branches[1]
+ .local_details()
+ .unwrap()
+ .remote
+ .as_ref()
+ .unwrap(),
+ "r1"
+ );
+ assert_eq!(
+ branches[2]
+ .local_details()
+ .unwrap()
+ .remote
+ .as_ref()
+ .unwrap(),
+ "r2"
+ );
+
+ assert_eq!(
+ get_branch_remote(repo_path, "r1branch")
+ .unwrap()
+ .unwrap(),
+ String::from("r1")
+ );
+
+ assert_eq!(
+ get_branch_remote(repo_path, "r2branch")
+ .unwrap()
+ .unwrap(),
+ String::from("r2")
+ );
+ }
+
+ #[test]
+ fn test_branch_remote_no_upstream() {
+ let (_r, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ assert_eq!(
+ get_branch_remote(repo_path, "master").unwrap(),
+ None
+ );
+ }
+
+ #[test]
+ fn test_branch_remote_no_branch() {
+ let (_r, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ assert!(get_branch_remote(repo_path, "foo").is_err());
+ }
}
#[cfg(test)]
mod tests_checkout {
- use super::*;
- use crate::sync::tests::repo_init;
-
- #[test]
- fn test_smoke() {
- let (_td, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- assert!(
- checkout_branch(repo_path, "refs/heads/master").is_ok()
- );
- assert!(
- checkout_branch(repo_path, "refs/heads/foobar").is_err()
- );
- }
-
- #[test]
- fn test_multiple() {
- let (_td, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- create_branch(repo_path, "test").unwrap();
-
- assert!(checkout_branch(repo_path, "refs/heads/test").is_ok());
- assert!(
- checkout_branch(repo_path, "refs/heads/master").is_ok()
- );
- assert!(checkout_branch(repo_path, "refs/heads/test").is_ok());
- }
+ use super::*;
+ use crate::sync::tests::repo_init;
+
+ #[test]
+ fn test_smoke() {
+ let (_td, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ assert!(
+ checkout_branch(repo_path, "refs/heads/master").is_ok()
+ );
+ assert!(
+ checkout_branch(repo_path, "refs/heads/foobar").is_err()
+ );
+ }
+
+ #[test]
+ fn test_multiple() {
+ let (_td, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ create_branch(repo_path, "test").unwrap();
+
+ assert!(checkout_branch(repo_path, "refs/heads/test").is_ok());
+ assert!(
+ checkout_branch(repo_path, "refs/heads/master").is_ok()
+ );
+ assert!(checkout_branch(repo_path, "refs/heads/test").is_ok());
+ }
}
#[cfg(test)]
mod test_delete_branch {
- use super::*;
- use crate::sync::tests::repo_init;
-
- #[test]
- fn test_delete_branch() {
- let (_td, repo) = repo_init().unwrap();
- let root = repo.path().parent().unwrap();
- let repo_path = root.as_os_str().to_str().unwrap();
-
- create_branch(repo_path, "branch1").unwrap();
- create_branch(repo_path, "branch2").unwrap();
-
- checkout_branch(repo_path, "refs/heads/branch1").unwrap();
-
- assert_eq!(
- repo.branches(None)
- .unwrap()
- .nth(1)
- .unwrap()
- .unwrap()
- .0
- .name()
- .unwrap()
- .unwrap(),
- "branch2"
- );
-
- delete_branch(repo_path, "refs/heads/branch2").unwrap();
-
- assert_eq!(
- repo.branches(None)
- .unwrap()
- .nth(1)
- .unwrap()
- .unwrap()
- .0
- .name()
- .unwrap()
- .unwrap(),
- "master"
- );
- }
+ use super::*;
+ use crate::sync::tests::repo_init;
+
+ #[test]
+ fn test_delete_branch() {
+ let (_td, repo) = repo_init().unwrap();
+ let root = repo.path().parent().unwrap();
+ let repo_path = root.as_os_str().to_str().unwrap();
+
+ create_branch(repo_path, "branch1").unwrap();
+ create_branch(repo_path, "branch2").unwrap();
+
+ checkout_branch(repo_path, "refs/heads/branch1").unwrap();
+
+ assert_eq!(
+ repo.branches(None)
+ .unwrap()
+ .nth(1)
+ .unwrap()
+ .unwrap()
+ .0
+ .name()
+ .unwrap()
+ .unwrap(),
+ "branch2"
+ );
+
+ delete_branch(repo_path, "refs/heads/branch2").unwrap();
+
+ assert_eq!(
+ repo.branches(None)
+ .unwrap()
+ .nth(1)