CBMignore Syntax and Precedence Over Gitignore: A Complete Guide
.cbmignore uses standard gitignore pattern syntax but sits lower in the precedence hierarchy than repository .gitignore files, only able to override global Git excludes.
The codebase-memory-mcp project by DeusData uses .cbmignore files to control which paths are fed to the indexer during the discovery phase. While the pattern syntax mirrors familiar gitignore conventions, the precedence rules differ significantly, determining whether your exclusion rules actually affect indexing. Understanding these mechanics ensures you configure file filtering correctly without silent failures.
CBMignore Syntax: Gitignore-Compatible Patterns
According to the specification in docs/cbmignore.md, the .cbmignore format follows the classic gitignore specification exactly. The file consists of one pattern per line, with blank lines and lines beginning with # ignored.
Core Pattern Operators
The supported wildcards and operators include:
*– Matches any run of characters except/?– Matches exactly one character except/**– Cross-directory wildcard (e.g.,**/name,dir/**,a/**/b)[abc]/[a-z]– Character classes (negated with!or^)- Trailing
/– Directory-only match - Leading
/– Anchor to the repository root - No
/– Match the name at any depth - Leading
!– Negation to re-include a previously excluded path (last matching rule wins)
Practical Syntax Examples
# Generated protobuf output, anywhere in the tree
*.pb.go
# A specific top-level directory (anchored)
/third_party/
# Any directory named "snapshots" at any depth
snapshots/
# Everything under any fixtures directory
**/fixtures/**
# Anchored glob for single-character API versions
/api/v?/generated/
# Yearly log folders
/logs/202[0-9]/
Precedence Hierarchy: Five Layers of Ignore Resolution
The discovery logic implemented in src/discover/discover.c evaluates ignore rules in a fixed five-layer order. The first layer that rejects a path wins, meaning .cbmignore cannot veto decisions made by higher layers.
-
Built-in skip list – Hard-coded directories such as
.git,node_modules,dist,target, andvendorthat cannot be overridden by any configuration. -
Repository-level
.gitignore– The root.gitignorefile merged with work-tree-awareinfo/exclude. -
Nested
.gitignorefiles – Any.gitignorediscovered while walking subdirectories, matched relative to their own location. -
.cbmignore– A positive match skips the path; a negated match (!) can rescue a path only from the next layer (Git global excludes). -
Git global excludes – The
core.excludesFileconfiguration (e.g.,$HOME/.config/git/ignore) consulted only when the project is a Git repository.
Critical Limitations
A rule in .cbmignore cannot override any built-in skip lists or any .gitignore rule (repository-level or nested). A negation (!) in .cbmignore can override the global Git excludes (layer 5) but cannot rescue files excluded by layers 1-4. Within the same .cbmignore file, the last matching rule wins, mirroring standard gitignore behavior.
Practical Implementation Examples
Example 1: Simple Positive Ignore
Create a .cbmignore file in your repository root:
generated/
*.pb.go
Effect: Any file under a generated/ directory or any file ending with .pb.go is omitted from the index, regardless of what .gitignore says.
Example 2: Negating a Global Git Exclude
Assume the user's global Git exclude contains *.sql:
File: ~/.config/git/ignore
*.sql
Project .cbmignore:
!*.sql
Effect: The global rule is overridden, and SQL files are indexed. This works because the negation targets layer 5.
Example 3: Attempting to Override Repository Gitignore (Fails)
Repository .gitignore:
*.log
Project .cbmignore:
!*.log
Effect: The .log files remain ignored because .gitignore (layer 2) outranks .cbmignore (layer 4). This limitation is verified in the test suite at tests/test_discover.c.
Example 4: Combining Patterns
# Exclude all generated protobuf files
*.pb.go
# But keep CI YAML files
!ci.yaml
Effect: All *.pb.go files are skipped, while ci.yaml is explicitly re-included (last-match wins within the file).
Summary
.cbmignoreuses identical syntax to.gitignore, supporting wildcards, anchoring, and negation.- Precedence follows a strict five-layer hierarchy where
.cbmignoresits below built-in skips and all.gitignorevariants. - Negation rules (
!) in.cbmignoreonly function against global Git excludes, not repository-level ignores. - The implementation resides in
src/discover/discover.c, with comprehensive test coverage intests/test_discover.c. - For complete syntax details, reference
docs/cbmignore.mdin the DeusData/codebase-memory-mcp repository.
Frequently Asked Questions
Can .cbmignore override rules in my repository's .gitignore?
No. The precedence hierarchy places .cbmignore at layer 4, below both repository-level and nested .gitignore files at layers 2 and 3. If a path is excluded by any .gitignore file, .cbmignore cannot rescue it, even with a negation pattern.
What is the exact syntax specification for .cbmignore?
The syntax is identical to standard gitignore format as documented in docs/cbmignore.md. It supports * for wildcards, ** for cross-directory matching, ? for single characters, character classes [abc], trailing / for directories, leading / for root anchoring, and ! for negation.
Why aren't my negation rules in .cbmignore working?
Negation patterns (!) only have authority to override the global Git excludes file (layer 5). They cannot re-include files that were excluded by the built-in skip list, repository .gitignore, or nested .gitignore files. If you need to index files excluded by the repository's own .gitignore, you must modify that file rather than using .cbmignore.
Where should the .cbmignore file be located?
Place .cbmignore in the repository root directory. The discovery module in src/discover/discover.c evaluates this file during the directory walk, applying its rules relative to the repository root when patterns use leading / anchors.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →