Skip to content

/commands/rsync/rsync-exclude

rsync --exclude: skip files and directories when syncing

The commands on this page have not been executed by our verification runner yet.updated
tool
rsync
versions
rsync 3.x
os
linux, macos

rsync -a --exclude='node_modules' --exclude='*.log' src/ dest/ copies src to dest but skips every node_modules directory and every .log file. A pattern without a slash matches a file or directory name at any depth; a pattern starting with / is anchored at the root of the transfer (--exclude='/build' skips only the top-level build); a trailing / matches directories only. Quote patterns so the shell does not expand *. Long lists go in a file: --exclude-from=.rsync-exclude.

Commands

bash
# Skip dependency folders, logs and the Git directory
rsync -av --exclude='node_modules' --exclude='*.log' --exclude='.git' ./app/ /backup/app/

# Patterns from a file, one per line; lines starting with # are comments
rsync -av --exclude-from=.rsync-exclude ./app/ user@server.example.com:/srv/app/

# Only the top-level build directory, not app/src/build
rsync -av --exclude='/build/' ./app/ /backup/app/

# Copy only .jpg files, keeping the directory tree
rsync -av -m --include='*/' --include='*.jpg' --exclude='*' ./photos/ /backup/photos/

An example .rsync-exclude file:

text
# dependencies and build output
node_modules/
dist/
*.log
.env

Pattern rules

PatternMatches
node_modulesAny file or directory named node_modules, at any depth
node_modules/Only directories with that name
*.logAny name ending in .log; * does not cross /
/buildbuild at the root of the transfer only
src/*.tmp.tmp files directly in a directory named src
logs/**Everything below logs, at any depth (** crosses /)
cache/***The cache directory itself and everything in it
--exclude-from=FILERead patterns from FILE, one per line
-C, --cvs-excludeA built-in list of version control and editor files (CVS, .git, *.o, *~ and more)
-FRead rules from .rsync-filter files in each directory

Where "/" anchors

An anchored pattern starts at the root of the transfer, which depends on the source path and its trailing slash, not at the root of the filesystem:

CommandPattern that skips app/build
rsync -a /home/me/app/ /dest--exclude=/build
rsync -a /home/me/app /dest--exclude=/app/build
rsync -a --relative /home/me/app/ /dest--exclude=/home/me/app/build

This is why an exclude that works in one command can stop working after a trailing slash is added or removed. See the page on the rsync trailing slash.

Pitfalls

  • Order matters with includes. Rules are checked in order and the first match wins: --include must come before the --exclude='*' it overrides.
  • An excluded directory hides its contents. --exclude='*' without --include='*/' stops rsync from descending into subdirectories, so nested files you included never match.
  • Unquoted wildcards. --exclude=*.log may be expanded by the shell when a matching file exists in the current directory. Quote it.
  • Paths written as absolute filesystem paths. --exclude=/home/me/app/node_modules does not match unless --relative is used; write the path relative to the transfer root.

Check before syncing

Run the command with -n (dry run) and -i (itemize changes) first, and read the list: an excluded file must not appear in it. The page on rsync --dry-run explains the output. rsync runs on Linux and macOS (macOS ships an older openrsync or rsync 2.6.9 depending on the version; install rsync 3 for *** and other newer features); on Windows use it inside WSL or Cygwin.

FAQ

How do I exclude several directories at once?

Repeat the option, --exclude=node_modules --exclude=.git --exclude=dist, or put one pattern per line in a file and pass --exclude-from=FILE. Bash brace expansion, --exclude={node_modules,.git}, also works but only in shells that support it.

Why is my excluded file still deleted on the destination with --delete?

It is not: excluded files are protected from deletion by default. They are deleted only with --delete-excluded. If a file disappears, check the pattern with --dry-run and -i to see what rsync matches.

How do I copy only some file types?

Include directories and the wanted files, then exclude the rest, in this order: --include='*/' --include='*.jpg' --exclude='*'. Add -m (--prune-empty-dirs) to skip directories that end up empty.

Sources