A cross-platform CLI tool for comparing, diffing and merging two directories of source code files, with Git history awareness.
- Fast comparison by SHA-256 hash, file size and modification date
- Side-by-side diff for text files (similar/unified diff engine)
- Git history awareness – reads both repos (even unrelated histories) to determine which side has newer changes and detect true conflicts
- Interactive TUI (Ratatui) – kdiff3 / Beyond Compare style: side-by-side diff, file list with status icons, git history popup
- CLI modes: dry-run, auto-sync, force-left, force-right
- Binary-file detection (no broken diffs)
- Cross-platform: Linux, macOS, Windows
Requires a current stable Rust toolchain (edition 2024; Rust 1.85+ recommended) and libgit2 (usually provided by the git2 crate
which builds it from source automatically if not found via pkg-config).
cargo build --release
# binary: target/release/dirsyncOn Linux you may need:
sudo apt install libssl-dev pkg-config # Debian/Ubuntu
sudo dnf install openssl-devel # Fedora/RHELdirsync [OPTIONS] <LEFT> <RIGHT>
| Argument | Description |
|---|---|
LEFT |
Left (source A) directory |
RIGHT |
Right (source B) directory |
| Flag | Description |
|---|---|
| (none) | Interactive TUI – browse diffs, choose actions, apply |
--dry-run |
Show a summary of differences without modifying files |
--auto |
Auto-sync: copy unambiguous changes, skip conflicts |
--force-left |
Force sync: RIGHT overwrites LEFT everywhere |
--force-right |
Force sync: LEFT overwrites RIGHT everywhere |
-v, --verbose |
Verbose output in non-interactive modes |
--exclude <PATTERN> |
Excluye rutas por patrón; puede repetirse varias veces |
La TUI ahora muestra contadores de visibles/pendientes, conserva mejor el estado de selección al filtrar y restaura el terminal correctamente incluso si ocurre un error.
Los .gitignore de cada árbol también se respetan durante el escaneo, junto con exclusiones extra por --exclude.
# Interactive TUI
dirsync ~/project-a ~/project-b
# See what differs without touching anything
dirsync --dry-run ~/project-a ~/project-b
# Auto-sync files where git history is clear, skip conflicts
dirsync --auto ~/project-a ~/project-b
# Exclude node_modules in any nested subdirectory
dirsync --exclude '**/node_modules' ~/project-a ~/project-b
# Repeat --exclude as many times as needed
dirsync --exclude '**/node_modules' --exclude 'dist/**' ~/project-a ~/project-b
# Mirror left from right (right always wins)
dirsync --force-left ~/project-a ~/project-b
# Mirror right from left (left always wins)
dirsync --force-right ~/project-a ~/project-b| Key | Action |
|---|---|
↑ / k |
Move up in file list |
↓ / j |
Move down in file list |
Tab |
Switch between file list ↔ diff view |
Esc / q |
Back / quit |
PgUp / PgDn |
Scroll diff view 20 lines |
Home / g |
Jump to first diff line |
End / G |
Jump to last diff line |
Ctrl-C |
Quit immediately |
| Key | Action |
|---|---|
l / → |
Queue: copy LEFT → RIGHT |
r / ← |
Queue: copy RIGHT → LEFT |
m |
Auto-merge current file (text only) |
s |
Skip this file (clear action) |
Enter |
Apply queued action for current file |
a |
Apply all queued actions |
| Key | Action |
|---|---|
f |
Cycle filter: Diffs → Conflicts → All |
g |
Git history popup for current file |
? |
Help popup |
≡ Identical ◀ Left-only ▶ Right-only
≠ Modified ⚡ Conflict
→ Queue L→R ← Queue R→L ⊕ Merged
When both directories are inside Git repositories (which may be completely
unrelated – different origins, no shared commits), dirsync reads up to
300 commits from each repo and builds a per-file timeline.
- If file X was last touched in LEFT more recently than in RIGHT → marked git: LEFT newer → auto mode copies LEFT → RIGHT automatically.
- If both sides have commits but timestamps are equal → Conflict.
- The git history popup (
g) shows the last 8 commits per side.
src/
├── main.rs Entry point, mode dispatch
├── cli.rs Clap argument definitions
├── scanner.rs Directory walk, SHA-256 hash, binary detection
├── diff.rs Diff computation (similar crate), merge attempt
├── git_history.rs Git repo discovery, commit timeline, per-file history
├── merge.rs File copy/delete operations for all sync modes
└── ui.rs Full Ratatui TUI (side-by-side diff, popups, actions)