rsync --dry-run: How to See Deletions and Overwrites Before Synchronization
A practical guide to safely checking rsync: read the itemized output, spot deleted files, and detect content changes when size and timestamp are identical.

In this article
Перед синхронизацией с удалением сначала выполните тот же rsync с --dry-run и --itemize-changes. Проверьте направление, завершающий слеш у источника и каждую строку *deleting. Только после этого решайте, допустим ли реальный запуск. Сухой прогон не заменяет резервную копию и проверку приложения.
Сначала проверим на маленькой модели. В источнике и назначении есть одинаковый файл, файл с другой длиной, новый и лишний файлы. Ещё один файл имеет разное содержимое, но одинаковые размер и время изменения — именно он показывает границу обычной быстрой проверки rsync.
Входные условия и границы
Linux с rsync 3.2.7, protocol 31; локальная модель проверена 17 октября 2026 года.
Источник и назначение — отдельные временные каталоги. Рабочие файлы, службы и сеть не использовались.
Ключ --delete включён намеренно: материал показывает, как увидеть удаление до реального запуска.
Удалённый SSH-сервер, ACL, extended attributes, sparse-файлы и открытые базы данных в стенде не проверялись.
rsync --version
В проверенной среде команда показала rsync 3.2.7 и protocol version 31. На удалённой синхронизации версию нужно проверить с обеих сторон: набор опций и формат диагностики зависят от фактически запущенных бинарных файлов.
Почему завершающий слеш меняет результат
Источник source/ означает «содержимое каталога source», а source без завершающего слеша — сам каталог source. При неверном варианте файлы могут оказаться на дополнительном уровне вложенности. Dry-run покажет имена, но заметить ошибку можно только если заранее записано ожидаемое дерево назначения.
rsync -ani --delete /path/source/ /path/destination/
Здесь -a включает архивный режим, -n запрещает изменения, -i выводит краткое описание каждого действия, а --delete добавляет в план удаление объектов назначения, которых нет в источнике. Команда остаётся опасной после удаления -n, поэтому направление и фильтры проверяют до запуска.
Семантика опций и завершающего слеша сверена с официальным руководством rsync. Документация отдельно предупреждает сначала использовать dry-run перед --delete.

Что показал обычный dry-run
rsync -ani --delete "$src/" "$dst/"
*deleting stale.txt
>f.s....... changed-size.txt
>f+++++++++ new.txt
Назначение осталось неизменным: список имён и SHA-256 каждого файла до и после dry-run совпал. Но changed-hidden.txt в выводе отсутствует. По умолчанию rsync использует быструю проверку размера и времени изменения; одинаковые значения могут скрыть отличающееся содержимое.
Строка | Что наблюдаем | Что проверить |
|---|---|---|
*deleting stale.txt | Файл есть только в назначении и попал в план удаления | Нужен ли он, не защищён ли фильтром и верно ли выбрано направление |
>f+++++++++ new.txt | В назначении будет создан новый обычный файл | Ожидаемы ли путь и уровень вложенности |
>f.s....... changed-size.txt | Файл будет передан; размер отличается | Не является ли изменение неполной записью или случайным источником |
Нет строки для changed-hidden.txt | Быстрая проверка сочла файл неизменным | Нужна ли проверка содержимого через --checksum |
Когда нужен --checksum
Если размер и mtime нельзя считать надёжным признаком — например, файлы восстановлены с сохранением времени или сформированы одинаковой длины — добавьте --checksum. Тогда rsync читает содержимое файлов с обеих сторон для предварительного сравнения. Это повышает дисковую нагрузку и время проверки, особенно на большом дереве.
rsync -anic --delete "$src/" "$dst/"
*deleting stale.txt
>fc........ changed-hidden.txt
>fcs....... changed-size.txt
>f+++++++++ new.txt
В строке >fc........ буква c означает изменение контрольной суммы содержимого. changed-hidden.txt обнаружен, хотя длина и mtime совпадали. Это не доказывает согласованность базы данных и файлов приложения: rsync сравнивает доступные объекты, а не бизнес-транзакции.
Воспроизводимый тест
Сценарий создал два временных каталога. Для changed-hidden.txt в источнике записано BBBB, в назначении — AAAA; оба файла имеют 5 байт и одинаковый mtime. До реального запуска хэши назначения сохранены и повторно рассчитаны после обычного dry-run.
printf 'BBBB\n' >"$src/changed-hidden.txt"
printf 'AAAA\n' >"$dst/changed-hidden.txt"
touch -t 202601010101 "$src/changed-hidden.txt" "$dst/changed-hidden.txt"
Обычный dry-run завершился с кодом 0 и не изменил ни один файл, но не показал скрытое расхождение. Dry-run с --checksum показал четыре действия. Затем в той же изолированной модели выполнен реальный rsync с теми же опциями без -n.
rsync -aic --delete "$src/" "$dst/"
Itemized-output реального запуска дословно совпал с checksum dry-run. changed-size.txt и changed-hidden.txt обновились, new.txt появился, stale.txt исчез. Повторный dry-run с --checksum вернул пустой вывод и код 0.
rsync -anic --delete "$src/" "$dst/"
printf 'exit=%s\n' "$?"
exit=0
Этап | Код | Наблюдение | Изменение назначения |
|---|---|---|---|
Обычный dry-run | 0 | Три действия; скрытое изменение не найдено | Нет |
Dry-run с --checksum | 0 | Четыре действия, включая changed-hidden.txt | Нет |
Реальный запуск | 0 | Вывод совпал с checksum dry-run | Да, только в учебном каталоге |
Финальный checksum dry-run | 0 | Пустой вывод | Нет |

