A tiny, fast Rust CLI that scans a directory tree for empty sub-directories and drops an empty .keep file in each one. Handy for committing directory structure to Git.
- Recursively scans a path (defaults to current working directory)
- Creates
.keepin truly empty sub-directories - Dry run mode to preview without writing
- Helpful summary at the end
- Works on macOS, Linux, and Windows
cargo install --path .
# or if published later:
# cargo install keep-empty-dirgit clone https://github.com/joelee/keep-empty-dir.git
cd keep-empty-dir
cargo build --release
# binary at target/release/keep-empty-dirkeep-empty-dir [PATH] [OPTIONS]- If
PATHis omitted, the current directory (.) is used.
-h, --help Print help and usage
-v, --version Print version (alias; also supports -V/--version)
-d, --dryrun Only print empty directories; do not write .keep files
Scan the current directory and create .keep files:
keep-empty-dirScan a specific path:
keep-empty-dir ./packages/sharedDry run (no files written):
keep-empty-dir -d ./srcTypical output:
created: /project/tmp/cache/.keep
created: /project/assets/images/.keep
Summary:
scanned dirs: 57
empty found: 2
.keep created: 2
errors: 0
A directory is considered empty if it has zero entries (no files or sub-directories).
If a directory already contains anything (including an existing .keep), it’s not treated as empty and is skipped.
Note: Symbolic links are not followed.
0— Completed (even if some directories were skipped)2— Provided path does not exist or is not a directory
Read and permission errors are reported as warnings and included in the summary, but they don’t stop the scan.
If you prefer not to commit .keep in some places, use a targeted .gitignore.
If you do want to commit them, ensure your global or repo .gitignore doesn’t ignore .keep.
Example .gitignore snippet to allow .keep even when ignoring everything else:
*
!.keep
- Uses
walkdirfor efficient recursive traversal. - Skips non-directories early.
- Avoids following symlinks for safety and speed.
.
├─ Cargo.toml
└─ src/
└─ main.rs
cargo run -- [OPTIONS] [PATH]
# Example:
cargo run -- -d .cargo fmt
cargo clippy -- -D warningsMIT — see LICENSE.
Built with ❤️ in Rust, using clap for CLI ergonomics and walkdir for traversal.