首页
/ ripgrep ignore crate 深度解析:构建尊重 .gitignore 的高速递归目录迭代器

ripgrep ignore crate 深度解析:构建尊重 .gitignore 的高速递归目录迭代器

2026-09-04 12:15:19作者:毕习沙Eudora

ignore 是 ripgrep 项目中承担“文件筛选”职责的核心 crate:它提供一个尊重 glob、文件类型与 .gitignore 规则的快速递归目录迭代器,同时向下暴露可独立使用的 gitignore 与文件类型匹配器。读完本文,你将掌握在 Rust 项目中集成目录遍历(Walk/WalkBuilder)、配置各类忽略规则、理解 ripgrep 默认排除优先级,以及使用 WalkParallel 并行遍历与 IncrementalIgnore 增量匹配的完整方法。

ignore crate 的定位与模块构成

根据 crates/ignore/README.md 的官方描述,ignore crate 提供两类能力:

  1. 快速递归目录迭代器——遍历时自动应用 globs、文件类型、.gitignore 等过滤器;
  2. 低层匹配器——对需要更细粒度控制的场景,直接暴露 gitignore 匹配器与文件类型匹配器。

从源码结构看,这些能力分别落在 crates/ignore/src/ 下的各模块中:

模块 职责
walk.rs WalkWalkBuilderWalkParallelDirEntry 等迭代器核心
gitignore.rs Gitignore/GitignoreBuilder,解析并匹配 gitignore 语法
types.rs 文件类型定义与匹配(如 rustc 等类型)
overrides.rs glob 覆盖匹配器(白名单/黑名单)
dir.rs 将 override、ignore 文件、类型匹配器组合成的 Ignore 复合匹配器
incremental.rs IncrementalIgnore 按路径做缓存式匹配,无需全量遍历
default_types.rs 内置文件类型定义表

crate 的公开导出集中在 crates/ignore/src/lib.rsWalkWalkBuilderWalkParallelWalkStateParallelVisitor 等从 walk 模块导出,gitignoreoverridestypes 作为公开模块导出,incremental 中的 IncrementalIgnoreIncrementalMatch 也直接重导出到根命名空间。该 crate 采用 MIT 或 UNLICENSE 双许可。

安装与依赖声明

Cargo.toml 中加入依赖即可使用(README 给出的版本号为 0.4):

[dependencies]
ignore = "0.4"

本仓库内该 crate 自身的清单见 crates/ignore/Cargo.toml。需要说明的是,版本能力以当前仓库实际代码为准;若使用 crates.io 上的发布版本,行为以对应 tag 的源码为界。

基础用法:Walk 递归迭代器

README 中的第一个示例演示了最基本的使用方式——递归遍历当前目录,并根据 .ignore.gitignore 等文件中的 glob 自动过滤条目:

use ignore::Walk;

for result in Walk::new("./") {
    // Each item yielded by the iterator is either a directory entry or an
    // error, so either print the path or the error.
    match result {
        Ok(entry) => println!("{}", entry.path().display()),
        Err(err) => println!("ERROR: {}", err),
    }
}

crates/ignore/src/walk.rs 可以看到,Walk::new 实际上就是 WalkBuilder::new(path).build() 的简写,因此它天然携带全部默认设置(尊重 .gitignore、跳过隐藏文件等)。迭代器产出的 Result 中:

  • Ok(DirEntry) 是目录条目。DirEntrywalk.rs)除 path() 外还提供 depth()file_name()file_type()metadata()path_is_symlink()is_stdin(),以及一个 error() 方法——后者报告“处理该条目时”的软性错误,例如某个目录下忽略文件解析失败;
  • Err(Error) 是遍历本身的错误(如 I/O 失败、符号链接环路),见后文错误模型一节。

多目录遍历时,文档建议对同一个 builder 调用 add 而不是创建多个 Walk,因为这样可以跨迭代复用资源(见 WalkBuilder::add 的注释,walk.rs)。

进阶配置:WalkBuilder 及其主要选项

README 的进阶示例展示了如何关闭默认启用的隐藏文件过滤:

use ignore::WalkBuilder;

for result in WalkBuilder::new("./").hidden(false).build() {
    println!("{:?}", result);
}

WalkBuilder 的完整选项较多,下面结合 crates/ignore/src/walk.rs 中各方法的文档注释,整理一份可直接参考的选项表:

方法 默认值 作用
hidden(yes) true 是否忽略以 . 开头的隐藏文件/目录
parents(yes) true 是否读取每个路径父目录中的 .gitignore
ignore(yes) true 是否读取 .ignore 文件(语法同 gitignore,ripgrep、Ag 等搜索工具支持)
git_ignore(yes) true 是否读取 .gitignore 文件
git_exclude(yes) true 是否读取 .git/info/exclude
git_global(yes) true 是否读取全局 gitignore(core.excludesFile,缺省时 $XDG_CONFIG_HOME/git/ignore,再缺省 $HOME/.config/git/ignore
standard_filters(yes) true 以一组开关形式同时切换上表前 6 项;调用后仍可对单项覆盖
require_git(yes) 是否要求存在 git 仓库才应用 git 相关规则;设为 false 时即使在 git 根目录之上也会读取父级 .gitignore(与 git 行为不同)
ignore_case_insensitive(yes) false 忽略大小写解析忽略文件
max_depth(d) / min_depth(d) None 限制递归深度区间;builder 会自动纠正两者冲突
max_filesize(n) None 超过该字节数的文件被跳过(只作用于文件)
follow_links(yes) false 是否跟随符号链接
same_file_system(yes) false 不跨文件系统边界;目前仅支持 Unix 与 Windows
threads(n) 0(自动启发式选择) 仅对 build_parallel 生效的线程数
sort_by_file_name(cmp) / sort_by_file_path(cmp) 不排序 对单线程迭代器按名称/路径排序;并行迭代器不使用排序器
skip_stdout(yes) false 跳过与 stdout 指向同一文件的条目,防止 grep -r foo ./ > results 这类自读自写死循环
filter_entry(pred) 自定义谓词:返回 false 的条目被跳过,且不再深入其目录
add_ignore(path) 显式追加一个全局忽略文件(优先级低于其他所有来源)
add_custom_ignore_filename(name) 追加自定义忽略文件名,优先级高于其他所有忽略文件
overrides(ov) / types(t) 注入 glob 覆盖匹配器 / 文件类型匹配器
current_dir(cwd) 自动探测 指定匹配全局 gitignore 所用的工作目录

一个典型的组合配置示例(在尊重默认规则的基础上,追加 .rgignore 并限制深度):

use ignore::WalkBuilder;

let walker = WalkBuilder::new("./")
    .add_custom_ignore_filename(".rgignore")
    .max_depth(Some(4))
    .build();
for result in walker {
    // ...
}

值得注意的是 build_matcherswalk.rs):它构建一套“只做路径匹配、不做递归遍历”的 IncrementalIgnore 匹配器,应用与遍历相同的按路径过滤配置(glob 覆盖、.ignore/.gitignore、全局 gitignore、自定义忽略文件名、文件类型选择、隐藏文件、深度与大小限制),但不应用需要目录条目状态的特性(如 filter_entry)。这在 ripgrep 中用于对少量变更文件做增量判定。

排除规则与优先级:一个条目如何被决定跳过

WalkBuilder 的文档(crates/ignore/src/walk.rs)明确规定了默认配置下每个路径经过的七步判定顺序:

  1. glob 覆盖(overrides)优先检查。若命中覆盖 glob,则匹配立即停止;仅当命中的是“忽略 glob”(以 ! 开头的覆盖 glob)时路径才被跳过,否则视为白名单。
  2. 检查忽略文件。来源包括 .ignore.gitignore.git/info/exclude、全局 gitignore 以及显式添加的忽略文件。文件类别间的优先级为:.ignore > .gitignore > .git/info/exclude > 全局 gitignore > 显式添加的忽略文件。类别优先级不受目录层级影响——任意层级的 .ignore 都压过任意层级的 .gitignore;而在同一类别内部,嵌套更深的文件优先级更高
  3. 若上一步得到“忽略”结果,匹配停止、路径被跳过;若得到“白名单”(反斜杠否定规则,如 !foo)结果,则匹配继续,后续匹配器仍可能推翻它。
  4. 对非目录路径运行文件类型匹配器;忽略结果跳过,白名单结果继续。
  5. 若路径尚未被白名单化且是隐藏文件,则跳过。
  6. 对非目录路径比较文件大小,超过 max_filesize 则跳过。
  7. 走到这一步的路径被迭代器产出。

这套顺序解释了实际使用中常见的两个疑问:为什么 .gitignore 里的规则会被同目录的 .ignore 压过,以及为什么“深层目录的更具体规则”总是赢。单文件层面的软错误(某个 glob 解析失败但不影响其余规则)通过 DirEntry::error 报告,而不是中断遍历——Walk::new 的迭代结果中 Ok(entry) 条目可能同时携带 entry.error()

低层匹配器:gitignore 与文件类型

gitignore 模块

crates/ignore/src/gitignore.rs 的模块文档明确指出:该模块从零实现gitignore man page 描述的规范,不会 shell 调用 git 命令行工具——这意味着无 git 依赖、可在任何平台运行。

