diff --git a/CHANGELOG.md b/CHANGELOG.md index d553bec..f295155 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ Categories Used: - CI refactor [\#578](https://github.com/ouch-org/ouch/pull/578) ([cyqsimon](https://github.com/cyqsimon)) - Use a prefix `tmp-ouch-` for temporary decompression path name to avoid conflicts [\#725](https://github.com/ouch-org/ouch/pull/725) ([valoq](https://github.com/valoq)) & [\#788](https://github.com/ouch-org/ouch/pull/788) ([talis-fb](https://github.com/talis-fb)) +- Ignore `.git/` when `-g/--gitignore` is set [\#507](https://github.com/ouch-org/ouch/pull/507) ([talis-fb](https://github.com/talis-fb)) - Run clippy for tests too [\#738](https://github.com/ouch-org/ouch/pull/738) ([marcospb19](https://github.com/marcospb19)) - Sevenz-rust is unmaintained, switch to sevenz-rust2 [\#796](https://github.com/ouch-org/ouch/pull/796) ([tommady](https://github.com/tommady)) diff --git a/src/utils/file_visibility.rs b/src/utils/file_visibility.rs index d8abd40..fc478b2 100644 --- a/src/utils/file_visibility.rs +++ b/src/utils/file_visibility.rs @@ -69,11 +69,18 @@ impl FileVisibilityPolicy { /// Walks through a directory using [`ignore::Walk`] pub fn build_walker(&self, path: impl AsRef) -> ignore::Walk { - ignore::WalkBuilder::new(path) + let mut builder = ignore::WalkBuilder::new(path); + + builder .git_exclude(self.read_git_exclude) .git_ignore(self.read_git_ignore) .ignore(self.read_ignore) - .hidden(self.read_hidden) - .build() + .hidden(self.read_hidden); + + if self.read_git_ignore { + builder.filter_entry(|p| p.path().file_name().is_some_and(|name| name != ".git")); + } + + builder.build() } } diff --git a/tests/integration.rs b/tests/integration.rs index 1a984a5..52413a7 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -381,10 +381,9 @@ fn multiple_files_with_disabled_smart_unpack_by_dir( let files_path = ["file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt"] .into_iter() .map(|f| src_files_path.join(f)) - .map(|path| { - let mut file = fs::File::create(&path).unwrap(); + .inspect(|path| { + let mut file = fs::File::create(path).unwrap(); file.write_all("Some content".as_bytes()).unwrap(); - path }) .collect::>(); @@ -560,3 +559,48 @@ fn symlink_pack_and_unpack( assert!(!f.file_type().unwrap().is_symlink()) } } + +#[test] +fn no_git_folder_after_decompression_with_gitignore_flag_active() { + use std::process::Command; + + let dir = tempdir().unwrap(); + let dir_path = dir.path(); + + let before = dir_path.join("before"); + + let decompressed = dir_path.join("decompressed"); + + // Create directory and a dummy file + fs::create_dir(&before).unwrap(); + fs::write(before.join("hello.txt"), b"Hello, world!").unwrap(); + + // Run `git init` inside it + Command::new("git") + .arg("init") + .current_dir(&before) + .output() + .expect("failed to run git init"); + + assert!(before.join(".git").exists(), ".git folder should exist after git init"); + + // Compress it + let archive = dir_path.join("archive.zip"); + ouch!("c", &before, &archive, "--gitignore"); + + // Decompress it + ouch!("d", &archive, "-d", &decompressed); + + // Find the subdirectory inside decompressed (e.g., "before") + let decompressed_subdir = fs::read_dir(&decompressed) + .unwrap() + .find_map(Result::ok) + .map(|entry| entry.path()) + .expect("Expected one directory inside decompressed"); + + // Assert that the decompressed folder does not include `.git/` + assert!( + !decompressed_subdir.join(".git").exists(), + ".git folder should not exist after decompression" + ); +}