中文 English

Stop Running rsync Blindly: Preview Differences Before a Safe Incremental Sync

Published: 2026-07-11
rsync Linux macOS Windows 11 WSL Incremental Sync Backup Automation Agent

The short answer

The best rsync habit is not memorizing more switches. It is separating every risky job into two stages: generate a dry-run plan first, review it, and only then perform the real incremental sync. Deletion should be a separate, explicit permission rather than a hidden default.

The common rsync -n -avz --delete --out-format="%n" pattern can list paths that may change, but %n only preserves the name. A safer machine-readable plan uses --itemize-changes together with %i, so each line identifies an addition, update, deletion, or metadata change.

Original cover: inspect differences before synchronizing

Why previewing differences matters

Most sync jobs begin innocently: copy a local directory to a server, move photos to a NAS, or publish build artifacts to another machine. With only a few files, a direct rsync -av feels harmless.

The directory grows, and the command eventually becomes a scheduled job. The destination may now contain valuable files that never existed at the source. Adding --delete changes the meaning from “copy my files” to “make the destination mirror the source and remove everything extra.”

Think of rsync as a moving company. A normal move delivers boxes from the old house. With --delete, the crew may also discard anything in the new house that is absent from the old-house inventory. That can be exactly what a mirror requires, but only when you intend it.

Everyday analogy: dry-run is the moving inventory

Starting from the common script

The original idea is reasonable:

DIFF_FILE="/tmp/rsync_diff.txt"
rsync -n -avz --delete --out-format="%n" $LOCAL_DIR $REMOTE_DIR > "$DIFF_FILE"
grep -v '/$' "$DIFF_FILE" | grep -v 'deleting' > "${DIFF_FILE}_filtered"

It previews the operation and stores the output, but several details become dangerous in automation:

A real isolated experiment

I created temporary source and destination trees containing an unchanged file, a new file, a modified file, destination-only files, and a rename-like pair. No production data was involved.

Real screenshot: source and destination before synchronization

The name-only dry run identified paths, but not whether each ordinary file was new or updated. That is insufficient when another script, monitoring system, or agent must assess the result.

Build a structured plan with itemized changes

The improved preview is:

rsync -ani --delete \
  --out-format="%i|%n%L" \
  "source/" "destination/"

Its output is self-describing:

*deleting photos/old-name.txt
*deleting docs/deleted.txt
>f+++++++|docs/added.txt
>f..t....|docs/modified.txt
>f+++++++|photos/new-name.txt

Real screenshot: additions, updates, and deletions in the dry-run plan

The most useful first-level interpretations are:

You do not need to memorize every position immediately. Read the major action first, then inspect individual attribute positions when a case needs deeper diagnosis.

Mobile-readable itemized-change guide

How rsync performs incremental work

Rsync does not blindly recopy every file. Its normal quick check compares metadata such as size and modification time, then transfers files that require work. Remote rsync operation can also reduce the amount of data crossing the network.

--checksum forces content reads and can detect files whose size and timestamp match despite different data. That is useful for valuable migration validation, but it may be expensive across large trees because both sides must read every file. Use the default quick check for routine mirrors and stronger checks for higher-risk validation.

Keep deletion behind an explicit gate

The downloadable scripts disable deletion by default. To preview mirror deletion on Ubuntu, explicitly opt in:

ALLOW_DELETE=1 ./rsync-safe-sync-ubuntu.sh \
  "/data/source/" \
  "backup-user@<destination>:/data/archive/" \
  --plan

After reviewing every deletion, run --apply. The script generates the plan again, requires the exact word APPLY, performs the sync, and runs one more dry-run. In the isolated experiment, the second preview and recursive diff were empty.

Real screenshot: incremental sync followed by an empty verification run

One-click scripts for three operating systems

All three versions follow the same model: plan first, no deletion by default, explicit confirmation, and post-sync verification.

The same safe workflow on Windows, Ubuntu, and macOS

Windows 11

The PowerShell wrapper uses Windows Subsystem for Linux, avoiding a third-party synchronization service. Install WSL from an elevated terminal if required:

wsl --install
powershell -ExecutionPolicy Bypass -File .\rsync-safe-sync-windows11.ps1 `
  -Source "/mnt/c/Data/source/" `
  -Destination "backup-user@<destination>:/data/archive/" `
  -Mode Plan

Use -Mode Apply only after review, and add -AllowDelete only for intentional mirror semantics.

Ubuntu 26.04

chmod +x rsync-safe-sync-ubuntu.sh
./rsync-safe-sync-ubuntu.sh "/data/source/" \
  "backup-user@<destination>:/data/archive/" --plan

If rsync is missing, the script installs rsync and the OpenSSH client from Ubuntu’s official repositories.

macOS 26

chmod +x rsync-safe-sync-macos.sh
./rsync-safe-sync-macos.sh "$HOME/Documents/source/" \
  "backup-user@<destination>:/data/archive/" --plan

The rsync bundled with macOS may be older, so test the required options in your environment. Upgrade through a trusted package manager only when the job genuinely requires a newer feature.

Human-controlled automation

Human-controlled automation lets the script do repetitive calculation and transfer while a person owns the risky decision:

  1. Confirm source, destination, and trailing-slash semantics.
  2. Generate and save a timestamped plan.
  3. Review every *deleting line separately.
  4. Stop if the number of changes is unexpectedly large.
  5. Run apply mode and provide the explicit confirmation word.
  6. Review the second dry run; use hashes or diff for high-value samples.

It resembles aircraft automation: software handles repetitive control, while a human still evaluates the instruments before a critical action.

Agent-assisted configuration

An agent can prepare configuration, run the preview, classify changes, and summarize risk. It should not silently grant itself permission to delete data. A useful prompt is:

Configure an incremental rsync job using only local tools, SSH, and official OS repositories.
The first run must be dry-run only.
Use itemized, structured output.
Disable deletion by default and list every proposed deletion separately.
Wait for my exact APPLY response before changing files.
After the real sync, run another dry-run and report whether it is empty.
Redact full addresses, account names, hostnames, and secrets from logs.

Agents reduce repetition; they do not own the decision to destroy destination data. A trustworthy workflow remains interruptible, reviewable, and auditable.

A safer minimal comparison script

#!/usr/bin/env bash
set -euo pipefail

: "${LOCAL_DIR:?Set LOCAL_DIR}"
: "${REMOTE_DIR:?Set REMOTE_DIR}"

DIFF_FILE="${DIFF_FILE:-/tmp/rsync-diff-$(date +%Y%m%d-%H%M%S).txt}"
LOCAL_DIR="${LOCAL_DIR%/}/"

rsync --dry-run --archive --itemize-changes \
  --out-format='%i|%n%L' \
  "$LOCAL_DIR" "$REMOTE_DIR" \
  | tee "$DIFF_FILE"

echo "Plan saved to $DIFF_FILE"

If mirror deletion is required, add --delete during review and highlight deletion lines instead of hiding them:

grep '^\*deleting ' "$DIFF_FILE" || true

Q&A

Does dry-run guarantee an identical apply result?

No. Files, permissions, mounts, free space, or network conditions can change between preview and execution. Generate the plan again immediately before apply and verify afterward.

Does --delete remove source files?

It normally removes destination paths that are absent from the source. Reversing source and destination can still be disastrous, so always print and review the direction.

Why does a rename appear as a deletion and an addition?

Rsync primarily evaluates paths and file states. When one path disappears and another appears, an ordinary run may represent the operation as removing the old path and transferring the new one.

Why is the second dry-run not completely empty?

Directory times, permissions, ownership, extended attributes, filesystem capabilities, or rsync versions may differ. Read the itemized attribute positions before adding privileged metadata options merely to make the output blank.

Can this run unattended from cron or Task Scheduler?

Yes, but observe several plan runs first. Unattended jobs should disable deletion by default, use locking and timeouts, retain logs, and alert on failure. Snapshot or version the destination before unattended deletion.

Is rsync itself a backup system?

Rsync is a synchronization tool. A mirror can reproduce accidental deletion or ransomware damage. Important data also needs history: snapshots, versioned backups, offline copies, or immutable storage.

Final safety checklist

A safe incremental sync is not a clever one-liner. It is an explainable, interruptible, and verifiable process. Rsync moves the files efficiently; dry-run exposes the plan; the final risk decision remains yours.