TL;DR
| |
How rsync decides what to copy
Before moving a byte, rsync compares each file with its copy at the destination using up to three things: size, modification time, and content checksum. By default it uses the first two (one stat, free); the third forces reading the whole file on both sides.
| Option | Compares | Copies the file if… | When |
|---|---|---|---|
| (default) | size + mtime | either differs | Almost always |
--size-only | size | the size differs | Dates cannot be trusted (restores, FAT, mass touch) and you accept missing changes that keep the size |
--checksum / -c | size + checksum | size or content differ; ignores the date | Integrity checks; builds that reset dates to 1970 |
--ignore-times / -I | nothing | always | Force a full recopy |
--checksum only hashes when the size matches, but it still reads every file end to end: over terabytes it is slow, not “safer by default”.
Resuming large transfers
With no options, if the connection drops halfway through a 200 GB file, rsync deletes the piece and the next run starts from zero. Three options change that:
--partialkeeps the half-done file. Better--partial-dir=.rsync-partial: it stores it in a subdirectory and the destination never exposes a truncated file.--append-verifyresumes from the size the destination already has, trusting what is there, and at the end verifies the checksum of the whole file; if it does not match, it resends it entirely. Meant for files written sequentially (an image being copied, a dump, a video). Plain--append, with no verification, do not use.--inplacewrites straight into the destination file instead of a temp file plusrename.--append-verifyneeds it, it saves the double space with huge files, and on destinations with snapshots (ZFS, btrfs) it only rewrites the blocks that changed, so the next snapshot stays small. In exchange, while the copy runs the destination file is inconsistent: do not use it on something being served.
| |
Over SSH the cipher is the bottleneck on a LAN: aes128-gcm@openssh.com with AES-NI, or chacha20-poly1305@openssh.com on CPUs without AES-NI, and Compression=no (compressing already compressed data only burns CPU). --bwlimit=50m if you share the link.
Only the directory tree
| |
Filters are evaluated in order: + */ includes anything that is a directory; - * excludes the rest. With -a it keeps permissions and owners. Useful to prepare a destination, replicate a skeleton on another storage, or see the shape of a dataset without dragging the data.
Verifying at the end
| |
-n copies nothing; --itemize-changes prints one line per difference. Empty output means an identical copy. It replaces walking both sides with md5sum by hand and does the comparison for you.
Traps
- The trailing slash changes the result:
source/copies the contents;sourcecreatesdest/source/. --deletewith the wrong path empties the destination. Always-nfirst.--append-verifyon files that change in the middle (databases, VM disks in use) verifies, fails, and resends the whole thing every time; there,--partial --inplacewithout append.-zcompresses in flight: fine for text, useless for videos, ISOs,.gzdumps, or already compressed VM images.- macOS as the source:
--iconv=utf-8-mac,utf-8converts names from NFD to NFC in flight; without it, accents arrive “odd” on Linux (the Nextcloud case). - Hard links are lost with
--inplaceif the file gets rewritten; use-Hwithout--inplacewhen they matter.