Skip to content

config: mark as sparse-index compatible#2134

Draft
spkrka wants to merge 2 commits into
gitgitgadget:masterfrom
spkrka:sparse-config-fix
Draft

config: mark as sparse-index compatible#2134
spkrka wants to merge 2 commits into
gitgitgadget:masterfrom
spkrka:sparse-config-fix

Conversation

@spkrka
Copy link
Copy Markdown

@spkrka spkrka commented Jun 1, 2026

Summary

git config --blob :.lfsconfig (and similar :path lookups) triggers
ensure_full_index() in sparse checkouts, expanding the entire sparse
index to a full index. On large repositories this takes seconds even
though the command only needs to look up a single path.

This is because git config was never added to the list of commands
that are sparse-index compatible. The fix follows the same pattern used
by ~30 other commands: set command_requires_full_index = 0.

The one wrinkle is that git config uses RUN_SETUP_GENTLY, which
does not call the default config callbacks that populate the sparse
checkout globals (core.sparseCheckout, core.sparseCheckoutCone).
Without those globals, is_sparse_index_allowed() returns false and
the index is expanded on read. Adding a repo_config() call (guarded
by startup_info->have_repository) fixes this. The call is cached and
free when config is already loaded.

Benchmark (388K-file monorepo, 7K sparse index entries)

Operation Before After Speedup
git config --blob :.lfsconfig 3.36s 0.01s 336x
git lfs post-checkout (calls the above) 3.35s 0.06s 56x

This matters in practice because git-lfs runs
git config --blob :.lfsconfig during every post-checkout hook
invocation, making sparse-checkout rebase/switch/checkout pay a
multi-second penalty on every operation.

Test plan

  • New test in t1092 verifies four cases:
    • Nonexistent root-level file: no expansion
    • Valid config at root: no expansion, values readable
    • Valid config inside sparse cone: no expansion, values readable
    • File outside sparse cone: expansion required (on-demand via index_name_pos)
  • Test fails without the fix, passes with it
  • All 498 t1300 (config) tests pass
  • All 105 t1092 (sparse-checkout-compatibility) tests pass

spkrka added 2 commits June 1, 2026 13:08
`git config --blob :.lfsconfig` (and similar :path lookups) triggers
ensure_full_index() in sparse checkouts, expanding the entire sparse
index to a full index. On large repositories this takes seconds even
though the command only needs to look up a single path.

The root cause has two parts:

1. `git config` uses RUN_SETUP_GENTLY and never calls repo_config(),
   so the sparse checkout globals (core.sparseCheckout,
   core.sparseCheckoutCone) are unset when the index is first read.

2. Without those globals, is_sparse_index_allowed() returns false,
   causing ensure_correct_sparsity() to call ensure_full_index()
   during do_read_index().

Fix this by loading repo config and setting command_requires_full_index
to 0 in cmd_config(). This is the standard opt-in pattern used by the
~30 other commands that are sparse-index compatible.

The repo_config() call is needed because RUN_SETUP_GENTLY does not
load the default config callbacks that populate the sparse checkout
globals. Other sparse-index-compatible commands use RUN_SETUP, which
handles this during setup_git_directory(). Note that this does not
introduce new failure modes for broken .git/config: the setup phase
under RUN_SETUP_GENTLY already parses enough config to fail on
syntax errors before cmd_config() runs.

The flag is safe to set unconditionally because git config only
accesses the index when resolving --blob :path specs. For non-blob
invocations, the flag has no effect. For --blob :path, in-cone paths
resolve directly from the sparse index; out-of-cone paths trigger
on-demand expansion through index_name_pos() with EXPAND_SPARSE.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Verify that `git config --blob :path` does not expand the sparse
index when the path is in-cone, and does expand when the path is
behind a sparse directory entry.

Uses valid config blobs (staged via git add) for the in-cone cases
to verify end-to-end correctness including config value parsing.

Add a separate test verifying that `git config --file` does not
trigger sparse index expansion, since it does not access the index
at all.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
@spkrka spkrka force-pushed the sparse-config-fix branch from d9c2686 to 21e2edd Compare June 1, 2026 11:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant