fix(extraction): keep git-aware scans working before Git 2.36 (#1793)
Land upstream PR #1604 by @maxmilian from commit
27c149524d968485164fb43bdec994fdb9323c75 on current main cece0720.
Fixes #1549.
Use the upstream lsFilesStaged helper at both collection and embedded-repo
discovery call sites. Retry without --recurse-submodules when staged
recursive listing fails, retaining the mode bits needed for gitlinks.
Keep the upstream regression test byte-for-byte and preserve main's
existing extraction/watcher changes, including #1728. Resolve the
changelog conflict with a concise Unreleased entry, and keep the existing
collectGitFiles documentation attached to its function.
Verified on Linux x86_64 with Node 22.19.0 and Git 2.47.3:
- The unchanged upstream test fails against main: expected [ 'a.ts' ]
to include 'dir_b/b.ts'; it passes with the fix.
- The same persistent fixture under a PATH shim rejecting -s with
--recurse-submodules (exit 128) changes scanDirectory from [a.ts]
to [a.ts, dir_b/b.ts], and gitlink watcher roots from [] to [lib/].
- Real-Git controls return both files and the watcher root in both arms.
- 69 related scope/config tests and 23 extraction scanning tests pass.
- npx tsc --noEmit passes.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-authored-by: newshowardz777 <newshowardz777@users.noreply.github.com>
This commit is contained in:
co-authored by
Colby McHenry
Max Hsu
newshowardz777
parent
cece0720e3
commit
a961491cea
+26
-4
@@ -925,9 +925,7 @@ export function discoverEmbeddedRepoRoots(rootDir: string): string[] {
|
||||
// same way collectGitFiles does, keeping watcher scope == indexer scope.
|
||||
// (#1031, #1033)
|
||||
try {
|
||||
const staged = execFileSync(
|
||||
'git',
|
||||
['ls-files', '-z', '-s', '--recurse-submodules'],
|
||||
const staged = lsFilesStaged(
|
||||
{ cwd: repoAbs, encoding: 'utf-8', timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true }
|
||||
);
|
||||
const repoIgnore = buildDefaultIgnore(repoAbs);
|
||||
@@ -1040,6 +1038,30 @@ function findIgnoredEmbeddedRepos(repoDir: string, includeIgnored: Ignore | null
|
||||
return repos;
|
||||
}
|
||||
|
||||
/**
|
||||
* `git ls-files -z -s`, expanding submodules where git allows it.
|
||||
*
|
||||
* `--recurse-submodules` could not be combined with `-s` before git 2.36:
|
||||
* `builtin/ls-files.c` listed `show_stage` among the modes that die, and the
|
||||
* check is unconditional — it does not look at whether the repo actually has
|
||||
* submodules, so every call fails on older git. Ubuntu 22.04 LTS (2.34.1) and
|
||||
* Debian 11 (2.30.2) are both below that line.
|
||||
*
|
||||
* Letting the throw escape cost far more than submodule expansion: it unwound
|
||||
* the whole git-visible pass, so `includeIgnored`, gitlink recursion and the
|
||||
* `codegraph.json` include allowlist silently stopped applying and files went
|
||||
* missing from the index with no error (#1549). Retry without the flag instead
|
||||
* — `-s` is the part that matters here, since gitlink detection reads the mode
|
||||
* bits, and embedded repos are reached through the gitlink recursion anyway.
|
||||
*/
|
||||
function lsFilesStaged(gitOpts: Parameters<typeof execFileSync>[2]): string {
|
||||
try {
|
||||
return execFileSync('git', ['ls-files', '-z', '-s', '--recurse-submodules'], gitOpts) as unknown as string;
|
||||
} catch {
|
||||
return execFileSync('git', ['ls-files', '-z', '-s'], gitOpts) as unknown as string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect git-visible files (tracked + untracked, .gitignore-respected) from the
|
||||
* git repository rooted at `repoDir`, adding each to `files` with `prefix`
|
||||
@@ -1085,7 +1107,7 @@ function collectGitFiles(repoDir: string, prefix: string, files: Set<string>, em
|
||||
// on disk → those files are silently dropped from the index. (#541) With -s the
|
||||
// path follows a TAB after the `<mode> <object> <stage>` prefix.
|
||||
const gitlinkRels: string[] = [];
|
||||
const tracked = execFileSync('git', ['ls-files', '-z', '-s', '--recurse-submodules'], gitOpts);
|
||||
const tracked = lsFilesStaged(gitOpts);
|
||||
for (const entry of tracked.split('\0')) {
|
||||
if (!entry) continue;
|
||||
const tab = entry.indexOf('\t');
|
||||
|
||||
Reference in New Issue
Block a user