Skip to content

Sub-repos / nested workspaces can't be indexed when parent .gitignore excludes them #38

@cdel1

Description

@cdel1

Summary

When contextplus is rooted at a workspace whose .gitignore excludes the
sub-trees containing the actual source (e.g. monorepos with git-managed
sub-repos under repos/ or packages/, or any layout using nested git
repos / git submodules / local symlinks), those sub-trees are invisible
to the indexer. There's no way to override this short of editing the
parent .gitignore.

Repro

workspace/
├── .gitignore            # contains:  repos/
├── docs/                 # indexed
└── repos/
    ├── lib-a/            # own git repo — NOT indexed
    │   └── src/...
    └── lib-b/            # own git repo — NOT indexed
        └── src/...

bunx contextplus /path/to/workspace indexes only docs/. The
embeddings-cache.json contains zero entries from repos/lib-a/ or
repos/lib-b/, even though each sub-repo has its own .gitignore that
would happily include its src/.

Cause

src/core/walker.ts:

  • L44 — loadIgnoreRules reads .gitignore only at rootDir. Nested
    .gitignore files (per-repo, per-package) are never loaded, so the
    ignore matcher uses only the parent's rules.
  • L63 — entry.name.startsWith(".") skips every dotfile/dir
    unconditionally, including any nested .git markers that might
    otherwise signal "this is a sub-repo, treat its own ignore rules".
  • No mechanism for multiple roots, include-overrides, or submodule
    awareness in WalkOptions.

Why the obvious workarounds don't work

  • Un-ignore the sub-trees in the parent .gitignore — changes the
    parent repo's git behavior (sub-repo contents start showing up in
    git status, gitlinks vs. embedded trees confusion, etc.). Also
    exposes build artifacts that the sub-repos correctly ignore but the
    parent doesn't know about.
  • Run a separate contextplus per sub-repo — works, but defeats
    cross-repo tools (get_blast_radius, semantic_navigate,
    get_feature_hub) at the workspace level. You can't ask "where is
    X used across all my packages" from one place.

Suggested resolutions (any one would solve it)

  1. Walk nested .gitignore files. When recursing into a directory,
    load its .gitignore (if any) and merge with the inherited rules.
    This is what ripgrep does and matches user mental model.
  2. Treat nested .git as a sub-repo boundary: when walkRecursive
    sees .git/ in a subdirectory, swap to that subdirectory's ignore
    rules instead of inheriting the parent's. (Closer to native git
    submodule semantics.)
  3. Add an include / extraRoots option to WalkOptions — an
    allow-list of paths that bypass parent ignore rules. Easiest to ship,
    most explicit, doesn't change defaults.

Happy to send a PR for option (1) or (3) if you have a preference.

Environment

  • contextplus 1.0.8
  • Node via bun (bunx contextplus)
  • macOS 25.1.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions