Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Support Git sparse-index sdir required index extension #7260

@DavidTeju

Description

@DavidTeju

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:

True

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions