mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-18 06:22:28 +03:00
Allow hunk locking to multiple commits
- adds `locked_to` field to `GitHunk` to avoid looking it up again - sends array to ui instead of single commit id
This commit is contained in:
parent
a664c85a9a
commit
c202d83b6b
@ -1,3 +1,7 @@
|
||||
export function isDefined<T>(file: T | undefined): file is T {
|
||||
export function isDefined<T>(file: T | undefined | null): file is T {
|
||||
return file !== undefined;
|
||||
}
|
||||
|
||||
export function notNull<T>(file: T | undefined | null): file is T {
|
||||
return file !== null;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Dif
|
||||
diff_lines: line.into_owned(),
|
||||
binary: false,
|
||||
change_type,
|
||||
locked_to: Box::new([]),
|
||||
}
|
||||
}
|
||||
LineOrHexHash::HexHashOfBinaryBlob(id) => {
|
||||
@ -404,6 +413,7 @@ pub fn reverse_hunk(hunk: &GitHunk) -> Option<GitHunk> {
|
||||
diff_lines: diff,
|
||||
binary: hunk.binary,
|
||||
change_type: hunk.change_type,
|
||||
locked_to: Box::new([]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ pub struct VirtualBranchHunk {
|
||||
pub end: u32,
|
||||
pub binary: bool,
|
||||
pub locked: bool,
|
||||
pub locked_to: Option<git::Oid>,
|
||||
pub locked_to: Option<Box<[git::Oid]>>,
|
||||
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<VirtualBranch>) -> Vec<V
|
||||
branches
|
||||
}
|
||||
|
||||
fn branches_with_hunk_locks(
|
||||
mut branches: Vec<VirtualBranch>,
|
||||
project_repository: &project_repository::Repository,
|
||||
) -> Result<Vec<VirtualBranch>> {
|
||||
let all_commits: Vec<VirtualBranchCommit> = 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user