diff --git a/lib/src/commit.rs b/lib/src/commit.rs index c87d85fc6..d701e97dd 100644 --- a/lib/src/commit.rs +++ b/lib/src/commit.rs @@ -20,7 +20,8 @@ use std::hash::{Hash, Hasher}; use std::sync::Arc; use crate::backend; -use crate::backend::{ChangeId, CommitId, Signature, TreeId}; +use crate::backend::{BackendError, ChangeId, CommitId, Signature, TreeId}; +use crate::merged_tree::MergedTree; use crate::repo_path::RepoPath; use crate::store::Store; use crate::tree::Tree; @@ -101,12 +102,27 @@ impl Commit { .collect() } + // TODO(#1624): Delete when all callers use `merged_tree()` pub fn tree(&self) -> Tree { self.store .get_tree(&RepoPath::root(), self.data.root_tree.as_legacy_tree_id()) .unwrap() } + pub fn merged_tree(&self) -> Result { + if self.data.uses_tree_conflict_format { + let tree_conflict = self + .data + .root_tree + .try_map(|tree_id| self.store.get_tree(&RepoPath::root(), tree_id))?; + Ok(MergedTree::new(tree_conflict)) + } else { + let tree_id = self.data.root_tree.as_legacy_tree_id(); + let tree = self.store.get_tree(&RepoPath::root(), tree_id)?; + Ok(MergedTree::legacy(tree)) + } + } + pub fn tree_id(&self) -> &TreeId { self.data.root_tree.as_legacy_tree_id() } diff --git a/lib/src/default_revset_engine.rs b/lib/src/default_revset_engine.rs index c57281cac..31bd2173f 100644 --- a/lib/src/default_revset_engine.rs +++ b/lib/src/default_revset_engine.rs @@ -870,7 +870,7 @@ fn build_predicate_fn<'index>( } RevsetFilterPredicate::HasConflict => pure_predicate_fn(move |entry| { let commit = store.get_commit(&entry.commit_id()).unwrap(); - commit.tree().has_conflict() + commit.merged_tree().unwrap().has_conflict() }), } } diff --git a/lib/src/merged_tree.rs b/lib/src/merged_tree.rs index 4418f4e19..c09cc554b 100644 --- a/lib/src/merged_tree.rs +++ b/lib/src/merged_tree.rs @@ -194,6 +194,14 @@ impl MergedTree { pub fn conflicts(&self) -> impl Iterator>)> { ConflictIterator::new(self.clone()) } + + /// Whether this tree has conflicts. + pub fn has_conflict(&self) -> bool { + match self { + MergedTree::Legacy(tree) => tree.has_conflict(), + MergedTree::Merge(conflict) => !conflict.is_resolved(), + } + } } fn all_tree_conflict_names(conflict: &Conflict) -> impl Iterator { diff --git a/src/commands/git.rs b/src/commands/git.rs index 70ed2bda3..d6c91d39a 100644 --- a/src/commands/git.rs +++ b/src/commands/git.rs @@ -845,7 +845,7 @@ fn cmd_git_push( { reasons.push("it has no author and/or committer set"); } - if commit.tree().has_conflict() { + if commit.merged_tree()?.has_conflict() { reasons.push("it has conflicts"); } if !reasons.is_empty() { diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 0365470c5..e54d0091e 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1524,13 +1524,13 @@ fn cmd_status( )?; } - let conflicts = tree.conflicts(); + let conflicts = wc_commit.merged_tree()?.conflicts().collect_vec(); if !conflicts.is_empty() { writeln!( formatter.labeled("conflict"), "There are unresolved conflicts at these paths:" )?; - print_conflicted_paths(&conflicts, &tree, formatter, &workspace_command)? + print_conflicted_paths(&conflicts, formatter, &workspace_command)? } } @@ -2667,8 +2667,11 @@ fn cmd_resolve( let mut workspace_command = command.workspace_helper(ui)?; let matcher = workspace_command.matcher_from_values(&args.paths)?; let commit = workspace_command.resolve_single_rev(&args.revision)?; - let tree = commit.tree(); - let conflicts = tree.conflicts_matching(matcher.as_ref()); + let tree = commit.merged_tree()?; + let conflicts = tree + .conflicts() + .filter(|path| matcher.matches(&path.0)) + .collect_vec(); if conflicts.is_empty() { return Err(CommandError::CliError(format!( "No conflicts found {}", @@ -2682,7 +2685,6 @@ fn cmd_resolve( if args.list { return print_conflicted_paths( &conflicts, - &tree, ui.stdout_formatter().as_mut(), &workspace_command, ); @@ -2703,13 +2705,12 @@ fn cmd_resolve( tx.finish(ui)?; if !args.quiet { - let new_tree = new_commit.tree(); - let new_conflicts = new_tree.conflicts_matching(&EverythingMatcher); + let new_tree = new_commit.merged_tree()?; + let new_conflicts = new_tree.conflicts().collect_vec(); if !new_conflicts.is_empty() { ui.write("After this operation, some files at this revision still have conflicts:\n")?; print_conflicted_paths( &new_conflicts, - &tree, ui.stdout_formatter().as_mut(), &workspace_command, )?; @@ -2719,24 +2720,20 @@ fn cmd_resolve( } fn print_conflicted_paths( - conflicts: &[(RepoPath, jj_lib::backend::ConflictId)], - tree: &Tree, + conflicts: &[(RepoPath, Conflict>)], formatter: &mut dyn Formatter, workspace_command: &WorkspaceCommandHelper, ) -> Result<(), CommandError> { let formatted_paths = conflicts .iter() - .map(|(path, _id)| workspace_command.format_file_path(path)) + .map(|(path, _conflict)| workspace_command.format_file_path(path)) .collect_vec(); let max_path_len = formatted_paths.iter().map(|p| p.len()).max().unwrap_or(0); let formatted_paths = formatted_paths .into_iter() .map(|p| format!("{:width$}", p, width = max_path_len.min(32) + 3)); - for ((repo_path, conflict_id), formatted_path) in - std::iter::zip(conflicts.iter(), formatted_paths) - { - let conflict = tree.store().read_conflict(repo_path, conflict_id)?; + for ((_, conflict), formatted_path) in std::iter::zip(conflicts.iter(), formatted_paths) { let sides = conflict.adds().len(); let n_adds = conflict.adds().iter().flatten().count(); let deletions = sides - n_adds; diff --git a/src/commit_templater.rs b/src/commit_templater.rs index b6ee6e8b4..d5d88447d 100644 --- a/src/commit_templater.rs +++ b/src/commit_templater.rs @@ -299,9 +299,9 @@ fn build_commit_keyword_opt<'repo>( let maybe_entries = repo.resolve_change_id(commit.change_id()); maybe_entries.map_or(true, |entries| !entries.contains(commit.id())) })), - "conflict" => { - language.wrap_boolean(wrap_fn(property, |commit| commit.tree().has_conflict())) - } + "conflict" => language.wrap_boolean(wrap_fn(property, |commit| { + commit.merged_tree().unwrap().has_conflict() + })), "empty" => language.wrap_boolean(wrap_fn(property, |commit| { let parent_tree = rewrite::merge_commit_trees(repo, &commit.parents()).unwrap(); commit.tree_id() == parent_tree.id()