Skip to content

Release M279.4 - #2107

Closed
tyrielv wants to merge 27 commits into
releases/shippedfrom
milestones/M279.4
Closed

tyrielv wants to merge 27 commits into
releases/shippedfrom
milestones/M279.4

Conversation

@tyrielv

@tyrielv tyrielv commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Changes:

tyrielv and others added 27 commits August 7, 2026 15:43
When a packfile in the shared object cache is corrupt or truncated (e.g. from a
past disk-full event), 'git multi-pack-index write/verify' fails with "could not
load pack N". The existing self-heal only deletes and rewrites the
multi-pack-index (MIDX), which does not fix the underlying pack: the rewrite
re-scans the same bad pack and keeps failing. The corruption then recurs
indefinitely.

PackfileMaintenanceStep now routes write/verify failures through a recovery path
that, when git reports a pack-load failure:

  - Detection (always runs, even with recovery disabled): verifies each pack in
    the object cache with 'git verify-pack' and reports every unreadable pack via
    telemetry (Operation=FoundCorruptPack). The "could not load pack N" ordinal is
    an internal MIDX position, not a filename, so per-pack verification is how we
    find the actual bad file.
  - Removal (gated, see kill switch below): deletes each corrupt pack's files
    (.pack/.idx/.keep/.rev; Operation=DeletedCorruptPack), then deletes and
    regenerates the MIDX from the packs that remain (fast path, no full repack).
    Missing objects are re-fetched on demand.
  - Corrupt prefetch pack (special case): prefetch packs are incremental and
    ordered by timestamp, so a corrupt one invalidates every later prefetch pack
    too - leaving a hole would let the newest surviving timestamp advance past it
    so a later prefetch never backfills the gap. Recovery removes the corrupt
    prefetch pack and every later prefetch pack
    (Operation=DeletedHealthyPrefetchPack for the healthy ones removed purely due
    to ordering), then requests a prefetch (via a callback GitMaintenanceScheduler
    wires to a PrefetchStep, only when using a cache server) to re-download them
    and rebuild the commit-graph.

Kill switch: the destructive pack removal is gated by a new git config,
gvfs.enable-packfile-recovery (default true). When false, GVFS still detects and
reports corrupt packs (Operation=FoundCorruptPack, then
CorruptPackRecoverySkipped) but deletes nothing and does not request a prefetch;
the non-destructive MIDX rewrite still runs, so behavior degrades to today's.
This gives a field kill switch without a redeploy if the destructive path ever
misbehaves.

This is stacked on the git-output bounding change: recovery runs additional git
commands (verify-pack, MIDX rewrites) against the corrupt repo, so it relies on
that change to keep a noisy stderr from OOM-ing the mount mid-recovery.

