# rsync Command Builder

> Build an rsync command with excludes and SSH options, and get the trailing-slash rule explained. --delete comes with a warning and dry-run enabled.

Canonical: https://host-tools.com/tools/rsync-command-builder/

---

## What this tool does

It assembles an `rsync` command from options: archive, compression, progress, exclusions, SSH
details, dry run. The output is text you copy. It never runs rsync and never opens an SSH
connection.

## The trailing slash, explained properly

This is the single most misunderstood detail of rsync:

```
rsync -a src/  dest/    # copies the CONTENTS of src into dest
rsync -a src   dest/    # copies the DIRECTORY src inside dest
```

With the slash, `dest` ends up containing what was inside `src`. Without it, `dest` ends up
containing a `src` directory. Both are correct commands; they produce different trees. When a
synchronisation "duplicates the folder" unexpectedly, this is almost always why.

## --delete removes files at the destination

```
rsync -av --delete src/ deploy@example.com:/srv/app/
```

`--delete` makes the destination match the source exactly: anything that exists only at the
destination is deleted. That is what you want for a mirror and a catastrophe for a backup
directory that also holds files you care about.

For that reason the builder enables `--dry-run` as soon as you tick the box. Run that first: it
prints exactly what would be transferred and deleted without touching anything. Only when the list
is what you expect should you uncheck dry run.

## Exclusions

Each `--exclude` takes a pattern, not necessarily a name:

```
--exclude=node_modules     any file or directory called node_modules
--exclude='*.log'          every file ending in .log
--exclude=/cache           only at the root of the transfer
--exclude='**/tmp/**'      anything under a tmp directory
```

Patterns are matched against the path relative to the transfer root, which is why a leading slash
anchors the match and a bare name matches at any depth.

## SSH options

If the remote endpoint uses a non-standard port, rsync needs to be told how to start SSH:

```
rsync -avz -e 'ssh -p 2222' ./app/ deploy@example.com:/srv/app/
```

The remote side is written `user@host:path`. If you omit the user, rsync uses your local username,
which is rarely what you want on a server — be explicit.

## A sane first command

When in doubt, start with `-avz --dry-run`. It tells you what would happen, keeps permissions and
timestamps, and compresses the transfer. Once the dry run looks right, remove `-n` and run it for
real. To build the list of files you want to move in the first place, the
[find command builder](/tools/find-command-builder/) is the natural companion.
