Skip to content

[BUG] Checkpoints nested-repo detection misses submodule/worktree .git files and can false-positive via symlink follow #11340

@0xMink

Description

@0xMink

Summary

ShadowCheckpointService.getNestedGitRepository() has three correctness issues that cause it to miss nested git repositories (false negatives) or incorrectly detect repositories outside the workspace (false positives).

Impact

  • False negatives: Git submodules and worktrees use a .git file (not directory) containing a gitdir: pointer. The current search pattern (**/.git/HEAD) only finds .git directories. Submodule/worktree-style nested repos are completely missed, allowing checkpoints to initialize when they should be disabled.
  • False positives: The --follow flag causes ripgrep to traverse symlinks outside the workspace boundary, potentially detecting git repositories that are not actually nested in the workspace.
  • Brittle path matching: The current filter uses includes(".git/HEAD") and startsWith(".git/") for path classification, which is imprecise across platforms and path formats.

Reproduction

False negative (submodule case):

  1. Create a workspace with a git submodule (the submodule directory will contain a .git file with gitdir: ... content instead of a .git directory)
  2. Initialize checkpoints
  3. Observe that the nested repo is not detected and checkpoints proceed

False positive (symlink case):

  1. Create a workspace containing a symlink that points to a directory outside the workspace
  2. The external directory (or its ancestors) contains a .git repository
  3. Initialize checkpoints
  4. Observe that --follow causes ripgrep to traverse the symlink and detect the external repo as "nested"

Expected behavior

  • Nested repos inside the workspace are detected consistently, regardless of whether they use a .git directory or a .git pointer file
  • Paths outside the workspace are not considered
  • Root-level .git (directory or file) is excluded from detection

Actual behavior

  • .git pointer files (submodules/worktrees) are missed entirely
  • --follow can cause out-of-workspace matches
  • String-based path matching is fragile across separator styles and relative/absolute path variations

Related issues and prior art

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions