从shell脚本中,如何过滤掉与.gitignore匹配的文件?

时间:2018-06-18 14:11:07

标签: bash git filtering gitignore pre-commit-hook

我正在维护一些git pre-commit挂钩,并且我一直想为所有或者应该受版本控制的文件做些什么。 了解项目结构可以让我做得很好,但有关构建系统输出目录,测试日志文件和编辑器粪便的所有信息都已在.gitignore中。

是否有一种简单的方法可以根据文件路径是否与.gitignore中的模式匹配来过滤文件路径。

喵,我可以在

中替换WHAT GOES HERE
find "$(git rev-parse --show-toplevel)" --my --filters | WHAT GOES HERE

这样我就可以获得与我的过滤器匹配的所有且只有非gitignored文件。

我认为我可以通过

获得一个负面过滤器,我可能会comm进入... | xargs git ls-files -X .gitignore -i
race

但我希望一步到位。

1 个答案:

答案 0 :(得分:2)

更新 - 如对此答案的评论交换中所述,check-ignore命令表示它列出了忽略的文件,但是如果您忽略了规则包括异常(以!开头的模式),即使文件未被忽略,也会打印与这些模式匹配的文件。虽然一些文档可以被理解为描述这种行为,但同一文档的其他部分强烈暗示它不是什么意思 - 所以我认为它是一个错误,但不管这些解释如何,它和#39;软件是如何工作的。

所以...如果你不使用!模式,下面的工作方式就像宣传的那样。如果你使用!模式,那么你可以通过使用--verbose输出和后处理来查看匹配模式是包含还是排除。< / p>

使用ls-files获取所需的确切行为可能并不像看起来那么容易。首先,您可能不是-i,因为列出忽略的文件...

但无论如何,一种不同的(更多&#34;一步&#34;)方法将是:

find命令中,您可以使用-exec操作为与其他过滤器匹配的每个文件调用git check-ignore

find "$(git rev-parse --show-toplevel)" <filters> -not -exec git check-ignore -q {} \; <actions>

这将正确解释所有来源的忽略规则。

默认情况下,这也意味着如果文件在索引中,则显示为&#34;排除&#34;即使它在.gitignore中反映了忽略规则的真实行为

但是如果您不想处理与忽略模式匹配的文件,即使它们在索引中并且因此并未真正被忽略,您可以修改命令来执行此操作:

find "$(git rev-parse --show-toplevel)" <filters> -not -exec git check-ignore -q --no-index {} \; <actions>

由于您从使用find开始,我假设您只关心工作树中当前存在的文件。

您可能还想排除.git目录。如果.git是唯一的&#34;点文件&#34;在您的顶级目录中,您可以说

find "$(git rev-parse --show-toplevel)"/* <filters> -not -exec git check-ignore -q --no-index {} \; <actions>

如果你不能做出这个假设,那么你可以

find "$(git rev-parse --show-toplevel)" -path "$(git rev-parse --show-toplevel)"/.git -prune -o <filters> -not -exec git check-ignore -q -no-index {} \; <actions>

由于对rev-parse的两次调用,这有点难看。您可以在运行rev-parse之前将find结果捕获到环境变量,但这可能会导致您的&#34;一步&#34;偏爱。另一个选项是,如果您可以安全地忽略名为.git

任何目录
find "$(git rev-parse --show-toplevel)" -path */.git -prune -o <filters> -not -exec git check-ignore -q -no-index {} \; <actions>