Rsync 根据. gitignore & . hgignore & svn 排除: 忽略 like —— filter = : C

Rsync 包含一个漂亮的选项 --cvs-exclude,可以“像 CVS 那样忽略文件”,但是 CVS 已经过时多年了。有没有办法使它也排除那些现代版本控制系统(Git、 Mercurial、 Subversion)会忽略的文件?

例如,我从 GitHub 签出了许多 Maven 项目。通常它们至少包含一个 .gitignore列表 target,这是默认的 Maven 构建目录(可能出现在顶级或子模块中)。由于这些目录的内容完全是一次性的,而且它们可能比源代码大得多,因此我希望在使用 rsync 进行备份时将它们排除在外。

当然,我可以显式地使用 --exclude=target/,但是这样会意外地抑制不相关的目录,而这些目录恰好被命名为 target,并且不应该被忽略。

我可以为磁盘上任何 .gitignore.hgignoresvn:ignore属性中提到的所有文件名和模式提供一个完整的绝对路径列表,但这将是一个庞大的列表,必须通过某种脚本才能产生。

由于 rsync 除了 CVS 之外没有对 VCS 签出的内置支持,那么有没有什么好的技巧可以提供给它它们的忽略模式呢?或者某种回调系统,通过它可以询问用户脚本是否应该包含给定的文件/目录?

更新 : 根据 LordJavac 的建议,--filter=':- .gitignore'对 Git 的作用似乎和 --filter=:C对 CVS 的作用一样好,至少在我发现的示例中是这样的,尽管还不清楚语法是否完全匹配。对于 Mercurial,--filter=':- .hgignore'不能很好地工作; 例如,包含类似于 ^target$(Mercurial 等效于 Git /target/)的代码行的 .hgignore不能被 rsync 识别为正则表达式。对于 Subversion,似乎没有什么是可行的,因为您必须为1.6或更早的工作副本解析 .svn/dir-prop-base,并为1.7或更高的工作副本感到沮丧。

38776 次浏览

查看 rsync (1)中的 Merge-Files FILTER RULES 部分。

似乎可以创建一个 rsync —— filter 规则,其中包括。在遍历目录结构时忽略文件。

正如 Luksan 所提到的,您可以通过将 --filter切换到 rsync来实现这一点。我用 --filter=':- .gitignore'实现了这一点(之前有一个空格)。“ gitignore”) ,它告诉 rsync.gitignore文件进行目录合并,并让它们按 git 的规则排除。如果您有一个全局忽略文件,您可能还想添加它。为了便于使用,我为 rsync创建了一个别名,其中包含了过滤器。

根据 rsync手册页,除了标准的文件模式列表之外:

$HOME/. CVSIGNORE 中列出的文件被添加到列表中,而 CVSIGNORE 环境变量中列出的任何文件也被添加到列表中

因此,我的 $HOME/. cvsignore 文件如下所示:

.git/
.sass-cache/

排除. git 和由 无礼生成的文件。

我有许多非常大的 .gitignore文件,没有一个“纯 rsync”解决方案适合我。我写了这个 Rsync 包装脚本,它充分尊重 .gitignore规则(包括 !风格的异常和子目录中的 .gitignore文件) ,并已经像一个魅力为我工作。

rsync --exclude-from='path/.gitignore' --exclude-from='path/myignore.txt' source destination呢?
这招对我很管用。
我相信你也可以有更多的 --exclude-from参数。

可以使用 git ls-files构建存储库的 .gitignore文件排除在外的文件列表。 Https://git-scm.com/docs/git-ls-files

选择:

  • 考虑所有 .gitignore文件。
  • 不要忽略非阶段性更改。
  • 只输出被忽略的文件。
  • 只有在忽略整个目录时才输出目录路径。

我唯一能忽略的就是 .git

rsync -azP --exclude=.git --exclude=`git -C <SRC> ls-files --exclude-standard -oi --directory` <SRC> <DEST>

您可以使用 git ls-files来选择要 rsync 的每个文件,而不是创建排除过滤器:

#!/usr/bin/env bash


if [[ ! $# -eq 2 ]] ; then
echo "Usage: $(basename $0) <local source> <rsync destination>"
exit 1
fi


cd $1
versioned=$(git ls-files --exclude-standard)
rsync --verbose --links --times --relative --protect-args ${versioned} $2

即使 git ls-files返回换行分隔的路径,这种方法仍然有效。如果文件名中有空格的版本化文件,那么可能无法工作。

对于 反复无常,您可以使用

hg status -i | sed 's/^I //' > /tmp/tmpfile.txt

收集由于 。 hgignore限制而不受汞控制的文件列表 然后逃跑

rsync -avm --exclude-from=/tmp/tmpfile.txt --delete source_dir/ target_dir/

同步所有文件,忽略的除外。 注意,rsync 中的 标志将排除空目录进行同步,因为 HG 状态-我只会列出被排除的文件,而不会列出 dir 文件

2018年解决方案 确认

rsync -ah --delete
--include .git --exclude-from="$(git -C SRC ls-files \
--exclude-standard -oi --directory >.git/ignores.tmp && \
echo .git/ignores.tmp')" \
SRC DST

详细信息: --exclude-from是强制的,而不是排除的,因为排除列表可能不会被解析为参数。“排除”需要一个文件,不能使用管道。

当前解决方案将排除文件保存在。Git 文件夹,以确保它不会影响 git status,同时保持其自包含。如果需要,欢迎使用/tmp。

试试这个:

Rsync-azP —— delete —— filter = “ :-. gitignore”< SRC > < DEST >

它可以将所有文件复制到远程目录,除了“ . gitignore”中的文件,还可以删除不在你工作目录中的文件。

备选方案:

git ls-files -zi --exclude-standard |rsync -0 --exclude-from=- ...

git ls-files -zi --exclude-per-directory=".gitignore" |...

(rsync 只能部分理解. gitignore)

长话短说

rsync -r --info=progress2 --filter=':- .gitignore' SOURCE DEST/

参数含义:

递归

显示进展

--filter=...: 按. gitignore 文件中列出的规则排除

经过几个小时的研究,我找到了我所需要的: 将目标文件夹与源文件夹同步(如果在源文件夹中删除了目标文件,也会删除目标文件) ,不要将被 .gitignore但也不要删除目标中的这些文件忽略的文件复制到目标文件:

rsync -vhra /source/project/ /destination/project/ --include='**.gitignore' --exclude='/.git' --filter=':- .gitignore' --delete-after

换句话说,这个命令 完全忽略来自.gitignore 的文件,包括源文件和目标文件。 你可以省略 --exclude='/.git'的一部分,如果想要复制的 .git文件夹了。

您从 必须的复制 .gitignore文件的源。如果您将使用上贾瓦克的命令,.gitignore将不会被复制。 如果您在目标文件夹中创建了一个文件,这个文件应该被 .gitignore忽略,尽管有 .gitignore,这个文件仍将被删除。 这是因为目标文件中没有 .gitignore文件。 但是,如果您将有这些文件,在 .gitignore中描述的文件将不会被删除,它们将被忽略,只是预期。