Skip to content

Conversation

@derrickstolee
Copy link
Contributor

@derrickstolee derrickstolee commented Jan 18, 2026

This PR adds support for the new git config-batch command to significantly improve config read performance on Windows platforms. The implementation uses a single persistent process for multiple config reads, reducing process spawn overhead.

Related Git PR: gitgitgadget/git#2033

I'll be submitting this soon as an RFC and we'll see how the protocol changes during review, so we don't need to over-index on that implementation at the moment. The most important thing is that it actually works to solve a problem we have right now.

I also noticed during the implementation that our interface with git config is much more varied based on the IGitConfiguration interface. This gives some interesting directions for extending the git config-batch command list very quickly. If not all endpoints are possible in the first version, then we'll need to have a more detailed fallback story on a per-method basis. The git config-batch protocol has a way of reporting that it doesn't understand a command you gave it, which would allow us to try a new method and fall back if the user hasn't upgraded.

This change creates GitBatchConfiguration which implements the IGitConfiguration and contains a child _fallback implementation that uses the standard one-process-per-request model. For interactions that are known to not work with my git config-batch draft, it's a simple pass-through.

However, the TryGet() method is able to check for the process to work.

We lazy-load the process so it doesn't attempt starting one until some config is requested. If git config-batch fails to run, then we mark the class state as not being compatible and go straight to the fallback mechanism.

The git config-batch command will exit when an empty line is read or when stdin closes, so we don't need to watch it too closely as our git-credential-manager process dies.

There are thread-safe locks so we do not get parallel reads interfering with our writing to or reading from the singleton git config-batch process. These locks should be extremely short after the initial process startup.

Performance Results

All tests performed on Windows using a test copy of my Git branch, merged with microsoft/git.

Table 1: Core Performance Benchmarks

Test Scenario Batch Time Traditional Time Speedup Improvement
Integration Test (20 reads) 75ms 590ms 7.87x 515ms
Monorepo (15 keys × 3 iterations) 42ms 601ms 14.31x 559ms
Sequential Reads (50 reads) 293ms 1463ms 4.99x 1170ms
Credential Operation (18 keys) 43ms 706ms 16.42x 663ms
Optimal Conditions (20 reads) 48ms 984ms 20.50x 936ms

Table 2: Real-World Impact on Azure DevOps Repository

Testing performed on a production Azure DevOps monorepo with typical credential configuration.

Operation Type Config Reads Batch Time Traditional Time Time Saved
Credential lookup 18 keys 43ms 706ms 663ms
Monorepo benchmark 15 keys 42ms 601ms 559ms

Impact: Every git fetch, git push, and git clone operation requiring credentials will be ~660ms faster.

Note that this gets even better when using the microsoft/git fork and the GVFS Protocol, as each instance of git-gvfs-helper gets its own credential interactions and is separate from the info/refs authentication, so these improvements stack across a complicated process such as git pull that runs git fetch and git merge (not to mention possible customizations that run git fetch and git sparse-checkout set within the post-command hook). I did not do extensive end-to-end testing on these cases as they are difficult to repeat. However, in my local enlistment I was looking at telemetry and saw as much as 20 seconds spent in git-credential-manager in a single git pull process without any user prompts causing delays.

Table 3: Speedup Summary by Workload

Workload Type Number of Reads Speedup Range Best Case
Small workload 5-20 reads 7.87x - 20.50x 20.50x
Medium workload 20-50 reads 4.99x - 16.42x 16.42x
Large workload 50+ reads 4.99x+ 14.31x

Test Execution

All tests can be run using:

# All batch configuration tests
dotnet test --filter "FullyQualifiedName~GitBatchConfiguration"

# Integration tests only (requires git config-batch)
dotnet test --filter "FullyQualifiedName~GitBatchConfigurationIntegrationTests"

# Performance benchmarks
dotnet test --filter "FullyQualifiedName~GitConfigPerformanceBenchmark"

# Credential scenarios
dotnet test --filter "FullyQualifiedName~GitConfigCredentialScenarioTest"

derrickstolee and others added 2 commits January 17, 2026 22:20
Implements GitBatchConfiguration to use the new 'git config-batch' command
for reading config values through a single persistent process, reducing
process spawn overhead especially on Windows platforms.

The implementation maintains full backward compatibility by:
- Automatically falling back to individual git config calls when
  config-batch is not available
- Using fallback for operations not yet supported by config-batch v1
  (typed queries, enumeration, regex, write operations)
- Gracefully handling errors and process failures

Includes comprehensive test coverage (12 tests) verifying fallback
behavior and correctness across all configuration operations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Adds comprehensive integration tests that verify git config-batch
functionality with real Git processes containing the config-batch command.

Performance benchmarks demonstrate significant improvements:
- 7.87x speedup on test repositories (20 config reads)
- 14.31x speedup on office repository (15 keys × 3 iterations)
- 16.42x speedup for credential operations (18 keys)
- 4.99x speedup for sequential reads (50 reads)
- Up to 20.50x speedup in optimal conditions

Real-world impact: Each credential operation (fetch/push/clone) is
~660ms faster on Windows with git config-batch support.

Integration tests verify:
- Batch process initialization and reuse
- Multiple queries producing correct results
- Different configuration scopes (local, global, all)
- Performance comparison between batch and traditional methods

Also fixes disposal check to occur before fallback path, ensuring
ObjectDisposedException is thrown consistently when using disposed objects.

All 30 tests passing (16 batch config + 12 fallback + 2 credential scenarios).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
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