Skip to main content

Exclude and Include Patterns

Rsync's filter system lets you precisely control which files are transferred. Without filters, rsync copies everything — including cache directories, log files, temporary uploads, and development artifacts that have no place in a backup or deployment.

Basic Exclude

Exclude a Single Directory

rsync -av --exclude='cache/' /var/www/html/ /backup/www/

Exclude Multiple Patterns

rsync -av \
--exclude='cache/' \
--exclude='*.log' \
--exclude='*.tmp' \
--exclude='.git/' \
--exclude='node_modules/' \
/var/www/html/ /backup/www/

Exclude by File Extension

# Skip all log files and temporary files
rsync -av --exclude='*.log' --exclude='*.tmp' --exclude='*.swp' \
/var/www/ /backup/

Basic Include

Include Only Specific File Types

When you want to sync only certain files, use include + exclude together:

# Sync only PHP files
rsync -av \
--include='*/' \
--include='*.php' \
--exclude='*' \
/var/www/html/ /backup/php-only/
Order Matters

The --include='*/' must come first — it tells rsync to traverse all directories. Without it, rsync won't descend into subdirectories to find matching files. The final --exclude='*' blocks everything not explicitly included.

Include Multiple File Types

# Sync only code files
rsync -av \
--include='*/' \
--include='*.php' \
--include='*.js' \
--include='*.css' \
--include='*.html' \
--exclude='*' \
/var/www/html/ /backup/code-only/

Pattern Matching Rules

PatternMatchesExample
*.logAny file ending in .log at any deptherror.log, app/debug.log
cache/Any directory named cache at any depthwp-content/cache/, app/cache/
/cache/Only cache/ at the root of the transferRoot cache/ only, not sub/cache/
*.jpgAll JPEG files anywhereAll .jpg files
backup*Files/dirs starting with backupbackup.sql, backup-2024/
**/*.logAny .log file in any subdirectorySame as *.log (rsync default)

Anchored vs Unanchored Patterns

# Unanchored — matches 'cache/' anywhere in the tree
--exclude='cache/'
# Matches: /var/www/html/wp-content/cache/
# Matches: /var/www/html/app/tmp/cache/

# Anchored (leading /) — matches only at the transfer root
--exclude='/cache/'
# Matches: /var/www/html/cache/ (root level only)
# Skips: /var/www/html/wp-content/cache/

Using Exclude Files

For complex projects, put rules in a file instead of the command line:

rsync-exclude.txt
# Development artifacts
.git/
node_modules/
.env
*.map

# Caches and temporary files
cache/
tmp/
*.tmp
*.log
*.swp

# OS junk
.DS_Store
Thumbs.db

# Build artifacts
dist/
build/
vendor/
rsync -av --exclude-from='rsync-exclude.txt' \
/var/www/html/ user@backup:/backups/www/
tip

Store rsync-exclude.txt in your project root or /etc/rsync/. This makes filters version-controlled and reusable across team members and servers.

Using .gitignore as Filter

If your project already has a .gitignore, you can use it directly:

rsync -av --filter=':- .gitignore' \
/var/www/html/ user@server:/deploy/www/

This reads each directory's .gitignore file and applies those rules. Perfect for deploying from a Git repository without sending development artifacts.

Common Filter Recipes

Web Application Deployment

rsync -avz \
--exclude='.git/' \
--exclude='node_modules/' \
--exclude='.env' \
--exclude='*.map' \
--exclude='tests/' \
--exclude='*.test.js' \
--exclude='*.spec.js' \
/var/www/app/ user@production:/var/www/app/

PHP Application Backup (WordPress Example)

rsync -avz \
--exclude='wp-content/cache/' \
--exclude='storage/framework/cache/' \
--exclude='var/cache/' \
--exclude='*.log' \
--exclude='.env' \
/var/www/html/ /backup/app-files/

Config Files Only

rsync -av \
--include='*/' \
--include='*.conf' \
--include='*.cfg' \
--include='*.ini' \
--include='*.yml' \
--include='*.yaml' \
--include='*.toml' \
--exclude='*' \
/etc/ /backup/configs/

Sync Everything Except Large Media

rsync -avz \
--exclude='*.mp4' \
--exclude='*.mov' \
--exclude='*.avi' \
--exclude='*.zip' \
--exclude='*.tar.gz' \
/var/www/html/ user@remote:/backup/

Testing Patterns with Dry Run

Always test your patterns before running on production:

# Preview what will be included/excluded
rsync -av --dry-run \
--exclude='cache/' \
--exclude='*.log' \
/var/www/html/ /backup/www/

# See detailed per-file decisions
rsync -av --dry-run --itemize-changes \
--exclude='cache/' \
/var/www/html/ /backup/www/

Common Pitfalls

PitfallWhat HappensFix
--exclude before --includeFiles excluded before include rule is evaluatedPut --include rules first
Missing --include='*/'Rsync doesn't traverse subdirectoriesAlways include */ when filtering by file type
No trailing / on directory excludesMay match files with similar namesUse cache/ not cache for directories
Anchored pattern when you want recursiveOnly matches at root levelRemove leading / for recursive matching
Not testing with --dry-runWrong files excluded/included in productionAlways preview first
Shell expansion of *Shell expands * before rsync sees itAlways quote patterns: '*.log' not *.log

Quick Reference

# Exclude a directory
rsync -av --exclude='cache/' /src/ /dest/

# Exclude multiple patterns
rsync -av --exclude='*.log' --exclude='*.tmp' /src/ /dest/

# Include only PHP files
rsync -av --include='*/' --include='*.php' --exclude='*' /src/ /dest/

# Use exclude file
rsync -av --exclude-from='rsync-exclude.txt' /src/ /dest/

# Use .gitignore rules
rsync -av --filter=':- .gitignore' /src/ /dest/

# Test patterns before running
rsync -av --dry-run --exclude='cache/' /src/ /dest/

What's Next