Skip to content

Share transient libgit2 config lookup helper#2066

Draft
tyrielv wants to merge 2 commits into
microsoft:masterfrom
tyrielv:tyrielv/shared-libgit2-config-lookup
Draft

Share transient libgit2 config lookup helper#2066
tyrielv wants to merge 2 commits into
microsoft:masterfrom
tyrielv:tyrielv/shared-libgit2-config-lookup

Conversation

@tyrielv

@tyrielv tyrielv commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add GVFS.Common.Git.LibGit2RepoExtensions.GetConfigBoolOrDefault(...) for transient config-only libgit2 reads
  • refactor short-lived config lookups to avoid LibGit2RepoInvoker object-store preload and duplicated open/try/catch/dispose code
  • cover helper happy-path and failure fallback behavior with unit tests

Motivation

LibGit2RepoInvoker.InitializeSharedRepo() intentionally forces an object-store probe so long-lived/shared callers can amortize object-store load costs. That is wasted work for one-off config reads that immediately dispose the repo. This change centralizes the short-lived config-read pattern behind a helper that opens a temporary LibGit2Repo, reads the config value, and falls back cleanly on InvalidDataException / LibGit2Exception.

Helper

Added GVFS/GVFS.Common/Git/LibGit2RepoExtensions.cs:

  • public static bool GetConfigBoolOrDefault(this LibGit2Repo repo, ITracer tracer, string key, bool defaultValue)
  • public static bool GetConfigBoolOrDefault(ITracer tracer, string repoPath, string key, bool defaultValue)

The path overload handles the transient open/dispose flow. The instance overload applies the same config-read fallback logic when a repo is already open.

Refactored call sites

  • GVFS/GVFS/CommandLine/CloneVerb.cs
    • before: created a short-lived LibGit2RepoInvoker just to read gvfs.trust-pack-indexes
    • after: uses the shared transient helper with enlistment.WorkingDirectoryBackingRoot
  • GVFS/GVFS.Hooks/Program.cs
    • before: created a short-lived LibGit2RepoInvoker just to read gvfs.show-hydration-status
    • after: uses the shared transient helper
  • GVFS/GVFS.Mount/InProcessMount.cs
    • before: hand-rolled LibGit2Repo + try/catch for gvfs.background-cache-auth
    • after: uses the shared transient helper
  • GVFS/GVFS/CommandLine/PrefetchVerb.cs
    • before: hand-rolled LibGit2Repo + try/catch for gvfs.prefetch-offload
    • after: uses the shared transient helper
  • GVFS/GVFS.Hooks/GVFS.Hooks.csproj
    • links the new shared helper into the hooks build (that project consumes selected GVFS.Common source files directly rather than via project reference)

Survey notes / intentionally left alone

I surveyed master for short-lived config-only LibGit2Repo / LibGit2RepoInvoker usage. The narrow transient call sites above were refactored. I left these alone intentionally because they are shared/long-lived repo access, not the transient anti-pattern:

  • GVFS/GVFS.Common/Maintenance/PrefetchStep.cs
  • GVFS/GVFS.Common/GitStatusCache.cs
  • GVFS/GVFS.Common/Git/GitRepo.cs

Open PR FYI (not modified here)

These branches are already under active PR review, so this PR only flags them for maintainers/reviewers:

  • Fix NullReferenceException when cloning into a non-empty directory #2065 Fix NullReferenceException when cloning into a non-empty directory by @tyrielv
    • contains the same transient config-only LibGit2Repo pattern in CloneVerb.GetTrustPackIndexes(...) as a one-off local fix on that branch
    • if this helper lands first, that PR could optionally switch to it in a follow-up/rebase

Validation

  • dotnet build GVFS\GVFS.UnitTests\GVFS.UnitTests.csproj -c Debug
  • out\GVFS.UnitTests\bin\Debug\net10.0-windows10.0.17763.0\win-x64\GVFS.UnitTests.exe
    • Result: 889 passed, 0 failed, 11 skipped

tyrielv added 2 commits July 15, 2026 11:50
Add a shared helper for transient config-only LibGit2Repo usage and switch short-lived call sites away from LibGit2RepoInvoker/object-store preload or duplicated try/catch blocks.

Assisted-by: GPT-5
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Replace the standalone LibGit2RepoExtensions static class with instance
and static GetConfigBoolOrDefault methods directly on LibGit2Repo. This
matches the existing repo.GetConfigBoolOrDefault(name, default)
convention already documented in AGENTS.md and used by
LibGit2RepoInvoker, and avoids an unnecessary extension-method
indirection for a class we own in the same assembly.

Also fixes a regression reintroduced by the earlier refactor: CloneVerb
called LibGit2Repo.GetConfigBoolOrDefault using enlistment.WorkingDirectoryBackingRoot
unconditionally, even when TryCreateEnlistment failed and enlistment was
null. The call is now correctly gated on cloneResult.Success.

Added a protected LibGit2Repo(ITracer tracer) constructor so test
doubles can inject a mock tracer and assert on RelatedWarning calls
from the new instance method, and rewrote the test file accordingly.

Assisted-by: Claude Sonnet 5
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
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