核心类型:

  • Globgitignore.rs):表示 gitignore 文件中的单条 glob,记录来源文件(from())、原始字符串(original())、编译后真正用于转换的正则形式(actual())、是否白名单(is_whitelist())、是否仅匹配目录(is_only_dir())。
  • Gitignore:同一目录内一个或多个 gitignore 文件的组合匹配器。Gitignore::new(path) 永远返回有效匹配器——即使文件部分有效(如某一条 glob 非法而其余合法),I/O 错误也被吞掉;需要细粒度错误控制时应使用 GitignoreBuilder
  • GitignoreBuilder:可多次 add 不同来源(文件、字符串、reader),编译成 GlobSet 后一次性匹配;构建错误会以带行号/路径标签的形式返回。

types 与 overrides 模块

  • types 模块管理文件类型定义(如 rustchtml),内置定义来自 default_types.rs,用户可通过自定义定义扩展或覆盖;
  • overrides 模块实现“覆盖 glob”:不带前缀的 glob 视为白名单(强制包含),以 ! 开头视为忽略(强制排除),在七步判定中占据最高优先级。

IncrementalIgnore:不做遍历的增量匹配

crates/ignore/src/incremental.rs 中的 IncrementalIgnore 通过 WalkBuilder::build_matchers 构建。它按目录粒度缓存已编译的忽略匹配器:首次查询某路径时读取根目录及其父链上的忽略文件,之后复用缓存。文档同时给出明确警告:该接口“每条路径的匹配开销更大”,不适合用来驱动整棵树遍历,其设计目标是避免“仅检测到少量文件增删时重新遍历整棵目录树”。其文档示例与 ripgrep 的 .rgignore 用法完全一致:

use ignore::WalkBuilder;

let mut builder = WalkBuilder::new(".");
builder.add_custom_ignore_filename(".rgignore");
let mut matchers = builder.build_matchers();
let matcher = &mut matchers[0];

if matcher.matched("src/generated.rs", false).is_ignore() {
    println!("ignored");
}

并行遍历:WalkParallel

对大规模目录树,build_parallel 返回的 WalkParallel 不是 Iterator,而是必须通过 run(closure) 驱动;闭包对每个条目返回 WalkState::ContinueWalkState::Abort。仓库自带示例 crates/ignore/examples/walk.rs 展示了并行(6 线程)、串行 ignore 遍历与普通 walkdir 三者的对照写法,其中并行部分的关键代码:

let walker = WalkBuilder::new(path).threads(6).build_parallel();
walker.run(|| {
    let tx = tx.clone();
    Box::new(move |result| {
        use ignore::WalkState::*;
        tx.send(DirEntry::Y(result.unwrap())).unwrap();
        Continue
    })
});

线程数由 threads(n) 控制,默认 0 表示由启发式自动选择;该选项只对并行迭代器生效,串行 Walk 忽略它(见 walk.rs 的注释)。

错误模型:软错误与硬错误

Error 枚举(crates/ignore/src/lib.rs)按上下文对错误打标签,便于定位:

  • Partial(Vec<Error>):部分成功的“软”错误集合,例如忽略文件中某条 glob 非法但其余生效;
  • WithLineNumber { line, err } / WithPath { path, err } / WithDepth { depth, err }:分别附带行号、文件路径、递归深度;
  • Loop { ancestor, child }:跟随符号链接时检测到目录环;
  • Io(std::io::Error):读取忽略文件等 I/O 错误;
  • Glob { glob, err }:glob 解析失败,glob 字段保留用户原始书写形式;
  • UnrecognizedFileType(String) / InvalidDefinition:文件类型未定义或自定义定义无法解析。

配套辅助方法包括 is_partial()is_io()io_error() / into_io_error()depth(),帮助调用方区分“可降级处理”与“必须终止”的错误。这也是迭代器 API 将“条目级软错误”与“遍历级硬错误”分离的原因:软错误随 DirEntry 携带,硬错误直接作为 Err 产出。

测试与验证

ignore crate 的测试可用作行为验证参考,位于 crates/ignore/tests/

在 ripgrep 主程序层面,crates/core/haystack.rs 等模块基于本 crate 的迭代器构建搜索入口;本文所述优先级与过滤顺序即 ripgrep 默认排除文件行为的底层依据。

小结

ignore crate 把“尊重 gitignore 的目录遍历”做成了一个可组合的公共 API:Walk 一行代码起步,WalkBuilder 提供隐藏文件、全局 gitignore、深度/大小限制、排序、过滤谓词等精细开关,WalkParallel 提供并行能力,gitignore/types/overrides 模块与 IncrementalIgnore 则覆盖无需遍历的匹配场景。理解其七步判定顺序与五类忽略文件的优先级(.ignore > .gitignore > .git/info/exclude > 全局 > 显式),是正确使用这个 crate、并正确解释 ripgrep 为何跳过(或不跳过)某个文件的关键。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
980
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384