Backups are boring, there is no two ways about that. It's the reason many (most?) of us fail to do them with the regularity warranted. All the more reason to make them easy and near friction less.
If your like me you don't trust a backup solution unless it's so easy to understand you could implement it by yourself in a couple of minutes. Years back, I came across this backup scheme that just used hard link copying and rsync. And that proved all I've needed since.
The hard links make sure to conserve precious disk space and not waste time on writing duplicate copies, the rsync makes sure you get all the changes accumulated since last backup applied on top of your new copy. Easy to understand, efficient and fast.
I know your supposed to keep backups offline and all that. There is best practises and there are pretty good practises. Just like pretty good privacy. Keeping things simple I just plug in my backup drive and call 'backup' wait a few seconds to a minute depending on how old that last backup were and the backup is made and the conscience is clear.
And if the worst happens, plugin your disk and copy from any of the date stamped directories in what ever way makes sense, low stress solution.
This is what I've got in my .bashrc:
function backup {
local backup_root="/media/nthcdr/Drive"
mountpoint -q "$backup_root" || { echo "Drive not mounted"; return 1; }
local todays_backup="$backup_root/$(date +"%Y-%m-%d")"
if [[ -d "$todays_backup" ]]; then
echo "Backup already created!"
return 0
fi
local partial="$backup_root/.backup-in-progress"
local last_backup=$(find "$backup_root" -maxdepth 1 -type d -name '20*' -printf '%f\n' | sort | tail -n 1)
rm -rf "$partial"
if [[ -n "$last_backup" ]]; then
echo "Hardlinking from $last_backup..."
cp -alR "$backup_root/$last_backup/" "$partial/" || { echo "Hardlink copy failed"; return 1; }
else
echo "First backup, creating fresh..."
mkdir -p "$partial"
fi
rsync -avX --delete \
--exclude='.cache' \
--exclude='.local/share/Trash' \
--exclude='node_modules' \
"${HOME:?HOME not set}/" "$partial/"
local rc=$?
if [[ $rc -eq 0 || $rc -eq 24 ]]; then
mv "$partial" "$todays_backup"
else
echo "Backup failed (rsync exit $rc); partial left in $partial"
return 1
fi
}