outpost_core/ops/
merge.rs1use crate::{Outpost, OutpostError, OutpostResult, Reporter, SourceRemoteRef, StepKind};
2
3pub struct MergeOptions {
4 pub source_ref: SourceRemoteRef,
5}
6
7pub struct MergeReport {
8 pub source_ref: SourceRemoteRef,
9}
10
11pub fn run(
12 outpost: &Outpost,
13 opts: MergeOptions,
14 reporter: &mut dyn Reporter,
15) -> OutpostResult<MergeReport> {
16 outpost.current_branch().map_err(|err| match err {
17 OutpostError::BranchNotFound { .. } => OutpostError::NoUpstreamTracking {
18 branch: "HEAD".to_owned(),
19 },
20 other => other,
21 })?;
22 validate_source_remote(outpost, &opts.source_ref)?;
23
24 reporter.step(
25 StepKind::OutpostFetch,
26 &format!(
27 "fetching source {} branch {} into outpost {}",
28 outpost.metadata().source_repo.display(),
29 opts.source_ref.branch.as_str(),
30 outpost.work_tree().display()
31 ),
32 );
33 let remote_tracking_ref = fetch_source_ref(outpost, &opts.source_ref)?;
34 outpost.git().run_check(["merge", &remote_tracking_ref])?;
35
36 Ok(MergeReport {
37 source_ref: opts.source_ref,
38 })
39}
40
41fn validate_source_remote(outpost: &Outpost, source_ref: &SourceRemoteRef) -> OutpostResult<()> {
42 if source_ref.remote == outpost.metadata().remote_name {
43 Ok(())
44 } else {
45 Err(OutpostError::InvalidRefName {
46 name: format!(
47 "{}/{}",
48 source_ref.remote.as_str(),
49 source_ref.branch.as_str()
50 ),
51 })
52 }
53}
54
55fn fetch_source_ref(outpost: &Outpost, source_ref: &SourceRemoteRef) -> OutpostResult<String> {
56 let remote_tracking_ref = format!(
57 "refs/remotes/{}/{}",
58 source_ref.remote.as_str(),
59 source_ref.branch.as_str()
60 );
61 let fetch_refspec = format!("{}:{remote_tracking_ref}", source_ref.branch.as_str());
62 outpost
63 .git()
64 .run_check(["fetch", source_ref.remote.as_str(), &fetch_refspec])?;
65 Ok(remote_tracking_ref)
66}