For some older projects we’re still deploying code with rsync, its not perfect but it works. Temporary files are excluded using --exclude-from=exclude.txt
, this is great until the parent folder of an excluded file needs to be deleted.
For example, say your file structure looks like this:

And you remove the data/cache directory completely:
$ rm -rf data/cache
$ rsync --exclude="*.tmp" --exclude="data/logs/*.log"
You’re going to get the error “cannot delete non-empty directory: data/cache” because data/cache/config.tmp has not been removed by rsync.
Unfortunately --delete-excluded
won’t work because you don’t want to delete the log files and other .tmp files created on the destination.
Fortunately rsync has filters (which include/exclude are shorthand for anyway), with a mode called “perishable”. Perishable excludes behave exactly as required, files are excluded from sync, and aren’t deleted on the destination unless they are in a directory that no longer exists.
The syntax for excluding files becomes:
$ rsync --filter="-,p *.tmp" --filter="-,p data/logs/"
The “-” signifies the filter is to exclude matches. The “p” makes the exclude perishable.
If, like us, you were using --exclude-from
for the patterns, you can with this syntax:
$ rsync --filter="merge,p- /home/ideal/scripts/push/excludes/lenta.txt"
This information is all available in the rsync docs under “FILTER RULES”, it just took me a while to figure out the right syntax. Hopefully these snippets help someone out.