Skip to content

fix(init): make the generated .codegraph index invisible to git in every repo (#492) - #1601

Open
walterf3 wants to merge 1 commit into
colbymchenry:mainfrom
walterf3:fm/codegraph-untracked-index-ignore
Open

fix(init): make the generated .codegraph index invisible to git in every repo (#492)#1601
walterf3 wants to merge 1 commit into
colbymchenry:mainfrom
walterf3:fm/codegraph-untracked-index-ignore

Conversation

@walterf3

Copy link
Copy Markdown

Problem

codegraph init writes .codegraph/.gitignore ending in !.gitignore. That
negation un-ignores the generated file, so git sees one non-ignored path under
the data dir — and in any repository whose root .gitignore has no rule for
.codegraph/ (that is, every consumer repo), the generated index shows up as
untracked work:

$ codegraph init
$ git status
?? .codegraph/

$ git status --untracked-files=all
?? .codegraph/.gitignore

This repo doesn't see it, because its own root .gitignore carries
.codegraph/ for the test projects. Consumers have no such rule.

This is the residual of #492. That issue asked for "the entire .codegraph/
directory is not tracked by Git"
and suggested * + !.gitignore; the
suggestion shipped, but it cannot deliver the thing that was asked for. Git
reads and honors an ignore file that ignores itself, so dropping the negation is
what actually hides the directory:

$ cat .codegraph/.gitignore   # after this PR
...
*

$ git status --untracked-files=all
                              # nothing — clean

$ git check-ignore -v .codegraph/.gitignore
.codegraph/.gitignore:5:*     .codegraph/.gitignore

The alternative — writing .codegraph/ into the consumer's root .gitignore
is deliberately not what this does. CodeGraph editing a file the project
owns and commits is a much bigger intrusion than owning its own generated
directory end to end.

Change

src/directory.ts only:

  • Generated content is now a bare *. It covers the ignore file itself, so
    the data dir is invisible in every repository with no consumer-side change.
  • The stale-default predicate gains a second generation. Still gated on the
    # CodeGraph data files header, it now treats * plus !.gitignore as stale
    in addition to the pre-wildcard allowlists from .codegraph/.gitignore should include daemon.pid #788, so existing projects
    self-heal on the next CodeGraph command (init, status, sync, MCP
    startup — anything that runs validateDirectory). Idempotent afterwards.
  • User files are still never rewritten. No header → user-authored → left
    alone, unchanged from before. A file that has our header but customizes the
    default with some other negation (!notes.md) is also left alone: only the
    exact !.gitignore line marks a stale default.

Nothing else moves — extraction, graph contents, resolution, routing, telemetry,
the watcher, and codegraph uninit are untouched. .codegraph/ was already
skipped by name during indexing and watching, independent of this file, so index
contents are unaffected.

Validation

Verified against real git in throwaway repos, plus the built CLI:

Check Result
git status -uall after codegraph init in a fresh consumer repo clean — byte-identical to pre-init
Migration: roll ignore file back to the shipped form, run codegraph status ?? .codegraph/.gitignore → clean, file healed
Index still queryable after migration codegraph query hello returns the symbol
CODEGRAPH_DIR=.codegraph-win alternate dir hidden the same way (#636)
codegraph uninit --force removes the dir, tree clean
User-authored ignore file not rewritten; keeps its own git semantics
Full suite (npm test) 174 files passed, 3014 tests passed, 0 failures
tsc --noEmit / git diff --check clean

New coverage in __tests__/foundation.test.ts drives real git against real
temp repos, with GIT_CONFIG_GLOBAL/GIT_CONFIG_SYSTEM pointed away so a
developer's personal core.excludesFile can neither mask a regression nor cause
a false failure. Its header records why the tests can't just use this repo:
the root .gitignore here would hide the bug.

Confirmed load-bearing — all 6 new/updated assertions fail on the unfixed
source
and pass with it.

Compatibility

Existing indexes upgrade silently and keep working; the database and everything
else in the directory are untouched.

One edge case worth naming: if someone committed .codegraph/.gitignore
(which the !.gitignore form invited), the upgrade rewrites a tracked file, so
they see a one-file M .codegraph/.gitignore — git's ignore rules never apply
to tracked files, so this is unavoidable for any content change. The rest of the
index stays hidden either way, and they can commit the new content or
git rm --cached the file to get the full benefit.

Rollback is reverting this commit: it restores the previous generated content,
and the predicate stops matching the new form, so nothing is left in a broken
state either way.

…where (colbymchenry#492)

`.codegraph/.gitignore` ended with `!.gitignore`, which un-ignored the
generated file itself. Git therefore had one non-ignored path under the
data dir, so in any repository whose root `.gitignore` has no rule for
`.codegraph/` — i.e. every consumer repo — `git status` reported the
whole generated index as untracked work:

    ?? .codegraph/                       # git status
    ?? .codegraph/.gitignore             # git status -uall

This is the residual of colbymchenry#492: the issue asked for "the entire
`.codegraph/` directory is not tracked by Git" and suggested
`*` + `!.gitignore`, but that suggestion cannot deliver it. Git reads
and honors an ignore file that ignores itself, so dropping the negation
is what actually hides the directory — with no edit to the consumer's
own root `.gitignore`, which CodeGraph has no business writing to.

- Generated content is now a bare `*` (self-ignoring).
- The stale-default predicate gains a second generation: under our
  header, `*` plus `!.gitignore` is now recognized as stale and upgraded
  in place, so existing projects self-heal on the next CodeGraph command.
  User-authored files (no header) are still never rewritten, and neither
  is a headered file customized with some other negation — only the exact
  `!.gitignore` line marks a stale default.

Regression coverage drives real `git` against real temp repos, since
this repo's own root `.gitignore` masks `.codegraph/` and would hide the
bug: fresh init, migration from the deployed form, an alternate
`CODEGRAPH_DIR`, and a user-authored file keeping its own semantics. All
six new/updated assertions fail on the unfixed source.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant