記事

Last Modified:

ファイルリストをrsyncするフィルタ #Shell #Git

git ls-files のファイルリストだけを rsync で転送したい。

この辺りを見て、いちいち全ディレクトリ階層をがんばって書いている人もいるかもしれない。(実は自分もそうだ)

解決

結論から言うと --filter='+ */'--filter='- *'--prune-empty-dirs を組み合わせるだけでOK。

{ git ls-files | sed 's@^@+ /@' ; printf '+ */\n- *\n' ; } | \
    rsync $OPTIONS --prune-empty-dirs --filter='. -' $SRCDIR $DESTDIR

この方法は、 man rsync(1) にずばり書いてある。

This fails because the parent directory "some" is excluded by the '' rule, so rsync never visits any of the files in the "some" or "some/path" directo- ries. One solution is to ask for all directories in the hierarchy to be included by using a single rule: "+ /" (put it somewhere before the "- *" rule), and perhaps use the --prune-empty-dirs option. Another solution is to add specific include rules for all the parent dirs that need to be visited. For instance, this set of rules works fine:

の"One solution"のところ。

+ */ で全ディレクトリが転送されてしまうけれど、 --prune-empty-dirs によってファイルが転送されないディレクトリは転送されなくなる。 これはGit自身の挙動と非常に相性が良い。

--filter 自身が . - となっていて標準入力から読み込んでいるのは、ファイルリストを渡すのでコマンドラインが長過ぎてしまうのを防ぐためです。

他にGit管理下に無いファイルを追加したい場合は、 - * より前( --filter オプションより前に --include するか、フィルターの適切な場所)に含める必要があります。