clonetree
A copy‑on‑write directory library for Rust
clonetree is a Rust crate for fast directory duplication. It uses
filesystem‑level reflinks so large trees are cloned quickly and consume no
extra space until files diverge.
Community
Want to contribute? Have ideas or feature requests? Come tell us about it on Discord.
Highlights
-
Fast copy‑on‑write clone on APFS, Btrfs, XFS, bcachefs, overlayfs, ReFS…
-
Powered by
reflink-copyfor portable block‑cloning. -
Flexible glob patterns to include/exclude files (uses
!prefix for exclusions). -
Graceful fallback to
std::fs::copywhen reflinks are unsupported. -
Symlink preservation — symbolic links are recreated with their original targets.
-
Empty directory preservation — empty directories are included in the clone.
-
Pure Rust, no unsafe code, minimal deps.
Library quick start
Clone only Rust source files under src/ into ./sandbox, while excluding
unit tests. This demonstrates the precedence rules from the
ignore crate: later patterns override earlier ones.
use ;
Glob syntax
clonetree accepts the same glob rules as a single line in a .gitignore
file. Prefix a pattern with ! to exclude matching paths instead of
including them.
| Pattern | Description |
|---|---|
*.rs |
All Rust source files in the current directory |
**/*.toml |
Any .toml file at any depth |
!target/** |
Exclude Cargo build artefacts |
images/**/thumb_* |
Every thumb_* file under images/ recursively |
Rules:
*matches any sequence of characters except path separators.**matches across directory boundaries.?matches exactly one character.- A trailing
/restricts the pattern to directories only. - Patterns are evaluated in the order they are given; later patterns can
override earlier ones (precedence follows the
ignorecrate).
ctree ‑ command‑line tool
The crate ships with a convenience binary so users can benefit without writing code.
Install
Semantics
ctree copies a directory to a specified destination. The source must be a
directory, and the destination must not exist.
Basic usage
)
|| )
Example: snapshot a repo while excluding Git metadata and build output:
Strategies
clonetree offers three strategies:
auto(default): on macOS/APFS it issues a singleclonefilecall on the root directory (fastest, atomic, COW). Else it falls back to traversal.single-call: force the one-shot clone (macOS only; destination must not exist; incompatible with glob filters).full-traversal: user-space walk that reflinks each file individually (works everywhere and honors glob filters).
Symlink handling
Symbolic links are preserved as symbolic links — they are not followed or dereferenced. The link target is copied verbatim, so relative symlinks maintain their relative paths in the cloned tree.
| Strategy | Symlink behaviour |
|---|---|
single-call |
Preserved by the kernel's clonefile(2) (macOS only) |
full-traversal |
Recreated via symlink(2) (Unix) or CreateSymbolicLink (Windows) |
Filesystem support matrix
Via reflink-copy
| OS / FS | Reflink supported | API used | Behaviour |
|---|---|---|---|
| macOS 10.13+ / APFS | ✅ | clonefile(2) |
COW clone |
| iOS / APFS | ✅ | clonefile(2) |
COW clone |
| Linux 6.7+ / Btrfs | ✅ | FICLONE ioctl |
COW clone |
Linux 5.4+ / XFS (reflink=1) |
✅ | FICLONE ioctl |
COW clone |
| Linux 6.1+ / bcachefs | ✅ | remap_file_range |
COW clone |
| Linux 5.13+ / overlayfs | ✅ | remap_file_range |
COW clone |
| Windows Server 2016+ / ReFS | ✅ | FSCTL_DUPLICATE_EXTENTS_TO_FILE |
COW clone |
| ext4 (Ubuntu/Fedora default) | ❌ | – | Byte‑for‑byte copy |