diff --git a/asyncgit/src/sync/merge.rs b/asyncgit/src/sync/merge.rs index c9a5b541..f087bb17 100644 --- a/asyncgit/src/sync/merge.rs +++ b/asyncgit/src/sync/merge.rs @@ -54,14 +54,15 @@ pub fn merge_branch(repo_path: &str, branch: &str) -> Result<()> { } /// -pub fn rebase_branch(repo_path: &str, branch: &str) -> Result<()> { +pub fn rebase_branch( + repo_path: &str, + branch: &str, +) -> Result { scope_time!("rebase_branch"); let repo = utils::repo(repo_path)?; - rebase_branch_repo(&repo, branch)?; - - Ok(()) + rebase_branch_repo(&repo, branch) } /// @@ -92,15 +93,13 @@ pub fn merge_branch_repo( pub fn rebase_branch_repo( repo: &Repository, branch_name: &str, -) -> Result<()> { +) -> Result { let branch = repo.find_branch(branch_name, BranchType::Local)?; let annotated = repo.reference_to_annotated_commit(&branch.into_reference())?; - conflict_free_rebase(repo, &annotated)?; - - Ok(()) + conflict_free_rebase(repo, &annotated) } /// diff --git a/asyncgit/src/sync/rebase.rs b/asyncgit/src/sync/rebase.rs index cece9bff..020f8f25 100644 --- a/asyncgit/src/sync/rebase.rs +++ b/asyncgit/src/sync/rebase.rs @@ -1,13 +1,16 @@ use crate::error::{Error, Result}; +use super::CommitId; + /// rebase attempt which aborts and undo's rebase if any conflict appears pub fn conflict_free_rebase( repo: &git2::Repository, commit: &git2::AnnotatedCommit, -) -> Result<()> { +) -> Result { let mut rebase = repo.rebase(None, Some(commit), None, None)?; let signature = crate::sync::commit::signature_allow_undefined_name(repo)?; + let mut last_commit = None; while let Some(op) = rebase.next() { let _op = op?; // dbg!(op.id()); @@ -17,12 +20,68 @@ pub fn conflict_free_rebase( return Err(Error::RebaseConflict); } - rebase.commit(None, &signature, None)?; + let c = rebase.commit(None, &signature, None)?; + + last_commit = Some(CommitId::from(c)); } + if repo.index()?.has_conflicts() { rebase.abort()?; return Err(Error::RebaseConflict); } + rebase.finish(Some(&signature))?; - Ok(()) + + last_commit.ok_or_else(|| { + Error::Generic(String::from("no commit rebased")) + }) +} + +#[cfg(test)] +mod tests { + use crate::sync::{ + checkout_branch, create_branch, rebase_branch, + tests::{repo_init, write_commit_file}, + CommitId, + }; + use git2::Repository; + + fn parent_ids(repo: &Repository, c: CommitId) -> Vec { + let foo = repo + .find_commit(c.into()) + .unwrap() + .parent_ids() + .map(|id| CommitId::from(id)) + .collect(); + + foo + } + + #[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(); + + let c1 = + write_commit_file(&repo, "test1.txt", "test", "commit1"); + + create_branch(repo_path, "foo").unwrap(); + + let c2 = + write_commit_file(&repo, "test2.txt", "test", "commit2"); + + assert_eq!(parent_ids(&repo, c2), vec![c1]); + + checkout_branch(repo_path, "refs/heads/master").unwrap(); + + let c3 = + write_commit_file(&repo, "test3.txt", "test", "commit3"); + + checkout_branch(repo_path, "refs/heads/foo").unwrap(); + + let r = rebase_branch(repo_path, "master").unwrap(); + + assert_eq!(parent_ids(&repo, r), vec![c3]); + } }