Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b4e9194
Marshal libgit2 P/Invoke strings as UTF-8, not ANSI
tyrielv Sep 21, 2026
096f16a
Update default Microsoft Git version to v2.55.0.vfs.0.10
dscho Sep 23, 2026
92020a4
Merge pull request #2111 from microsoft/automation/gitrelease-v2.55.0…
dscho Sep 23, 2026
f4728ba
Merge pull request #2110 from tyrielv/tyrielv/libgit2-utf8-marshalling
tyrielv Sep 23, 2026
b3c837f
docs(agents): clarify functional test dev workflow
tyrielv Sep 23, 2026
fb3ea43
docs(agents): clarify payload prerequisites
tyrielv Sep 24, 2026
269288e
Merge pull request #2114 from tyrielv/tyrielv/agents-guidance
tyrielv Sep 24, 2026
51592aa
Retry native C++ project builds on transient MSBuild failure
tyrielv Sep 24, 2026
27d8d9a
Only retry native builds on the actual C3859 PCH error
tyrielv Sep 24, 2026
cb20708
Merge pull request #2117 from tyrielv/tyrielv/retry-native-pch-build
tyrielv Sep 24, 2026
b35b9b6
Add regression tests for reset --mixed skip-worktree on hydrated files
tyrielv Jun 10, 2026
ab95cf5
Merge pull request #2018 from tyrielv/tyrielv/fix-reset-mixed-skipwor…
tyrielv Sep 28, 2026
6dd6f63
Add IsSendingAnonymousRequests to VFS.Heartbeat
tyrielv Sep 30, 2026
a6c33d2
Show credential prompts above other windows for background mounts
tyrielv Oct 1, 2026
d274d51
Bump actions/upload-artifact from 7 to 7
dependabot[bot] Oct 6, 2026
78e3e57
Merge pull request #2128 from microsoft/dependabot/github_actions/act…
tyrielv Oct 6, 2026
a65ec22
Merge pull request #2125 from tyrielv/tyrielv/isanonymous-heartbeat
tyrielv Oct 7, 2026
58edd7c
Make credential-fill console-visibility telemetry authoritative and l…
tyrielv Oct 7, 2026
56d0b72
Merge pull request #2127 from tyrielv/tyrielv/credential-nowindow
tyrielv Oct 7, 2026
4ae7784
Merge upstream/master into tyrielv/merge-master-to-vnext-20261008
tyrielv Oct 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ permissions:
checks: read

env:
GIT_VERSION: ${{ github.event.inputs.git_version || 'v2.55.0.vfs.0.8' }}
GIT_VERSION: ${{ github.event.inputs.git_version || 'v2.55.0.vfs.0.10' }}

jobs:
validate:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/functional-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ jobs:

- name: Upload failure diagnostics (mount dumps + logs)
if: always() && steps.skip.outputs.result != 'true'
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
continue-on-error: true
with:
name: ${{ env.ARTIFACT_PREFIX }}FailureDiagnostics_${{ env.FT_MATRIX_NAME }}
Expand Down
77 changes: 66 additions & 11 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,27 @@ an installer. `PublishAot=false` skips ilc (~3–4 min saved);
`GVFS.Payload` only assembles the payload directory — it does **not** build or
publish the projects it copies from (see the warning below).

