I often need to use rsync to synchronize a local with a possible remote directory, while ignoring exactly all the files git would ignore because of its .gitignore configuration.

To do so, I am currently listing all files relevant to copy with git and then pipe them to rsync.

cd $source
{ git ls-files -coz --directory --exclude-standard
  printf '.git\0'
} | rsync --info=progress2 -ar0 --files-from=- ./ "$destination"

Leaving the parsing to git itself and then piping the file list to rsync has some advantages I depend on.

  • The patterns to ignore files may be rather complex, also involving negation (!inverse-pattern-to-include), which rsync does not understand in this syntax.
  • .gitignore files placed in subdirectories should also be taken into account. Rsync's merge-dir filter does not entirely allow to remodel this, because for rsync, the order of includes and excludes matters.
  • Global git configuration files, like .git/info/exclude, are also considered.
  • It can even work without a git repository initialized, one just has to point git to an empty repository with --git-dir.
  • Repositories can be quite big, so specifying all the relevant files as rsync --filter --exclude or --include patterns is likely to burst the command line limit or severely slow down rsync. Using --files-from avoids this.

Now I need to improve this code fragment to support rsync's --del flag to remove all files from $destination that are missing from or excluded at $source. Unfortunately, it does not play well with --files-from. Is this possible without again comparing file lists from both ends?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.