gnostr_asyncgit/sync/branch/
merge_ff.rs1use scopetime::scope_time;
4
5use super::BranchType;
6use crate::{
7 error::{Error, Result},
8 sync::{repository::repo, RepoPath},
9};
10
11pub fn branch_merge_upstream_fastforward(repo_path: &RepoPath, branch: &str) -> Result<()> {
13 scope_time!("branch_merge_upstream");
14
15 let repo = repo(repo_path)?;
16
17 let branch = repo.find_branch(branch, BranchType::Local)?;
18 let upstream = branch.upstream()?;
19
20 let upstream_commit = upstream.into_reference().peel_to_commit()?;
21
22 let annotated = repo.find_annotated_commit(upstream_commit.id())?;
23
24 let (analysis, pref) = repo.merge_analysis(&[&annotated])?;
25
26 if !analysis.is_fast_forward() {
27 return Err(Error::Generic("fast forward merge not possible".into()));
28 }
29
30 if pref.is_no_fast_forward() {
31 return Err(Error::Generic("fast forward not wanted".into()));
32 }
33
34 if analysis.is_unborn() {
36 return Err(Error::Generic("head is unborn".into()));
37 }
38
39 repo.checkout_tree(upstream_commit.as_object(), None)?;
40
41 repo.head()?.set_target(annotated.id(), "")?;
42
43 Ok(())
44}
45
46#[cfg(test)]
47pub mod test {
48 use super::*;
49 use crate::sync::{
50 remotes::{fetch, push::push_branch},
51 tests::{debug_cmd_print, get_commit_ids, repo_clone, repo_init_bare, write_commit_file},
52 };
53
54 #[test]
55 fn test_merge_fastforward() {
56 let (r1_dir, _repo) = repo_init_bare().unwrap();
57
58 let (clone1_dir, clone1) = repo_clone(r1_dir.path().to_str().unwrap()).unwrap();
59
60 let (clone2_dir, clone2) = repo_clone(r1_dir.path().to_str().unwrap()).unwrap();
61
62 let commit1 = write_commit_file(&clone1, "test.txt", "test", "commit1");
65
66 push_branch(
67 &clone1_dir.path().to_str().unwrap().into(),
68 "origin",
69 "master",
70 false,
71 false,
72 None,
73 None,
74 )
75 .unwrap();
76
77 debug_cmd_print(&clone2_dir.path().to_str().unwrap().into(), "git pull --ff");
79
80 let commit2 = write_commit_file(&clone2, "test2.txt", "test", "commit2");
81
82 push_branch(
83 &clone2_dir.path().to_str().unwrap().into(),
84 "origin",
85 "master",
86 false,
87 false,
88 None,
89 None,
90 )
91 .unwrap();
92
93 let bytes = fetch(
96 &clone1_dir.path().to_str().unwrap().into(),
97 "master",
98 None,
99 None,
100 )
101 .unwrap();
102 assert!(bytes > 0);
103
104 let bytes = fetch(
105 &clone1_dir.path().to_str().unwrap().into(),
106 "master",
107 None,
108 None,
109 )
110 .unwrap();
111 assert_eq!(bytes, 0);
112
113 branch_merge_upstream_fastforward(&clone1_dir.path().to_str().unwrap().into(), "master")
114 .unwrap();
115
116 let commits = get_commit_ids(&clone1, 10);
117 assert_eq!(commits.len(), 2);
118 assert_eq!(commits[1], commit1);
119 assert_eq!(commits[0], commit2);
120 }
121}