> **Prerequisite: the native C++ projects must already be built.** They are
> `.vcxproj` (see [Native C++ projects](#native-c-projects-need-msbuild-not-dotnet-build)
> **Prerequisite: the native C++ projects and all managed payload projects must
> already have built outputs.** The native projects are `.vcxproj` (see
> [Native C++ projects](#native-c-projects-need-msbuild-not-dotnet-build)
> below) and `dotnet publish` will not build them for you. If you have not
> already done a `Build.bat` once in this enlistment, build the native
> projects via VS MSBuild first (or run `Build.bat` once to populate `out\`,
> then iterate with the commands below). After that they are incremental and
> only rebuild when their own sources change.
> projects via VS MSBuild and publish the managed payload projects below
> (or run `Build.bat` once to populate `out\`, then iterate with the commands
> below). After that they are incremental and only rebuild when their own
> sources change.

```powershell
dotnet publish src\GVFS\GVFS.FunctionalTests\GVFS.FunctionalTests.csproj `
-c Debug /p:PublishAot=false
dotnet publish src\GVFS\GVFS\GVFS.csproj `
-c Debug /p:PublishAot=false
dotnet publish src\GVFS\GVFS.Hooks\GVFS.Hooks.csproj `
-c Debug /p:PublishAot=false
dotnet publish src\GVFS\GVFS.Mount\GVFS.Mount.csproj `
-c Debug /p:PublishAot=false
dotnet publish src\GVFS\GVFS.Service\GVFS.Service.csproj `
-c Debug /p:PublishAot=false
dotnet publish src\GVFS\GVFS.Payload\GVFS.Payload.csproj `
-c Debug /p:PublishAot=false /p:SkipCreateInstaller=true

Expand Down Expand Up @@ -113,11 +121,19 @@ hook binaries are copied straight from the vcxproj output.
> your edit, publish the project that owns the changed code and re-run the
> payload publish. The same applies to `GVFS.Mount`, `GVFS.Hooks`, and
> `GVFS.Service` when you change those.
>
> Publish all four managed payload projects at least once in a new enlistment.

`RunFunctionalTests-Dev.ps1` runs functional tests against the build output
without requiring admin or a system-wide install. It launches the test
service as a console process. Each invocation gets a unique service name
and data dir, so concurrent runs from different worktrees don't collide.
service as a console process. Each invocation gets a unique service name and
service-data directory. Some fixtures still use shared machine paths or drive
mappings, so do not assume that separate test processes can run concurrently.

The script sets dev-mode variables. `Settings.Default.Initialize` then resolves
`gvfs.exe` and `GVFS.Service.exe` from `out\GVFS.Payload\...`, not
`C:\Program Files\VFS for Git\`. This path does not require a GVFS
installation.

> **Pass `-Configuration` and `-Arch` by name.** The script's first two
> positional parameters are `Configuration` and `Arch`, so a bare
Expand Down Expand Up @@ -166,12 +182,14 @@ participate in the C# inner-loop paths above.

```powershell
# ✅ Correct
& "out\GVFS.UnitTests\bin\...\GVFS.UnitTests.exe" --test "GVFS.UnitTests.Common.WorktreeInfoTests"
src\scripts\RunFunctionalTests-Dev.ps1 -Configuration Debug -Arch x64 --test=GVFS.FunctionalTests.Tests.GVFSVerbTests.UnknownVerb
& "out\GVFS.UnitTests\bin\...\GVFS.UnitTests.exe" --test "GVFS.UnitTests.Common.WorktreeInfoTests"
src\scripts\RunFunctionalTests-Dev.ps1 -Configuration Debug -Arch x64 `
--test=GVFS.FunctionalTests.Tests.GVFSVerbTests.UnknownVerb

# ❌ Wrong — silently runs the entire suite
& "out\GVFS.UnitTests\bin\...\GVFS.UnitTests.exe" --where "class =~ Worktree"
src\scripts\RunFunctionalTests-Dev.ps1 -Configuration Debug -Arch x64 --where "cat == Smoke"
& "out\GVFS.UnitTests\bin\...\GVFS.UnitTests.exe" --where "class =~ Worktree"
src\scripts\RunFunctionalTests-Dev.ps1 -Configuration Debug -Arch x64 `
--where "cat == Smoke"
```

For unit tests, `--where` is merely annoying (the whole suite runs in
Expand Down Expand Up @@ -256,6 +274,43 @@ Default new gates to `false` and gate the **runtime entry point** into a
feature, not its build, so the code still compiles and ships (and keeps
getting exercised) while its behavior stays off by default.

## libgit2 P/Invoke string marshalling (UTF-8, not ANSI)

The libgit2 bindings live in `GVFS.Common/Git/LibGit2Repo.cs` under the
`Native` class. **libgit2 treats every string it receives and returns as
UTF-8** — paths, revspecs, config keys and values, and error messages.

The .NET default for a bare `[DllImport]` string parameter is
`CharSet.Ansi`, which encodes through the Windows ANSI code page and
**silently corrupts non-ASCII input** (a repo path under a non-English user
name, a non-ASCII branch name, etc.) — an unmappable character becomes `?`,
so `git_repository_open` and friends resolve the wrong path or fail. There is
no `[module: DefaultCharSet]` override in `GVFS.Common`, so the ANSI default
applies unless each declaration opts out.

When you add a libgit2 P/Invoke:

- Annotate **every** `string` parameter, `out string` parameter, string return
value, and string struct field with
`[MarshalAs(UnmanagedType.LPUTF8Str)]`.
- Do **not** use `CharSet.Unicode` — that marshals UTF-16, which libgit2 does
not accept (it is the same bug in the other direction).
- For a function that returns a **borrowed** pointer owned by libgit2 (e.g.
`git_config_get_string`), marshal it as `IntPtr` and copy with
`Marshal.PtrToStringUTF8(...)`; do not marshal it as `out string`, or the
interop marshaller frees libgit2's heap memory with the wrong allocator.

Because the mismatch only manifests through the native call, cover new
string-carrying paths with a real-libgit2 test that uses a non-ASCII input
(see `GVFS.FunctionalTests/Tests/LibGit2NonAsciiPathTests.cs`), not a
mock-based unit test.

## Public repository hygiene

Do not include Microsoft-internal work item IDs, ADO URLs, incident IDs, or
internal service names in repository content or pull requests. Describe the
public problem and fix without requiring internal access.

## Coding standards

See [CONTRIBUTING.md](CONTRIBUTING.md) for StyleCop rules, error-handling
Expand Down
14 changes: 14 additions & 0 deletions GVFS/GVFS.Common/GVFSPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ public static void Register(GVFSPlatform platform)
/// </exception>
public abstract void PrepareProcessToRunInBackground();

/// <summary>
/// Returns true if the current process owns a visible console window that a child process
/// (e.g. git launching the credential manager) can use as the owner for an interactive prompt.
/// </summary>
/// <remarks>
/// This inspects the current process's console window and its root owner, not arbitrary GUI
/// windows. Background processes such as GVFS.Mount run with a hidden console, so this returns
/// false for them; foreground processes launched from a visible console return true. Credential
/// helpers launched by a process with no visible console window should be started detached from
/// the console, so the credential manager parents its prompt to a topmost stub window instead
/// of the hidden console.
/// </remarks>
public abstract bool CurrentProcessHasVisibleConsoleWindow();

public abstract bool IsProcessActive(int processId);

/// <summary>
Expand Down
Loading
Loading