rsync根据.gitignore和.hgignore&svn排除:--ignore像--filter =:C


113

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

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

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

而且我可以提供磁盘上任何.gitignore.hgignoresvn: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或更高版本的工作副本感到沮丧。


11
听起来有点像这将是一个好主意,提交补丁给rsync的,增加了支持的.gitignore,.hgignore等
ThiefMaster

3
@ThiefMaster:我以bugzilla.samba.org/show_bug.cgi?id=9744为起点。
Jesse Glick 2013年

2
只是对其他人的说明,.gitignore必须位于rysnc'd的文件夹层次结构中,而不是位于正在执行命令的目录中
myol 2014年

到底:-是什么意思?结肠是什么意思?什么破折号?
大卫,大卫

check-ignore如果您想使用“生成所有不被忽略的文件列表”选项,Git现在具有一个子命令,可以处理解析各种“忽略”文件的艰苦工作。我在这里的答案详细说明了如何执行此操作。
cjs

Answers:


120

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


一个好的开始,尽管我犹豫“接受”这个答案,因为它只涉及Git。
Jesse Glick 2013年

23
更冗长的版本,该版本也排除了.git文件:--exclude='/.git' --filter="dir-merge,- .gitignore"
VasiliNovikov 2014年

2
我现在有这样的事情:rsync -rvv --exclude='.git*' --exclude='/rsync-to-dev.sh' --filter='dir-merge,-n /.gitignore' $DIR/ development.foobar.com:~/test/..虽然说了[sender] hiding file .gitignore because of pattern .git*,但文件仍然被发送到目的地
rolandow

2
如果您还想使用--deleteoption,请使用以下工作命令行:rsync --delete-after --filter=":e- .gitignore" --filter "- .git/" -v -a ...。这花了我一段时间... e在过滤器中,--delete-after两者都很重要。我建议阅读rsync手册页的“ PER-DIRECTORY RULES AND DELETE”一章。
dbolotin

1
要同步删除以及添加和更新,您只需将其添加--delete-after到@VasiliNovikov的命令版本中即可。(这似乎等效于@dboliton的命令版本,除了@db使用:e,我认为它不会复制.gitignore文件,这不是我想要的。)
Bampfer

10

您可以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>

4
这行不通。它从git子命令中排除第一个文件,然后将其余文件视为SRC列表的一部分。这项工作: rsync -azP --exclude-from="$(git -C SRC ls-files --exclude-standard -oi --directory > /tmp/excludes; echo /tmp/excludes)" SRC DEST
马拉松比赛

2
如果您同时具有排除和包含.gitignore(即以开头的行),则这是唯一有效的方法!。它还会同步--force添加到仓库中的文件,这通常是一件好事。
ostrokach

1
确实,这个答案没有用,所以我最终写了一个
可行的方法

6

怎么样rsync --exclude-from='path/.gitignore' --exclude-from='path/myignore.txt' source destination
它为我工作。
我相信您也可以有更多--exclude-from参数。


3
只要您的.gitignore文件碰巧使用了与兼容的语法,这就会起作用rsync
杰西·格里克

@JesseGlick是正确的,rsync无法解析.gitignore文件,请参阅stackoverflow.com/a/50059607/99834工作区
索林

6

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。


3
如果您要同步一个特定的 Git存储库,则此方法似乎可以正常工作(SRC此处),但不适用于我所说的原始问题,它是一个庞大的目录,具有成千上万个Git存储库作为不同深度的子目录,其中许多具有特质.gitignore的。
杰西·格里克

1
如果您使用的外壳程序支持进程替换(bash,zsh等),则可以使用--exclude-from=<(git -C SRC ls-files --exclude-standard -oi --directory)
Roland W

3

对于水银您可以使用

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

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

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

rsync除被忽略的文件以外的所有文件。注意rsync中的-m标志将排除空目录,因为hg status -i只列出被排除的文件,而不是dirs


2

试试这个:

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

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


1

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

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

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

.git/
.sass-cache/

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


2
相反,我绝对想包含.git/目录,甚至比工作副本还要强。我要排除的是构建产品。
Jesse Glick 2013年

另外,此设置不可移植。它是针对每个用户的,而不是针对每个项目的。
VasiliNovikov

@JesseGlick我支持您保留.git / dirs。Git是分布式SCM,因此备份整个本地存储库非常重要。
JohanBoulé2015年

1 / rsync此答案中引用的手册页中的句子描述了该--cvs-exclude选项,因此您必须显式使用它。2 /您可以.cvsignore在任何目录中创建文件以具有特定于项目的忽略,这些文件也将被读取。根据手册,.git当您使用时3 / 已经被忽略--cvs-exclude了,因此放入它$HOME/.cvsignore似乎是多余的。
Niavlys

1

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


通过尝试此操作locate -0e .gitignore | (while read -d '' x; do process_git_ignore "$x"; done),但存在很多问题。目录中的文件,如果.gitignore没有正确将其与目录名分开,请使用/。空白行和注释被误解。在扼流圈.gitignore与空格的路径文件(心中永远的魔王/opt/vagrant/embedded/gems/gems/rb-fsevent-0.9.4/spec/fixtures/custom 'path/.gitignorevagrant包装的Ubuntu)。作为Perl脚本,也许做得更好。
Jesse Glick 2015年

@JesseGlick我不确定为什么要在脚本中调用该函数。它打算用作的替代品rsync,具体原因是处理引号/空格太麻烦了。如果您有一个gsync失败的命令行示例以及.gitignore与之相关的文件,我很乐意仔细查看。
cobbzilla

我需要rsync一个完整的文件系统,周围散布着各种Git存储库。也许您的脚本在同步单个存储库的情况下可以正常工作。
Jesse Glick 2015年

1
当然是。对不起,我没有说清楚。使用此脚本,您必须从repo目录中的每个git repo调用一次。
cobbzilla

0

检出rsync(1)中的“合并文件过滤器规则”部分。

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


0

除了创建排除过滤器之外,您还可以git ls-files用来选择要同步的每个文件:

#!/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返回换行符分隔的路径,此方法也有效。如果文件名中带有空格的版本控制文件可能不起作用。


0

备择方案:

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

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

(rsync仅部分理解.gitignore)


0

简短答案

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

参数含义:

-r:递归

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.