gix_merge/commit/
virtual_merge_base.rs1pub struct Outcome {
3 pub virtual_merge_bases: Vec<gix_hash::ObjectId>,
8 pub commit_id: gix_hash::ObjectId,
10 pub tree_id: gix_hash::ObjectId,
12}
13
14#[derive(Debug, thiserror::Error)]
16#[allow(missing_docs)]
17pub enum Error {
18 #[error(transparent)]
19 MergeTree(#[from] crate::tree::Error),
20 #[error("Failed to write tree for merged merge-base or virtual commit")]
21 WriteObject(gix_object::write::Error),
22 #[error(
23 "Conflicts occurred when trying to resolve multiple merge-bases by merging them. This is most certainly a bug."
24 )]
25 VirtualMergeBaseConflict,
26 #[error("Could not find commit to use as basis for a virtual commit")]
27 FindCommit(#[from] gix_object::find::existing_object::Error),
28}
29
30pub(super) mod function {
31 use super::Error;
32 use crate::blob::builtin_driver;
33 use crate::tree::{treat_as_unresolved, TreatAsUnresolved};
34 use gix_object::FindExt;
35
36 #[allow(clippy::too_many_arguments)]
44 pub fn virtual_merge_base<'objects>(
45 first_commit: gix_hash::ObjectId,
46 second_commit: gix_hash::ObjectId,
47 mut others: Vec<gix_hash::ObjectId>,
48 graph: &mut gix_revwalk::Graph<'_, '_, gix_revwalk::graph::Commit<gix_revision::merge_base::Flags>>,
49 diff_resource_cache: &mut gix_diff::blob::Platform,
50 blob_merge: &mut crate::blob::Platform,
51 objects: &'objects (impl gix_object::FindObjectOrHeader + gix_object::Write),
52 abbreviate_hash: &mut dyn FnMut(&gix_hash::oid) -> String,
53 mut options: crate::tree::Options,
54 ) -> Result<super::Outcome, crate::commit::Error> {
55 let mut merged_commit_id = first_commit;
56 others.push(second_commit);
57
58 options.tree_conflicts = Some(crate::tree::ResolveWith::Ancestor);
59 options.blob_merge.is_virtual_ancestor = true;
60 options.blob_merge.text.conflict = builtin_driver::text::Conflict::ResolveWithOurs;
61 let favor_ancestor = Some(builtin_driver::binary::ResolveWith::Ancestor);
62 options.blob_merge.resolve_binary_with = favor_ancestor;
63 options.symlink_conflicts = favor_ancestor;
64 let labels = builtin_driver::text::Labels {
65 current: Some("Temporary merge branch 1".into()),
66 other: Some("Temporary merge branch 2".into()),
67 ancestor: None,
68 };
69 let mut virtual_merge_bases = Vec::new();
70 let mut tree_id = None;
71 while let Some(next_commit_id) = others.pop() {
72 options.marker_size_multiplier += 1;
73 let mut out = crate::commit(
74 merged_commit_id,
75 next_commit_id,
76 labels,
77 graph,
78 diff_resource_cache,
79 blob_merge,
80 objects,
81 abbreviate_hash,
82 crate::commit::Options {
83 allow_missing_merge_base: false,
84 tree_merge: options.clone(),
85 use_first_merge_base: false,
86 },
87 )?;
88 if out.tree_merge.has_unresolved_conflicts(TreatAsUnresolved {
90 content_merge: treat_as_unresolved::ContentMerge::Markers,
91 tree_merge: treat_as_unresolved::TreeMerge::Undecidable,
92 }) {
93 return Err(Error::VirtualMergeBaseConflict.into());
94 }
95 let merged_tree_id = out
96 .tree_merge
97 .tree
98 .write(|tree| objects.write(tree))
99 .map_err(Error::WriteObject)?;
100
101 tree_id = Some(merged_tree_id);
102 merged_commit_id = create_virtual_commit(objects, merged_commit_id, next_commit_id, merged_tree_id)?;
103
104 virtual_merge_bases.extend(out.virtual_merge_bases);
105 virtual_merge_bases.push(merged_commit_id);
106 }
107
108 Ok(super::Outcome {
109 virtual_merge_bases,
110 commit_id: merged_commit_id,
111 tree_id: tree_id.map_or_else(
112 || {
113 let mut buf = Vec::new();
114 objects.find_commit(&merged_commit_id, &mut buf).map(|c| c.tree())
115 },
116 Ok,
117 )?,
118 })
119 }
120
121 fn create_virtual_commit(
122 objects: &(impl gix_object::Find + gix_object::Write),
123 parent_a: gix_hash::ObjectId,
124 parent_b: gix_hash::ObjectId,
125 tree_id: gix_hash::ObjectId,
126 ) -> Result<gix_hash::ObjectId, Error> {
127 let mut buf = Vec::new();
128 let mut commit: gix_object::Commit = objects.find_commit(&parent_a, &mut buf)?.into();
129 commit.parents = vec![parent_a, parent_b].into();
130 commit.tree = tree_id;
131 objects.write(&commit).map_err(Error::WriteObject)
132 }
133}