A hard-linked rsync snapshot tree can hold many dated restore points while storing unchanged file data only once. Retention is therefore enforced by unlinking expired snapshot directories, not by treating each date as an independent full backup.
Files copied with --link-dest can share one inode across several dates. Removing one dated pathname decreases the inode's link count, while the data remains reachable through retained snapshots until the last hard link is removed.
Pruning is safe only when the backup writer is idle and the removal arguments contain reviewed, completed dates. On Linux, GNU rm can use --one-file-system to skip nested mounts on other filesystems; the newest successful snapshot must stay outside the prune list.
Steps to prune old rsync snapshots:
- Check for an in-progress snapshot before reviewing the prune list.
$ find /snapshots -maxdepth 1 -type d -name '.*.in-progress' -print
If this command prints a path, stop. Wait for the backup writer to finish, or investigate the exact staging directory as an interrupted run before pruning any completed snapshot.
- Confirm that rm provides the cross-filesystem safeguard.
$ rm --help Usage: rm [OPTION]... [FILE]... Remove (unlink) the FILE(s). ##### snipped ##### --one-file-system when removing a hierarchy recursively, skip any directory that is on a file system different from that of the corresponding command line argument ##### snipped #####
If --one-file-system is absent, do not copy the removal command unchanged. Use the deletion tool and filesystem-boundary protection supported by that operating system.
- List the completed snapshots against the retention record.
$ ls -1 /snapshots 2026-07-07 2026-07-08 2026-07-09 2026-07-10 2026-07-11
The sample policy prunes only 2026-07-07 and 2026-07-08. Replace every date with reviewed values from the real retention record, and keep the newest successful restore point out of the removal arguments.
- Check a known unchanged file in an expired snapshot and the newest retained snapshot.
$ stat -c '%i %h %n' /snapshots/2026-07-07/releases/v1.txt /snapshots/2026-07-11/releases/v1.txt 378158 5 /snapshots/2026-07-07/releases/v1.txt 378158 5 /snapshots/2026-07-11/releases/v1.txt
The matching inode and link count of 5 show that five snapshot paths still share this file before pruning.
- Recursive removal is irreversible; remove only the reviewed expired directories.
$ rm -r --one-file-system -- /snapshots/2026-07-07 /snapshots/2026-07-08
--one-file-system skips nested mounts on other filesystems, but it does not protect an incorrectly named directory on the same filesystem. Stop if either explicit path is not an expired snapshot.
- List the snapshot root again and confirm only retained dates remain.
$ ls -1 /snapshots 2026-07-09 2026-07-10 2026-07-11
- Recheck the shared file across the retained dates.
$ stat -c '%i %h %n' /snapshots/2026-07-09/releases/v1.txt /snapshots/2026-07-11/releases/v1.txt 378158 3 /snapshots/2026-07-09/releases/v1.txt 378158 3 /snapshots/2026-07-11/releases/v1.txt
The inode is unchanged and the link count fell from 5 to 3 because two expired pathnames were unlinked.
- Read the file from the newest successful snapshot.
$ cat /snapshots/2026-07-11/releases/v1.txt release 1
The retained restore point still exposes the expected file content after pruning.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.