File backup tools
Copy a tree with rsync
Create an incremental file copy, preview changes, preserve metadata, and avoid accidental deletion.
10 minute lesson
rsync efficiently updates a destination tree. On the first run it copies everything. On every run after that, it transfers only what changed, which makes it ideal for pushing a working directory to an external disk or a remote server.
One thing to be clear about up front: by itself, one synchronized destination is not version history. rsync gives you the current state, mirrored. Yesterday’s version of a file is gone from the mirror the moment you sync today’s.
Preview, then copy
Preview before copying:
rsync --archive --dry-run --itemize-changes notes/ /Volumes/Backup/notes/
rsync --archive --itemize-changes notes/ /Volumes/Backup/notes/
--archive (or -a) preserves permissions, timestamps, symlinks, and ownership where possible — you almost always want it. --dry-run shows what would happen without touching anything. --itemize-changes prints one line per affected file:
>f+++++++++ report.txt
>f.st...... budget.md
>f+++++++++ means a new file is being created. >f.st...... means an existing file is being updated because its size and modification time differ.
Now modify, add, and remove a source file. Run the dry-run again and explain every proposed change before running the real command. When a second dry-run prints nothing, source and destination are in sync — that silence is your verification.
Trailing slashes and —delete
Be extremely careful with source trailing slashes and --delete.
The trailing slash changes meaning: notes/ means “the contents of notes”, while notes means “the directory itself”. Get it wrong and you end up with /Volumes/Backup/notes/notes/, and your next sync compares the wrong trees.
--delete removes destination files that no longer exist in the source. It’s what keeps a mirror honest, but it turns rsync into something that destroys data. A reversed source and destination can destroy the wanted copy: sync an empty new laptop to your backup disk with --delete, and the backup is now empty too. Always dry-run any command that includes --delete, every time.
Lesson completed