Summary
EffectiveExclude reads .gitignore only at the tracked root itself (statGitignore(repoPath) in internal/config/manager.go). Git applies ignore files from the repository root downward, so in the common monorepo layout — git root at repo/, gortex tracking repo/projects/App — the entire gitignore layer silently disappears. Nothing warns; the index just quietly fills with everything the ignore file was supposed to keep out.
For .NET solutions this is compounded by internal/excludes/builtin.go: Builtin covers JS (node_modules/), Python (.venv/, __pycache__/), JVM (.gradle/, target/), iOS (Pods/) — but has no Visual Studio / MSBuild entries at all. When the gitignore layer is missing, nothing catches .vs/, bin/, or obj/.
Observed on a real solution
Production .NET solution, ~10,400 indexed files, tracked root one level below the git root (whose .gitignore has standard .vs/ and [Oo]bj/ entries — verified with git check-ignore -v):
.vs/<Solution>/v17/HierarchyCache.v1.txt and the v18 copy indexed as first-class doc nodes
- 50+
obj/**/project.assets.json indexed (hit the result cap)
- generated
obj/{Debug,Release}/net8.0/*.AssemblyInfo.cs indexed as real C# source — duplicate generated symbols per build configuration alongside the hand-written ones
obj/**/*.csproj.FileListAbsolute.txt indexed as doc nodes
Beyond wasted index size, this junk actively breaks search recall — the ranking side of that is addressed in PR #416, but the two-line version: those .vs/obj text files are stuffed with source file paths, so they outrank real classes on exactly the tokens .NET naming conventions use. Keeping them out of the index in the first place is the other half of the defense.
Repro (minimal)
git init repo && cd repo
echo "junk/" > .gitignore
mkdir -p projects/app/junk
echo "class Real {}" > projects/app/Real.cs
echo "noise" > projects/app/junk/noise.txt
gortex track projects/app # track the subdirectory, not the git root
# index → junk/noise.txt is indexed despite being git-ignored
Suggested fix
- Discover the git root by walking up from the tracked root to the nearest
.git, and layer every .gitignore on the path from the git root down to the tracked root (patterns re-anchored relative to the tracked root, matching git semantics).
- Independently, add the standard VS/MSBuild set to
excludes.Builtin as defense-in-depth, same spirit as the existing Pods//.gradle/ entries: .vs/, bin/, obj/, TestResults/. (bin/ and obj/ are effectively never first-party source directories in .NET repos; a re-include via !pattern remains available for the exceptions.)
Happy to send a PR for either or both halves if that's welcome.
Summary
EffectiveExcludereads.gitignoreonly at the tracked root itself (statGitignore(repoPath)ininternal/config/manager.go). Git applies ignore files from the repository root downward, so in the common monorepo layout — git root atrepo/, gortex trackingrepo/projects/App— the entire gitignore layer silently disappears. Nothing warns; the index just quietly fills with everything the ignore file was supposed to keep out.For .NET solutions this is compounded by
internal/excludes/builtin.go:Builtincovers JS (node_modules/), Python (.venv/,__pycache__/), JVM (.gradle/,target/), iOS (Pods/) — but has no Visual Studio / MSBuild entries at all. When the gitignore layer is missing, nothing catches.vs/,bin/, orobj/.Observed on a real solution
Production .NET solution, ~10,400 indexed files, tracked root one level below the git root (whose
.gitignorehas standard.vs/and[Oo]bj/entries — verified withgit check-ignore -v):.vs/<Solution>/v17/HierarchyCache.v1.txtand thev18copy indexed as first-class doc nodesobj/**/project.assets.jsonindexed (hit the result cap)obj/{Debug,Release}/net8.0/*.AssemblyInfo.csindexed as real C# source — duplicate generated symbols per build configuration alongside the hand-written onesobj/**/*.csproj.FileListAbsolute.txtindexed as doc nodesBeyond wasted index size, this junk actively breaks search recall — the ranking side of that is addressed in PR #416, but the two-line version: those
.vs/objtext files are stuffed with source file paths, so they outrank real classes on exactly the tokens .NET naming conventions use. Keeping them out of the index in the first place is the other half of the defense.Repro (minimal)
Suggested fix
.git, and layer every.gitignoreon the path from the git root down to the tracked root (patterns re-anchored relative to the tracked root, matching git semantics).excludes.Builtinas defense-in-depth, same spirit as the existingPods//.gradle/entries:.vs/,bin/,obj/,TestResults/. (bin/andobj/are effectively never first-party source directories in .NET repos; a re-include via!patternremains available for the exceptions.)Happy to send a PR for either or both halves if that's welcome.