globstar:跨目录通配
01 页的 * 只在一段之内匹配,跨目录全靠 ** (globstar): 当它单独占一个路径段时,匹配零个或多个路径段。注意是「零个」起步——**/*.md 连根目录的 README.md 也命中,src/**
在本仓库实现里连 src 自身也算。而一旦与字面量混写 (a**b),双星就失去跨段语义,退化为普通 *。
在下面这棵典型前端项目树上换 pattern,看命中范围怎么伸缩。先对比前三个预设:*.md(只看根)→ **/*.md(不限深度)→ docs/**/*.md(限定在 docs)。
1 · 零个也算:** 匹配空序列
** 匹配「零个或多个段」,这个零是高频考点:**/*.js = *.js ∪ */*.js ∪ */*/*.js ∪ …,所以根目录的 js 也在内;至于 src/** 是否连 src 自身也算,四家分成两派:node-glob 走盘、picomatch
与本仓库实现都算(实测),而 minimatch 的纯字符串匹配与 gitignore 都不算——git 文档写明「abc/** matches all files inside directory abc」,目录自身不在内(核对于 2026-08)。对照 src/* 与 src/** 两个预设:单星只到直接子级,双星覆盖全部后代。
2 · 单独成段才有跨段语义
** 的跨段语义有个前提:整段恰好是 ** 才生效——src/**/x.ts ✓。写成 a**b、**.js 这种混写,minimatch、node-glob、VS Code 与本仓库实现都把它当普通 * 处理(两颗星折叠成一颗):**.js 就是
*.js,照样不跨目录。但 picomatch(fast-glob、Jest、chokidar 的内核)在这一点上与 minimatch 分家:实测 picomatch 4.0.5 判 **.js 命中 a/b.js,即混写下它照样跨段(核对于 2026-08)。另外 ** 与相邻段之间的 / 不能省,src** ≠
src/**。
它也有不进的地方: ** 默认不进 dot 目录 (.git/、.vscode/),对 symlink 也有节制:node-glob 默认最多跟一层,且 ** 位于 pattern 首位时一层都不跟(与 bash 一致),follow:true
才全跟、代价是要防环。前者是 dot 规则在目录维度的体现,04 页有开关可试。另外 ** 是开销最大的通配——它要求实现遍历整棵子树,放在 pattern 开头(**/…)时尤其注意范围。