/commands/rsync/rsync-delete-mirror
rsync --delete: mirror a directory and remove extra files
- tool
- rsync
- versions
- rsync 3.x
- os
- linux, macos
rsync -av --delete src/ dest/ makes dest an exact copy of src: it copies new and changed files and deletes files in dest that no longer exist in src. Deletion only happens inside the directories being synchronised and needs a recursive mode (-a includes -r). Because a wrong path or a missing trailing slash can delete a whole tree, preview with rsync -avn --delete src/ dest/ first, and consider --backup --backup-dir to keep deleted files.
Commands
# Preview: lines starting with "deleting" are the files that would be removed
rsync -avn --delete ./site/ /var/www/site/
# Mirror locally
rsync -av --delete ./site/ /var/www/site/
# Mirror to a server, keeping deleted and overwritten files in a dated directory
rsync -av --delete --backup --backup-dir="/srv/site-trash/$(date +%F)" ./site/ deploy@server.example.com:/srv/site/
# Delete excluded files on the destination as well
rsync -av --delete --delete-excluded --exclude='*.log' ./site/ /var/www/site/
# Refuse to delete more than 100 files (exit code 25 if the limit is hit)
rsync -av --delete --max-delete=100 ./site/ /var/www/site/Deletion options
| Option | Effect |
|---|---|
| --delete | Delete extra files on the receiver; rsync 3 uses --delete-during by default |
| --delete-before | Delete before transferring; frees space first, but scans the whole tree up front |
| --delete-during, --del | Delete directory by directory during the transfer |
| --delete-delay | Find deletions during the transfer, remove them at the end |
| --delete-after | Delete after all transfers in a separate pass |
| --delete-excluded | Also delete files on the receiver that match an exclude rule |
| --max-delete=NUM | Delete at most NUM files; the rest are skipped and rsync exits with code 25 |
| --max-delete=0 | Warn about extra files but delete none |
| -b --backup-dir=DIR | Move deleted and replaced files into DIR instead of removing them |
| --ignore-errors | Delete even when there were I/O errors on the sender |
Trailing slash and --delete
rsync -a --delete src/ dest/ syncs the contents of src into dest. rsync -a --delete src dest/ syncs the directory src into dest/src/ and deletes only inside dest/src/, so other files in dest survive. Mixing the two forms between runs leaves duplicate trees or deletes more than expected. The page on the rsync trailing slash shows both layouts.
Pitfalls
- Wildcards as source.
src/*passes individual names, so files deleted fromsrcare never removed fromdest. - Several sources. With two sources,
--deleteremoves files indestthat exist in neither. - Exit codes. A run that hits
--max-deleteexits 25; a run with partial errors exits 23 and may have skipped deletions. Check$?in scripts. - Availability. rsync runs on Linux and macOS; recent macOS releases ship
openrsync, which supports--deletebut not every option above. On Windows use WSL or Cygwin.
Confirm the mirror
After the real run, the same command with -n -i should list nothing to transfer or delete. diff -r src dest (locally) gives an independent check.
FAQ
Does --delete remove files that I excluded?
No. Excluded files are protected from deletion on the receiver by default. Add --delete-excluded to delete them too, which is what you want when the destination should be an exact copy of what you send.
Why does rsync print IO error encountered -- skipping file deletion?
rsync found an I/O error on the sending side, for example an unreadable directory, and disabled deletion so a temporary failure cannot wipe the destination. Fix the read error, or use --ignore-errors if you are sure deletions are still safe.
Why does --delete do nothing with rsync -av src/* dest/?
The shell expands src/* into a list of files and directories, so rsync is not asked to sync the src directory itself and does not know which extra files in dest to remove. Use src/ as the source.