
[](https://crates.io/crates/clonetree)
[](https://docs.rs/clonetree)
# 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](https://discord.gg/fHmRmuBDxF).
---
## Highlights
* **Fast copy‑on‑write clone** on APFS, Btrfs, XFS, bcachefs, overlayfs, ReFS…
* **Powered by [`reflink-copy`](https://github.com/cargo-bins/reflink-copy)** for portable block‑cloning.
* **Flexible glob patterns** to include/exclude files (uses `!` prefix for exclusions).
* **Graceful fallback** to `std::fs::copy` when 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`](https://docs.rs/ignore) crate: later patterns override earlier ones.
```rust
use clonetree::{clone_tree, Options};
fn main() -> anyhow::Result<()> {
// Include all source files but drop tests
let opts = Options::new()
.glob("src/**") // positive include
.glob("!src/tests/**"); // negative exclude; overrides the line above
clone_tree("./", "./sandbox", &opts)?;
Ok(())
}
```
---
## 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.
| `*.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 `ignore` crate).
---
## `ctree` ‑ command‑line tool
The crate ships with a convenience binary so users can benefit without writing code.
### Install
```bash
cargo install ctree
```
### Semantics
`ctree` copies a directory to a specified destination. The source must be a
directory, and the destination must not exist.
### Basic usage
```bash
ctree <SRC> <DEST> [OPTIONS]
OPTIONS:
-g, --glob <GLOB> Match or exclude glob (repeatable)
--strategy <auto|single-call|full-traversal>
Cloning strategy (defaults to auto)
-q, --quiet Suppress progress output
-h, --help Show this help
```
Example: snapshot a repo while excluding Git metadata and build output:
```bash
ctree . ./sandbox \
--glob '!target/**' \
--glob '!.git/**'
```
### Strategies
`clonetree` offers three strategies:
* `auto` (default): on macOS/APFS it issues a **single `clonefile` call** 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.
| `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](https://crates.io/crates/reflink-copy)
| 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 |