Skip to content

CodeGraph writes .git/info/exclude when .git exists but is not a valid repository #126

Description

@XucroYuri

Summary

The bundled CodeGraph SessionStart helper writes .git/info/exclude whenever a .git path exists, even when that path is an empty or otherwise invalid repository marker. On Windows, Codex can leave such invalid .git directories behind; CodeGraph then mutates them into a more persistent partial Git structure, which combines badly with Codex Desktop's repeated Git discovery.

Environment

  • LazyCodex installed: 4.16.2
  • Latest LazyCodex source checked: bb8764ca1754148ca56478d433c42b91c550e0f4 (main)
  • Codex Desktop: 26.707.3748.0
  • Codex CLI: 0.144.1
  • OS: Windows 11 Pro for Workstations, build 26200, x64
  • Relevant config: OMO CodeGraph MCP and SessionStart hook enabled

Repository Decision

Reproduction

  1. Create a normal non-Git workspace.
  2. Create an empty .git directory in it, matching the invalid marker produced by the Windows sandbox report.
  3. Run the LazyCodex CodeGraph SessionStart bootstrap for that workspace.
  4. Inspect .git/info/exclude and run git -C <workspace> rev-parse --is-inside-work-tree.

Minimal state before the hook:

workspace/
  .git/        # empty, not a repository

Observed state after the hook:

workspace/
  .git/
    info/
      exclude  # contains .codegraph

git rev-parse --is-inside-work-tree still fails because the workspace is not a repository.

Expected Behavior

CodeGraph must leave an invalid .git path untouched. It should write an exclude entry only after Git confirms that the workspace is a valid worktree and resolves the correct per-worktree exclude path.

Actual Behavior

ensureCodegraphGitignored() treats existence as validity:

const gitDir = join(workspace, ".git");
if (!existsSync(gitDir)) return false;
const excludePath = join(gitDir, "info", "exclude");
mkdirSync(join(gitDir, "info"), { recursive: true });
appendFileSync(excludePath, ".codegraph\n");

On the affected machine, D:\TTS\.git was created at 10:17:14 as an invalid marker. At 17:27:30, after CodeGraph startup, its only content became .git/info/exclude with the 11-byte value .codegraph\n. The top-level .git creation predates the CodeGraph write, so CodeGraph did not create the marker but did mutate and preserve the invalid structure.

Evidence

Root Cause

Repository validity is reduced to existsSync(<workspace>/.git). This does not distinguish a valid repository from an empty sandbox-created directory, and it does not handle linked worktrees where .git is a file. The helper then creates repository-internal paths before Git has validated or resolved them.

Proposed Fix

  1. Ask Git to validate and resolve the path, for example with a bounded git -C <workspace> rev-parse --git-path info/exclude after confirming --is-inside-work-tree.
  2. Do not call mkdirSync or appendFileSync when validation fails.
  3. Use the Git-resolved exclude path so linked worktrees are handled correctly.
  4. Add regression tests for an empty .git directory, a normal repository, and a linked worktree whose .git is a file.

Verification Plan

  • Given an empty .git, the hook returns a skipped/not-repository result and leaves the filesystem unchanged.
  • Given a valid repository, .codegraph is added once to the Git-resolved exclude file.
  • Given a linked worktree, the exclude entry is written to the correct common/worktree Git path without replacing the .git file.
  • Re-running SessionStart remains idempotent.

This issue or PR was generated by LazyCodex.
Tag: lazycodex-generated

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