diff options
Diffstat (limited to 'asyncgit/src/sync/branch/merge_commit.rs')
-rw-r--r-- | asyncgit/src/sync/branch/merge_commit.rs | 466 |
1 files changed, 233 insertions, 233 deletions
diff --git a/asyncgit/src/sync/branch/merge_commit.rs b/asyncgit/src/sync/branch/merge_commit.rs index ee287192..fcabf915 100644 --- a/asyncgit/src/sync/branch/merge_commit.rs +++ b/asyncgit/src/sync/branch/merge_commit.rs @@ -2,8 +2,8 @@ use super::BranchType; use crate::{ - error::{Error, Result}, - sync::{merge_msg, utils, CommitId}, + error::{Error, Result}, + sync::{merge_msg, utils, CommitId}, }; use git2::Commit; use scopetime::scope_time; @@ -12,260 +12,260 @@ use scopetime::scope_time; /// if we did not create conflicts we create a merge commit and return the commit id. /// Otherwise we return `None` pub fn merge_upstream_commit( - repo_path: &str, - branch_name: &str, + repo_path: &str, + branch_name: &str, ) -> Result<Option<CommitId>> { - scope_time!("merge_upstream_commit"); + scope_time!("merge_upstream_commit"); - let repo = utils::repo(repo_path)?; + let repo = utils::repo(repo_path)?; - let branch = repo.find_branch(branch_name, BranchType::Local)?; - let upstream = branch.upstream()?; + let branch = repo.find_branch(branch_name, BranchType::Local)?; + let upstream = branch.upstream()?; - let upstream_commit = upstream.get().peel_to_commit()?; + let upstream_commit = upstream.get().peel_to_commit()?; - let annotated_upstream = repo - .reference_to_annotated_commit(&upstream.into_reference())?; + let annotated_upstream = repo + .reference_to_annotated_commit(&upstream.into_reference())?; - let (analysis, pref) = - repo.merge_analysis(&[&annotated_upstream])?; + let (analysis, pref) = + repo.merge_analysis(&[&annotated_upstream])?; - if !analysis.is_normal() { - return Err(Error::Generic( - "normal merge not possible".into(), - )); - } + if !analysis.is_normal() { + return Err(Error::Generic( + "normal merge not possible".into(), + )); + } - if analysis.is_fast_forward() && pref.is_fastforward_only() { - return Err(Error::Generic( - "ff merge would be possible".into(), - )); - } + if analysis.is_fast_forward() && pref.is_fastforward_only() { + return Err(Error::Generic( + "ff merge would be possible".into(), + )); + } - //TODO: support merge on unborn? - if analysis.is_unborn() { - return Err(Error::Generic("head is unborn".into())); - } + //TODO: support merge on unborn? + if analysis.is_unborn() { + return Err(Error::Generic("head is unborn".into())); + } - repo.merge(&[&annotated_upstream], None, None)?; + repo.merge(&[&annotated_upstream], None, None)?; - if !repo.index()?.has_conflicts() { - let msg = merge_msg(repo_path)?; + if !repo.index()?.has_conflicts() { + let msg = merge_msg(repo_path)?; - let commit_id = - commit_merge_with_head(&repo, &[upstream_commit], &msg)?; + let commit_id = + commit_merge_with_head(&repo, &[upstream_commit], &msg)?; - return Ok(Some(commit_id)); - } + return Ok(Some(commit_id)); + } - Ok(None) + Ok(None) } pub(crate) fn commit_merge_with_head( - repo: &git2::Repository, - commits: &[Commit], - msg: &str, + repo: &git2::Repository, + commits: &[Commit], + msg: &str, ) -> Result<CommitId> { - let signature = - crate::sync::commit::signature_allow_undefined_name(repo)?; - let mut index = repo.index()?; - let tree_id = index.write_tree()?; - let tree = repo.find_tree(tree_id)?; - let head_commit = repo.find_commit( - crate::sync::utils::get_head_repo(repo)?.into(), - )?; - - let mut parents = vec![&head_commit]; - parents.extend(commits); - - let commit_id = repo - .commit( - Some("HEAD"), - &signature, - &signature, - msg, - &tree, - parents.as_slice(), - )? - .into(); - repo.cleanup_state()?; - Ok(commit_id) + let signature = + crate::sync::commit::signature_allow_undefined_name(repo)?; + let mut index = repo.index()?; + let tree_id = index.write_tree()?; + let tree = repo.find_tree(tree_id)?; + let head_commit = repo.find_commit( + crate::sync::utils::get_head_repo(repo)?.into(), + )?; + + let mut parents = vec![&head_commit]; + parents.extend(commits); + + let commit_id = repo + .commit( + Some("HEAD"), + &signature, + &signature, + msg, + &tree, + parents.as_slice(), + )? + .into(); + repo.cleanup_state()?; + Ok(commit_id) } #[cfg(test)] mod test { - use git2::Time; - - use super::*; - use crate::sync::{ - branch_compare_upstream, - remotes::{fetch, push::push}, - tests::{ - debug_cmd_print, get_commit_ids, repo_clone, - repo_init_bare, write_commit_file, write_commit_file_at, - }, - RepoState, - }; - - #[test] - fn test_merge_normal() { - let (r1_dir, _repo) = repo_init_bare().unwrap(); - - let (clone1_dir, clone1) = - repo_clone(r1_dir.path().to_str().unwrap()).unwrap(); - - let (clone2_dir, clone2) = - repo_clone(r1_dir.path().to_str().unwrap()).unwrap(); - - let clone2_dir = clone2_dir.path().to_str().unwrap(); - - // clone1 - - let commit1 = write_commit_file_at( - &clone1, - "test.txt", - "test", - "commit1", - Time::new(1, 0), - ); - - push( - clone1_dir.path().to_str().unwrap(), - "origin", - "master", - false, - false, - None, - None, - ) - .unwrap(); - - // clone2 - - let commit2 = write_commit_file_at( - &clone2, - "test2.txt", - "test", - "commit2", - Time::new(2, 0), - ); - - //push should fail since origin diverged - assert!(push( - clone2_dir, "origin", "master", false, false, None, None, - ) - .is_err()); - - //lets fetch from origin - let bytes = fetch(clone2_dir, "master", None, None).unwrap(); - assert!(bytes > 0); - - //we should be one commit behind - assert_eq!( - branch_compare_upstream(clone2_dir, "master") - .unwrap() - .behind, - 1 - ); - - let merge_commit = - merge_upstream_commit(clone2_dir, "master") - .unwrap() - .unwrap(); - - let state = crate::sync::repo_state(clone2_dir).unwrap(); - assert_eq!(state, RepoState::Clean); - - assert!(!clone2.head_detached().unwrap()); - - let commits = get_commit_ids(&clone2, 10); - assert_eq!(commits.len(), 3); - assert_eq!(commits[0], merge_commit); - assert_eq!(commits[1], commit2); - assert_eq!(commits[2], commit1); - - //verify commit msg - let details = - crate::sync::get_commit_details(clone2_dir, merge_commit) - .unwrap(); - assert_eq!( + use git2::Time; + + use super::*; + use crate::sync::{ + branch_compare_upstream, + remotes::{fetch, push::push}, + tests::{ + debug_cmd_print, get_commit_ids, repo_clone, + repo_init_bare, write_commit_file, write_commit_file_at, + }, + RepoState, + }; + + #[test] + fn test_merge_normal() { + let (r1_dir, _repo) = repo_init_bare().unwrap(); + + let (clone1_dir, clone1) = + repo_clone(r1_dir.path().to_str().unwrap()).unwrap(); + + let (clone2_dir, clone2) = + repo_clone(r1_dir.path().to_str().unwrap()).unwrap(); + + let clone2_dir = clone2_dir.path().to_str().unwrap(); + + // clone1 + + let commit1 = write_commit_file_at( + &clone1, + "test.txt", + "test", + "commit1", + Time::new(1, 0), + ); + + push( + clone1_dir.path().to_str().unwrap(), + "origin", + "master", + false, + false, + None, + None, + ) + .unwrap(); + + // clone2 + + let commit2 = write_commit_file_at( + &clone2, + "test2.txt", + "test", + "commit2", + Time::new(2, 0), + ); + + //push should fail since origin diverged + assert!(push( + clone2_dir, "origin", "master", false, false, None, None, + ) + .is_err()); + + //lets fetch from origin + let bytes = fetch(clone2_dir, "master", None, None).unwrap(); + assert!(bytes > 0); + + //we should be one commit behind + assert_eq!( + branch_compare_upstream(clone2_dir, "master") + .unwrap() + .behind, + 1 + ); + + let merge_commit = + merge_upstream_commit(clone2_dir, "master") + .unwrap() + .unwrap(); + + let state = crate::sync::repo_state(clone2_dir).unwrap(); + assert_eq!(state, RepoState::Clean); + + assert!(!clone2.head_detached().unwrap()); + + let commits = get_commit_ids(&clone2, 10); + assert_eq!(commits.len(), 3); + assert_eq!(commits[0], merge_commit); + assert_eq!(commits[1], commit2); + assert_eq!(commits[2], commit1); + + //verify commit msg + let details = + crate::sync::get_commit_details(clone2_dir, merge_commit) + .unwrap(); + assert_eq!( details.message.unwrap().combine(), String::from("Merge remote-tracking branch 'refs/remotes/origin/master'") ); - } - - #[test] - fn test_merge_normal_non_ff() { - let (r1_dir, _repo) = repo_init_bare().unwrap(); - - let (clone1_dir, clone1) = - repo_clone(r1_dir.path().to_str().unwrap()).unwrap(); - - let (clone2_dir, clone2) = - repo_clone(r1_dir.path().to_str().unwrap()).unwrap(); - - // clone1 - - write_commit_file( - &clone1, - "test.bin", - "test\nfooo", - "commit1", - ); - - debug_cmd_print( - clone2_dir.path().to_str().unwrap(), - "git status", - ); - - push( - clone1_dir.path().to_str().unwrap(), - "origin", - "master", - false, - false, - None, - None, - ) - .unwrap(); - - // clone2 - - write_commit_file( - &clone2, - "test.bin", - "foobar\ntest", - "commit2", - ); - - let bytes = fetch( - clone2_dir.path().to_str().unwrap(), - "master", - None, - None, - ) - .unwrap(); - assert!(bytes > 0); - - let res = merge_upstream_commit( - clone2_dir.path().to_str().unwrap(), - "master", - ) - .unwrap(); - - //this should not have commited cause we left conflicts behind - assert_eq!(res, None); - - let state = crate::sync::repo_state( - clone2_dir.path().to_str().unwrap(), - ) - .unwrap(); - - //validate the repo is in a merge state now - assert_eq!(state, RepoState::Merge); - - //check that we still only have the first commit - let commits = get_commit_ids(&clone1, 10); - assert_eq!(commits.len(), 1); - } + } + + #[test] + fn test_merge_normal_non_ff() { + let (r1_dir, _repo) = repo_init_bare().unwrap(); + + let (clone1_dir, clone1) = + repo_clone(r1_dir.path().to_str().unwrap()).unwrap(); + + let (clone2_dir, clone2) = + repo_clone(r1_dir.path().to_str().unwrap()).unwrap(); + + // clone1 + + write_commit_file( + &clone1, + "test.bin", + "test\nfooo", + "commit1", + ); + + debug_cmd_print( + clone2_dir.path().to_str().unwrap(), + "git status", + ); + + push( + clone1_dir.path().to_str().unwrap(), + "origin", + "master", + false, + false, + None, + None, + ) + .unwrap(); + + // clone2 + + write_commit_file( + &clone2, + "test.bin", + "foobar\ntest", + "commit2", + ); + + let bytes = fetch( + clone2_dir.path().to_str().unwrap(), + "master", + None, + None, + ) + .unwrap(); + assert!(bytes > 0); + + let res = merge_upstream_commit( + clone2_dir.path().to_str().unwrap(), + "master", + ) + .unwrap(); + + //this should not have commited cause we left conflicts behind + assert_eq!(res, None); + + let state = crate::sync::repo_state( + clone2_dir.path().to_str().unwrap(), + ) + .unwrap(); + + //validate the repo is in a merge state now + assert_eq!(state, RepoState::Merge); + + //check that we still only have the first commit + let commits = get_commit_ids(&clone1, 10); + assert_eq!(commits.len(), 1); + } } |