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