【问题标题】:From a shell script, how can I filter out files matching .gitignore?从 shell 脚本中,如何过滤掉与 .gitignore 匹配的文件?
【发布时间】:2018-06-18 14:11:07
【问题描述】:

我正在维护一些 git pre-commit 钩子,并且我一直想为所有正在或应该处于修订控制之下的文件做一些事情。 了解项目结构可以让我做得很好,但是关于构建系统输出目录、测试日志文件和编辑器粪便的所有信息都已经在 .gitignore 中。

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

我可以用什么代替WHAT GOES HERE in

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

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

我想我可以得到一个否定过滤器,我可能会通过这样做进入comm

... | xargs git ls-files -X .gitignore -i

但我希望迈出一步。

【问题讨论】:

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


【解决方案1】:

更新 - 正如 cmets 在这个答案的交流中所指出的,check-ignore 命令它列出了被忽略的文件,但如果你的忽略规则包括异常(以! 开头的模式),即使文件未被忽略,匹配这些模式的文件也会被打印。虽然某些文档可以被解读为描述了这种行为,但同一文档的其他部分强烈暗示这不是预期的 - 所以我认为这是一个错误,但不管这样的解释如何,这就是软件的工作方式。

所以...如果您不使用! 模式,则以下内容将按广告宣传。如果您确实使用! 模式,那么您可以通过使用--verbose 输出和后处理来查看匹配模式是包含还是排除来解决此问题。


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

但无论如何,一种不同的(更“一步”)方法是:

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

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

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

默认情况下,这也意味着如果一个文件在索引中,它确实显示为“排除”,即使它在.gitignore 中,这反映了如何忽略规则真正行为

但是,如果您不想处理匹配忽略模式的文件,即使它们在索引中,因此不会被真正忽略,您可以修改命令来做到这一点:

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

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

您可能还想排除.git 目录。如果.git 是您的顶级目录中唯一的“点文件”,您可以说

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 的两次调用,这有点难看。您可以在运行find 之前将rev-parse 结果捕获到环境变量中,但这可能会与您的“一步”偏好相冲突。另一种选择,如果您可以放心地忽略名为 .git

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

【讨论】:

  • 谢谢。 git check-ignore 是我遗漏的部分,感谢您展示有助于它作为否定 find 谓词的一部分工作的特定标志。
  • 好答案,但更明确一点:小心该命令将显示与 ignore 模式 匹配的文件(答案说),而不是如果它们被忽略git add 与否(OP 似乎想要);如果规则包含 *.html 和 !foobar.html,则 foobar.html 仍会显示。
  • @NoDataFound - 这很有趣;我在测试中没有注意到它。这也与文档相反,因此几乎可以肯定它是一个错误。
  • 文档说:git-scm.com/docs/git-check-ignore 默认情况下,将输出任何给定的路径名​​匹配忽略模式,每行一个。如果没有模式与给定路径匹配,则该路径不会输出任何内容;这意味着路径将不会被忽略。 但是标题具有误导性:对于通过命令行或通过 --stdin 从文件给出的每个路径名,检查文件是否被排除.gitignore(或排除机制的其他输入文件)并在排除时输出路径。
  • 请注意,我已经使用 find -type f -print0|xargs -r0 git check-ignore --no-index -v 测试了几个文件的命令(因为我想使用 git filter-branch 从树中删除它们),而不是像你正在做的一个。这可能会有所不同。
猜你喜欢
  • 1970-01-01
  • 2017-07-12
  • 2020-09-22
  • 1970-01-01
  • 2013-06-14
  • 1970-01-01
  • 1970-01-01
  • 2016-08-13
  • 1970-01-01
相关资源
最近更新 更多