Files
wehub-resource-sync 41cb1c0170
OpenSSF Scorecard / scorecard (push) Failing after 0s
DCO / dco (push) Failing after 0s
CodeQL SAST / analyze (push) Failing after 1s
Deploy Pages / deploy (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:28:05 +08:00

122 lines
5.2 KiB
Markdown

# `.cbmignore` — Excluding Files from Indexing
`.cbmignore` is a project-specific ignore file that controls which files the
indexer sees. It uses gitignore-style syntax and is read from the **root of
the indexed directory** (`<repo>/.cbmignore`). Nested `.cbmignore` files in
subdirectories are not read.
It applies at **file discovery time** — the directory walk that selects files
for parsing. Every indexing path uses the same discovery: the initial
`index_repository`, manual re-indexing, and background auto-sync. A path
matched by `.cbmignore` never enters the graph. Changes to `.cbmignore` take
effect on the next (re-)index.
Unlike `.gitignore`, it has no effect on git itself — it only shapes what the
indexer sees. Commit it to share indexing excludes with your team, or list it
in `.gitignore` to keep personal excludes untracked.
To verify it works: directory subtrees skipped during discovery are reported
in the `index_repository` response under `excluded`
(`{"dirs": [up to 25 paths], "count": <total>, "truncated": <bool>}`).
## Syntax
One pattern per line. Blank lines are ignored, lines starting with `#` are
comments, and trailing whitespace is trimmed.
| Feature | Meaning |
|---|---|
| `*` | matches any run of characters, except `/` |
| `?` | matches exactly one character, except `/` |
| `**` | matches across directory boundaries (`**/name`, `dir/**`, `a/**/b`) |
| `[abc]`, `[a-z]` | character classes; `[!a-z]` / `[^a-z]` negate the class |
| trailing `/` | pattern matches **directories only** |
| `/` anywhere else | anchors the pattern to the repo root |
| no `/` in pattern | matches the file/directory name at **any depth** |
| leading `!` | negation — re-includes a previously matched path; the **last matching pattern wins** |
Examples:
```gitignore
# Generated protobuf output, anywhere in the tree
*.pb.go
# A specific top-level directory (leading / anchors to the repo root)
/third_party/
# Any directory named "snapshots", at any depth (trailing / = directories only)
snapshots/
# Everything under any fixtures directory
**/fixtures/**
# Anchored glob: generated clients for any single-character API version
/api/v?/generated/
# Character class: yearly log folders 2020-2029
/logs/202[0-9]/
# Ignore all YAML, but keep CI configs (negation — last match wins)
*.yaml
!ci.yaml
```
## Precedence
Discovery applies its filters in a fixed order — the first layer that rejects
a path wins. For directories:
1. **Built-in skip list**`.git`, `node_modules`, `dist`, `target`,
`vendor`, tool caches, etc. (60+ names; the fast/moderate index modes add
more, e.g. `docs`, `examples`, `testdata`). Not overridable from any
ignore file today.
2. **Repo `.gitignore`**`<repo>/.gitignore` merged with
`<git-common-dir>/info/exclude` (worktree-aware); later patterns win on
conflict. Honored even when the indexed directory is not a git repo root.
3. **Nested `.gitignore` files** — picked up during the walk and matched
relative to their own directory.
4. **`.cbmignore`** — a positive match skips the path; a negated match can
only rescue paths from layer 5.
5. **Git global excludes**`core.excludesFile` from `~/.gitconfig` or the
XDG git config (default `$XDG_CONFIG_HOME/git/ignore`); consulted only
when the project is a git repo with a config.
For files, built-in suffix filters (`.png`, `.o`, `.db`, …; fast modes add
archives, media, lockfiles, `.min.js`, …) and fast-mode filename/substring
filters run **before** the ignore files, and a maximum-file-size cap runs
after them; none of these are overridable from `.cbmignore`. Symlinks are
always skipped.
## Negation (`!`) — current behavior
- **Within `.cbmignore`**: standard gitignore semantics. Patterns are
evaluated top to bottom and the last matching pattern wins, so
`!pattern` re-includes something an earlier line excluded.
- **Parent pruning** (same caveat as git): when a directory is excluded, the
walk never descends into it — you cannot re-include a file whose parent
directory is excluded. Negate the directory itself if you need its
contents.
- **Across layers**: a `.cbmignore` negation overrides the **git global
excludes** layer only. Example: your `~/.config/git/ignore` ignores
`*.sql`, but this project's SQL should be indexed — add `!*.sql` to
`.cbmignore`. Negation cannot override the built-in skip lists, the repo
`.gitignore`/`info/exclude`, nested `.gitignore` files, the built-in
suffix/filename filters, or the size cap.
### Planned (not yet implemented)
The negation story is being unified; none of the following works yet:
- `!` in `.cbmignore` will be able to un-skip ordinary built-in skip
directories (`obj/`, `dist/`, `target/`, …) so build-output-like
directories that actually contain source can be indexed.
- A small safety core stays non-negatable by design — `.git`,
`node_modules`, and worktree-internal directories — because indexing them
risks OOM and correctness issues (see issue #489).
- Auxiliary filesystem walkers will honor the same ignore predicate as
discovery, so every code path sees an identical ignore decision
(unification tracked in a follow-up issue).
Until these land, the "Precedence" and "Negation — current behavior" sections
above describe the actual behavior.