diff --git a/cli/src/commands/mod.rs b/cli/src/commands/mod.rs index 6f1950c72..6c0465c75 100644 --- a/cli/src/commands/mod.rs +++ b/cli/src/commands/mod.rs @@ -33,7 +33,7 @@ use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; use jj_lib::backend::{CommitId, ObjectId, TreeValue}; use jj_lib::commit::Commit; -use jj_lib::conflicts::Conflict; +use jj_lib::conflicts::Merge; use jj_lib::dag_walk::topo_order_reverse; use jj_lib::git_backend::GitBackend; use jj_lib::matchers::EverythingMatcher; @@ -2703,7 +2703,7 @@ fn cmd_chmod(ui: &mut Ui, command: &CommandHelper, args: &ChmodArgs) -> Result<( )); } let new_conflict_id = - store.write_conflict(&repo_path, &Conflict::new(new_removes, new_adds))?; + store.write_conflict(&repo_path, &Merge::new(new_removes, new_adds))?; TreeValue::Conflict(new_conflict_id) } Some(_) => return Err(user_error_with_path("Found neither a file nor a conflict")), @@ -2805,7 +2805,7 @@ fn cmd_resolve( #[instrument(skip_all)] fn print_conflicted_paths( - conflicts: &[(RepoPath, Conflict>)], + conflicts: &[(RepoPath, Merge>)], formatter: &mut dyn Formatter, workspace_command: &WorkspaceCommandHelper, ) -> Result<(), CommandError> { diff --git a/cli/src/merge_tools.rs b/cli/src/merge_tools.rs index 3dd9da999..d179f44e4 100644 --- a/cli/src/merge_tools.rs +++ b/cli/src/merge_tools.rs @@ -244,7 +244,7 @@ pub fn run_mergetool( None => return Err(ConflictResolveError::PathNotFound(repo_path.clone())), }; let conflict = tree.store().read_conflict(repo_path, &conflict_id)?; - let file_conflict = conflict.to_file_conflict().ok_or_else(|| { + let file_merge = conflict.to_file_merge().ok_or_else(|| { let mut summary_bytes: Vec = vec![]; conflict .describe(&mut summary_bytes) @@ -255,13 +255,13 @@ pub fn run_mergetool( ) })?; // We only support conflicts with 2 sides (3-way conflicts) - if file_conflict.adds().len() > 2 { + if file_merge.adds().len() > 2 { return Err(ConflictResolveError::ConflictTooComplicated { path: repo_path.clone(), - sides: file_conflict.adds().len(), + sides: file_merge.adds().len(), }); }; - let content = file_conflict.extract_as_single_hunk(tree.store(), repo_path); + let content = file_merge.extract_as_single_hunk(tree.store(), repo_path); let editor = get_merge_tool_from_settings(ui, settings)?; let initial_output_content: Vec = if editor.merge_tool_edits_conflict_markers { diff --git a/lib/src/backend.rs b/lib/src/backend.rs index cc06e6e0a..06ef84fa9 100644 --- a/lib/src/backend.rs +++ b/lib/src/backend.rs @@ -23,7 +23,7 @@ use std::vec::Vec; use thiserror::Error; -use crate::conflicts; +use crate::conflicts::Merge; use crate::content_hash::ContentHash; use crate::repo_path::{RepoPath, RepoPathComponent}; @@ -148,7 +148,7 @@ content_hash! { pub struct Commit { pub parents: Vec, pub predecessors: Vec, - pub root_tree: conflicts::Conflict, + pub root_tree: Merge, /// Indicates that there this commit uses the new tree-level conflict format, which means /// that if `root_tree` is not a conflict, we know that we won't have to walk it to /// determine if there are conflicts. @@ -397,7 +397,7 @@ pub fn make_root_commit(root_change_id: ChangeId, empty_tree_id: TreeId) -> Comm Commit { parents: vec![], predecessors: vec![], - root_tree: conflicts::Conflict::resolved(empty_tree_id), + root_tree: Merge::resolved(empty_tree_id), uses_tree_conflict_format: false, change_id: root_change_id, description: String::new(), diff --git a/lib/src/commit_builder.rs b/lib/src/commit_builder.rs index 1f24e914e..c58049824 100644 --- a/lib/src/commit_builder.rs +++ b/lib/src/commit_builder.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use crate::backend::{self, BackendResult, ChangeId, CommitId, Signature, TreeId}; use crate::commit::Commit; -use crate::conflicts::Conflict; +use crate::conflicts::Merge; use crate::repo::{MutableRepo, Repo}; use crate::settings::{JJRng, UserSettings}; @@ -45,7 +45,7 @@ impl CommitBuilder<'_> { parents, predecessors: vec![], // TODO(#1624): set this when appropriate - root_tree: Conflict::from_legacy_tree_id(tree_id), + root_tree: Merge::from_legacy_tree_id(tree_id), uses_tree_conflict_format: false, change_id, description: String::new(), @@ -108,7 +108,7 @@ impl CommitBuilder<'_> { } pub fn set_tree(mut self, tree_id: TreeId) -> Self { - self.commit.root_tree = Conflict::from_legacy_tree_id(tree_id); + self.commit.root_tree = Merge::from_legacy_tree_id(tree_id); self } diff --git a/lib/src/conflicts.rs b/lib/src/conflicts.rs index ed953e490..496803063 100644 --- a/lib/src/conflicts.rs +++ b/lib/src/conflicts.rs @@ -37,34 +37,34 @@ const CONFLICT_DIFF_LINE: &[u8] = b"%%%%%%%\n"; const CONFLICT_MINUS_LINE: &[u8] = b"-------\n"; const CONFLICT_PLUS_LINE: &[u8] = b"+++++++\n"; -/// A generic representation of conflicting values. +/// A generic representation of merged values. /// /// There is exactly one more `adds()` than `removes()`. When interpreted as a -/// series of diffs, the conflict's (i+1)-st add is matched with the i-th +/// series of diffs, the merge's (i+1)-st add is matched with the i-th /// remove. The zeroth add is considered a diff from the non-existent state. #[derive(PartialEq, Eq, Hash, Clone, Debug)] -pub struct Conflict { +pub struct Merge { removes: Vec, adds: Vec, } -impl Conflict { +impl Merge { pub fn new(removes: Vec, adds: Vec) -> Self { assert_eq!(adds.len(), removes.len() + 1); - Conflict { removes, adds } + Merge { removes, adds } } - /// Creates a `Conflict` with a single resolved value. + /// Creates a `Merge` with a single resolved value. pub fn resolved(value: T) -> Self { - Conflict::new(vec![], vec![value]) + Merge::new(vec![], vec![value]) } - /// Create a `Conflict` from a `removes` and `adds`, padding with `None` to + /// Create a `Merge` from a `removes` and `adds`, padding with `None` to /// make sure that there is exactly one more `adds` than `removes`. pub fn from_legacy_form( removes: impl IntoIterator, adds: impl IntoIterator, - ) -> Conflict> { + ) -> Merge> { let mut removes = removes.into_iter().map(Some).collect_vec(); let mut adds = adds.into_iter().map(Some).collect_vec(); while removes.len() + 1 < adds.len() { @@ -73,7 +73,7 @@ impl Conflict { while adds.len() < removes.len() + 1 { adds.push(None); } - Conflict::new(removes, adds) + Merge::new(removes, adds) } /// Returns the removes and adds as a pair. @@ -89,13 +89,13 @@ impl Conflict { &self.adds } - /// Whether this conflict is resolved. Does not resolve trivial conflicts. + /// Whether this merge is resolved. Does not resolve trivial merges. pub fn is_resolved(&self) -> bool { self.removes.is_empty() } - /// Returns the resolved value, if this conflict is resolved. Does not - /// resolve trivial conflicts. + /// Returns the resolved value, if this merge is resolved. Does not + /// resolve trivial merges. pub fn as_resolved(&self) -> Option<&T> { if let [value] = &self.adds[..] { Some(value) @@ -104,7 +104,7 @@ impl Conflict { } } - /// Simplify the conflict by joining diffs like A->B and B->C into A->C. + /// Simplify the merge by joining diffs like A->B and B->C into A->C. /// Also drops trivial diffs like A->A. pub fn simplify(mut self) -> Self where @@ -133,38 +133,35 @@ impl Conflict { trivial_merge(&self.removes, &self.adds) } - /// Creates a new conflict by applying `f` to each remove and add. - pub fn map<'a, U>(&'a self, mut f: impl FnMut(&'a T) -> U) -> Conflict { + /// Creates a new merge by applying `f` to each remove and add. + pub fn map<'a, U>(&'a self, mut f: impl FnMut(&'a T) -> U) -> Merge { self.maybe_map(|term| Some(f(term))).unwrap() } - /// Creates a new conflict by applying `f` to each remove and add, returning + /// Creates a new merge by applying `f` to each remove and add, returning /// `None if `f` returns `None` for any of them. - pub fn maybe_map<'a, U>( - &'a self, - mut f: impl FnMut(&'a T) -> Option, - ) -> Option> { + pub fn maybe_map<'a, U>(&'a self, mut f: impl FnMut(&'a T) -> Option) -> Option> { let removes = self.removes.iter().map(&mut f).collect::>()?; let adds = self.adds.iter().map(&mut f).collect::>()?; - Some(Conflict { removes, adds }) + Some(Merge { removes, adds }) } - /// Creates a new conflict by applying `f` to each remove and add, returning + /// Creates a new merge by applying `f` to each remove and add, returning /// `Err if `f` returns `Err` for any of them. pub fn try_map<'a, U, E>( &'a self, mut f: impl FnMut(&'a T) -> Result, - ) -> Result, E> { + ) -> Result, E> { let removes = self.removes.iter().map(&mut f).try_collect()?; let adds = self.adds.iter().map(&mut f).try_collect()?; - Ok(Conflict { removes, adds }) + Ok(Merge { removes, adds }) } } -impl Conflict> { - /// Creates lists of `removes` and `adds` from a `Conflict` by dropping +impl Merge> { + /// Creates lists of `removes` and `adds` from a `Merge` by dropping /// `None` values. Note that the conversion is lossy: the order of `None` - /// values is not preserved when converting back to a `Conflict`. + /// values is not preserved when converting back to a `Merge`. pub fn into_legacy_form(self) -> (Vec, Vec) { ( self.removes.into_iter().flatten().collect(), @@ -173,8 +170,8 @@ impl Conflict> { } } -impl Conflict> { - /// Flattens a nested conflict into a regular conflict. +impl Merge> { + /// Flattens a nested merge into a regular merge. /// /// Let's say we have a 3-way merge of 3-way merges like this: /// @@ -183,11 +180,11 @@ impl Conflict> { /// 1 2 /// 0 /// - /// Flattening that results in this 9-way conflict: + /// Flattening that results in this 9-way merge: /// /// 4 5 0 7 8 /// 3 2 1 6 - pub fn flatten(mut self) -> Conflict { + pub fn flatten(mut self) -> Merge { self.removes.reverse(); self.adds.reverse(); let mut result = self.adds.pop().unwrap(); @@ -207,20 +204,20 @@ impl Conflict> { } } -impl ContentHash for Conflict { +impl ContentHash for Merge { fn hash(&self, state: &mut impl digest::Update) { self.removes().hash(state); self.adds().hash(state); } } -impl Conflict { - // Creates a resolved conflict for a legacy tree id (same as - // `Conflict::resolved()`). +impl Merge { + // Creates a resolved merge for a legacy tree id (same as + // `Merge::resolved()`). // TODO(#1624): delete when all callers have been updated to support tree-level // conflicts pub fn from_legacy_tree_id(value: TreeId) -> Self { - Conflict { + Merge { removes: vec![], adds: vec![value], } @@ -233,18 +230,18 @@ impl Conflict { } } -impl Conflict> { - /// Create a `Conflict` from a `backend::Conflict`, padding with `None` to +impl Merge> { + /// Create a `Merge` from a `backend::Conflict`, padding with `None` to /// make sure that there is exactly one more `adds()` than `removes()`. pub fn from_backend_conflict(conflict: backend::Conflict) -> Self { let removes = conflict.removes.into_iter().map(|term| term.value); let adds = conflict.adds.into_iter().map(|term| term.value); - Conflict::from_legacy_form(removes, adds) + Merge::from_legacy_form(removes, adds) } - /// Creates a `backend::Conflict` from a `Conflict` by dropping `None` + /// Creates a `backend::Conflict` from a `Merge` by dropping `None` /// values. Note that the conversion is lossy: the order of `None` values is - /// not preserved when converting back to a `Conflict`. + /// not preserved when converting back to a `Merge`. pub fn into_backend_conflict(self) -> backend::Conflict { let (removes, adds) = self.into_legacy_form(); let removes = removes @@ -264,17 +261,17 @@ impl Conflict> { path: &RepoPath, output: &mut dyn Write, ) -> std::io::Result<()> { - if let Some(file_conflict) = self.to_file_conflict() { - let content = file_conflict.extract_as_single_hunk(store, path); + if let Some(file_merge) = self.to_file_merge() { + let content = file_merge.extract_as_single_hunk(store, path); materialize_merge_result(&content, output) } else { // Unless all terms are regular files, we can't do much better than to try to - // describe the conflict. + // describe the merge. self.describe(output) } } - pub fn to_file_conflict(&self) -> Option>> { + pub fn to_file_merge(&self) -> Option>> { self.maybe_map(|term| match term { None => Some(None), Some(TreeValue::File { @@ -303,9 +300,9 @@ impl Conflict> { store: &Store, path: &RepoPath, content: &[u8], - ) -> BackendResult>>> { + ) -> BackendResult>>> { // TODO: Check that the conflict only involves files and convert it to a - // `Conflict>` so we can remove the wildcard pattern in the loops + // `Merge>` so we can remove the wildcard pattern in the loops // further down. // First check if the new content is unchanged compared to the old content. If @@ -344,7 +341,7 @@ impl Conflict> { } } // Now write the new files contents we found by parsing the file - // with conflict markers. Update the Conflict object with the new + // with conflict markers. Update the Merge object with the new // FileIds. let mut new_removes = vec![]; for (i, buf) in removed_content.iter().enumerate() { @@ -392,30 +389,30 @@ impl Conflict> { } } } - Ok(Some(Conflict::new(new_removes, new_adds))) + Ok(Some(Merge::new(new_removes, new_adds))) } } -impl Conflict> { - pub fn extract_as_single_hunk(&self, store: &Store, path: &RepoPath) -> Conflict { +impl Merge> { + pub fn extract_as_single_hunk(&self, store: &Store, path: &RepoPath) -> Merge { self.map(|term| get_file_contents(store, path, term)) } } -impl Conflict> +impl Merge> where T: Borrow, { - /// If every non-`None` term of a `Conflict>` + /// If every non-`None` term of a `Merge>` /// is a `TreeValue::Tree`, this converts it to - /// a `Conflict`, with empty trees instead of + /// a `Merge`, with empty trees instead of /// any `None` terms. Otherwise, returns `None`. - pub fn to_tree_conflict( + pub fn to_tree_merge( &self, store: &Arc, dir: &RepoPath, - ) -> Result>, BackendError> { - let tree_id_conflict = self.maybe_map(|term| match term { + ) -> Result>, BackendError> { + let tree_id_merge = self.maybe_map(|term| match term { None => Some(None), Some(value) => { if let TreeValue::Tree(id) = value.borrow() { @@ -425,7 +422,7 @@ where } } }); - if let Some(tree_id_conflict) = tree_id_conflict { + if let Some(tree_id_merge) = tree_id_merge { let get_tree = |id: &Option<&TreeId>| -> Result { if let Some(id) = id { store.get_tree(dir, id) @@ -433,7 +430,7 @@ where Ok(Tree::null(store.clone(), dir.clone())) } }; - Ok(Some(tree_id_conflict.try_map(get_tree)?)) + Ok(Some(tree_id_merge.try_map(get_tree)?)) } else { Ok(None) } @@ -511,7 +508,7 @@ fn write_diff_hunks(hunks: &[DiffHunk], file: &mut dyn Write) -> std::io::Result } pub fn materialize_merge_result( - single_hunk: &Conflict, + single_hunk: &Merge, output: &mut dyn Write, ) -> std::io::Result<()> { let removed_slices = single_hunk @@ -608,7 +605,7 @@ pub fn parse_conflict( input: &[u8], num_removes: usize, num_adds: usize, -) -> Option>> { +) -> Option>> { if input.is_empty() { return None; } @@ -625,7 +622,7 @@ pub fn parse_conflict( if hunk.removes().len() == num_removes && hunk.adds().len() == num_adds { let resolved_slice = &input[resolved_start..conflict_start.unwrap()]; if !resolved_slice.is_empty() { - hunks.push(Conflict::resolved(ContentHunk(resolved_slice.to_vec()))); + hunks.push(Merge::resolved(ContentHunk(resolved_slice.to_vec()))); } hunks.push(hunk); resolved_start = pos + line.len(); @@ -639,7 +636,7 @@ pub fn parse_conflict( None } else { if resolved_start < input.len() { - hunks.push(Conflict::resolved(ContentHunk( + hunks.push(Merge::resolved(ContentHunk( input[resolved_start..].to_vec(), ))); } @@ -647,7 +644,7 @@ pub fn parse_conflict( } } -fn parse_conflict_hunk(input: &[u8]) -> Conflict { +fn parse_conflict_hunk(input: &[u8]) -> Merge { enum State { Diff, Minus, @@ -688,7 +685,7 @@ fn parse_conflict_hunk(input: &[u8]) -> Conflict { adds.last_mut().unwrap().0.extend_from_slice(rest); } else { // Doesn't look like a conflict - return Conflict::resolved(ContentHunk(vec![])); + return Merge::resolved(ContentHunk(vec![])); } } State::Minus => { @@ -699,81 +696,78 @@ fn parse_conflict_hunk(input: &[u8]) -> Conflict { } State::Unknown => { // Doesn't look like a conflict - return Conflict::resolved(ContentHunk(vec![])); + return Merge::resolved(ContentHunk(vec![])); } } } - Conflict::new(removes, adds) + Merge::new(removes, adds) } #[cfg(test)] mod tests { use super::*; - fn c(removes: &[T], adds: &[T]) -> Conflict { - Conflict::new(removes.to_vec(), adds.to_vec()) + fn c(removes: &[T], adds: &[T]) -> Merge { + Merge::new(removes.to_vec(), adds.to_vec()) } #[test] fn test_legacy_form_conversion() { - fn test_equivalent(legacy_form: (Vec, Vec), conflict: Conflict>) + fn test_equivalent(legacy_form: (Vec, Vec), merge: Merge>) where T: Clone + PartialEq + std::fmt::Debug, { - assert_eq!(conflict.clone().into_legacy_form(), legacy_form); - assert_eq!( - Conflict::from_legacy_form(legacy_form.0, legacy_form.1), - conflict - ); + assert_eq!(merge.clone().into_legacy_form(), legacy_form); + assert_eq!(Merge::from_legacy_form(legacy_form.0, legacy_form.1), merge); } // Non-conflict - test_equivalent((vec![], vec![0]), Conflict::new(vec![], vec![Some(0)])); + test_equivalent((vec![], vec![0]), Merge::new(vec![], vec![Some(0)])); // Regular 3-way conflict test_equivalent( (vec![0], vec![1, 2]), - Conflict::new(vec![Some(0)], vec![Some(1), Some(2)]), + Merge::new(vec![Some(0)], vec![Some(1), Some(2)]), ); // Modify/delete conflict test_equivalent( (vec![0], vec![1]), - Conflict::new(vec![Some(0)], vec![Some(1), None]), + Merge::new(vec![Some(0)], vec![Some(1), None]), ); // Add/add conflict test_equivalent( (vec![], vec![0, 1]), - Conflict::new(vec![None], vec![Some(0), Some(1)]), + Merge::new(vec![None], vec![Some(0), Some(1)]), ); // 5-way conflict test_equivalent( (vec![0, 1], vec![2, 3, 4]), - Conflict::new(vec![Some(0), Some(1)], vec![Some(2), Some(3), Some(4)]), + Merge::new(vec![Some(0), Some(1)], vec![Some(2), Some(3), Some(4)]), ); // 5-way delete/delete conflict test_equivalent( (vec![0, 1], vec![]), - Conflict::new(vec![Some(0), Some(1)], vec![None, None, None]), + Merge::new(vec![Some(0), Some(1)], vec![None, None, None]), ); } #[test] fn test_as_resolved() { - assert_eq!(Conflict::new(vec![], vec![0]).as_resolved(), Some(&0)); - // Even a trivially resolvable conflict is not resolved - assert_eq!(Conflict::new(vec![0], vec![0, 1]).as_resolved(), None); + assert_eq!(Merge::new(vec![], vec![0]).as_resolved(), Some(&0)); + // Even a trivially resolvable merge is not resolved + assert_eq!(Merge::new(vec![0], vec![0, 1]).as_resolved(), None); } #[test] fn test_simplify() { - // 1-way "conflict" + // 1-way merge assert_eq!(c(&[], &[0]).simplify(), c(&[], &[0])); - // 3-way conflict + // 3-way merge assert_eq!(c(&[0], &[0, 0]).simplify(), c(&[], &[0])); assert_eq!(c(&[0], &[0, 1]).simplify(), c(&[], &[1])); assert_eq!(c(&[0], &[1, 0]).simplify(), c(&[], &[1])); assert_eq!(c(&[0], &[1, 1]).simplify(), c(&[0], &[1, 1])); assert_eq!(c(&[0], &[1, 2]).simplify(), c(&[0], &[1, 2])); - // 5-way conflict + // 5-way merge assert_eq!(c(&[0, 0], &[0, 0, 0]).simplify(), c(&[], &[0])); assert_eq!(c(&[0, 0], &[0, 0, 1]).simplify(), c(&[], &[1])); assert_eq!(c(&[0, 0], &[0, 1, 0]).simplify(), c(&[], &[1])); @@ -833,31 +827,31 @@ mod tests { } #[test] - fn test_conflict_invariants() { + fn test_merge_invariants() { fn check_invariants(removes: &[u32], adds: &[u32]) { - let conflict = Conflict::new(removes.to_vec(), adds.to_vec()); + let merge = Merge::new(removes.to_vec(), adds.to_vec()); // `simplify()` is idempotent assert_eq!( - conflict.clone().simplify().simplify(), - conflict.clone().simplify(), - "simplify() not idempotent for {conflict:?}" + merge.clone().simplify().simplify(), + merge.clone().simplify(), + "simplify() not idempotent for {merge:?}" ); // `resolve_trivial()` is unaffected by `simplify()` assert_eq!( - conflict.clone().simplify().resolve_trivial(), - conflict.resolve_trivial(), - "simplify() changed result of resolve_trivial() for {conflict:?}" + merge.clone().simplify().resolve_trivial(), + merge.resolve_trivial(), + "simplify() changed result of resolve_trivial() for {merge:?}" ); } - // 1-way "conflict" + // 1-way merge check_invariants(&[], &[0]); for i in 0..=1 { for j in 0..=i + 1 { - // 3-way conflict + // 3-way merge check_invariants(&[0], &[i, j]); for k in 0..=j + 1 { for l in 0..=k + 1 { - // 5-way conflict + // 5-way merge check_invariants(&[0, i], &[j, k, l]); } } @@ -870,9 +864,9 @@ mod tests { fn increment(i: &i32) -> i32 { i + 1 } - // 1-way conflict + // 1-way merge assert_eq!(c(&[], &[1]).map(increment), c(&[], &[2])); - // 3-way conflict + // 3-way merge assert_eq!(c(&[1], &[3, 5]).map(increment), c(&[2], &[4, 6])); } @@ -885,10 +879,10 @@ mod tests { None } } - // 1-way conflict + // 1-way merge assert_eq!(c(&[], &[1]).maybe_map(sqrt), Some(c(&[], &[1]))); assert_eq!(c(&[], &[-1]).maybe_map(sqrt), None); - // 3-way conflict + // 3-way merge assert_eq!(c(&[1], &[4, 9]).maybe_map(sqrt), Some(c(&[1], &[2, 3]))); assert_eq!(c(&[-1], &[4, 9]).maybe_map(sqrt), None); assert_eq!(c(&[1], &[-4, 9]).maybe_map(sqrt), None); @@ -903,10 +897,10 @@ mod tests { Err(()) } } - // 1-way conflict + // 1-way merge assert_eq!(c(&[], &[1]).try_map(sqrt), Ok(c(&[], &[1]))); assert_eq!(c(&[], &[-1]).try_map(sqrt), Err(())); - // 3-way conflict + // 3-way merge assert_eq!(c(&[1], &[4, 9]).try_map(sqrt), Ok(c(&[1], &[2, 3]))); assert_eq!(c(&[-1], &[4, 9]).try_map(sqrt), Err(())); assert_eq!(c(&[1], &[-4, 9]).try_map(sqrt), Err(())); @@ -914,16 +908,16 @@ mod tests { #[test] fn test_flatten() { - // 1-way conflict of 1-way conflict + // 1-way merge of 1-way merge assert_eq!(c(&[], &[c(&[], &[0])]).flatten(), c(&[], &[0])); - // 1-way conflict of 3-way conflict + // 1-way merge of 3-way merge assert_eq!(c(&[], &[c(&[0], &[1, 2])]).flatten(), c(&[0], &[1, 2])); - // 3-way conflict of 1-way conflicts + // 3-way merge of 1-way merges assert_eq!( c(&[c(&[], &[0])], &[c(&[], &[1]), c(&[], &[2])]).flatten(), c(&[0], &[1, 2]) ); - // 3-way conflict of 3-way conflicts + // 3-way merge of 3-way merges assert_eq!( c(&[c(&[0], &[1, 2])], &[c(&[3], &[4, 5]), c(&[6], &[7, 8])]).flatten(), c(&[3, 2, 1, 6], &[4, 5, 0, 7, 8]) diff --git a/lib/src/files.rs b/lib/src/files.rs index 56d369c14..1aa123d48 100644 --- a/lib/src/files.rs +++ b/lib/src/files.rs @@ -20,7 +20,7 @@ use std::ops::Range; use itertools::Itertools; -use crate::conflicts::Conflict; +use crate::conflicts::Merge; use crate::diff; use crate::diff::{Diff, DiffHunk}; use crate::merge::trivial_merge; @@ -157,7 +157,7 @@ impl Debug for ContentHunk { #[derive(PartialEq, Eq, Clone, Debug)] pub enum MergeResult { Resolved(ContentHunk), - Conflict(Vec>), + Conflict(Vec>), } /// A region where the base and two sides match. @@ -179,7 +179,7 @@ pub fn merge(removes: &[&[u8]], adds: &[&[u8]]) -> MergeResult { let diff = Diff::for_tokenizer(&diff_inputs, &diff::find_line_ranges); let mut resolved_hunk = ContentHunk(vec![]); - let mut merge_hunks: Vec> = vec![]; + let mut merge_hunks: Vec> = vec![]; for diff_hunk in diff.hunks() { match diff_hunk { DiffHunk::Matching(content) => { @@ -190,10 +190,10 @@ pub fn merge(removes: &[&[u8]], adds: &[&[u8]]) -> MergeResult { resolved_hunk.0.extend(*resolved); } else { if !resolved_hunk.0.is_empty() { - merge_hunks.push(Conflict::resolved(resolved_hunk)); + merge_hunks.push(Merge::resolved(resolved_hunk)); resolved_hunk = ContentHunk(vec![]); } - merge_hunks.push(Conflict::new( + merge_hunks.push(Merge::new( parts[..num_diffs] .iter() .map(|part| ContentHunk(part.to_vec())) @@ -212,7 +212,7 @@ pub fn merge(removes: &[&[u8]], adds: &[&[u8]]) -> MergeResult { MergeResult::Resolved(resolved_hunk) } else { if !resolved_hunk.0.is_empty() { - merge_hunks.push(Conflict::resolved(resolved_hunk)); + merge_hunks.push(Merge::resolved(resolved_hunk)); } MergeResult::Conflict(merge_hunks) } @@ -268,7 +268,7 @@ mod tests { // One side modified, two sides added assert_eq!( merge(&[b"a", b""], &[b"b", b"b", b"b"]), - MergeResult::Conflict(vec![Conflict::new( + MergeResult::Conflict(vec![Merge::new( vec![hunk(b"a"), hunk(b"")], vec![hunk(b"b"), hunk(b"b"), hunk(b"b")] )]) @@ -281,7 +281,7 @@ mod tests { // One side modified, two sides removed assert_eq!( merge(&[b"a\n", b"a\n"], &[b"b\n", b"", b""]), - MergeResult::Conflict(vec![Conflict::new( + MergeResult::Conflict(vec![Merge::new( vec![hunk(b"a\n"), hunk(b"a\n")], vec![hunk(b"b\n"), hunk(b""), hunk(b"")] )]) @@ -294,7 +294,7 @@ mod tests { // One side removed, one side modified assert_eq!( merge(&[b"a\n"], &[b"", b"b\n"]), - MergeResult::Conflict(vec![Conflict::new( + MergeResult::Conflict(vec![Merge::new( vec![hunk(b"a\n")], vec![hunk(b""), hunk(b"b\n")] )]) @@ -302,7 +302,7 @@ mod tests { // One side modified, one side removed assert_eq!( merge(&[b"a\n"], &[b"b\n", b""]), - MergeResult::Conflict(vec![Conflict::new( + MergeResult::Conflict(vec![Merge::new( vec![hunk(b"a\n")], vec![hunk(b"b\n"), hunk(b"")] )]) @@ -310,7 +310,7 @@ mod tests { // Two sides modified in different ways assert_eq!( merge(&[b"a"], &[b"b", b"c"]), - MergeResult::Conflict(vec![Conflict::new( + MergeResult::Conflict(vec![Merge::new( vec![hunk(b"a")], vec![hunk(b"b"), hunk(b"c")] )]) @@ -328,7 +328,7 @@ mod tests { // One side unchanged, two other sides make the different change assert_eq!( merge(&[b"a", b"a"], &[b"b", b"a", b"c"]), - MergeResult::Conflict(vec![Conflict::new( + MergeResult::Conflict(vec![Merge::new( vec![hunk(b"a"), hunk(b"a")], vec![hunk(b"b"), hunk(b"a"), hunk(b"c")] )]) @@ -343,7 +343,7 @@ mod tests { // Merge of an unresolved conflict and another branch. assert_eq!( merge(&[b"a", b"b"], &[b"c", b"d", b"e"]), - MergeResult::Conflict(vec![Conflict::new( + MergeResult::Conflict(vec![Merge::new( vec![hunk(b"a"), hunk(b"b")], vec![hunk(b"c"), hunk(b"d"), hunk(b"e")] )]) @@ -351,7 +351,7 @@ mod tests { // Two sides made the same change, third side made a different change assert_eq!( merge(&[b"a", b"b"], &[b"c", b"c", b"c"]), - MergeResult::Conflict(vec![Conflict::new( + MergeResult::Conflict(vec![Merge::new( vec![hunk(b"a"), hunk(b"b")], vec![hunk(b"c"), hunk(b"c"), hunk(b"c")] )]) @@ -364,8 +364,8 @@ mod tests { assert_eq!( merge(&[b"a\n"], &[b"a\nb\n", b"a\nc\n"]), MergeResult::Conflict(vec![ - Conflict::resolved(hunk(b"a\n")), - Conflict::new(vec![hunk(b"")], vec![hunk(b"b\n"), hunk(b"c\n")]) + Merge::resolved(hunk(b"a\n")), + Merge::new(vec![hunk(b"")], vec![hunk(b"b\n"), hunk(b"c\n")]) ]) ); // Two sides changed different lines: no conflict @@ -377,9 +377,9 @@ mod tests { assert_eq!( merge(&[b"a\nb\nc\n"], &[b"a\nb1\nc\n", b"a\nb2\nc\n"]), MergeResult::Conflict(vec![ - Conflict::resolved(hunk(b"a\n")), - Conflict::new(vec![hunk(b"b\n")], vec![hunk(b"b1\n"), hunk(b"b2\n")]), - Conflict::resolved(hunk(b"c\n")) + Merge::resolved(hunk(b"a\n")), + Merge::new(vec![hunk(b"b\n")], vec![hunk(b"b1\n"), hunk(b"b2\n")]), + Merge::resolved(hunk(b"c\n")) ]) ); // One side changes a line and adds a block after. The other side just adds the diff --git a/lib/src/git_backend.rs b/lib/src/git_backend.rs index a3e5adb62..e8bbcdb46 100644 --- a/lib/src/git_backend.rs +++ b/lib/src/git_backend.rs @@ -32,7 +32,7 @@ use crate::backend::{ ChangeId, Commit, CommitId, Conflict, ConflictId, ConflictTerm, FileId, MillisSinceEpoch, ObjectId, Signature, SymlinkId, Timestamp, Tree, TreeId, TreeValue, }; -use crate::conflicts; +use crate::conflicts::Merge; use crate::file_util::{IoResultExt as _, PathError}; use crate::lock::FileLock; use crate::repo_path::{RepoPath, RepoPathComponent}; @@ -223,7 +223,7 @@ fn commit_from_git_without_root_parent(commit: &git2::Commit) -> Commit { let tree_id = TreeId::from_bytes(commit.tree_id().as_bytes()); // If this commit is a conflict, we'll update the root tree later, when we read // the extra metadata. - let root_tree = conflicts::Conflict::resolved(tree_id); + let root_tree = Merge::resolved(tree_id); let description = commit.message().unwrap_or("").to_owned(); let author = signature_from_git(commit.author()); let committer = signature_from_git(commit.committer()); @@ -304,7 +304,7 @@ fn deserialize_extras(commit: &mut Commit, bytes: &[u8]) { match proto.root_tree { Some(crate::protos::git_store::commit::RootTree::Conflict(proto_conflict)) => { assert!(commit.uses_tree_conflict_format); - commit.root_tree = conflicts::Conflict::new( + commit.root_tree = Merge::new( proto_conflict .removes .iter() @@ -765,7 +765,7 @@ impl Backend for GitBackend { /// `.jjconflict-base-N` subtrees. This ensure that the parts are not GC'd. fn write_tree_conflict( repo: &git2::Repository, - conflict: &conflicts::Conflict, + conflict: &Merge, ) -> Result { let mut builder = repo.treebuilder(None).unwrap(); let mut add_tree_entry = |name, tree_id: &TreeId| { @@ -988,7 +988,7 @@ mod tests { let mut commit = Commit { parents: vec![], predecessors: vec![], - root_tree: conflicts::Conflict::resolved(backend.empty_tree_id().clone()), + root_tree: Merge::resolved(backend.empty_tree_id().clone()), uses_tree_conflict_format: false, change_id: ChangeId::from_hex("abc123"), description: "".to_string(), @@ -1058,7 +1058,7 @@ mod tests { TreeId::from_bytes(tree_builder.write().unwrap().as_bytes()) }; - let root_tree = conflicts::Conflict::new( + let root_tree = Merge::new( vec![crete_tree(0), crete_tree(1)], vec![crete_tree(2), crete_tree(3), crete_tree(4)], ); @@ -1103,7 +1103,7 @@ mod tests { // When writing a single tree using the new format, it's represented by a // regular git tree. - commit.root_tree = conflicts::Conflict::resolved(crete_tree(5)); + commit.root_tree = Merge::resolved(crete_tree(5)); let read_commit_id = backend.write_commit(commit.clone()).unwrap().0; let read_commit = backend.read_commit(&read_commit_id).unwrap(); assert_eq!(read_commit, commit); @@ -1131,7 +1131,7 @@ mod tests { let commit = Commit { parents: vec![store.root_commit_id().clone()], predecessors: vec![], - root_tree: conflicts::Conflict::resolved(store.empty_tree_id().clone()), + root_tree: Merge::resolved(store.empty_tree_id().clone()), uses_tree_conflict_format: false, change_id: ChangeId::new(vec![]), description: "initial".to_string(), @@ -1155,7 +1155,7 @@ mod tests { let mut commit1 = Commit { parents: vec![store.root_commit_id().clone()], predecessors: vec![], - root_tree: conflicts::Conflict::resolved(store.empty_tree_id().clone()), + root_tree: Merge::resolved(store.empty_tree_id().clone()), uses_tree_conflict_format: false, change_id: ChangeId::new(vec![]), description: "initial".to_string(), diff --git a/lib/src/local_backend.rs b/lib/src/local_backend.rs index b96f257a0..57858906d 100644 --- a/lib/src/local_backend.rs +++ b/lib/src/local_backend.rs @@ -30,7 +30,7 @@ use crate::backend::{ ConflictId, ConflictTerm, FileId, MillisSinceEpoch, ObjectId, Signature, SymlinkId, Timestamp, Tree, TreeId, TreeValue, }; -use crate::conflicts; +use crate::conflicts::Merge; use crate::content_hash::blake2b_hash; use crate::file_util::persist_content_addressed_temp_file; use crate::repo_path::{RepoPath, RepoPathComponent}; @@ -311,7 +311,7 @@ fn commit_from_proto(proto: crate::protos::local_store::Commit) -> Commit { let parents = proto.parents.into_iter().map(CommitId::new).collect(); let predecessors = proto.predecessors.into_iter().map(CommitId::new).collect(); let conflict = proto.root_tree.unwrap(); - let root_tree = conflicts::Conflict::new( + let root_tree = Merge::new( conflict.removes.into_iter().map(TreeId::new).collect(), conflict.adds.into_iter().map(TreeId::new).collect(), ); diff --git a/lib/src/merged_tree.rs b/lib/src/merged_tree.rs index c09cc554b..ce718ba09 100644 --- a/lib/src/merged_tree.rs +++ b/lib/src/merged_tree.rs @@ -22,7 +22,7 @@ use itertools::Itertools; use crate::backend; use crate::backend::{ConflictId, TreeValue}; -use crate::conflicts::Conflict; +use crate::conflicts::Merge; use crate::repo_path::{RepoPath, RepoPathComponent, RepoPathJoin}; use crate::store::Store; use crate::tree::{try_resolve_file_conflict, Tree, TreeMergeError}; @@ -35,7 +35,7 @@ pub enum MergedTree { Legacy(Tree), /// A merge of multiple trees, or just a single tree. The individual trees /// have no path-level conflicts. - Merge(Conflict), + Merge(Merge), } /// The value at a given path in a `MergedTree`. @@ -43,20 +43,20 @@ pub enum MergedTree { pub enum MergedTreeValue<'a> { /// A single non-conflicted value. Resolved(Option<&'a TreeValue>), - /// TODO: Make this a `Conflict>` (reference to the + /// TODO: Make this a `Merge>` (reference to the /// value) once we have removed the `MergedTree::Legacy` variant. - Conflict(Conflict>), + Conflict(Merge>), } impl MergedTree { /// Creates a new `MergedTree` representing a single tree without conflicts. pub fn resolved(tree: Tree) -> Self { - MergedTree::new(Conflict::resolved(tree)) + MergedTree::new(Merge::resolved(tree)) } /// Creates a new `MergedTree` representing a merge of a set of trees. The /// individual trees must not have any conflicts. - pub fn new(conflict: Conflict) -> Self { + pub fn new(conflict: Merge) -> Self { debug_assert!(!conflict.removes().iter().any(|t| t.has_conflict())); debug_assert!(!conflict.adds().iter().any(|t| t.has_conflict())); debug_assert!(itertools::chain(conflict.removes(), conflict.adds()) @@ -85,7 +85,7 @@ impl MergedTree { // build `2*num_removes + 1` trees let mut max_num_removes = 0; let store = tree.store(); - let mut conflicts: Vec<(&RepoPath, Conflict>)> = vec![]; + let mut conflicts: Vec<(&RepoPath, Merge>)> = vec![]; for (path, conflict_id) in &conflict_ids { let conflict = store.read_conflict(path, conflict_id).unwrap(); max_num_removes = max(max_num_removes, conflict.removes().len()); @@ -126,7 +126,7 @@ impl MergedTree { store.get_tree(&RepoPath::root(), &tree_id).unwrap() }; - MergedTree::Merge(Conflict::new( + MergedTree::Merge(Merge::new( removes.into_iter().map(write_tree).collect(), adds.into_iter().map(write_tree).collect(), )) @@ -179,9 +179,9 @@ impl MergedTree { /// automatically resolved and leaving the rest unresolved. The returned /// conflict will either be resolved or have the same number of sides as /// the input. - pub fn resolve(&self) -> Result, TreeMergeError> { + pub fn resolve(&self) -> Result, TreeMergeError> { match self { - MergedTree::Legacy(tree) => Ok(Conflict::resolved(tree.clone())), + MergedTree::Legacy(tree) => Ok(Merge::resolved(tree.clone())), MergedTree::Merge(conflict) => merge_trees(conflict), } } @@ -191,7 +191,7 @@ impl MergedTree { /// all sides are trees, so tree/file conflicts will be reported as a single /// conflict, not one for each path in the tree. // TODO: Restrict this by a matcher (or add a separate method for that). - pub fn conflicts(&self) -> impl Iterator>)> { + pub fn conflicts(&self) -> impl Iterator>)> { ConflictIterator::new(self.clone()) } @@ -204,19 +204,19 @@ impl MergedTree { } } -fn all_tree_conflict_names(conflict: &Conflict) -> impl Iterator { +fn all_tree_conflict_names(conflict: &Merge) -> impl Iterator { itertools::chain(conflict.removes(), conflict.adds()) .map(|tree| tree.data().names()) .kmerge() .dedup() } -fn merge_trees(conflict: &Conflict) -> Result, TreeMergeError> { - if let Some(tree) = conflict.resolve_trivial() { - return Ok(Conflict::resolved(tree.clone())); +fn merge_trees(merge: &Merge) -> Result, TreeMergeError> { + if let Some(tree) = merge.resolve_trivial() { + return Ok(Merge::resolved(tree.clone())); } - let base_tree = &conflict.adds()[0]; + let base_tree = &merge.adds()[0]; let store = base_tree.store(); let dir = base_tree.dir(); // Keep resolved entries in `new_tree` and conflicted entries in `conflicts` to @@ -224,24 +224,24 @@ fn merge_trees(conflict: &Conflict) -> Result, TreeMergeErr // any conflicts. let mut new_tree = backend::Tree::default(); let mut conflicts = vec![]; - for basename in all_tree_conflict_names(conflict) { - let path_conflict = conflict.map(|tree| tree.value(basename).cloned()); - let path_conflict = merge_tree_values(store, dir, path_conflict)?; - if let Some(value) = path_conflict.as_resolved() { + for basename in all_tree_conflict_names(merge) { + let path_merge = merge.map(|tree| tree.value(basename).cloned()); + let path_merge = merge_tree_values(store, dir, path_merge)?; + if let Some(value) = path_merge.as_resolved() { new_tree.set_or_remove(basename, value.clone()); } else { - conflicts.push((basename, path_conflict)); + conflicts.push((basename, path_merge)); }; } if conflicts.is_empty() { let new_tree_id = store.write_tree(dir, new_tree)?; - Ok(Conflict::resolved(new_tree_id)) + Ok(Merge::resolved(new_tree_id)) } else { // For each side of the conflict, overwrite the entries in `new_tree` with the // values from `conflicts`. Entries that are not in `conflicts` will remain // unchanged and will be reused for each side. let mut tree_removes = vec![]; - for i in 0..conflict.removes().len() { + for i in 0..merge.removes().len() { for (basename, path_conflict) in &conflicts { new_tree.set_or_remove(basename, path_conflict.removes()[i].clone()); } @@ -249,7 +249,7 @@ fn merge_trees(conflict: &Conflict) -> Result, TreeMergeErr tree_removes.push(tree); } let mut tree_adds = vec![]; - for i in 0..conflict.adds().len() { + for i in 0..merge.adds().len() { for (basename, path_conflict) in &conflicts { new_tree.set_or_remove(basename, path_conflict.adds()[i].clone()); } @@ -257,7 +257,7 @@ fn merge_trees(conflict: &Conflict) -> Result, TreeMergeErr tree_adds.push(tree); } - Ok(Conflict::new(tree_removes, tree_adds)) + Ok(Merge::new(tree_removes, tree_adds)) } } @@ -268,18 +268,18 @@ fn merge_trees(conflict: &Conflict) -> Result, TreeMergeErr fn merge_tree_values( store: &Arc, path: &RepoPath, - conflict: Conflict>, -) -> Result>, TreeMergeError> { + conflict: Merge>, +) -> Result>, TreeMergeError> { if let Some(resolved) = conflict.resolve_trivial() { - return Ok(Conflict::resolved(resolved.clone())); + return Ok(Merge::resolved(resolved.clone())); } - if let Some(tree_conflict) = conflict.to_tree_conflict(store, path)? { + if let Some(tree_conflict) = conflict.to_tree_merge(store, path)? { // If all sides are trees or missing, merge the trees recursively, treating // missing trees as empty. let merged_tree = merge_trees(&tree_conflict)?; if merged_tree.as_resolved().map(|tree| tree.id()) == Some(store.empty_tree_id()) { - Ok(Conflict::resolved(None)) + Ok(Merge::resolved(None)) } else { Ok(merged_tree.map(|tree| Some(TreeValue::Tree(tree.id().clone())))) } @@ -287,7 +287,7 @@ fn merge_tree_values( // Try to resolve file conflicts by merging the file contents. Treats missing // files as empty. if let Some(resolved) = try_resolve_file_conflict(store, path, &conflict)? { - Ok(Conflict::resolved(Some(resolved))) + Ok(Merge::resolved(Some(resolved))) } else { // Failed to merge the files, or the paths are not files Ok(conflict) @@ -325,7 +325,7 @@ impl<'a> ConflictEntriesNonRecursiveIterator<'a> { } impl<'a> Iterator for ConflictEntriesNonRecursiveIterator<'a> { - type Item = (&'a RepoPathComponent, Conflict>); + type Item = (&'a RepoPathComponent, Merge>); fn next(&mut self) -> Option { for basename in self.basename_iter.by_ref() { @@ -387,7 +387,7 @@ impl ConflictIterator { } impl Iterator for ConflictIterator { - type Item = (RepoPath, Conflict>); + type Item = (RepoPath, Merge>); fn next(&mut self) -> Option { match self { @@ -409,7 +409,7 @@ impl Iterator for ConflictIterator { let path = top.tree.dir().join(basename); // TODO: propagate errors if let Some(tree_conflict) = - conflict.to_tree_conflict(top.tree.store(), &path).unwrap() + conflict.to_tree_merge(top.tree.store(), &path).unwrap() { // If all sides are trees or missing, descend into the merged tree stack.push(ConflictsDirItem::new(MergedTree::Merge(tree_conflict))); diff --git a/lib/src/op_store.rs b/lib/src/op_store.rs index ee441955f..d186200c3 100644 --- a/lib/src/op_store.rs +++ b/lib/src/op_store.rs @@ -21,7 +21,7 @@ use once_cell::sync::Lazy; use thiserror::Error; use crate::backend::{id_type, CommitId, ObjectId, Timestamp}; -use crate::conflicts::Conflict; +use crate::conflicts::Merge; content_hash! { #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] @@ -56,7 +56,7 @@ id_type!(pub OperationId); content_hash! { #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub struct RefTarget { - conflict: Conflict>, + merge: Merge>, } } @@ -69,7 +69,7 @@ impl Default for RefTarget { impl RefTarget { /// Creates non-conflicting target pointing to no commit. pub fn absent() -> Self { - Self::from_conflict(Conflict::resolved(None)) + Self::from_merge(Merge::resolved(None)) } /// Returns non-conflicting target pointing to no commit. @@ -82,7 +82,7 @@ impl RefTarget { /// Creates non-conflicting target pointing to a commit. pub fn normal(id: CommitId) -> Self { - Self::from_conflict(Conflict::resolved(Some(id))) + Self::from_merge(Merge::resolved(Some(id))) } /// Creates target from removed/added ids. @@ -90,22 +90,22 @@ impl RefTarget { removed_ids: impl IntoIterator, added_ids: impl IntoIterator, ) -> Self { - Self::from_conflict(Conflict::from_legacy_form(removed_ids, added_ids)) + Self::from_merge(Merge::from_legacy_form(removed_ids, added_ids)) } - pub fn from_conflict(conflict: Conflict>) -> Self { - RefTarget { conflict } + pub fn from_merge(merge: Merge>) -> Self { + RefTarget { merge } } /// Returns id if this target is non-conflicting and points to a commit. pub fn as_normal(&self) -> Option<&CommitId> { - let maybe_id = self.conflict.as_resolved()?; + let maybe_id = self.merge.as_resolved()?; maybe_id.as_ref() } /// Returns true if this target points to no commit. pub fn is_absent(&self) -> bool { - matches!(self.conflict.as_resolved(), Some(None)) + matches!(self.merge.as_resolved(), Some(None)) } /// Returns true if this target points to any commit. Conflicting target is @@ -116,19 +116,19 @@ impl RefTarget { /// Whether this target has conflicts. pub fn has_conflict(&self) -> bool { - !self.conflict.is_resolved() + !self.merge.is_resolved() } pub fn removed_ids(&self) -> impl Iterator { - self.conflict.removes().iter().flatten() + self.merge.removes().iter().flatten() } pub fn added_ids(&self) -> impl Iterator { - self.conflict.adds().iter().flatten() + self.merge.adds().iter().flatten() } - pub fn as_conflict(&self) -> &Conflict> { - &self.conflict + pub fn as_conflict(&self) -> &Merge> { + &self.merge } } diff --git a/lib/src/refs.rs b/lib/src/refs.rs index d4900b231..a4b6ef685 100644 --- a/lib/src/refs.rs +++ b/lib/src/refs.rs @@ -15,7 +15,7 @@ #![allow(missing_docs)] use crate::backend::CommitId; -use crate::conflicts::Conflict; +use crate::conflicts::Merge; use crate::index::Index; use crate::merge::trivial_merge; use crate::op_store::{BranchTarget, RefTarget, RefTargetOptionExt}; @@ -30,31 +30,31 @@ pub fn merge_ref_targets( return resolved.clone(); } - let conflict = Conflict::new( + let merge = Merge::new( vec![base.as_conflict().clone()], vec![left.as_conflict().clone(), right.as_conflict().clone()], ) .flatten() .simplify(); - if conflict.is_resolved() { - RefTarget::from_conflict(conflict) + if merge.is_resolved() { + RefTarget::from_merge(merge) } else { - let conflict = merge_ref_targets_non_trivial(index, conflict); - RefTarget::from_conflict(conflict) + let merge = merge_ref_targets_non_trivial(index, merge); + RefTarget::from_merge(merge) } } fn merge_ref_targets_non_trivial( index: &dyn Index, - conflict: Conflict>, -) -> Conflict> { + conflict: Merge>, +) -> Merge> { let (mut removes, mut adds) = conflict.take(); while let Some((remove_index, add_index)) = find_pair_to_remove(index, &removes, &adds) { removes.remove(remove_index); adds.remove(add_index); } - Conflict::new(removes, adds) + Merge::new(removes, adds) } fn find_pair_to_remove( diff --git a/lib/src/simple_op_store.rs b/lib/src/simple_op_store.rs index 3e089c300..ec83f740e 100644 --- a/lib/src/simple_op_store.rs +++ b/lib/src/simple_op_store.rs @@ -25,7 +25,7 @@ use tempfile::{NamedTempFile, PersistError}; use thiserror::Error; use crate::backend::{CommitId, MillisSinceEpoch, ObjectId, Timestamp}; -use crate::conflicts::Conflict; +use crate::conflicts::Merge; use crate::content_hash::blake2b_hash; use crate::file_util::persist_content_addressed_temp_file; use crate::op_store::{ @@ -426,7 +426,7 @@ fn ref_target_from_proto(maybe_proto: Option |term: crate::protos::op_store::ref_conflict::Term| term.value.map(CommitId::new); let removes = conflict.removes.into_iter().map(term_from_proto).collect(); let adds = conflict.adds.into_iter().map(term_from_proto).collect(); - RefTarget::from_conflict(Conflict::new(removes, adds)) + RefTarget::from_merge(Merge::new(removes, adds)) } } } @@ -556,7 +556,7 @@ mod tests { #[test] fn test_ref_target_change_delete_order_roundtrip() { - let target = RefTarget::from_conflict(Conflict::new( + let target = RefTarget::from_merge(Merge::new( vec![Some(CommitId::from_hex("111111"))], vec![Some(CommitId::from_hex("222222")), None], )); @@ -564,7 +564,7 @@ mod tests { assert_eq!(ref_target_from_proto(maybe_proto), target); // If it were legacy format, order of None entry would be lost. - let target = RefTarget::from_conflict(Conflict::new( + let target = RefTarget::from_merge(Merge::new( vec![Some(CommitId::from_hex("111111"))], vec![None, Some(CommitId::from_hex("222222"))], )); diff --git a/lib/src/store.rs b/lib/src/store.rs index e73b1fbe3..724c61aaf 100644 --- a/lib/src/store.rs +++ b/lib/src/store.rs @@ -19,14 +19,15 @@ use std::collections::HashMap; use std::io::Read; use std::sync::{Arc, RwLock}; +use crate::backend; use crate::backend::{ Backend, BackendResult, ChangeId, CommitId, ConflictId, FileId, SymlinkId, TreeId, TreeValue, }; use crate::commit::Commit; +use crate::conflicts::Merge; use crate::repo_path::RepoPath; use crate::tree::Tree; use crate::tree_builder::TreeBuilder; -use crate::{backend, conflicts}; /// Wraps the low-level backend and makes it return more convenient types. Also /// adds caching. @@ -159,15 +160,15 @@ impl Store { &self, path: &RepoPath, id: &ConflictId, - ) -> BackendResult>> { + ) -> BackendResult>> { let backend_conflict = self.backend.read_conflict(path, id)?; - Ok(conflicts::Conflict::from_backend_conflict(backend_conflict)) + Ok(Merge::from_backend_conflict(backend_conflict)) } pub fn write_conflict( &self, path: &RepoPath, - contents: &conflicts::Conflict>, + contents: &Merge>, ) -> BackendResult { self.backend .write_conflict(path, &contents.clone().into_backend_conflict()) diff --git a/lib/src/tree.rs b/lib/src/tree.rs index 95672f59a..bfd934495 100644 --- a/lib/src/tree.rs +++ b/lib/src/tree.rs @@ -27,7 +27,7 @@ use crate::backend::{ BackendError, ConflictId, FileId, ObjectId, TreeEntriesNonRecursiveIterator, TreeEntry, TreeId, TreeValue, }; -use crate::conflicts::Conflict; +use crate::conflicts::Merge; use crate::files::MergeResult; use crate::matchers::{EverythingMatcher, Matcher}; use crate::merge::trivial_merge; @@ -565,19 +565,19 @@ fn merge_tree_value( _ => { // Start by creating a Conflict object. Conflicts can cleanly represent a single // resolved state, the absence of a state, or a conflicted state. - let conflict = Conflict::new( + let conflict = Merge::new( vec![maybe_base.cloned()], vec![maybe_side1.cloned(), maybe_side2.cloned()], ); let filename = dir.join(basename); - let conflict = simplify_conflict(store, &filename, conflict)?; - if let Some(value) = conflict.as_resolved() { + let merge = simplify_conflict(store, &filename, conflict)?; + if let Some(value) = merge.as_resolved() { return Ok(value.clone()); } - if let Some(tree_value) = try_resolve_file_conflict(store, &filename, &conflict)? { + if let Some(tree_value) = try_resolve_file_conflict(store, &filename, &merge)? { Some(tree_value) } else { - let conflict_id = store.write_conflict(&filename, &conflict)?; + let conflict_id = store.write_conflict(&filename, &merge)?; Some(TreeValue::Conflict(conflict_id)) } } @@ -587,7 +587,7 @@ fn merge_tree_value( pub fn try_resolve_file_conflict( store: &Store, filename: &RepoPath, - conflict: &Conflict>, + conflict: &Merge>, ) -> Result, TreeMergeError> { // If there are any non-file or any missing parts in the conflict, we can't // merge it. We check early so we don't waste time reading file contents if @@ -657,8 +657,8 @@ pub fn try_resolve_file_conflict( fn simplify_conflict( store: &Store, path: &RepoPath, - conflict: Conflict>, -) -> Result>, BackendError> { + conflict: Merge>, +) -> Result>, BackendError> { // Important cases to simplify: // // D @@ -692,7 +692,7 @@ fn simplify_conflict( let expanded = conflict.try_map(|term| match term { Some(TreeValue::Conflict(id)) => store.read_conflict(path, id), - _ => Ok(Conflict::resolved(term.clone())), + _ => Ok(Merge::resolved(term.clone())), })?; Ok(expanded.flatten().simplify()) } diff --git a/lib/tests/test_conflicts.rs b/lib/tests/test_conflicts.rs index 3a61bf717..23f89680a 100644 --- a/lib/tests/test_conflicts.rs +++ b/lib/tests/test_conflicts.rs @@ -13,7 +13,7 @@ // limitations under the License. use jj_lib::backend::{FileId, TreeValue}; -use jj_lib::conflicts::{parse_conflict, Conflict}; +use jj_lib::conflicts::{parse_conflict, Merge}; use jj_lib::repo::Repo; use jj_lib::repo_path::RepoPath; use jj_lib::store::Store; @@ -67,7 +67,7 @@ line 5 // The left side should come first. The diff should be use the smaller (right) // side, and the left side should be a snapshot. - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_id))], vec![Some(file_value(&left_id)), Some(file_value(&right_id))], ); @@ -91,7 +91,7 @@ line 5 ); // Swap the positive terms in the conflict. The diff should still use the right // side, but now the right side should come first. - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_id))], vec![Some(file_value(&right_id)), Some(file_value(&left_id))], ); @@ -160,7 +160,7 @@ line 3 // The order of (a, b, c) should be preserved. For all cases, the "a" side // should be a snapshot. - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_id)), Some(file_value(&base_id))], vec![ Some(file_value(&a_id)), @@ -188,7 +188,7 @@ line 3 line 3 "### ); - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_id)), Some(file_value(&base_id))], vec![ Some(file_value(&c_id)), @@ -216,7 +216,7 @@ line 3 line 3 "### ); - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_id)), Some(file_value(&base_id))], vec![ Some(file_value(&c_id)), @@ -283,7 +283,7 @@ line 5 right ", ); - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_id))], vec![Some(file_value(&left_id)), Some(file_value(&right_id))], ); @@ -320,7 +320,7 @@ line 5 right @r###" Some( [ - Conflict { + Merge { removes: [ "line 1\nline 2\n", ], @@ -329,13 +329,13 @@ line 5 right "line 1 right\nline 2\n", ], }, - Conflict { + Merge { removes: [], adds: [ "line 3\n", ], }, - Conflict { + Merge { removes: [ "line 4\nline 5\n", ], @@ -386,7 +386,7 @@ line 5 ); // left modifies a line, right deletes the same line. - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_id))], vec![ Some(file_value(&modified_id)), @@ -408,7 +408,7 @@ line 5 ); // right modifies a line, left deletes the same line. - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_id))], vec![ Some(file_value(&deleted_id)), @@ -430,7 +430,7 @@ line 5 ); // modify/delete conflict at the file level - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_id))], vec![Some(file_value(&modified_id)), None], ); @@ -488,13 +488,13 @@ line 5 @r###" Some( [ - Conflict { + Merge { removes: [], adds: [ "line 1\n", ], }, - Conflict { + Merge { removes: [ "line 2\nline 3\nline 4\n", ], @@ -503,7 +503,7 @@ line 5 "right\n", ], }, - Conflict { + Merge { removes: [], adds: [ "line 5\n", @@ -542,13 +542,13 @@ line 5 @r###" Some( [ - Conflict { + Merge { removes: [], adds: [ "line 1\n", ], }, - Conflict { + Merge { removes: [ "line 2\nline 3\nline 4\n", "line 2\nline 3\nline 4\n", @@ -559,7 +559,7 @@ line 5 "line 2\nforward\nline 3\nline 4\n", ], }, - Conflict { + Merge { removes: [], adds: [ "line 5\n", @@ -650,7 +650,7 @@ fn test_update_conflict_from_content() { let base_file_id = testutils::write_file(store, &path, "line 1\nline 2\nline 3\n"); let left_file_id = testutils::write_file(store, &path, "left 1\nline 2\nleft 3\n"); let right_file_id = testutils::write_file(store, &path, "right 1\nline 2\nright 3\n"); - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&base_file_id))], vec![ Some(file_value(&left_file_id)), @@ -691,7 +691,7 @@ fn test_update_conflict_from_content() { let new_right_file_id = testutils::write_file(store, &path, "resolved 1\nline 2\nright 3\n"); assert_eq!( new_conflict, - Conflict::new( + Merge::new( vec![Some(file_value(&new_base_file_id))], vec![ Some(file_value(&new_left_file_id)), @@ -709,7 +709,7 @@ fn test_update_conflict_from_content_modify_delete() { let path = RepoPath::from_internal_string("dir/file"); let before_file_id = testutils::write_file(store, &path, "line 1\nline 2 before\nline 3\n"); let after_file_id = testutils::write_file(store, &path, "line 1\nline 2 after\nline 3\n"); - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(file_value(&before_file_id))], vec![Some(file_value(&after_file_id)), None], ); @@ -746,7 +746,7 @@ fn test_update_conflict_from_content_modify_delete() { assert_eq!( new_conflict, - Conflict::new( + Merge::new( vec![Some(file_value(&new_base_file_id))], vec![Some(file_value(&new_left_file_id)), None] ) @@ -756,7 +756,7 @@ fn test_update_conflict_from_content_modify_delete() { fn materialize_conflict_string( store: &Store, path: &RepoPath, - conflict: &Conflict>, + conflict: &Merge>, ) -> String { let mut result: Vec = vec![]; conflict.materialize(store, path, &mut result).unwrap(); diff --git a/lib/tests/test_merged_tree.rs b/lib/tests/test_merged_tree.rs index fe3dfbca4..b2822aa9b 100644 --- a/lib/tests/test_merged_tree.rs +++ b/lib/tests/test_merged_tree.rs @@ -14,7 +14,7 @@ use itertools::Itertools; use jj_lib::backend::{FileId, TreeValue}; -use jj_lib::conflicts::Conflict; +use jj_lib::conflicts::Merge; use jj_lib::merged_tree::{MergedTree, MergedTreeValue}; use jj_lib::repo::Repo; use jj_lib::repo_path::{RepoPath, RepoPathComponent, RepoPathJoin}; @@ -45,7 +45,7 @@ fn test_from_legacy_tree() { let file2_v1_id = write_file(store.as_ref(), &file2_path, "file2_v1"); let file2_v2_id = write_file(store.as_ref(), &file2_path, "file2_v2"); let file2_v3_id = write_file(store.as_ref(), &file2_path, "file2_v3"); - let file2_conflict = Conflict::new( + let file2_conflict = Merge::new( vec![Some(file_value(&file2_v1_id))], vec![ Some(file_value(&file2_v2_id)), @@ -59,7 +59,7 @@ fn test_from_legacy_tree() { let file3_path = RepoPath::from_internal_string("modify_delete"); let file3_v1_id = write_file(store.as_ref(), &file3_path, "file3_v1"); let file3_v2_id = write_file(store.as_ref(), &file3_path, "file3_v2"); - let file3_conflict = Conflict::new( + let file3_conflict = Merge::new( vec![Some(file_value(&file3_v1_id))], vec![Some(file_value(&file3_v2_id)), None], ); @@ -70,7 +70,7 @@ fn test_from_legacy_tree() { let file4_path = RepoPath::from_internal_string("add_add"); let file4_v1_id = write_file(store.as_ref(), &file4_path, "file4_v1"); let file4_v2_id = write_file(store.as_ref(), &file4_path, "file4_v2"); - let file4_conflict = Conflict::new( + let file4_conflict = Merge::new( vec![None], vec![ Some(file_value(&file4_v1_id)), @@ -87,7 +87,7 @@ fn test_from_legacy_tree() { let file5_v3_id = write_file(store.as_ref(), &file5_path, "file5_v3"); let file5_v4_id = write_file(store.as_ref(), &file5_path, "file5_v4"); let file5_v5_id = write_file(store.as_ref(), &file5_path, "file5_v5"); - let file5_conflict = Conflict::new( + let file5_conflict = Merge::new( vec![ Some(file_value(&file5_v1_id)), Some(file_value(&file5_v2_id)), @@ -130,7 +130,7 @@ fn test_from_legacy_tree() { // file2: 3-way conflict assert_eq!( merged_tree.value(&file2_path.components()[0]), - MergedTreeValue::Conflict(Conflict::new( + MergedTreeValue::Conflict(Merge::new( vec![Some(file_value(&file2_v1_id)), None], vec![ Some(file_value(&file2_v2_id)), @@ -142,7 +142,7 @@ fn test_from_legacy_tree() { // file3: modify/delete conflict assert_eq!( merged_tree.value(&file3_path.components()[0]), - MergedTreeValue::Conflict(Conflict::new( + MergedTreeValue::Conflict(Merge::new( vec![Some(file_value(&file3_v1_id)), None], vec![Some(file_value(&file3_v2_id)), None, None], )) @@ -150,7 +150,7 @@ fn test_from_legacy_tree() { // file4: add/add conflict assert_eq!( merged_tree.value(&file4_path.components()[0]), - MergedTreeValue::Conflict(Conflict::new( + MergedTreeValue::Conflict(Merge::new( vec![None, None], vec![ Some(file_value(&file4_v1_id)), @@ -162,7 +162,7 @@ fn test_from_legacy_tree() { // file5: 5-way conflict assert_eq!( merged_tree.value(&file5_path.components()[0]), - MergedTreeValue::Conflict(Conflict::new( + MergedTreeValue::Conflict(Merge::new( vec![ Some(file_value(&file5_v1_id)), Some(file_value(&file5_v2_id)), @@ -236,7 +236,7 @@ fn test_resolve_success() { ], ); - let tree = MergedTree::new(Conflict::new(vec![base1], vec![side1, side2])); + let tree = MergedTree::new(Merge::new(vec![base1], vec![side1, side2])); let resolved = tree.resolve().unwrap(); let resolved_tree = resolved.as_resolved().unwrap().clone(); assert_eq!( @@ -260,7 +260,7 @@ fn test_resolve_root_becomes_empty() { let side1 = testutils::create_tree(repo, &[(&path2, "base1")]); let side2 = testutils::create_tree(repo, &[(&path1, "base1")]); - let tree = MergedTree::new(Conflict::new(vec![base1], vec![side1, side2])); + let tree = MergedTree::new(Merge::new(vec![base1], vec![side1, side2])); let resolved = tree.resolve().unwrap(); assert_eq!(resolved.as_resolved().unwrap().id(), store.empty_tree_id()); } @@ -287,11 +287,11 @@ fn test_resolve_with_conflict() { let expected_side2 = testutils::create_tree(repo, &[(&trivial_path, "side1"), (&conflict_path, "side2")]); - let tree = MergedTree::new(Conflict::new(vec![base1], vec![side1, side2])); + let tree = MergedTree::new(Merge::new(vec![base1], vec![side1, side2])); let resolved_tree = tree.resolve().unwrap(); assert_eq!( resolved_tree, - Conflict::new(vec![expected_base1], vec![expected_side1, expected_side2]) + Merge::new(vec![expected_base1], vec![expected_side1, expected_side2]) ) } @@ -368,13 +368,13 @@ fn test_conflict_iterator() { ], ); - let tree = MergedTree::new(Conflict::new( + let tree = MergedTree::new(Merge::new( vec![base1.clone()], vec![side1.clone(), side2.clone()], )); let conflicts = tree.conflicts().collect_vec(); let conflict_at = |path: &RepoPath| { - Conflict::new( + Merge::new( vec![base1.path_value(path)], vec![side1.path_value(path), side2.path_value(path)], ) @@ -439,13 +439,13 @@ fn test_conflict_iterator_higher_arity() { &[(&two_sided_path, "side3"), (&three_sided_path, "side3")], ); - let tree = MergedTree::new(Conflict::new( + let tree = MergedTree::new(Merge::new( vec![base1.clone(), base2.clone()], vec![side1.clone(), side2.clone(), side3.clone()], )); let conflicts = tree.conflicts().collect_vec(); let conflict_at = |path: &RepoPath| { - Conflict::new( + Merge::new( vec![base1.path_value(path), base2.path_value(path)], vec![ side1.path_value(path), @@ -474,7 +474,7 @@ fn test_conflict_iterator_higher_arity() { vec![ ( two_sided_path.clone(), - Conflict::new( + Merge::new( vec![base2.path_value(&two_sided_path)], vec![ side1.path_value(&two_sided_path), diff --git a/lib/tests/test_refs.rs b/lib/tests/test_refs.rs index 057be0617..7c5ea4cb0 100644 --- a/lib/tests/test_refs.rs +++ b/lib/tests/test_refs.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use jj_lib::conflicts::Conflict; +use jj_lib::conflicts::Merge; use jj_lib::op_store::RefTarget; use jj_lib::refs::merge_ref_targets; use jj_lib::repo::Repo; @@ -167,7 +167,7 @@ fn test_merge_ref_targets() { // Left removed, right moved forward assert_eq!( merge_ref_targets(index, RefTarget::absent_ref(), &target1, &target3), - RefTarget::from_conflict(Conflict::new( + RefTarget::from_merge(Merge::new( vec![Some(commit1.id().clone())], vec![None, Some(commit3.id().clone())], )) @@ -176,7 +176,7 @@ fn test_merge_ref_targets() { // Right removed, left moved forward assert_eq!( merge_ref_targets(index, &target3, &target1, RefTarget::absent_ref()), - RefTarget::from_conflict(Conflict::new( + RefTarget::from_merge(Merge::new( vec![Some(commit1.id().clone())], vec![Some(commit3.id().clone()), None], )) diff --git a/lib/tests/test_working_copy.rs b/lib/tests/test_working_copy.rs index 7e2a272b3..34a7cb10e 100644 --- a/lib/tests/test_working_copy.rs +++ b/lib/tests/test_working_copy.rs @@ -22,7 +22,7 @@ use std::sync::Arc; use itertools::Itertools; use jj_lib::backend::{ObjectId, TreeId, TreeValue}; -use jj_lib::conflicts::Conflict; +use jj_lib::conflicts::Merge; use jj_lib::fsmonitor::FsmonitorKind; use jj_lib::op_store::{OperationId, WorkspaceId}; use jj_lib::repo::{ReadonlyRepo, Repo}; @@ -117,7 +117,7 @@ fn test_checkout_file_transitions(use_git: bool) { let base_file_id = testutils::write_file(store, path, "base file contents"); let left_file_id = testutils::write_file(store, path, "left file contents"); let right_file_id = testutils::write_file(store, path, "right file contents"); - let conflict = Conflict::new( + let conflict = Merge::new( vec![Some(TreeValue::File { id: base_file_id, executable: false,