diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index ea92fb7f..49223306 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -10,7 +10,7 @@ pub mod utils; pub use hooks::{hooks_commit_msg, hooks_post_commit, HookResult}; pub use hunks::{stage_hunk, unstage_hunk}; pub use reset::{reset_stage, reset_workdir}; -pub use utils::{commit, stage_add}; +pub use utils::{commit, stage_add, stage_addremoved}; #[cfg(test)] mod tests { diff --git a/asyncgit/src/sync/utils.rs b/asyncgit/src/sync/utils.rs index a82b45bc..27942790 100644 --- a/asyncgit/src/sync/utils.rs +++ b/asyncgit/src/sync/utils.rs @@ -62,7 +62,7 @@ pub fn commit(repo_path: &str, msg: &str) { .unwrap(); } -/// +/// add a file diff from workingdir to stage (will not add removed files see `stage_addremoved`) pub fn stage_add(repo_path: &str, path: &Path) -> bool { scope_time!("stage_add"); @@ -78,6 +78,22 @@ pub fn stage_add(repo_path: &str, path: &Path) -> bool { false } +/// stage a removed file +pub fn stage_addremoved(repo_path: &str, path: &Path) -> bool { + scope_time!("stage_addremoved"); + + let repo = repo(repo_path); + + let mut index = repo.index().unwrap(); + + if index.remove_path(path).is_ok() { + index.write().unwrap(); + return true; + } + + false +} + #[cfg(test)] mod tests { use super::*; @@ -86,7 +102,11 @@ mod tests { status::{get_status, StatusType}, tests::{repo_init, repo_init_empty}, }; - use std::{fs::File, io::Write, path::Path}; + use std::{ + fs::{remove_file, File}, + io::Write, + path::Path, + }; #[test] fn test_commit() { @@ -172,4 +192,38 @@ mod tests { assert_eq!(status_count(StatusType::WorkingDir), 1); assert_eq!(status_count(StatusType::Stage), 1); } + + #[test] + fn test_staging_deleted_file() { + let file_path = Path::new("file1.txt"); + let (_td, repo) = repo_init(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); + + let status_count = |s: StatusType| -> usize { + get_status(repo_path, s).len() + }; + + let full_path = &root.join(file_path); + + File::create(full_path) + .unwrap() + .write_all(b"test file1 content") + .unwrap(); + + assert_eq!(stage_add(repo_path, file_path), true); + + commit(repo_path, "commit msg"); + + // delete the file now + assert_eq!(remove_file(full_path).is_ok(), true); + + // deleted file in diff now + assert_eq!(status_count(StatusType::WorkingDir), 1); + + assert_eq!(stage_addremoved(repo_path, file_path), true); + + assert_eq!(status_count(StatusType::WorkingDir), 0); + assert_eq!(status_count(StatusType::Stage), 1); + } } diff --git a/src/components/changes.rs b/src/components/changes.rs index 3ae90b63..96fbb74a 100644 --- a/src/components/changes.rs +++ b/src/components/changes.rs @@ -114,9 +114,15 @@ impl ChangesComponent { fn index_add_remove(&mut self) -> bool { if let Some(i) = self.selection() { if self.is_working_dir { - let path = Path::new(i.path.as_str()); - - return sync::stage_add(CWD, path); + if let Some(status) = i.status { + let path = Path::new(i.path.as_str()); + return match status { + StatusItemType::Deleted => { + sync::stage_addremoved(CWD, path) + } + _ => sync::stage_add(CWD, path), + }; + } } else { let path = Path::new(i.path.as_str());