tarn.

Documentation

Command reference, layout on disk and retention rules.

Commands

CommandEffect
tarn snap SRC DESTTake a snapshot of SRC into the repository at DEST
tarn list DESTList snapshots, newest first, with unique size
tarn prune DESTApply the retention policy and delete expired snapshots
tarn diff DEST A BShow files that changed between two snapshots
tarn verify DESTRe-hash every file and report mismatches

Repository layout

A repository is an ordinary directory. Each snapshot is a subdirectory named after its UTC timestamp, plus a small metadata file:

/mnt/backup/work/
├── 2026-07-28T09-00-01/
├── 2026-07-29T09-00-04/
├── 2026-07-30T09-14-02/
└── tarn.index

tarn.index holds the file hashes used to decide what changed. If it is lost, the next run falls back to size and mtime comparison and rebuilds it.

Excluding files

Patterns are read from .tarnignore in the source root, using the same syntax as .gitignore:

node_modules/
*.tmp
.cache/
!.cache/keep-this

One-off exclusions

$ tarn snap ~/work /mnt/backup/work --exclude '*.iso' --exclude 'vm/'

Retention

tarn prune keeps the newest snapshot in each period and deletes the rest. The default policy is:

PeriodKept
Daily7
Weekly4
Monthly6
Yearlyall

Override per run, or set it once in the repository config:

$ tarn prune /mnt/backup/work --daily 14 --weekly 8 --monthly 12
Pruning never touches the most recent snapshot, even if the policy would otherwise expire it.

Scheduling

A systemd timer is the usual way to run it unattended:

[Unit]
Description=Nightly snapshot of /home/work

[Service]
Type=oneshot
ExecStart=/usr/local/bin/tarn snap /home/work /mnt/backup/work
ExecStartPost=/usr/local/bin/tarn prune /mnt/backup/work

Exit codes

CodeMeaning
0Success
1Usage error
2Source unreadable
3Destination not writable, or no hard-link support
4Verification found a mismatch