diff --git a/__tests__/foundation.test.ts b/__tests__/foundation.test.ts index 05fa79804..be0707d8c 100644 --- a/__tests__/foundation.test.ts +++ b/__tests__/foundation.test.ts @@ -27,13 +27,18 @@ function cleanupTempDir(dir: string): void { describe('CodeGraph Foundation', () => { let tempDir: string; + let savedLocalGitignore: string | undefined; beforeEach(() => { tempDir = createTempDir(); + savedLocalGitignore = process.env.CODEGRAPH_LOCAL_GITIGNORE; + delete process.env.CODEGRAPH_LOCAL_GITIGNORE; }); afterEach(() => { cleanupTempDir(tempDir); + if (savedLocalGitignore === undefined) delete process.env.CODEGRAPH_LOCAL_GITIGNORE; + else process.env.CODEGRAPH_LOCAL_GITIGNORE = savedLocalGitignore; }); describe('Initialization', () => { @@ -62,6 +67,20 @@ describe('CodeGraph Foundation', () => { cg.close(); }); + it('can create a local-only .codegraph/.gitignore', () => { + process.env.CODEGRAPH_LOCAL_GITIGNORE = '1'; + const cg = CodeGraph.initSync(tempDir); + + const gitignorePath = path.join(getCodeGraphDir(tempDir), '.gitignore'); + expect(fs.existsSync(gitignorePath)).toBe(true); + + const content = fs.readFileSync(gitignorePath, 'utf-8'); + expect(content).toContain('*'); + expect(content).not.toContain('!.gitignore'); + + cg.close(); + }); + it('should throw if already initialized', () => { const cg = CodeGraph.initSync(tempDir); cg.close(); diff --git a/src/directory.ts b/src/directory.ts index da5b6e9cb..fb144384e 100644 --- a/src/directory.ts +++ b/src/directory.ts @@ -401,9 +401,19 @@ const GITIGNORE_CONTENT = `# CodeGraph data files — local to each machine, not !.gitignore `; +const LOCAL_GITIGNORE_CONTENT = `# CodeGraph data files — local to this machine, not for committing. +# Ignore everything in .codegraph/, including this file itself. +* +`; + /** Header line that prefixes every .gitignore CodeGraph has auto-generated. */ const GITIGNORE_MARKER = '# CodeGraph data files'; +function localGitignoreEnabled(): boolean { + const raw = process.env.CODEGRAPH_LOCAL_GITIGNORE?.trim().toLowerCase(); + return raw === '1' || raw === 'true' || raw === 'yes'; +} + /** * Is `content` a stale CodeGraph-generated `.gitignore` that should be * regenerated in place? True when it carries our header but predates the @@ -434,7 +444,7 @@ function ensureGitignore(gitignorePath: string): boolean { // Current default or a user-authored file: nothing to do. if (existing !== null && !isStaleDefaultGitignore(existing)) return true; try { - fs.writeFileSync(gitignorePath, GITIGNORE_CONTENT, 'utf-8'); + fs.writeFileSync(gitignorePath, localGitignoreEnabled() ? LOCAL_GITIGNORE_CONTENT : GITIGNORE_CONTENT, 'utf-8'); return true; } catch { return false;