|
1 | 1 | use crate::config::cache::util::ApplyLeniencyDefault;
|
2 | 2 | use crate::config::tree;
|
3 | 3 | use crate::prelude::ObjectIdExt;
|
4 |
| -use crate::repository::{blob_merge_options, merge_commits, merge_resource_cache, merge_trees, tree_merge_options}; |
| 4 | +use crate::repository::{ |
| 5 | + blob_merge_options, merge_commits, merge_resource_cache, merge_trees, tree_merge_options, virtual_merge_base, |
| 6 | + virtual_merge_base_with_graph, |
| 7 | +}; |
5 | 8 | use crate::Repository;
|
6 | 9 | use gix_merge::blob::builtin_driver::text;
|
7 | 10 | use gix_object::Write;
|
@@ -223,4 +226,69 @@ impl Repository {
|
223 | 226 | virtual_merge_bases,
|
224 | 227 | })
|
225 | 228 | }
|
| 229 | + |
| 230 | + /// Create a single virtual merge-base by merging all `merge_bases` into one. |
| 231 | + /// If the list is empty, an error will be returned as the histories are then unrelated. |
| 232 | + /// If there is only one commit in the list, it is returned directly with this case clearly marked in the outcome. |
| 233 | + /// |
| 234 | + /// Note that most of `options` are overwritten to match the requirements of a merge-base merge, but they can be useful |
| 235 | + /// to control the diff algorithm or rewrite tracking, for example. |
| 236 | + // TODO: test |
| 237 | + pub fn virtual_merge_base( |
| 238 | + &self, |
| 239 | + merge_bases: impl IntoIterator<Item = impl Into<gix_hash::ObjectId>>, |
| 240 | + options: crate::merge::tree::Options, |
| 241 | + ) -> Result<crate::merge::virtual_merge_base::Outcome<'_>, virtual_merge_base::Error> { |
| 242 | + let commit_graph = self.commit_graph_if_enabled()?; |
| 243 | + let mut graph = self.revision_graph(commit_graph.as_ref()); |
| 244 | + Ok(self.virtual_merge_base_with_graph(merge_bases, &mut graph, options)?) |
| 245 | + } |
| 246 | + |
| 247 | + /// Like [`Self::virtual_merge_base()`], but also allows to reuse a `graph` for faster merge-base calculation, |
| 248 | + /// particularly if `graph` was used to find the `merge_bases`. |
| 249 | + pub fn virtual_merge_base_with_graph( |
| 250 | + &self, |
| 251 | + merge_bases: impl IntoIterator<Item = impl Into<gix_hash::ObjectId>>, |
| 252 | + graph: &mut gix_revwalk::Graph<'_, '_, gix_revwalk::graph::Commit<gix_revision::merge_base::Flags>>, |
| 253 | + options: crate::merge::tree::Options, |
| 254 | + ) -> Result<crate::merge::virtual_merge_base::Outcome<'_>, virtual_merge_base_with_graph::Error> { |
| 255 | + let mut merge_bases: Vec<_> = merge_bases.into_iter().map(Into::into).collect(); |
| 256 | + let first = merge_bases |
| 257 | + .pop() |
| 258 | + .ok_or(virtual_merge_base_with_graph::Error::MissingCommit)?; |
| 259 | + let Some(second) = merge_bases.pop() else { |
| 260 | + let tree_id = self.find_commit(first)?.tree_id()?; |
| 261 | + let commit_id = first.attach(self); |
| 262 | + return Ok(crate::merge::virtual_merge_base::Outcome { |
| 263 | + virtual_merge_bases: Vec::new(), |
| 264 | + commit_id, |
| 265 | + tree_id, |
| 266 | + }); |
| 267 | + }; |
| 268 | + |
| 269 | + let mut diff_cache = self.diff_resource_cache_for_tree_diff()?; |
| 270 | + let mut blob_merge = self.merge_resource_cache(Default::default())?; |
| 271 | + |
| 272 | + let gix_merge::commit::virtual_merge_base::Outcome { |
| 273 | + virtual_merge_bases, |
| 274 | + commit_id, |
| 275 | + tree_id, |
| 276 | + } = gix_merge::commit::virtual_merge_base( |
| 277 | + first, |
| 278 | + second, |
| 279 | + merge_bases, |
| 280 | + graph, |
| 281 | + &mut diff_cache, |
| 282 | + &mut blob_merge, |
| 283 | + self, |
| 284 | + &mut |id| id.to_owned().attach(self).shorten_or_id().to_string(), |
| 285 | + options.into(), |
| 286 | + )?; |
| 287 | + |
| 288 | + Ok(crate::merge::virtual_merge_base::Outcome { |
| 289 | + virtual_merge_bases: virtual_merge_bases.into_iter().map(|id| id.attach(self)).collect(), |
| 290 | + commit_id: commit_id.attach(self), |
| 291 | + tree_id: tree_id.attach(self), |
| 292 | + }) |
| 293 | + } |
226 | 294 | }
|
0 commit comments