diff --git a/app/src/lib/utils/typeguards.ts b/app/src/lib/utils/typeguards.ts index c9659e76e..76e9c7c3d 100644 --- a/app/src/lib/utils/typeguards.ts +++ b/app/src/lib/utils/typeguards.ts @@ -1,3 +1,7 @@ -export function isDefined(file: T | undefined): file is T { +export function isDefined(file: T | undefined | null): file is T { return file !== undefined; } + +export function notNull(file: T | undefined | null): file is T { + return file !== null; +} diff --git a/app/src/lib/vbranches/types.ts b/app/src/lib/vbranches/types.ts index 367b6c943..fb545399b 100644 --- a/app/src/lib/vbranches/types.ts +++ b/app/src/lib/vbranches/types.ts @@ -1,6 +1,7 @@ import 'reflect-metadata'; import { splitMessage } from '$lib/utils/commitMessage'; import { hashCode } from '$lib/utils/string'; +import { isDefined, notNull } from '$lib/utils/typeguards'; import { Type, Transform } from 'class-transformer'; export type ChangeType = @@ -21,7 +22,7 @@ export class Hunk { filePath!: string; hash?: string; locked!: boolean; - lockedTo!: string | undefined; + lockedTo!: string[] | undefined; changeType!: ChangeType; } @@ -58,14 +59,15 @@ export class LocalFile { get locked(): boolean { return this.hunks - ? this.hunks.map((hunk) => hunk.lockedTo).reduce((a, b) => !!(a || b), false) + ? this.hunks.map((hunk) => hunk.locked).reduce((a, b) => !!(a || b), false) : false; } get lockedIds(): string[] { return this.hunks - .map((hunk) => hunk.lockedTo) - .filter((lockedTo): lockedTo is string => !!lockedTo); + .flatMap((hunk) => hunk.lockedTo) + .filter(notNull) + .filter(isDefined); } } diff --git a/crates/gitbutler-core/src/git/diff.rs b/crates/gitbutler-core/src/git/diff.rs index f7cf14694..7dca0de77 100644 --- a/crates/gitbutler-core/src/git/diff.rs +++ b/crates/gitbutler-core/src/git/diff.rs @@ -53,6 +53,7 @@ pub struct GitHunk { #[serde(rename = "diff", serialize_with = "crate::serde::as_string_lossy")] pub diff_lines: BString, pub binary: bool, + pub locked_to: Box<[git::Oid]>, pub change_type: ChangeType, } @@ -69,6 +70,7 @@ impl GitHunk { diff_lines: hex_id.into(), binary: true, change_type, + locked_to: Box::new([]), } } @@ -82,6 +84,7 @@ impl GitHunk { diff_lines: Default::default(), binary: false, change_type: ChangeType::Modified, + locked_to: Box::new([]), } } } @@ -91,6 +94,11 @@ impl GitHunk { pub fn contains(&self, line: u32) -> bool { self.new_start <= line && self.new_start + self.new_lines >= line } + + pub fn with_locks(mut self, locks: &[git::Oid]) -> Self { + self.locked_to = locks.to_owned().into(); + self + } } #[derive(Debug, PartialEq, Clone, Serialize, Default)] @@ -298,6 +306,7 @@ fn hunks_by_filepath(repo: Option<&Repository>, diff: &git2::Diff) -> Result { @@ -404,6 +413,7 @@ pub fn reverse_hunk(hunk: &GitHunk) -> Option { diff_lines: diff, binary: hunk.binary, change_type: hunk.change_type, + locked_to: Box::new([]), }) } } diff --git a/crates/gitbutler-core/src/virtual_branches/branch/hunk.rs b/crates/gitbutler-core/src/virtual_branches/branch/hunk.rs index e21c82e23..c818f7eb9 100644 --- a/crates/gitbutler-core/src/virtual_branches/branch/hunk.rs +++ b/crates/gitbutler-core/src/virtual_branches/branch/hunk.rs @@ -23,7 +23,7 @@ impl From<&diff::GitHunk> for Hunk { end: hunk.new_start + hunk.new_lines, hash: Some(Hunk::hash_diff(hunk.diff_lines.as_ref())), timestamp_ms: None, - locked_to: vec![], + locked_to: hunk.locked_to.to_vec(), } } } diff --git a/crates/gitbutler-core/src/virtual_branches/virtual.rs b/crates/gitbutler-core/src/virtual_branches/virtual.rs index 0f1b4581b..00e9bbd0f 100644 --- a/crates/gitbutler-core/src/virtual_branches/virtual.rs +++ b/crates/gitbutler-core/src/virtual_branches/virtual.rs @@ -142,7 +142,7 @@ pub struct VirtualBranchHunk { pub end: u32, pub binary: bool, pub locked: bool, - pub locked_to: Option, + pub locked_to: Option>, pub change_type: diff::ChangeType, } @@ -164,8 +164,8 @@ impl VirtualBranchHunk { end: hunk.new_start + hunk.new_lines, binary: hunk.binary, hash: Hunk::hash_diff(hunk.diff_lines.as_ref()), - locked: false, - locked_to: None, + locked: hunk.locked_to.len() > 0, + locked_to: Some(hunk.locked_to.clone()), change_type: hunk.change_type, } } @@ -937,9 +937,7 @@ pub fn list_virtual_branches( branches.push(branch); } - let branches = branches_with_large_files_abridged(branches); - let mut branches = branches_with_hunk_locks(branches, project_repository)?; - + let mut branches = branches_with_large_files_abridged(branches); branches.sort_by(|a, b| a.order.cmp(&b.order)); Ok((branches, skipped_files)) @@ -960,51 +958,6 @@ fn branches_with_large_files_abridged(mut branches: Vec) -> Vec, - project_repository: &project_repository::Repository, -) -> Result> { - let all_commits: Vec = branches - .clone() - .iter() - .filter(|branch| branch.active) - .flat_map(|vbranch| vbranch.commits.clone()) - .collect(); - - for commit in all_commits { - let commit = project_repository.git_repository.find_commit(commit.id)?; - let parent = commit.parent(0).context("failed to get parent commit")?; - let commit_tree = commit.tree().context("failed to get commit tree")?; - let parent_tree = parent.tree().context("failed to get parent tree")?; - let commited_file_diffs = diff::trees( - &project_repository.git_repository, - &parent_tree, - &commit_tree, - )?; - for branch in &mut branches { - for file in &mut branch.files { - for hunk in &mut file.hunks { - let locked = commited_file_diffs.get(&file.path).map_or(false, |file| { - file.hunks.iter().any(|committed_hunk| { - joined( - committed_hunk.new_start, - committed_hunk.new_start + committed_hunk.new_lines, - hunk.start, - hunk.end, - ) - }) - }); - if locked { - hunk.locked = true; - hunk.locked_to = Some(commit.id()); - } - } - } - } - } - Ok(branches) -} - fn joined(start_a: u32, end_a: u32, start_b: u32, end_b: u32) -> bool { ((start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b)) || ((start_b >= start_a && start_b <= end_a) || (end_b >= start_a && end_b <= end_a)) @@ -1906,7 +1859,7 @@ fn get_applied_status( end: git_diff_hunk.new_start + git_diff_hunk.new_lines, timestamp_ms: Some(mtime), hash: Some(hash), - locked_to: vec![], + locked_to: git_diff_hunk.locked_to.to_vec(), }; git_diff_hunks.remove(i); return Some(updated_hunk); @@ -1977,12 +1930,16 @@ fn get_applied_status( .with_hash(Hunk::hash_diff(hunk.diff_lines.as_ref()))], }); + let hunk = match locked_to { + Some(locks) => hunk.with_locks(locks), + _ => hunk, + }; diffs_by_branch .entry(virtual_branches[vbranch_pos].id) .or_default() .entry(filepath.clone()) .or_default() - .push(hunk.clone()); + .push(hunk); } }