Skip to content

index_repository ignores .git/info/exclude and core.excludesFile inside linked git worktrees #682

Description

@Naam

Version

codebase-memory-mcp 0.8.1 (also reproduces on main @ 9169f46, built from source)

Platform

macOS (Apple Silicon)

Install channel

GitHub release archive / install.sh (0.8.1); Built from source (main)

Binary variant

standard

What happened, and what did you expect?

#489 and #499 taught the indexer to honor .git/info/exclude and the global core.excludesFile, but only for an ordinary checkout. Inside a linked git worktree both are dropped again, so directories you excluded there get walked and indexed.

The reason is that in a linked worktree <repo>/.git is a regular file (a gitlink, gitdir: <path>), not a directory. cbm_discover_ex() gates every per-clone ignore source on .git being a directory:

bool is_git_repo = wide_stat(gi_path, &gi_stat) == 0 && S_ISDIR(gi_stat.st_mode);

When that check is false, info/exclude and config are never read. Committed .gitignore still applies (the #510 path loads <repo>/.gitignore unconditionally), which is why only the non-committed excludes break and the gap is easy to overlook.

This is the same class of problem #489 was opened for (agent/sandbox worktrees blowing up the index), just from the other side: #489 indexes the main repo whose worktrees sit under an info/exclude path; this is indexing the worktree itself, which is exactly what branch-per-worktree agent workflows do. I hit it on a Zephyr firmware worktree where indexing pulled in ~31k nodes of build/ output that git check-ignore reports as ignored.

Expected: a worktree honors info/exclude and core.excludesFile the same way an ordinary checkout does.

Reproduction

T=$(mktemp -d); cd "$T"
git init -q main && cd main
echo 'def included(): return 1' > main.py
git add -A && git -c user.email=t@t -c user.name=t commit -qm init

# add a linked worktree, then exclude build/ ONLY via the shared info/exclude
git worktree add -q ../wt -b feat
echo 'build/' > .git/info/exclude
mkdir -p ../wt/build
echo 'def build_artifact(): return 2' > ../wt/build/gen.py

# git agrees build/ is ignored inside the worktree:
( cd ../wt && git check-ignore build/gen.py )   # -> build/gen.py
head -1 ../wt/.git                                # -> gitdir: .../worktrees/wt   (a file, not a dir)

codebase-memory-mcp cli index_repository "{\"repo_path\":\"$T/wt\"}"

Actual: the index summary has no build in excluded, and build/gen.py is indexed:

"nodes":8        # main.py + build/gen.py
# search_code build_artifact -> "file":"build/gen.py","total_results":1

Expected: build/ excluded, only main.py indexed (matching git check-ignore).

For contrast, the identical layout in a normal checkout (info/exclude in a non-worktree .git/) excludes build/ correctly, so the divergence is specific to the worktree gitlink.

Confirmations

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority/normalStandard review queue; useful PR with ordinary maintainer urgency.ux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions