mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-18 14:31:30 +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;
|
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 'reflect-metadata';
|
||||||
import { splitMessage } from '$lib/utils/commitMessage';
|
import { splitMessage } from '$lib/utils/commitMessage';
|
||||||
import { hashCode } from '$lib/utils/string';
|
import { hashCode } from '$lib/utils/string';
|
||||||
|
import { isDefined, notNull } from '$lib/utils/typeguards';
|
||||||
import { Type, Transform } from 'class-transformer';
|
import { Type, Transform } from 'class-transformer';
|
||||||
|
|
||||||
export type ChangeType =
|
export type ChangeType =
|
||||||
@ -21,7 +22,7 @@ export class Hunk {
|
|||||||
filePath!: string;
|
filePath!: string;
|
||||||
hash?: string;
|
hash?: string;
|
||||||
locked!: boolean;
|
locked!: boolean;
|
||||||
lockedTo!: string | undefined;
|
lockedTo!: string[] | undefined;
|
||||||
changeType!: ChangeType;
|
changeType!: ChangeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,14 +59,15 @@ export class LocalFile {
|
|||||||
|
|
||||||
get locked(): boolean {
|
get locked(): boolean {
|
||||||
return this.hunks
|
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;
|
: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get lockedIds(): string[] {
|
get lockedIds(): string[] {
|
||||||
return this.hunks
|
return this.hunks
|
||||||
.map((hunk) => hunk.lockedTo)
|
.flatMap((hunk) => hunk.lockedTo)
|
||||||
.filter((lockedTo): lockedTo is string => !!lockedTo);
|
.filter(notNull)
|
||||||
|
.filter(isDefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ pub struct GitHunk {
|
|||||||
#[serde(rename = "diff", serialize_with = "crate::serde::as_string_lossy")]
|
#[serde(rename = "diff", serialize_with = "crate::serde::as_string_lossy")]
|
||||||
pub diff_lines: BString,
|
pub diff_lines: BString,
|
||||||
pub binary: bool,
|
pub binary: bool,
|
||||||
|
pub locked_to: Box<[git::Oid]>,
|
||||||
pub change_type: ChangeType,
|
pub change_type: ChangeType,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +70,7 @@ impl GitHunk {
|
|||||||
diff_lines: hex_id.into(),
|
diff_lines: hex_id.into(),
|
||||||
binary: true,
|
binary: true,
|
||||||
change_type,
|
change_type,
|
||||||
|
locked_to: Box::new([]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +84,7 @@ impl GitHunk {
|
|||||||
diff_lines: Default::default(),
|
diff_lines: Default::default(),
|
||||||
binary: false,
|
binary: false,
|
||||||
change_type: ChangeType::Modified,
|
change_type: ChangeType::Modified,
|
||||||
|
locked_to: Box::new([]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,6 +94,11 @@ impl GitHunk {
|
|||||||
pub fn contains(&self, line: u32) -> bool {
|
pub fn contains(&self, line: u32) -> bool {
|
||||||
self.new_start <= line && self.new_start + self.new_lines >= line
|
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)]
|
#[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(),
|
diff_lines: line.into_owned(),
|
||||||
binary: false,
|
binary: false,
|
||||||
change_type,
|
change_type,
|
||||||
|
locked_to: Box::new([]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LineOrHexHash::HexHashOfBinaryBlob(id) => {
|
LineOrHexHash::HexHashOfBinaryBlob(id) => {
|
||||||
@ -404,6 +413,7 @@ pub fn reverse_hunk(hunk: &GitHunk) -> Option<GitHunk> {
|
|||||||
diff_lines: diff,
|
diff_lines: diff,
|
||||||
binary: hunk.binary,
|
binary: hunk.binary,
|
||||||
change_type: hunk.change_type,
|
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,
|
end: hunk.new_start + hunk.new_lines,
|
||||||
hash: Some(Hunk::hash_diff(hunk.diff_lines.as_ref())),
|
hash: Some(Hunk::hash_diff(hunk.diff_lines.as_ref())),
|
||||||
timestamp_ms: None,
|
timestamp_ms: None,
|
||||||
locked_to: vec![],
|
locked_to: hunk.locked_to.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ pub struct VirtualBranchHunk {
|
|||||||
pub end: u32,
|
pub end: u32,
|
||||||
pub binary: bool,
|
pub binary: bool,
|
||||||
pub locked: bool,
|
pub locked: bool,
|
||||||
pub locked_to: Option<git::Oid>,
|
pub locked_to: Option<Box<[git::Oid]>>,
|
||||||
pub change_type: diff::ChangeType,
|
pub change_type: diff::ChangeType,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,8 +164,8 @@ impl VirtualBranchHunk {
|
|||||||
end: hunk.new_start + hunk.new_lines,
|
end: hunk.new_start + hunk.new_lines,
|
||||||
binary: hunk.binary,
|
binary: hunk.binary,
|
||||||
hash: Hunk::hash_diff(hunk.diff_lines.as_ref()),
|
hash: Hunk::hash_diff(hunk.diff_lines.as_ref()),
|
||||||
locked: false,
|
locked: hunk.locked_to.len() > 0,
|
||||||
locked_to: None,
|
locked_to: Some(hunk.locked_to.clone()),
|
||||||
change_type: hunk.change_type,
|
change_type: hunk.change_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -937,9 +937,7 @@ pub fn list_virtual_branches(
|
|||||||
branches.push(branch);
|
branches.push(branch);
|
||||||
}
|
}
|
||||||
|
|
||||||
let branches = branches_with_large_files_abridged(branches);
|
let mut branches = branches_with_large_files_abridged(branches);
|
||||||
let mut branches = branches_with_hunk_locks(branches, project_repository)?;
|
|
||||||
|
|
||||||
branches.sort_by(|a, b| a.order.cmp(&b.order));
|
branches.sort_by(|a, b| a.order.cmp(&b.order));
|
||||||
|
|
||||||
Ok((branches, skipped_files))
|
Ok((branches, skipped_files))
|
||||||
@ -960,51 +958,6 @@ fn branches_with_large_files_abridged(mut branches: Vec<VirtualBranch>) -> Vec<V
|
|||||||
branches
|
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 {
|
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_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))
|
|| ((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,
|
end: git_diff_hunk.new_start + git_diff_hunk.new_lines,
|
||||||
timestamp_ms: Some(mtime),
|
timestamp_ms: Some(mtime),
|
||||||
hash: Some(hash),
|
hash: Some(hash),
|
||||||
locked_to: vec![],
|
locked_to: git_diff_hunk.locked_to.to_vec(),
|
||||||
};
|
};
|
||||||
git_diff_hunks.remove(i);
|
git_diff_hunks.remove(i);
|
||||||
return Some(updated_hunk);
|
return Some(updated_hunk);
|
||||||
@ -1977,12 +1930,16 @@ fn get_applied_status(
|
|||||||
.with_hash(Hunk::hash_diff(hunk.diff_lines.as_ref()))],
|
.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
|
diffs_by_branch
|
||||||
.entry(virtual_branches[vbranch_pos].id)
|
.entry(virtual_branches[vbranch_pos].id)
|
||||||
.or_default()
|
.or_default()
|
||||||
.entry(filepath.clone())
|
.entry(filepath.clone())
|
||||||
.or_default()
|
.or_default()
|
||||||
.push(hunk.clone());
|
.push(hunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user