Skip to content

includeIgnored silently bypassed on older git (<2.34): git ls-files -s --recurse-submodules fails, falls back to filesystem walk that ignores the opt-in #1549

Description

@newshowardz777

Summary

On systems with older git (verified failing on git 2.25.1 / Ubuntu 20.04; working on git 2.34.1+ / Ubuntu 22.04/24.04/26.04), codegraph index silently drops files that should be pulled in via codegraph.json 's includeIgnored . The user gets no error — just a smaller index. Same project, same codegraph.json , same codegraph version (1.5.0) indexes correctly on newer git.

Environment

  • codegraph: @colbymchenry/codegraph 1.5.0
  • OS: Ubuntu 20.04 LTS
  • git: 2.25.1 (fails) — works on 2.34.1+ (Ubuntu 22.04/24.04/26.04)
  • Node: 20.x
  • engines in package.json only constrains Node ( >=20.0.0 <25.0.0 ); no minimum git version is declared.

Reproduction

Minimal project ( t1/ ):

On Ubuntu 20.04 / git 2.25.1:

On Ubuntu 22.04 / git 2.34.1 (same repo, same codegraph 1.5.0):

Root cause

Both call sites run git ls-files -z -s --recurse-submodules . On older git, --recurse-submodules only supports -c/--cached , not -s/--stage :
Call site 1 — collectGitFiles() (the indexing path, fatal )
No try/catch here → execFileSync throws (exit 128) → exception escapes → getGitVisibleFiles() catches it and return null → scanDirectory() falls back to scanDirectoryWalk() (the non-git filesystem walk). scanDirectoryWalk() only parses .gitignore and does not implement includeIgnored — that opt-in lives exclusively in the git path ( findIgnoredEmbeddedRepos() , called from collectGitFiles() ), which never runs. dir_b is gitignored → skipped → only a.c is indexed.

Net effect: on older git the entire includeIgnored mechanism is silently disabled, and because the failure is swallowed into a "non-git project" fallback, the user gets no diagnostic — just missing files.
Call site 2 — discoverEmbeddedRepoRoots() (the watcher scope, non-fatal but inconsistent )
This one is already wrapped in try/catch, so on older git the gitlink discovery pass is silently skipped (unexpanded gitlinks → not found). Non-fatal, but it means the watcher scope diverges from the indexer scope on older git: the indexer (once site 1 is fixed) recurses into gitlinks via collectGitFiles() , while the watcher's discoverEmbeddedRepoRoots() misses them.

Impact

Any project relying on includeIgnored to index embedded/gitignored repos is silently mis-indexed on older git. The super-repo-of-clones layout (the very use case includeIgnored exists for, per issues #622/#699/#514) is affected — and in particular embedded repos tracked as gitlinks (mode 160000, without .gitmodules ) are missed by the watcher on old git even after site 1 is fixed. No warning or error is surfaced in either case.

Suggested fix

Wrap both call sites in a try/catch and fall back to git ls-files -z -s (drop --recurse-submodules ) when the combined form is unsupported.

Site 1 — collectGitFiles() :

Site 2 — discoverEmbeddedRepoRoots() :
Why the -s fallback is safe

  • -s keeps the \t format, so the existing 160000 gitlink detection still works.
  • Without --recurse-submodules , active submodules surface as 160000 gitlinks and are recursed into by the existing gitlink pass at the end of collectGitFiles() ( classifyGitDir(...) === 'embedded' covers submodule checkouts). So active submodules are still indexed.
  • Embedded independent repos (the dir_b case — untracked, not a gitlink) are still discovered by the untracked trailing-slash pass and findIgnoredEmbeddedRepos() , so includeIgnored works again. Verification
    Applied to the packaged lib/dist/extraction/index.js on Ubuntu 20.04 / git 2.25.1:
  • $ codegraph index .
    ◆  Indexed 2 files        # a.c + dir_b/b.c  ✓
    $ codegraph files
    ├── dir_b
    │   └── b.c (c, 2 symbols)
    └── a.c (c, 2 symbols)
    

    Behavior on newer git is unchanged (the try branch still runs the original command).

    Alternatives considered

    • Declare a minimum git version (e.g. ≥2.34) and error out clearly on older git. This avoids the silent-misindex UX but excludes Ubuntu 20.04 LTS users entirely; the graceful fallback above is strictly better for compatibility.
    • Fall back to git ls-files -z -c --recurse-submodules (which old git supports). Rejected: -c omits mode bits, breaking 160000 gitlink detection, so the gitlink pass would stop finding unexpanded submodules. The -s fallback keeps mode bits.

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