Review follow-ups:
  - prefetchRestoreNeeded is now set only after a corrupt prefetch pack is
    actually removed (RemovePackFileSet returns whether the .pack file was
    deleted), instead of as soon as one is detected. If deletion is blocked,
    the restore no longer runs while the corrupt pack is still present.
  - DetectAndRemoveCorruptPacks now remembers, for the lifetime of a single
    maintenance run, that it already reported corrupt packs with recovery
    disabled, and skips the redundant per-pack verify-pack rescan on later
    MIDX failures in that same run.
  - DetectAndRemoveCorruptPacks now parses the corrupt pack's filename directly
    out of the write/verify failure's stderr when git includes it (e.g.
    "packfile pack-1234.pack does not match index" / "wrong index v2 file size
    in pack-1234.idx"), and verifies only that candidate instead of every pack
    in the object cache. This only helps when git actually names the file,
    which it does for the verify-triggered failures this code mostly handles
    (not for the rarer write-path "could not load pack N", which is genuinely
    an unresolvable internal ordinal - confirmed by reading git's midx-write.c).
    Falls back to verifying every pack whenever no candidate can be parsed, or
    the parsed candidate turns out to be healthy, so detection is never less
    thorough than before.

Tests:
  - A verify failure reporting a pack-load error removes the corrupt pack and
    rewrites the MIDX from the remaining good packs (recovery enabled).
  - With recovery disabled, the same failure still verifies each pack and reports
    the corrupt one but deletes nothing.
  - A corrupt prefetch pack removes it and every later prefetch pack, keeps the
    earlier healthy one, and requests a prefetch.
  - A verify failure that names the corrupt pack directly verifies only that
    pack (fast path).
  - A verify failure that names a pack which turns out to be healthy falls back
    to verifying every pack (fallback path).

Assisted-by: Claude Sonnet 5
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
GVFS erased a valid credential when an object-download response was HTTP 400,
which triggered a storm of Git Credential Manager popups.

A 400 is a request or formatting problem, not an authentication failure. An
expired or invalid credential always returns 401 (Unauthorized) or 302 (the
Azure DevOps sign-in redirect), never 400. Treating 400 as an auth failure
erased good credentials and produced the misleading "Your PAT may be expired"
message.

Remove BadRequest (400) from the credential-rejection branch in SendRequest.
Only 401 and 302 now reject credentials; 400 flows through the generic,
non-auth error path (unchanged retry / circuit-breaker behavior, and 400
remains non-retryable). Extract the decision into ShouldRejectCredentials so it
is unit tested: 400 does not reject credentials, while 401 and 302 still do.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
…"auth required" body

An earlier change dropped HTTP 400 from the credential-rejection branch entirely,
on the premise that a 400 is never an authentication failure. That premise is
incomplete. The Azure DevOps GVFS cache server returns a 400 (not a 401) in one
genuine authentication case: when the request carried no parseable Basic
Authorization header. Its response body is "A valid Basic Authorization header is
required." microsoft/git's git-gvfs-helper maps that same cache-server 400 to a
401 for this reason, and its own TODO says to confirm the response body - which is
what this change does.

A present-but-expired or invalid credential still returns 401, and a malformed
request (for example a corrupt object SHA in the loose-object URL) returns a 400
that has nothing to do with credentials. So the decision is now body-aware:

- 401 and 302 always reject credentials.
- 400 rejects credentials only when the body matches the cache server's
  auth-required message (case-insensitive substring).
- Every other 400 (and 404/5xx/timeouts) does not reject credentials.

This stops the credential-manager popup storm caused by rejecting a valid
credential on a non-auth 400, while preserving credential refresh for the one 400
that really does mean "authentication required", keeping the behavior consistent
with git-gvfs-helper.

Tests updated for the new body-aware signature and cases.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Pin GitHub Actions to full-length commit SHAs
…als-on-400

HttpRequestor: do not reject credentials on HTTP 400
…overy

Auto-recover corrupt packfiles in packfile maintenance
The upgrade test job selected the last-known-good installer with
`(Get-ChildItem gvfs-lkg\SetupGVFS*.exe).FullName`. Releases now publish
both an x64 and an arm64 installer, so the glob matches two files and
`.FullName` returns an array. `Start-Process -FilePath` then fails with
"Cannot convert 'System.Object[]' to the type 'System.String'".

Select the x64 installer explicitly. The x64 installer has no
architecture suffix; the arm64 one is named `SetupGVFS.<version>-arm64.exe`.
These tests run on an x64 runner and download the x64 "new" installer, so
the x64 LKG installer is the correct match. Apply the same guard to the
"new" installer selection and throw a clear error if no x64 installer is
present.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Address self-review feedback on the multi-installer fix. Replace the
`-arm64` denylist plus `Select-Object -First 1` with a shared
`Select-X64Installer` helper that positively matches the x64 asset by its
suffix-less name (`SetupGVFS.<version>.exe`) and requires exactly one match.

The denylist would still pass a future non-x64 asset (for example a `-x86`
or `-arm` installer) and `-First 1` would then pick an arbitrary file. The
positive allowlist matches the documented x64 naming contract and fails
loudly when the directory holds an unexpected number of installers. The
helper also removes the duplicated filter across the LKG and new installer
selection, and its error message reports the directory and the files found.

Note in a comment that arm64 upgrade is not exercised here because the
runner is x64.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Fix upgrade tests when the LKG release has multiple installers
When a functional test fails because its GVFS.Mount is unreachable (a hang or
silent exit), we currently have no post-mortem data. Per-test enlistment
inlined into the console by TestResultsHelper.OutputGVFSLogs -- lossy under
parallel fixtures and empty when the mount hung. There is no process dump, so a
mount deadlock leaves zero diagnostic signal.

On test failure only, into a CI-uploadable diagnostics directory:
GVFSFunctionalTestEnlistment.CaptureFailureDiagnostics runs first in
DeleteEnlistment, gated on TestStatus.Failed, before the enlistment directory is
deleted. The mount-process PID discovery is extracted from KillMountProcess into
a shared GetMountProcessIds helper.

CI: functional-tests.yaml sets GVFS_TEST_DIAGNOSTICS_DIR and uploads it as a
FailureDiagnostics artifact with if: always().

Review follow-ups:
- GetMountProcessIds doubled the backslashes in the enlistment path before
  using it in a PowerShell -like wildcard. In -like, '\' is a literal (not an
  escape), so the doubled pattern never matched a real single-backslash
  command line: CaptureFailureDiagnostics found no live mount and wrote no
  minidump, and KillMountProcess silently killed nothing. Match on the
  enlistment's unique leaf folder id instead -- present on the GVFS.Mount
  command line (launched with PrimaryEnlistmentRoot), unique, and free of
  path separators or wildcard metacharacters, so it needs no escaping.
- WaitForExit(int) only guarantees the helper process has exited -- it does
  not guarantee the async OutputDataReceived callbacks (raised on the thread
  pool as data arrives) have all run yet. Reading the output buffer
  immediately afterward could race the last callback and intermittently drop
  a trailing PID, making GetMountProcessIds miss a live mount process. Call
  the parameterless WaitForExit() right after the timed wait succeeds to
  drain any pending async output callbacks before parsing.

Assisted-by: Claude Sonnet 5
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
GetDirectoryEnumeration logs "Failed to find active enumeration ID" when an
enumeration ID is absent. Every non-eviction miss carried the reason Unknown,
which hid two different causes:

- EndedRecently: ProjFS delivered a Get that raced or followed the End for the
  same enumeration (a benign kernel close/query race).
- NeverSeen: GVFS never held the ID (it never started, or it predates a
  provider restart).

The classification, the once-per-ID error de-duplication, and the bounded
tracking maps are extracted into a new EnumerationFailureTracker class
(mirroring the MissingTreeTracker pattern) so the policy is cohesive and unit
testable on its own. The tracker owns all three "why is this ID absent" maps -
recently evicted, recently ended, and recently reported - and exposes
RecordEvicted, RecordEnded, ClassifyMiss, and TryReserveReport. The virtualizer
records an end (and an eviction) before removing the ID from activeEnumerations,
so a racing Get always finds the ID in one collection or the other; ClassifyMiss
attributes Evicted (most actionable), then EndedRecently, then NeverSeen. The
old Unknown value is renamed NeverSeen.

When an End removes nothing from the active set and the ID was not evicted, GVFS
never actually held it, so the ended marker recorded before the removal is undone
(UndoEnded) - keeping the record-before-remove ordering for the normal path while
avoiding a later Get being skewed to EndedRecently for an ID that was never seen.

De-duplicate the error: a caller that re-enumerates a lost handle can emit the
same error a very large number of times on one machine. The tracker emits the
full error once per ID within a window; the first occurrence still logs at
Error, so the machine-based signal stays intact. The returned HResult does not
change.

The tracker prunes its maps on a throttle from every record point, so no map
can grow unbounded when one callback (e.g. End) stops arriving - the never-ended
scenario this instrumentation targets. It keeps lock-free ConcurrentDictionary
state; a coarse lock would serialize the hot enumeration path.

The EnumerationFailureReason values are a case-sensitive contract consumed by
the release-readiness telemetry dashboard; its cause bucketing must add
EndedRecently and NeverSeen.

Tests: EnumerationFailureTracker is unit-tested directly (classification,
Evicted-over-EndedRecently precedence, eviction undo, ended undo, dedup,
prune/retention); the virtualizer tests cover the wiring, the record-before-remove
ordering, the Evicted-over-EndedRecently precedence, and that an End for a
never-held ID does not skew a later Get to EndedRecently.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Add LibGit2Repo.GetConfigBoolOrDefault(...) (instance + static overloads) for
one-off boolean config reads, replacing scattered short-lived
LibGit2Repo/LibGit2RepoInvoker usage at 4 call sites:

- GVFS/CommandLine/CloneVerb.cs (gvfs.trust-pack-indexes)
- GVFS.Hooks/Program.cs (gvfs.show-hydration-status)
- GVFS.Mount/InProcessMount.cs (gvfs.background-cache-auth)
- GVFS/CommandLine/PrefetchVerb.cs (gvfs.prefetch-offload)

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.

The helper methods live directly on LibGit2Repo rather than a separate
extension class, matching the repo.GetConfigBoolOrDefault(name, default)
convention already documented in AGENTS.md, and avoiding unnecessary
indirection for a class the team owns in the same assembly. Both methods
fall back to defaultValue and log a RelatedWarning on any failure, matching
the "default on any failure" contract each call site previously implemented
independently.

Added a protected LibGit2Repo(ITracer tracer) constructor to support test
doubles that inject a mock tracer without opening a real repo.

Surveyed master for other short-lived config-only LibGit2Repo/
LibGit2RepoInvoker usage; PrefetchStep.cs, GitStatusCache.cs, and
GitRepo.cs were left alone because they use shared/long-lived repo access,
not the transient anti-pattern this change addresses.

Reviewed with an internal 6-lens review-swarm pass (correctness, security,
design, tests, async-parallelism, risk-rollout); addressed all actionable
findings:
- Widened the shared helper's exception handling to a plain catch
  (Exception), restoring the "default on any failure" guarantee
  InProcessMount/PrefetchVerb relied on before this refactor.
- Fixed a double-RelatedWarning log on the repo-open-failure path.
- Replaced a hardcoded, non-portable "Z:\..." path in a unit test with a
  GUID-suffixed temp path.
- Added test coverage for the unset-key (null-coalescing) branch and the
  InvalidDataException catch arm.
- Simplified the parameterless constructor to delegate to the
  tracer-accepting one.

Full unit test suite: 891 passed, 0 failed, 11 skipped (pre-existing,
unrelated).

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
…ookup

Share transient libgit2 config lookup helper
The GitCommands functional tests compare a GVFS repo against a plain "control"
git repo. Every control repo fetches from one machine-global bare cache. The
cache was set up in a static constructor that checked Directory.Exists and then
either cloned or fetched, and it discarded every git exit code.

That setup was not atomic and not verified. Fixtures run in parallel and the
cache path is shared by concurrent test processes on the same machine, so a
process could observe a half-built clone directory (Directory.Exists is true
before the clone finishes) and fetch from an incomplete repo. A transient
clone or fetch failure had the same effect. The cache was then left missing
branches, the failure was swallowed, and every GitCommands test failed its
setup checkout with:

    error: pathspec 'FunctionalTests/20201014' did not match any file(s) known to git

A local repro confirmed the cause: against a healthy cache 0/50 control-repo
builds fail; against a cache missing the branch 50/50 fail with that exact
error.

Make the setup robust:

- Serialize cache creation and refresh across processes with a system-wide
  mutex.
- Build the cache atomically: clone into a temporary directory, verify the
  base branch is present, then move it into place so no other process sees a
  partial cache.
- Retry transient clone and fetch failures, and rebuild the cache when
  verification fails.
- Fail loudly with a clear message when a control repo cannot fetch or check
  out its branch, and retry the whole control-repo build, instead of producing
  a broken repo that fails 20+ tests with a confusing cascade.

With the fix, a control repo that starts from a broken cache self-heals and
0/50 builds fail.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
The previous commit rebuilt the shared control-repo cache with "git clone
--bare". A --bare clone copies only refs/heads/* and tags. Some tests fetch
commits by SHA that live outside refs/heads (for example RebaseTests fetches
the tip of FunctionalTests/RebaseTestsSource_20170130). Those objects were
absent from a --bare cache, so the control repo's fetch failed with:

    fatal: git upload-pack: not our ref <sha>

and, now that Fetch throws on a non-zero exit, RebaseSmallOneFileConflict
failed on functional-test slice 4 (both architectures).

Rebuild the cache with "git clone --mirror" instead. --mirror maps
refs/*:refs/*, so the cache carries the complete ref set, matching the
refresh path's "fetch origin +refs/*:refs/*". A local test confirms a --bare
clone omits a non-refs/heads ref while a --mirror clone retains it.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
The prior commits regressed functional-test slice 4: RebaseTests fetch a
specific commit by SHA (for example 5d29951...), and those fetches failed
with "fatal: git upload-pack: not our ref". Two problems caused this.

1. The shared cache is machine-global and persistent on CI runners. It can
   hold commits reachable only from branches that upstream no longer
   advertises, which some tests still fetch by SHA. My EnsureSharedCache
   could rebuild (replace) that cache when a branch check or refresh looked
   wrong, which drops those commits. Decide fresh-build vs refresh by
   Directory.Exists (matching the original code), refresh an existing cache
   best-effort, and never delete or rebuild it.

2. upload-pack refuses to serve a SHA that is not an advertised ref tip
   unless the served repo allows it. Enable uploadpack.allowAnySHA1InWant
   (plus reachable and tip) on the cache so control repos can fetch any
   commit present in the cache by SHA.

Also make ControlGitRepo.Fetch tolerant again: it retries, but on final
failure it logs instead of throwing. Whether the cache can serve a given SHA
is a property of the cache, not the test; the test's own ValidateGitCommand
(control repo vs GVFS repo) remains the correctness gate. The loud failure
for a genuinely broken cache stays on the base-branch checkout in
Initialize, which is what caused the original swallowed cascade.

Fresh caches are still built with clone --mirror (complete ref set) into a
temporary directory and moved into place under a system-wide mutex, so no
process observes a half-built cache.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Capture mount dumps and preserve logs when a functional test fails
FunctionalTests: make shared control-repo cache setup resilient
Split enumeration-miss cause + extract EnumerationFailureTracker + de-duplicate error telemetry
Context:
The microsoft/git GVFS helper supports endpoint-specific cache servers so cache infrastructure can be migrated independently. VFS for Git previously sent every protocol request to one global URL.

Justification:
Use the same gvfs.<endpoint>.cache-server keys and clone option names as Scalar. Keeping endpoint preferences on CacheServerInfo centralizes precedence and lets mount-time cache resolution preserve the configured routes.

Implementation:
Load, persist, and validate overrides for prefetch, object GET, object POST, and sizes requests. Add matching clone options, retain the global cache as the default, preserve overrides while resolving cache identity, and cover configuration, CLI parsing, and mount resolution.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Context:
Endpoint-specific cache servers are preferences above the global cache, but failures previously terminated requests instead of using the healthy fallback route. Early fallback handling also charged abandoned attempts to the process-wide circuit breaker, confused cancellation with transport failure, and exposed excess URI data in telemetry.

Justification:
Treat route failover separately from transient retry accounting. Cancellation remains control flow, local processing errors stay on the active route, and network-body failures alone can move a request to the global cache. Authority-only metadata preserves diagnostics without exposing credentials or request details.

Implementation:
Fall back prefetch, object GET, object POST, and sizes requests through the global cache, with sizes retaining its final origin fallback. Track response-stream failures, preserve circuit-breaker budget across route transitions, propagate cancellation unchanged, validate endpoint URLs, and emit redacted fallback telemetry. Add focused coverage for HTTP, transport, body-read, local-write, cancellation, telemetry, and terminal failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Context:
Administrators need to understand how dedicated GVFS endpoint caches interact with the existing global cache and with gvfs cache-server commands.

Justification:
Documenting precedence and fallback behavior alongside the configuration keys makes staged cache migrations predictable and preserves the distinction between global and endpoint-specific settings.

Implementation:
Describe the clone options, local Git config keys, endpoint-to-global fallback order, the sizes-to-origin fallback, and troubleshooting guidance for inspecting or changing endpoint overrides.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Context:
The prefetch entry point now reports only URI authority when a request fails, but requestor-level tests did not execute the warning and unsupported-command telemetry paths that consume the terminal request URI.

Justification:
Exercise the production composition directly so future changes cannot reintroduce credentials, paths, queries, or fragments into prefetch failure diagnostics. These focused cases also raise changed-line coverage above the repository threshold without relying on incidental functional-test execution.

Implementation:
Add a deterministic prefetch requestor that returns terminal HTTP failures. Verify both general failure warnings and not-supported events emit only the host and port from a credential-bearing request URI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Why This Matters

The microsoft/git GVFS helper can route protocol endpoints to dedicated cache servers, but VFS for Git previously sent every protocol request to one global cache URL. Supporting the same endpoint-specific preferences lets cache infrastructure migrate incrementally without making a dedicated endpoint a hard dependency.

The `/gvfs/sizes` endpoint is unique to VFS for Git, so this change adds the corresponding `gvfs.sizes.cache-server` setting alongside the prefetch, GET, and POST settings used by Scalar.

## Commit Narrative

1. **Route GVFS endpoints to dedicated cache servers**: load, persist, and validate endpoint overrides; add matching `gvfs clone` options; preserve overrides during mount-time cache resolution.
2. **Fall back safely from dedicated cache endpoints**: retry failed endpoint requests through the global cache, preserve circuit-breaker budgets, distinguish network body failures from local processing errors, propagate cancellation unchanged, and emit authority-only telemetry.
3. **Explain endpoint-specific cache routing**: document configuration, precedence, fallback order, and troubleshooting.
4. **Cover prefetch failure telemetry redaction**: exercise terminal prefetch failures at the production entry point and ensure diagnostics retain only URI authority.

## Routing and Fallback Behavior

- `gvfs.prefetch.cache-server` routes `/gvfs/prefetch`.
- `gvfs.get.cache-server` routes object GET requests.
- `gvfs.post.cache-server` routes object POST requests.
- `gvfs.sizes.cache-server` routes `/gvfs/sizes`.
- If an endpoint-specific route is absent or fails, the request uses `gvfs.cache-server`.
- Sizes requests can additionally fall back from the global cache to origin.
- Existing repositories without endpoint overrides retain their previous behavior.

Endpoint-to-global transitions do not consume the process-wide circuit-breaker budget. Response-body transport failures can trigger fallback, while local processing failures remain on the current route. `OperationCanceledException` propagates without retry or fallback. Fallback and terminal prefetch diagnostics include only URI authority, excluding credentials, paths, queries, and fragments.

## Clone and Configuration Surface

`gvfs clone` accepts `--prefetch-cache-server-url`, `--get-cache-server-url`, `--post-cache-server-url`, and `--sizes-cache-server-url`. Values are stored in local Git config and malformed absolute URLs are rejected.

`gvfs cache-server --get` and `--set` continue to operate only on the global cache setting. Endpoint-specific values can be inspected or changed with `git config --local`.

## Related microsoft/git Changes

- [microsoft/git#836: gvfs-helper: add config to incrementally replace cache servers](microsoft/git#836)
- [microsoft/git#849: scalar: add endpoint cache-server clone options](microsoft/git#849)

## Tests

Coverage includes configuration precedence and persistence, mount-time resolution, clone option parsing and URL validation, endpoint/global/origin routing, HTTP and transport failures, response-body failures, local handler failures, cancellation propagation, telemetry redaction, terminal endpoint reporting, and circuit-breaker accounting.
Assisted-by: Auto

Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Disable Git fsmonitor in virtual repositories
@tyrielv
tyrielv enabled auto-merge September 16, 2026 15:42
@tyrielv tyrielv closed this Sep 16, 2026
auto-merge was automatically disabled September 16, 2026 16:17

Pull request was closed

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.

3 participants