From 32d6bfbe6548fc699deee41895bcafff1423f117 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 31 Oct 2024 20:33:05 +0100 Subject: [PATCH 01/23] fix: assure that `gix tree diff` doesn't slow down too much when shortening IDs --- gitoxide-core/src/repository/diff.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gitoxide-core/src/repository/diff.rs b/gitoxide-core/src/repository/diff.rs index 18ca60f9e88..0927acbeec6 100644 --- a/gitoxide-core/src/repository/diff.rs +++ b/gitoxide-core/src/repository/diff.rs @@ -1,5 +1,6 @@ use gix::bstr::{BString, ByteSlice}; use gix::objs::tree::EntryMode; +use gix::odb::store::RefreshMode; use gix::prelude::ObjectIdExt; pub fn tree( @@ -9,6 +10,7 @@ pub fn tree( new_treeish: BString, ) -> anyhow::Result<()> { repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&**repo.index_or_empty()?)); + repo.objects.refresh = RefreshMode::Never; let old_tree_id = repo.rev_parse_single(old_treeish.as_bstr())?; let new_tree_id = repo.rev_parse_single(new_treeish.as_bstr())?; From 1f40a898284777f255a6e2f2c202483d122c8f65 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 15 Oct 2024 20:37:58 +0200 Subject: [PATCH 02/23] Add a link to OpenCollective --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 80819f5d8c9..fb2d9a4dca4 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1,2 @@ github: byron +open_collective: gitoxide From eb9f9c327f94e59ff72160809e1409bc60629b2f Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 12 Oct 2024 10:25:51 +0200 Subject: [PATCH 03/23] Improve error message to be less elusive Co-authored-by: Eliah Kagan --- gix-discover/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gix-discover/src/lib.rs b/gix-discover/src/lib.rs index df0ca849489..939928f829a 100644 --- a/gix-discover/src/lib.rs +++ b/gix-discover/src/lib.rs @@ -39,7 +39,7 @@ pub mod is_git { Metadata { source: std::io::Error, path: PathBuf }, #[error("The repository's config file doesn't exist or didn't have a 'bare' configuration or contained core.worktree without value")] Inconclusive, - #[error("Could not obtain current directory when conforming repository path")] + #[error("Could not obtain current directory for resolving the '.' repository path")] CurrentDir(#[from] std::io::Error), } } From eb55c00be63960a7999978eef3f49d58bb10707c Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 14 Oct 2024 16:35:29 +0200 Subject: [PATCH 04/23] feat: Allow access to `tree::State::buf1|2`. This allows to re-use that memory at least, making this kind of state a little more useful. Also, these fields can certainly be considered stable. --- gix-diff/src/rewrites/tracker.rs | 6 +++--- gix-diff/src/tree/mod.rs | 6 ++++-- gix-diff/tests/diff/rewrites/tracker.rs | 24 +++++++++++++----------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/gix-diff/src/rewrites/tracker.rs b/gix-diff/src/rewrites/tracker.rs index df166bd43e3..5524c316328 100644 --- a/gix-diff/src/rewrites/tracker.rs +++ b/gix-diff/src/rewrites/tracker.rs @@ -168,13 +168,13 @@ impl Tracker { return Some(change); }; - let relation = change - .relation() - .filter(|_| matches!(change_kind, ChangeKind::Addition | ChangeKind::Deletion)); let entry_kind = change.entry_mode().kind(); if entry_kind == EntryKind::Commit { return Some(change); } + let relation = change + .relation() + .filter(|_| matches!(change_kind, ChangeKind::Addition | ChangeKind::Deletion)); if let (None, EntryKind::Tree) = (relation, entry_kind) { return Some(change); }; diff --git a/gix-diff/src/tree/mod.rs b/gix-diff/src/tree/mod.rs index 7ef2b277a4d..d542b1c1239 100644 --- a/gix-diff/src/tree/mod.rs +++ b/gix-diff/src/tree/mod.rs @@ -36,8 +36,10 @@ pub trait Visit { /// The state required to run [tree-diffs](super::tree()). #[derive(Default, Clone)] pub struct State { - buf1: Vec, - buf2: Vec, + /// A buffer for object data. + pub buf1: Vec, + /// Another buffer for object data. + pub buf2: Vec, trees: VecDeque, change_id: visit::ChangeId, } diff --git a/gix-diff/tests/diff/rewrites/tracker.rs b/gix-diff/tests/diff/rewrites/tracker.rs index fb6da4c5b47..1a6cb56340b 100644 --- a/gix-diff/tests/diff/rewrites/tracker.rs +++ b/gix-diff/tests/diff/rewrites/tracker.rs @@ -525,17 +525,19 @@ fn rename_by_50_percent_similarity() -> crate::Result { #[test] fn directories_without_relation_are_ignored() -> crate::Result { let mut track = util::new_tracker(Default::default()); - let tree_without_relation = Change { - id: NULL_ID, - kind: ChangeKind::Deletion, - mode: EntryKind::Tree.into(), - relation: None, - }; - assert_eq!( - track.try_push_change(tree_without_relation, "dir".into()), - Some(tree_without_relation), - "trees, or non-blobs, are ignored, particularly when they have no relation" - ); + for mode in [EntryKind::Tree, EntryKind::Commit] { + let tree_without_relation = Change { + id: NULL_ID, + kind: ChangeKind::Deletion, + mode: mode.into(), + relation: None, + }; + assert_eq!( + track.try_push_change(tree_without_relation, "dir".into()), + Some(tree_without_relation), + "trees and submodules are ignored, particularly when they have no relation" + ); + } Ok(()) } From 76e6762db493e10883b2dd332c7715e6f5524fd0 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 17 Oct 2024 16:10:15 +0200 Subject: [PATCH 05/23] feat: add `tree_with_rewrites::Change(Ref)::previous_location()` That way, it's also possible to obtain the previous location in case of rewrites. --- gix-diff/src/tree_with_rewrites/change.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/gix-diff/src/tree_with_rewrites/change.rs b/gix-diff/src/tree_with_rewrites/change.rs index 196a4b977b6..2e99c770690 100644 --- a/gix-diff/src/tree_with_rewrites/change.rs +++ b/gix-diff/src/tree_with_rewrites/change.rs @@ -444,6 +444,17 @@ impl<'a> ChangeRef<'a> { | ChangeRef::Rewrite { location, .. } => location, } } + + /// Return the *previous* location of the resource where possible, i.e. the source of a rename or copy, or the + /// location at which an addition, deletion or modification took place. + pub fn source_location(&self) -> &BStr { + match self { + ChangeRef::Addition { location, .. } + | ChangeRef::Deletion { location, .. } + | ChangeRef::Modification { location, .. } => location, + ChangeRef::Rewrite { source_location, .. } => source_location, + } + } } impl Change { @@ -477,4 +488,15 @@ impl Change { | Change::Rewrite { location, .. } => location.as_bstr(), } } + + /// Return the *previous* location of the resource where possible, i.e. the source of a rename or copy, or the + /// location at which an addition, deletion or modification took place. + pub fn source_location(&self) -> &BStr { + match self { + Change::Addition { location, .. } + | Change::Deletion { location, .. } + | Change::Modification { location, .. } => location.as_bstr(), + Change::Rewrite { source_location, .. } => source_location.as_bstr(), + } + } } From 674052002a781889d9b308ebd782f4f3cf5f41e8 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 21 Oct 2024 11:20:19 +0200 Subject: [PATCH 06/23] feat: add traits for partial equality comparison to `tree_with_rewrites::Change` types --- gix-diff/src/tree_with_rewrites/change.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gix-diff/src/tree_with_rewrites/change.rs b/gix-diff/src/tree_with_rewrites/change.rs index 2e99c770690..508c1137519 100644 --- a/gix-diff/src/tree_with_rewrites/change.rs +++ b/gix-diff/src/tree_with_rewrites/change.rs @@ -4,7 +4,7 @@ use bstr::BString; use bstr::{BStr, ByteSlice}; /// Represents any possible change in order to turn one tree into another, which references data owned by its producer. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum ChangeRef<'a> { /// An entry was added, like the addition of a file or directory. Addition { @@ -101,7 +101,7 @@ pub enum ChangeRef<'a> { } /// Represents any possible change in order to turn one tree into another, with fully-owned data. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum Change { /// An entry was added, like the addition of a file or directory. Addition { From e2ea398d1fb789cb180a1cf9d81f2d9fbb010927 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 17 Oct 2024 15:15:45 +0200 Subject: [PATCH 07/23] feat: Add `tree::Editor::get()` to get entries directly from the editor. This is useful if in the middle of an edit you'd like to lookup what's there to choose a non-conflicting name, for example. --- gix-object/src/tree/editor.rs | 108 +++++++++++++++++++------ gix-object/src/tree/mod.rs | 3 +- gix-object/tests/object/tree/editor.rs | 88 ++++++++++++++++++-- 3 files changed, 166 insertions(+), 33 deletions(-) diff --git a/gix-object/src/tree/editor.rs b/gix-object/src/tree/editor.rs index 4edf723b434..0b86fa090a1 100644 --- a/gix-object/src/tree/editor.rs +++ b/gix-object/src/tree/editor.rs @@ -46,7 +46,7 @@ impl<'a> Editor<'a> { find, object_hash, trees: HashMap::from_iter(Some((empty_path(), root))), - path_buf: Vec::with_capacity(256).into(), + path_buf: BString::from(Vec::with_capacity(256)).into(), tree_buf: Vec::with_capacity(512), } } @@ -54,7 +54,8 @@ impl<'a> Editor<'a> { /// Operations impl Editor<'_> { - /// Write the entire in-memory state of all changed trees (and only changed trees) to `out`. + /// Write the entire in-memory state of all changed trees (and only changed trees) to `out`, and remove + /// written portions from our state except for the root tree, which affects [`get()`](Editor::get()). /// Note that the returned object id *can* be the empty tree if everything was removed or if nothing /// was added to the tree. /// @@ -72,7 +73,7 @@ impl Editor<'_> { /// It is absolutely and intentionally possible to write out invalid trees with this method. /// Higher layers are expected to perform detailed validation. pub fn write(&mut self, out: impl FnMut(&Tree) -> Result) -> Result { - self.path_buf.clear(); + self.path_buf.borrow_mut().clear(); self.write_at_pathbuf(out, WriteMode::Normal) } @@ -85,10 +86,24 @@ impl Editor<'_> { I: IntoIterator, C: AsRef, { - self.path_buf.clear(); + self.path_buf.borrow_mut().clear(); self.upsert_or_remove_at_pathbuf(rela_path, None) } + /// Obtain the entry at `rela_path` or return `None` if none was found, or the tree wasn't yet written + /// to that point. + /// Note that after [writing](Self::write) only the root path remains, all other intermediate trees are removed. + /// The entry can be anything that can be stored in a tree, but may have a null-id if it's a newly + /// inserted tree. Also, ids of trees might not be accurate as they may have been changed in memory. + pub fn get(&self, rela_path: I) -> Option<&tree::Entry> + where + I: IntoIterator, + C: AsRef, + { + self.path_buf.borrow_mut().clear(); + self.get_inner(rela_path) + } + /// Insert a new entry of `kind` with `id` at `rela_path`, an iterator over each path component in the tree, /// like `a/b/c`. Names are matched case-sensitively. /// @@ -108,10 +123,41 @@ impl Editor<'_> { I: IntoIterator, C: AsRef, { - self.path_buf.clear(); + self.path_buf.borrow_mut().clear(); self.upsert_or_remove_at_pathbuf(rela_path, Some((kind, id, UpsertMode::Normal))) } + fn get_inner(&self, rela_path: I) -> Option<&tree::Entry> + where + I: IntoIterator, + C: AsRef, + { + let mut path_buf = self.path_buf.borrow_mut(); + let mut cursor = self.trees.get(path_buf.as_bstr()).expect("root is always present"); + let mut rela_path = rela_path.into_iter().peekable(); + while let Some(name) = rela_path.next() { + let name = name.as_ref(); + let is_last = rela_path.peek().is_none(); + match cursor + .entries + .binary_search_by(|e| cmp_entry_with_name(e, name, true)) + .or_else(|_| cursor.entries.binary_search_by(|e| cmp_entry_with_name(e, name, false))) + { + Ok(idx) if is_last => return Some(&cursor.entries[idx]), + Ok(idx) => { + if cursor.entries[idx].mode.is_tree() { + push_path_component(&mut path_buf, name); + cursor = self.trees.get(path_buf.as_bstr())?; + } else { + break; + } + } + Err(_) => break, + }; + } + None + } + fn write_at_pathbuf( &mut self, mut out: impl FnMut(&Tree) -> Result, @@ -120,11 +166,12 @@ impl Editor<'_> { assert_ne!(self.trees.len(), 0, "there is at least the root tree"); // back is for children, front is for parents. + let path_buf = self.path_buf.borrow_mut(); let mut parents = vec![( None::, - self.path_buf.clone(), + path_buf.clone(), self.trees - .remove(&path_hash(&self.path_buf)) + .remove(path_buf.as_bstr()) .expect("root tree is always present"), )]; let mut children = Vec::new(); @@ -133,7 +180,7 @@ impl Editor<'_> { for entry in &tree.entries { if entry.mode.is_tree() { let prev_len = push_path_component(&mut rela_path, &entry.filename); - if let Some(sub_tree) = self.trees.remove(&path_hash(&rela_path)) { + if let Some(sub_tree) = self.trees.remove(&rela_path) { all_entries_unchanged_or_written = false; let next_parent_idx = parents.len(); children.push((Some(next_parent_idx), rela_path.clone(), sub_tree)); @@ -167,7 +214,7 @@ impl Editor<'_> { } } else if parents.is_empty() { debug_assert!(children.is_empty(), "we consume children before parents"); - debug_assert_eq!(rela_path, self.path_buf, "this should always be the root tree"); + debug_assert_eq!(rela_path, **path_buf, "this should always be the root tree"); // There may be left-over trees if they are replaced with blobs for example. match out(&tree) { @@ -207,10 +254,8 @@ impl Editor<'_> { I: IntoIterator, C: AsRef, { - let mut cursor = self - .trees - .get_mut(&path_hash(&self.path_buf)) - .expect("root is always present"); + let mut path_buf = self.path_buf.borrow_mut(); + let mut cursor = self.trees.get_mut(path_buf.as_bstr()).expect("root is always present"); let mut rela_path = rela_path.into_iter().peekable(); let new_kind_is_tree = kind_and_id.map_or(false, |(kind, _, _)| kind == EntryKind::Tree); while let Some(name) = rela_path.next() { @@ -294,9 +339,8 @@ impl Editor<'_> { if is_last && kind_and_id.map_or(false, |(_, _, mode)| mode == UpsertMode::Normal) { break; } - push_path_component(&mut self.path_buf, name); - let path_id = path_hash(&self.path_buf); - cursor = match self.trees.entry(path_id) { + push_path_component(&mut path_buf, name); + cursor = match self.trees.entry(path_buf.clone()) { hash_map::Entry::Occupied(e) => e.into_mut(), hash_map::Entry::Vacant(e) => e.insert( if let Some(tree_id) = tree_to_lookup.filter(|tree_id| !tree_id.is_empty_tree()) { @@ -307,6 +351,7 @@ impl Editor<'_> { ), }; } + drop(path_buf); Ok(self) } @@ -325,7 +370,7 @@ impl Editor<'_> { mod cursor { use crate::tree::editor::{Cursor, UpsertMode, WriteMode}; use crate::tree::{Editor, EntryKind}; - use crate::Tree; + use crate::{tree, Tree}; use bstr::{BStr, BString}; use gix_hash::ObjectId; @@ -350,26 +395,41 @@ mod cursor { I: IntoIterator, C: AsRef, { - self.path_buf.clear(); + self.path_buf.borrow_mut().clear(); self.upsert_or_remove_at_pathbuf( rela_path, Some((EntryKind::Tree, self.object_hash.null(), UpsertMode::AssureTreeOnly)), )?; + let prefix = self.path_buf.borrow_mut().clone(); Ok(Cursor { - prefix: self.path_buf.clone(), /* set during the upsert call */ + prefix, /* set during the upsert call */ parent: self, }) } } impl Cursor<'_, '_> { + /// Obtain the entry at `rela_path` or return `None` if none was found, or the tree wasn't yet written + /// to that point. + /// Note that after [writing](Self::write) only the root path remains, all other intermediate trees are removed. + /// The entry can be anything that can be stored in a tree, but may have a null-id if it's a newly + /// inserted tree. Also, ids of trees might not be accurate as they may have been changed in memory. + pub fn get(&self, rela_path: I) -> Option<&tree::Entry> + where + I: IntoIterator, + C: AsRef, + { + self.parent.path_buf.borrow_mut().clone_from(&self.prefix); + self.parent.get_inner(rela_path) + } + /// Like [`Editor::upsert()`], but with the constraint of only editing in this cursor's tree. pub fn upsert(&mut self, rela_path: I, kind: EntryKind, id: ObjectId) -> Result<&mut Self, super::Error> where I: IntoIterator, C: AsRef, { - self.parent.path_buf.clone_from(&self.prefix); + self.parent.path_buf.borrow_mut().clone_from(&self.prefix); self.parent .upsert_or_remove_at_pathbuf(rela_path, Some((kind, id, UpsertMode::Normal)))?; Ok(self) @@ -381,14 +441,14 @@ mod cursor { I: IntoIterator, C: AsRef, { - self.parent.path_buf.clone_from(&self.prefix); + self.parent.path_buf.borrow_mut().clone_from(&self.prefix); self.parent.upsert_or_remove_at_pathbuf(rela_path, None)?; Ok(self) } /// Like [`Editor::write()`], but will write only the subtree of the cursor. pub fn write(&mut self, out: impl FnMut(&Tree) -> Result) -> Result { - self.parent.path_buf.clone_from(&self.prefix); + self.parent.path_buf.borrow_mut().clone_from(&self.prefix); self.parent.write_at_pathbuf(out, WriteMode::FromCursor) } } @@ -424,10 +484,6 @@ fn empty_path() -> BString { BString::default() } -fn path_hash(path: &[u8]) -> BString { - path.to_vec().into() -} - fn push_path_component(base: &mut BString, component: &[u8]) -> usize { let prev_len = base.len(); debug_assert!(base.last() != Some(&b'/')); diff --git a/gix-object/src/tree/mod.rs b/gix-object/src/tree/mod.rs index 688af26dd57..1fcb1004a2d 100644 --- a/gix-object/src/tree/mod.rs +++ b/gix-object/src/tree/mod.rs @@ -2,6 +2,7 @@ use crate::{ bstr::{BStr, BString}, tree, Tree, TreeRef, }; +use std::cell::RefCell; use std::cmp::Ordering; /// @@ -30,7 +31,7 @@ pub struct Editor<'a> { /// dropped when writing at the latest. trees: std::collections::HashMap, /// A buffer to build up paths when finding the tree to edit. - path_buf: BString, + path_buf: RefCell, /// Our buffer for storing tree-data in, right before decoding it. tree_buf: Vec, } diff --git a/gix-object/tests/object/tree/editor.rs b/gix-object/tests/object/tree/editor.rs index f74b5c15602..2565a319cb0 100644 --- a/gix-object/tests/object/tree/editor.rs +++ b/gix-object/tests/object/tree/editor.rs @@ -1,4 +1,4 @@ -use gix_object::tree::EntryKind; +use gix_object::tree::{Entry, EntryKind}; use gix_object::Tree; #[test] @@ -32,6 +32,19 @@ fn from_empty_cursor() -> crate::Result { "only one item is left in the tree, which also keeps it alive" ); assert_eq!(num_writes_and_clear(), 1, "root tree"); + assert_eq!( + cursor.get(None::<&str>), + None, + "the 'root' can't be obtained, no entry exists for it, ever" + ); + assert_eq!( + cursor.get(Some("empty-dir-via-cursor")), + Some(&Entry { + mode: EntryKind::Tree.into(), + filename: "empty-dir-via-cursor".into(), + oid: gix_hash::ObjectId::empty_tree(gix_hash::Kind::Sha1), + }), + ); let actual = edit.write(&mut write)?; assert_eq!( @@ -52,6 +65,20 @@ fn from_empty_cursor() -> crate::Result { let mut cursor = edit.cursor_at(cursor_path)?; let actual = cursor.remove(Some("empty-dir-via-cursor"))?.write(&mut write)?; assert_eq!(actual, empty_tree(), "it keeps the empty tree like the editor would"); + assert_eq!( + edit.get(["some", "deeply", "nested", "path"]), + Some(&Entry { + mode: EntryKind::Tree.into(), + filename: "path".into(), + oid: gix_hash::Kind::Sha1.null(), + }), + "the directory leading to the removed one is still present" + ); + assert_eq!( + edit.get(["some", "deeply", "nested", "path", "empty-dir-via-cursor"]), + None, + "but the removed entry is indee removed" + ); let actual = edit.write(&mut write)?; assert_eq!( @@ -400,6 +427,11 @@ fn from_empty_add() -> crate::Result { "4b825dc642cb6eb9a060e54bf8d69288fbee4904\n" ); assert_eq!(odb.access_count_and_clear(), 0); + assert_eq!( + edit.get(None::<&str>), + None, + "the 'root' can't be obtained, no entry exists for it, ever" + ); let actual = edit .upsert(Some("hi"), EntryKind::Blob, gix_hash::Kind::Sha1.null())? @@ -431,12 +463,28 @@ fn from_empty_add() -> crate::Result { assert_eq!(storage.borrow().len(), 1, "still nothing but empty trees"); assert_eq!(odb.access_count_and_clear(), 0); - let actual = edit - .upsert(["a", "b"], EntryKind::Tree, empty_tree())? + edit.upsert(["a", "b"], EntryKind::Tree, empty_tree())? .upsert(["a", "b", "c"], EntryKind::Tree, empty_tree())? - .upsert(["a", "b", "d", "e"], EntryKind::Tree, empty_tree())? - .write(&mut write) - .expect("it's OK to write empty trees"); + .upsert(["a", "b", "d", "e"], EntryKind::Tree, empty_tree())?; + assert_eq!( + edit.get(["a", "b"]), + Some(&Entry { + mode: EntryKind::Tree.into(), + filename: "b".into(), + oid: hex_to_id("4b825dc642cb6eb9a060e54bf8d69288fbee4904"), + }), + "before writing, entries are still present, just like they were written" + ); + assert_eq!( + edit.get(["a", "b", "c"]), + Some(&Entry { + mode: EntryKind::Tree.into(), + filename: "c".into(), + oid: gix_hash::ObjectId::empty_tree(gix_hash::Kind::Sha1), + }), + ); + + let actual = edit.write(&mut write).expect("it's OK to write empty trees"); assert_eq!( display_tree(actual, &storage), "bf91a94ae659ac8a9da70d26acf42df1a36adb6e @@ -450,6 +498,16 @@ fn from_empty_add() -> crate::Result { ); assert_eq!(num_writes_and_clear(), 4, "it wrote the trees it needed to write"); assert_eq!(odb.access_count_and_clear(), 0); + assert_eq!(edit.get(["a", "b"]), None, "nothing exists here"); + assert_eq!( + edit.get(Some("a")), + Some(&Entry { + mode: EntryKind::Tree.into(), + filename: "a".into(), + oid: hex_to_id("850bf83c26003cb0541318718bc9217c4a5bde6d"), + }), + "but the top-level tree is still available and can yield its entries, as written with proper ids" + ); let actual = edit .upsert(["a"], EntryKind::Blob, any_blob())? @@ -532,6 +590,24 @@ fn from_empty_add() -> crate::Result { "still, only the root-tree changes effectively" ); assert_eq!(odb.access_count_and_clear(), 0); + + let actual = edit + .upsert(["a", "b"], EntryKind::Tree, empty_tree())? + .upsert(["a", "b", "c"], EntryKind::BlobExecutable, any_blob())? + // .upsert(["a", "b", "d"], EntryKind::Blob, any_blob())? + .write(&mut write)?; + assert_eq!( + display_tree(actual, &storage), + "d8d3f558776965f70452625b72363234f517b290 +└── a + └── b + └── c bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.100755 +", + "the intermediate tree is rewritten to be suitable to hold the blob" + ); + assert_eq!(num_writes_and_clear(), 3, "root, and two child-trees"); + assert_eq!(odb.access_count_and_clear(), 0); + Ok(()) } From 78a535572643a0657348aea3c2fed0123505f7fe Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 19 Oct 2024 11:17:51 +0200 Subject: [PATCH 08/23] fix!: prefer to receive borrowed `gix_command::Context` when it's just passed on. That way, the clone occours only when needed, without forcing the caller to pre-emptively clone each time it's called. --- gix-merge/src/blob/platform/merge.rs | 4 ++-- gix-merge/tests/merge/blob/platform.rs | 28 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/gix-merge/src/blob/platform/merge.rs b/gix-merge/src/blob/platform/merge.rs index cd803006268..014effa3f49 100644 --- a/gix-merge/src/blob/platform/merge.rs +++ b/gix-merge/src/blob/platform/merge.rs @@ -374,7 +374,7 @@ impl<'parent> PlatformRef<'parent> { &self, out: &mut Vec, labels: builtin_driver::text::Labels<'_>, - context: gix_command::Context, + context: &gix_command::Context, ) -> Result<(inner::builtin_merge::Pick, Resolution), Error> { let _span = gix_trace::coarse!( "gix_merge::blob::PlatformRef::merge()", @@ -382,7 +382,7 @@ impl<'parent> PlatformRef<'parent> { ); match self.configured_driver() { Ok(driver) => { - let mut cmd = self.prepare_external_driver(driver.command.clone(), labels, context)?; + let mut cmd = self.prepare_external_driver(driver.command.clone(), labels, context.clone())?; let status = cmd.status().map_err(|err| Error::SpawnExternalDriver { cmd: format!("{:?}", cmd.cmd), source: err, diff --git a/gix-merge/tests/merge/blob/platform.rs b/gix-merge/tests/merge/blob/platform.rs index d03a3ddc960..01123612dfb 100644 --- a/gix-merge/tests/merge/blob/platform.rs +++ b/gix-merge/tests/merge/blob/platform.rs @@ -46,7 +46,7 @@ mod merge { ); let mut buf = Vec::new(); - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!( res, (Pick::Ours, Resolution::Conflict), @@ -54,7 +54,7 @@ mod merge { ); platform_ref.options.resolve_binary_with = Some(builtin_driver::binary::ResolveWith::Theirs); - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!( res, (Pick::Theirs, Resolution::Complete), @@ -86,7 +86,7 @@ mod merge { let mut platform_ref = platform.prepare_merge(&db, Default::default())?; assert_eq!(platform_ref.driver, DriverChoice::BuiltIn(BuiltinDriver::Text)); let mut buf = Vec::new(); - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!(res, (Pick::Buffer, Resolution::Conflict)); assert_eq!( buf.as_bstr(), @@ -102,7 +102,7 @@ theirs style: ConflictStyle::Diff3, marker_size: 3, }; - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!(res, (Pick::Buffer, Resolution::Conflict)); assert_eq!( @@ -119,7 +119,7 @@ theirs ); platform_ref.options.text.conflict = builtin_driver::text::Conflict::ResolveWithOurs; - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!( res, (Pick::Buffer, Resolution::Complete), @@ -128,23 +128,23 @@ theirs assert_eq!(buf.as_bstr(), "ours"); platform_ref.options.text.conflict = builtin_driver::text::Conflict::ResolveWithTheirs; - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!(res, (Pick::Buffer, Resolution::Complete)); assert_eq!(buf.as_bstr(), "theirs"); platform_ref.options.text.conflict = builtin_driver::text::Conflict::ResolveWithUnion; - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!(res, (Pick::Buffer, Resolution::Complete)); assert_eq!(buf.as_bstr(), "ours\ntheirs"); platform_ref.driver = DriverChoice::BuiltIn(BuiltinDriver::Union); platform_ref.options.text.conflict = builtin_driver::text::Conflict::default(); - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!(res, (Pick::Buffer, Resolution::Complete)); assert_eq!(buf.as_bstr(), "ours\ntheirs"); platform_ref.driver = DriverChoice::BuiltIn(BuiltinDriver::Binary); - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!( res, (Pick::Ours, Resolution::Conflict), @@ -163,7 +163,7 @@ theirs ("b\n", Pick::Ancestor, builtin_driver::binary::ResolveWith::Ancestor), ] { platform_ref.options.resolve_binary_with = Some(resolve); - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!(res, (expected_pick, Resolution::Complete)); assert_eq!(platform_ref.buffer_by_pick(res.0).unwrap().as_bstr(), expected); } @@ -202,7 +202,7 @@ theirs let platform_ref = platform.prepare_merge(&db, Default::default())?; let mut buf = Vec::new(); - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!(res, (Pick::Buffer, Resolution::Complete), "merge drivers always merge "); let mut lines = cleaned_driver_lines(&buf)?; for tmp_file in lines.by_ref().take(3) { @@ -228,7 +228,7 @@ theirs let id = db.insert("binary\0"); platform.set_resource(id, EntryKind::Blob, "b".into(), ResourceKind::OtherOrTheirs, &db)?; let platform_ref = platform.prepare_merge(&db, Default::default())?; - let res = platform_ref.merge(&mut buf, default_labels(), Default::default())?; + let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!( res, (Pick::Buffer, Resolution::Complete), @@ -282,7 +282,7 @@ theirs let platform_ref = platform.prepare_merge(&gix_object::find::Never, Default::default())?; let mut buf = Vec::new(); - let res = platform_ref.merge(&mut buf, Default::default(), Default::default())?; + let res = platform_ref.merge(&mut buf, Default::default(), &Default::default())?; assert_eq!( res, (Pick::Buffer, Resolution::Complete), @@ -359,7 +359,7 @@ theirs let mut out = Vec::new(); let err = platform_ref - .merge(&mut out, Default::default(), Default::default()) + .merge(&mut out, Default::default(), &Default::default()) .unwrap_err(); assert!(matches!(err, platform::merge::Error::ResourceTooLarge)); From c1cf08cc47f98abda017544b1791ab3b4463cc77 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 30 Oct 2024 10:55:55 +0100 Subject: [PATCH 09/23] feat!: Don't fail on big files during blob-merge, but turn them into binary merges. Binary merges are mere choices of which side to pick, which works well for big files as well. Git doesn't define this well during its own merges, so there is some room here. --- gix-merge/src/blob/platform/merge.rs | 31 ++++++++++++++------------ gix-merge/tests/merge/blob/platform.rs | 27 +++++++++++----------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/gix-merge/src/blob/platform/merge.rs b/gix-merge/src/blob/platform/merge.rs index 014effa3f49..bb4185023d9 100644 --- a/gix-merge/src/blob/platform/merge.rs +++ b/gix-merge/src/blob/platform/merge.rs @@ -18,8 +18,6 @@ pub struct Options { #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { - #[error("At least one resource was too large to be processed")] - ResourceTooLarge, #[error(transparent)] PrepareExternalDriver(#[from] inner::prepare_external_driver::Error), #[error("Failed to launch external merge driver: {cmd}")] @@ -299,16 +297,19 @@ pub(super) mod inner { /// Returns `None` if one of the buffers is too large, making a merge impossible. /// Note that if the *pick* wasn't [`Pick::Buffer`], then `out` will not have been cleared, /// and one has to take the data from the respective resource. + /// + /// If there is no buffer loaded as the resource is too big, we will automatically perform a binary merge + /// which effectively chooses our side by default. pub fn builtin_merge( &self, driver: BuiltinDriver, out: &mut Vec, input: &mut imara_diff::intern::InternedInput<&'parent [u8]>, labels: builtin_driver::text::Labels<'_>, - ) -> Option<(Pick, Resolution)> { - let base = self.ancestor.data.as_slice()?; - let ours = self.current.data.as_slice()?; - let theirs = self.other.data.as_slice()?; + ) -> (Pick, Resolution) { + let base = self.ancestor.data.as_slice(); + let ours = self.current.data.as_slice(); + let theirs = self.other.data.as_slice(); let driver = if driver != BuiltinDriver::Binary && (is_binary_buf(ours) || is_binary_buf(theirs) || is_binary_buf(base)) { @@ -316,8 +317,9 @@ pub(super) mod inner { } else { driver }; - Some(match driver { + match driver { BuiltinDriver::Text => { + let ((base, ours), theirs) = base.zip(ours).zip(theirs).expect("would use binary if missing"); let resolution = builtin_driver::text(out, input, labels, ours, base, theirs, self.options.text); (Pick::Buffer, resolution) @@ -332,6 +334,7 @@ pub(super) mod inner { (pick, resolution) } BuiltinDriver::Union => { + let ((base, ours), theirs) = base.zip(ours).zip(theirs).expect("would use binary if missing"); let resolution = builtin_driver::text( out, input, @@ -346,13 +349,15 @@ pub(super) mod inner { ); (Pick::Buffer, resolution) } - }) + } } } - fn is_binary_buf(buf: &[u8]) -> bool { - let buf = &buf[..buf.len().min(8000)]; - buf.contains(&0) + fn is_binary_buf(buf: Option<&[u8]>) -> bool { + buf.map_or(true, |buf| { + let buf = &buf[..buf.len().min(8000)]; + buf.contains(&0) + }) } } } @@ -400,9 +405,7 @@ impl<'parent> PlatformRef<'parent> { Err(builtin) => { let mut input = imara_diff::intern::InternedInput::new(&[][..], &[]); out.clear(); - let (pick, resolution) = self - .builtin_merge(builtin, out, &mut input, labels) - .ok_or(Error::ResourceTooLarge)?; + let (pick, resolution) = self.builtin_merge(builtin, out, &mut input, labels); Ok((pick, resolution)) } } diff --git a/gix-merge/tests/merge/blob/platform.rs b/gix-merge/tests/merge/blob/platform.rs index 01123612dfb..2d750fdcccf 100644 --- a/gix-merge/tests/merge/blob/platform.rs +++ b/gix-merge/tests/merge/blob/platform.rs @@ -295,11 +295,7 @@ theirs let mut input = imara_diff::intern::InternedInput::new(&[][..], &[]); let res = platform_ref.builtin_merge(BuiltinDriver::Text, &mut buf, &mut input, Default::default()); - assert_eq!( - res, - Some((Pick::Buffer, Resolution::Complete)), - "both versions are deleted" - ); + assert_eq!(res, (Pick::Buffer, Resolution::Complete), "both versions are deleted"); assert!(buf.is_empty(), "the result is the same on direct invocation"); let print_all = "for arg in $@ %O %A %B %L %P %S %X %Y %F; do echo $arg; done"; @@ -358,24 +354,27 @@ theirs assert_eq!(platform_ref.other.data, platform::resource::Data::TooLarge { size: 12 }); let mut out = Vec::new(); - let err = platform_ref - .merge(&mut out, Default::default(), &Default::default()) - .unwrap_err(); - assert!(matches!(err, platform::merge::Error::ResourceTooLarge)); + let res = platform_ref.merge(&mut out, Default::default(), &Default::default())?; + assert_eq!( + res, + (Pick::Ours, Resolution::Conflict), + "this is the default for binary merges, which are used in this case" + ); let mut input = imara_diff::intern::InternedInput::new(&[][..], &[]); assert_eq!( platform_ref.builtin_merge(BuiltinDriver::Text, &mut out, &mut input, Default::default(),), - None + res, + "we can't enforce it, it will just default to using binary" ); let err = platform_ref .prepare_external_driver("bogus".into(), Default::default(), Default::default()) .unwrap_err(); - assert!(matches!( - err, - platform::prepare_external_driver::Error::ResourceTooLarge { .. } - )); + assert!( + matches!(err, platform::prepare_external_driver::Error::ResourceTooLarge { .. }), + "however, for external drivers, resources can still be too much to handle, until we learn how to stream them" + ); Ok(()) } From dd99991ec2bfb07ef571769abc32f1b35122d5ca Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 30 Oct 2024 11:07:17 +0100 Subject: [PATCH 10/23] feat: add `blob::PlatformRef::id_by_pick()` to more efficiently pick merge results. This works by either selecting a possibly unchanged and not even loaded resource, instead of always loading it to provide a buffer, in case the user doesn't actually want a buffer. Note that this also alters `buffer_by_pick()` to enforce handling of the 'buffer-too-large' option. --- gix-merge/src/blob/platform/merge.rs | 72 ++++++++++++++++++++------ gix-merge/tests/merge/blob/platform.rs | 65 ++++++++++++++++++++--- gix-merge/tests/merge/main.rs | 5 ++ 3 files changed, 118 insertions(+), 24 deletions(-) diff --git a/gix-merge/src/blob/platform/merge.rs b/gix-merge/src/blob/platform/merge.rs index bb4185023d9..5116ee4f96d 100644 --- a/gix-merge/src/blob/platform/merge.rs +++ b/gix-merge/src/blob/platform/merge.rs @@ -266,6 +266,8 @@ pub(super) mod inner { /// pub mod builtin_merge { + use crate::blob::platform::resource; + use crate::blob::platform::resource::Data; use crate::blob::{builtin_driver, BuiltinDriver, PlatformRef, Resolution}; /// An identifier to tell us how a merge conflict was resolved by [builtin_merge](PlatformRef::builtin_merge). @@ -307,11 +309,13 @@ pub(super) mod inner { input: &mut imara_diff::intern::InternedInput<&'parent [u8]>, labels: builtin_driver::text::Labels<'_>, ) -> (Pick, Resolution) { - let base = self.ancestor.data.as_slice(); - let ours = self.current.data.as_slice(); - let theirs = self.other.data.as_slice(); + let base = self.ancestor.data.as_slice().unwrap_or_default(); + let ours = self.current.data.as_slice().unwrap_or_default(); + let theirs = self.other.data.as_slice().unwrap_or_default(); let driver = if driver != BuiltinDriver::Binary - && (is_binary_buf(ours) || is_binary_buf(theirs) || is_binary_buf(base)) + && (is_binary_buf(self.ancestor.data) + || is_binary_buf(self.other.data) + || is_binary_buf(self.current.data)) { BuiltinDriver::Binary } else { @@ -319,7 +323,6 @@ pub(super) mod inner { }; match driver { BuiltinDriver::Text => { - let ((base, ours), theirs) = base.zip(ours).zip(theirs).expect("would use binary if missing"); let resolution = builtin_driver::text(out, input, labels, ours, base, theirs, self.options.text); (Pick::Buffer, resolution) @@ -334,7 +337,6 @@ pub(super) mod inner { (pick, resolution) } BuiltinDriver::Union => { - let ((base, ours), theirs) = base.zip(ours).zip(theirs).expect("would use binary if missing"); let resolution = builtin_driver::text( out, input, @@ -353,11 +355,15 @@ pub(super) mod inner { } } - fn is_binary_buf(buf: Option<&[u8]>) -> bool { - buf.map_or(true, |buf| { - let buf = &buf[..buf.len().min(8000)]; - buf.contains(&0) - }) + fn is_binary_buf(data: resource::Data<'_>) -> bool { + match data { + Data::Missing => false, + Data::Buffer(buf) => { + let buf = &buf[..buf.len().min(8000)]; + buf.contains(&0) + } + Data::TooLarge { .. } => true, + } } } } @@ -412,13 +418,45 @@ impl<'parent> PlatformRef<'parent> { } /// Using a `pick` obtained from [`merge()`](Self::merge), obtain the respective buffer suitable for reading or copying. - /// Return `None` if the buffer is too large, or if the `pick` corresponds to a buffer (that was written separately). - pub fn buffer_by_pick(&self, pick: inner::builtin_merge::Pick) -> Option<&'parent [u8]> { + /// Return `Ok(None)` if the `pick` corresponds to a buffer (that was written separately). + /// Return `Err(())` if the buffer is *too large*, so it was never read. + #[allow(clippy::result_unit_err)] + pub fn buffer_by_pick(&self, pick: inner::builtin_merge::Pick) -> Result, ()> { match pick { - inner::builtin_merge::Pick::Ancestor => self.ancestor.data.as_slice(), - inner::builtin_merge::Pick::Ours => self.current.data.as_slice(), - inner::builtin_merge::Pick::Theirs => self.other.data.as_slice(), - inner::builtin_merge::Pick::Buffer => None, + inner::builtin_merge::Pick::Ancestor => self.ancestor.data.as_slice().map(Some).ok_or(()), + inner::builtin_merge::Pick::Ours => self.current.data.as_slice().map(Some).ok_or(()), + inner::builtin_merge::Pick::Theirs => self.other.data.as_slice().map(Some).ok_or(()), + inner::builtin_merge::Pick::Buffer => Ok(None), + } + } + + /// Use `pick` to return the object id of the merged result, assuming that `buf` was passed as `out` to [merge()](Self::merge). + /// In case of binary or large files, this will simply be the existing ID of the resource. + /// In case of resources available in the object DB for binary merges, the object ID will be returned. + /// If new content was produced due to a content merge, `buf` will be written out + /// to the object database using `write_blob`. + /// Beware that the returned ID could be `Ok(None)` if the underlying resource was loaded + /// from the worktree *and* was too large so it was never loaded from disk. + /// `Ok(None)` will also be returned if one of the resources was missing. + /// `write_blob()` is used to turn buffers. + pub fn id_by_pick( + &self, + pick: inner::builtin_merge::Pick, + buf: &[u8], + mut write_blob: impl FnMut(&[u8]) -> Result, + ) -> Result, E> { + let field = match pick { + inner::builtin_merge::Pick::Ancestor => &self.ancestor, + inner::builtin_merge::Pick::Ours => &self.current, + inner::builtin_merge::Pick::Theirs => &self.other, + inner::builtin_merge::Pick::Buffer => return write_blob(buf).map(Some), + }; + use crate::blob::platform::resource::Data; + match field.data { + Data::TooLarge { .. } | Data::Missing if !field.id.is_null() => Ok(Some(field.id.to_owned())), + Data::TooLarge { .. } | Data::Missing => Ok(None), + Data::Buffer(buf) if field.id.is_null() => write_blob(buf).map(Some), + Data::Buffer(_) => Ok(Some(field.id.to_owned())), } } } diff --git a/gix-merge/tests/merge/blob/platform.rs b/gix-merge/tests/merge/blob/platform.rs index 2d750fdcccf..ae264245c5d 100644 --- a/gix-merge/tests/merge/blob/platform.rs +++ b/gix-merge/tests/merge/blob/platform.rs @@ -5,12 +5,14 @@ use gix_merge::blob::Platform; mod merge { use crate::blob::platform::new_platform; use crate::blob::util::ObjectDb; + use crate::hex_to_id; use bstr::{BStr, ByteSlice}; use gix_merge::blob::builtin_driver::text::ConflictStyle; use gix_merge::blob::platform::builtin_merge::Pick; use gix_merge::blob::platform::DriverChoice; use gix_merge::blob::{builtin_driver, pipeline, platform, BuiltinDriver, Resolution, ResourceKind}; use gix_object::tree::EntryKind; + use std::convert::Infallible; use std::process::Stdio; #[test] @@ -66,8 +68,9 @@ mod merge { #[test] fn builtin_with_conflict() -> crate::Result { let mut platform = new_platform(None, pipeline::Mode::ToGit); + let non_existing_ancestor_id = hex_to_id("ffffffffffffffffffffffffffffffffffffffff"); platform.set_resource( - gix_hash::Kind::Sha1.null(), + non_existing_ancestor_id, EntryKind::Blob, "b".into(), ResourceKind::CommonAncestorOrBase, @@ -152,20 +155,56 @@ theirs ); assert!(buf.is_empty(), "it tells us where to get the content from"); assert_eq!( - platform_ref.buffer_by_pick(res.0).unwrap().as_bstr(), + platform_ref.buffer_by_pick(res.0).unwrap().unwrap().as_bstr(), "ours", "getting access to the content is simplified" ); + assert_eq!( + platform_ref + .id_by_pick(res.0, &buf, |_buf| -> Result<_, Infallible> { + panic!("no need to write buffer") + }) + .unwrap() + .unwrap(), + hex_to_id("424860eef4edb9f5a2dacbbd6dc8c2d2e7645035"), + "there is no need to write a buffer here, it just returns one of our inputs" + ); - for (expected, expected_pick, resolve) in [ - ("ours", Pick::Ours, builtin_driver::binary::ResolveWith::Ours), - ("theirs", Pick::Theirs, builtin_driver::binary::ResolveWith::Theirs), - ("b\n", Pick::Ancestor, builtin_driver::binary::ResolveWith::Ancestor), + for (expected, expected_pick, resolve, expected_id) in [ + ( + "ours", + Pick::Ours, + builtin_driver::binary::ResolveWith::Ours, + hex_to_id("424860eef4edb9f5a2dacbbd6dc8c2d2e7645035"), + ), + ( + "theirs", + Pick::Theirs, + builtin_driver::binary::ResolveWith::Theirs, + hex_to_id("228068dbe790983c15535164cd483eb77ade97e4"), + ), + ( + "b\n", + Pick::Ancestor, + builtin_driver::binary::ResolveWith::Ancestor, + non_existing_ancestor_id, + ), ] { platform_ref.options.resolve_binary_with = Some(resolve); let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!(res, (expected_pick, Resolution::Complete)); - assert_eq!(platform_ref.buffer_by_pick(res.0).unwrap().as_bstr(), expected); + assert_eq!(platform_ref.buffer_by_pick(res.0).unwrap().unwrap().as_bstr(), expected); + + assert_eq!( + platform_ref + .id_by_pick(res.0, &buf, |_buf| -> Result<_, Infallible> { + panic!("no need to write buffer") + }) + .unwrap() + .unwrap(), + expected_id, + "{expected}: each input has an id, so it's just returned as is without handling buffers" + ); } Ok(()) @@ -234,6 +273,18 @@ theirs (Pick::Buffer, Resolution::Complete), "merge drivers deal with binary themselves" ); + assert_eq!( + platform_ref.buffer_by_pick(res.0), + Ok(None), + "This indicates the buffer must be read" + ); + + let marker = hex_to_id("ffffffffffffffffffffffffffffffffffffffff"); + assert_eq!( + platform_ref.id_by_pick(res.0, &buf, |_buf| Ok::<_, Infallible>(marker)), + Ok(Some(marker)), + "the id is created by hashing the merge buffer" + ); let mut lines = cleaned_driver_lines(&buf)?; for tmp_file in lines.by_ref().take(3) { assert!(tmp_file.contains_str(&b".tmp"[..]), "{tmp_file}"); diff --git a/gix-merge/tests/merge/main.rs b/gix-merge/tests/merge/main.rs index 9f7a6989d2c..4eaf3b13d0e 100644 --- a/gix-merge/tests/merge/main.rs +++ b/gix-merge/tests/merge/main.rs @@ -1,6 +1,11 @@ +use gix_hash::ObjectId; extern crate core; #[cfg(feature = "blob")] mod blob; pub use gix_testtools::Result; + +fn hex_to_id(hex: &str) -> ObjectId { + ObjectId::from_hex(hex.as_bytes()).expect("40 bytes hex") +} From 278dd8896007a7fa3d0ec2558cc2055303486259 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 19 Oct 2024 13:04:37 +0200 Subject: [PATCH 11/23] adapt to changes in `gix-merge` --- gitoxide-core/src/repository/merge.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gitoxide-core/src/repository/merge.rs b/gitoxide-core/src/repository/merge.rs index 6698dd3dd2f..120eff0135b 100644 --- a/gitoxide-core/src/repository/merge.rs +++ b/gitoxide-core/src/repository/merge.rs @@ -1,5 +1,5 @@ use crate::OutputFormat; -use anyhow::{bail, Context}; +use anyhow::{anyhow, bail, Context}; use gix::bstr::BString; use gix::bstr::ByteSlice; use gix::merge::blob::builtin_driver::binary; @@ -83,8 +83,11 @@ pub fn file( other: Some(theirs.as_bstr()), }; let mut buf = repo.empty_reusable_buffer(); - let (pick, resolution) = platform.merge(&mut buf, labels, repo.command_context()?)?; - let buf = platform.buffer_by_pick(pick).unwrap_or(&buf); + let (pick, resolution) = platform.merge(&mut buf, labels, &repo.command_context()?)?; + let buf = platform + .buffer_by_pick(pick) + .map_err(|_| anyhow!("Participating object was too large"))? + .unwrap_or(&buf); out.write_all(buf)?; if resolution == Resolution::Conflict { From de1cfb6a9caf5ac086c6411824835c75e888e2d7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 20 Oct 2024 17:39:50 +0200 Subject: [PATCH 12/23] fix!: Adjust blob-merge baseline to also test the reverse of each operation This also fixes an issue with blob merge computations. It's breaking because the marker-size was reduced to `u8`. --- gix-merge/fuzz/.gitignore | 7 + gix-merge/fuzz/Cargo.toml | 26 ++ gix-merge/fuzz/fuzz_targets/blob.rs | 80 +++++ .../src/blob/builtin_driver/text/function.rs | 315 +++++++++--------- gix-merge/src/blob/builtin_driver/text/mod.rs | 12 +- .../src/blob/builtin_driver/text/utils.rs | 61 +++- gix-merge/src/blob/platform/set_resource.rs | 2 +- .../generated-archives/text-baseline.tar | Bin 402944 -> 684032 bytes gix-merge/tests/fixtures/text-baseline.sh | 5 +- gix-merge/tests/merge/blob/builtin_driver.rs | 160 ++++++--- gix-merge/tests/merge/blob/platform.rs | 2 +- gix/src/repository/merge.rs | 2 +- 12 files changed, 445 insertions(+), 227 deletions(-) create mode 100644 gix-merge/fuzz/.gitignore create mode 100644 gix-merge/fuzz/Cargo.toml create mode 100644 gix-merge/fuzz/fuzz_targets/blob.rs diff --git a/gix-merge/fuzz/.gitignore b/gix-merge/fuzz/.gitignore new file mode 100644 index 00000000000..94e6cc53131 --- /dev/null +++ b/gix-merge/fuzz/.gitignore @@ -0,0 +1,7 @@ +target +corpus +artifacts + +# These usually involve a lot of local CPU time, keep them. +$artifacts +$corpus diff --git a/gix-merge/fuzz/Cargo.toml b/gix-merge/fuzz/Cargo.toml new file mode 100644 index 00000000000..881b91cb8fd --- /dev/null +++ b/gix-merge/fuzz/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "gix-merge-fuzz" +version = "0.0.0" +authors = ["Automatically generated"] +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +anyhow = "1.0.76" +libfuzzer-sys = "0.4" +arbitrary = { version = "1.3.2", features = ["derive"] } +imara-diff = { version = "0.1.7" } +gix-merge = { path = ".." } + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "blob" +path = "fuzz_targets/blob.rs" +test = false +doc = false diff --git a/gix-merge/fuzz/fuzz_targets/blob.rs b/gix-merge/fuzz/fuzz_targets/blob.rs new file mode 100644 index 00000000000..e96979a3b2a --- /dev/null +++ b/gix-merge/fuzz/fuzz_targets/blob.rs @@ -0,0 +1,80 @@ +#![no_main] +use anyhow::Result; +use arbitrary::Arbitrary; +use gix_merge::blob::builtin_driver::text::{Conflict, ConflictStyle, Options}; +use gix_merge::blob::Resolution; +use libfuzzer_sys::fuzz_target; +use std::hint::black_box; +use std::num::NonZero; + +fn fuzz_text_merge( + Ctx { + base, + ours, + theirs, + marker_size, + }: Ctx, +) -> Result<()> { + let mut buf = Vec::new(); + let mut input = imara_diff::intern::InternedInput::default(); + for diff_algorithm in [ + imara_diff::Algorithm::Histogram, + imara_diff::Algorithm::Myers, + imara_diff::Algorithm::MyersMinimal, + ] { + let mut opts = Options { + diff_algorithm, + conflict: Default::default(), + }; + for (left, right) in [(ours, theirs), (theirs, ours)] { + let resolution = gix_merge::blob::builtin_driver::text( + &mut buf, + &mut input, + Default::default(), + left, + base, + right, + opts, + ); + if resolution == Resolution::Conflict { + for conflict in [ + Conflict::ResolveWithOurs, + Conflict::ResolveWithTheirs, + Conflict::ResolveWithUnion, + Conflict::Keep { + style: ConflictStyle::Diff3, + marker_size, + }, + Conflict::Keep { + style: ConflictStyle::ZealousDiff3, + marker_size, + }, + ] { + opts.conflict = conflict; + gix_merge::blob::builtin_driver::text( + &mut buf, + &mut input, + Default::default(), + left, + base, + right, + opts, + ); + } + } + } + } + Ok(()) +} + +#[derive(Debug, Arbitrary)] +struct Ctx<'a> { + base: &'a [u8], + ours: &'a [u8], + theirs: &'a [u8], + marker_size: NonZero, +} + +fuzz_target!(|ctx: Ctx<'_>| { + _ = black_box(fuzz_text_merge(ctx)); +}); diff --git a/gix-merge/src/blob/builtin_driver/text/function.rs b/gix-merge/src/blob/builtin_driver/text/function.rs index bb800ce47e2..2b0a2e7522c 100644 --- a/gix-merge/src/blob/builtin_driver/text/function.rs +++ b/gix-merge/src/blob/builtin_driver/text/function.rs @@ -5,6 +5,7 @@ use crate::blob::builtin_driver::text::utils::{ }; use crate::blob::builtin_driver::text::{Conflict, ConflictStyle, Labels, Options}; use crate::blob::Resolution; +use std::ops::Range; /// Merge `current` and `other` with `ancestor` as base according to `opts`. /// @@ -36,7 +37,7 @@ pub fn merge<'a>( input.update_before(tokens(ancestor)); input.update_after(tokens(current)); - let current_hunks = imara_diff::diff( + let hunks = imara_diff::diff( opts.diff_algorithm, input, CollectHunks { @@ -53,187 +54,197 @@ pub fn merge<'a>( input, CollectHunks { side: Side::Other, - hunks: current_hunks, + hunks, }, ); + if hunks.is_empty() { + write_ancestor(input, 0, input.before.len(), out); + return Resolution::Complete; + } + hunks.sort_by(|a, b| a.before.start.cmp(&b.before.start)); let mut hunks = hunks.into_iter().peekable(); let mut intersecting = Vec::new(); let mut ancestor_integrated_until = 0; let mut resolution = Resolution::Complete; - let mut filled_hunks = Vec::with_capacity(2); - while let Some(hunk) = hunks.next() { - if take_intersecting(&hunk, &mut hunks, &mut intersecting) { - fill_ancestor(&hunk.before, &mut intersecting); + let mut current_hunks = Vec::with_capacity(2); + while take_intersecting(&mut hunks, &mut current_hunks, &mut intersecting).is_some() { + if intersecting.is_empty() { + let hunk = current_hunks.pop().expect("always pushed during intersection check"); + write_ancestor(input, ancestor_integrated_until, hunk.before.start as usize, out); + ancestor_integrated_until = hunk.before.end; + write_hunks(std::slice::from_ref(&hunk), input, ¤t_tokens, out); + continue; + } - let filled_hunks_side = hunk.side; - filled_hunks.clear(); - filled_hunks.push(hunk); - fill_ancestor( - &intersecting - .first() - .zip(intersecting.last()) - .map(|(f, l)| f.before.start..l.before.end) - .expect("at least one entry"), - &mut filled_hunks, - ); - match opts.conflict { - Conflict::Keep { style, marker_size } => { - let (hunks_front_and_back, num_hunks_front) = match style { - ConflictStyle::Merge | ConflictStyle::ZealousDiff3 => { - zealously_contract_hunks(&mut filled_hunks, &mut intersecting, input, ¤t_tokens) - } - ConflictStyle::Diff3 => (Vec::new(), 0), - }; - let (our_hunks, their_hunks) = match filled_hunks_side { - Side::Current => (&filled_hunks, &intersecting), - Side::Other => (&intersecting, &filled_hunks), - Side::Ancestor => { - unreachable!("initial hunks are never ancestors") + let filled_hunks_side = current_hunks.first().expect("at least one hunk").side; + { + let filled_hunks_range = before_range_from_hunks(¤t_hunks); + let intersecting_range = before_range_from_hunks(&intersecting); + let extended_range = filled_hunks_range.start..intersecting_range.end.max(filled_hunks_range.end); + fill_ancestor(&extended_range, &mut current_hunks); + fill_ancestor(&extended_range, &mut intersecting); + } + match opts.conflict { + Conflict::Keep { style, marker_size } => { + let marker_size = marker_size.get(); + let (hunks_front_and_back, num_hunks_front) = match style { + ConflictStyle::Merge | ConflictStyle::ZealousDiff3 => { + zealously_contract_hunks(&mut current_hunks, &mut intersecting, input, ¤t_tokens) + } + ConflictStyle::Diff3 => (Vec::new(), 0), + }; + let (our_hunks, their_hunks) = match filled_hunks_side { + Side::Current => (¤t_hunks, &intersecting), + Side::Other => (&intersecting, ¤t_hunks), + Side::Ancestor => { + unreachable!("initial hunks are never ancestors") + } + }; + let (front_hunks, back_hunks) = hunks_front_and_back.split_at(num_hunks_front); + let first_hunk = first_hunk(front_hunks, our_hunks, their_hunks, back_hunks); + let last_hunk = last_hunk(front_hunks, our_hunks, their_hunks, back_hunks); + write_ancestor(input, ancestor_integrated_until, first_hunk.before.start as usize, out); + write_hunks(front_hunks, input, ¤t_tokens, out); + if their_hunks.is_empty() { + write_hunks(our_hunks, input, ¤t_tokens, out); + } else if our_hunks.is_empty() { + write_hunks(their_hunks, input, ¤t_tokens, out); + } else { + // DEVIATION: this makes tests (mostly) pass, but probably is very different from what Git does. + let hunk_storage; + let nl = detect_line_ending( + if front_hunks.is_empty() { + hunk_storage = Hunk { + before: ancestor_integrated_until..first_hunk.before.start, + after: Default::default(), + side: Side::Ancestor, + }; + std::slice::from_ref(&hunk_storage) + } else { + front_hunks + }, + input, + ¤t_tokens, + ) + .or_else(|| detect_line_ending(our_hunks, input, ¤t_tokens)) + .unwrap_or(b"\n".into()); + match style { + ConflictStyle::Merge => { + if contains_lines(our_hunks) || contains_lines(their_hunks) { + resolution = Resolution::Conflict; + write_conflict_marker(out, b'<', current_label, marker_size, nl); + write_hunks(our_hunks, input, ¤t_tokens, out); + write_conflict_marker(out, b'=', None, marker_size, nl); + write_hunks(their_hunks, input, ¤t_tokens, out); + write_conflict_marker(out, b'>', other_label, marker_size, nl); + } } - }; - let (front_hunks, back_hunks) = hunks_front_and_back.split_at(num_hunks_front); - let first_hunk = front_hunks - .first() - .or(our_hunks.first()) - .expect("at least one hunk to write"); - let last_hunk = back_hunks - .last() - .or(their_hunks.last()) - .or(our_hunks.last()) - .or(front_hunks.last()) - .expect("at least one hunk"); - write_ancestor(input, ancestor_integrated_until, first_hunk.before.start as usize, out); - - write_hunks(front_hunks, input, ¤t_tokens, out); - if their_hunks.is_empty() { - write_hunks(our_hunks, input, ¤t_tokens, out); - } else if our_hunks.is_empty() { - // TODO: assure we run into this - currently no test triggers this. Can this happen at all? - write_hunks(their_hunks, input, ¤t_tokens, out); - } else { - // DEVIATION: this makes tests (mostly) pass, but probably is very different from what Git does. - let hunk_storage; - let nl = detect_line_ending( - if front_hunks.is_empty() { - hunk_storage = Hunk { - before: ancestor_integrated_until..first_hunk.before.start, - after: Default::default(), - side: Side::Ancestor, - }; - std::slice::from_ref(&hunk_storage) - } else { - front_hunks - }, - input, - ¤t_tokens, - ) - .or_else(|| detect_line_ending(our_hunks, input, ¤t_tokens)) - .unwrap_or(b"\n".into()); - match style { - ConflictStyle::Merge => { - if contains_lines(our_hunks) || contains_lines(their_hunks) { + ConflictStyle::Diff3 | ConflictStyle::ZealousDiff3 => { + if contains_lines(our_hunks) || contains_lines(their_hunks) { + if hunks_differ_in_diff3(style, our_hunks, their_hunks, input, ¤t_tokens) { resolution = Resolution::Conflict; write_conflict_marker(out, b'<', current_label, marker_size, nl); write_hunks(our_hunks, input, ¤t_tokens, out); + let ancestor_hunk = Hunk { + before: first_hunk.before.start..last_hunk.before.end, + after: Default::default(), + side: Side::Ancestor, + }; + let ancestor_hunk = std::slice::from_ref(&ancestor_hunk); + let ancestor_nl = detect_line_ending_or_nl(ancestor_hunk, input, ¤t_tokens); + write_conflict_marker(out, b'|', ancestor_label, marker_size, ancestor_nl); + write_hunks(ancestor_hunk, input, ¤t_tokens, out); write_conflict_marker(out, b'=', None, marker_size, nl); write_hunks(their_hunks, input, ¤t_tokens, out); write_conflict_marker(out, b'>', other_label, marker_size, nl); - } - } - ConflictStyle::Diff3 | ConflictStyle::ZealousDiff3 => { - if contains_lines(our_hunks) || contains_lines(their_hunks) { - if hunks_differ_in_diff3(style, our_hunks, their_hunks, input, ¤t_tokens) { - resolution = Resolution::Conflict; - write_conflict_marker(out, b'<', current_label, marker_size, nl); - write_hunks(our_hunks, input, ¤t_tokens, out); - let ancestor_hunk = Hunk { - before: first_hunk.before.start..last_hunk.before.end, - after: Default::default(), - side: Side::Ancestor, - }; - let ancestor_hunk = std::slice::from_ref(&ancestor_hunk); - let ancestor_nl = - detect_line_ending_or_nl(ancestor_hunk, input, ¤t_tokens); - write_conflict_marker(out, b'|', ancestor_label, marker_size, ancestor_nl); - write_hunks(ancestor_hunk, input, ¤t_tokens, out); - write_conflict_marker(out, b'=', None, marker_size, nl); - write_hunks(their_hunks, input, ¤t_tokens, out); - write_conflict_marker(out, b'>', other_label, marker_size, nl); - } else { - write_hunks(our_hunks, input, ¤t_tokens, out); - } + } else { + write_hunks(our_hunks, input, ¤t_tokens, out); } } } } - write_hunks(back_hunks, input, ¤t_tokens, out); - ancestor_integrated_until = last_hunk.before.end; } - Conflict::ResolveWithOurs | Conflict::ResolveWithTheirs => { - let (our_hunks, their_hunks) = match filled_hunks_side { - Side::Current => (&filled_hunks, &intersecting), - Side::Other => (&intersecting, &filled_hunks), - Side::Ancestor => { - unreachable!("initial hunks are never ancestors") - } - }; - let hunks_to_write = if opts.conflict == Conflict::ResolveWithOurs { - our_hunks - } else { - their_hunks - }; - if let Some(first_hunk) = hunks_to_write.first() { - write_ancestor(input, ancestor_integrated_until, first_hunk.before.start as usize, out); - } - write_hunks(hunks_to_write, input, ¤t_tokens, out); - if let Some(last_hunk) = hunks_to_write.last() { - ancestor_integrated_until = last_hunk.before.end; + write_hunks(back_hunks, input, ¤t_tokens, out); + ancestor_integrated_until = last_hunk.before.end; + } + Conflict::ResolveWithOurs | Conflict::ResolveWithTheirs => { + let (our_hunks, their_hunks) = match filled_hunks_side { + Side::Current => (¤t_hunks, &intersecting), + Side::Other => (&intersecting, ¤t_hunks), + Side::Ancestor => { + unreachable!("initial hunks are never ancestors") } + }; + let hunks_to_write = if opts.conflict == Conflict::ResolveWithOurs { + our_hunks + } else { + their_hunks + }; + if let Some(first_hunk) = hunks_to_write.first() { + write_ancestor(input, ancestor_integrated_until, first_hunk.before.start as usize, out); + } + write_hunks(hunks_to_write, input, ¤t_tokens, out); + if let Some(last_hunk) = hunks_to_write.last() { + ancestor_integrated_until = last_hunk.before.end; } - Conflict::ResolveWithUnion => { - let (hunks_front_and_back, num_hunks_front) = - zealously_contract_hunks(&mut filled_hunks, &mut intersecting, input, ¤t_tokens); + } + Conflict::ResolveWithUnion => { + let (hunks_front_and_back, num_hunks_front) = + zealously_contract_hunks(&mut current_hunks, &mut intersecting, input, ¤t_tokens); - let (our_hunks, their_hunks) = match filled_hunks_side { - Side::Current => (&filled_hunks, &intersecting), - Side::Other => (&intersecting, &filled_hunks), - Side::Ancestor => { - unreachable!("initial hunks are never ancestors") - } - }; - let (front_hunks, back_hunks) = hunks_front_and_back.split_at(num_hunks_front); - let first_hunk = front_hunks - .first() - .or(our_hunks.first()) - .expect("at least one hunk to write"); - write_ancestor(input, ancestor_integrated_until, first_hunk.before.start as usize, out); - write_hunks(front_hunks, input, ¤t_tokens, out); - assure_ends_with_nl(out, detect_line_ending_or_nl(front_hunks, input, ¤t_tokens)); - write_hunks(our_hunks, input, ¤t_tokens, out); - assure_ends_with_nl(out, detect_line_ending_or_nl(our_hunks, input, ¤t_tokens)); - write_hunks(their_hunks, input, ¤t_tokens, out); - if !back_hunks.is_empty() { - assure_ends_with_nl(out, detect_line_ending_or_nl(their_hunks, input, ¤t_tokens)); + let (our_hunks, their_hunks) = match filled_hunks_side { + Side::Current => (¤t_hunks, &intersecting), + Side::Other => (&intersecting, ¤t_hunks), + Side::Ancestor => { + unreachable!("initial hunks are never ancestors") } - write_hunks(back_hunks, input, ¤t_tokens, out); - let last_hunk = back_hunks - .last() - .or(their_hunks.last()) - .or(our_hunks.last()) - .or(front_hunks.last()) - .expect("at least one hunk"); - ancestor_integrated_until = last_hunk.before.end; + }; + let (front_hunks, back_hunks) = hunks_front_and_back.split_at(num_hunks_front); + let first_hunk = first_hunk(front_hunks, our_hunks, their_hunks, back_hunks); + write_ancestor(input, ancestor_integrated_until, first_hunk.before.start as usize, out); + write_hunks(front_hunks, input, ¤t_tokens, out); + assure_ends_with_nl(out, detect_line_ending_or_nl(front_hunks, input, ¤t_tokens)); + write_hunks(our_hunks, input, ¤t_tokens, out); + assure_ends_with_nl(out, detect_line_ending_or_nl(our_hunks, input, ¤t_tokens)); + write_hunks(their_hunks, input, ¤t_tokens, out); + if !back_hunks.is_empty() { + assure_ends_with_nl(out, detect_line_ending_or_nl(their_hunks, input, ¤t_tokens)); } + write_hunks(back_hunks, input, ¤t_tokens, out); + let last_hunk = last_hunk(front_hunks, our_hunks, their_hunks, back_hunks); + ancestor_integrated_until = last_hunk.before.end; } - } else { - write_ancestor(input, ancestor_integrated_until, hunk.before.start as usize, out); - ancestor_integrated_until = hunk.before.end; - write_hunks(std::slice::from_ref(&hunk), input, ¤t_tokens, out); } } write_ancestor(input, ancestor_integrated_until, input.before.len(), out); resolution } + +fn first_hunk<'a>(front: &'a [Hunk], ours: &'a [Hunk], theirs: &'a [Hunk], back: &'a [Hunk]) -> &'a Hunk { + front + .first() + .or(ours.first()) + .or(theirs.first()) + .or(back.first()) + .expect("at least one hunk - we aborted if there are none anywhere") +} + +/// Note that last-hunk could be [`first_hunk()`], so the hunk must only be used accordingly. +fn last_hunk<'a>(front: &'a [Hunk], ours: &'a [Hunk], theirs: &'a [Hunk], back: &'a [Hunk]) -> &'a Hunk { + back.last() + .or(theirs.last()) + .or(ours.last()) + .or(front.last()) + .expect("at least one hunk - we aborted if there are none anywhere") +} + +fn before_range_from_hunks(hunks: &[Hunk]) -> Range { + hunks + .first() + .zip(hunks.last()) + .map(|(f, l)| f.before.start..l.before.end) + .expect("at least one entry") +} diff --git a/gix-merge/src/blob/builtin_driver/text/mod.rs b/gix-merge/src/blob/builtin_driver/text/mod.rs index 6c5a432782d..a3b38048abd 100644 --- a/gix-merge/src/blob/builtin_driver/text/mod.rs +++ b/gix-merge/src/blob/builtin_driver/text/mod.rs @@ -1,4 +1,5 @@ use bstr::BStr; +use std::num::NonZeroU8; /// The way the built-in [text driver](crate::blob::BuiltinDriver::Text) will express /// merge conflicts in the resulting file. @@ -87,7 +88,7 @@ pub enum Conflict { /// How to visualize conflicts in merged files. style: ConflictStyle, /// The amount of markers to draw, defaults to 7, i.e. `<<<<<<<` - marker_size: usize, + marker_size: NonZeroU8, }, /// Chose our side to resolve a conflict. ResolveWithOurs, @@ -99,12 +100,13 @@ pub enum Conflict { impl Conflict { /// The amount of conflict marker characters to print by default. - pub const DEFAULT_MARKER_SIZE: usize = 7; + // TODO: use NonZeroU8::new().unwrap() here once the MSRV supports it. + pub const DEFAULT_MARKER_SIZE: u8 = 7; /// The amount of conflict markers to print if this instance contains them, or `None` otherwise - pub fn marker_size(&self) -> Option { + pub fn marker_size(&self) -> Option { match self { - Conflict::Keep { marker_size, .. } => Some(*marker_size), + Conflict::Keep { marker_size, .. } => Some(marker_size.get()), Conflict::ResolveWithOurs | Conflict::ResolveWithTheirs | Conflict::ResolveWithUnion => None, } } @@ -114,7 +116,7 @@ impl Default for Conflict { fn default() -> Self { Conflict::Keep { style: Default::default(), - marker_size: Conflict::DEFAULT_MARKER_SIZE, + marker_size: Conflict::DEFAULT_MARKER_SIZE.try_into().unwrap(), } } } diff --git a/gix-merge/src/blob/builtin_driver/text/utils.rs b/gix-merge/src/blob/builtin_driver/text/utils.rs index 1aab3e47f08..877f2693145 100644 --- a/gix-merge/src/blob/builtin_driver/text/utils.rs +++ b/gix-merge/src/blob/builtin_driver/text/utils.rs @@ -93,9 +93,9 @@ pub fn assure_ends_with_nl(out: &mut Vec, nl: &BStr) { } } -pub fn write_conflict_marker(out: &mut Vec, marker: u8, label: Option<&BStr>, marker_size: usize, nl: &BStr) { +pub fn write_conflict_marker(out: &mut Vec, marker: u8, label: Option<&BStr>, marker_size: u8, nl: &BStr) { assure_ends_with_nl(out, nl); - out.extend(std::iter::repeat(marker).take(marker_size)); + out.extend(std::iter::repeat(marker).take(marker_size as usize)); if let Some(label) = label { out.push(b' '); out.extend_from_slice(label); @@ -132,8 +132,8 @@ pub fn fill_ancestor(Range { start, end }: &Range, in_out: &mut Vec) for (idx, next_idx) in (first_idx..in_out.len()).map(|idx| (idx, idx + 1)) { let Some(next_hunk) = in_out.get(next_idx) else { break }; let hunk = &in_out[idx]; - if let Some(lines_to_add) = next_hunk.after.start.checked_sub(hunk.after.end).filter(is_nonzero) { - in_out.push(ancestor_hunk(hunk.after.end, lines_to_add)); + if let Some(lines_to_add) = next_hunk.before.start.checked_sub(hunk.before.end).filter(is_nonzero) { + in_out.push(ancestor_hunk(hunk.before.end, lines_to_add)); added_hunks = true; } } @@ -414,21 +414,46 @@ fn write_tokens( } /// Find all hunks in `iter` which aren't from the same side as `hunk` and intersect with it. -/// Return `true` if `out` is non-empty after the operation, indicating overlapping hunks were found. -pub fn take_intersecting(hunk: &Hunk, iter: &mut Peekable>, out: &mut Vec) -> bool { - out.clear(); - while iter - .peek() - .filter(|b_hunk| { - b_hunk.side != hunk.side - && (hunk.before.contains(&b_hunk.before.start) - || (hunk.before.is_empty() && hunk.before.start == b_hunk.before.start)) - }) - .is_some() - { - out.extend(iter.next()); +/// Also put `hunk` into `input` so it's the first item, and possibly put more hunks of the side of `hunk` so +/// `iter` doesn't have any overlapping hunks left. +/// Return `true` if `intersecting` is non-empty after the operation, indicating overlapping hunks were found. +pub fn take_intersecting( + iter: &mut Peekable>, + input: &mut Vec, + intersecting: &mut Vec, +) -> Option<()> { + input.clear(); + input.push(iter.next()?); + intersecting.clear(); + + fn left_overlaps_right(left: &Hunk, right: &Hunk) -> bool { + left.side != right.side + && (right.before.contains(&left.before.start) + || (right.before.is_empty() && right.before.start == left.before.start)) + } + + loop { + let hunk = input.last().expect("just pushed"); + while iter.peek().filter(|b_hunk| left_overlaps_right(b_hunk, hunk)).is_some() { + intersecting.extend(iter.next()); + } + // The hunks that overlap might themselves overlap with a following hunk of the other side. + // If so, split it so it doesn't overlap anymore. + let mut found_more_intersections = false; + while intersecting + .last_mut() + .zip(iter.peek_mut()) + .filter(|(last_intersecting, candidate)| left_overlaps_right(candidate, last_intersecting)) + .is_some() + { + input.extend(iter.next()); + found_more_intersections = true; + } + if !found_more_intersections { + break; + } } - !out.is_empty() + Some(()) } pub fn tokens(input: &[u8]) -> imara_diff::sources::ByteLines<'_, true> { diff --git a/gix-merge/src/blob/platform/set_resource.rs b/gix-merge/src/blob/platform/set_resource.rs index c3dae8ffd4d..675c84d9ce9 100644 --- a/gix-merge/src/blob/platform/set_resource.rs +++ b/gix-merge/src/blob/platform/set_resource.rs @@ -34,7 +34,7 @@ impl Platform { /// If an `id` is known, as the hash of the object as (would) be stored in `git`, then it should be provided /// for completeness. Note that it's not expected to be in `objects` if `rela_path` is set and a worktree-root /// is available for `kind`. - /// * `mode` is the kind of object (only blobs and links are allowed) + /// * `mode` is the kind of object (only blobs and executables are allowed) /// * `rela_path` is the relative path as seen from the (work)tree root. /// * `kind` identifies the side of the merge this resource will be used for. /// * `objects` provides access to the object database in case the resource can't be read from a worktree. diff --git a/gix-merge/tests/fixtures/generated-archives/text-baseline.tar b/gix-merge/tests/fixtures/generated-archives/text-baseline.tar index 8bd4e8f2244dd7a8d08f0d24d4c0d6fcb7aaa715..c0601e39edef7336fece921dbe2d5b7d51cafdf1 100644 GIT binary patch delta 25577 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 delta 2482 zcmYLLe@vCv8P50fob!E`i-NTkE^zCdaYo=4<<2@(td?rlA^Q=s8rw4c(jjdOTGwV+ z^(MvJ4lRmT?hA?(E8E>%O9@PlbqpEVI{%==xn^^w+3u3Xbd70mnx!r^>-L=QyVgH6 zdcN~M@B2Q_^SOM5aW@^ZI_ZyiutLEj{1~mE*?*= zc#Wl6YTWVix;sYtNx{aWo3d=IDXi16-CBss2d##ls7YQ{$K~c%-PHP4L8W8X7M!NM zG!ENdb*U#bjZA-}9dW6pNeC*da@L?P z1BhQ}T`uLe`n=Sru4FQ-pJuf7dCjGYMrSp7%T;i>-eXYv^Fgt3g{aEWcd>~Yy;P_7 zcA?;kS+SP9eflcdw_1PMrO^iDLIdDi;XbbSy7csOnoWyxVq{-q2EqB%h zN6+b}4O+yVjS^4;Y$BmEJ;RcED8o*vzs~DivP(L;|2Qu0b{`^dN>wzYDw@+ndM5Nf zE{8tULv*H7Q>s5oJL1|Bnf#BQWHQ7J0F?g#00H@S%G-+?=NVuxV$4TJT|q|(TW-W< z-(us(Zn`ySXme^u7DsU$(dDB-L*G>QY9%!QfkwOhjvDf@&Bh^vrdspW<`17TTG>RK zQJ`lE+6}1vU0?_9vdA0a;Jnj#5o(__p!TpTH*gfb!jUrhrYiNKA3ursbyLQd@d1%n zjaLw!H8_nt12F@GBKoF{=$!GIb`Nk;S>ZFI&AOnO3r(sV4g9}>yv-)Qa5DktysZft zjhL9DLt~mP%T}15Gx~eC@Sz_eZ^o*X{dH!iK~=vEc&*RJZ!-5V$(zg~J5#dF4AIrj zpw|u3+igy`)SeW!j2={YqnV)8_2k7EIOsOJ3>i(EA2NFQv{oqZf5X&tiXIS_Ec>~6 z$EBu@0Ba)w3(lKVwPsIg77Y$)A?W^%UeCh$teIfcav-P{i9awe8M6GJ=0}X4I4DAL zK~4eZ@J}`QJ{sEj%zQ~u;w(BZ=hkgO(`TV}Bq3Y?uOol}d7*WHQS1%PmC>cv9fL-O zf++zdennMQJ0mfnmCL1TEaXVMgW|r`3yP5FA@YVcGhF@kbs+%vd9gntJnw#g(}1zh=R(UoIEgx!XkC4Qn5x-=vZEt4rDXo@kNuZd#)n zjrOCT=y{FF=q(HTw(&*etFC9YxI!LMUg)>?yHwcck0FHhJvGk;YsdS+T1C_bYuywy z1m^wk%WUPDRrY;OrtA?rM4x1_4Pig9{(=opHrq*;*8c-?z=#`C-m(Yf;b-hVwDN7+ zcVwN!#mo21h>iCh8;&|??}g+ucB%YImkl{0m!N*^xQ)tN{sN&ZhizE=>J1=I|JoP2 zn!FAUGyKXv!f4)KQF8U~RLQwZfz4Mcp)pgl_9<|1-L~}fTd+}eGsl+!HEn;hUkByy z0ln%|h2As=^fyO*^eQ!xXh>(>jB;~8j}(V5F3r7#L=XUpmLKtDu2j>6&rK@F^iMDZARWbBRDNn0sgXBqYGwaaY2V>~JB~pYb!`k@3xWo^=WudR=8`bnqJZT28Se z29-2Bn22FD)K}PEnDx)>zM@RoEf%Ki*S}dy174RCafH(6}hqhePLJ|@{*8jZ^K324G@NxW)AZ_ghp%z0-Le|UR z*yFCO>f+#h-k;!NaDJW9mUmU}gB(l`ofj6}?=OXBwU>uEtT*(Fpk|N}*HGU@p2km& z-vfT+5B}Z(BmNe@!js4`#(h(Q5&!TyKk63_MtsODf0jw@7I*ZF`zd#*?hAf*o3mh> zo8qvWaTj1wx>140Ai6V{7yNKw(px6*QobvSb!zEB2_K(8A9#+@{IO$b9*?kc-Ep{X zV2$rOtmY2{#LtQSjHY?0@Tb){GiCP^g^dt7B6tn|MWI&+eIY~wr%bSY$#X& zXwm(u*O&ZW?~<_2>1OHuYNi{3CL#Gv_Ol(18Gh*Dc "$output" || true - echo "$ours" "$base" "$theirs" "$output" "$@" >> baseline.cases + + local output="${output}-reversed" + git merge-file --stdout "$@" "$theirs" "$base" "$ours" > "${output}" || true + echo "$theirs" "$base" "$ours" "${output}" "$@" >> baseline-reversed.cases } mkdir simple diff --git a/gix-merge/tests/merge/blob/builtin_driver.rs b/gix-merge/tests/merge/blob/builtin_driver.rs index b0d7afa8f85..fd08c0f8140 100644 --- a/gix-merge/tests/merge/blob/builtin_driver.rs +++ b/gix-merge/tests/merge/blob/builtin_driver.rs @@ -25,7 +25,8 @@ fn binary() { mod text { use bstr::ByteSlice; - use gix_merge::blob::Resolution; + use gix_merge::blob::builtin_driver::text::Conflict; + use gix_merge::blob::{builtin_driver, Resolution}; use pretty_assertions::assert_str_eq; const DIVERGING: &[&str] = &[ @@ -71,60 +72,122 @@ mod text { "complex/spurious-c-conflicts/zdiff3-histogram.merged", ]; + /// Should be a copy of `DIVERGING` once the reverse operation truly works like before + const DIVERGING_REVERSED: &[&str] = &[ + // expected cases + "zdiff3-middlecommon/merge.merged-reversed", + "zdiff3-middlecommon/merge-union.merged-reversed", + "zdiff3-interesting/merge.merged-reversed", + "zdiff3-interesting/merge-theirs.merged-reversed", + "zdiff3-interesting/diff3.merged-reversed", + "zdiff3-interesting/diff3-histogram.merged-reversed", + "zdiff3-interesting/zdiff3.merged-reversed", + "zdiff3-interesting/zdiff3-histogram.merged-reversed", + "zdiff3-interesting/merge-union.merged-reversed", + "zdiff3-evil/merge.merged-reversed", + "zdiff3-evil/merge-union.merged-reversed", + "complex/missing-LF-at-EOF/merge.merged-reversed", + "complex/missing-LF-at-EOF/diff3.merged-reversed", + "complex/missing-LF-at-EOF/diff3-histogram.merged-reversed", + "complex/missing-LF-at-EOF/zdiff3.merged-reversed", + "complex/missing-LF-at-EOF/zdiff3-histogram.merged-reversed", + "complex/missing-LF-at-EOF/merge-ours.merged-reversed", + "complex/missing-LF-at-EOF/merge-theirs.merged-reversed", + "complex/missing-LF-at-EOF/merge-union.merged-reversed", + "complex/auto-simplification/merge.merged-reversed", + "complex/auto-simplification/merge-union.merged-reversed", + "complex/marker-newline-handling-lf2/zdiff3.merged-reversed", + "complex/marker-newline-handling-lf2/zdiff3-histogram.merged-reversed", + "complex/spurious-c-conflicts/merge.merged-reversed", + "complex/spurious-c-conflicts/merge-union.merged-reversed", + "complex/spurious-c-conflicts/diff3-histogram.merged-reversed", + "complex/spurious-c-conflicts/zdiff3-histogram.merged-reversed", + ]; + // TODO: fix all of these eventually - fn is_case_diverging(case: &baseline::Expectation) -> bool { - DIVERGING.iter().any(|name| case.name == *name) + fn is_case_diverging(case: &baseline::Expectation, diverging: &[&str]) -> bool { + diverging.iter().any(|name| case.name == *name) + } + + #[test] + fn fuzzed() { + for (ours, base, theirs, opts) in [ + ( + &[255, 10, 10, 255][..], + &[0, 10, 10, 13, 10, 193, 0, 51, 8, 33][..], + &[10, 255, 10, 10, 10, 0, 10][..], + builtin_driver::text::Options { + conflict: Conflict::ResolveWithUnion, + diff_algorithm: imara_diff::Algorithm::Myers, + }, + ), + ( + &[], + &[10, 255, 255, 255], + &[255, 10, 255, 10, 10, 255, 40], + builtin_driver::text::Options::default(), + ), + ] { + let mut out = Vec::new(); + let mut input = imara_diff::intern::InternedInput::default(); + gix_merge::blob::builtin_driver::text(&mut out, &mut input, Default::default(), ours, base, theirs, opts); + } } #[test] fn run_baseline() -> crate::Result { let root = gix_testtools::scripted_fixture_read_only("text-baseline.sh")?; - let cases = std::fs::read_to_string(root.join("baseline.cases"))?; - let mut out = Vec::new(); - let mut num_diverging = 0; - let mut num_cases = 0; - for case in baseline::Expectations::new(&root, &cases) { - num_cases += 1; - let mut input = imara_diff::intern::InternedInput::default(); - let actual = gix_merge::blob::builtin_driver::text( - &mut out, - &mut input, - case.labels(), - &case.ours, - &case.base, - &case.theirs, - case.options, - ); - if is_case_diverging(&case) { - num_diverging += 1; - } else { - let expected_resolution = if case.expected.contains_str("<<<<<<<") { - Resolution::Conflict - } else { - Resolution::Complete - }; - assert_eq!(out.as_bstr(), case.expected); - assert_str_eq!( - out.as_bstr().to_str_lossy(), - case.expected.to_str_lossy(), - "{}: output mismatch\n{}", - case.name, - out.as_bstr() + for (baseline, diverging, expected_percentage) in [ + ("baseline-reversed.cases", DIVERGING_REVERSED, 11), + ("baseline.cases", DIVERGING, 11), + ] { + let cases = std::fs::read_to_string(root.join(baseline))?; + let mut out = Vec::new(); + let mut num_diverging = 0; + let mut num_cases = 0; + for case in baseline::Expectations::new(&root, &cases) { + num_cases += 1; + let mut input = imara_diff::intern::InternedInput::default(); + let actual = gix_merge::blob::builtin_driver::text( + &mut out, + &mut input, + case.labels(), + &case.ours, + &case.base, + &case.theirs, + case.options, ); - assert_eq!(actual, expected_resolution, "{}: resolution mismatch", case.name,); + if is_case_diverging(&case, diverging) { + num_diverging += 1; + } else { + let expected_resolution = if case.expected.contains_str("<<<<<<<") { + Resolution::Conflict + } else { + Resolution::Complete + }; + assert_str_eq!( + out.as_bstr().to_str_lossy(), + case.expected.to_str_lossy(), + "{}: output mismatch\n{}", + case.name, + out.as_bstr() + ); + assert_eq!(out.as_bstr(), case.expected); + assert_eq!(actual, expected_resolution, "{}: resolution mismatch", case.name,); + } } - } - assert_eq!( - num_diverging, - DIVERGING.len(), - "Number of expected diverging cases must match the actual one - probably the implementation improved" - ); - assert_eq!( - ((num_diverging as f32 / num_cases as f32) * 100.0) as usize, - 11, - "Just to show the percentage of skipped tests - this should get better" - ); + assert_eq!( + num_diverging, + diverging.len(), + "Number of expected diverging cases must match the actual one - probably the implementation improved" + ); + assert_eq!( + ((num_diverging as f32 / num_cases as f32) * 100.0) as usize, + expected_percentage, + "Just to show the percentage of skipped tests - this should get better" + ); + } Ok(()) } @@ -185,15 +248,16 @@ mod text { let read = |rela_path: &str| read_blob(self.root, rela_path); let mut options = gix_merge::blob::builtin_driver::text::Options::default(); + let marker_size = 7.try_into().unwrap(); for arg in words { options.conflict = match arg { "--diff3" => Conflict::Keep { style: ConflictStyle::Diff3, - marker_size: 7, + marker_size, }, "--zdiff3" => Conflict::Keep { style: ConflictStyle::ZealousDiff3, - marker_size: 7, + marker_size, }, "--ours" => Conflict::ResolveWithOurs, "--theirs" => Conflict::ResolveWithTheirs, diff --git a/gix-merge/tests/merge/blob/platform.rs b/gix-merge/tests/merge/blob/platform.rs index ae264245c5d..6ac8b2b7e0f 100644 --- a/gix-merge/tests/merge/blob/platform.rs +++ b/gix-merge/tests/merge/blob/platform.rs @@ -103,7 +103,7 @@ theirs ); platform_ref.options.text.conflict = builtin_driver::text::Conflict::Keep { style: ConflictStyle::Diff3, - marker_size: 3, + marker_size: 3.try_into().unwrap(), }; let res = platform_ref.merge(&mut buf, default_labels(), &Default::default())?; assert_eq!(res, (Pick::Buffer, Resolution::Conflict)); diff --git a/gix/src/repository/merge.rs b/gix/src/repository/merge.rs index 6b038489b02..10e187ec6cc 100644 --- a/gix/src/repository/merge.rs +++ b/gix/src/repository/merge.rs @@ -74,7 +74,7 @@ impl Repository { }) .transpose()? .unwrap_or_default(), - marker_size: text::Conflict::DEFAULT_MARKER_SIZE, + marker_size: text::Conflict::DEFAULT_MARKER_SIZE.try_into().unwrap(), }, }, }) From 29aad45ec93b19aca6aca06bc525277e0fc0d728 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 25 Oct 2024 10:08:39 +0200 Subject: [PATCH 13/23] feat: `FindExt` now supports empty trees and empty blobs natively. --- gix-object/src/traits.rs | 64 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/gix-object/src/traits.rs b/gix-object/src/traits.rs index b773a5cc8bf..a48ab0e695e 100644 --- a/gix-object/src/traits.rs +++ b/gix-object/src/traits.rs @@ -287,10 +287,70 @@ mod find { .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() }) } + /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error + /// while returning the desired object type. + fn find_blob<'a>( + &self, + id: &gix_hash::oid, + buffer: &'a mut Vec, + ) -> Result, find::existing_object::Error> { + if id == gix_hash::ObjectId::empty_blob(id.kind()) { + return Ok(BlobRef { data: &[] }); + } + self.try_find(id, buffer) + .map_err(find::existing_object::Error::Find)? + .ok_or_else(|| find::existing_object::Error::NotFound { + oid: id.as_ref().to_owned(), + }) + .and_then(|o| { + o.decode().map_err(|err| find::existing_object::Error::Decode { + source: err, + oid: id.as_ref().to_owned(), + }) + }) + .and_then(|o| match o { + ObjectRef::Blob(o) => Ok(o), + o => Err(find::existing_object::Error::ObjectKind { + oid: id.as_ref().to_owned(), + actual: o.kind(), + expected: Kind::Blob, + }), + }) + } + + /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error + /// while returning the desired object type. + fn find_tree<'a>( + &self, + id: &gix_hash::oid, + buffer: &'a mut Vec, + ) -> Result, find::existing_object::Error> { + if id == gix_hash::ObjectId::empty_tree(id.kind()) { + return Ok(TreeRef { entries: Vec::new() }); + } + self.try_find(id, buffer) + .map_err(find::existing_object::Error::Find)? + .ok_or_else(|| find::existing_object::Error::NotFound { + oid: id.as_ref().to_owned(), + }) + .and_then(|o| { + o.decode().map_err(|err| find::existing_object::Error::Decode { + source: err, + oid: id.as_ref().to_owned(), + }) + }) + .and_then(|o| match o { + ObjectRef::Tree(o) => Ok(o), + o => Err(find::existing_object::Error::ObjectKind { + oid: id.as_ref().to_owned(), + actual: o.kind(), + expected: Kind::Tree, + }), + }) + } + make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>); - make_obj_lookup!(find_tree, ObjectRef::Tree, Kind::Tree, TreeRef<'a>); make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>); - make_obj_lookup!(find_blob, ObjectRef::Blob, Kind::Blob, BlobRef<'a>); make_iter_lookup!(find_commit_iter, Kind::Commit, CommitRefIter<'a>, try_into_commit_iter); make_iter_lookup!(find_tree_iter, Kind::Tree, TreeRefIter<'a>, try_into_tree_iter); make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter); From ba7b811bdfc8cba7b3622360749bfc4d927d974c Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 25 Oct 2024 15:32:23 +0200 Subject: [PATCH 14/23] feat: support rename tracking across changed directories --- gix-diff/src/rewrites/mod.rs | 4 + gix-diff/src/rewrites/tracker.rs | 79 +++++++++-- gix-diff/tests/diff/rewrites/tracker.rs | 16 ++- gix-diff/tests/diff/tree_with_rewrites.rs | 131 ++++++++++++++++++ .../make_diff_for_rewrites_repo.tar | Bin 335360 -> 354816 bytes .../fixtures/make_diff_for_rewrites_repo.sh | 12 ++ 6 files changed, 230 insertions(+), 12 deletions(-) diff --git a/gix-diff/src/rewrites/mod.rs b/gix-diff/src/rewrites/mod.rs index 08d6f2cce53..f18052b343b 100644 --- a/gix-diff/src/rewrites/mod.rs +++ b/gix-diff/src/rewrites/mod.rs @@ -1,4 +1,6 @@ +use crate::tree::visit::ChangeId; use crate::Rewrites; +use std::collections::BTreeSet; /// Types related to the rename tracker for renames, rewrites and copies. pub mod tracker; @@ -12,6 +14,8 @@ pub struct Tracker { path_backing: Vec, /// How to track copies and/or rewrites. rewrites: Rewrites, + /// Previously emitted relation ids of rewrite pairs, with `(deleted source, added destination)`. + child_renames: BTreeSet<(ChangeId, ChangeId)>, } /// Determine in which set of files to search for copies. diff --git a/gix-diff/src/rewrites/tracker.rs b/gix-diff/src/rewrites/tracker.rs index 5524c316328..e1416a172f2 100644 --- a/gix-diff/src/rewrites/tracker.rs +++ b/gix-diff/src/rewrites/tracker.rs @@ -10,6 +10,7 @@ use std::ops::Range; use bstr::{BStr, ByteSlice}; use gix_object::tree::{EntryKind, EntryMode}; +use crate::rewrites::tracker::visit::SourceKind; use crate::tree::visit::{Action, ChangeId, Relation}; use crate::{ blob::{platform::prepare_diff::Operation, DiffLineStats, ResourceKind}, @@ -155,6 +156,7 @@ impl Tracker { items: vec![], path_backing: vec![], rewrites, + child_renames: Default::default(), } } } @@ -244,8 +246,9 @@ impl Tracker { }; self.items.sort_by(by_id_and_location); - // Rewrites by directory can be pruned out quickly, quickly pruning candidates - // for the following per-item steps. + // Rewrites by directory (without local changes) can be pruned out quickly, + // by finding only parents, their counterpart, and then all children can be matched by + // relationship ID. self.match_pairs_of_kind( visit::SourceKind::Rename, &mut cb, @@ -266,6 +269,8 @@ impl Tracker { None, )?; + self.match_renamed_directories(&mut cb)?; + if let Some(copies) = self.rewrites.copies { self.match_pairs_of_kind( visit::SourceKind::Copy, @@ -387,6 +392,7 @@ impl Tracker { }) { dest_idx += dest_ofs; dest_ofs = dest_idx + 1; + self.items[dest_idx].location(&self.path_backing); let src = find_match( &self.items, dest, @@ -434,11 +440,17 @@ impl Tracker { return Ok(Action::Cancel); } - if let Some((Relation::Parent(src), Relation::Parent(dst))) = relations { - let res = self.emit_child_renames_matching_identity(cb, kind, src, dst)?; - if res == Action::Cancel { - return Ok(Action::Cancel); + match relations { + Some((Relation::Parent(src), Relation::Parent(dst))) => { + let res = self.emit_child_renames_matching_identity(cb, kind, src, dst)?; + if res == Action::Cancel { + return Ok(Action::Cancel); + } } + Some((Relation::ChildOfParent(src), Relation::ChildOfParent(dst))) => { + self.child_renames.insert((src, dst)); + } + _ => {} } } Ok(Action::Continue) @@ -446,6 +458,7 @@ impl Tracker { /// Emit the children of `src_parent_id` and `dst_parent_id` as pairs of exact matches, which are assumed /// as `src` and `dst` were an exact match (so all children have to match exactly). + /// Note that we intentionally do not record them as their parents will be emitted, too. fn emit_child_renames_matching_identity( &mut self, cb: &mut impl FnMut(visit::Destination<'_, T>, Option>) -> Action, @@ -504,6 +517,56 @@ impl Tracker { } Ok(Action::Continue) } + + /// Find directories with relation id that haven't been emitted yet and store them for lookup. + /// Then use the previously stored emitted renames with relation id to learn which directories they 'link' + /// and emit them, too. + /// Note that this works whenever top-level directories are renamed because they are always added and deleted, + /// and we only match those. Thus, one rewrite inside the directory is enough. + fn match_renamed_directories( + &mut self, + cb: &mut impl FnMut(visit::Destination<'_, T>, Option>) -> Action, + ) -> Result<(), emit::Error> { + fn unemitted_directory_matching_relation_id(items: &[Item], child_id: ChangeId) -> Option { + items.iter().position(|i| { + !i.emitted && matches!(i.change.relation(), Some(Relation::Parent(pid)) if pid == child_id) + }) + } + for (deleted_child_id, added_child_id) in &self.child_renames { + let Some(src_idx) = unemitted_directory_matching_relation_id(&self.items, *deleted_child_id) else { + continue; + }; + let Some(dst_idx) = unemitted_directory_matching_relation_id(&self.items, *added_child_id) else { + // This could go wrong in case there are mismatches, so be defensive here. + // But generally, we'd expect the destination item to exist. + continue; + }; + + let (src_item, dst_item) = (&self.items[src_idx], &self.items[dst_idx]); + let entry_mode = src_item.change.entry_mode(); + let location = src_item.location(&self.path_backing); + let src = visit::Source { + entry_mode, + id: src_item.change.id().to_owned(), + kind: SourceKind::Rename, + location, + change: &src_item.change, + diff: None, + }; + let location = dst_item.location(&self.path_backing); + let change = dst_item.change.clone(); + let dst = visit::Destination { change, location }; + let res = cb(dst, Some(src)); + + self.items[src_idx].emitted = true; + self.items[dst_idx].emitted = true; + + if res == Action::Cancel { + return Ok(()); + } + } + Ok(()) + } } fn filename(path: &BStr) -> &BStr { @@ -572,8 +635,8 @@ fn find_match<'a, T: Change>( let (item_id, item_mode) = item.change.id_and_entry_mode(); if needs_exact_match(percentage) || item_mode.is_link() { let first_idx = items.partition_point(|a| a.change.id() < item_id); - let range = items.get(first_idx..).map(|items| { - let end = items + let range = items.get(first_idx..).map(|slice| { + let end = slice .iter() .position(|a| a.change.id() != item_id) .map_or(items.len(), |idx| first_idx + idx); diff --git a/gix-diff/tests/diff/rewrites/tracker.rs b/gix-diff/tests/diff/rewrites/tracker.rs index 1a6cb56340b..998e9076726 100644 --- a/gix-diff/tests/diff/rewrites/tracker.rs +++ b/gix-diff/tests/diff/rewrites/tracker.rs @@ -588,6 +588,7 @@ fn directory_renames_by_id_can_fail_gracefully() -> crate::Result { (Change::addition(), "b", "firt\nsecond\n"), ], ); + let mut calls = 0; let out = util::assert_emit_with_objects( &mut track, @@ -600,10 +601,17 @@ fn directory_renames_by_id_can_fail_gracefully() -> crate::Result { assert_eq!(src.location, expected_src); assert_eq!(dst.location, expected_dst); } - 3..=6 => { + 3 => { + assert_eq!(src.unwrap().location, "d"); + assert_eq!( + dst.location, "d-renamed", + "it can now track modified and renamed directories" + ); + } + 4 => { assert_eq!(src, None); - let expected_dst = ["d", "d-renamed", "d/subdir/d"][calls - 3]; - assert_eq!(dst.location, expected_dst); + assert_eq!(dst.change.kind, ChangeKind::Deletion); + assert_eq!(dst.location, "d/subdir/d"); } _ => unreachable!("Should have expected emission call {calls}"), } @@ -620,7 +628,7 @@ fn directory_renames_by_id_can_fail_gracefully() -> crate::Result { ..Default::default() } ); - assert_eq!(calls, 6, "Should not have too few calls"); + assert_eq!(calls, 5, "Should not have too few calls"); Ok(()) } diff --git a/gix-diff/tests/diff/tree_with_rewrites.rs b/gix-diff/tests/diff/tree_with_rewrites.rs index f0c137b6abe..5f30c26b8fd 100644 --- a/gix-diff/tests/diff/tree_with_rewrites.rs +++ b/gix-diff/tests/diff/tree_with_rewrites.rs @@ -1904,6 +1904,137 @@ rename to gix-sec/tests/sec.rs Ok(()) } +#[test] +fn realistic_renames_3_without_identity() -> crate::Result { + let (changes, out) = collect_changes_opts( + "r4-base", + "r4-dir-rename-non-identity", + Options { + location: Some(Location::Path), + rewrites: Some(Rewrites { + copies: None, + percentage: None, + limit: 0, + }), + }, + )?; + + // Look how nicely it captures and associates this directory rename. + insta::assert_debug_snapshot!(changes.into_iter() + .filter(|c| !c.entry_mode().is_tree() || + c.relation().map_or(false, |r| matches!(r, Relation::Parent(_))) + ).collect::>(), @r#" + [ + Rewrite { + source_location: "src/plumbing/options.rs", + source_entry_mode: EntryMode( + 33188, + ), + source_relation: Some( + ChildOfParent( + 2, + ), + ), + source_id: Sha1(00750edc07d6415dcc07ae0351e9397b0222b7ba), + diff: None, + entry_mode: EntryMode( + 33188, + ), + id: Sha1(00750edc07d6415dcc07ae0351e9397b0222b7ba), + location: "src/plumbing-renamed/options/mod.rs", + relation: Some( + ChildOfParent( + 1, + ), + ), + copy: false, + }, + Rewrite { + source_location: "src/plumbing/mod.rs", + source_entry_mode: EntryMode( + 33188, + ), + source_relation: Some( + ChildOfParent( + 2, + ), + ), + source_id: Sha1(0cfbf08886fca9a91cb753ec8734c84fcbe52c9f), + diff: None, + entry_mode: EntryMode( + 33188, + ), + id: Sha1(0cfbf08886fca9a91cb753ec8734c84fcbe52c9f), + location: "src/plumbing-renamed/mod.rs", + relation: Some( + ChildOfParent( + 1, + ), + ), + copy: false, + }, + Rewrite { + source_location: "src/plumbing/main.rs", + source_entry_mode: EntryMode( + 33188, + ), + source_relation: Some( + ChildOfParent( + 2, + ), + ), + source_id: Sha1(d00491fd7e5bb6fa28c517a0bb32b8b506539d4d), + diff: None, + entry_mode: EntryMode( + 33188, + ), + id: Sha1(d00491fd7e5bb6fa28c517a0bb32b8b506539d4d), + location: "src/plumbing-renamed/main.rs", + relation: Some( + ChildOfParent( + 1, + ), + ), + copy: false, + }, + Rewrite { + source_location: "src/plumbing", + source_entry_mode: EntryMode( + 16384, + ), + source_relation: Some( + Parent( + 2, + ), + ), + source_id: Sha1(b9d41dcdbd92fcab2fb6594d04f2ad99b3472621), + diff: None, + entry_mode: EntryMode( + 16384, + ), + id: Sha1(202702465d7bb291153629dc2e8b353afe9cbdae), + location: "src/plumbing-renamed", + relation: Some( + Parent( + 1, + ), + ), + copy: false, + }, + ] + "#); + + let out = out.expect("tracking enabled"); + assert_eq!( + out.num_similarity_checks, 0, + "similarity checks disabled, and not necessary" + ); + assert_eq!(out.num_similarity_checks_skipped_for_rename_tracking_due_to_limit, 0); + assert_eq!(out.num_similarity_checks_skipped_for_copy_tracking_due_to_limit, 0); + + Ok(()) +} + mod util { use gix_diff::rewrites; use gix_object::{FindExt, TreeRefIter}; diff --git a/gix-diff/tests/fixtures/generated-archives/make_diff_for_rewrites_repo.tar b/gix-diff/tests/fixtures/generated-archives/make_diff_for_rewrites_repo.tar index ecc1fadbcc9873da647b45261b8693d0d9cd84ae..878a4113ef799f5cc50be490602134493ac692e6 100644 GIT binary patch delta 3639 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 A`2YX_ diff --git a/gix-diff/tests/fixtures/make_diff_for_rewrites_repo.sh b/gix-diff/tests/fixtures/make_diff_for_rewrites_repo.sh index 5d63c067de6..a03188ed553 100644 --- a/gix-diff/tests/fixtures/make_diff_for_rewrites_repo.sh +++ b/gix-diff/tests/fixtures/make_diff_for_rewrites_repo.sh @@ -794,4 +794,16 @@ git -c diff.renames=1 show HEAD~2 > baseline-2.with-renames git -c diff.renames=0 show HEAD~4 > baseline.no-renames git -c diff.renames=1 show HEAD~4 > baseline.with-renames +echo 1 >src/plumbing/main.rs +echo 2 >src/plumbing/mod.rs +echo 3 >src/plumbing/options.rs +git add src/plumbing && git commit -m "r4-base" +store_tree "r4-base" + +mkdir src/plumbing/options +git mv src/plumbing/options.rs src/plumbing/options/mod.rs +git mv src/plumbing src/plumbing-renamed +git commit -m "r4-dir-rename-non-identity" +store_tree "r4-dir-rename-non-identity" + mv ../*.tree . \ No newline at end of file From 1fbb9464d45237c6aa53b98e5a555b774099ad11 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 28 Oct 2024 17:05:58 +0100 Subject: [PATCH 15/23] fix: make sure ordinary capitalized partial names can be found by partial name. For instance, previously, a ref named `A` could not be found even though `refs/heads/A` existed. --- gix-ref/src/name.rs | 13 ++++--- gix-ref/src/store/file/find.rs | 32 +++++++++++++---- gix-ref/src/store/packed/find.rs | 4 +-- gix-ref/tests/Cargo.toml | 2 +- .../make_packed_ref_repository.tar | Bin 71680 -> 69120 bytes ...make_packed_ref_repository_for_overlay.tar | Bin 66560 -> 64000 bytes .../make_ref_repository.tar | Bin 80384 -> 78848 bytes .../fixtures/make_packed_ref_repository.sh | 1 + .../make_packed_ref_repository_for_overlay.sh | 1 + gix-ref/tests/fixtures/make_ref_repository.sh | 1 + gix-ref/tests/{ => refs}/file/log.rs | 0 gix-ref/tests/{ => refs}/file/mod.rs | 0 gix-ref/tests/{ => refs}/file/reference.rs | 0 gix-ref/tests/{ => refs}/file/store/access.rs | 0 gix-ref/tests/{ => refs}/file/store/find.rs | 33 ++++++++++++++---- gix-ref/tests/{ => refs}/file/store/iter.rs | 14 +++++--- gix-ref/tests/{ => refs}/file/store/mod.rs | 0 gix-ref/tests/{ => refs}/file/store/reflog.rs | 0 .../tests/{ => refs}/file/transaction/mod.rs | 0 .../create_or_update/collisions.rs | 0 .../create_or_update/mod.rs | 2 +- .../transaction/prepare_and_commit/delete.rs | 0 gix-ref/tests/{ => refs}/file/worktree.rs | 0 gix-ref/tests/{ => refs}/fullname/mod.rs | 0 gix-ref/tests/{refs.rs => refs/main.rs} | 0 gix-ref/tests/{ => refs}/namespace/mod.rs | 0 gix-ref/tests/{ => refs}/packed/find.rs | 13 +++++++ gix-ref/tests/{ => refs}/packed/iter.rs | 5 +-- gix-ref/tests/{ => refs}/packed/mod.rs | 0 gix-ref/tests/{ => refs}/packed/open.rs | 0 gix-ref/tests/{ => refs}/reference/mod.rs | 0 gix-ref/tests/{ => refs}/store/mod.rs | 0 gix-ref/tests/{ => refs}/transaction/mod.rs | 0 33 files changed, 93 insertions(+), 28 deletions(-) rename gix-ref/tests/{ => refs}/file/log.rs (100%) rename gix-ref/tests/{ => refs}/file/mod.rs (100%) rename gix-ref/tests/{ => refs}/file/reference.rs (100%) rename gix-ref/tests/{ => refs}/file/store/access.rs (100%) rename gix-ref/tests/{ => refs}/file/store/find.rs (87%) rename gix-ref/tests/{ => refs}/file/store/iter.rs (97%) rename gix-ref/tests/{ => refs}/file/store/mod.rs (100%) rename gix-ref/tests/{ => refs}/file/store/reflog.rs (100%) rename gix-ref/tests/{ => refs}/file/transaction/mod.rs (100%) rename gix-ref/tests/{ => refs}/file/transaction/prepare_and_commit/create_or_update/collisions.rs (100%) rename gix-ref/tests/{ => refs}/file/transaction/prepare_and_commit/create_or_update/mod.rs (99%) rename gix-ref/tests/{ => refs}/file/transaction/prepare_and_commit/delete.rs (100%) rename gix-ref/tests/{ => refs}/file/worktree.rs (100%) rename gix-ref/tests/{ => refs}/fullname/mod.rs (100%) rename gix-ref/tests/{refs.rs => refs/main.rs} (100%) rename gix-ref/tests/{ => refs}/namespace/mod.rs (100%) rename gix-ref/tests/{ => refs}/packed/find.rs (95%) rename gix-ref/tests/{ => refs}/packed/iter.rs (97%) rename gix-ref/tests/{ => refs}/packed/mod.rs (100%) rename gix-ref/tests/{ => refs}/packed/open.rs (100%) rename gix-ref/tests/{ => refs}/reference/mod.rs (100%) rename gix-ref/tests/{ => refs}/store/mod.rs (100%) rename gix-ref/tests/{ => refs}/transaction/mod.rs (100%) diff --git a/gix-ref/src/name.rs b/gix-ref/src/name.rs index 27522758af9..4da2a9db9d8 100644 --- a/gix-ref/src/name.rs +++ b/gix-ref/src/name.rs @@ -62,16 +62,21 @@ impl PartialNameRef { } impl PartialNameRef { - pub(crate) fn looks_like_full_name(&self) -> bool { + pub(crate) fn looks_like_full_name(&self, consider_pseudo_ref: bool) -> bool { let name = self.0.as_bstr(); name.starts_with_str("refs/") || name.starts_with(Category::MainPseudoRef.prefix()) || name.starts_with(Category::LinkedPseudoRef { name: "".into() }.prefix()) - || is_pseudo_ref(name) + || (consider_pseudo_ref && is_pseudo_ref(name)) } - pub(crate) fn construct_full_name_ref<'buf>(&self, inbetween: &str, buf: &'buf mut BString) -> &'buf FullNameRef { + pub(crate) fn construct_full_name_ref<'buf>( + &self, + inbetween: &str, + buf: &'buf mut BString, + consider_pseudo_ref: bool, + ) -> &'buf FullNameRef { buf.clear(); - if !self.looks_like_full_name() { + if !self.looks_like_full_name(consider_pseudo_ref) { buf.push_str("refs/"); } if !inbetween.is_empty() { diff --git a/gix-ref/src/store/file/find.rs b/gix-ref/src/store/file/find.rs index 9842de1d852..439c356b465 100644 --- a/gix-ref/src/store/file/find.rs +++ b/gix-ref/src/store/file/find.rs @@ -6,6 +6,7 @@ use std::{ pub use error::Error; +use crate::name::is_pseudo_ref; use crate::{ file, store_impl::{file::loose, packed}, @@ -103,13 +104,28 @@ impl file::Store { let precomposed_partial_name = precomposed_partial_name_storage .as_ref() .map(std::convert::AsRef::as_ref); - for inbetween in &["", "tags", "heads", "remotes"] { - match self.find_inner(inbetween, partial_name, precomposed_partial_name, packed, &mut buf) { - Ok(Some(r)) => return Ok(Some(decompose_if(r, precomposed_partial_name.is_some()))), - Ok(None) => { - continue; + for consider_pseudo_ref in [true, false] { + if !consider_pseudo_ref && !is_pseudo_ref(partial_name.as_bstr()) { + break; + } + 'try_directories: for inbetween in &["", "tags", "heads", "remotes"] { + match self.find_inner( + inbetween, + partial_name, + precomposed_partial_name, + packed, + &mut buf, + consider_pseudo_ref, + ) { + Ok(Some(r)) => return Ok(Some(decompose_if(r, precomposed_partial_name.is_some()))), + Ok(None) => { + if consider_pseudo_ref && is_pseudo_ref(partial_name.as_bstr()) { + break 'try_directories; + } + continue; + } + Err(err) => return Err(err), } - Err(err) => return Err(err), } } if partial_name.as_bstr() != "HEAD" { @@ -129,6 +145,7 @@ impl file::Store { .map(std::convert::AsRef::as_ref), None, &mut buf, + true, /* consider-pseudo-ref */ ) .map(|res| res.map(|r| decompose_if(r, precomposed_partial_name_storage.is_some()))) } else { @@ -143,10 +160,11 @@ impl file::Store { precomposed_partial_name: Option<&PartialNameRef>, packed: Option<&packed::Buffer>, path_buf: &mut BString, + consider_pseudo_ref: bool, ) -> Result, Error> { let full_name = precomposed_partial_name .unwrap_or(partial_name) - .construct_full_name_ref(inbetween, path_buf); + .construct_full_name_ref(inbetween, path_buf, consider_pseudo_ref); let content_buf = self.ref_contents(full_name).map_err(|err| Error::ReadFileContents { source: err, path: self.reference_path(full_name), diff --git a/gix-ref/src/store/packed/find.rs b/gix-ref/src/store/packed/find.rs index 59988c4069b..a172ab61032 100644 --- a/gix-ref/src/store/packed/find.rs +++ b/gix-ref/src/store/packed/find.rs @@ -17,7 +17,7 @@ impl packed::Buffer { let name = name.try_into()?; let mut buf = BString::default(); for inbetween in &["", "tags", "heads", "remotes"] { - let (name, was_absolute) = if name.looks_like_full_name() { + let (name, was_absolute) = if name.looks_like_full_name(false) { let name = FullNameRef::new_unchecked(name.as_bstr()); let name = match transform_full_name_for_lookup(name) { None => return Ok(None), @@ -25,7 +25,7 @@ impl packed::Buffer { }; (name, true) } else { - let full_name = name.construct_full_name_ref(inbetween, &mut buf); + let full_name = name.construct_full_name_ref(inbetween, &mut buf, false); (full_name, false) }; match self.try_find_full_name(name)? { diff --git a/gix-ref/tests/Cargo.toml b/gix-ref/tests/Cargo.toml index 31864c6cbeb..1f6ec8940e7 100644 --- a/gix-ref/tests/Cargo.toml +++ b/gix-ref/tests/Cargo.toml @@ -17,7 +17,7 @@ serde = ["gix-ref/serde"] [[test]] name = "refs" -path = "refs.rs" +path = "refs/main.rs" [dev-dependencies] gix-ref = { path = ".." } diff --git a/gix-ref/tests/fixtures/generated-archives/make_packed_ref_repository.tar b/gix-ref/tests/fixtures/generated-archives/make_packed_ref_repository.tar index 9c2bc2ea2b93521df92ec811ce79de0d8ae2b892..87d999da6baf14cf49b925aa782da9ab91baec61 100644 GIT binary patch delta 485 zcmZqJz|t^>WdkeAVpctt$*e5(l7=Q`42A|KW`+hv21dpP3%@ zZ7CNc%Vw@WAQ>-qrp-Kc|9Lla?_m+z%)jLi`)2NQj4X?J=CN$%x%8iTGxr)6j?Mf% ze^?iDCy8z5zV?fGGV7uS2~%TqH<_520Nn<0)8Yu$&G9Q1GEY=s+vLLy)K>9}busHb zpra&MnKpCDadR*_P89T;B*QW}L(PEI(8vU)Q=Nr+*wjGpiE^(_&s5w#~dIKiDU;-l~^0GBiYY1~6=lVTRp~X4K)#OwY?NN=;5IPF1i~ zC@CsU<>D*=^7C^G@{3bT^D>k3Q(!Wi9nVxSZsTGUV%jbw!1$h#&&&ekD z?Sf1|!Ri0F8QZ6~vM>sGa#9uCGfQ+0O-(d6E55kT PxLtvX@d1>as9+BO#Ve2T delta 2679 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 U@JxC+oWunoq`!{;U5C?u0h3Z!wEzGB diff --git a/gix-ref/tests/fixtures/generated-archives/make_ref_repository.tar b/gix-ref/tests/fixtures/generated-archives/make_ref_repository.tar index ae58c4f1ab52b7b7fcbe22f426ebe16d958980ba..d239944d93b322409ffb999e9fdb8604a9522f49 100644 GIT binary patch delta 463 zcmXw!ziSjx5XUpSZ+7?I-nz*Vf&>X`ig1Dac)R!RLJETiqK%}s5G3RlJxFp(en3c* zYZ9!4%R;gS26705s7+2no%rt;4jZf%I% z&mA+xm(A;Xawuda6p@HZqECoWN~!g7+p7mikKVj6TY+^v?`mwTg9^XvM~2ZL9=Hxv zTLbfZBP@MV6c|SGiX3M)VNw6WZ*)zCj1x-7An$G)3GXI0e5X zDxxCgY$PXj=O%@n56}um_orazU}p>pmYkXSe_{sH;K5*NcB&i{t4XpH2lwjhlVMqo S)6LUwK({;ZE<>8w+kXMWY>!3& delta 2672 zcmb_ePi)&%7@wQCYhT-?OxrYuG(Fs?O{6-F(`+3TLoI6Ue`xB=q82+|I4*`mP}&4(cVNWg(BaOZ$Hpq)4kY1)Ry_iQIi+Kqukq&Bgi-|zc< zzwh^beiv^fFWyXk&L^+&9BT2&p%y=$4EW#qfdJjTlL+`5<3qvTTYn}3bn{N4#g8W2 zJmQ81+G7W}TRYqQ9&Tvxv$5SA+!*C<@d1Bk=Rh#}!@a$&k*oWHkza1Ztv3dDwMIS} z+~p8MCF?TP#SK}f%`xM|hkqn5)t@*}EarFzX(xJh*#n}*)NN}VWc04zu7A@vL+s>lYQGcr0QDm;u`)54|(V2nnLhCR!1 zZ6X5`TQ+=1dy~3#({r(68k$ZO*TK{PO&kI@RM~FeP19b3EhL8*HJ8|c$HWG%6k=o? zPf>{DXddvhv0=Jdh#5xIWyg)hggXq8DLNgl#h5-5Hp~r}t3)R*QKS4TKv^?&-P~k) zF>bU5aY5v>I&nJ5Is{ZOK@-`ik-ju-vTm~48Y)DHFKohyfpD@-u;+kCK5S-!HNw52 zmH;l-WNJ9>d{_t^7Cx+YF3y{jBk)YD={#gkYt+a>sE0pZhUoWqJYQN|$|9eYx=bux zRwDY9m8BINUe--rCAJfmr`KVT0f3~Un09DL$f03+tS$y2s*^*g!?UWG8^o@HtWYKNButs%qR7gt#8lJ#Di#Ok8z^w3~SQ(P5<*;KBFk$FFs7W@5hF#ku=&hc3aU*RH zR5Bb7MDMpPmi^GIQIdTg1n?Tz9&9SkVj;~)3;4nXsHE%J2BZG(m_zSEQ0hcJWc#9A z!YnM=hrZ8Q`U7)`>>8`~-{KLx3FRZPPw|lOQjbVmrquoTRvH;9$R_&RHalF@KG!w zm>ZyV)ICSj8CH?F6GgEzPa^9B!5Z{pcbsi$l`Ni|WI);$6u%3@`r#2E&_EGRXCMLC z`kG7DE!gO;TPn4&sNUxgz7yC;&8gemn&Vn>ZE%Frg;l{g)b(O!HX5#1qZxD#-TJP*;dgOo)YWlaHHO_aKc zg>KMp>hqY`wrS5}4PKHk@L*QJyUAh$kj3=bTo>>&lLde{55h>Sojrri)#J;R>e6yK z{64)>K2fcdOC_YJz5JO5%uqGJ#Ns(DoKdN!u{r`4sK>@kWTNg!ibh1ZLUeflq2caQ z-?R#!fc)YJUCaKHW0|G5tyfkmizhoY`s(EwYmn%p%Eg@P+OmbGdYu!#Q#J^AN9z@2 z3YS)wE1@;IX+?tsHGlqirn#{2)Ajd9lg-hu8~YDSTTdv(;_O`Kg!0WQKPXZ--kc9! z{r*bg`bVjuAa(KX&S1ny?haD#{FMksKe(3&M!vY6xXcTj|F|@}?Z_h)q!_TxO>nPs z?RV4MCU*&o*MH;TOty!e$(|lW!T71$i57Yx*+S)HfO2pnPH?ZlZM5%BVu+m~pl_V!m4VZ6@@m#|dHxXOaEP6<+T0X3&b1$#eCE2kdmY$(rh9BRAEl^40=A07JlS{g@tdU Jf1u~pzX2pYT{-{& diff --git a/gix-ref/tests/fixtures/make_packed_ref_repository.sh b/gix-ref/tests/fixtures/make_packed_ref_repository.sh index daea997523b..3a81139d5aa 100755 --- a/gix-ref/tests/fixtures/make_packed_ref_repository.sh +++ b/gix-ref/tests/fixtures/make_packed_ref_repository.sh @@ -7,6 +7,7 @@ git checkout -q -b main git commit -q --allow-empty -m c1 git branch dt1 git branch d1 +git branch A mkdir -p .git/refs/remotes/origin diff --git a/gix-ref/tests/fixtures/make_packed_ref_repository_for_overlay.sh b/gix-ref/tests/fixtures/make_packed_ref_repository_for_overlay.sh index 9410375c73d..03574b865ae 100755 --- a/gix-ref/tests/fixtures/make_packed_ref_repository_for_overlay.sh +++ b/gix-ref/tests/fixtures/make_packed_ref_repository_for_overlay.sh @@ -6,6 +6,7 @@ git init -q git checkout -q -b main git commit -q --allow-empty -m c1 git branch newer-as-loose +git branch A git tag -m "tag object" tag-object mkdir -p .git/refs/remotes/origin diff --git a/gix-ref/tests/fixtures/make_ref_repository.sh b/gix-ref/tests/fixtures/make_ref_repository.sh index 7288ffe59f0..38080cddfca 100755 --- a/gix-ref/tests/fixtures/make_ref_repository.sh +++ b/gix-ref/tests/fixtures/make_ref_repository.sh @@ -7,6 +7,7 @@ git checkout -q -b main git commit -q --allow-empty -m c1 git branch dt1 git branch d1 +git branch A mkdir -p .git/refs/remotes/origin diff --git a/gix-ref/tests/file/log.rs b/gix-ref/tests/refs/file/log.rs similarity index 100% rename from gix-ref/tests/file/log.rs rename to gix-ref/tests/refs/file/log.rs diff --git a/gix-ref/tests/file/mod.rs b/gix-ref/tests/refs/file/mod.rs similarity index 100% rename from gix-ref/tests/file/mod.rs rename to gix-ref/tests/refs/file/mod.rs diff --git a/gix-ref/tests/file/reference.rs b/gix-ref/tests/refs/file/reference.rs similarity index 100% rename from gix-ref/tests/file/reference.rs rename to gix-ref/tests/refs/file/reference.rs diff --git a/gix-ref/tests/file/store/access.rs b/gix-ref/tests/refs/file/store/access.rs similarity index 100% rename from gix-ref/tests/file/store/access.rs rename to gix-ref/tests/refs/file/store/access.rs diff --git a/gix-ref/tests/file/store/find.rs b/gix-ref/tests/refs/file/store/find.rs similarity index 87% rename from gix-ref/tests/file/store/find.rs rename to gix-ref/tests/refs/file/store/find.rs index d4eb8dd0e88..f9cb0a26489 100644 --- a/gix-ref/tests/file/store/find.rs +++ b/gix-ref/tests/refs/file/store/find.rs @@ -2,12 +2,22 @@ mod existing { use crate::{file::store_at, hex_to_id}; #[test] - fn with_packed_refs() -> crate::Result { - let store = store_at("make_packed_ref_repository_for_overlay.sh")?; - let c1 = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03"); - let r = store.find("main")?; - assert_eq!(r.target.into_id(), c1); - assert_eq!(r.name.as_bstr(), "refs/heads/main"); + fn various_repositories() -> crate::Result { + for fixture in [ + "make_ref_repository.sh", + "make_packed_ref_repository.sh", + "make_packed_ref_repository_for_overlay.sh", + ] { + let store = store_at(fixture)?; + let c1 = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03"); + let r = store.find("main")?; + assert_eq!(r.target.into_id(), c1); + assert_eq!(r.name.as_bstr(), "refs/heads/main"); + let r = store + .find("A") + .unwrap_or_else(|_| panic!("{fixture}: should find capitalized refs")); + assert_eq!(r.target.into_id(), c1); + } Ok(()) } @@ -98,6 +108,17 @@ mod loose { use crate::file::store; + #[test] + fn capitalized_branch() -> crate::Result { + let store = store()?; + assert_eq!( + store.find("A")?.name.as_bstr(), + "refs/heads/A", + "capitalized loose refs can be found fine" + ); + Ok(()) + } + #[test] fn success_and_failure() -> crate::Result { let store = store()?; diff --git a/gix-ref/tests/file/store/iter.rs b/gix-ref/tests/refs/file/store/iter.rs similarity index 97% rename from gix-ref/tests/file/store/iter.rs rename to gix-ref/tests/refs/file/store/iter.rs index 900a15d56f0..046bdbc58b1 100644 --- a/gix-ref/tests/file/store/iter.rs +++ b/gix-ref/tests/refs/file/store/iter.rs @@ -253,7 +253,7 @@ fn no_packed_available_thus_no_iteration_possible() -> crate::Result { #[test] fn packed_file_iter() -> crate::Result { let store = store_with_packed_refs()?; - assert_eq!(store.open_packed_buffer()?.expect("pack available").iter()?.count(), 8); + assert_eq!(store.open_packed_buffer()?.expect("pack available").iter()?.count(), 9); Ok(()) } @@ -262,7 +262,7 @@ fn loose_iter_with_broken_refs() -> crate::Result { let store = store()?; let mut actual: Vec<_> = store.loose_iter()?.collect(); - assert_eq!(actual.len(), 15); + assert_eq!(actual.len(), 16); actual.sort_by_key(Result::is_err); let first_error = actual .iter() @@ -271,7 +271,7 @@ fn loose_iter_with_broken_refs() -> crate::Result { .expect("there is an error"); assert_eq!( - first_error, 14, + first_error, 15, "there is exactly one invalid item, and it didn't abort the iterator most importantly" ); #[cfg(not(windows))] @@ -291,6 +291,7 @@ fn loose_iter_with_broken_refs() -> crate::Result { ref_paths, vec![ "d1", + "heads/A", "heads/d1", "heads/dt1", "heads/main", @@ -343,6 +344,7 @@ fn loose_iter_with_prefix() -> crate::Result { assert_eq!( actual, vec![ + "refs/heads/A", "refs/heads/d1", "refs/heads/dt1", "refs/heads/main", @@ -394,7 +396,8 @@ fn overlay_iter() -> crate::Result { assert_eq!( ref_names, vec![ - (b"refs/heads/main".as_bstr().to_owned(), Object(c1)), + (b"refs/heads/A".as_bstr().to_owned(), Object(c1)), + (b"refs/heads/main".into(), Object(c1)), ("refs/heads/newer-as-loose".into(), Object(c2)), ( "refs/remotes/origin/HEAD".into(), @@ -440,7 +443,8 @@ fn overlay_prefixed_iter() -> crate::Result { assert_eq!( ref_names, vec![ - (b"refs/heads/main".as_bstr().to_owned(), Object(c1)), + (b"refs/heads/A".as_bstr().to_owned(), Object(c1)), + (b"refs/heads/main".into(), Object(c1)), ("refs/heads/newer-as-loose".into(), Object(c2)), ] ); diff --git a/gix-ref/tests/file/store/mod.rs b/gix-ref/tests/refs/file/store/mod.rs similarity index 100% rename from gix-ref/tests/file/store/mod.rs rename to gix-ref/tests/refs/file/store/mod.rs diff --git a/gix-ref/tests/file/store/reflog.rs b/gix-ref/tests/refs/file/store/reflog.rs similarity index 100% rename from gix-ref/tests/file/store/reflog.rs rename to gix-ref/tests/refs/file/store/reflog.rs diff --git a/gix-ref/tests/file/transaction/mod.rs b/gix-ref/tests/refs/file/transaction/mod.rs similarity index 100% rename from gix-ref/tests/file/transaction/mod.rs rename to gix-ref/tests/refs/file/transaction/mod.rs diff --git a/gix-ref/tests/file/transaction/prepare_and_commit/create_or_update/collisions.rs b/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/collisions.rs similarity index 100% rename from gix-ref/tests/file/transaction/prepare_and_commit/create_or_update/collisions.rs rename to gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/collisions.rs diff --git a/gix-ref/tests/file/transaction/prepare_and_commit/create_or_update/mod.rs b/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/mod.rs similarity index 99% rename from gix-ref/tests/file/transaction/prepare_and_commit/create_or_update/mod.rs rename to gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/mod.rs index dbdb5e4035c..f90d8cf03c4 100644 --- a/gix-ref/tests/file/transaction/prepare_and_commit/create_or_update/mod.rs +++ b/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/mod.rs @@ -791,7 +791,7 @@ fn packed_refs_creation_with_packed_refs_mode_prune_removes_original_loose_refs( assert_eq!( edits.len(), - 8, + 9, "there are a certain amount of loose refs that are packed" ); diff --git a/gix-ref/tests/file/transaction/prepare_and_commit/delete.rs b/gix-ref/tests/refs/file/transaction/prepare_and_commit/delete.rs similarity index 100% rename from gix-ref/tests/file/transaction/prepare_and_commit/delete.rs rename to gix-ref/tests/refs/file/transaction/prepare_and_commit/delete.rs diff --git a/gix-ref/tests/file/worktree.rs b/gix-ref/tests/refs/file/worktree.rs similarity index 100% rename from gix-ref/tests/file/worktree.rs rename to gix-ref/tests/refs/file/worktree.rs diff --git a/gix-ref/tests/fullname/mod.rs b/gix-ref/tests/refs/fullname/mod.rs similarity index 100% rename from gix-ref/tests/fullname/mod.rs rename to gix-ref/tests/refs/fullname/mod.rs diff --git a/gix-ref/tests/refs.rs b/gix-ref/tests/refs/main.rs similarity index 100% rename from gix-ref/tests/refs.rs rename to gix-ref/tests/refs/main.rs diff --git a/gix-ref/tests/namespace/mod.rs b/gix-ref/tests/refs/namespace/mod.rs similarity index 100% rename from gix-ref/tests/namespace/mod.rs rename to gix-ref/tests/refs/namespace/mod.rs diff --git a/gix-ref/tests/packed/find.rs b/gix-ref/tests/refs/packed/find.rs similarity index 95% rename from gix-ref/tests/packed/find.rs rename to gix-ref/tests/refs/packed/find.rs index 9cc6753c6c4..20fb3f9a444 100644 --- a/gix-ref/tests/packed/find.rs +++ b/gix-ref/tests/refs/packed/find.rs @@ -14,6 +14,19 @@ fn a_lock_file_would_not_be_a_valid_partial_name() { assert_eq!(err.to_string(), "A reference must be a valid tag name as well"); } +#[test] +fn capitalized_branch() -> crate::Result { + let store = store_with_packed_refs()?; + let packed_refs = store.open_packed_buffer()?.expect("packed-refs exist"); + + assert_eq!( + packed_refs.find("A")?.name.as_bstr(), + "refs/heads/A", + "fully capitalized refs aren't just considered pseudorefs" + ); + Ok(()) +} + #[test] fn all_iterable_refs_can_be_found() -> crate::Result { let store = store_with_packed_refs()?; diff --git a/gix-ref/tests/packed/iter.rs b/gix-ref/tests/refs/packed/iter.rs similarity index 97% rename from gix-ref/tests/packed/iter.rs rename to gix-ref/tests/refs/packed/iter.rs index 28d15ab1ca3..b22c7c7adba 100644 --- a/gix-ref/tests/packed/iter.rs +++ b/gix-ref/tests/refs/packed/iter.rs @@ -18,7 +18,7 @@ fn packed_refs_with_header() -> crate::Result { let dir = gix_testtools::scripted_fixture_read_only_standalone("make_packed_ref_repository.sh")?; let buf = std::fs::read(dir.join(".git").join("packed-refs"))?; let iter = packed::Iter::new(&buf)?; - assert_eq!(iter.count(), 8, "it finds the right amount of items"); + assert_eq!(iter.count(), 9, "it finds the right amount of items"); Ok(()) } @@ -31,7 +31,8 @@ fn iter_prefix() -> crate::Result { .map(|r| r.map(|r| r.name.as_bstr())) .collect::, _>>()?, vec![ - "refs/heads/d1".as_bytes().as_bstr(), + "refs/heads/A".as_bytes().as_bstr(), + "refs/heads/d1".into(), "refs/heads/dt1".into(), "refs/heads/main".into() ] diff --git a/gix-ref/tests/packed/mod.rs b/gix-ref/tests/refs/packed/mod.rs similarity index 100% rename from gix-ref/tests/packed/mod.rs rename to gix-ref/tests/refs/packed/mod.rs diff --git a/gix-ref/tests/packed/open.rs b/gix-ref/tests/refs/packed/open.rs similarity index 100% rename from gix-ref/tests/packed/open.rs rename to gix-ref/tests/refs/packed/open.rs diff --git a/gix-ref/tests/reference/mod.rs b/gix-ref/tests/refs/reference/mod.rs similarity index 100% rename from gix-ref/tests/reference/mod.rs rename to gix-ref/tests/refs/reference/mod.rs diff --git a/gix-ref/tests/store/mod.rs b/gix-ref/tests/refs/store/mod.rs similarity index 100% rename from gix-ref/tests/store/mod.rs rename to gix-ref/tests/refs/store/mod.rs diff --git a/gix-ref/tests/transaction/mod.rs b/gix-ref/tests/refs/transaction/mod.rs similarity index 100% rename from gix-ref/tests/transaction/mod.rs rename to gix-ref/tests/refs/transaction/mod.rs From 7325c584c3f0973975935b307630e29bc36ef5c7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 31 Oct 2024 18:53:45 +0100 Subject: [PATCH 16/23] feat!: move `gix-odb::Write` trait to `gix-object::Write`. There it's far more useful and plumbing crates are enabled to write objects without pulling in `gix-odb` as dependency. --- gix-object/src/lib.rs | 8 +- gix-object/src/traits.rs | 363 ----------------------- gix-object/src/traits/_impls.rs | 74 +++++ gix-object/src/traits/find.rs | 310 +++++++++++++++++++ gix-object/src/traits/mod.rs | 54 ++++ gix-odb/src/cache.rs | 11 +- gix-odb/src/lib.rs | 8 +- gix-odb/src/memory.rs | 6 +- gix-odb/src/sink.rs | 4 +- gix-odb/src/store_impls/dynamic/write.rs | 4 +- gix-odb/src/store_impls/loose/verify.rs | 3 +- gix-odb/src/store_impls/loose/write.rs | 8 +- gix-odb/src/traits.rs | 83 +----- gix-odb/tests/odb/memory.rs | 2 +- gix-odb/tests/odb/sink/mod.rs | 2 +- gix-odb/tests/odb/store/dynamic.rs | 4 +- gix-odb/tests/odb/store/loose.rs | 3 +- 17 files changed, 475 insertions(+), 472 deletions(-) delete mode 100644 gix-object/src/traits.rs create mode 100644 gix-object/src/traits/_impls.rs create mode 100644 gix-object/src/traits/find.rs create mode 100644 gix-object/src/traits/mod.rs diff --git a/gix-object/src/lib.rs b/gix-object/src/lib.rs index 0ef56d52954..8c94f9e6bf9 100644 --- a/gix-object/src/lib.rs +++ b/gix-object/src/lib.rs @@ -33,8 +33,14 @@ pub mod data; /// pub mod find; +/// +pub mod write { + /// The error type returned by the [`Write`](crate::Write) trait. + pub type Error = Box; +} + mod traits; -pub use traits::{Exists, Find, FindExt, FindObjectOrHeader, Header as FindHeader, HeaderExt, WriteTo}; +pub use traits::{Exists, Find, FindExt, FindObjectOrHeader, Header as FindHeader, HeaderExt, Write, WriteTo}; pub mod encode; pub(crate) mod parse; diff --git a/gix-object/src/traits.rs b/gix-object/src/traits.rs deleted file mode 100644 index a48ab0e695e..00000000000 --- a/gix-object/src/traits.rs +++ /dev/null @@ -1,363 +0,0 @@ -use std::io::Write; - -use crate::Kind; - -/// Writing of objects to a `Write` implementation -pub trait WriteTo { - /// Write a representation of this instance to `out`. - fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()>; - - /// Returns the type of this object. - fn kind(&self) -> Kind; - - /// Returns the size of this object's representation (the amount - /// of data which would be written by [`write_to`](Self::write_to)). - /// - /// [`size`](Self::size)'s value has no bearing on the validity of - /// the object, as such it's possible for [`size`](Self::size) to - /// return a sensible value but [`write_to`](Self::write_to) to - /// fail because the object was not actually valid in some way. - fn size(&self) -> u64; - - /// Returns a loose object header based on the object's data - fn loose_header(&self) -> smallvec::SmallVec<[u8; 28]> { - crate::encode::loose_header(self.kind(), self.size()) - } -} - -impl WriteTo for &T -where - T: WriteTo, -{ - fn write_to(&self, out: &mut dyn Write) -> std::io::Result<()> { - ::write_to(self, out) - } - - fn kind(&self) -> Kind { - ::kind(self) - } - - fn size(&self) -> u64 { - ::size(self) - } -} - -mod find { - use crate::find; - - /// Check if an object is present in an object store. - pub trait Exists { - /// Returns `true` if the object exists in the database. - fn exists(&self, id: &gix_hash::oid) -> bool; - } - - /// Find an object in the object store. - /// - /// ## Notes - /// - /// Find effectively needs [generic associated types][issue] to allow a trait for the returned object type. - /// Until then, we will have to make due with explicit types and give them the potentially added features we want. - /// - /// [issue]: https://github.com/rust-lang/rust/issues/44265 - pub trait Find { - /// Find an object matching `id` in the database while placing its raw, possibly encoded data into `buffer`. - /// - /// Returns `Some` object if it was present in the database, or the error that occurred during lookup or object - /// retrieval. - fn try_find<'a>( - &self, - id: &gix_hash::oid, - buffer: &'a mut Vec, - ) -> Result>, find::Error>; - } - - /// Find the header of an object in the object store. - pub trait Header { - /// Find the header of the object matching `id` in the database. - /// - /// Returns `Some` header if it was present, or the error that occurred during lookup. - fn try_header(&self, id: &gix_hash::oid) -> Result, find::Error>; - } - - /// A combination of [`Find`] and [`Header`] traits to help with `dyn` trait objects. - pub trait FindObjectOrHeader: Find + Header {} - - mod _impls { - use std::{ops::Deref, rc::Rc, sync::Arc}; - - use gix_hash::oid; - - use crate::Data; - - impl crate::Exists for &T - where - T: crate::Exists, - { - fn exists(&self, id: &oid) -> bool { - (*self).exists(id) - } - } - - impl crate::FindObjectOrHeader for T where T: crate::Find + crate::FindHeader {} - - impl crate::Find for &T - where - T: crate::Find, - { - fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec) -> Result>, crate::find::Error> { - (*self).try_find(id, buffer) - } - } - - impl crate::FindHeader for &T - where - T: crate::FindHeader, - { - fn try_header(&self, id: &gix_hash::oid) -> Result, crate::find::Error> { - (*self).try_header(id) - } - } - - impl crate::Exists for Box - where - T: crate::Exists, - { - fn exists(&self, id: &oid) -> bool { - self.deref().exists(id) - } - } - - impl crate::Exists for Rc - where - T: crate::Exists, - { - fn exists(&self, id: &oid) -> bool { - self.deref().exists(id) - } - } - - impl crate::Find for Rc - where - T: crate::Find, - { - fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec) -> Result>, crate::find::Error> { - self.deref().try_find(id, buffer) - } - } - - impl crate::FindHeader for Rc - where - T: crate::FindHeader, - { - fn try_header(&self, id: &gix_hash::oid) -> Result, crate::find::Error> { - self.deref().try_header(id) - } - } - - impl crate::Find for Box - where - T: crate::Find, - { - fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec) -> Result>, crate::find::Error> { - self.deref().try_find(id, buffer) - } - } - - impl crate::FindHeader for Box - where - T: crate::FindHeader, - { - fn try_header(&self, id: &gix_hash::oid) -> Result, crate::find::Error> { - self.deref().try_header(id) - } - } - - impl crate::Exists for Arc - where - T: crate::Exists, - { - fn exists(&self, id: &oid) -> bool { - self.deref().exists(id) - } - } - - impl crate::Find for Arc - where - T: crate::Find, - { - fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec) -> Result>, crate::find::Error> { - self.deref().try_find(id, buffer) - } - } - - impl crate::FindHeader for Arc - where - T: crate::FindHeader, - { - fn try_header(&self, id: &gix_hash::oid) -> Result, crate::find::Error> { - self.deref().try_header(id) - } - } - } - - mod ext { - use crate::{ - find, BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter, - }; - - macro_rules! make_obj_lookup { - ($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => { - /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error - /// while returning the desired object type. - fn $method<'a>( - &self, - id: &gix_hash::oid, - buffer: &'a mut Vec, - ) -> Result<$object_type, find::existing_object::Error> { - self.try_find(id, buffer) - .map_err(find::existing_object::Error::Find)? - .ok_or_else(|| find::existing_object::Error::NotFound { - oid: id.as_ref().to_owned(), - }) - .and_then(|o| { - o.decode() - .map_err(|err| find::existing_object::Error::Decode { - source: err, - oid: id.as_ref().to_owned(), - }) - }) - .and_then(|o| match o { - $object_variant(o) => return Ok(o), - o => Err(find::existing_object::Error::ObjectKind { - oid: id.as_ref().to_owned(), - actual: o.kind(), - expected: $object_kind, - }), - }) - } - }; - } - - macro_rules! make_iter_lookup { - ($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => { - /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error - /// while returning the desired iterator type. - fn $method<'a>( - &self, - id: &gix_hash::oid, - buffer: &'a mut Vec, - ) -> Result<$object_type, find::existing_iter::Error> { - self.try_find(id, buffer) - .map_err(find::existing_iter::Error::Find)? - .ok_or_else(|| find::existing_iter::Error::NotFound { - oid: id.as_ref().to_owned(), - }) - .and_then(|o| { - o.$into_iter() - .ok_or_else(|| find::existing_iter::Error::ObjectKind { - oid: id.as_ref().to_owned(), - actual: o.kind, - expected: $object_kind, - }) - }) - } - }; - } - - /// An extension trait with convenience functions. - pub trait HeaderExt: super::Header { - /// Like [`try_header(…)`](super::Header::try_header()), but flattens the `Result>` into a single `Result` making a non-existing header an error. - fn header(&self, id: &gix_hash::oid) -> Result { - self.try_header(id) - .map_err(find::existing::Error::Find)? - .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() }) - } - } - - /// An extension trait with convenience functions. - pub trait FindExt: super::Find { - /// Like [`try_find(…)`](super::Find::try_find()), but flattens the `Result>` into a single `Result` making a non-existing object an error. - fn find<'a>( - &self, - id: &gix_hash::oid, - buffer: &'a mut Vec, - ) -> Result, find::existing::Error> { - self.try_find(id, buffer) - .map_err(find::existing::Error::Find)? - .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() }) - } - - /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error - /// while returning the desired object type. - fn find_blob<'a>( - &self, - id: &gix_hash::oid, - buffer: &'a mut Vec, - ) -> Result, find::existing_object::Error> { - if id == gix_hash::ObjectId::empty_blob(id.kind()) { - return Ok(BlobRef { data: &[] }); - } - self.try_find(id, buffer) - .map_err(find::existing_object::Error::Find)? - .ok_or_else(|| find::existing_object::Error::NotFound { - oid: id.as_ref().to_owned(), - }) - .and_then(|o| { - o.decode().map_err(|err| find::existing_object::Error::Decode { - source: err, - oid: id.as_ref().to_owned(), - }) - }) - .and_then(|o| match o { - ObjectRef::Blob(o) => Ok(o), - o => Err(find::existing_object::Error::ObjectKind { - oid: id.as_ref().to_owned(), - actual: o.kind(), - expected: Kind::Blob, - }), - }) - } - - /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error - /// while returning the desired object type. - fn find_tree<'a>( - &self, - id: &gix_hash::oid, - buffer: &'a mut Vec, - ) -> Result, find::existing_object::Error> { - if id == gix_hash::ObjectId::empty_tree(id.kind()) { - return Ok(TreeRef { entries: Vec::new() }); - } - self.try_find(id, buffer) - .map_err(find::existing_object::Error::Find)? - .ok_or_else(|| find::existing_object::Error::NotFound { - oid: id.as_ref().to_owned(), - }) - .and_then(|o| { - o.decode().map_err(|err| find::existing_object::Error::Decode { - source: err, - oid: id.as_ref().to_owned(), - }) - }) - .and_then(|o| match o { - ObjectRef::Tree(o) => Ok(o), - o => Err(find::existing_object::Error::ObjectKind { - oid: id.as_ref().to_owned(), - actual: o.kind(), - expected: Kind::Tree, - }), - }) - } - - make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>); - make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>); - make_iter_lookup!(find_commit_iter, Kind::Commit, CommitRefIter<'a>, try_into_commit_iter); - make_iter_lookup!(find_tree_iter, Kind::Tree, TreeRefIter<'a>, try_into_tree_iter); - make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter); - } - - impl FindExt for T {} - } - pub use ext::{FindExt, HeaderExt}; -} -pub use find::*; diff --git a/gix-object/src/traits/_impls.rs b/gix-object/src/traits/_impls.rs new file mode 100644 index 00000000000..5a1347a3430 --- /dev/null +++ b/gix-object/src/traits/_impls.rs @@ -0,0 +1,74 @@ +use crate::{Kind, WriteTo}; +use gix_hash::ObjectId; +use std::io::Read; +use std::ops::Deref; +use std::rc::Rc; +use std::sync::Arc; + +impl crate::Write for &T +where + T: crate::Write, +{ + fn write(&self, object: &dyn WriteTo) -> Result { + (*self).write(object) + } + + fn write_buf(&self, object: Kind, from: &[u8]) -> Result { + (*self).write_buf(object, from) + } + + fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result { + (*self).write_stream(kind, size, from) + } +} + +impl crate::Write for Arc +where + T: crate::Write, +{ + fn write(&self, object: &dyn WriteTo) -> Result { + self.deref().write(object) + } + + fn write_buf(&self, object: Kind, from: &[u8]) -> Result { + self.deref().write_buf(object, from) + } + + fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result { + self.deref().write_stream(kind, size, from) + } +} + +impl crate::Write for Rc +where + T: crate::Write, +{ + fn write(&self, object: &dyn WriteTo) -> Result { + self.deref().write(object) + } + + fn write_buf(&self, object: Kind, from: &[u8]) -> Result { + self.deref().write_buf(object, from) + } + + fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result { + self.deref().write_stream(kind, size, from) + } +} + +impl WriteTo for &T +where + T: WriteTo, +{ + fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> { + ::write_to(self, out) + } + + fn kind(&self) -> Kind { + ::kind(self) + } + + fn size(&self) -> u64 { + ::size(self) + } +} diff --git a/gix-object/src/traits/find.rs b/gix-object/src/traits/find.rs new file mode 100644 index 00000000000..8bedbd960a7 --- /dev/null +++ b/gix-object/src/traits/find.rs @@ -0,0 +1,310 @@ +use crate::find; + +/// Check if an object is present in an object store. +pub trait Exists { + /// Returns `true` if the object exists in the database. + fn exists(&self, id: &gix_hash::oid) -> bool; +} + +/// Find an object in the object store. +/// +/// ## Notes +/// +/// Find effectively needs [generic associated types][issue] to allow a trait for the returned object type. +/// Until then, we will have to make due with explicit types and give them the potentially added features we want. +/// +/// [issue]: https://github.com/rust-lang/rust/issues/44265 +pub trait Find { + /// Find an object matching `id` in the database while placing its raw, possibly encoded data into `buffer`. + /// + /// Returns `Some` object if it was present in the database, or the error that occurred during lookup or object + /// retrieval. + fn try_find<'a>(&self, id: &gix_hash::oid, buffer: &'a mut Vec) + -> Result>, find::Error>; +} + +/// Find the header of an object in the object store. +pub trait Header { + /// Find the header of the object matching `id` in the database. + /// + /// Returns `Some` header if it was present, or the error that occurred during lookup. + fn try_header(&self, id: &gix_hash::oid) -> Result, find::Error>; +} + +/// A combination of [`Find`] and [`Header`] traits to help with `dyn` trait objects. +pub trait FindObjectOrHeader: Find + Header {} + +mod _impls { + use std::{ops::Deref, rc::Rc, sync::Arc}; + + use gix_hash::oid; + + use crate::Data; + + impl crate::Exists for &T + where + T: crate::Exists, + { + fn exists(&self, id: &oid) -> bool { + (*self).exists(id) + } + } + + impl crate::FindObjectOrHeader for T where T: crate::Find + crate::FindHeader {} + + impl crate::Find for &T + where + T: crate::Find, + { + fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec) -> Result>, crate::find::Error> { + (*self).try_find(id, buffer) + } + } + + impl crate::FindHeader for &T + where + T: crate::FindHeader, + { + fn try_header(&self, id: &gix_hash::oid) -> Result, crate::find::Error> { + (*self).try_header(id) + } + } + + impl crate::Exists for Box + where + T: crate::Exists, + { + fn exists(&self, id: &oid) -> bool { + self.deref().exists(id) + } + } + + impl crate::Exists for Rc + where + T: crate::Exists, + { + fn exists(&self, id: &oid) -> bool { + self.deref().exists(id) + } + } + + impl crate::Find for Rc + where + T: crate::Find, + { + fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec) -> Result>, crate::find::Error> { + self.deref().try_find(id, buffer) + } + } + + impl crate::FindHeader for Rc + where + T: crate::FindHeader, + { + fn try_header(&self, id: &gix_hash::oid) -> Result, crate::find::Error> { + self.deref().try_header(id) + } + } + + impl crate::Find for Box + where + T: crate::Find, + { + fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec) -> Result>, crate::find::Error> { + self.deref().try_find(id, buffer) + } + } + + impl crate::FindHeader for Box + where + T: crate::FindHeader, + { + fn try_header(&self, id: &gix_hash::oid) -> Result, crate::find::Error> { + self.deref().try_header(id) + } + } + + impl crate::Exists for Arc + where + T: crate::Exists, + { + fn exists(&self, id: &oid) -> bool { + self.deref().exists(id) + } + } + + impl crate::Find for Arc + where + T: crate::Find, + { + fn try_find<'a>(&self, id: &oid, buffer: &'a mut Vec) -> Result>, crate::find::Error> { + self.deref().try_find(id, buffer) + } + } + + impl crate::FindHeader for Arc + where + T: crate::FindHeader, + { + fn try_header(&self, id: &gix_hash::oid) -> Result, crate::find::Error> { + self.deref().try_header(id) + } + } +} + +mod ext { + use crate::{find, BlobRef, CommitRef, CommitRefIter, Kind, ObjectRef, TagRef, TagRefIter, TreeRef, TreeRefIter}; + + macro_rules! make_obj_lookup { + ($method:ident, $object_variant:path, $object_kind:path, $object_type:ty) => { + /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error + /// while returning the desired object type. + fn $method<'a>( + &self, + id: &gix_hash::oid, + buffer: &'a mut Vec, + ) -> Result<$object_type, find::existing_object::Error> { + self.try_find(id, buffer) + .map_err(find::existing_object::Error::Find)? + .ok_or_else(|| find::existing_object::Error::NotFound { + oid: id.as_ref().to_owned(), + }) + .and_then(|o| { + o.decode().map_err(|err| find::existing_object::Error::Decode { + source: err, + oid: id.as_ref().to_owned(), + }) + }) + .and_then(|o| match o { + $object_variant(o) => return Ok(o), + o => Err(find::existing_object::Error::ObjectKind { + oid: id.as_ref().to_owned(), + actual: o.kind(), + expected: $object_kind, + }), + }) + } + }; + } + + macro_rules! make_iter_lookup { + ($method:ident, $object_kind:path, $object_type:ty, $into_iter:tt) => { + /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error + /// while returning the desired iterator type. + fn $method<'a>( + &self, + id: &gix_hash::oid, + buffer: &'a mut Vec, + ) -> Result<$object_type, find::existing_iter::Error> { + self.try_find(id, buffer) + .map_err(find::existing_iter::Error::Find)? + .ok_or_else(|| find::existing_iter::Error::NotFound { + oid: id.as_ref().to_owned(), + }) + .and_then(|o| { + o.$into_iter() + .ok_or_else(|| find::existing_iter::Error::ObjectKind { + oid: id.as_ref().to_owned(), + actual: o.kind, + expected: $object_kind, + }) + }) + } + }; + } + + /// An extension trait with convenience functions. + pub trait HeaderExt: super::Header { + /// Like [`try_header(…)`](super::Header::try_header()), but flattens the `Result>` into a single `Result` making a non-existing header an error. + fn header(&self, id: &gix_hash::oid) -> Result { + self.try_header(id) + .map_err(find::existing::Error::Find)? + .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() }) + } + } + + /// An extension trait with convenience functions. + pub trait FindExt: super::Find { + /// Like [`try_find(…)`](super::Find::try_find()), but flattens the `Result>` into a single `Result` making a non-existing object an error. + fn find<'a>( + &self, + id: &gix_hash::oid, + buffer: &'a mut Vec, + ) -> Result, find::existing::Error> { + self.try_find(id, buffer) + .map_err(find::existing::Error::Find)? + .ok_or_else(|| find::existing::Error::NotFound { oid: id.to_owned() }) + } + + /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error + /// while returning the desired object type. + fn find_blob<'a>( + &self, + id: &gix_hash::oid, + buffer: &'a mut Vec, + ) -> Result, find::existing_object::Error> { + if id == gix_hash::ObjectId::empty_blob(id.kind()) { + return Ok(BlobRef { data: &[] }); + } + self.try_find(id, buffer) + .map_err(find::existing_object::Error::Find)? + .ok_or_else(|| find::existing_object::Error::NotFound { + oid: id.as_ref().to_owned(), + }) + .and_then(|o| { + o.decode().map_err(|err| find::existing_object::Error::Decode { + source: err, + oid: id.as_ref().to_owned(), + }) + }) + .and_then(|o| match o { + ObjectRef::Blob(o) => Ok(o), + o => Err(find::existing_object::Error::ObjectKind { + oid: id.as_ref().to_owned(), + actual: o.kind(), + expected: Kind::Blob, + }), + }) + } + + /// Like [`find(…)`][Self::find()], but flattens the `Result>` into a single `Result` making a non-existing object an error + /// while returning the desired object type. + fn find_tree<'a>( + &self, + id: &gix_hash::oid, + buffer: &'a mut Vec, + ) -> Result, find::existing_object::Error> { + if id == gix_hash::ObjectId::empty_tree(id.kind()) { + return Ok(TreeRef { entries: Vec::new() }); + } + self.try_find(id, buffer) + .map_err(find::existing_object::Error::Find)? + .ok_or_else(|| find::existing_object::Error::NotFound { + oid: id.as_ref().to_owned(), + }) + .and_then(|o| { + o.decode().map_err(|err| find::existing_object::Error::Decode { + source: err, + oid: id.as_ref().to_owned(), + }) + }) + .and_then(|o| match o { + ObjectRef::Tree(o) => Ok(o), + o => Err(find::existing_object::Error::ObjectKind { + oid: id.as_ref().to_owned(), + actual: o.kind(), + expected: Kind::Tree, + }), + }) + } + + make_obj_lookup!(find_commit, ObjectRef::Commit, Kind::Commit, CommitRef<'a>); + make_obj_lookup!(find_tag, ObjectRef::Tag, Kind::Tag, TagRef<'a>); + make_iter_lookup!(find_commit_iter, Kind::Commit, CommitRefIter<'a>, try_into_commit_iter); + make_iter_lookup!(find_tree_iter, Kind::Tree, TreeRefIter<'a>, try_into_tree_iter); + make_iter_lookup!(find_tag_iter, Kind::Tag, TagRefIter<'a>, try_into_tag_iter); + } + + impl FindExt for T {} +} +pub use ext::{FindExt, HeaderExt}; diff --git a/gix-object/src/traits/mod.rs b/gix-object/src/traits/mod.rs new file mode 100644 index 00000000000..d28d29315c5 --- /dev/null +++ b/gix-object/src/traits/mod.rs @@ -0,0 +1,54 @@ +use std::io; + +use crate::Kind; + +/// Describe the capability to write git objects into an object store. +pub trait Write { + /// Write objects using the intrinsic kind of [`hash`][gix_hash::Kind] into the database, + /// returning id to reference it in subsequent reads. + fn write(&self, object: &dyn WriteTo) -> Result { + let mut buf = Vec::with_capacity(2048); + object.write_to(&mut buf)?; + self.write_stream(object.kind(), buf.len() as u64, &mut buf.as_slice()) + } + /// As [`write`][Write::write], but takes an [`object` kind][gix_object::Kind] along with its encoded bytes. + fn write_buf(&self, object: crate::Kind, mut from: &[u8]) -> Result { + self.write_stream(object, from.len() as u64, &mut from) + } + /// As [`write`][Write::write], but takes an input stream. + /// This is commonly used for writing blobs directly without reading them to memory first. + fn write_stream( + &self, + kind: crate::Kind, + size: u64, + from: &mut dyn io::Read, + ) -> Result; +} + +/// Writing of objects to a `Write` implementation +pub trait WriteTo { + /// Write a representation of this instance to `out`. + fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()>; + + /// Returns the type of this object. + fn kind(&self) -> Kind; + + /// Returns the size of this object's representation (the amount + /// of data which would be written by [`write_to`](Self::write_to)). + /// + /// [`size`](Self::size)'s value has no bearing on the validity of + /// the object, as such it's possible for [`size`](Self::size) to + /// return a sensible value but [`write_to`](Self::write_to) to + /// fail because the object was not actually valid in some way. + fn size(&self) -> u64; + + /// Returns a loose object header based on the object's data + fn loose_header(&self) -> smallvec::SmallVec<[u8; 28]> { + crate::encode::loose_header(self.kind(), self.size()) + } +} + +mod _impls; + +mod find; +pub use find::*; diff --git a/gix-odb/src/cache.rs b/gix-odb/src/cache.rs index cc737041e63..77022a09661 100644 --- a/gix-odb/src/cache.rs +++ b/gix-odb/src/cache.rs @@ -141,11 +141,16 @@ mod impls { use crate::{find::Header, pack::data::entry::Location, Cache}; - impl crate::Write for Cache + impl gix_object::Write for Cache where - S: crate::Write, + S: gix_object::Write, { - fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result { + fn write_stream( + &self, + kind: Kind, + size: u64, + from: &mut dyn Read, + ) -> Result { self.inner.write_stream(kind, size, from) } } diff --git a/gix-odb/src/lib.rs b/gix-odb/src/lib.rs index aaedc74a175..ca91fa7a185 100644 --- a/gix-odb/src/lib.rs +++ b/gix-odb/src/lib.rs @@ -77,13 +77,7 @@ pub mod find; /// An object database equivalent to `/dev/null`, dropping all objects stored into it. mod traits; -pub use traits::{Header, HeaderExt, Write}; - -/// -pub mod write { - /// The error type returned by the [`Write`](crate::Write) trait. - pub type Error = Box; -} +pub use traits::{Header, HeaderExt}; /// A thread-local handle to access any object. pub type Handle = Cache>>; diff --git a/gix-odb/src/memory.rs b/gix-odb/src/memory.rs index 5fdbd2abe3e..cd8e9fbdc3d 100644 --- a/gix-odb/src/memory.rs +++ b/gix-odb/src/memory.rs @@ -202,16 +202,16 @@ where } } -impl crate::Write for Proxy +impl gix_object::Write for Proxy where - T: crate::Write, + T: gix_object::Write, { fn write_stream( &self, kind: gix_object::Kind, size: u64, from: &mut dyn std::io::Read, - ) -> Result { + ) -> Result { let Some(map) = self.memory.as_ref() else { return self.inner.write_stream(kind, size, from); }; diff --git a/gix-odb/src/sink.rs b/gix-odb/src/sink.rs index 7784901a8c9..46077ff37cf 100644 --- a/gix-odb/src/sink.rs +++ b/gix-odb/src/sink.rs @@ -19,13 +19,13 @@ impl Sink { } } -impl crate::traits::Write for Sink { +impl gix_object::Write for Sink { fn write_stream( &self, kind: gix_object::Kind, mut size: u64, from: &mut dyn io::Read, - ) -> Result { + ) -> Result { let mut buf = [0u8; u16::MAX as usize]; let header = gix_object::encode::loose_header(kind, size); diff --git a/gix-odb/src/store_impls/dynamic/write.rs b/gix-odb/src/store_impls/dynamic/write.rs index ba615f351f4..014cd587c9e 100644 --- a/gix-odb/src/store_impls/dynamic/write.rs +++ b/gix-odb/src/store_impls/dynamic/write.rs @@ -24,11 +24,11 @@ pub use error::Error; use crate::store_impls::dynamic; -impl crate::Write for store::Handle +impl gix_object::Write for store::Handle where S: Deref + Clone, { - fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result { + fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result { let mut snapshot = self.snapshot.borrow_mut(); Ok(match snapshot.loose_dbs.first() { Some(ldb) => ldb.write_stream(kind, size, from)?, diff --git a/gix-odb/src/store_impls/loose/verify.rs b/gix-odb/src/store_impls/loose/verify.rs index ae83c1d01cb..dd08e9cd9f2 100644 --- a/gix-odb/src/store_impls/loose/verify.rs +++ b/gix-odb/src/store_impls/loose/verify.rs @@ -5,7 +5,7 @@ use std::{ use gix_features::progress::{Count, DynNestedProgress, Progress}; -use crate::{loose::Store, Write}; +use crate::loose::Store; /// pub mod integrity { @@ -64,6 +64,7 @@ impl Store { progress: &mut dyn DynNestedProgress, should_interrupt: &AtomicBool, ) -> Result { + use gix_object::Write; let mut buf = Vec::new(); let sink = crate::sink(self.object_hash); diff --git a/gix-odb/src/store_impls/loose/write.rs b/gix-odb/src/store_impls/loose/write.rs index a70351a1574..0e9dd019868 100644 --- a/gix-odb/src/store_impls/loose/write.rs +++ b/gix-odb/src/store_impls/loose/write.rs @@ -26,8 +26,8 @@ pub enum Error { }, } -impl crate::traits::Write for Store { - fn write(&self, object: &dyn WriteTo) -> Result { +impl gix_object::Write for Store { + fn write(&self, object: &dyn WriteTo) -> Result { let mut to = self.dest()?; to.write_all(&object.loose_header()).map_err(|err| Error::Io { source: err, @@ -46,7 +46,7 @@ impl crate::traits::Write for Store { /// Write the given buffer in `from` to disk in one syscall at best. /// /// This will cost at least 4 IO operations. - fn write_buf(&self, kind: gix_object::Kind, from: &[u8]) -> Result { + fn write_buf(&self, kind: gix_object::Kind, from: &[u8]) -> Result { let mut to = self.dest().map_err(Box::new)?; to.write_all(&gix_object::encode::loose_header(kind, from.len() as u64)) .map_err(|err| Error::Io { @@ -72,7 +72,7 @@ impl crate::traits::Write for Store { kind: gix_object::Kind, size: u64, mut from: &mut dyn io::Read, - ) -> Result { + ) -> Result { let mut to = self.dest().map_err(Box::new)?; to.write_all(&gix_object::encode::loose_header(kind, size)) .map_err(|err| Error::Io { diff --git a/gix-odb/src/traits.rs b/gix-odb/src/traits.rs index df6bd9b0c12..f3e5cec6403 100644 --- a/gix-odb/src/traits.rs +++ b/gix-odb/src/traits.rs @@ -1,32 +1,5 @@ -use std::io; - -use gix_object::WriteTo; - use crate::find; -/// Describe the capability to write git objects into an object store. -pub trait Write { - /// Write objects using the intrinsic kind of [`hash`][gix_hash::Kind] into the database, - /// returning id to reference it in subsequent reads. - fn write(&self, object: &dyn WriteTo) -> Result { - let mut buf = Vec::with_capacity(2048); - object.write_to(&mut buf)?; - self.write_stream(object.kind(), buf.len() as u64, &mut buf.as_slice()) - } - /// As [`write`][Write::write], but takes an [`object` kind][gix_object::Kind] along with its encoded bytes. - fn write_buf(&self, object: gix_object::Kind, mut from: &[u8]) -> Result { - self.write_stream(object, from.len() as u64, &mut from) - } - /// As [`write`][Write::write], but takes an input stream. - /// This is commonly used for writing blobs directly without reading them to memory first. - fn write_stream( - &self, - kind: gix_object::Kind, - size: u64, - from: &mut dyn io::Read, - ) -> Result; -} - /// A way to obtain object properties without fully decoding it. pub trait Header { /// Try to read the header of the object associated with `id` or return `None` if it could not be found. @@ -34,64 +7,12 @@ pub trait Header { } mod _impls { - use std::{io::Read, ops::Deref, rc::Rc, sync::Arc}; + use std::{ops::Deref, rc::Rc, sync::Arc}; - use gix_hash::{oid, ObjectId}; - use gix_object::{Kind, WriteTo}; + use gix_hash::oid; use crate::find::Header; - impl crate::Write for &T - where - T: crate::Write, - { - fn write(&self, object: &dyn WriteTo) -> Result { - (*self).write(object) - } - - fn write_buf(&self, object: Kind, from: &[u8]) -> Result { - (*self).write_buf(object, from) - } - - fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result { - (*self).write_stream(kind, size, from) - } - } - - impl crate::Write for Arc - where - T: crate::Write, - { - fn write(&self, object: &dyn WriteTo) -> Result { - self.deref().write(object) - } - - fn write_buf(&self, object: Kind, from: &[u8]) -> Result { - self.deref().write_buf(object, from) - } - - fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result { - self.deref().write_stream(kind, size, from) - } - } - - impl crate::Write for Rc - where - T: crate::Write, - { - fn write(&self, object: &dyn WriteTo) -> Result { - self.deref().write(object) - } - - fn write_buf(&self, object: Kind, from: &[u8]) -> Result { - self.deref().write_buf(object, from) - } - - fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result { - self.deref().write_stream(kind, size, from) - } - } - impl crate::Header for &T where T: crate::Header, diff --git a/gix-odb/tests/odb/memory.rs b/gix-odb/tests/odb/memory.rs index d0d8ddb2bfd..f9c34a4c9f7 100644 --- a/gix-odb/tests/odb/memory.rs +++ b/gix-odb/tests/odb/memory.rs @@ -1,6 +1,6 @@ use crate::odb::hex_to_id; +use gix_object::Write; use gix_object::{tree, Exists, FindExt}; -use gix_odb::Write; use gix_testtools::tempfile::TempDir; #[test] diff --git a/gix-odb/tests/odb/sink/mod.rs b/gix-odb/tests/odb/sink/mod.rs index a6859a10b78..44abcae5f80 100644 --- a/gix-odb/tests/odb/sink/mod.rs +++ b/gix-odb/tests/odb/sink/mod.rs @@ -1,4 +1,4 @@ -use gix_odb::Write; +use gix_object::Write; use crate::store::loose::{locate_oid, object_ids}; diff --git a/gix-odb/tests/odb/store/dynamic.rs b/gix-odb/tests/odb/store/dynamic.rs index 87caddd9682..e0241f2ee4b 100644 --- a/gix-odb/tests/odb/store/dynamic.rs +++ b/gix-odb/tests/odb/store/dynamic.rs @@ -1,8 +1,8 @@ use std::process::Command; use gix_hash::ObjectId; -use gix_object::{Exists, FindExt}; -use gix_odb::{store, store::iter::Ordering, Header, Write}; +use gix_object::{Exists, FindExt, Write}; +use gix_odb::{store, store::iter::Ordering, Header}; use gix_testtools::fixture_path_standalone; use crate::{hex_to_id, odb::db}; diff --git a/gix-odb/tests/odb/store/loose.rs b/gix-odb/tests/odb/store/loose.rs index 7848e5b5b5d..e5b4fee35d6 100644 --- a/gix-odb/tests/odb/store/loose.rs +++ b/gix-odb/tests/odb/store/loose.rs @@ -45,7 +45,8 @@ fn verify_integrity() { } mod write { - use gix_odb::{loose, Write}; + use gix_object::Write; + use gix_odb::loose; use crate::store::loose::{locate_oid, object_ids}; From 96488f745506698e4183e8e544c4e0ecd1ef868b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 31 Oct 2024 19:03:39 +0100 Subject: [PATCH 17/23] adapt to changes in `gix-object` and `gix-odb` --- gitoxide-core/src/pack/explode.rs | 9 +++++---- gix-object/src/traits/mod.rs | 6 +++--- gix-odb/src/store_impls/dynamic/write.rs | 2 +- gix-odb/src/store_impls/loose/write.rs | 2 +- gix/src/prelude.rs | 4 ++-- gix/src/repository/object.rs | 4 ++-- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/gitoxide-core/src/pack/explode.rs b/gitoxide-core/src/pack/explode.rs index f73a54533ad..9e51cf51a17 100644 --- a/gitoxide-core/src/pack/explode.rs +++ b/gitoxide-core/src/pack/explode.rs @@ -9,7 +9,8 @@ use anyhow::{anyhow, Result}; use gix::{ hash::ObjectId, object, objs, odb, - odb::{loose, pack, Write}, + odb::{loose, pack}, + prelude::Write, NestedProgress, }; @@ -96,8 +97,8 @@ enum OutputWriter { Sink(odb::Sink), } -impl gix::odb::Write for OutputWriter { - fn write_buf(&self, kind: object::Kind, from: &[u8]) -> Result { +impl gix::objs::Write for OutputWriter { + fn write_buf(&self, kind: object::Kind, from: &[u8]) -> Result { match self { OutputWriter::Loose(db) => db.write_buf(kind, from), OutputWriter::Sink(db) => db.write_buf(kind, from), @@ -109,7 +110,7 @@ impl gix::odb::Write for OutputWriter { kind: object::Kind, size: u64, from: &mut dyn Read, - ) -> Result { + ) -> Result { match self { OutputWriter::Loose(db) => db.write_stream(kind, size, from), OutputWriter::Sink(db) => db.write_stream(kind, size, from), diff --git a/gix-object/src/traits/mod.rs b/gix-object/src/traits/mod.rs index d28d29315c5..f0078fd9345 100644 --- a/gix-object/src/traits/mod.rs +++ b/gix-object/src/traits/mod.rs @@ -4,18 +4,18 @@ use crate::Kind; /// Describe the capability to write git objects into an object store. pub trait Write { - /// Write objects using the intrinsic kind of [`hash`][gix_hash::Kind] into the database, + /// Write objects using the intrinsic kind of [`hash`](gix_hash::Kind) into the database, /// returning id to reference it in subsequent reads. fn write(&self, object: &dyn WriteTo) -> Result { let mut buf = Vec::with_capacity(2048); object.write_to(&mut buf)?; self.write_stream(object.kind(), buf.len() as u64, &mut buf.as_slice()) } - /// As [`write`][Write::write], but takes an [`object` kind][gix_object::Kind] along with its encoded bytes. + /// As [`write`](Write::write), but takes an [`object` kind](Kind) along with its encoded bytes. fn write_buf(&self, object: crate::Kind, mut from: &[u8]) -> Result { self.write_stream(object, from.len() as u64, &mut from) } - /// As [`write`][Write::write], but takes an input stream. + /// As [`write`](Write::write), but takes an input stream. /// This is commonly used for writing blobs directly without reading them to memory first. fn write_stream( &self, diff --git a/gix-odb/src/store_impls/dynamic/write.rs b/gix-odb/src/store_impls/dynamic/write.rs index 014cd587c9e..d0b8735121f 100644 --- a/gix-odb/src/store_impls/dynamic/write.rs +++ b/gix-odb/src/store_impls/dynamic/write.rs @@ -8,7 +8,7 @@ use crate::store; mod error { use crate::{loose, store}; - /// The error returned by the [dynamic Store's][crate::Store] [`Write`][crate::Write] implementation. + /// The error returned by the [dynamic Store's][crate::Store] [`Write`](gix_object::Write) implementation. #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { diff --git a/gix-odb/src/store_impls/loose/write.rs b/gix-odb/src/store_impls/loose/write.rs index 0e9dd019868..bdef0b90005 100644 --- a/gix-odb/src/store_impls/loose/write.rs +++ b/gix-odb/src/store_impls/loose/write.rs @@ -7,7 +7,7 @@ use tempfile::NamedTempFile; use super::Store; use crate::store_impls::loose; -/// Returned by the [`crate::Write`] trait implementation of [`Store`] +/// Returned by the [`gix_object::Write`] trait implementation of [`Store`] #[derive(thiserror::Error, Debug)] #[allow(missing_docs)] pub enum Error { diff --git a/gix/src/prelude.rs b/gix/src/prelude.rs index 8a3e01124c2..03954574a36 100644 --- a/gix/src/prelude.rs +++ b/gix/src/prelude.rs @@ -1,5 +1,5 @@ pub use gix_features::parallel::reduce::Finalize; -pub use gix_object::{Find, FindExt}; -pub use gix_odb::{Header, HeaderExt, Write}; +pub use gix_object::{Find, FindExt, Write}; +pub use gix_odb::{Header, HeaderExt}; pub use crate::ext::*; diff --git a/gix/src/repository/object.rs b/gix/src/repository/object.rs index dcb999aa763..c0112ab1195 100644 --- a/gix/src/repository/object.rs +++ b/gix/src/repository/object.rs @@ -2,8 +2,8 @@ use std::ops::DerefMut; use gix_hash::ObjectId; -use gix_object::{Exists, Find, FindExt}; -use gix_odb::{Header, HeaderExt, Write}; +use gix_object::{Exists, Find, FindExt, Write}; +use gix_odb::{Header, HeaderExt}; use gix_ref::{ transaction::{LogChange, PreviousValue, RefLog}, FullName, From 4b1764ca9148e08ae9f11bca68e0689b12bc8c80 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 31 Oct 2024 19:39:07 +0100 Subject: [PATCH 18/23] feat: add `tree()` and `commit()` merge support, en par with `merge-ORT` as far as tests go. Note that this judgement of quality is based on a limited amount of partially complex test, but it's likely that in practice there will be deviations of sorts. Also, given the complexity of the implementation it is definitely under-tested, but with that it's mostly en par with Git, unfortunatly. On the bright side, some of the tests are very taxing and I'd hope this means something for real-world quality. --- Cargo.lock | 10 +- crate-status.md | 13 +- gix-merge/Cargo.toml | 27 +- gix-merge/src/blob/platform/merge.rs | 5 +- gix-merge/src/blob/platform/set_resource.rs | 1 - gix-merge/src/commit.rs | 227 ++++ gix-merge/src/lib.rs | 7 +- gix-merge/src/tree/function.rs | 1091 +++++++++++++++++ gix-merge/src/tree/mod.rs | 260 ++++ gix-merge/src/tree/utils.rs | 572 +++++++++ .../generated-archives/tree-baseline.tar | Bin 0 -> 2681344 bytes gix-merge/tests/fixtures/tree-baseline.sh | 864 +++++++++++++ gix-merge/tests/merge/main.rs | 2 +- gix-merge/tests/merge/tree/baseline.rs | 344 ++++++ gix-merge/tests/merge/tree/mod.rs | 180 +++ gix/Cargo.toml | 2 +- 16 files changed, 3580 insertions(+), 25 deletions(-) create mode 100644 gix-merge/src/commit.rs create mode 100644 gix-merge/src/tree/function.rs create mode 100644 gix-merge/src/tree/mod.rs create mode 100644 gix-merge/src/tree/utils.rs create mode 100644 gix-merge/tests/fixtures/generated-archives/tree-baseline.tar create mode 100644 gix-merge/tests/fixtures/tree-baseline.sh create mode 100644 gix-merge/tests/merge/tree/baseline.rs create mode 100644 gix-merge/tests/merge/tree/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 030f8c91182..d8aee88db33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1063,9 +1063,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "libz-ng-sys", @@ -2069,19 +2069,25 @@ dependencies = [ "bstr", "document-features", "gix-command", + "gix-diff", "gix-filter", "gix-fs 0.12.0", "gix-hash 0.15.0", "gix-object 0.45.0", + "gix-odb", "gix-path 0.10.12", "gix-quote 0.4.13", + "gix-revision", + "gix-revwalk 0.16.0", "gix-tempfile 15.0.0", "gix-testtools", "gix-trace 0.1.11", + "gix-utils 0.1.13", "gix-worktree 0.37.0", "imara-diff", "pretty_assertions", "serde", + "termtree", "thiserror", ] diff --git a/crate-status.md b/crate-status.md index 0d75dce40b6..502583127b8 100644 --- a/crate-status.md +++ b/crate-status.md @@ -338,14 +338,21 @@ Check out the [performance discussion][gix-diff-performance] as well. ### gix-merge -* [x] three-way merge analysis of **blobs** with choice of how to resolve conflicts +* [x] three-way content-merge analysis of **blobs** with choice of how to resolve conflicts + - [x] respect git attributes and drivers. - [ ] choose how to resolve conflicts on the data-structure - - [ ] produce a new blob based on data-structure containing possible resolutions + - [ ] more efficient handling of paths with `merge=binary` attributes (do not load them into memory) + - [x] produce a new blob based on data-structure containing possible resolutions - [x] `merge` style - [x] `diff3` style - [x] `zdiff` style + - [ ] various newlines-related options during the merge (see https://git-scm.com/docs/git-merge#Documentation/git-merge.txt-ignore-space-change). - [ ] a way to control inter-hunk merging based on proximity (maybe via `gix-diff` feature which could use the same) -* [ ] diff-heuristics match Git perfectly +* [x] **tree**-diff-heuristics match Git for its test-cases + - [ ] a way to generate an index with stages + - *currently the data it provides won't generate index entries, and possibly can't be used for it yet* + - [ ] submodule merges (*right now they count as conflicts if they differ*) +* [x] **commits** - with handling of multiple merge bases by recursive merge-base merge * [x] API documentation * [ ] Examples diff --git a/gix-merge/Cargo.toml b/gix-merge/Cargo.toml index 92a6fb1c2d5..1070e979516 100644 --- a/gix-merge/Cargo.toml +++ b/gix-merge/Cargo.toml @@ -15,26 +15,26 @@ workspace = true doctest = false [features] -default = ["blob"] -## Enable diffing of blobs using imara-diff, which also allows for a generic rewrite tracking implementation. -blob = ["dep:imara-diff", "dep:gix-filter", "dep:gix-worktree", "dep:gix-path", "dep:gix-fs", "dep:gix-command", "dep:gix-tempfile", "dep:gix-trace", "dep:gix-quote"] ## Data structures implement `serde::Serialize` and `serde::Deserialize`. serde = ["dep:serde", "gix-hash/serde", "gix-object/serde"] [dependencies] gix-hash = { version = "^0.15.0", path = "../gix-hash" } gix-object = { version = "^0.45.0", path = "../gix-object" } -gix-filter = { version = "^0.14.0", path = "../gix-filter", optional = true } -gix-worktree = { version = "^0.37.0", path = "../gix-worktree", default-features = false, features = ["attributes"], optional = true } -gix-command = { version = "^0.3.10", path = "../gix-command", optional = true } -gix-path = { version = "^0.10.12", path = "../gix-path", optional = true } -gix-fs = { version = "^0.12.0", path = "../gix-fs", optional = true } -gix-tempfile = { version = "^15.0.0", path = "../gix-tempfile", optional = true } -gix-trace = { version = "^0.1.11", path = "../gix-trace", optional = true } -gix-quote = { version = "^0.4.13", path = "../gix-quote", optional = true } +gix-filter = { version = "^0.14.0", path = "../gix-filter" } +gix-worktree = { version = "^0.37.0", path = "../gix-worktree", default-features = false, features = ["attributes"] } +gix-command = { version = "^0.3.10", path = "../gix-command" } +gix-path = { version = "^0.10.12", path = "../gix-path" } +gix-fs = { version = "^0.12.0", path = "../gix-fs" } +gix-tempfile = { version = "^15.0.0", path = "../gix-tempfile" } +gix-trace = { version = "^0.1.11", path = "../gix-trace" } +gix-quote = { version = "^0.4.13", path = "../gix-quote" } +gix-revision = { version = "^0.30.0", path = "../gix-revision", default-features = false, features = ["merge_base"] } +gix-revwalk = { version = "^0.16.0", path = "../gix-revwalk" } +gix-diff = { version = "^0.47.0", path = "../gix-diff", default-features = false, features = ["blob"] } thiserror = "1.0.63" -imara-diff = { version = "0.1.7", optional = true } +imara-diff = { version = "0.1.7" } bstr = { version = "1.5.0", default-features = false } serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] } @@ -42,6 +42,9 @@ document-features = { version = "0.2.0", optional = true } [dev-dependencies] gix-testtools = { path = "../tests/tools" } +gix-odb = { path = "../gix-odb" } +gix-utils = { version = "^0.1.12", path = "../gix-utils" } +termtree = "0.5.1" pretty_assertions = "1.4.0" [package.metadata.docs.rs] diff --git a/gix-merge/src/blob/platform/merge.rs b/gix-merge/src/blob/platform/merge.rs index 5116ee4f96d..460c24ad85b 100644 --- a/gix-merge/src/blob/platform/merge.rs +++ b/gix-merge/src/blob/platform/merge.rs @@ -7,6 +7,7 @@ use std::path::PathBuf; pub struct Options { /// If `true`, the resources being merged are contained in a virtual ancestor, /// which is the case when merge bases are merged into one. + /// This flag affects the choice of merge drivers. pub is_virtual_ancestor: bool, /// Determine how to resolve conflicts. If `None`, no conflict resolution is possible, and it picks a side. pub resolve_binary_with: Option, @@ -387,10 +388,6 @@ impl<'parent> PlatformRef<'parent> { labels: builtin_driver::text::Labels<'_>, context: &gix_command::Context, ) -> Result<(inner::builtin_merge::Pick, Resolution), Error> { - let _span = gix_trace::coarse!( - "gix_merge::blob::PlatformRef::merge()", - current_rela_path = %self.current.rela_path - ); match self.configured_driver() { Ok(driver) => { let mut cmd = self.prepare_external_driver(driver.command.clone(), labels, context.clone())?; diff --git a/gix-merge/src/blob/platform/set_resource.rs b/gix-merge/src/blob/platform/set_resource.rs index 675c84d9ce9..75be7b65e07 100644 --- a/gix-merge/src/blob/platform/set_resource.rs +++ b/gix-merge/src/blob/platform/set_resource.rs @@ -46,7 +46,6 @@ impl Platform { kind: ResourceKind, objects: &impl gix_object::FindObjectOrHeader, ) -> Result<(), Error> { - gix_trace::detail!("gix_merge::blob::Platform::set_resource()", %id, %rela_path); if !matches!( mode, gix_object::tree::EntryKind::Blob | gix_object::tree::EntryKind::BlobExecutable diff --git a/gix-merge/src/commit.rs b/gix-merge/src/commit.rs new file mode 100644 index 00000000000..94097ec7004 --- /dev/null +++ b/gix-merge/src/commit.rs @@ -0,0 +1,227 @@ +/// The error returned by [`commit()`](crate::commit()). +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum Error { + #[error(transparent)] + MergeBase(#[from] gix_revision::merge_base::Error), + #[error(transparent)] + MergeTree(#[from] crate::tree::Error), + #[error("Failed to write tree for merged merge-base or virtual commit")] + WriteObject(gix_object::write::Error), + #[error("No common ancestor between {our_commit_id} and {their_commit_id}")] + NoMergeBase { + /// The commit on our side that was to be merged. + our_commit_id: gix_hash::ObjectId, + /// The commit on their side that was to be merged. + their_commit_id: gix_hash::ObjectId, + }, + #[error( + "Conflicts occurred when trying to resolve multiple merge-bases by merging them. This is most certainly a bug." + )] + VirtualMergeBaseConflict, + #[error("Could not find ancestor, our or their commit to extract tree from")] + FindCommit(#[from] gix_object::find::existing_object::Error), +} + +/// A way to configure [`commit()`](crate::commit()). +#[derive(Default, Debug, Clone)] +pub struct Options { + /// If `true`, merging unrelated commits is allowed, with the merge-base being assumed as empty tree. + pub allow_missing_merge_base: bool, + /// Options to define how trees should be merged. + pub tree_merge: crate::tree::Options, + /// If `true`, do not merge multiple merge-bases into one. Instead, just use the first one. + // TODO: test + #[doc(alias = "no_recursive", alias = "git2")] + pub use_first_merge_base: bool, +} + +/// The result of [`commit()`](crate::commit()). +#[derive(Clone)] +pub struct Outcome<'a> { + /// The outcome of the actual tree-merge. + pub tree_merge: crate::tree::Outcome<'a>, + /// The tree id of the base commit we used. This is either… + /// * the single merge-base we found + /// * the first of multiple merge-bases if [`use_first_merge_base`](Options::use_first_merge_base) was `true`. + /// * the merged tree of all merge-bases, which then isn't linked to an actual commit. + /// * an empty tree, if [`allow_missing_merge_base`](Options::allow_missing_merge_base) is enabled. + pub merge_base_tree_id: gix_hash::ObjectId, + /// The object ids of all the commits which were found to be merge-bases, or `None` if there was no merge-base. + pub merge_bases: Option>, + /// A list of virtual commits that were created to merge multiple merge-bases into one. + /// As they are not reachable by anything they will be garbage collected, but knowing them provides options. + pub virtual_merge_bases: Vec, +} + +pub(super) mod function { + use crate::blob::builtin_driver; + use crate::commit::{Error, Options}; + use crate::tree::UnresolvedConflict; + use gix_object::FindExt; + use std::borrow::Cow; + + /// Like [`tree()`](crate::tree()), but it takes only two commits, `our_commit` and `their_commit` to automatically + /// compute the merge-bases among them. + /// If there are multiple merge bases, these will be auto-merged into one, recursively, if + /// [`allow_missing_merge_base`](Options::allow_missing_merge_base) is `true`. + /// + /// `labels` are names where [`current`](crate::blob::builtin_driver::text::Labels::current) is a name for `our_commit` + /// and [`other`](crate::blob::builtin_driver::text::Labels::other) is a name for `their_commit`. + /// If [`ancestor`](crate::blob::builtin_driver::text::Labels::ancestor) is unset, it will be set by us based on the + /// merge-bases of `our_commit` and `their_commit`. + /// + /// The `graph` is used to find the merge-base between `our_commit` and `their_commit`, and can also act as cache + /// to speed up subsequent merge-base queries. + /// + /// Use `abbreviate_hash(id)` to shorten the given `id` according to standard git shortening rules. It's used in case + /// the ancestor-label isn't explicitly set so that the merge base label becomes the shortened `id`. + /// Note that it's a dyn closure only to make it possible to recursively call this function in case of multiple merge-bases. + /// + /// `write_object` is used only if it's allowed to merge multiple merge-bases into one, and if there + /// are multiple merge bases, and to write merged buffers as blobs. + /// + /// ### Performance + /// + /// Note that `objects` *should* have an object cache to greatly accelerate tree-retrieval. + /// + /// ### Notes + /// + /// When merging merge-bases recursively, the options are adjusted automatically to act like Git, i.e. merge binary + /// blobs and resolve with *ours*, while resorting to using the base/ancestor in case of unresolvable conflicts. + /// + /// ### Deviation + /// + /// * It's known that certain conflicts around symbolic links can be auto-resolved. We don't have an option for this + /// at all, yet, primarily as Git seems to not implement the *ours*/*theirs* choice in other places even though it + /// reasonably could. So we leave it to the caller to continue processing the returned tree at will. + #[allow(clippy::too_many_arguments)] + pub fn commit<'objects>( + our_commit: gix_hash::ObjectId, + their_commit: gix_hash::ObjectId, + labels: builtin_driver::text::Labels<'_>, + graph: &mut gix_revwalk::Graph<'_, '_, gix_revwalk::graph::Commit>, + diff_resource_cache: &mut gix_diff::blob::Platform, + blob_merge: &mut crate::blob::Platform, + objects: &'objects (impl gix_object::FindObjectOrHeader + gix_object::Write), + abbreviate_hash: &mut dyn FnMut(&gix_hash::oid) -> String, + options: Options, + ) -> Result, Error> { + let merge_bases = gix_revision::merge_base(our_commit, &[their_commit], graph)?; + let mut virtual_merge_bases = Vec::new(); + let mut state = gix_diff::tree::State::default(); + let mut commit_to_tree = + |commit_id: gix_hash::ObjectId| objects.find_commit(&commit_id, &mut state.buf1).map(|c| c.tree()); + + let (merge_base_tree_id, ancestor_name): (_, Cow<'_, str>) = match merge_bases.clone() { + Some(base_commit) if base_commit.len() == 1 => { + (commit_to_tree(base_commit[0])?, abbreviate_hash(&base_commit[0]).into()) + } + Some(mut base_commits) => { + let virtual_base_tree = if options.use_first_merge_base { + let first = *base_commits.first().expect("if Some() there is at least one."); + commit_to_tree(first)? + } else { + let mut merged_commit_id = base_commits.pop().expect("at least one base"); + let mut options = options.clone(); + options.tree_merge.allow_lossy_resolution = true; + options.tree_merge.blob_merge.is_virtual_ancestor = true; + options.tree_merge.blob_merge.text.conflict = builtin_driver::text::Conflict::ResolveWithOurs; + let favor_ancestor = Some(builtin_driver::binary::ResolveWith::Ancestor); + options.tree_merge.blob_merge.resolve_binary_with = favor_ancestor; + options.tree_merge.symlink_conflicts = favor_ancestor; + let labels = builtin_driver::text::Labels { + current: Some("Temporary merge branch 1".into()), + other: Some("Temporary merge branch 2".into()), + ..labels + }; + while let Some(next_commit_id) = base_commits.pop() { + options.tree_merge.marker_size_multiplier += 1; + let mut out = commit( + merged_commit_id, + next_commit_id, + labels, + graph, + diff_resource_cache, + blob_merge, + objects, + abbreviate_hash, + options.clone(), + )?; + // This shouldn't happen, but if for some buggy reason it does, we rather bail. + if out + .tree_merge + .has_unresolved_conflicts(UnresolvedConflict::ConflictMarkers) + { + return Err(Error::VirtualMergeBaseConflict); + } + let merged_tree_id = out + .tree_merge + .tree + .write(|tree| objects.write(tree)) + .map_err(Error::WriteObject)?; + + merged_commit_id = + create_virtual_commit(objects, merged_commit_id, next_commit_id, merged_tree_id)?; + + virtual_merge_bases.extend(out.virtual_merge_bases); + virtual_merge_bases.push(merged_commit_id); + } + commit_to_tree(merged_commit_id)? + }; + (virtual_base_tree, "merged common ancestors".into()) + } + None => { + if options.allow_missing_merge_base { + (gix_hash::ObjectId::empty_tree(our_commit.kind()), "empty tree".into()) + } else { + return Err(Error::NoMergeBase { + our_commit_id: our_commit, + their_commit_id: their_commit, + }); + } + } + }; + + let mut labels = labels; // TODO(borrowchk): this re-assignment shouldn't be needed. + if labels.ancestor.is_none() { + labels.ancestor = Some(ancestor_name.as_ref().into()); + } + + let our_tree_id = objects.find_commit(&our_commit, &mut state.buf1)?.tree(); + let their_tree_id = objects.find_commit(&their_commit, &mut state.buf1)?.tree(); + + let outcome = crate::tree( + &merge_base_tree_id, + &our_tree_id, + &their_tree_id, + labels, + objects, + |buf| objects.write_buf(gix_object::Kind::Blob, buf), + &mut state, + diff_resource_cache, + blob_merge, + options.tree_merge, + )?; + + Ok(super::Outcome { + tree_merge: outcome, + merge_bases, + merge_base_tree_id, + virtual_merge_bases, + }) + } + + fn create_virtual_commit( + objects: &(impl gix_object::Find + gix_object::Write), + parent_a: gix_hash::ObjectId, + parent_b: gix_hash::ObjectId, + tree_id: gix_hash::ObjectId, + ) -> Result { + let mut buf = Vec::new(); + let mut commit: gix_object::Commit = objects.find_commit(&parent_a, &mut buf)?.into(); + commit.parents = vec![parent_a, parent_b].into(); + commit.tree = tree_id; + objects.write(&commit).map_err(Error::WriteObject) + } +} diff --git a/gix-merge/src/lib.rs b/gix-merge/src/lib.rs index 8e608c53ab4..18be9a67604 100644 --- a/gix-merge/src/lib.rs +++ b/gix-merge/src/lib.rs @@ -2,5 +2,10 @@ #![forbid(unsafe_code)] /// -#[cfg(feature = "blob")] pub mod blob; +/// +pub mod commit; +pub use commit::function::commit; +/// +pub mod tree; +pub use tree::function::tree; diff --git a/gix-merge/src/tree/function.rs b/gix-merge/src/tree/function.rs new file mode 100644 index 00000000000..5cffd377cdd --- /dev/null +++ b/gix-merge/src/tree/function.rs @@ -0,0 +1,1091 @@ +use crate::tree::utils::{ + apply_change, perform_blob_merge, possibly_rewritten_location, rewrite_location_with_renamed_directory, + to_components, track, unique_path_in_tree, ChangeList, ChangeListRef, PossibleConflict, TrackedChange, TreeNodes, +}; +use crate::tree::ConflictMapping::{Original, Swapped}; +use crate::tree::{ + Conflict, ConflictMapping, ContentMerge, Error, Options, Outcome, Resolution, ResolutionFailure, UnresolvedConflict, +}; +use bstr::{BString, ByteSlice}; +use gix_diff::tree::recorder::Location; +use gix_diff::tree_with_rewrites::Change; +use gix_hash::ObjectId; +use gix_object::tree::{EntryKind, EntryMode}; +use gix_object::{tree, FindExt}; +use std::convert::Infallible; + +/// Perform a merge between `our_tree` and `their_tree`, using `base_tree` as merge-base. +/// Note that `base_tree` can be an empty tree to indicate 'no common ancestor between the two sides'. +/// +/// * `labels` are relevant for text-merges and will be shown in conflicts. +/// * `objects` provides access to trees when diffing them. +/// * `write_blob_to_odb(content) -> Result` writes newly merged content into the odb to obtain an id +/// that will be used in merged trees. +/// * `diff_state` is state used for diffing trees. +/// * `diff_resource_cache` is used for similarity checks. +/// * `blob_merge` is a pre-configured platform to merge any content. +/// - Note that it shouldn't be allowed to read from the worktree, given that this is a tree-merge. +/// * `options` are used to affect how the merge is performed. +/// +/// ### Unbiased (Ours x Theirs == Theirs x Ours) +/// +/// The algorithm is implemented so that the result is the same no matter how the sides are ordered. +/// +/// ### Differences to Merge-ORT +/// +/// Merge-ORT (Git) defines the desired outcomes where are merely mimicked here. The algorithms are different, and it's +/// clear that Merge-ORT is significantly more elaborate and general. +/// +/// It also writes out trees once it's done with them in a form of reduction process, here an editor is used +/// to keep only the changes, to be written by the caller who receives it as part of the result. +/// This may use more memory in the worst case scenario, but in average *shouldn't* perform much worse due to the +/// natural sparsity of the editor. +/// +/// Our rename-tracking also produces copy information, but we discard it and simply treat it like an addition. +/// +/// Finally, our algorithm will consider reasonable solutions to merge-conflicts as conflicts that are resolved, leaving +/// only content with conflict markers as unresolved ones. +/// +/// ### Performance +/// +/// Note that `objects` *should* have an object cache to greatly accelerate tree-retrieval. +#[allow(clippy::too_many_arguments)] +pub fn tree<'objects, E>( + base_tree: &gix_hash::oid, + our_tree: &gix_hash::oid, + their_tree: &gix_hash::oid, + mut labels: crate::blob::builtin_driver::text::Labels<'_>, + objects: &'objects impl gix_object::FindObjectOrHeader, + mut write_blob_to_odb: impl FnMut(&[u8]) -> Result, + diff_state: &mut gix_diff::tree::State, + diff_resource_cache: &mut gix_diff::blob::Platform, + blob_merge: &mut crate::blob::Platform, + options: Options, +) -> Result, Error> +where + E: Into>, +{ + let ours_needs_diff = base_tree != our_tree; + let theirs_needs_diff = base_tree != their_tree; + let _span = gix_trace::coarse!("gix_merge::tree", ?base_tree, ?our_tree, ?their_tree, ?labels); + let (mut base_buf, mut side_buf) = (Vec::new(), Vec::new()); + let ancestor_tree = objects.find_tree(base_tree, &mut base_buf)?; + let allow_resolution_failure = !options.allow_lossy_resolution; + + let mut editor = tree::Editor::new(ancestor_tree.to_owned(), objects, base_tree.kind()); + let ancestor_tree = gix_object::TreeRefIter::from_bytes(&base_buf); + + let mut our_changes = Vec::new(); + if ours_needs_diff { + let our_tree = objects.find_tree_iter(our_tree, &mut side_buf)?; + gix_diff::tree_with_rewrites( + ancestor_tree, + our_tree, + diff_resource_cache, + diff_state, + objects, + |change| -> Result<_, Infallible> { + track(change, &mut our_changes); + Ok(gix_diff::tree_with_rewrites::Action::Continue) + }, + gix_diff::tree_with_rewrites::Options { + location: Some(Location::Path), + rewrites: options.rewrites, + }, + )?; + } + + let mut our_tree = TreeNodes::new(); + for (idx, change) in our_changes.iter().enumerate() { + our_tree.track_change(&change.inner, idx); + } + + let mut their_changes = Vec::new(); + if theirs_needs_diff { + let their_tree = objects.find_tree_iter(their_tree, &mut side_buf)?; + gix_diff::tree_with_rewrites( + ancestor_tree, + their_tree, + diff_resource_cache, + diff_state, + objects, + |change| -> Result<_, Infallible> { + track(change, &mut their_changes); + Ok(gix_diff::tree_with_rewrites::Action::Continue) + }, + gix_diff::tree_with_rewrites::Options { + location: Some(Location::Path), + rewrites: options.rewrites, + }, + )?; + } + + let mut their_tree = TreeNodes::new(); + for (idx, change) in their_changes.iter().enumerate() { + their_tree.track_change(&change.inner, idx); + } + + let mut conflicts = Vec::new(); + let mut failed_on_first_conflict = false; + let mut should_fail_on_conflict = |conflict: Conflict| -> bool { + if let Some(how) = options.fail_on_conflict { + if conflict.resolution.is_err() || is_unresolved(std::slice::from_ref(&conflict), how) { + failed_on_first_conflict = true; + } + } + conflicts.push(conflict); + failed_on_first_conflict + }; + + let ((mut our_changes, mut our_tree), (mut their_changes, mut their_tree)) = + ((&mut our_changes, &mut our_tree), (&mut their_changes, &mut their_tree)); + let mut outer_side = Original; + if their_changes.is_empty() { + ((our_changes, our_tree), (their_changes, their_tree)) = ((their_changes, their_tree), (our_changes, our_tree)); + (labels.current, labels.other) = (labels.other, labels.current); + outer_side = outer_side.swapped(); + } + + #[derive(Debug)] + enum MatchKind { + /// A tree is supposed to be superseded by something else. + EraseTree, + /// A leaf node is superseded by a tree + EraseLeaf, + } + + 'outer: while their_changes.iter().rev().any(|c| !c.was_written) { + let mut segment_start = 0; + let mut last_seen_len = their_changes.len(); + + while segment_start != last_seen_len { + for theirs_idx in segment_start..last_seen_len { + // `their` can be a tree, and it could be used to efficiently prune child-changes as these + // trees are always rewrites with parent ids (of course we validate), so child-changes could be handled + // quickly. However, for now the benefit of having these trees is to have them as part of the match-tree + // on *our* side so that it's clear that we passed a renamed directory (by identity). + let TrackedChange { + inner: theirs, + was_written, + needs_tree_insertion, + rewritten_location, + } = &their_changes[theirs_idx]; + if theirs.entry_mode().is_tree() || *was_written { + continue; + } + + if needs_tree_insertion.is_some() { + their_tree.insert(theirs, theirs_idx); + } + + match our_tree + .check_conflict( + rewritten_location + .as_ref() + .map_or_else(|| theirs.source_location(), |t| t.0.as_bstr()), + ) + .filter(|ours| { + ours.change_idx() + .zip(needs_tree_insertion.flatten()) + .map_or(true, |(ours_idx, ignore_idx)| ours_idx != ignore_idx) + && our_tree.is_not_same_change_in_possible_conflict(theirs, ours, our_changes) + }) { + None => { + if let Some((rewritten_location, ours_idx)) = rewritten_location { + if should_fail_on_conflict(Conflict::with_resolution( + Resolution::SourceLocationAffectedByRename { + final_location: rewritten_location.to_owned(), + }, + (&our_changes[*ours_idx].inner, theirs, Original, outer_side), + )) { + break 'outer; + }; + editor.remove(to_components(theirs.location()))?; + } + apply_change(&mut editor, theirs, rewritten_location.as_ref().map(|t| &t.0))?; + their_changes[theirs_idx].was_written = true; + } + Some(candidate) => { + use crate::tree::utils::to_components_bstring_ref as toc; + debug_assert!( + rewritten_location.is_none(), + "We should probably handle the case where a rewritten location is passed down here" + ); + + let (ours_idx, match_kind) = match candidate { + PossibleConflict::PassedRewrittenDirectory { change_idx } => { + let ours = &our_changes[change_idx]; + let location_after_passed_rename = + rewrite_location_with_renamed_directory(theirs.location(), &ours.inner); + if let Some(new_location) = location_after_passed_rename { + their_tree.remove_existing_leaf(theirs.location()); + push_deferred_with_rewrite( + (theirs.clone(), Some(change_idx)), + Some((new_location, change_idx)), + their_changes, + ); + } else { + apply_change(&mut editor, theirs, None)?; + their_changes[theirs_idx].was_written = true; + } + their_changes[theirs_idx].was_written = true; + continue; + } + PossibleConflict::TreeToNonTree { change_idx: Some(idx) } + if matches!( + our_changes[idx].inner, + Change::Deletion { .. } | Change::Addition { .. } + ) => + { + (Some(idx), Some(MatchKind::EraseTree)) + } + PossibleConflict::NonTreeToTree { change_idx } => (change_idx, Some(MatchKind::EraseLeaf)), + PossibleConflict::Match { change_idx: ours_idx } => (Some(ours_idx), None), + _ => (None, None), + }; + + let Some(ours_idx) = ours_idx else { + let ours = match candidate { + PossibleConflict::TreeToNonTree { change_idx, .. } + | PossibleConflict::NonTreeToTree { change_idx, .. } => change_idx, + PossibleConflict::Match { change_idx } + | PossibleConflict::PassedRewrittenDirectory { change_idx } => Some(change_idx), + } + .map(|idx| &our_changes[idx]); + + if let Some(ours) = ours { + gix_trace::debug!("Turning a case we could probably handle into a conflict for now. theirs: {theirs:#?} ours: {ours:#?} kind: {match_kind:?}"); + if allow_resolution_failure + && should_fail_on_conflict(Conflict::without_resolution( + ResolutionFailure::Unknown, + (&ours.inner, theirs, Original, outer_side), + )) + { + break 'outer; + }; + continue; + } else { + gix_trace::debug!("Couldn't figure out how to handle {match_kind:?} theirs: {theirs:#?} candidate: {candidate:#?}"); + continue; + } + }; + + let ours = &our_changes[ours_idx].inner; + debug_assert!( + match_kind.is_none() + || (ours.location() == theirs.location() + || ours.source_location() == theirs.source_location()), + "BUG: right now it's not known to be possible to match changes from different paths: {match_kind:?} {candidate:?}" + ); + match (ours, theirs) { + ( + Change::Modification { + previous_id, + previous_entry_mode, + id: our_id, + location: our_location, + entry_mode: our_mode, + .. + }, + Change::Rewrite { + source_id: their_source_id, + id: their_id, + location: their_location, + entry_mode: their_mode, + source_location, + .. + }, + ) + | ( + Change::Rewrite { + source_id: their_source_id, + id: their_id, + location: their_location, + entry_mode: their_mode, + source_location, + .. + }, + Change::Modification { + previous_id, + previous_entry_mode, + id: our_id, + location: our_location, + entry_mode: our_mode, + .. + }, + ) => { + let side = if matches!(ours, Change::Modification { .. }) { + Original + } else { + Swapped + }; + if let Some(merged_mode) = merge_modes(*our_mode, *their_mode) { + assert_eq!( + previous_id, their_source_id, + "both refer to the same base, so should always match" + ); + let their_rewritten_location = possibly_rewritten_location( + pick_our_tree(side, our_tree, their_tree), + their_location.as_ref(), + pick_our_changes(side, our_changes, their_changes), + ); + let renamed_without_change = their_source_id == their_id; + let (our_id, resolution) = if renamed_without_change { + (*our_id, None) + } else { + let (our_location, our_id, our_mode, their_location, their_id, their_mode) = + match side { + Original => ( + our_location, + our_id, + our_mode, + their_location, + their_id, + their_mode, + ), + Swapped => ( + their_location, + their_id, + their_mode, + our_location, + our_id, + our_mode, + ), + }; + let (merged_blob_id, resolution) = perform_blob_merge( + labels, + objects, + blob_merge, + &mut diff_state.buf1, + &mut write_blob_to_odb, + (our_location, *our_id, *our_mode), + (their_location, *their_id, *their_mode), + (source_location, *previous_id, *previous_entry_mode), + (0, outer_side), + &options, + )?; + (merged_blob_id, Some(resolution)) + }; + + editor.remove(toc(our_location))?; + pick_our_tree(side, our_tree, their_tree) + .remove_existing_leaf(our_location.as_bstr()); + let final_location = their_rewritten_location.clone(); + let new_change = Change::Addition { + location: their_rewritten_location.unwrap_or_else(|| their_location.to_owned()), + relation: None, + entry_mode: merged_mode, + id: our_id, + }; + if should_fail_on_conflict(Conflict::with_resolution( + Resolution::OursModifiedTheirsRenamedAndChangedThenRename { + merged_mode: (merged_mode != *their_mode).then_some(merged_mode), + merged_blob: resolution.map(|resolution| ContentMerge { + resolution, + merged_blob_id: our_id, + }), + final_location, + }, + (ours, theirs, side, outer_side), + )) { + break 'outer; + } + + // The other side gets the addition, not our side. + push_deferred( + (new_change, None), + pick_our_changes_mut(side, their_changes, our_changes), + ); + } else if allow_resolution_failure { + editor.upsert(toc(our_location), our_mode.kind(), *our_id)?; + editor.upsert(toc(their_location), their_mode.kind(), *their_id)?; + + if should_fail_on_conflict(Conflict::without_resolution( + ResolutionFailure::OursModifiedTheirsRenamedTypeMismatch, + (ours, theirs, side, outer_side), + )) { + break 'outer; + } + } + } + ( + Change::Modification { + location, + previous_id, + previous_entry_mode, + entry_mode: our_mode, + id: our_id, + .. + }, + Change::Modification { + entry_mode: their_mode, + id: their_id, + .. + }, + ) if !involves_submodule(our_mode, their_mode) + && our_mode.kind() == their_mode.kind() + && our_id != their_id => + { + let (merged_blob_id, resolution) = perform_blob_merge( + labels, + objects, + blob_merge, + &mut diff_state.buf1, + &mut write_blob_to_odb, + (location, *our_id, *our_mode), + (location, *their_id, *their_mode), + (location, *previous_id, *previous_entry_mode), + (0, outer_side), + &options, + )?; + editor.upsert(toc(location), our_mode.kind(), merged_blob_id)?; + if should_fail_on_conflict(Conflict::with_resolution( + Resolution::OursModifiedTheirsModifiedThenBlobContentMerge { + merged_blob: ContentMerge { + resolution, + merged_blob_id, + }, + }, + (ours, theirs, Original, outer_side), + )) { + break 'outer; + }; + } + ( + Change::Addition { + location, + entry_mode: our_mode, + id: our_id, + .. + }, + Change::Addition { + entry_mode: their_mode, + id: their_id, + .. + }, + ) if !involves_submodule(our_mode, their_mode) && our_id != their_id => { + let conflict = if let Some(merged_mode) = merge_modes(*our_mode, *their_mode) { + let side = if our_mode == their_mode || matches!(our_mode.kind(), EntryKind::Blob) { + outer_side + } else { + outer_side.swapped() + }; + let (merged_blob_id, resolution) = perform_blob_merge( + labels, + objects, + blob_merge, + &mut diff_state.buf1, + &mut write_blob_to_odb, + (location, *our_id, merged_mode), + (location, *their_id, merged_mode), + (location, their_id.kind().null(), merged_mode), + (0, side), + &options, + )?; + editor.upsert(toc(location), merged_mode.kind(), merged_blob_id)?; + Some(Conflict::with_resolution( + Resolution::OursModifiedTheirsModifiedThenBlobContentMerge { + merged_blob: ContentMerge { + resolution, + merged_blob_id, + }, + }, + (ours, theirs, Original, outer_side), + )) + } else if allow_resolution_failure { + // Actually this has a preference, as symlinks are always left in place with the other side renamed. + let ( + logical_side, + label_of_side_to_be_moved, + (our_mode, our_id), + (their_mode, their_id), + ) = if matches!(our_mode.kind(), EntryKind::Link | EntryKind::Tree) { + ( + Original, + labels.other.unwrap_or_default(), + (*our_mode, *our_id), + (*their_mode, *their_id), + ) + } else { + ( + Swapped, + labels.current.unwrap_or_default(), + (*their_mode, *their_id), + (*our_mode, *our_id), + ) + }; + let tree_with_rename = pick_our_tree(logical_side, their_tree, our_tree); + let renamed_location = unique_path_in_tree( + location.as_bstr(), + &editor, + tree_with_rename, + label_of_side_to_be_moved, + )?; + editor.upsert(toc(location), our_mode.kind(), our_id)?; + let conflict = Conflict::without_resolution( + ResolutionFailure::OursAddedTheirsAddedTypeMismatch { + their_unique_location: renamed_location.clone(), + }, + (ours, theirs, logical_side, outer_side), + ); + + let new_change = Change::Addition { + location: renamed_location, + entry_mode: their_mode, + id: their_id, + relation: None, + }; + tree_with_rename.remove_existing_leaf(location.as_bstr()); + push_deferred( + (new_change, None), + pick_our_changes_mut(logical_side, their_changes, our_changes), + ); + Some(conflict) + } else { + None + }; + + if let Some(conflict) = conflict { + if should_fail_on_conflict(conflict) { + break 'outer; + }; + } + } + ( + Change::Modification { + location, + entry_mode, + id, + .. + }, + Change::Deletion { .. }, + ) + | ( + Change::Deletion { .. }, + Change::Modification { + location, + entry_mode, + id, + .. + }, + ) if allow_resolution_failure => { + let (label_of_side_to_be_moved, side) = if matches!(ours, Change::Modification { .. }) { + (labels.current.unwrap_or_default(), Original) + } else { + (labels.other.unwrap_or_default(), Swapped) + }; + let deletion_prefaces_addition_of_directory = { + let change_on_right = match side { + Original => their_changes.get(theirs_idx + 1), + Swapped => our_changes.get(ours_idx + 1), + }; + change_on_right + .map(|change| { + change.inner.entry_mode().is_tree() && change.inner.location() == location + }) + .unwrap_or_default() + }; + + if deletion_prefaces_addition_of_directory { + let our_tree = pick_our_tree(side, our_tree, their_tree); + let renamed_path = unique_path_in_tree( + location.as_bstr(), + &editor, + our_tree, + label_of_side_to_be_moved, + )?; + editor.remove(toc(location))?; + our_tree.remove_existing_leaf(location.as_bstr()); + + let new_change = Change::Addition { + location: renamed_path.clone(), + relation: None, + entry_mode: *entry_mode, + id: *id, + }; + let should_break = should_fail_on_conflict(Conflict::without_resolution( + ResolutionFailure::OursModifiedTheirsDirectoryThenOursRenamed { + renamed_unique_path_to_modified_blob: renamed_path, + }, + (ours, theirs, side, outer_side), + )); + + // Since we move *our* side, our tree needs to be modified. + push_deferred( + (new_change, None), + pick_our_changes_mut(side, our_changes, their_changes), + ); + + if should_break { + break 'outer; + }; + } else { + let should_break = should_fail_on_conflict(Conflict::without_resolution( + ResolutionFailure::OursModifiedTheirsDeleted, + (ours, theirs, side, outer_side), + )); + editor.upsert(toc(location), entry_mode.kind(), *id)?; + if should_break { + break 'outer; + } + } + } + ( + Change::Rewrite { + source_location, + source_entry_mode, + source_id, + entry_mode: our_mode, + id: our_id, + location: our_location, + .. + }, + Change::Rewrite { + entry_mode: their_mode, + id: their_id, + location: their_location, + .. + }, + // NOTE: renames are only tracked among these kinds of types anyway, but we make sure. + ) if our_mode.is_blob_or_symlink() && their_mode.is_blob_or_symlink() => { + let (merged_blob_id, mut resolution) = if our_id == their_id { + (*our_id, None) + } else { + let (id, resolution) = perform_blob_merge( + labels, + objects, + blob_merge, + &mut diff_state.buf1, + &mut write_blob_to_odb, + (our_location, *our_id, *our_mode), + (their_location, *their_id, *their_mode), + (source_location, *source_id, *source_entry_mode), + (1, outer_side), + &options, + )?; + (id, Some(resolution)) + }; + + let merged_mode = + merge_modes(*our_mode, *their_mode).expect("this case was assured earlier"); + + editor.remove(toc(source_location))?; + our_tree.remove_existing_leaf(source_location.as_bstr()); + their_tree.remove_existing_leaf(source_location.as_bstr()); + + let their_rewritten_location = + possibly_rewritten_location(our_tree, their_location.as_bstr(), our_changes); + let our_rewritten_location = + possibly_rewritten_location(their_tree, our_location.as_bstr(), their_changes); + let (our_addition, their_addition) = + match (our_rewritten_location, their_rewritten_location) { + (None, Some(location)) => ( + None, + Some(Change::Addition { + location, + relation: None, + entry_mode: merged_mode, + id: merged_blob_id, + }), + ), + (Some(location), None) => ( + None, + Some(Change::Addition { + location, + relation: None, + entry_mode: merged_mode, + id: merged_blob_id, + }), + ), + (Some(_ours), Some(_theirs)) => { + gix_trace::debug!( + "Found two rewritten locations, '{_ours}' and '{_theirs}'" + ); + // Pretend this is the end of the loop and keep this as conflict. + // If this happens in the wild, we'd want to reproduce it. + if allow_resolution_failure + && should_fail_on_conflict(Conflict::without_resolution( + ResolutionFailure::Unknown, + (ours, theirs, Original, outer_side), + )) + { + break 'outer; + }; + their_changes[theirs_idx].was_written = true; + our_changes[ours_idx].was_written = true; + continue; + } + (None, None) => { + if our_location == their_location { + ( + None, + Some(Change::Addition { + location: our_location.to_owned(), + relation: None, + entry_mode: merged_mode, + id: merged_blob_id, + }), + ) + } else { + if !allow_resolution_failure { + their_changes[theirs_idx].was_written = true; + our_changes[ours_idx].was_written = true; + continue; + } + if should_fail_on_conflict(Conflict::without_resolution( + ResolutionFailure::OursRenamedTheirsRenamedDifferently { + merged_blob: resolution.take().map(|resolution| ContentMerge { + resolution, + merged_blob_id, + }), + }, + (ours, theirs, Original, outer_side), + )) { + break 'outer; + }; + let our_addition = Change::Addition { + location: our_location.to_owned(), + relation: None, + entry_mode: merged_mode, + id: merged_blob_id, + }; + let their_addition = Change::Addition { + location: their_location.to_owned(), + relation: None, + entry_mode: merged_mode, + id: merged_blob_id, + }; + (Some(our_addition), Some(their_addition)) + } + } + }; + + if let Some(resolution) = resolution { + if should_fail_on_conflict(Conflict::with_resolution( + Resolution::OursModifiedTheirsModifiedThenBlobContentMerge { + merged_blob: ContentMerge { + resolution, + merged_blob_id, + }, + }, + (ours, theirs, Original, outer_side), + )) { + break 'outer; + }; + } + if let Some(addition) = our_addition { + push_deferred((addition, Some(ours_idx)), our_changes); + } + if let Some(addition) = their_addition { + push_deferred((addition, Some(theirs_idx)), their_changes); + } + } + ( + Change::Deletion { .. }, + Change::Rewrite { + source_location, + entry_mode: rewritten_mode, + id: rewritten_id, + location, + .. + }, + ) + | ( + Change::Rewrite { + source_location, + entry_mode: rewritten_mode, + id: rewritten_id, + location, + .. + }, + Change::Deletion { .. }, + ) if !rewritten_mode.is_commit() && allow_resolution_failure => { + let side = if matches!(ours, Change::Deletion { .. }) { + Original + } else { + Swapped + }; + + editor.remove(toc(source_location))?; + pick_our_tree(side, our_tree, their_tree) + .remove_existing_leaf(source_location.as_bstr()); + + let their_rewritten_location = possibly_rewritten_location( + pick_our_tree(side, our_tree, their_tree), + location.as_ref(), + pick_our_changes(side, our_changes, their_changes), + ) + .unwrap_or_else(|| location.to_owned()); + let our_addition = Change::Addition { + location: their_rewritten_location, + relation: None, + entry_mode: *rewritten_mode, + id: *rewritten_id, + }; + + if should_fail_on_conflict(Conflict::without_resolution( + ResolutionFailure::OursDeletedTheirsRenamed, + (ours, theirs, side, outer_side), + )) { + break 'outer; + }; + + push_deferred( + (our_addition, None), + pick_our_changes_mut(side, their_changes, our_changes), + ); + } + ( + Change::Rewrite { + source_location, + source_entry_mode, + source_id, + entry_mode: our_mode, + id: our_id, + location, + .. + }, + Change::Addition { + id: their_id, + entry_mode: their_mode, + .. + }, + ) + | ( + Change::Addition { + id: their_id, + entry_mode: their_mode, + .. + }, + Change::Rewrite { + source_location, + source_entry_mode, + source_id, + entry_mode: our_mode, + id: our_id, + location, + .. + }, + ) if !involves_submodule(our_mode, their_mode) => { + let side = if matches!(ours, Change::Rewrite { .. }) { + Original + } else { + Swapped + }; + if let Some(merged_mode) = merge_modes(*our_mode, *their_mode) { + let (merged_blob_id, resolution) = if our_id == their_id { + (*our_id, None) + } else { + let (id, resolution) = perform_blob_merge( + labels, + objects, + blob_merge, + &mut diff_state.buf1, + &mut write_blob_to_odb, + (location, *our_id, *our_mode), + (location, *their_id, *their_mode), + (source_location, source_id.kind().null(), *source_entry_mode), + (0, outer_side), + &options, + )?; + (id, Some(resolution)) + }; + + editor.remove(toc(source_location))?; + pick_our_tree(side, our_tree, their_tree).remove_leaf(source_location.as_bstr()); + + if let Some(resolution) = resolution { + if should_fail_on_conflict(Conflict::with_resolution( + Resolution::OursModifiedTheirsModifiedThenBlobContentMerge { + merged_blob: ContentMerge { + resolution, + merged_blob_id, + }, + }, + (ours, theirs, Original, outer_side), + )) { + break 'outer; + }; + } + + // Because this constellation can only be found by the lookup tree, there is + // no need to put it as addition, we know it's not going to intersect on the other side. + editor.upsert(toc(location), merged_mode.kind(), merged_blob_id)?; + } else if allow_resolution_failure { + editor.remove(toc(source_location))?; + pick_our_tree(side, our_tree, their_tree).remove_leaf(source_location.as_bstr()); + + let ( + logical_side, + label_of_side_to_be_moved, + (our_mode, our_id), + (their_mode, their_id), + ) = if matches!(our_mode.kind(), EntryKind::Link | EntryKind::Tree) { + ( + Original, + labels.other.unwrap_or_default(), + (*our_mode, *our_id), + (*their_mode, *their_id), + ) + } else { + ( + Swapped, + labels.current.unwrap_or_default(), + (*their_mode, *their_id), + (*our_mode, *our_id), + ) + }; + let tree_with_rename = pick_our_tree(logical_side, their_tree, our_tree); + let renamed_location = unique_path_in_tree( + location.as_bstr(), + &editor, + tree_with_rename, + label_of_side_to_be_moved, + )?; + editor.upsert(toc(location), our_mode.kind(), our_id)?; + let conflict = Conflict::without_resolution( + ResolutionFailure::OursAddedTheirsAddedTypeMismatch { + their_unique_location: renamed_location.clone(), + }, + (ours, theirs, side, outer_side), + ); + + let new_change_with_rename = Change::Addition { + location: renamed_location, + entry_mode: their_mode, + id: their_id, + relation: None, + }; + tree_with_rename.remove_existing_leaf(location.as_bstr()); + push_deferred( + ( + new_change_with_rename, + Some(pick_idx(logical_side, theirs_idx, ours_idx)), + ), + pick_our_changes_mut(logical_side, their_changes, our_changes), + ); + + if should_fail_on_conflict(conflict) { + break 'outer; + } + } + } + _unknown => { + if allow_resolution_failure + && should_fail_on_conflict(Conflict::without_resolution( + ResolutionFailure::Unknown, + (ours, theirs, Original, outer_side), + )) + { + break 'outer; + }; + } + } + their_changes[theirs_idx].was_written = true; + our_changes[ours_idx].was_written = true; + } + } + } + segment_start = last_seen_len; + last_seen_len = their_changes.len(); + } + + ((our_changes, our_tree), (their_changes, their_tree)) = ((their_changes, their_tree), (our_changes, our_tree)); + (labels.current, labels.other) = (labels.other, labels.current); + outer_side = outer_side.swapped(); + } + + Ok(Outcome { + tree: editor, + conflicts, + failed_on_first_unresolved_conflict: failed_on_first_conflict, + }) +} + +pub(super) fn is_unresolved(conflicts: &[Conflict], how: UnresolvedConflict) -> bool { + match how { + UnresolvedConflict::ConflictMarkers => conflicts.iter().any(|c| { + c.resolution.is_err() + || c.content_merge().map_or(false, |info| { + matches!(info.resolution, crate::blob::Resolution::Conflict) + }) + }), + UnresolvedConflict::Renames => conflicts.iter().any(|c| match &c.resolution { + Ok(success) => match success { + Resolution::SourceLocationAffectedByRename { .. } + | Resolution::OursModifiedTheirsRenamedAndChangedThenRename { .. } => true, + Resolution::OursModifiedTheirsModifiedThenBlobContentMerge { merged_blob } => { + matches!(merged_blob.resolution, crate::blob::Resolution::Conflict) + } + }, + Err(_failure) => true, + }), + } +} + +fn involves_submodule(a: &EntryMode, b: &EntryMode) -> bool { + a.is_commit() || b.is_commit() +} + +/// Allows equal modes or preferes executables bits in case of blobs +fn merge_modes(a: EntryMode, b: EntryMode) -> Option { + match (a.kind(), b.kind()) { + (EntryKind::BlobExecutable, EntryKind::BlobExecutable | EntryKind::Blob) + | (EntryKind::Blob, EntryKind::BlobExecutable) => Some(EntryKind::BlobExecutable.into()), + (_, _) if a == b => Some(a), + _ => None, + } +} + +fn push_deferred(change_and_idx: (Change, Option), changes: &mut ChangeList) { + push_deferred_with_rewrite(change_and_idx, None, changes); +} + +fn push_deferred_with_rewrite( + (change, ours_idx): (Change, Option), + new_location: Option<(BString, usize)>, + changes: &mut ChangeList, +) { + changes.push(TrackedChange { + inner: change, + was_written: false, + needs_tree_insertion: Some(ours_idx), + rewritten_location: new_location, + }); +} + +fn pick_our_tree<'a>(side: ConflictMapping, ours: &'a mut TreeNodes, theirs: &'a mut TreeNodes) -> &'a mut TreeNodes { + match side { + Original => ours, + Swapped => theirs, + } +} + +fn pick_our_changes<'a>( + side: ConflictMapping, + ours: &'a ChangeListRef, + theirs: &'a ChangeListRef, +) -> &'a ChangeListRef { + match side { + Original => ours, + Swapped => theirs, + } +} + +fn pick_idx(side: ConflictMapping, ours: usize, theirs: usize) -> usize { + match side { + Original => ours, + Swapped => theirs, + } +} + +fn pick_our_changes_mut<'a>( + side: ConflictMapping, + ours: &'a mut ChangeList, + theirs: &'a mut ChangeList, +) -> &'a mut ChangeList { + match side { + Original => ours, + Swapped => theirs, + } +} diff --git a/gix-merge/src/tree/mod.rs b/gix-merge/src/tree/mod.rs new file mode 100644 index 00000000000..cfc47e6de28 --- /dev/null +++ b/gix-merge/src/tree/mod.rs @@ -0,0 +1,260 @@ +use bstr::BString; +use gix_diff::tree_with_rewrites::Change; +use gix_diff::Rewrites; + +/// The error returned by [`tree()`](crate::tree()). +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum Error { + #[error("Could not find ancestor, our or their tree to get started")] + FindTree(#[from] gix_object::find::existing_object::Error), + #[error("Could not find ancestor, our or their tree iterator to get started")] + FindTreeIter(#[from] gix_object::find::existing_iter::Error), + #[error("Failed to diff our side or their side")] + DiffTree(#[from] gix_diff::tree_with_rewrites::Error), + #[error("Could not apply merge result to base tree")] + TreeEdit(#[from] gix_object::tree::editor::Error), + #[error("Failed to load resource to prepare for blob merge")] + BlobMergeSetResource(#[from] crate::blob::platform::set_resource::Error), + #[error(transparent)] + BlobMergePrepare(#[from] crate::blob::platform::prepare_merge::Error), + #[error(transparent)] + BlobMerge(#[from] crate::blob::platform::merge::Error), + #[error("Failed to write merged blob content as blob to the object database")] + WriteBlobToOdb(Box), + #[error("The merge was performed, but the binary merge result couldn't be selected as it wasn't found")] + MergeResourceNotFound, +} + +/// The outcome produced by [`tree()`](crate::tree()). +#[derive(Clone)] +pub struct Outcome<'a> { + /// The ready-made (but unwritten) which is the *base* tree, including all non-conflicting changes, and the changes that had + /// conflicts which could be resolved automatically. + /// + /// This means, if all of their changes were conflicting, this will be equivalent to the *base* tree. + pub tree: gix_object::tree::Editor<'a>, + /// The set of conflicts we encountered. Can be empty to indicate there was no conflict. + /// Note that conflicts might have been auto-resolved, but they are listed here for completeness. + /// Use [`has_unresolved_conflicts()`](Outcome::has_unresolved_conflicts()) to see if any action is needed + /// before using [`tree`](Outcome::tree). + pub conflicts: Vec, + /// `true` if `conflicts` contains only a single *unresolved* conflict in the last slot, but possibly more resolved ones. + /// This also makes this outcome a very partial merge that cannot be completed. + /// Only set if [`fail_on_conflict`](Options::fail_on_conflict) is `true`. + pub failed_on_first_unresolved_conflict: bool, +} + +/// Determine what should be considered an unresolved conflict. +/// +/// Note that no matter which variant, [conflicts](Conflict) with [resolution failure](`ResolutionFailure`) +/// will always be unresolved. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum UnresolvedConflict { + /// Only consider content merges with conflict markers as unresolved. + ConflictMarkers, + /// Whenever there was any rename, or conflict markers, it is unresolved. + Renames, +} + +impl Outcome<'_> { + /// Return `true` if there is any conflict that would still need to be resolved as they would yield undesirable trees. + /// This is based on `how` to determine what should be considered unresolved. + pub fn has_unresolved_conflicts(&self, how: UnresolvedConflict) -> bool { + function::is_unresolved(&self.conflicts, how) + } +} + +/// A description of a conflict (i.e. merge issue without an auto-resolution) as seen during a [tree-merge](crate::tree()). +/// They may have a resolution that was applied automatically, or be left for the caller to resolved. +#[derive(Debug, Clone)] +pub struct Conflict { + /// A record on how the conflict resolution succeeded with `Ok(_)` or failed with `Err(_)`. + /// In case of `Err(_)`, no write + /// On failure, one can examine `ours` and `theirs` to potentially find a custom solution. + /// Note that the descriptions of resolutions or resolution failures may be swapped compared + /// to the actual changes. This is due to changes like `modification|deletion` being treated the + /// same as `deletion|modification`, i.e. *ours* is not more privileged than theirs. + /// To compensate for that, use [`changes_in_resolution()`](Conflict::changes_in_resolution()). + pub resolution: Result, + /// The change representing *our* side. + pub ours: Change, + /// The change representing *their* side. + pub theirs: Change, + map: ConflictMapping, +} + +/// A utility to help define which side is what. +#[derive(Debug, Clone, Copy)] +enum ConflictMapping { + Original, + Swapped, +} + +impl ConflictMapping { + fn is_swapped(&self) -> bool { + matches!(self, ConflictMapping::Swapped) + } + fn swapped(self) -> ConflictMapping { + match self { + ConflictMapping::Original => ConflictMapping::Swapped, + ConflictMapping::Swapped => ConflictMapping::Original, + } + } +} + +impl Conflict { + /// Returns the changes of fields `ours` and `theirs` so they match their description in the + /// [`Resolution`] or [`ResolutionFailure`] respectively. + /// Without this, the sides may appear swapped as `ours|theirs` is treated the same as `theirs/ours` + /// if both types are different, like `modification|deletion`. + pub fn changes_in_resolution(&self) -> (&Change, &Change) { + match self.map { + ConflictMapping::Original => (&self.ours, &self.theirs), + ConflictMapping::Swapped => (&self.theirs, &self.ours), + } + } + + /// Similar to [`changes_in_resolution()`](Self::changes_in_resolution()), but returns the parts + /// of the structure so the caller can take ownership. This can be useful when applying your own + /// resolutions for resolution failures. + pub fn into_parts_by_resolution(self) -> (Result, Change, Change) { + match self.map { + ConflictMapping::Original => (self.resolution, self.ours, self.theirs), + ConflictMapping::Swapped => (self.resolution, self.theirs, self.ours), + } + } + + /// Return information about the content merge if it was performed. + pub fn content_merge(&self) -> Option { + match &self.resolution { + Ok(success) => match success { + Resolution::SourceLocationAffectedByRename { .. } => None, + Resolution::OursModifiedTheirsRenamedAndChangedThenRename { merged_blob, .. } => *merged_blob, + Resolution::OursModifiedTheirsModifiedThenBlobContentMerge { merged_blob } => Some(*merged_blob), + }, + Err(failure) => match failure { + ResolutionFailure::OursRenamedTheirsRenamedDifferently { merged_blob } => *merged_blob, + ResolutionFailure::Unknown + | ResolutionFailure::OursModifiedTheirsDeleted + | ResolutionFailure::OursModifiedTheirsRenamedTypeMismatch + | ResolutionFailure::OursModifiedTheirsDirectoryThenOursRenamed { + renamed_unique_path_to_modified_blob: _, + } + | ResolutionFailure::OursAddedTheirsAddedTypeMismatch { .. } + | ResolutionFailure::OursDeletedTheirsRenamed => None, + }, + } + } +} + +/// Describes of a conflict involving *our* change and *their* change was specifically resolved. +/// +/// Note that all resolutions are side-agnostic, so *ours* could also have been *theirs* and vice versa. +/// Also note that symlink merges are always done via binary merge, using the same logic. +#[derive(Debug, Clone)] +pub enum Resolution { + /// *ours* had a renamed directory and *theirs* made a change in the now renamed directory. + /// We moved that change into its location. + SourceLocationAffectedByRename { + /// The repository-relative path to the location that the change ended up in after + /// being affected by a renamed directory. + final_location: BString, + }, + /// *ours* was a modified blob and *theirs* renamed that blob. + /// We moved the changed blob from *ours* to its new location, and merged it successfully. + /// If this is a `copy`, the source of the copy was set to be the changed blob as well so both match. + OursModifiedTheirsRenamedAndChangedThenRename { + /// If one side added the executable bit, we always add it in the merged result. + merged_mode: Option, + /// If `Some(…)`, the content of the involved blob had to be merged. + merged_blob: Option, + /// The repository relative path to the location the blob finally ended up in. + /// It's `Some()` only if *they* rewrote the blob into a directory which *we* renamed on *our* side. + final_location: Option, + }, + /// *ours* and *theirs* carried changes and where content-merged. + /// + /// Note that *ours* and *theirs* may also be rewrites with the same destination and mode, + /// or additions. + OursModifiedTheirsModifiedThenBlobContentMerge { + /// The outcome of the content merge. + merged_blob: ContentMerge, + }, +} + +/// Describes of a conflict involving *our* change and *their* failed to be resolved. +#[derive(Debug, Clone)] +pub enum ResolutionFailure { + /// *ours* was renamed, but *theirs* was renamed differently. Both versions will be present in the tree, + OursRenamedTheirsRenamedDifferently { + /// If `Some(…)`, the content of the involved blob had to be merged. + merged_blob: Option, + }, + /// *ours* was modified, but *theirs* was turned into a directory, so *ours* was renamed to a non-conflicting path. + OursModifiedTheirsDirectoryThenOursRenamed { + /// The path at which `ours` can be found in the tree - it's in the same directory that it was in before. + renamed_unique_path_to_modified_blob: BString, + }, + /// *ours* was added (or renamed into place) with a different mode than theirs, e.g. blob and symlink, and we kept + /// the symlink in its original location, renaming the other side to `their_unique_location`. + OursAddedTheirsAddedTypeMismatch { + /// The location at which *their* state was placed to resolve the name and type clash, named to indicate + /// where the entry is coming from. + their_unique_location: BString, + }, + /// *ours* was modified, and they renamed the same file, but there is also a non-mergable type-change. + /// Here we keep both versions of the file. + OursModifiedTheirsRenamedTypeMismatch, + /// *ours* was deleted, but *theirs* was renamed. + OursDeletedTheirsRenamed, + /// *ours* was modified and *theirs* was deleted. We keep the modified one and ignore the deletion. + OursModifiedTheirsDeleted, + /// *ours* and *theirs* are in an untested state so it can't be handled yet, and is considered a conflict + /// without adding our *or* their side to the resulting tree. + Unknown, +} + +/// Information about a blob content merge for use in a [`Resolution`]. +/// Note that content merges always count as success to avoid duplication of cases, which forces callers +/// to check for the [`resolution`](Self::resolution) field. +#[derive(Debug, Copy, Clone)] +pub struct ContentMerge { + /// The fully merged blob. + pub merged_blob_id: gix_hash::ObjectId, + /// Identify the kind of resolution of the blob merge. Note that it may be conflicting. + pub resolution: crate::blob::Resolution, +} + +/// A way to configure [`tree()`](crate::tree()). +#[derive(Default, Debug, Clone)] +pub struct Options { + /// If *not* `None`, rename tracking will be performed when determining the changes of each side of the merge. + pub rewrites: Option, + /// Decide how blob-merges should be done. This relates to if conflicts can be resolved or not. + pub blob_merge: crate::blob::platform::merge::Options, + /// The context to use when invoking merge-drivers. + pub blob_merge_command_ctx: gix_command::Context, + /// If `Some(what-is-unresolved)`, the first unresolved conflict will cause the entire merge to stop. + /// This is useful to see if there is any conflict, without performing the whole operation. + // TODO: Maybe remove this if the cost of figuring out conflicts is so low - after all, the data structures + // and initial diff is the expensive thing right now, which are always done upfront. + // However, this could change once we know do everything during the traversal, which probably doesn't work + // without caching stuff and is too complicated to actually do. + pub fail_on_conflict: Option, + /// This value also affects the size of merge-conflict markers, to allow differentiating + /// merge conflicts on each level, for any value greater than 0, with values `N` causing `N*2` + /// markers to be added to the configured value. + /// + /// This is used automatically when merging merge-bases recursively. + pub marker_size_multiplier: u8, + /// If `None`, when symlinks clash *ours* will be chosen and a conflict will occur. + /// Otherwise, the same logic applies as for the merge of binary resources. + pub symlink_conflicts: Option, + /// If `true`, instead of issuing a conflict with [`ResolutionFailure`], do nothing and keep the base/ancestor + /// version. This is useful when one wants to avoid any kind of merge-conflict to have *some*, *lossy* resolution. + pub allow_lossy_resolution: bool, +} + +pub(super) mod function; +mod utils; diff --git a/gix-merge/src/tree/utils.rs b/gix-merge/src/tree/utils.rs new file mode 100644 index 00000000000..cd37f809e1e --- /dev/null +++ b/gix-merge/src/tree/utils.rs @@ -0,0 +1,572 @@ +//! ## About `debug_assert!() +//! +//! The idea is to have code that won't panic in production. Thus, if in production that assertion would fail, +//! we will rather let the code run and hope it will either be correct enough or fail in more graceful ways later. +//! +//! Once such a case becomes a bug and is reproduced in testing, the debug-assertion will kick in and hopefully +//! contribute to finding a fix faster. +use crate::blob::builtin_driver::binary::Pick; +use crate::blob::ResourceKind; +use crate::tree::{Conflict, ConflictMapping, Error, Options, Resolution, ResolutionFailure}; +use bstr::ByteSlice; +use bstr::{BStr, BString, ByteVec}; +use gix_diff::tree_with_rewrites::{Change, ChangeRef}; +use gix_hash::ObjectId; +use gix_object::tree; +use gix_object::tree::{EntryKind, EntryMode}; +use std::collections::HashMap; + +/// Assuming that `their_location` is the destination of *their* rewrite, check if *it* passes +/// over a directory rewrite in *our* tree. If so, rewrite it so that we get the path +/// it would have had if it had been renamed along with *our* directory. +pub fn possibly_rewritten_location( + check_tree: &mut TreeNodes, + their_location: &BStr, + our_changes: &ChangeListRef, +) -> Option { + check_tree.check_conflict(their_location).and_then(|pc| match pc { + PossibleConflict::PassedRewrittenDirectory { change_idx } => { + let passed_change = &our_changes[change_idx]; + rewrite_location_with_renamed_directory(their_location, &passed_change.inner) + } + _ => None, + }) +} + +pub fn rewrite_location_with_renamed_directory(their_location: &BStr, passed_change: &Change) -> Option { + match passed_change { + Change::Rewrite { + source_location, + location, + .. + } if passed_change.entry_mode().is_tree() => { + // This is safe even without dealing with slashes as we found this rewrite + // by walking each component, and we know it's a tree for added safety. + let suffix = their_location.strip_prefix(source_location.as_bytes())?; + let mut rewritten = location.to_owned(); + rewritten.push_str(suffix); + Some(rewritten) + } + _ => None, + } +} + +/// Produce a unique path within the directory that contains the file at `file_path` like `a/b`, using `editor` +/// and `tree` to assure unique names, to obtain the tree at `a/` and `side_name` to more clearly signal +/// where the file is coming from. +pub fn unique_path_in_tree( + file_path: &BStr, + editor: &tree::Editor<'_>, + tree: &mut TreeNodes, + side_name: &BStr, +) -> Result { + let mut buf = file_path.to_owned(); + buf.push(b'~'); + buf.extend( + side_name + .as_bytes() + .iter() + .copied() + .map(|b| if b == b'/' { b'_' } else { b }), + ); + + // We could use a cursor here, but clashes are so unlikely that this wouldn't be meaningful for performance. + let base_len = buf.len(); + let mut suffix = 0; + while editor.get(to_components_bstring_ref(&buf)).is_some() || tree.check_conflict(buf.as_bstr()).is_some() { + buf.truncate(base_len); + buf.push_str(format!("_{suffix}",)); + suffix += 1; + } + Ok(buf) +} + +/// Perform a merge between two blobs and return the result of its object id. +#[allow(clippy::too_many_arguments)] +pub fn perform_blob_merge( + mut labels: crate::blob::builtin_driver::text::Labels<'_>, + objects: &impl gix_object::FindObjectOrHeader, + blob_merge: &mut crate::blob::Platform, + buf: &mut Vec, + write_blob_to_odb: &mut impl FnMut(&[u8]) -> Result, + (our_location, our_id, our_mode): (&BString, ObjectId, EntryMode), + (their_location, their_id, their_mode): (&BString, ObjectId, EntryMode), + (previous_location, previous_id, previous_mode): (&BString, ObjectId, EntryMode), + (extra_markers, outer_side): (u8, ConflictMapping), + options: &Options, +) -> Result<(ObjectId, crate::blob::Resolution), Error> +where + E: Into>, +{ + if matches!(our_mode.kind(), EntryKind::Link) && matches!(their_mode.kind(), EntryKind::Link) { + let (pick, resolution) = crate::blob::builtin_driver::binary(options.symlink_conflicts); + let (our_id, their_id) = match outer_side { + ConflictMapping::Original => (our_id, their_id), + ConflictMapping::Swapped => (their_id, our_id), + }; + let id = match pick { + Pick::Ancestor => previous_id, + Pick::Ours => our_id, + Pick::Theirs => their_id, + }; + return Ok((id, resolution)); + } + let (our_kind, their_kind) = match outer_side { + ConflictMapping::Original => (ResourceKind::CurrentOrOurs, ResourceKind::OtherOrTheirs), + ConflictMapping::Swapped => (ResourceKind::OtherOrTheirs, ResourceKind::CurrentOrOurs), + }; + blob_merge.set_resource(our_id, our_mode.kind(), our_location.as_bstr(), our_kind, objects)?; + blob_merge.set_resource( + their_id, + their_mode.kind(), + their_location.as_bstr(), + their_kind, + objects, + )?; + blob_merge.set_resource( + previous_id, + previous_mode.kind(), + previous_location.as_bstr(), + ResourceKind::CommonAncestorOrBase, + objects, + )?; + + fn combined(side: &BStr, location: &BString) -> BString { + let mut buf = side.to_owned(); + buf.push_byte(b':'); + buf.push_str(location); + buf + } + + if outer_side.is_swapped() { + (labels.current, labels.other) = (labels.other, labels.current); + } + + let (ancestor, current, other); + let labels = if our_location == their_location { + labels + } else { + ancestor = labels.ancestor.map(|side| combined(side, previous_location)); + current = labels.current.map(|side| combined(side, our_location)); + other = labels.other.map(|side| combined(side, their_location)); + crate::blob::builtin_driver::text::Labels { + ancestor: ancestor.as_ref().map(|n| n.as_bstr()), + current: current.as_ref().map(|n| n.as_bstr()), + other: other.as_ref().map(|n| n.as_bstr()), + } + }; + let prep = blob_merge.prepare_merge(objects, with_extra_markers(options, extra_markers))?; + let (pick, resolution) = prep.merge(buf, labels, &options.blob_merge_command_ctx)?; + + let merged_blob_id = prep + .id_by_pick(pick, buf, write_blob_to_odb) + .map_err(|err| Error::WriteBlobToOdb(err.into()))? + .ok_or(Error::MergeResourceNotFound)?; + Ok((merged_blob_id, resolution)) +} + +fn with_extra_markers(opts: &Options, extra_makers: u8) -> crate::blob::platform::merge::Options { + let mut out = opts.blob_merge; + if let crate::blob::builtin_driver::text::Conflict::Keep { marker_size, .. } = &mut out.text.conflict { + *marker_size = + marker_size.saturating_add(extra_makers.saturating_add(opts.marker_size_multiplier.saturating_mul(2))); + } + out +} + +/// A way to attach metadata to each change. +#[derive(Debug)] +pub struct TrackedChange { + /// The actual change + pub inner: Change, + /// If `true`, this change counts as written to the tree using a [`tree::Editor`]. + pub was_written: bool, + /// If `Some(ours_idx_to_ignore)`, this change must be placed into the tree before handling it. + /// This makes sure that new changes aren't visible too early, which would mean the algorithm + /// knows things too early which can be misleading. + /// The `ours_idx_to_ignore` assures that the same rewrite won't be used as matching side, which + /// would lead to strange effects. Only set if it's a rewrite though. + pub needs_tree_insertion: Option>, + /// A new `(location, change_idx)` pair for the change that can happen if the location is touching a rewrite in a parent + /// directory, but otherwise doesn't have a match. This means we shall redo the operation but with + /// the changed path. + /// The second tuple entry `change_idx` is the change-idx we passed over, which refers to the other side that interfered. + pub rewritten_location: Option<(BString, usize)>, +} + +pub type ChangeList = Vec; +pub type ChangeListRef = [TrackedChange]; + +/// Only keep leaf nodes, or trees that are the renamed, pushing `change` on `changes`. +/// Doing so makes it easy to track renamed or rewritten or copied directories, and properly +/// handle *their* changes that fall within them. +/// Note that it also rewrites `change` if it is a copy, turning it into an addition so copies don't have an effect +/// on the merge algorithm. +pub fn track(change: ChangeRef<'_>, changes: &mut ChangeList) { + if change.entry_mode().is_tree() && matches!(change, ChangeRef::Modification { .. }) { + return; + } + let is_tree = change.entry_mode().is_tree(); + changes.push(TrackedChange { + inner: match change.into_owned() { + Change::Rewrite { + id, + entry_mode, + location, + relation, + copy, + .. + } if copy => Change::Addition { + location, + relation, + entry_mode, + id, + }, + other => other, + }, + was_written: is_tree, + needs_tree_insertion: None, + rewritten_location: None, + }); +} + +/// Unconditionally apply `change` to `editor`. +pub fn apply_change( + editor: &mut tree::Editor<'_>, + change: &Change, + alternative_location: Option<&BString>, +) -> Result<(), tree::editor::Error> { + use to_components_bstring_ref as to_components; + if change.entry_mode().is_tree() { + return Ok(()); + } + + let (location, mode, id) = match change { + Change::Addition { + location, + entry_mode, + id, + .. + } + | Change::Modification { + location, + entry_mode, + id, + .. + } => (location, entry_mode, id), + Change::Deletion { location, .. } => { + editor.remove(to_components(alternative_location.unwrap_or(location)))?; + return Ok(()); + } + Change::Rewrite { + source_location, + entry_mode, + id, + location, + copy, + .. + } => { + if !*copy { + editor.remove(to_components(source_location))?; + } + (location, entry_mode, id) + } + }; + + editor.upsert( + to_components(alternative_location.unwrap_or(location)), + mode.kind(), + *id, + )?; + Ok(()) +} + +/// A potential conflict that needs to be checked. It comes in several varieties and always happens +/// if paths overlap in some way between *theirs* and *ours*. +#[derive(Debug)] +pub enum PossibleConflict { + /// *our* changes have a tree here, but *they* place a non-tree or edit an existing item (that we removed). + TreeToNonTree { + /// The possibly available change at this node. + change_idx: Option, + }, + /// A non-tree in *our* tree turned into a tree in *theirs* - this can be done with additions in *theirs*, + /// or if we added a blob, while they added a directory. + NonTreeToTree { + /// The possibly available change at this node. + change_idx: Option, + }, + /// A perfect match, i.e. *our* change at `a/b/c` corresponds to *their* change at the same path. + Match { + /// The index to *our* change at *their* path. + change_idx: usize, + }, + /// *their* change at `a/b/c` passed `a/b` which is an index to *our* change indicating a directory that was rewritten, + /// with all its contents being renamed. However, *theirs* has been added *into* that renamed directory. + PassedRewrittenDirectory { change_idx: usize }, +} + +impl PossibleConflict { + pub(super) fn change_idx(&self) -> Option { + match self { + PossibleConflict::TreeToNonTree { change_idx, .. } | PossibleConflict::NonTreeToTree { change_idx, .. } => { + *change_idx + } + PossibleConflict::Match { change_idx, .. } + | PossibleConflict::PassedRewrittenDirectory { change_idx, .. } => Some(*change_idx), + } + } +} + +/// The flat list of all tree-nodes so we can avoid having a linked-tree using pointers +/// which is useful for traversal and initial setup as that can then trivially be non-recursive. +pub struct TreeNodes(Vec); + +/// Trees lead to other trees, or leafs (without children), and it can be represented by a renamed directory. +#[derive(Debug, Default, Clone)] +struct TreeNode { + /// A mapping of path components to their children to quickly see if `theirs` in some way is potentially + /// conflicting with `ours`. + children: HashMap, + /// The index to a change, which is always set if this is a leaf node (with no children), and if there are children and this + /// is a rewritten tree. + change_idx: Option, + /// Keep track of where the location of this node is derived from. + location: ChangeLocation, +} + +#[derive(Debug, Default, Clone, Copy)] +enum ChangeLocation { + /// The change is at its current (and only) location, or in the source location of a rename. + #[default] + CurrentLocation, + /// This is always the destination of a rename. + RenamedLocation, +} + +impl TreeNode { + fn is_leaf_node(&self) -> bool { + self.children.is_empty() + } +} + +impl TreeNodes { + pub fn new() -> Self { + TreeNodes(vec![TreeNode::default()]) + } + + /// Insert our `change` at `change_idx`, into a linked-tree, assuring that each `change` is non-conflicting + /// with this tree structure, i.e. each leaf path is only seen once. + /// Note that directories can be added in between. + pub fn track_change(&mut self, change: &Change, change_idx: usize) { + for (path, location_hint) in [ + Some((change.source_location(), ChangeLocation::CurrentLocation)), + match change { + Change::Addition { .. } | Change::Deletion { .. } | Change::Modification { .. } => None, + Change::Rewrite { location, .. } => Some((location.as_bstr(), ChangeLocation::RenamedLocation)), + }, + ] + .into_iter() + .flatten() + { + let mut components = to_components(path).peekable(); + let mut next_index = self.0.len(); + let mut cursor = &mut self.0[0]; + while let Some(component) = components.next() { + let is_last = components.peek().is_none(); + match cursor.children.get(component).copied() { + None => { + let new_node = TreeNode { + children: Default::default(), + change_idx: is_last.then_some(change_idx), + location: location_hint, + }; + cursor.children.insert(component.to_owned(), next_index); + self.0.push(new_node); + cursor = &mut self.0[next_index]; + next_index += 1; + } + Some(index) => { + cursor = &mut self.0[index]; + if is_last && !cursor.is_leaf_node() { + assert_eq!( + cursor.change_idx, None, + "BUG: each node should only see a single change when tracking initially: {path} {change_idx}" + ); + cursor.change_idx = Some(change_idx); + } + } + } + } + } + } + + /// Search the tree with `our` changes for `theirs` by [`source_location()`](Change::source_location())). + /// If there is an entry but both are the same, or if there is no entry, return `None`. + pub fn check_conflict(&mut self, theirs_location: &BStr) -> Option { + if self.0.len() == 1 { + return None; + } + let components = to_components(theirs_location); + let mut cursor = &mut self.0[0]; + let mut cursor_idx = 0; + let mut intermediate_change = None; + for component in components { + if cursor.change_idx.is_some() { + intermediate_change = cursor.change_idx.map(|change_idx| (change_idx, cursor_idx)); + } + match cursor.children.get(component).copied() { + // *their* change is outside *our* tree + None => { + let res = if cursor.is_leaf_node() { + Some(PossibleConflict::NonTreeToTree { + change_idx: cursor.change_idx, + }) + } else { + // a change somewhere else, i.e. `a/c` and we know `a/b` only. + intermediate_change.and_then(|(change, cursor_idx)| { + let cursor = &mut self.0[cursor_idx]; + // If this is a destination location of a rename, then the `their_location` + // is already at the right spot, and we can just ignore it. + if matches!(cursor.location, ChangeLocation::CurrentLocation) { + Some(PossibleConflict::PassedRewrittenDirectory { change_idx: change }) + } else { + None + } + }) + }; + return res; + } + Some(child_idx) => { + cursor_idx = child_idx; + cursor = &mut self.0[cursor_idx]; + } + } + } + + if cursor.is_leaf_node() { + PossibleConflict::Match { + change_idx: cursor.change_idx.expect("leaf nodes always have a change"), + } + } else { + PossibleConflict::TreeToNonTree { + change_idx: cursor.change_idx, + } + } + .into() + } + + /// Compare both changes and return `true` if they are *not* exactly the same. + /// One two changes are the same, they will have the same effect. + /// Since this is called after [`Self::check_conflict`], *our* change will not be applied, + /// only theirs, which naturally avoids double-application + /// (which shouldn't have side effects, but let's not risk it) + pub fn is_not_same_change_in_possible_conflict( + &self, + theirs: &Change, + conflict: &PossibleConflict, + our_changes: &ChangeListRef, + ) -> bool { + conflict + .change_idx() + .map_or(true, |idx| our_changes[idx].inner != *theirs) + } + + pub fn remove_existing_leaf(&mut self, location: &BStr) { + self.remove_leaf_inner(location, true); + } + + pub fn remove_leaf(&mut self, location: &BStr) { + self.remove_leaf_inner(location, false); + } + + fn remove_leaf_inner(&mut self, location: &BStr, must_exist: bool) { + let mut components = to_components(location).peekable(); + let mut cursor = &mut self.0[0]; + while let Some(component) = components.next() { + match cursor.children.get(component).copied() { + None => assert!(!must_exist, "didn't find '{location}' for removal"), + Some(existing_idx) => { + let is_last = components.peek().is_none(); + if is_last { + cursor.children.remove(component); + cursor = &mut self.0[existing_idx]; + debug_assert!( + cursor.is_leaf_node(), + "BUG: we should really only try to remove leaf nodes" + ); + cursor.change_idx = None; + } else { + cursor = &mut self.0[existing_idx]; + } + } + } + } + } + + /// Insert `new_change` which affects this tree into it and put it into `storage` to obtain the index. + /// Panic if that change already exists as it must be made so that it definitely doesn't overlap with this tree. + pub fn insert(&mut self, new_change: &Change, new_change_idx: usize) { + let mut next_index = self.0.len(); + let mut cursor = &mut self.0[0]; + for component in to_components(new_change.location()) { + match cursor.children.get(component).copied() { + None => { + cursor.children.insert(component.to_owned(), next_index); + self.0.push(TreeNode::default()); + cursor = &mut self.0[next_index]; + next_index += 1; + } + Some(existing_idx) => { + cursor = &mut self.0[existing_idx]; + } + } + } + + debug_assert!( + !matches!(new_change, Change::Rewrite { .. }), + "BUG: we thought we wouldn't do that current.location is related?" + ); + cursor.change_idx = Some(new_change_idx); + cursor.location = ChangeLocation::CurrentLocation; + } +} + +pub fn to_components_bstring_ref(rela_path: &BString) -> impl Iterator { + rela_path.split(|b| *b == b'/').map(Into::into) +} + +pub fn to_components(rela_path: &BStr) -> impl Iterator { + rela_path.split(|b| *b == b'/').map(Into::into) +} + +impl Conflict { + pub(super) fn without_resolution( + resolution: ResolutionFailure, + changes: (&Change, &Change, ConflictMapping, ConflictMapping), + ) -> Self { + Conflict::maybe_resolved(Err(resolution), changes) + } + + pub(super) fn with_resolution( + resolution: Resolution, + changes: (&Change, &Change, ConflictMapping, ConflictMapping), + ) -> Self { + Conflict::maybe_resolved(Ok(resolution), changes) + } + + pub(super) fn maybe_resolved( + resolution: Result, + (ours, theirs, map, outer_map): (&Change, &Change, ConflictMapping, ConflictMapping), + ) -> Self { + Conflict { + resolution, + ours: ours.clone(), + theirs: theirs.clone(), + map: match outer_map { + ConflictMapping::Original => map, + ConflictMapping::Swapped => map.swapped(), + }, + } + } +} diff --git a/gix-merge/tests/fixtures/generated-archives/tree-baseline.tar b/gix-merge/tests/fixtures/generated-archives/tree-baseline.tar new file mode 100644 index 0000000000000000000000000000000000000000..4b74b96874d300e6e42ece4ad484d2dfc08b5641 GIT binary patch literal 2681344 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 wLyoe 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�y+|G@GV4)lTajKwyxT!jOn!PIkxi!z@LH0S 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

Uf14RHtvwZ4C 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ξQCQ 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

^9!y=u%}3J20w zAb(}nm<`X)D=PQvzWvC&=AU7UE+SCF+7K*NU284D{X(O3Q`M+D(@~m%2Dn3k3r>g9 zs=yuz?i&4Gf0+Pp`Yao8DmB-zOigHwNWFo ze2krXlyE_65T#fVw0#)5w2aapu zp}9`Z#?+!lpo)K{lO+qe_Ce%TN6N5VW@6gThC$l?qwj%fos)2F0P0oSN;;B+dv#p+ zrfQ5rWWC3$B(6?)!@`mk-$--JO-gE2=rP6adTx|e6-J+HN2~jq^kGF=E2Uj4xJX8gG3B_12k6E7_?-=SflG398s&Q-t=gUN;H@oRFFWE! zkg?fDt_(%~kTDZs)eGlNQ8?^h7Ns#yw!-=x76Gn&DVQdD&pGhJE9?=LV^wQfN9=12 ztEfz3YbCmUluJx69pfaDtXe5&RcQvR zU}W0g$8H>l$GyrUi2Vloz4~4*`V! zd~5XdA#zAaLv3u+*NmL57+$qb#Y|Sze{t=s-kZ}^= zhxJp*ERX{hq2Y?}$JIou?Y1_YMxdOXhOa~kJaFP6@&{{7;nD#v+MR|oYm@M4jfYZ) z>IyArsRIZtLO8Ltvq9*Yy&7zdE*NZYon{}Zj!MO*YK8UFP2h!Ed95>3lPE&^Hv%Pt zl!=9{7_$$f0?h|9cxwMmsGwNOt<<4nNKC{14=NVs)pOp|gl6l%2wxr;?%0DZu=f`~gf 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 G82Eps4VtR} literal 0 HcmV?d00001 diff --git a/gix-merge/tests/fixtures/tree-baseline.sh b/gix-merge/tests/fixtures/tree-baseline.sh new file mode 100644 index 00000000000..928a52abea5 --- /dev/null +++ b/gix-merge/tests/fixtures/tree-baseline.sh @@ -0,0 +1,864 @@ +#!/usr/bin/env bash +set -eu -o pipefail + +function tick () { + if test -z "${tick+set}" + then + tick=1112911993 + else + tick=$(($tick + 60)) + fi + GIT_COMMITTER_DATE="$tick -0700" + GIT_AUTHOR_DATE="$tick -0700" + export GIT_COMMITTER_DATE GIT_AUTHOR_DATE +} + +function write_lines () { + printf "%s\n" "$@" +} + +function seq () { + case $# in + 1) set 1 "$@" ;; + 2) ;; + *) { echo "need 1 or 2 parameters: or " 1>&2 && exit 2; } ;; + esac + local seq_counter=$1 + while test "$seq_counter" -le "$2" + do + echo "$seq_counter" + seq_counter=$(( seq_counter + 1 )) + done +} + +function baseline () ( + local dir=${1:?the directory to enter} + local output_name=${2:?the basename of the output of the merge} + local our_committish=${3:?our side from which a commit can be derived} + local their_committish=${4:?Their side from which a commit can be derived} + local opt_deviation_message=${5:-} + local one_side=${6:-} + + cd "$dir" + local our_commit_id + local their_commit_id + + local conflict_style="merge" + if [[ "$output_name" == *-merge ]]; then + conflict_style="merge" + elif [[ "$output_name" == *-diff3 ]]; then + conflict_style="diff3" + fi + + our_commit_id="$(git rev-parse "$our_committish")" + their_commit_id="$(git rev-parse "$their_committish")" + local maybe_expected_tree="$(git rev-parse expected^{tree})" + if [ -z "$opt_deviation_message" ]; then + maybe_expected_tree="expected^{tree}" + fi + + local merge_info="${output_name}.merge-info" + git -c merge.conflictStyle=$conflict_style merge-tree -z --write-tree --allow-unrelated-histories "$our_committish" "$their_committish" > "$merge_info" || : + echo "$dir" "$conflict_style" "$our_commit_id" "$our_committish" "$their_commit_id" "$their_committish" "$merge_info" "$maybe_expected_tree" "$opt_deviation_message" >> ../baseline.cases + + if [[ "$one_side" != "no-reverse" ]]; then + local merge_info="${output_name}-reversed.merge-info" + git -c merge.conflictStyle=$conflict_style merge-tree -z --write-tree --allow-unrelated-histories "$their_committish" "$our_committish" > "$merge_info" || : + echo "$dir" "$conflict_style" "$their_commit_id" "$their_committish" "$our_commit_id" "$our_committish" "$merge_info" "$maybe_expected_tree" "$opt_deviation_message" >> ../baseline.cases + fi +) + +git init simple +(cd simple + rm -Rf .git/hooks + write_lines 1 2 3 4 5 >numbers + echo hello >greeting + echo foo >whatever + git add numbers greeting whatever + tick + git commit -m initial + + git branch side1 + git branch side2 + git branch side3 + git branch side4 + + git checkout side1 + write_lines 1 2 3 4 5 6 >numbers + echo hi >greeting + echo bar >whatever + git add numbers greeting whatever + tick + git commit -m modify-stuff + + git checkout side2 + write_lines 0 1 2 3 4 5 >numbers + echo yo >greeting + git rm whatever + mkdir whatever + >whatever/empty + git add numbers greeting whatever/empty + tick + git commit -m other-modifications + + git checkout side3 + git mv numbers sequence + tick + git commit -m rename-numbers + + git checkout side4 + write_lines 0 1 2 3 4 5 >numbers + echo yo >greeting + git add numbers greeting + tick + git commit -m other-content-modifications + + git switch --orphan unrelated + >something-else + git add something-else + tick + git commit -m first-commit + + git checkout -b tweak1 side1 + write_lines zero 1 2 3 4 5 6 >numbers + git add numbers + git mv numbers "Αυτά μου φαίνονται κινέζικα" + git commit -m "Renamed numbers" +) + +git init rename-delete +(cd rename-delete + write_lines 1 2 3 4 5 >foo + mkdir olddir + for i in a b c; do echo $i >olddir/$i; done + git add foo olddir + git commit -m "original" + + git branch A + git branch B + + git checkout A + write_lines 1 2 3 4 5 6 >foo + git add foo + git mv olddir newdir + git commit -m "Modify foo, rename olddir to newdir" + + git checkout B + write_lines 1 2 3 4 5 six >foo + git add foo + git mv foo olddir/bar + git commit -m "Modify foo & rename foo -> olddir/bar" +) + +git init rename-add +(cd rename-add + write_lines original 1 2 3 4 5 >foo + git add foo + git commit -m "original" + + git branch A + git branch B + + git checkout A + write_lines 1 2 3 4 5 >foo + echo "different file" >bar + git add foo bar + git commit -m "Modify foo, add bar" + + git checkout B + write_lines original 1 2 3 4 5 6 >foo + git add foo + git mv foo bar + git commit -m "rename foo to bar" +) + +git init rename-add-symlink +(cd rename-add-symlink + write_lines original 1 2 3 4 5 >foo + git add foo + git commit -m "original" + + git branch A + git branch B + + git checkout A + write_lines 1 2 3 4 5 >foo + ln -s foo bar + git add foo bar + git commit -m "Modify foo, add symlink bar" + + git checkout B + write_lines original 1 2 3 4 5 6 >foo + git add foo + git mv foo bar + git commit -m "rename foo to bar" +) + +git init rename-rename-plus-content +(cd rename-rename-plus-content + write_lines 1 2 3 4 5 >foo + git add foo + git commit -m "original" + + git branch A + git branch B + + git checkout A + write_lines 1 2 3 4 5 six >foo + git add foo + git mv foo bar + git commit -m "Modify foo + rename to bar" + + git checkout B + write_lines 1 2 3 4 5 6 >foo + git add foo + git mv foo baz + git commit -m "Modify foo + rename to baz" +) + +git init rename-add-delete +( + cd rename-add-delete + echo "original file" >foo + git add foo + git commit -m "original" + + git branch A + git branch B + + git checkout A + git rm foo + echo "different file" >bar + git add bar + git commit -m "Remove foo, add bar" + + git checkout B + git mv foo bar + git commit -m "rename foo to bar" +) + +git init rename-rename-delete-delete +( + cd rename-rename-delete-delete + echo foo >foo + echo bar >bar + git add foo bar + git commit -m O + + git branch A + git branch B + + git checkout A + git mv foo baz + git rm bar + git commit -m "Rename foo, remove bar" + + git checkout B + git mv bar baz + git rm foo + git commit -m "Rename bar, remove foo" +) + +git init super-1 +(cd super-1 + seq 11 19 >one + seq 31 39 >three + seq 51 59 >five + git add . + tick + git commit -m "O" + + git branch A + git branch B + + git checkout A + seq 10 19 >one + echo 40 >>three + git add one three + git mv one two + git mv three four + git mv five six + tick + git commit -m "A" + + git checkout B + echo 20 >>one + echo forty >>three + echo 60 >>five + git add one three five + git mv one six + git mv three two + git mv five four + tick + git commit -m "B" +) + +git init super-2 +(cd super-2 + write_lines 1 2 3 4 5 >foo + mkdir olddir + for i in a b c; do echo $i >olddir/$i || exit 1; done + git add foo olddir + git commit -m "original" + + git branch A + git branch B + + git checkout A + git rm foo + git mv olddir newdir + mkdir newdir/bar + >newdir/bar/file + git add newdir/bar/file + git commit -m "rm foo, olddir/ -> newdir/, + newdir/bar/file" + + git checkout B + write_lines 1 2 3 4 5 6 >foo + git add foo + git mv foo olddir/bar + git commit -m "Modify foo & rename foo -> olddir/bar" +) + +git init rename-within-rename +(cd rename-within-rename + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f + touch a/w a/sub/z + git add . && git commit -m "original" + + git branch A + git branch B + git branch expected + + git checkout A + write_lines 1 2 3 4 5 >a/x.f + write_lines 1 2 3 4 5 >a/sub/y.f + git mv a a-renamed + git commit -am "changed all content, renamed a -> a-renamed" + + git checkout B + write_lines original 1 2 3 4 5 6 >a/x.f + write_lines original 1 2 3 4 5 6 >a/sub/y.f + git mv a/sub a/sub-renamed + git commit -am "changed all content, renamed a/sub -> a/sub-renamed" + + git checkout expected + write_lines 1 2 3 4 5 6 >a/x.f + write_lines 1 2 3 4 5 6 >a/sub/y.f + git mv a/sub a/sub-renamed + git mv a a-renamed + git commit -am "tracked both renames, applied all modifications by merge" +) + +git init rename-within-rename-2 +(cd rename-within-rename-2 + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f + touch a/w a/sub/z + git add . && git commit -m "original" + + git branch A + git branch B + git branch expected + + git checkout A + write_lines 1 2 3 4 5 >a/x.f + write_lines 1 2 3 4 5 >a/sub/y.f + git mv a/sub a/sub-renamed + git mv a a-renamed + git commit -am "changed all content, renamed a -> a-renamed, a/sub -> a/sub-renamed" + + git checkout B + write_lines original 1 2 3 4 5 6 >a/x.f + write_lines original 1 2 3 4 5 6 >a/sub/y.f + git mv a/sub a/sub-renamed + git commit -am "changed all content, renamed a/sub -> a/sub-renamed" + + git checkout expected + write_lines 1 2 3 4 5 6 >a/x.f + write_lines 1 2 3 4 5 6 >a/sub/y.f + git mv a/sub a/sub-renamed + git mv a a-renamed + git commit -am "tracked both renames, applied all modifications by merge" +) + +git init conflicting-rename +(cd conflicting-rename + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f + touch a/w a/sub/z + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + write_lines 1 2 3 4 5 >a/x.f + write_lines 1 2 3 4 5 >a/sub/y.f + git mv a a-renamed + git commit -am "changed all content, renamed a -> a-renamed" + + git checkout B + write_lines original 1 2 3 4 5 6 >a/x.f + write_lines original 1 2 3 4 5 6 >a/sub/y.f + git mv a a-different + git commit -am "changed all content, renamed a -> a-different" +) + +git init conflicting-rename-2 +(cd conflicting-rename-2 + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f + touch a/w a/sub/z + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + write_lines 1 2 3 4 5 >a/x.f + write_lines 1 2 3 4 5 >a/sub/y.f + git mv a/sub a/sub-renamed + git commit -am "changed all content, renamed a/sub -> a/sub-renamed" + + git checkout B + write_lines original 1 2 3 4 5 6 >a/x.f + write_lines original 1 2 3 4 5 6 >a/sub/y.f + git mv a/sub a/sub-different + git commit -am "changed all content, renamed a/sub -> a/sub-different" +) + +git init conflicting-rename-complex +(cd conflicting-rename-complex + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f + touch a/w a/sub/z + git add . && git commit -m "original" + + git branch A + git branch B + git branch expected + + git checkout A + write_lines 1 2 3 4 5 >a/x.f + write_lines 1 2 3 4 5 >a/sub/y.f + git mv a a-renamed + git commit -am "changed all content, renamed a -> a-renamed" + + git checkout B + write_lines original 1 2 3 4 5 6 >a/sub/y.f + git mv a/sub tmp + git rm -r a + git mv tmp a + git commit -am "change something in subdirectory, then overwrite directory with subdirectory" + + git checkout expected + rm .git/index + rm -Rf ./a + mkdir -p a-renamed/sub + write_lines 1 2 3 4 5 >a-renamed/sub/y.f + write_lines 1 2 3 4 5 6 >a-renamed/y.f + touch a-renamed/z a-renamed/sub/z + git add . + git commit -m "Close to what Git has, but different due to rename tracking (which looses 'a/w', and 'x.f' becomes y.f). But the merge is so 'erroneous' that it's beyond rescue" +) + +git init same-rename-different-mode +(cd same-rename-different-mode + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + touch a/w + git add . && git commit -m "original" + + git branch A + git branch B + git branch expected + + git checkout A + write_lines 1 2 3 4 5 >a/x.f + chmod +x a/x.f + chmod +x a/w + git mv a a-renamed + git commit -am "changed all content, add +x, renamed a -> a-renamed" + + git checkout B + write_lines original 1 2 3 4 5 6 >a/x.f + git mv a a-renamed + git commit -am "changed all content, renamed a -> a-renamed" + + git checkout expected + chmod +x a/x.f + chmod +x a/w + write_lines 1 2 3 4 5 6 >a/x.f + git mv a a-renamed + git commit -am "Git, when branches are reversed, doesn't keep the +x flag on a/w so we specify our own expectation" +) + +git init renamed-symlink-with-conflict +(cd renamed-symlink-with-conflict + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + ln -s a/x.f link + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + write_lines 1 2 3 4 5 >a/x.f + git mv link link-renamed + git commit -am "changed a/x.f, renamed link -> link-renamed" + + git checkout B + write_lines original 1 2 3 4 5 6 >a/x.f + git mv link link-different + git commit -am "change content, renamed link -> link-different" +) + +git init added-file-changed-content-and-mode +(cd added-file-changed-content-and-mode + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + git add . && git commit -m "original" + + git branch A + git branch B + git branch expected + + git checkout A + write_lines 1 2 3 4 5 >new + git add . + git commit -m "add 'new' with content A" + + git checkout B + write_lines original 1 2 3 4 5 6 >new + chmod +x new + git add . + git commit -m "add new with content B and +x" + + git checkout expected + echo -n $'<<<<<<< A\n1\n2\n3\n4\n5\n=======\noriginal\n1\n2\n3\n4\n5\n6\n>>>>>>> B\n' >new + chmod +x new + git add new + git commit -m "Git has a better merge here, but that's due to better hunk handling/hunk splitting. We, however, consistently use +x" +) + +git init type-change-and-renamed +(cd type-change-and-renamed + mkdir a && >a/x.f + ln -s a/x.f link + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + rm link && echo not-link > link + git commit -am "link type-changed, file changed" + + git checkout B + git mv link link-renamed + git commit -am "just renamed the link" +) + +git init change-and-delete +(cd change-and-delete + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + ln -s a/x.f link + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + write_lines 1 2 3 4 5 6 >a/x.f + rm link && echo not-link > link + git commit -am "link type-changed, file changed" + + git checkout B + git rm link a/x.f + git commit -am "delete everything" +) + +git init submodule-both-modify +(cd submodule-both-modify + mkdir sub + (cd sub + git init + echo original > file + git add file + tick + git commit -m sub-root + ) + git add sub + tick + git commit -m root + + git branch expected + + git checkout -b A main + (cd sub + echo A > file + git add file + tick + git commit -m sub-a + ) + git add sub + tick + git commit -m a + + git checkout -b B main + (cd sub + echo B > file + git add file + tick + git commit -m sub-b + ) + git add sub + tick + git commit -m b +) + +git init both-modify-union-attr +(cd both-modify-union-attr + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + echo "a/* merge=union" >.gitattributes + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + write_lines A 1 2 3 4 5 6 >a/x.f + git commit -am "change file" + + git checkout B + write_lines B 1 2 3 4 5 7 >a/x.f + git commit -am "change file differently" +) + +git init both-modify-binary +(cd both-modify-binary + mkdir a && printf '\x00 binary' >a/x.f + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + printf '\x00 A' >a/x.f + git commit -am "change binary file" + + git checkout B + printf '\x00 B' >a/x.f + git commit -am "change binary file differently" +) + +git init both-modify-file-with-binary-attr +(cd both-modify-file-with-binary-attr + mkdir a && echo 'not binary' >a/x.f + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + echo 'A binary' >a/x.f + git commit -am "change pseudo-binary file" + + git checkout B + echo 'B binary' >a/x.f + git commit -am "change pseudo-binary file differently" +) + +git init big-file-merge +(cd big-file-merge + git config --local core.bigFileThreshold 80 + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + seq 30 >a/x.f + git commit -am "turn normal file into big one (81 bytes)" + git branch expected + + git checkout B + write_lines 1 2 3 4 5 6 >a/x.f + git commit -am "a normal but conflicting file change" +) + +git init no-merge-base +(cd no-merge-base + git checkout -b A + echo "A" >content && git add . && git commit -m "content A" + + git checkout --orphan B + echo "B" >content && git add . && git commit -m "content B" + + git checkout -b expectation +) + +git init multiple-merge-bases +(cd multiple-merge-bases + write_lines 1 2 3 4 5 >content + git add . && git commit -m "initial" + + git branch A + git branch B + + git checkout A + write_lines 0 1 2 3 4 5 >content + git commit -am "change in A" && git tag A1 + + git checkout B + write_lines 1 2 3 4 5 6 >content + git commit -am "change in B" && git tag B1 + + git checkout A + git merge B1 + + git checkout B + git merge A1 + + git checkout A + write_lines 0 1 2 3 4 5 A >content + git commit -am "conflicting in A" + + git checkout B + git rm content + write_lines 0 2 3 4 5 six >renamed + git commit -m "rename in B" +) + +git init rename-and-modification +(cd rename-and-modification + mkdir a && write_lines original 1 2 3 4 5 >a/x.f + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + git mv a/x.f x.f + git commit -am "move a/x.f to the top-level" + + git checkout B + write_lines 1 2 3 4 5 6 >a/x.f + git commit -am "changed a/x.f" +) + +git init symlink-modification +(cd symlink-modification + touch a b o + ln -s o link + git add . && git commit -m "original" + + git branch A + git branch B + + git checkout A + rm link && ln -s a link + git commit -am "set link to point to 'a'" + + git checkout B + rm link && ln -s b link + git commit -am "set link to point to 'b'" +) + +git init symlink-addition +(cd symlink-addition + touch a b + git add . && git commit -m "original without symlink" + + git branch A + git branch B + + git checkout A + ln -s a link && git add . + git commit -m "new link to point to 'a'" + + git checkout B + ln -s b link && git add . + git commit -m "new link to point to 'b'" +) + +git init type-change-to-symlink +(cd type-change-to-symlink + touch a b link + git add . && git commit -m "original without symlink" + + git branch A + git branch B + + git checkout A + git rm link + ln -s a link && git add . + git commit -m "new link to point to 'a'" + + git checkout B + git rm link + ln -s b link && git add . + git commit -m "new link to point to 'b'" +) + + + +baseline simple side-1-3-without-conflict side1 side3 +baseline simple fast-forward side1 main +baseline simple no-change main main +baseline simple side-1-3-without-conflict-diff3 side1 side3 +baseline simple side-1-2-various-conflicts side1 side2 +baseline simple side-1-2-various-conflicts-diff3 side1 side2 +baseline simple single-content-conflict side1 side4 +baseline simple single-content-conflict-diff3 side1 side4 +baseline simple tweak1-side2 tweak1 side2 +baseline simple tweak1-side2-diff3 tweak1 side2 +baseline simple side-1-unrelated side1 unrelated +baseline simple side-1-unrelated-diff3 side1 unrelated +baseline rename-delete A-B A B +baseline rename-delete A-similar A A +baseline rename-delete B-similar B B +baseline rename-add A-B A B +baseline rename-add A-B-diff3 A B +baseline rename-add-symlink A-B A B +baseline rename-add-symlink A-B-diff3 A B +baseline rename-rename-plus-content A-B A B +baseline rename-rename-plus-content A-B-diff3 A B +baseline rename-add-delete A-B A B +baseline rename-rename-delete-delete A-B A B +baseline super-1 A-B A B +baseline super-1 A-B-diff3 A B +baseline super-2 A-B A B +baseline super-2 A-B-diff3 A B + +baseline rename-within-rename A-B-deviates A B "Git doesn't detect the rename-nesting so there is duplication - we achieve the optimal result" +baseline rename-within-rename-2 A-B-deviates A B "TBD: Right, something is different documentation was forgotten :/" +baseline conflicting-rename A-B A B +baseline conflicting-rename-2 A-B A B +baseline conflicting-rename-complex A-B A B "Git has different rename tracking which is why a-renamed/w disappears - it's still close enough" + +baseline same-rename-different-mode A-B A B "Git works for the A/B case, but for B/A it forgets to set the executable bit" +baseline same-rename-different-mode A-B-diff3 A B "Git works for the A/B case, but for B/A it forgets to set the executable bit" +baseline renamed-symlink-with-conflict A-B A B +baseline added-file-changed-content-and-mode A-B A B "We improve on executable bit handling, but loose on diff quality as we are definitely missing some tweaks" + +baseline type-change-and-renamed A-B A B +baseline change-and-delete A-B A B +baseline submodule-both-modify A-B A B "We can't handle submodules yet and just mark them as conflicting. This is planned to be improved." +baseline both-modify-union-attr A-B A B +baseline both-modify-union-attr A-B-diff3 A B +baseline both-modify-binary A-B A B +baseline both-modify-binary A-B A B +baseline both-modify-file-with-binary-attr A-B A B +baseline big-file-merge A-B A B "Git actually ignores core.bigFileThreshold during merging and tries a normal merge (or binary one) anyway. We don't ignore it and treat big files like binary files" \ + no-reverse +baseline no-merge-base A-B A B +baseline no-merge-base A-B-diff3 A B + +baseline multiple-merge-bases A-B A B +baseline multiple-merge-bases A-B-diff3 A B + +baseline rename-and-modification A-B A B +baseline symlink-modification A-B A B +baseline symlink-addition A-B A B +baseline type-change-to-symlink A-B A B diff --git a/gix-merge/tests/merge/main.rs b/gix-merge/tests/merge/main.rs index 4eaf3b13d0e..d1887c1c705 100644 --- a/gix-merge/tests/merge/main.rs +++ b/gix-merge/tests/merge/main.rs @@ -1,8 +1,8 @@ use gix_hash::ObjectId; extern crate core; -#[cfg(feature = "blob")] mod blob; +mod tree; pub use gix_testtools::Result; diff --git a/gix-merge/tests/merge/tree/baseline.rs b/gix-merge/tests/merge/tree/baseline.rs new file mode 100644 index 00000000000..18ba8aa0f06 --- /dev/null +++ b/gix-merge/tests/merge/tree/baseline.rs @@ -0,0 +1,344 @@ +use bstr::{BStr, ByteSlice}; +use gix_hash::ObjectId; +use gix_merge::blob::builtin_driver::text::ConflictStyle; +use gix_object::tree::EntryMode; +use gix_object::FindExt; +use std::path::{Path, PathBuf}; + +/// An entry in the conflict +#[derive(Debug)] +pub struct Entry { + /// The relative path in the repository + pub location: String, + /// The content id. + pub id: gix_hash::ObjectId, + /// The kind of entry. + pub mode: EntryMode, +} + +/// Keep track of all the sides of a conflict. Some might not be set to indicate removal, including the ancestor. +#[derive(Default, Debug)] +pub struct Conflict { + pub ancestor: Option, + pub ours: Option, + pub theirs: Option, +} + +#[derive(Debug)] +pub enum ConflictKind { + /// The conflict was resolved by automatically merging the content. + AutoMerging, + /// The content could not be resolved so it's conflicting. + ConflictContents, + /// Directory in theirs in the way of our file. + ConflictDirectoryBlocksFile, + /// Modified in ours but deleted in theirs. + ConflictModifyDelete, + /// Modified in ours but parent directory renamed in theirs. + DirectoryRenamedWithModificationInside, + /// Added files differ in mode. + DistinctModes, + /// The same file was renamed to different destinations. + RenameRename, + /// Deleted in ours with a new file added, renamed to new file in theirs with original content. + RenameAddDelete, + /// Two binary files were changed in different ways, which can never be merged (without a merge-driver) + Binary, +} + +/// More loosely structured information about the `Conflict`. +#[derive(Debug)] +pub struct ConflictInfo { + /// All the paths involved in the informational message + pub paths: Vec, + /// The type of the conflict, further described in `message`. + pub kind: ConflictKind, + /// An arbitrary message formed from paths and kind + pub message: String, +} + +impl Conflict { + fn any_location(&self) -> Option<&str> { + self.ancestor + .as_ref() + .or(self.ours.as_ref()) + .or(self.theirs.as_ref()) + .map(|a| a.location.as_str()) + } + fn storage_for(&mut self, side: Side, location: &str) -> Option<&mut Option> { + let current_location = self.any_location(); + let location_is_same = current_location.is_none() || current_location == Some(location); + let side = match side { + Side::Ancestor => &mut self.ancestor, + Side::Ours => &mut self.ours, + Side::Theirs => &mut self.theirs, + }; + (!side.is_some() && location_is_same).then_some(side) + } +} + +pub struct MergeInfo { + /// The hash of the merged tree - it may contain intermediate files if the merge didn't succeed entirely. + pub merged_tree: gix_hash::ObjectId, + /// If there were conflicts, this is the conflicting paths. + pub conflicts: Option>, + /// Structured details which to some extent can be compared to our own conflict information. + pub information: Vec, +} + +pub struct Expectation { + pub root: PathBuf, + pub conflict_style: gix_merge::blob::builtin_driver::text::ConflictStyle, + pub odb: gix_odb::memory::Proxy, + pub our_commit_id: gix_hash::ObjectId, + pub our_side_name: String, + pub their_commit_id: gix_hash::ObjectId, + pub their_side_name: String, + pub merge_info: MergeInfo, + pub case_name: String, + pub deviation: Option, +} + +/// Git doesn't provide the same result. +pub struct Deviation { + /// Tells us the reason for expecting a difference compared to the Git result. + pub message: String, + /// The tree we wish to see, it's hand-crafted directly in the test as Git can't provide the baseline here. + pub expected_tree_id: gix_hash::ObjectId, +} + +pub struct Expectations<'a> { + root: &'a Path, + lines: std::str::Lines<'a>, +} + +impl<'a> Expectations<'a> { + pub fn new(root: &'a Path, cases: &'a str) -> Self { + Expectations { + root, + lines: cases.lines(), + } + } +} + +impl Iterator for Expectations<'_> { + type Item = Expectation; + + fn next(&mut self) -> Option { + let line = self.lines.next()?; + let mut tokens = line.split(' '); + let ( + Some(subdir), + Some(conflict_style), + Some(our_commit_id), + Some(our_side_name), + Some(their_commit_id), + Some(their_side_name), + Some(merge_info_filename), + Some(expected_custom_tree), + ) = ( + tokens.next(), + tokens.next(), + tokens.next(), + tokens.next(), + tokens.next(), + tokens.next(), + tokens.next(), + tokens.next(), + ) + else { + unreachable!("invalid line: {line:?}") + }; + let deviation = (expected_custom_tree != "expected^{tree}").then(|| { + let expected_tree_id = gix_hash::ObjectId::from_hex(expected_custom_tree.as_bytes()) + .expect("valid tree id in hex for the expected tree"); + let message = tokens.collect::>().join(" ").trim().to_owned(); + Deviation { + message, + expected_tree_id, + } + }); + + let subdir_path = self.root.join(subdir); + let conflict_style = match conflict_style { + "merge" => ConflictStyle::Merge, + "diff3" => ConflictStyle::Diff3, + unknown => unreachable!("Unknown conflict style: '{unknown}'"), + }; + let odb = gix_odb::at(subdir_path.join(".git/objects")).expect("object dir exists"); + let objects = gix_odb::memory::Proxy::new(odb, gix_hash::Kind::Sha1); + let our_commit_id = gix_hash::ObjectId::from_hex(our_commit_id.as_bytes()).unwrap(); + let their_commit_id = gix_hash::ObjectId::from_hex(their_commit_id.as_bytes()).unwrap(); + let merge_info = parse_merge_info(std::fs::read_to_string(subdir_path.join(merge_info_filename)).unwrap()); + Some(Expectation { + root: subdir_path, + conflict_style, + odb: objects, + our_commit_id, + our_side_name: our_side_name.to_owned(), + their_commit_id, + their_side_name: their_side_name.to_owned(), + merge_info, + case_name: format!( + "{subdir}-{}", + merge_info_filename + .split('.') + .next() + .expect("extension after single dot") + ), + deviation, + }) + } +} + +fn parse_merge_info(content: String) -> MergeInfo { + let mut lines = content.split('\0').filter(|t| !t.is_empty()).peekable(); + let tree_id = gix_hash::ObjectId::from_hex(lines.next().unwrap().as_bytes()).unwrap(); + let mut out = MergeInfo { + merged_tree: tree_id, + conflicts: None, + information: Vec::new(), + }; + + let mut conflicts = Vec::new(); + let mut conflict = Conflict::default(); + while let Some(line) = lines.peek() { + let (entry, side) = match parse_conflict_file_info(line) { + Some(t) => t, + None => break, + }; + lines.next(); + let field = match conflict.storage_for(side, &entry.location) { + None => { + conflicts.push(conflict); + conflict = Conflict::default(); + conflict + .storage_for(side, &entry.location) + .expect("always available for new side") + } + Some(field) => field, + }; + *field = Some(entry); + } + + while lines.peek().is_some() { + out.information + .push(parse_info(&mut lines).expect("if there are lines, it should be valid info")); + } + assert_eq!(lines.next(), None, "TODO: conflict messages"); + out.conflicts = (!conflicts.is_empty()).then_some(conflicts); + out +} + +#[derive(Copy, Clone)] +enum Side { + Ancestor, + Ours, + Theirs, +} + +fn parse_conflict_file_info(line: &str) -> Option<(Entry, Side)> { + let (info, mut path) = line.split_at(line.find('\t')?); + path = &path[1..]; + let mut tokens = info.split(' '); + let (oct_mode, hex_id, stage) = ( + tokens.next().expect("mode"), + tokens.next().expect("id"), + tokens.next().expect("stage"), + ); + assert_eq!( + tokens.next(), + None, + "info line not understood, expected three fields only" + ); + Some(( + Entry { + location: path.to_owned(), + id: gix_hash::ObjectId::from_hex(hex_id.as_bytes()).unwrap(), + mode: EntryMode(gix_utils::btoi::to_signed_with_radix::(oct_mode.as_bytes(), 8).unwrap() as u16), + }, + match stage { + "1" => Side::Ancestor, + "2" => Side::Ours, + "3" => Side::Theirs, + invalid => panic!("{invalid} is an unexpected side"), + }, + )) +} + +fn parse_info<'a>(mut lines: impl Iterator) -> Option { + let num_paths: usize = lines.next()?.parse().ok()?; + let paths: Vec<_> = lines.by_ref().take(num_paths).map(ToOwned::to_owned).collect(); + let kind = match lines.next()? { + "Auto-merging" => ConflictKind::AutoMerging, + "CONFLICT (contents)" => ConflictKind::ConflictContents, + "CONFLICT (file/directory)" => ConflictKind::ConflictDirectoryBlocksFile, + "CONFLICT (modify/delete)" => ConflictKind::ConflictModifyDelete, + "CONFLICT (directory rename suggested)" => ConflictKind::DirectoryRenamedWithModificationInside, + "CONFLICT (distinct modes)" => ConflictKind::DistinctModes, + "CONFLICT (rename/rename)" => ConflictKind::RenameRename, + "CONFLICT (rename/delete)" => ConflictKind::RenameAddDelete, + "CONFLICT (binary)" => ConflictKind::Binary, + conflict_type => panic!("Unkonwn conflict type: {conflict_type}"), + }; + let message = lines.next()?.to_owned(); + Some(ConflictInfo { paths, kind, message }) +} + +pub fn visualize_tree( + id: &gix_hash::oid, + odb: &impl gix_object::Find, + name_and_mode: Option<(&BStr, EntryMode)>, +) -> termtree::Tree { + fn short_id(id: &gix_hash::oid) -> String { + id.to_string()[..7].to_string() + } + let entry_name = |id: &gix_hash::oid, name: Option<(&BStr, EntryMode)>| -> String { + let mut buf = Vec::new(); + match name { + None => short_id(id), + Some((name, mode)) => { + format!( + "{name}:{mode}{} {}", + short_id(id), + match odb.find_blob(id, &mut buf) { + Ok(blob) => format!("{:?}", blob.data.as_bstr()), + Err(_) => "".into(), + }, + mode = if mode.is_tree() { + "".into() + } else { + format!("{:o}:", mode.0) + } + ) + } + } + }; + + let mut tree = termtree::Tree::new(entry_name(id, name_and_mode)); + let mut buf = Vec::new(); + for entry in odb.find_tree(id, &mut buf).unwrap().entries { + if entry.mode.is_tree() { + tree.push(visualize_tree(entry.oid, odb, Some((entry.filename, entry.mode)))); + } else { + tree.push(entry_name(entry.oid, Some((entry.filename, entry.mode)))); + } + } + tree +} + +pub fn show_diff_and_fail( + case_name: &str, + actual_id: ObjectId, + actual: &gix_merge::tree::Outcome<'_>, + expected: &MergeInfo, + odb: &gix_odb::memory::Proxy, +) { + pretty_assertions::assert_str_eq!( + visualize_tree(&actual_id, odb, None).to_string(), + visualize_tree(&expected.merged_tree, odb, None).to_string(), + "{case_name}: merged tree mismatch\n{:#?}\n{:#?}\n{case_name}", + actual.conflicts, + expected.information + ); +} diff --git a/gix-merge/tests/merge/tree/mod.rs b/gix-merge/tests/merge/tree/mod.rs new file mode 100644 index 00000000000..833166bc61a --- /dev/null +++ b/gix-merge/tests/merge/tree/mod.rs @@ -0,0 +1,180 @@ +use crate::tree::baseline::Deviation; +use gix_diff::Rewrites; +use gix_merge::commit::Options; +use gix_object::Write; +use gix_worktree::stack::state::attributes; +use std::path::Path; + +/// ### How to add a new baseline test +/// +/// 1. Add it to the `tree_baseline.sh` script and don't forget to call the +/// `baseline` function there with the respective parameters. +/// 2. Run all tests - maybe it works, if so, jump to the last point. +/// 3. Change `let new_test = None` to `… = Some("case-name")` to focus on the +/// newly added test and its reversed version. +/// 4. Make it work, then set the `let new_test = Some(…)` back to `… = None`. +/// 5. Validate that all tests are still working, and adjust the expected number of cases +/// in the assertion that would then fail. +#[test] +fn run_baseline() -> crate::Result { + let root = gix_testtools::scripted_fixture_read_only("tree-baseline.sh")?; + let cases = std::fs::read_to_string(root.join("baseline.cases"))?; + let mut actual_cases = 0; + // let new_test = Some("simple-fast-forward"); + let new_test = None; + for baseline::Expectation { + root, + conflict_style, + odb, + our_commit_id, + our_side_name, + their_commit_id, + their_side_name, + merge_info, + case_name, + deviation, + } in baseline::Expectations::new(&root, &cases) + .filter(|case| new_test.map_or(true, |prefix: &str| case.case_name.starts_with(prefix))) + { + actual_cases += 1; + let mut graph = gix_revwalk::Graph::new(&odb, None); + let large_file_threshold_bytes = 100; + let mut blob_merge = new_blob_merge_platform(&root, large_file_threshold_bytes); + let mut diff_resource_cache = new_diff_resource_cache(&root); + let mut options = basic_merge_options(); + options.tree_merge.blob_merge.text.conflict = gix_merge::blob::builtin_driver::text::Conflict::Keep { + style: conflict_style, + marker_size: gix_merge::blob::builtin_driver::text::Conflict::DEFAULT_MARKER_SIZE + .try_into() + .expect("non-zero"), + }; + + let mut actual = gix_merge::commit( + our_commit_id, + their_commit_id, + gix_merge::blob::builtin_driver::text::Labels { + ancestor: None, + current: Some(our_side_name.as_str().into()), + other: Some(their_side_name.as_str().into()), + }, + &mut graph, + &mut diff_resource_cache, + &mut blob_merge, + &odb, + &mut |id| id.to_hex_with_len(7).to_string(), + options, + )? + .tree_merge; + + let actual_id = actual.tree.write(|tree| odb.write(tree))?; + match deviation { + None => { + if actual_id != merge_info.merged_tree { + baseline::show_diff_and_fail(&case_name, actual_id, &actual, &merge_info, &odb); + } + } + Some(Deviation { + message, + expected_tree_id, + }) => { + // Sometimes only the reversed part of a specific test is different. + if case_name != "same-rename-different-mode-A-B" && case_name != "same-rename-different-mode-A-B-diff3" + { + assert_ne!( + actual_id, merge_info.merged_tree, + "{case_name}: Git caught up - adjust expectation {message}" + ); + } else { + assert_eq!( + actual_id, merge_info.merged_tree, + "{case_name}: Git should match here, it just doesn't match in one of two cases" + ); + } + pretty_assertions::assert_str_eq!( + baseline::visualize_tree(&actual_id, &odb, None).to_string(), + baseline::visualize_tree(&expected_tree_id, &odb, None).to_string(), + "{case_name}: tree mismatch: {message} \n{:#?}\n{case_name}", + actual.conflicts + ); + } + } + } + + assert_eq!( + actual_cases, 105, + "BUG: update this number, and don't forget to remove a filter in the end" + ); + + Ok(()) +} + +fn basic_merge_options() -> Options { + gix_merge::commit::Options { + allow_missing_merge_base: true, + use_first_merge_base: false, + tree_merge: gix_merge::tree::Options { + symlink_conflicts: None, + rewrites: Some(Rewrites { + copies: None, + percentage: Some(0.5), + limit: 0, + }), + blob_merge: gix_merge::blob::platform::merge::Options::default(), + blob_merge_command_ctx: Default::default(), + fail_on_conflict: None, + marker_size_multiplier: 0, + allow_lossy_resolution: false, + }, + } +} + +fn new_diff_resource_cache(root: &Path) -> gix_diff::blob::Platform { + gix_diff::blob::Platform::new( + Default::default(), + gix_diff::blob::Pipeline::new(Default::default(), Default::default(), Vec::new(), Default::default()), + Default::default(), + gix_worktree::Stack::new( + root, + gix_worktree::stack::State::AttributesStack(gix_worktree::stack::state::Attributes::default()), + Default::default(), + Vec::new(), + Vec::new(), + ), + ) +} + +fn new_blob_merge_platform( + root: &Path, + large_file_threshold_bytes: impl Into>, +) -> gix_merge::blob::Platform { + let attributes = gix_worktree::Stack::new( + root, + gix_worktree::stack::State::AttributesStack(gix_worktree::stack::state::Attributes::new( + Default::default(), + None, + attributes::Source::WorktreeThenIdMapping, + Default::default(), + )), + gix_worktree::glob::pattern::Case::Sensitive, + Vec::new(), + Vec::new(), + ); + let filter = gix_merge::blob::Pipeline::new( + Default::default(), + gix_filter::Pipeline::default(), + gix_merge::blob::pipeline::Options { + large_file_threshold_bytes: large_file_threshold_bytes.into().unwrap_or_default(), + }, + ); + gix_merge::blob::Platform::new( + filter, + gix_merge::blob::pipeline::Mode::ToGit, + attributes, + vec![], + Default::default(), + ) +} + +// TODO: make sure everything is read eventually, even if only to improve debug messages in case of failure. +#[allow(dead_code)] +mod baseline; diff --git a/gix/Cargo.toml b/gix/Cargo.toml index aa5f4efe20f..e2f1eadfddd 100644 --- a/gix/Cargo.toml +++ b/gix/Cargo.toml @@ -139,7 +139,7 @@ revparse-regex = ["regex", "revision"] blob-diff = ["gix-diff/blob", "attributes"] ## Add functions to specifically merge files, using the standard three-way merge that git offers. -blob-merge = ["dep:gix-merge", "gix-merge/blob", "attributes"] +blob-merge = ["dep:gix-merge", "attributes"] ## Make it possible to turn a tree into a stream of bytes, which can be decoded to entries and turned into various other formats. worktree-stream = ["gix-worktree-stream", "attributes"] From 80e006b759d130f4f07a346b75cfc0b39986210c Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 1 Nov 2024 13:22:48 +0100 Subject: [PATCH 19/23] support for merge related options in config tree --- gix/src/config/tree/sections/diff.rs | 2 +- gix/src/config/tree/sections/merge.rs | 16 +++++++++++++++- src/plumbing/progress.rs | 12 ++++++------ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/gix/src/config/tree/sections/diff.rs b/gix/src/config/tree/sections/diff.rs index f328254e8fd..7caa0b447a7 100644 --- a/gix/src/config/tree/sections/diff.rs +++ b/gix/src/config/tree/sections/diff.rs @@ -165,7 +165,7 @@ mod renames { } } -mod validate { +pub(super) mod validate { use crate::{ bstr::BStr, config::tree::{keys, Diff}, diff --git a/gix/src/config/tree/sections/merge.rs b/gix/src/config/tree/sections/merge.rs index 32eb833d84e..9b8ff3e9754 100644 --- a/gix/src/config/tree/sections/merge.rs +++ b/gix/src/config/tree/sections/merge.rs @@ -1,11 +1,21 @@ use crate::config; use crate::config::tree::SubSectionRequirement; use crate::config::{ - tree::{keys, Key, Merge, Section}, + tree::{diff, keys, Key, Merge, Section}, Tree, }; impl Merge { + /// The `merge.renameLimit` key. + pub const RENAME_LIMIT: keys::UnsignedInteger = keys::UnsignedInteger::new_unsigned_integer( + "renameLimit", + &config::Tree::MERGE, + ) + .with_note( + "The limit is actually squared, so 1000 stands for up to 1 million diffs if fuzzy rename tracking is enabled", + ); + /// The `merge.renames` key. + pub const RENAMES: diff::Renames = diff::Renames::new_renames("renames", &config::Tree::MERGE); /// The `merge.renormalize` key pub const RENORMALIZE: keys::Boolean = keys::Boolean::new_boolean("renormalize", &Tree::MERGE); /// The `merge.default` key @@ -32,11 +42,15 @@ impl Section for Merge { fn keys(&self) -> &[&dyn Key] { &[ + &Self::RENAME_LIMIT, + &Self::RENAMES, &Self::RENORMALIZE, &Self::DEFAULT, &Self::DRIVER_NAME, &Self::DRIVER_COMMAND, &Self::DRIVER_RECURSIVE, + #[cfg(feature = "blob-merge")] + &Self::CONFLICT_STYLE, ] } } diff --git a/src/plumbing/progress.rs b/src/plumbing/progress.rs index 846837694f8..429fe81876e 100644 --- a/src/plumbing/progress.rs +++ b/src/plumbing/progress.rs @@ -29,7 +29,7 @@ impl Display for Usage { } InUse(deviation) => { if !deviation.is_empty() { - write!(f, "❗️❗️❗️{deviation}")?; + write!(f, "❗️{deviation}")?; } } } @@ -411,12 +411,12 @@ static GIT_CONFIG: &[Record] = &[ usage: Planned("Required for big monorepos, and typically used in conjunction with sparse indices") }, Record { - config: "merge.renameLimit", - usage: Planned("The same as 'diff.renameLimit'") + config: "merge.directoryRenames", + usage: NotPlanned("On demand") }, Record { - config: "merge.renames", - usage: Planned("The same as 'diff.renames'") + config: "merge.verbosity", + usage: NotApplicable("Only useful for Git CLI") }, Record { config: "status.renameLimit", @@ -431,7 +431,7 @@ static GIT_CONFIG: &[Record] = &[ usage: Planned("Currently we are likely to expose passwords in errors or in other places, and it's better to by default not do that") }, Record { - config: "diff.*.cachetextconv", + config: "diff.*.cacheTextConv", usage: NotPlanned("It seems to slow to do that, and persisting results to save a relatively cheap computation doesn't seem right") }, ]; From bd91d6ae97d1981a2366136040407590f64fdad4 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 1 Nov 2024 15:54:52 +0100 Subject: [PATCH 20/23] feat: respect the `conflict-marker-size` attribute as well. --- gix-merge/src/blob/platform/mod.rs | 2 +- gix-merge/src/blob/platform/prepare_merge.rs | 22 +++++++++++++++--- .../generated-archives/make_blob_repo.tar | Bin 74240 -> 74240 bytes gix-merge/tests/fixtures/make_blob_repo.sh | 2 +- gix-merge/tests/merge/blob/platform.rs | 9 +++++-- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/gix-merge/src/blob/platform/mod.rs b/gix-merge/src/blob/platform/mod.rs index 14b33d03fd5..aa51102288e 100644 --- a/gix-merge/src/blob/platform/mod.rs +++ b/gix-merge/src/blob/platform/mod.rs @@ -95,7 +95,7 @@ impl Platform { attr_stack, attrs: { let mut out = attributes::search::Outcome::default(); - out.initialize_with_selection(&Default::default(), Some("merge")); + out.initialize_with_selection(&Default::default(), ["merge", "conflict-marker-size"]); out }, options, diff --git a/gix-merge/src/blob/platform/prepare_merge.rs b/gix-merge/src/blob/platform/prepare_merge.rs index 24ffb5af32e..310a5896637 100644 --- a/gix-merge/src/blob/platform/prepare_merge.rs +++ b/gix-merge/src/blob/platform/prepare_merge.rs @@ -1,7 +1,10 @@ +use crate::blob::builtin_driver::text::Conflict; use crate::blob::platform::{merge, DriverChoice, ResourceRef}; use crate::blob::{BuiltinDriver, Platform, PlatformRef, ResourceKind}; use bstr::{BStr, BString, ByteSlice}; use gix_filter::attributes; +use std::num::NonZeroU8; +use std::str::FromStr; /// The error returned by [Platform::prepare_merge_state()](Platform::prepare_merge()). #[derive(Debug, thiserror::Error)] @@ -45,12 +48,14 @@ impl Platform { rela_path: current.rela_path.clone(), })?; entry.matching_attributes(&mut self.attrs); - let attr = self.attrs.iter_selected().next().expect("pre-initialized with 'diff'"); - let mut driver = match attr.assignment.state { + let mut attrs = self.attrs.iter_selected(); + let merge_attr = attrs.next().expect("pre-initialized with 'merge'"); + let marker_size_attr = attrs.next().expect("pre-initialized with 'conflict-marker-size'"); + let mut driver = match merge_attr.assignment.state { attributes::StateRef::Set => DriverChoice::BuiltIn(BuiltinDriver::Text), attributes::StateRef::Unset => DriverChoice::BuiltIn(BuiltinDriver::Binary), attributes::StateRef::Value(_) | attributes::StateRef::Unspecified => { - let name = match attr.assignment.state { + let name = match merge_attr.assignment.state { attributes::StateRef::Value(name) => Some(name.as_bstr()), attributes::StateRef::Unspecified => { self.options.default_driver.as_ref().map(|name| name.as_bstr()) @@ -60,6 +65,17 @@ impl Platform { self.find_driver_by_name(name) } }; + if let attributes::StateRef::Value(value) = marker_size_attr.assignment.state { + if let Some(value) = u8::from_str(value.as_bstr().to_str_lossy().as_ref()) + .ok() + .and_then(NonZeroU8::new) + { + match &mut options.text.conflict { + Conflict::Keep { marker_size, .. } => *marker_size = value, + Conflict::ResolveWithOurs | Conflict::ResolveWithTheirs | Conflict::ResolveWithUnion => {} + } + } + } if let Some(recursive_driver_name) = match driver { DriverChoice::Index(idx) => self.drivers.get(idx), _ => None, diff --git a/gix-merge/tests/fixtures/generated-archives/make_blob_repo.tar b/gix-merge/tests/fixtures/generated-archives/make_blob_repo.tar index 9105e6caa792b3db34251677ebb38f21751ab371..d190eeee11d1c4113b3d22225f4dddd31d13ff20 100644 GIT binary patch delta 1359 zcmZoT!qRYrWdjdieY(n;ztk%oo28@R4v7Eex&j2FncJ2yT5=cWO%_jeWNqYR93YG-YP)Uo)F8olP z-o}@}l0X_NX*IbACh60h3zh`ZP)X~_SNL5uc0T>SsbTezKff1E*|NO$M7WJy8ZS(9#;InB$!5t0DJF)NrY6ajrfHVR z=4pv(W+}!gsb;BWW+o=)n;BVdFm963nn1LMz%@6SiC4T~uP~$Kf_gv$re-k8i5oE(8km?F8WKK9P5+D_Z@%b(Ajz&qVbFMY8VhgN@pO~LHR+!?Dos&_8nIK=*C z*$m0uW@}W>WL}yd>7wLQS2lTH{PwQ++Yi~g`5r!ay&`U}kX|}4jOQ^L%d`7-I``<8mv_3CzdrTT;p&uUsn4DpuG#nakj#e1|7UqE@p$&@%jZ2u z^>&HgDqvL*{$u9)T(?MM?t-8DmH#=3a`PAeuH)zby zs>0$NX@4v8%6Fy;GKil~)7X44K#XzI1zxVjybpw!j7{N*VV@DR5iHP70|U)epSUCo z3$!!(Z03fh@Tfn_%vgVr>o73ltG{V~i_^&JSuNmI=ek{6G)p&W!F>6Jsx1H} zo^subc-=Eu=vV6vyuaWjLf2%Ih*mU{SD53eSD-HI6MABpU=*Okkqb?Y6fSVl0fc2{_)$ zkRWAhd*^_OpaxyWP#l+lFcGSl0RjQV=wKn)i!(!K8O$LI%-xlCOZdcxoBxO3|C}fH zoc}2skdzHbE(gj=jnAU($m`Y6s{lbl!cEKf5X9PyAmAy2Afe*N_K(@*9eG4r-OP?d z(xk2Sww9+kh%EjzU7!3it2&m{IVB@?)=ORMfJeje9|UQWq9_a8;a_IlYEUAMjUgw zp{O2sm!I5}ylpP=+*p$hgocczE>!oL)2uz2GkIM~Yi(tHu`+coz+vT^7iU{G3Nicp zK)W1lh@+tzBMCJ_;3TIrG7L!?afV?qhEa2r0cRf{b?t=8z?|j#9 zzT6uEAb-{;!_g|?vxhNXh>*Nf!wKM~6vV*<+`wXb17lR{Ac_(wt~U@mBd%t398D0M z8r88R#qlvw3GVt4=trOsfvX)xqd}=U@6z7vRO?Y!%|}%C)%cc>du@Mx{$fV`z=_?? z#5ccux2X5hP*dE)#S)qHV5Xux<-+VQ4<40|uvdl-FJ#^sI``?_rN)5cbq!JGj`^z< z%3-A{enPcV#ok}(UmnXndhyipmHfSE@%F_Zf9=Un)R5;3>z4`xzj9rH{*Rya#il46 z-H9tZa=*5jj!;@KDCtX^D70-(j?4brRn@1tdHu%sB{RNf&qR|9uENP9&Wm4YE*K8w zP8)^>{K~UR8>jb~vLs03`9^rW&RWeasqyxd3NeV`Vk{s^qcr9H z^Pl`dGI3zgv(fayG*!ww4^qmpkOq;f$zUm%Ml(6z5(kfc{%?E(NuL07B~m;(0b$W95U nlt)l&{o+k}{5$~9Wf;n!YMO?O%3{hX5Q1l2pljtN;Je`;y&dJY diff --git a/gix-merge/tests/fixtures/make_blob_repo.sh b/gix-merge/tests/fixtures/make_blob_repo.sh index 8f4d23f38ec..59f3ed046d8 100644 --- a/gix-merge/tests/fixtures/make_blob_repo.sh +++ b/gix-merge/tests/fixtures/make_blob_repo.sh @@ -11,7 +11,7 @@ echo unset > unset echo unspecified > unspecified cat <.gitattributes -just-set merge +just-set merge conflict-marker-size=32 b merge=b union merge=union missing merge=missing diff --git a/gix-merge/tests/merge/blob/platform.rs b/gix-merge/tests/merge/blob/platform.rs index 6ac8b2b7e0f..b9df80a8f21 100644 --- a/gix-merge/tests/merge/blob/platform.rs +++ b/gix-merge/tests/merge/blob/platform.rs @@ -514,7 +514,7 @@ mod prepare_merge { platform.set_resource( gix_hash::Kind::Sha1.null(), EntryKind::Blob, - "just-set".into(), + "ancestor does not matter for attributes".into(), ResourceKind::CommonAncestorOrBase, &gix_object::find::Never, )?; @@ -522,7 +522,7 @@ mod prepare_merge { platform.set_resource( gix_hash::Kind::Sha1.null(), EntryKind::Blob, - "does not matter for driver".into(), + "just-set".into(), ResourceKind::CurrentOrOurs, &gix_object::find::Never, )?; @@ -540,6 +540,11 @@ mod prepare_merge { DriverChoice::BuiltIn(BuiltinDriver::Text), "`merge` attribute means text" ); + assert_eq!( + prepared.options.text.conflict.marker_size(), + Some(32), + "marker sizes are picked up from attributes as well" + ); platform.set_resource( gix_hash::Kind::Sha1.null(), From 07746f3ccf3e5c71f12319cfd2fb069b5f380624 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 2 Nov 2024 09:37:49 +0100 Subject: [PATCH 21/23] feat: `gix::Repository` implements all traits for object reading and writing. That way it becomes usable when merging trees, which benefits from automatic checking of hashes before writing loose objects. --- gix/src/repository/impls.rs | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/gix/src/repository/impls.rs b/gix/src/repository/impls.rs index 1dbf21fa2e0..f528cda2860 100644 --- a/gix/src/repository/impls.rs +++ b/gix/src/repository/impls.rs @@ -1,3 +1,6 @@ +use gix_object::Exists; +use std::ops::DerefMut; + impl Clone for crate::Repository { fn clone(&self) -> Self { let mut new = crate::Repository::from_refs_and_objects( @@ -93,3 +96,55 @@ impl From for crate::ThreadSafeRepository { } } } + +impl gix_object::Write for crate::Repository { + fn write(&self, object: &dyn gix_object::WriteTo) -> Result { + let mut buf = self.empty_reusable_buffer(); + object.write_to(buf.deref_mut())?; + self.write_buf(object.kind(), &buf) + } + + fn write_buf(&self, object: gix_object::Kind, from: &[u8]) -> Result { + let oid = gix_object::compute_hash(self.object_hash(), object, from); + if self.objects.exists(&oid) { + return Ok(oid); + } + self.objects.write_buf(object, from) + } + + fn write_stream( + &self, + kind: gix_object::Kind, + size: u64, + from: &mut dyn std::io::Read, + ) -> Result { + let mut buf = self.empty_reusable_buffer(); + let bytes = std::io::copy(from, buf.deref_mut())?; + if size != bytes { + return Err(format!("Found {bytes} bytes in stream, but had {size} bytes declared").into()); + } + self.write_buf(kind, &buf) + } +} + +impl gix_object::FindHeader for crate::Repository { + fn try_header(&self, id: &gix_hash::oid) -> Result, gix_object::find::Error> { + self.objects.try_header(id) + } +} + +impl gix_object::Find for crate::Repository { + fn try_find<'a>( + &self, + id: &gix_hash::oid, + buffer: &'a mut Vec, + ) -> Result>, gix_object::find::Error> { + self.objects.try_find(id, buffer) + } +} + +impl gix_object::Exists for crate::Repository { + fn exists(&self, id: &gix_hash::oid) -> bool { + self.objects.exists(id) + } +} From d1ac584d9098988e66091217db4264d69fb77282 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 1 Nov 2024 13:43:03 +0100 Subject: [PATCH 22/23] feat: add `Repository::merge_trees()` --- gix/Cargo.toml | 2 +- gix/src/config/tree/sections/merge.rs | 6 ++- gix/src/diff.rs | 20 ++++++--- gix/src/repository/merge.rs | 62 +++++++++++++++++++++++++-- gix/src/repository/mod.rs | 32 ++++++++++++++ 5 files changed, 110 insertions(+), 12 deletions(-) diff --git a/gix/Cargo.toml b/gix/Cargo.toml index e2f1eadfddd..2afbf8d2b59 100644 --- a/gix/Cargo.toml +++ b/gix/Cargo.toml @@ -139,7 +139,7 @@ revparse-regex = ["regex", "revision"] blob-diff = ["gix-diff/blob", "attributes"] ## Add functions to specifically merge files, using the standard three-way merge that git offers. -blob-merge = ["dep:gix-merge", "attributes"] +blob-merge = ["blob-diff", "dep:gix-merge", "attributes"] ## Make it possible to turn a tree into a stream of bytes, which can be decoded to entries and turned into various other formats. worktree-stream = ["gix-worktree-stream", "attributes"] diff --git a/gix/src/config/tree/sections/merge.rs b/gix/src/config/tree/sections/merge.rs index 9b8ff3e9754..966dda16083 100644 --- a/gix/src/config/tree/sections/merge.rs +++ b/gix/src/config/tree/sections/merge.rs @@ -1,7 +1,7 @@ use crate::config; use crate::config::tree::SubSectionRequirement; use crate::config::{ - tree::{diff, keys, Key, Merge, Section}, + tree::{keys, Key, Merge, Section}, Tree, }; @@ -15,7 +15,8 @@ impl Merge { "The limit is actually squared, so 1000 stands for up to 1 million diffs if fuzzy rename tracking is enabled", ); /// The `merge.renames` key. - pub const RENAMES: diff::Renames = diff::Renames::new_renames("renames", &config::Tree::MERGE); + #[cfg(feature = "blob-merge")] + pub const RENAMES: super::diff::Renames = super::diff::Renames::new_renames("renames", &config::Tree::MERGE); /// The `merge.renormalize` key pub const RENORMALIZE: keys::Boolean = keys::Boolean::new_boolean("renormalize", &Tree::MERGE); /// The `merge.default` key @@ -43,6 +44,7 @@ impl Section for Merge { fn keys(&self) -> &[&dyn Key] { &[ &Self::RENAME_LIMIT, + #[cfg(feature = "blob-merge")] &Self::RENAMES, &Self::RENORMALIZE, &Self::DEFAULT, diff --git a/gix/src/diff.rs b/gix/src/diff.rs index 5308c5c3fbd..01361b1bbdd 100644 --- a/gix/src/diff.rs +++ b/gix/src/diff.rs @@ -122,7 +122,7 @@ pub mod rename { /// #[cfg(feature = "blob-diff")] -mod utils { +pub(crate) mod utils { use gix_diff::{rewrites::Copies, Rewrites}; use crate::{ @@ -172,10 +172,18 @@ mod utils { config: &gix_config::File<'static>, lenient: bool, ) -> Result, new_rewrites::Error> { - let key = "diff.renames"; + new_rewrites_inner(config, lenient, &Diff::RENAMES, &Diff::RENAME_LIMIT) + } + + pub fn new_rewrites_inner( + config: &gix_config::File<'static>, + lenient: bool, + renames: &'static crate::config::tree::diff::Renames, + rename_limit: &'static crate::config::tree::keys::UnsignedInteger, + ) -> Result, new_rewrites::Error> { let copies = match config - .boolean(key) - .map(|value| Diff::RENAMES.try_into_renames(value)) + .boolean(renames) + .map(|value| renames.try_into_renames(value)) .transpose() .with_leniency(lenient)? { @@ -191,8 +199,8 @@ mod utils { Ok(Rewrites { copies, limit: config - .integer("diff.renameLimit") - .map(|value| Diff::RENAME_LIMIT.try_into_usize(value)) + .integer(rename_limit) + .map(|value| rename_limit.try_into_usize(value)) .transpose() .with_leniency(lenient)? .unwrap_or(default.limit), diff --git a/gix/src/repository/merge.rs b/gix/src/repository/merge.rs index 10e187ec6cc..7f41f23fd46 100644 --- a/gix/src/repository/merge.rs +++ b/gix/src/repository/merge.rs @@ -1,8 +1,9 @@ use crate::config::cache::util::ApplyLeniencyDefault; use crate::config::tree; -use crate::repository::{blob_merge_options, merge_resource_cache}; +use crate::repository::{blob_merge_options, merge_resource_cache, merge_trees, tree_merge_options}; use crate::Repository; use gix_merge::blob::builtin_driver::text; +use gix_object::Write; use std::borrow::Cow; /// Merge-utilities @@ -10,7 +11,7 @@ impl Repository { /// Create a resource cache that can hold the three resources needed for a three-way merge. `worktree_roots` /// determines which side of the merge is read from the worktree, or from which worktree. /// - /// The platform can be used to setup resources and finally perform a merge. + /// The platform can be used to set up resources and finally perform a merge among blobs. /// /// Note that the current index is used for attribute queries. pub fn merge_resource_cache( @@ -55,7 +56,8 @@ impl Repository { Ok(gix_merge::blob::Platform::new(filter, mode, attrs, drivers, options)) } - /// Return options for use with [`gix_merge::blob::PlatformRef::merge()`]. + /// Return options for use with [`gix_merge::blob::PlatformRef::merge()`], accessible through + /// [merge_resource_cache()](Self::merge_resource_cache). pub fn blob_merge_options(&self) -> Result { Ok(gix_merge::blob::platform::merge::Options { is_virtual_ancestor: false, @@ -79,4 +81,58 @@ impl Repository { }, }) } + + /// Read all relevant configuration options to instantiate options for use in [`merge_trees()`](Self::merge_trees). + pub fn tree_merge_options(&self) -> Result { + Ok(gix_merge::tree::Options { + rewrites: crate::diff::utils::new_rewrites_inner( + &self.config.resolved, + self.config.lenient_config, + &tree::Merge::RENAMES, + &tree::Merge::RENAME_LIMIT, + )?, + blob_merge: self.blob_merge_options()?, + blob_merge_command_ctx: self.command_context()?, + fail_on_conflict: None, + marker_size_multiplier: 0, + symlink_conflicts: None, + allow_lossy_resolution: false, + }) + } + + /// Merge `our_tree` and `their_tree` together, assuming they have the same `ancestor_tree`, to yield a new tree + /// which is provided as [tree editor](gix_object::tree::Editor) to inspect and finalize results at will. + /// No change to the worktree or index is made, but objects may be written to the object database as merge results + /// are stored. + /// If these changes should not be observable outside of this instance, consider [enabling object memory](Self::with_object_memory). + /// + /// Note that `ancestor_tree` can be the [empty tree hash](gix_hash::ObjectId::empty_tree) to indicate no common ancestry. + /// + /// `labels` are typically chosen to identify the refs or names for `our_tree` and `their_tree` and `ancestor_tree` respectively. + /// + /// `options` should be initialized with [`tree_merge_options()`](Self::tree_merge_options()). + // TODO: Use `crate::merge::Options` here and add niceties such as setting the resolution strategy. + pub fn merge_trees( + &self, + ancestor_tree: impl AsRef, + our_tree: impl AsRef, + their_tree: impl AsRef, + labels: gix_merge::blob::builtin_driver::text::Labels<'_>, + options: gix_merge::tree::Options, + ) -> Result, merge_trees::Error> { + let mut diff_cache = self.diff_resource_cache_for_tree_diff()?; + let mut blob_merge = self.merge_resource_cache(Default::default())?; + Ok(gix_merge::tree( + ancestor_tree.as_ref(), + our_tree.as_ref(), + their_tree.as_ref(), + labels, + self, + |buf| self.write_buf(gix_object::Kind::Blob, buf), + &mut Default::default(), + &mut diff_cache, + &mut blob_merge, + options, + )?) + } } diff --git a/gix/src/repository/mod.rs b/gix/src/repository/mod.rs index a7659a858de..8485b8d7cd5 100644 --- a/gix/src/repository/mod.rs +++ b/gix/src/repository/mod.rs @@ -112,6 +112,38 @@ pub mod merge_resource_cache { } } +/// +#[cfg(feature = "blob-merge")] +pub mod merge_trees { + /// The error returned by [Repository::merge_trees()](crate::Repository::merge_trees()). + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error(transparent)] + MergeResourceCache(#[from] super::merge_resource_cache::Error), + #[error(transparent)] + DiffResourceCache(#[from] super::diff_resource_cache::Error), + #[error(transparent)] + TreeMerge(#[from] gix_merge::tree::Error), + } +} + +/// +#[cfg(feature = "blob-merge")] +pub mod tree_merge_options { + /// The error returned by [Repository::tree_merge_options()](crate::Repository::tree_merge_options()). + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error(transparent)] + BlobMergeOptions(#[from] super::blob_merge_options::Error), + #[error(transparent)] + RewritesConfig(#[from] crate::diff::new_rewrites::Error), + #[error(transparent)] + CommandContext(#[from] crate::config::command_context::Error), + } +} + /// #[cfg(feature = "blob-diff")] pub mod diff_resource_cache { From 84707c2b7540f9a73cc3f0cde74dabd9822cd809 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 1 Nov 2024 20:06:36 +0100 Subject: [PATCH 23/23] feat: add `gix merge tree` to merge trees similarly to `git merge-tree`. --- .../repository/{merge.rs => merge/file.rs} | 0 gitoxide-core/src/repository/merge/mod.rs | 5 + gitoxide-core/src/repository/merge/tree.rs | 112 ++++++++++++++++++ src/plumbing/main.rs | 41 +++++-- src/plumbing/options/mod.rs | 32 +++++ 5 files changed, 179 insertions(+), 11 deletions(-) rename gitoxide-core/src/repository/{merge.rs => merge/file.rs} (100%) create mode 100644 gitoxide-core/src/repository/merge/mod.rs create mode 100644 gitoxide-core/src/repository/merge/tree.rs diff --git a/gitoxide-core/src/repository/merge.rs b/gitoxide-core/src/repository/merge/file.rs similarity index 100% rename from gitoxide-core/src/repository/merge.rs rename to gitoxide-core/src/repository/merge/file.rs diff --git a/gitoxide-core/src/repository/merge/mod.rs b/gitoxide-core/src/repository/merge/mod.rs new file mode 100644 index 00000000000..6acb97bba28 --- /dev/null +++ b/gitoxide-core/src/repository/merge/mod.rs @@ -0,0 +1,5 @@ +mod file; +pub use file::file; + +pub mod tree; +pub use tree::function::tree; diff --git a/gitoxide-core/src/repository/merge/tree.rs b/gitoxide-core/src/repository/merge/tree.rs new file mode 100644 index 00000000000..3f497f08a37 --- /dev/null +++ b/gitoxide-core/src/repository/merge/tree.rs @@ -0,0 +1,112 @@ +use crate::OutputFormat; + +pub struct Options { + pub format: OutputFormat, + pub resolve_content_merge: Option, + pub in_memory: bool, +} + +pub(super) mod function { + + use crate::OutputFormat; + use anyhow::{anyhow, bail, Context}; + use gix::bstr::BString; + use gix::bstr::ByteSlice; + use gix::merge::blob::builtin_driver::binary; + use gix::merge::blob::builtin_driver::text::Conflict; + use gix::merge::tree::UnresolvedConflict; + use gix::prelude::Write; + + use super::Options; + + #[allow(clippy::too_many_arguments)] + pub fn tree( + mut repo: gix::Repository, + out: &mut dyn std::io::Write, + err: &mut dyn std::io::Write, + base: BString, + ours: BString, + theirs: BString, + Options { + format, + resolve_content_merge, + in_memory, + }: Options, + ) -> anyhow::Result<()> { + if format != OutputFormat::Human { + bail!("JSON output isn't implemented yet"); + } + repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&**repo.index_or_empty()?)); + if in_memory { + repo.objects.enable_object_memory(); + } + let (base_ref, base_id) = refname_and_tree(&repo, base)?; + let (ours_ref, ours_id) = refname_and_tree(&repo, ours)?; + let (theirs_ref, theirs_id) = refname_and_tree(&repo, theirs)?; + + let mut options = repo.tree_merge_options()?; + if let Some(resolve) = resolve_content_merge { + options.blob_merge.text.conflict = resolve; + options.blob_merge.resolve_binary_with = match resolve { + Conflict::Keep { .. } => None, + Conflict::ResolveWithOurs => Some(binary::ResolveWith::Ours), + Conflict::ResolveWithTheirs => Some(binary::ResolveWith::Theirs), + Conflict::ResolveWithUnion => None, + }; + } + + let base_id_str = base_id.to_string(); + let ours_id_str = ours_id.to_string(); + let theirs_id_str = theirs_id.to_string(); + let labels = gix::merge::blob::builtin_driver::text::Labels { + ancestor: base_ref + .as_ref() + .map_or(base_id_str.as_str().into(), |n| n.as_bstr()) + .into(), + current: ours_ref + .as_ref() + .map_or(ours_id_str.as_str().into(), |n| n.as_bstr()) + .into(), + other: theirs_ref + .as_ref() + .map_or(theirs_id_str.as_str().into(), |n| n.as_bstr()) + .into(), + }; + let mut res = repo.merge_trees(base_id, ours_id, theirs_id, labels, options)?; + { + let _span = gix::trace::detail!("Writing merged tree"); + let mut written = 0; + let tree_id = res + .tree + .write(|tree| { + written += 1; + repo.write(tree) + }) + .map_err(|err| anyhow!("{err}"))?; + writeln!(out, "{tree_id} (wrote {written} trees)")?; + } + + if !res.conflicts.is_empty() { + writeln!(err, "{} possibly resolved conflicts", res.conflicts.len())?; + } + if res.has_unresolved_conflicts(UnresolvedConflict::Renames) { + bail!("Tree conflicted") + } + Ok(()) + } + + fn refname_and_tree( + repo: &gix::Repository, + revspec: BString, + ) -> anyhow::Result<(Option, gix::hash::ObjectId)> { + let spec = repo.rev_parse(revspec.as_bstr())?; + let tree_id = spec + .single() + .context("Expected revspec to expand to a single rev only")? + .object()? + .peel_to_tree()? + .id; + let refname = spec.first_reference().map(|r| r.name.shorten().as_bstr().to_owned()); + Ok((refname, tree_id)) + } +} diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 944c7c9022f..c7859a0938f 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -164,23 +164,42 @@ pub fn main() -> Result<()> { repository(Mode::Lenient)?, out, format, - resolve_with.map(|c| match c { - merge::ResolveWith::Union => { - gix::merge::blob::builtin_driver::text::Conflict::ResolveWithUnion - } - merge::ResolveWith::Ours => { - gix::merge::blob::builtin_driver::text::Conflict::ResolveWithOurs - } - merge::ResolveWith::Theirs => { - gix::merge::blob::builtin_driver::text::Conflict::ResolveWithTheirs - } - }), + resolve_with.map(Into::into), base, ours, theirs, ) }, ), + merge::SubCommands::Tree { + in_memory, + resolve_content_with, + ours, + base, + theirs, + } => prepare_and_run( + "merge-tree", + trace, + verbose, + progress, + progress_keep_open, + None, + move |_progress, out, err| { + core::repository::merge::tree( + repository(Mode::Lenient)?, + out, + err, + base, + ours, + theirs, + core::repository::merge::tree::Options { + format, + resolve_content_merge: resolve_content_with.map(Into::into), + in_memory, + }, + ) + }, + ), }, Subcommands::MergeBase(crate::plumbing::options::merge_base::Command { first, others }) => prepare_and_run( "merge-base", diff --git a/src/plumbing/options/mod.rs b/src/plumbing/options/mod.rs index b6b1b005f11..47f92b4034f 100644 --- a/src/plumbing/options/mod.rs +++ b/src/plumbing/options/mod.rs @@ -357,6 +357,16 @@ pub mod merge { Theirs, } + impl From for gix::merge::blob::builtin_driver::text::Conflict { + fn from(value: ResolveWith) -> Self { + match value { + ResolveWith::Union => gix::merge::blob::builtin_driver::text::Conflict::ResolveWithUnion, + ResolveWith::Ours => gix::merge::blob::builtin_driver::text::Conflict::ResolveWithOurs, + ResolveWith::Theirs => gix::merge::blob::builtin_driver::text::Conflict::ResolveWithTheirs, + } + } + } + #[derive(Debug, clap::Parser)] #[command(about = "perform merges of various kinds")] pub struct Platform { @@ -382,6 +392,28 @@ pub mod merge { #[clap(value_name = "OURS", value_parser = crate::shared::AsBString)] theirs: BString, }, + + /// Merge a tree by specifying ours, base and theirs, writing it to the object database. + Tree { + /// Keep all objects to be written in memory to avoid any disk IO. + /// + /// Note that the resulting tree won't be available or inspectable. + #[clap(long, short = 'm')] + in_memory: bool, + /// Decide how to resolve content conflicts. If unset, write conflict markers and fail. + #[clap(long, short = 'c')] + resolve_content_with: Option, + + /// A revspec to our treeish. + #[clap(value_name = "OURS", value_parser = crate::shared::AsBString)] + ours: BString, + /// A revspec to the base as treeish for both ours and theirs. + #[clap(value_name = "BASE", value_parser = crate::shared::AsBString)] + base: BString, + /// A revspec to their treeish. + #[clap(value_name = "OURS", value_parser = crate::shared::AsBString)] + theirs: BString, + }, } }