Hard-linked rsync snapshots let a Linux backup operator keep several browseable points in time without storing another copy of every unchanged file. Each dated directory looks like a complete tree, while matching regular files can share one inode on the backup filesystem.
The --link-dest option hard-links a file from an earlier tree only when its content and preserved attributes match. Its relative ../2026-07-10 value selects the previous sibling from the new destination, so both dated trees must share the same backup filesystem. The --checksum check reads same-size files instead of trusting only their modification time and size, which costs more disk I/O but prevents an undetected same-size content change from being linked as unchanged.
The publish and inode checks target Linux and use GNU-compatible mv and stat options that differ from the default macOS and BSD forms. Keep source writes paused through the whole-tree comparison, resume the workload afterward, and leave completed snapshot trees unchanged because later writes through shared inodes can alter more than one date.
Use the application's native backup, checkpoint, or snapshot method for databases and other write-heavy data. A filesystem copy taken while related files are changing may not restore to one consistent point in time.
$ ls -1 /snapshots 2026-07-10
Replace the sample dates and paths consistently. Only one backup process should write to this snapshot root at a time.
$ mkdir /snapshots/.2026-07-11.in-progress
mkdir must fail if this staging name already exists. Do not reuse an interrupted or completed snapshot as the writable destination; inspect and remove only the exact abandoned staging tree before starting again.
$ rsync --archive --checksum --itemize-changes --link-dest=../2026-07-10 /srv/projects/ /snapshots/.2026-07-11.in-progress/ .d..t...... ./ >fcst...... workload.log >fc........ releases/current.txt >f+++++++++ releases/release-notes.txt
Do not add --inplace or point this command at /snapshots/2026-07-10/. In-place writes can change data through shared hard links, and writing into a completed snapshot can damage historical data.
$ mv --no-clobber --verbose --no-target-directory /snapshots/.2026-07-11.in-progress /snapshots/2026-07-11 renamed '/snapshots/.2026-07-11.in-progress' -> '/snapshots/2026-07-11'
The --no-clobber and --no-target-directory options prevent an existing dated directory from becoming an accidental parent. Continue only when mv prints the renamed line.
$ rsync --archive --checksum --dry-run --delete --itemize-changes /srv/projects/ /snapshots/2026-07-11/
The command must print nothing and exit with status 0. An itemized line identifies a content, path, or archived-attribute mismatch; --delete reports destination-only paths without removing them because --dry-run is active.
The live source may change after this point. Run later restore checks against the completed snapshot rather than comparing them with the changing source.
$ stat --format='%i %h %n' /snapshots/2026-07-10/policy.txt /snapshots/2026-07-11/policy.txt 366911 2 /snapshots/2026-07-10/policy.txt 366911 2 /snapshots/2026-07-11/policy.txt
The matching inode number and link count of 2 show that the two paths share one unchanged file on disk.
$ mkdir /tmp/rsync-restore-test
$ rsync --archive --itemize-changes /snapshots/2026-07-11/ /tmp/rsync-restore-test/ .d..t...... ./ >f+++++++++ policy.txt >f+++++++++ workload.log cd+++++++++ releases/ >f+++++++++ releases/current.txt >f+++++++++ releases/release-notes.txt
$ rsync --archive --checksum --dry-run --delete --itemize-changes /snapshots/2026-07-11/ /tmp/rsync-restore-test/
No output with status 0 confirms that every regular file matches by checksum, the archived attributes match, and neither tree has an extra path.
$ rm -r /tmp/rsync-restore-test
$ cat /snapshots/2026-07-11/releases/current.txt release-2026.07.11