Порядок перед рабочей синхронизацией
Зафиксируйте источник, назначение, направление передачи, пользователя и версии rsync на обеих сторонах.
Проверьте завершающий слеш и ожидаемый уровень вложенности на небольшом известном поддереве.
Выполните dry-run с теми же include, exclude и delete-опциями, которые планируются в реальном запуске.
Отдельно разберите каждую строку *deleting; при сомнении остановитесь и сохраните нужные данные независимым способом.
Решите, достаточны ли размер и mtime. Если нет, оцените нагрузку и выполните dry-run с --checksum.
Перед изменением обеспечьте согласованную резервную копию или другой проверенный способ отката.
Выполните реальный запуск без -n в согласованное окно и сохраните код завершения и itemized-output.
Повторите dry-run и проверьте не только пустой план rsync, но и работоспособность приложения и целостность данных.
Если задача относится к резервной копии интернет-магазина, отдельно проверьте RPO, RTO и тестовое восстановление: пустой вывод rsync не доказывает, что копия пригодна для восстановления.
Где dry-run не даёт гарантии
Источник или назначение изменились между предварительным и реальным запуском.
Реальный запуск столкнулся с ошибкой чтения, записи, места, сети или прав, которой не было во время проверки.
Открытая база данных записывалась во время копирования, поэтому отдельные файлы относятся к разным моментам.
Фильтры защищают или исключают объект иначе, чем ожидалось; особенно внимательно проверяют правила вместе с --delete.
Нужны ACL, extended attributes, hard links, sparse-файлы или владельцы, но соответствующие опции не включены и не проверены.
По одному коду 0 выводить рано. Приёмка состоит из трёх независимых признаков: предварительный план понятен, фактический запуск завершился без необъяснённых действий, а результат проверен исходной операцией приложения или восстановлением.
Before synchronizing with deletion, first run the same rsync command with --dry-run and --itemize-changes. Check the direction, the trailing slash on the source, and every line starting with *deleting. Only then decide if a real run is acceptable. A dry run does not replace a backup or application verification.
First, we test on a small model. The source and destination contain an identical file, a file with a different length, a new file, and an extra file. Another file has different content but the same size and modification time—this is exactly the case that reveals the limit of a standard fast rsync check.
Input Conditions and Boundaries
Linux with rsync 3.2.7, protocol 31; local model verified on October 17, 2026.
Source and destination are separate temporary directories. Working files, services, and network were not used.
The --delete flag was intentionally enabled: the material demonstrates how to view deletions before the actual run.
Remote SSH server, ACLs, extended attributes, sparse files, and open databases were not verified in the staging environment.
rsync --version
In the tested environment, the command showed rsync version 3.2.7 and protocol version 31. For remote synchronization, check the version on both sides: the set of options and the diagnostic format depend on the actual binary files running.
Why a Trailing Slash Changes the Result
The source source/ denotes the contents of the source directory, while source without a trailing slash denotes the source directory itself. With the wrong variant, files may end up at an additional nesting level. A dry-run will show the names, but the error can only be spotted if the expected destination tree has been recorded in advance.
rsync -ani --delete /path/source/ /path/destination/
Here, -a enables archive mode, -n prohibits changes, -i outputs a brief description of each action, and --delete adds removal of destination objects that do not exist in the source to the plan. The command remains dangerous after removing -n, so the direction and filters must be checked before running.
The semantics of options and the trailing slash were cross-checked against the official rsync guide. The documentation separately warns to use dry-run before --delete.

What a standard dry-run showed
rsync -ani --delete "$src/" "$dst/"
*deleting stale.txt
>f.s....... changed-size.txt
>f+++++++++ new.txt
The destination remained unchanged: the list of names and the SHA-256 hash of each file before and after the dry-run matched. However, changed-hidden.txt is absent from the output. By default, rsync uses a fast size and modification time check; identical values can hide differing content.
Line | What we observe | What to check |
|---|---|---|
*deleting stale.txt | File exists only in the destination and is included in the deletion plan | Is it needed, is it protected by a filter, and was the direction selected correctly |
>f+++++++++ new.txt | A new regular file will be created in the destination | Are the path and nesting level expected? |
>f.s....... changed-size.txt | The file will be transferred; the size differs | Is the change an incomplete write or from a random source? |
No line for changed-hidden.txt | A quick check considered the file unchanged | Is content verification via --checksum necessary? |
When --checksum is needed
If file size and mtime cannot be considered reliable indicators—for example, if files are restored with their original timestamps or generated with identical lengths—add --checksum. In this case, rsync reads the contents of files on both sides for a preliminary comparison. This increases disk I/O and verification time, especially on large directory trees.
rsync -anic --delete "$src/" "$dst/"
*deleting stale.txt
>fc........ changed-hidden.txt
>fcs....... changed-size.txt
>f+++++++++ new.txt
In the >fc........ string, the letter c indicates a change in the content checksum. changed-hidden.txt was detected even though its length and mtime matched. This does not prove consistency between the database and application files: rsync compares available objects, not business transactions.
Reproducible test
The scenario created two temporary directories. For changed-hidden.txt, the source contained BBBB and the destination AAAA; both files were 5 bytes long with identical mtime. Before the actual run, the destination hashes were saved and recalculated after a standard dry-run.
printf 'BBBB\n' >"$src/changed-hidden.txt"
printf 'AAAA\n' >"$dst/changed-hidden.txt"
touch -t 202601010101 "$src/changed-hidden.txt" "$dst/changed-hidden.txt"
A standard dry-run completed with exit code 0 and did not modify any files, yet it failed to reveal the hidden discrepancy. A dry-run with --checksum showed four actions. Then, a real rsync was executed in the same isolated model using the same options without -n.
rsync -aic --delete "$src/" "$dst/"
The itemized output of the actual run matched the checksum dry-run verbatim. changed-size.txt and changed-hidden.txt were updated, new.txt appeared, and stale.txt disappeared. A subsequent dry-run with --checksum returned empty output and exit code 0.
rsync -anic --delete "$src/" "$dst/"
printf 'exit=%s\n' "$?"
exit=0
Stage | Code | Observation | Destination change |
|---|---|---|---|
Standard dry-run | 0 | Three actions; hidden change not found | No |
Dry-run with --checksum | 0 | Four actions, including changed-hidden.txt | No |
Actual run | 0 | Output matched the checksum dry-run | Yes, only in the test catalog |
Final checksum dry-run | 0 | Empty output | No |

Order before working synchronization
Record the source, destination, transfer direction, user, and rsync versions on both sides.
Check the trailing slash and expected nesting level on a small, known subtree.
Run the dry-run with the same include, exclude, and delete options planned for the actual run.
Review each line of *deleting; if in doubt, stop and save the necessary data independently.
Decide whether size and mtime are sufficient. If not, assess the load and run a dry-run with --checksum.
Before making changes, ensure a consistent backup or another verified rollback method is in place.
Execute the actual run without -n during a coordinated window and save the exit code and itemized output.
Repeat the dry-run and verify not only the empty rsync plan but also application functionality and data integrity.
If the task involves an online store backup, separately verify RPO, RTO, and test restoration: an empty rsync output does not prove the backup is suitable for recovery.
Where dry-run offers no guarantee
The source or destination changed between the preliminary and actual runs.
The actual run encountered a read, write, space, network, or permission error that was not present during the check.
The open database was being written during the copy, so individual files correspond to different points in time.
Filters protect or exclude objects differently than expected; rules should be checked carefully, especially when used together with --delete.
ACLs, extended attributes, hard links, sparse files, or owners are required, but the corresponding options are not enabled or verified.
Do not consider code 0 an early success. Acceptance consists of three independent indicators: the preliminary plan is clear, the actual run completed without unexplained actions, and the result is verified by the application's original operation or restoration.





Discussion 0
Share your experience and ask questions. Comments without links appear after editorial review.
No comments yet. Start the discussion.