137

Rsync 包含一个--cvs-exclude“以与 CVS 相同的方式忽略文件”的漂亮选项,但 CVS 已过时多年。有没有办法让它也排除现代版本控制系统(Git、Mercurial、Subversion)会忽略的文件?

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

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

我可以为磁盘上任何 、 或 属性中提到的所有文件名和模式提供完整的绝对路径列表.gitignore.hgignore但这svn:ignore将是一个巨大的列表,必须由某种脚本生成。

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

更新--filter=':- .gitignore'正如 LordJavac 所建议的那样,Git--filter=:C似乎与 CVS 一样适用,至少在我找到的示例中,尽管尚不清楚语法是否完全匹配。--filter=':- .hgignore'对于 Mercurial 来说效果不佳;例如,.hgignore包含类似^target$(Git 的 Mercurial 等效项/target/)的行不被 rsync 识别为正则表达式。Subversion 似乎没有任何效果,您必须解析.svn/dir-prop-base1.6 或更早版本的工作副本,并沮丧地举手寻找 1.7 或更高版本的工作副本。

4

13 回答 13

146

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

于 2013-03-12T22:48:15.263 回答
13

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

选项:

  • --exclude-standard考虑所有.gitignore文件。
  • -o不要忽略未分级的更改。
  • -i只输出被忽略的文件。
  • --directory仅在忽略整个目录时才输出目录路径。

我唯一可以忽略的是.git

rsync -azP --exclude=.git --exclude=`git -C <SRC> ls-files --exclude-standard -oi --directory` <SRC> <DEST>
于 2016-03-10T21:21:30.063 回答
13

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

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

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

必须.gitignore从源中复制文件。如果您将使用 LordJavac 的命令,.gitignore则不会被复制。如果您在目标文件夹中创建一个文件,该文件应该被 忽略.gitignore,尽管.gitignore. 这是因为您在目标中没有.gitignore-files。但是如果你会有这些文件,那么这些文件中描述的文件.gitignore不会被删除,它们会被忽略,只是意料之中的。

于 2020-08-16T15:13:40.380 回答
9

怎么样rsync --exclude-from='path/.gitignore' --exclude-from='path/myignore.txt' source destination
它对我有用。
我相信你也可以有更多的--exclude-from参数。

于 2015-09-30T06:09:54.627 回答
8

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是强制性的,而不是 --exclude 因为排除列表的可能情况不会被解析为参数。从需要文件中排除并且不能使用管道。

当前的解决方案将排除文件保存在 .git 文件夹中,以确保它git status在保持独立的同时不会受到影响。如果你愿意,欢迎使用 /tmp。

于 2018-04-27T09:41:49.717 回答
3

对于mercurial,您可以使用

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

收集由于.hgignore限制而不受 mercurial 控制的文件列表,然后运行

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

rsync 除了忽略的文件之外的所有文件。注意rsync 中的-m标志,它将从同步中排除空目录,因为hg status -i只会列出排除的文件,而不是目录

于 2016-12-27T21:00:18.997 回答
3

尝试这个:

rsync -azP --delete --filter=":- .gitignore" <SRC> <DEST>

它可以将所有文件复制到远程目录,不包括“.gitignore”中的文件,并删除不在当前目录中的文件。

于 2018-07-18T09:24:54.760 回答
2

我有许多非常大的.gitignore文件,没有一个“纯 rsync”解决方案对我有用。我编写了这个rsync 包装脚本,它完全遵守.gitignore规则(包括!- 样式的异常和.gitignore子目录中的文件),并且对我来说就像一个魅力。

于 2015-09-23T22:01:33.690 回答
1

查看 rsync(1) 中的 MERGE-FILES FILTER RULES 部分。

看起来可以创建一个 rsync --filter 规则,该规则将包含 .gitignore 文件作为遍历目录结构。

于 2012-12-09T11:46:19.340 回答
1

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

$HOME/.cvsignore 中列出的文件将添加到列表中,并且 CVSIGNORE 环境变量中列出的所有文件

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

.git/
.sass-cache/

排除 .git 和Sass生成的文件。

于 2013-07-15T13:49:42.637 回答
1

备择方案:

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

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

(rsync 只能部分理解 .gitignore)

于 2019-06-06T14:45:03.310 回答
0

简短的回答

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

参数含义:

-r: 递归

--info=...: 显示进度

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

于 2020-01-25T20:11:47.377 回答
0

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返回换行符分隔的路径,这也有效。如果您有文件名中带有空格的版本化文件,则可能无法正常工作。

于 2016-11-02T16:02:38.477 回答