Merge pull request #4885 from gitbutlerapp/fix-discarding-of-deleted-and-created-files

fix discarding of deleted and created files
This commit is contained in:
Sebastian Thiel 2024-09-11 21:46:01 +02:00 committed by GitHub
commit 92c36b1a81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 41 additions and 7 deletions

View File

@ -159,7 +159,7 @@ pub fn unapply_ownership(
},
)?;
let final_tree_oid = gitbutler_diff::write::hunks_onto_tree(ctx, &final_tree, diff)?;
let final_tree_oid = gitbutler_diff::write::hunks_onto_tree(ctx, &final_tree, diff, true)?;
let final_tree = repo
.find_tree(final_tree_oid)
.context("failed to find tree")?;

View File

@ -78,7 +78,7 @@ impl GitHunk {
new_lines: 0,
diff_lines: Default::default(),
binary: false,
change_type: ChangeType::Modified,
change_type: ChangeType::Added,
}
}
}
@ -387,6 +387,11 @@ fn reverse_patch(patch: &BStr) -> Option<BString> {
// returns `None` if the reversal failed
pub fn reverse_hunk(hunk: &GitHunk) -> Option<GitHunk> {
let new_change_type = match hunk.change_type {
ChangeType::Added => ChangeType::Deleted,
ChangeType::Deleted => ChangeType::Added,
ChangeType::Modified => ChangeType::Modified,
};
if hunk.binary {
None
} else {
@ -397,7 +402,7 @@ pub fn reverse_hunk(hunk: &GitHunk) -> Option<GitHunk> {
new_lines: hunk.old_lines,
diff_lines: diff.into(),
binary: hunk.binary,
change_type: hunk.change_type,
change_type: new_change_type,
})
}
}

View File

@ -1,6 +1,6 @@
#[cfg(target_family = "unix")]
use std::os::unix::prelude::PermissionsExt;
use std::{borrow::Borrow, path::PathBuf};
use std::{borrow::Borrow, fs, path::PathBuf};
use anyhow::{anyhow, Context, Result};
use bstr::{BString, ByteSlice, ByteVec};
@ -38,13 +38,14 @@ where
let head_commit = git_repository.find_commit(commit_oid)?;
let base_tree = head_commit.tree()?;
hunks_onto_tree(ctx, &base_tree, files)
hunks_onto_tree(ctx, &base_tree, files, false)
}
pub fn hunks_onto_tree<T>(
ctx: &CommandContext,
base_tree: &git2::Tree,
files: impl IntoIterator<Item = (impl Borrow<PathBuf>, impl Borrow<Vec<T>>)>,
allow_new_file: bool,
) -> Result<git2::Oid>
where
T: Into<GitHunk> + Clone,
@ -62,7 +63,21 @@ where
&& hunks[0].diff_lines.contains_str(b"Subproject commit");
// if file exists
if full_path.exists() {
let full_path_exists = full_path.exists();
let discard_hunk = (hunks.len() == 1).then(|| &hunks[0]);
if full_path_exists || allow_new_file {
if discard_hunk.map_or(false, |hunk| hunk.change_type == crate::ChangeType::Deleted) {
// File was created but now that hunk is being discarded with an inversed hunk
builder.remove(rel_path);
fs::remove_file(full_path.clone()).or_else(|err| {
if err.kind() == std::io::ErrorKind::NotFound {
Ok(())
} else {
Err(err)
}
})?;
continue;
}
// if file is executable, use 755, otherwise 644
let mut filemode = git2::FileMode::Blob;
// check if full_path file is executable
@ -115,7 +130,7 @@ where
)?;
builder.upsert(rel_path, blob_oid, filemode);
} else if let Ok(tree_entry) = base_tree.get_path(rel_path) {
if hunks.len() == 1 && hunks[0].binary {
if discard_hunk.map_or(false, |hunk| hunk.binary) {
let new_blob_oid = &hunks[0].diff_lines;
// convert string to Oid
let new_blob_oid = new_blob_oid
@ -178,6 +193,20 @@ where
let new_blob_oid = git_repository.blob(blob_contents.as_bytes())?;
// upsert into the builder
builder.upsert(rel_path, new_blob_oid, filemode);
} else if !full_path_exists
&& discard_hunk.map_or(false, |hunk| hunk.change_type == crate::ChangeType::Added)
{
// File was deleted but now that hunk is being discarded with an inversed hunk
let mut all_diffs = BString::default();
for hunk in hunks {
all_diffs.push_str(&hunk.diff_lines);
}
let patch = Patch::from_bytes(&all_diffs)?;
let blob_contents =
apply([], &patch).context(format!("failed to apply {}", all_diffs))?;
let new_blob_oid = git_repository.blob(&blob_contents)?;
builder.upsert(rel_path, new_blob_oid, filemode);
} else {
// create a git blob from a file on disk
let blob_oid = git_repository