gnostr_asyncgit/sync/
merge.rs

1use git2::{BranchType, Commit, MergeOptions, Repository};
2use scopetime::scope_time;
3
4use super::{
5	RepoPath,
6	rebase::{RebaseProgress, RebaseState},
7};
8use crate::{
9	error::{Error, Result},
10	sync::{
11		CommitId,
12		branch::merge_commit::commit_merge_with_head,
13		rebase::{
14			abort_rebase, continue_rebase, get_rebase_progress,
15		},
16		repository::repo,
17		reset_stage, reset_workdir,
18	},
19};
20
21///
22pub fn mergehead_ids(repo_path: &RepoPath) -> Result<Vec<CommitId>> {
23	scope_time!("mergehead_ids");
24
25	let mut repo = repo(repo_path)?;
26
27	let mut ids: Vec<CommitId> = Vec::new();
28	repo.mergehead_foreach(|id| {
29		ids.push(CommitId::from(*id));
30		true
31	})?;
32
33	Ok(ids)
34}
35
36/// does these steps:
37/// * reset all staged changes,
38/// * revert all changes in workdir
39/// * cleanup repo merge state
40pub fn abort_pending_state(repo_path: &RepoPath) -> Result<()> {
41	scope_time!("abort_pending_state");
42
43	let repo = repo(repo_path)?;
44
45	reset_stage(repo_path, "*")?;
46	reset_workdir(repo_path, "*")?;
47
48	repo.cleanup_state()?;
49
50	Ok(())
51}
52
53///
54pub fn merge_branch(
55	repo_path: &RepoPath,
56	branch: &str,
57	branch_type: BranchType,
58) -> Result<()> {
59	scope_time!("merge_branch");
60
61	let repo = repo(repo_path)?;
62
63	merge_branch_repo(&repo, branch, branch_type)?;
64
65	Ok(())
66}
67
68///
69pub fn rebase_progress(
70	repo_path: &RepoPath,
71) -> Result<RebaseProgress> {
72	scope_time!("rebase_progress");
73
74	let repo = repo(repo_path)?;
75
76	get_rebase_progress(&repo)
77}
78
79///
80pub fn continue_pending_rebase(
81	repo_path: &RepoPath,
82) -> Result<RebaseState> {
83	scope_time!("continue_pending_rebase");
84
85	let repo = repo(repo_path)?;
86
87	continue_rebase(&repo)
88}
89
90///
91pub fn abort_pending_rebase(repo_path: &RepoPath) -> Result<()> {
92	scope_time!("abort_pending_rebase");
93
94	let repo = repo(repo_path)?;
95
96	abort_rebase(&repo)
97}
98
99///
100pub fn merge_branch_repo(
101	repo: &Repository,
102	branch: &str,
103	branch_type: BranchType,
104) -> Result<()> {
105	let branch = repo.find_branch(branch, branch_type)?;
106
107	let annotated =
108		repo.reference_to_annotated_commit(&branch.into_reference())?;
109
110	let (analysis, _) = repo.merge_analysis(&[&annotated])?;
111
112	//TODO: support merge on unborn
113	if analysis.is_unborn() {
114		return Err(Error::Generic("head is unborn".into()));
115	}
116
117	let mut opt = MergeOptions::default();
118
119	repo.merge(&[&annotated], Some(&mut opt), None)?;
120
121	Ok(())
122}
123
124///
125pub fn merge_msg(repo_path: &RepoPath) -> Result<String> {
126	scope_time!("merge_msg");
127
128	let repo = repo(repo_path)?;
129	let content = repo.message()?;
130
131	Ok(content)
132}
133
134///
135pub fn merge_commit(
136	repo_path: &RepoPath,
137	msg: &str,
138	ids: &[CommitId],
139) -> Result<CommitId> {
140	scope_time!("merge_commit");
141
142	let repo = repo(repo_path)?;
143
144	let mut commits: Vec<Commit> = Vec::new();
145
146	for id in ids {
147		commits.push(repo.find_commit((*id).into())?);
148	}
149
150	let id = commit_merge_with_head(&repo, &commits, msg)?;
151
152	Ok(id)
153}
154
155#[cfg(test)]
156mod tests {
157	use pretty_assertions::assert_eq;
158
159	use super::*;
160	use crate::sync::{
161		RepoPath, create_branch,
162		tests::{repo_init, write_commit_file},
163	};
164
165	#[test]
166	fn test_smoke() {
167		let (_td, repo) = repo_init().unwrap();
168		let root = repo.path().parent().unwrap();
169		let repo_path: &RepoPath =
170			&root.as_os_str().to_str().unwrap().into();
171
172		let c1 =
173			write_commit_file(&repo, "test.txt", "test", "commit1");
174
175		create_branch(repo_path, "foo").unwrap();
176
177		write_commit_file(&repo, "test.txt", "test2", "commit2");
178
179		merge_branch(repo_path, "master", BranchType::Local).unwrap();
180
181		let msg = merge_msg(repo_path).unwrap();
182
183		assert_eq!(&msg[0..12], "Merge branch");
184
185		let mergeheads = mergehead_ids(repo_path).unwrap();
186
187		assert_eq!(mergeheads[0], c1);
188	}
189}