fix hunk locking

This commit is contained in:
Nikita Galaiko 2023-11-01 13:27:12 +01:00 committed by GitButler
parent 78c179389b
commit ba0069e6ae
2 changed files with 96 additions and 4 deletions

View File

@ -1,4 +1,8 @@
use std::{collections::HashMap, os::unix::fs::PermissionsExt, path, time, vec};
use std::{
collections::{HashMap, HashSet},
os::unix::fs::PermissionsExt,
path, time, vec,
};
use anyhow::{anyhow, bail, Context, Result};
use diffy::{apply_bytes, Patch};
@ -640,10 +644,20 @@ pub fn list_virtual_branches(
let statuses = get_status_by_branch(gb_repository, project_repository)?;
for (branch, files) in &statuses {
let file_diffs = files
.iter()
.map(|(filepath, hunks)| {
(
filepath,
hunks.iter().map(|hunk| &hunk.diff).collect::<HashSet<_>>(),
)
})
.collect::<HashMap<_, _>>();
// check if head tree does not match target tree
// if so, we diff the head tree and the new write_tree output to see what is new and filter the hunks to just those
let files =
calculate_non_commited_files(project_repository, branch, &default_target, files)?;
calculate_non_commited_diffs(project_repository, branch, &default_target, files)?;
let repo = &project_repository.git_repository;
@ -732,6 +746,18 @@ pub fn list_virtual_branches(
)
});
// mark locked hunks
for file in &mut files {
file.hunks.iter_mut().for_each(|hunk| {
// we consider a hunk to be locked if it's not seen verbatim
// non-commited. reason beging - we can't partialy move hunks between
// branches just yet.
hunk.locked = file_diffs
.get(&file.path)
.map_or(false, |h| !h.contains(&hunk.diff));
});
}
let requires_force = is_requires_force(project_repository, branch)?;
let branch = VirtualBranch {
id: branch.id,
@ -786,7 +812,7 @@ fn is_requires_force(
// given a virtual branch and it's files that are calculated off of a default target,
// return files adjusted to the branch's head commit
fn calculate_non_commited_files(
fn calculate_non_commited_diffs(
project_repository: &project_repository::Repository,
branch: &branch::Branch,
default_target: &target::Target,
@ -1876,7 +1902,7 @@ pub fn commit(
.find(|(branch, _)| branch.id == *branch_id)
.ok_or_else(|| anyhow!("branch {} not found", branch_id))?;
let files = calculate_non_commited_files(project_repository, branch, &default_target, files)?;
let files = calculate_non_commited_diffs(project_repository, branch, &default_target, files)?;
if conflicts::is_conflicting(project_repository, None)? {
return Err(CommitError::Conflicted);
}

View File

@ -41,6 +41,72 @@ impl Default for Test {
}
}
mod create_commit {
use super::*;
#[tokio::test]
async fn should_lock_updated_hunks() {
let Test {
project_id,
controller,
repository,
..
} = Test::default();
controller
.set_base_branch(
&project_id,
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
)
.unwrap();
let branch_id = controller
.create_virtual_branch(&project_id, &branch::BranchCreateRequest::default())
.await
.unwrap();
{
// by default, hunks are not locked
fs::write(repository.path().join("file.txt"), "content").unwrap();
let branch = controller
.list_virtual_branches(&project_id)
.await
.unwrap()
.into_iter()
.find(|b| b.id == branch_id)
.unwrap();
assert_eq!(branch.files.len(), 1);
assert_eq!(branch.files[0].path.display().to_string(), "file.txt");
assert_eq!(branch.files[0].hunks.len(), 1);
assert!(!branch.files[0].hunks[0].locked);
}
controller
.create_commit(&project_id, &branch_id, "test", None)
.await
.unwrap();
{
// change in the comitted hunks leads to hunk locking
fs::write(repository.path().join("file.txt"), "updated content").unwrap();
let branch = controller
.list_virtual_branches(&project_id)
.await
.unwrap()
.into_iter()
.find(|b| b.id == branch_id)
.unwrap();
assert_eq!(branch.files.len(), 1);
assert_eq!(branch.files[0].path.display().to_string(), "file.txt");
assert_eq!(branch.files[0].hunks.len(), 1);
assert!(branch.files[0].hunks[0].locked);
}
}
}
mod references {
use super::*;