phomv phomv
Use this command to install phomv:
winget install --id=phomv.phomv -e Organizes photos into a YYYY/YYYY_MM/YYYY_MM_DD hierarchy from EXIF metadata
winget install --id=phomv.phomv -e Organizes photos into a YYYY/YYYY_MM/YYYY_MM_DD hierarchy from EXIF metadata
phomv (photo move) is a high-performance CLI utility written in Go that
organizes photo directories into a YYYY/YYYY_MM/YYYY_MM_DD hierarchy based on EXIF
metadata. It is designed to be fast, safe, and decoupled enough that the same
core engine can later back a Wails or Fyne GUI.
.jpg, .jpeg, .png, .heic,
.cr2, .nef, .arw, .dng, .tif, .tiff).DateTimeOriginal extraction with file-mtime fallback.IMG_001_1.jpg, IMG_001_2.jpg, ...).Unknown/ bucket instead of
crashing the run.brew install phomv/tap/phomv
winget install phomv.phomv
Grab the latest release for your platform from the releases page.
go install github.com/phomv/phomv/cmd/phomv@latest
Or build locally:
make build # produces ./bin/phomv
make install # installs into $GOBIN
make release # cross-compiles to ./dist for linux/macOS/windows
Requires Go 1.24+.
# Preview what a copy would do
phomv copy --src ~/Pictures/import --dest ~/Pictures/library --dry-run
# Actually copy
phomv copy -s ~/Pictures/import -d ~/Pictures/library -w 8
# Move and clean up empty source dirs
phomv move -s /mnt/sdcard -d ~/Pictures/library
# Version
phomv version
| Flag | Default | Description |
|---|---|---|
-s, --src | - | Source directory (required) |
-d, --dest | - | Destination directory (required) |
-n, --dry-run | false | Simulate execution without touching disk |
-w, --workers | 4 | Number of concurrent workers |
-v, --verbose | false | Enable debug logging |
phomv/
├── cmd/phomv/ # Cobra CLI entry point
├── internal/
│ ├── processor/ # EXIF extraction + destination path formatting
│ ├── worker/ # Discovery + worker pool pipeline
│ └── filesystem/ # Copy/move/collision/idempotency primitives
├── Makefile # Build, test, cross-compile
└── go.mod
The CLI is a thin shell around internal/worker.Run, which streams Result
values on a channel. A future GUI can consume the same channel to render
progress without touching the engine.
make test