Version tested
Repro'd against libgit2 main:
- Repository: https://github.com/libgit2/libgit2
git describe --tags --always --dirty: d23f18f
- Commit:
d23f18fd881b8c5bb5e7a7abfcbc71ddf0c9a5ea
- Build environment: Windows, Visual Studio 2022 compiler, CMake + Ninja from Visual Studio
Summary
libgit2 fails to open a Git index that contains Git's sparse-index sdir required extension.
Observed error from git_repository_index on main:
git_repository_index failed: unsupported mandatory extension: 'sdir'
The same repository works with the Git CLI. The failure occurs when libgit2 reads the repository index.
This matters for large monorepos that rely on cone-mode sparse checkout plus sparse-index. Temporarily disabling sparse-index works around the failure, but it can be expensive because the index expands to include all paths at HEAD instead of scaling with the sparse-checkout cone.
Minimal repro steps
The following creates a small repository whose index contains sparse-directory entries and the sdir extension:
git init sdir-repro
cd sdir-repro
git config user.name 'Sparse Index Repro'
git config user.email '[email protected]'
printf 'initial\n' > initial.txt
git add initial.txt
git commit -m 'initial'
for i in $(seq 1 200); do
mkdir -p "src/dir$i"
printf 'base %s\n' "$i" > "src/dir$i/file$i.txt"
done
git add src
git commit -m 'seed sparse base tree'
git checkout -b feature/sparse-index
printf 'base 1\nfeature line\n' > src/dir1/file1.txt
git commit -am 'feature dir1'
git sparse-checkout init --cone --sparse-index
git sparse-checkout set src/dir1
printf 'base 1\nfeature line\nreview fix\n' > src/dir1/file1.txt
git add src/dir1/file1.txt
Confirm that the index contains sdir:
python - <<'PY'
from pathlib import Path
print(b'sdir' in Path('.git/index').read_bytes())
PY
This prints:
Minimal libgit2 reproducer
From inside the repro repository above, a minimal libgit2 consumer only needs to open/read the index:
#include <git2.h>
#include <stdio.h>
int main(void)
{
git_repository *repo = NULL;
git_index *index = NULL;
const git_error *err;
int rc;
git_libgit2_init();
rc = git_repository_open_ext(&repo, ".", 0, NULL);
if (rc < 0) {
err = git_error_last();
fprintf(stderr, "git_repository_open_ext failed: %s\n",
err ? err->message : "unknown error");
git_libgit2_shutdown();
return 1;
}
rc = git_repository_index(&index, repo);
if (rc < 0) {
err = git_error_last();
fprintf(stderr, "git_repository_index failed: %s\n",
err ? err->message : "unknown error");
git_repository_free(repo);
git_libgit2_shutdown();
return 1;
}
printf("index entries: %u\n", (unsigned)git_index_entrycount(index));
git_index_free(index);
git_repository_free(repo);
git_libgit2_shutdown();
return 0;
}
Actual result on main
The repro repository contains sdir, the C reproducer compiles, and running it against libgit2 main fails:
indexContainsSdir=True
compileExit=0
git_repository_index failed: unsupported mandatory extension: 'sdir'
reproExit=1
Expected behavior
libgit2 should support reading sparse-indexes containing the required sdir extension, either by safely expanding sparse-directory entries to a full in-memory index where necessary or by making the relevant index APIs sparse-index aware.
Current workaround
Temporarily disable sparse-index, run the libgit2-backed tool, then restore sparse-index:
git sparse-checkout reapply --no-sparse-index
# run libgit2-backed tool
git sparse-checkout reapply --sparse-index
This preserves sparse-checkout patterns, but it can be costly in very large monorepos.
Related references
Version tested
Repro'd against libgit2
main:git describe --tags --always --dirty:d23f18fd23f18fd881b8c5bb5e7a7abfcbc71ddf0c9a5eaSummary
libgit2 fails to open a Git index that contains Git's sparse-index
sdirrequired extension.Observed error from
git_repository_indexonmain:The same repository works with the Git CLI. The failure occurs when libgit2 reads the repository index.
This matters for large monorepos that rely on cone-mode sparse checkout plus sparse-index. Temporarily disabling sparse-index works around the failure, but it can be expensive because the index expands to include all paths at
HEADinstead of scaling with the sparse-checkout cone.Minimal repro steps
The following creates a small repository whose index contains sparse-directory entries and the
sdirextension:Confirm that the index contains
sdir:This prints:
Minimal libgit2 reproducer
From inside the repro repository above, a minimal libgit2 consumer only needs to open/read the index:
Actual result on
mainThe repro repository contains
sdir, the C reproducer compiles, and running it against libgit2mainfails:Expected behavior
libgit2 should support reading sparse-indexes containing the required
sdirextension, either by safely expanding sparse-directory entries to a full in-memory index where necessary or by making the relevant index APIs sparse-index aware.Current workaround
Temporarily disable sparse-index, run the libgit2-backed tool, then restore sparse-index:
git sparse-checkout reapply --no-sparse-index # run libgit2-backed tool git sparse-checkout reapply --sparse-indexThis preserves sparse-checkout patterns, but it can be costly in very large monorepos.
Related references