rsync Trailing Slash: Source Directory Semantics
A trailing slash on the rsync source copies the contents of the directory; without it, rsync copies the directory itself into the destination.
This one byte changes where your files land. Getting it wrong in CI either nests dist/ inside the target or, with --delete, wipes the wrong tree.
What it does
rsync treats the trailing slash on the source specially. "dist/" means "copy what is inside dist into the destination". "dist" (no slash) means "copy the directory dist itself into the destination", creating destination/dist/... A trailing slash on the destination has no such effect; it is cosmetic.
Common usage
# Contents of dist go directly into /var/www/app/
rsync -av dist/ user@host:/var/www/app/
# The dist directory itself lands at /var/www/app/dist/
rsync -av dist user@host:/var/www/app/Behavior summary
| Command | Result on destination |
|---|---|
| rsync -a src/ dst/ | dst/ gets the files that were inside src/ |
| rsync -a src dst/ | dst/src/ is created with src inside it |
| rsync -a src/ dst | Same as src/ dst/ (dest slash is cosmetic) |
In CI
Standardize on the trailing slash for deploys: "rsync -a dist/ host:/var/www/app/". Combined with --delete, the no-slash form is dangerous: "rsync --delete dist host:/var/www" copies dist into /var/www and deletes everything else in /var/www that is not named dist.
Common errors in CI
The usual symptom is a nested path like /var/www/app/dist/index.html when you expected /var/www/app/index.html. There is no error message; the deploy "succeeds" but serves a 404. Fix by adding the trailing slash to the source.