From a3f95d48b78f81511a52fb44e0772064617b82fd Mon Sep 17 00:00:00 2001 From: Tyrie Vella Date: Mon, 1 Jun 2026 12:02:03 -0700 Subject: [PATCH] Add AGENTS.md and refresh outdated Readme sections This commit does four related things: 1. Add an AGENTS.md at the repo root, following the 2025-2026 cross-tool convention (Linux Foundation Agentic AI Foundation). It is natively read by GitHub Copilot, Claude Code, OpenAI Codex, Cursor, Gemini CLI, Windsurf, Aider, Devin, Zed, and others; agents that have their own native file (e.g. CLAUDE.md) fall back to AGENTS.md when no native file is present. The file captures project-specific knowledge that isn't obvious from a fresh `git clone` and which routinely trips up AI coding assistants: - The wrapped-output layout (build outputs land one level up from the working tree -- catches agents reaching for ./out or similar). Notes the documented `src\` convention and that all commands assume CWD at the enlistment root. - Three explicit build paths scoped to scenario, so agents stop reaching for the full installer build (~5 min, NativeAOT publish + Inno Setup, no incremental support) when they just want to rerun a unit test: Path A -- unit-test inner loop: ~10-15 s (dotnet build .csproj) Path B -- functional-test loop: ~30-60 s (dotnet publish w/ PublishAot=false + SkipCreateInstaller=true) Path C -- installer build: ~5 min (Build.bat, only when you actually need an installer) Path B explicitly calls out the native C++ vcxproj prerequisite, since dotnet publish won't build those. - The NUnit filter footgun: this codebase uses NUnitLite, which supports only --test (not --where). --where is silently ignored and runs every test. For unit tests that's just slow; for functional tests it's hours of wasted runtime against fresh enlistments. - Fully-qualified-name requirement for --test (short names silently match nothing). - The vcpkg caching behavior in Build.bat (don't manually re-run vcpkg unless overlay ports changed). Coding standards are NOT duplicated here -- agents are pointed at CONTRIBUTING.md, which already covers StyleCop, error handling, TryXxx patterns, logging conventions, etc. No new precompiled binaries, no helper scripts, no opinionated workflow recommendations (worktree model etc.) -- just the minimum project-specific knowledge needed to keep an agent productive in this repo. 2. Remove the "maintenance mode" notice from Readme.md. VFS for Git has resumed active development; the line about "only required updates as a reaction to critical security vulnerabilities will prompt a release" is no longer accurate. The Scalar recommendation paragraph (for new deployments) is unchanged. 3. Remove the build-badge table from Readme.md. The four pipelines it referenced are a mix of still-running (gvfs/ci CI - Windows and CI - Windows - Full Functional Tests, both currently green) and never-configured for master (mseng/AzureDevOps GVFS/GitHub VFSForGit Large Repo Perf Tests and Large Repo Build both render the "set up now" placeholder). Active CI signal lives in the GitHub Actions checks on each commit/PR; keeping a separately-maintained badge table just creates a "is this still accurate?" question that no one answers. 4. Update the "Building VFS for Git" section of Readme.md to reflect the current build system: - The .NET 10 SDK has replaced the .NET Core 8 SDK requirement. - The "Install nuget.exe" prerequisite is gone (modern dotnet SDK handles restore). - vcpkg is now required (for native libgit2 et al.); call it out and point at the official getting-started doc. - The .NET Core cross-platform development workload and runtime bullets are obsolete; dropped. - The build script is `Build.bat`, not the historical `BuildGVFSForWindows.bat`. - The installer output path is `out\GVFS.Installers\bin\\win-x64\`, not the historical `BuildOutput\GVFS.Installer.Windows\bin\x64\\`. - Added a pointer at the end of the section to AGENTS.md for AI coding assistants. Assisted-by: Claude Opus 4.7 Signed-off-by: Tyrie Vella --- AGENTS.md | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Readme.md | 19 ++---- 2 files changed, 180 insertions(+), 13 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..4fafb53e9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,174 @@ +# Agent instructions for VFS for Git + +This file is for AI coding assistants (GitHub Copilot, Claude Code, Cursor, OpenAI +Codex, Gemini CLI, Aider, etc.). It captures project-specific knowledge that isn't +obvious from a fresh `git clone` and which routinely trips up agents. See +[CONTRIBUTING.md](CONTRIBUTING.md) for coding standards (StyleCop rules, error +handling, exception logging) — do not duplicate those here. + +## Repository layout + +The build scripts (`scripts\Build.bat` and friends) put build outputs **one +level up** from the git working tree. The Readme documents the recommended +clone-into-`src\` convention, which matches the layout that `gvfs clone` +creates for end users: + +```powershell +# Recommended (matches Readme.md and CI): +git clone https://github.com/microsoft/VFSForGit C:\Repos\VFSForGit\src +``` + +``` +C:\Repos\VFSForGit\ +├── src\ ← git working tree (.git, GVFS.sln, all source) +├── out\ ← build output (gitignored — it's outside the working tree) +└── packages\ ← NuGet cache +``` + +Cloning without the `src\` suffix also works — outputs just land one level +above wherever you cloned. The rest of this document and the project's own +scripts (CI, Readme) use the `src\` form, so commands assume it. **The +parent directory must be writable** (cloning to `C:\` itself won't work +because the build can't create `C:\out`). + +All commands below run from the **enlistment root** (the parent of `src\`): + +```powershell +cd C:\Repos\VFSForGit # NOT C:\Repos\VFSForGit\src +``` + +This keeps `src\...` and `out\...` paths symmetric and matches what +`Build.bat` does internally. + +## Build paths + +`scripts\Build.bat` does a full installer build with NativeAOT publish plus +Inno Setup. That's ~5 minutes minimum, and AOT has no incremental support +— ilc relinks every executable on every `dotnet publish`. **Do not use +`Build.bat` for dev-loop iteration.** Pick the right path for what you're +doing. + +### Path A — Unit-test inner loop (~10–15 s incremental) + +For C# changes verified by unit tests only. + +```powershell +dotnet build src\GVFS\GVFS.UnitTests\GVFS.UnitTests.csproj -c Debug +& "out\GVFS.UnitTests\bin\Debug\net10.0-windows10.0.17763.0\win-x64\GVFS.UnitTests.exe" --test Fully.Qualified.Class.Or.Method +``` + +Skips `dotnet publish`, AOT, native C++ projects, payload assembly, installer. + +### Path B — Functional-test inner loop (~30–60 s incremental) + +For changes that need the GVFS payload (`gvfs.exe`, hooks, service) but not +an installer. `PublishAot=false` skips ilc (~3–4 min saved); +`SkipCreateInstaller=true` skips Inno Setup (~95 s saved). +`GVFS.Payload` cascades to its dependencies (GVFS, GVFS.Mount, GVFS.Hooks, +GVFS.Service) via `ProjectReference`. + +> **Prerequisite: the native C++ projects must already be built.** They 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. + +```powershell +dotnet publish src\GVFS\GVFS.FunctionalTests\GVFS.FunctionalTests.csproj ` + -c Debug /p:PublishAot=false +dotnet publish src\GVFS\GVFS.Payload\GVFS.Payload.csproj ` + -c Debug /p:PublishAot=false /p:SkipCreateInstaller=true + +src\scripts\RunFunctionalTests-Dev.ps1 Debug --test=GVFS.FunctionalTests.Tests... +``` + +`layout.bat` (invoked by GVFS.Payload) `xcopy`s from each project's `publish\` +or native-output directory — the C# projects do not require AOT, so +`PublishAot=false` produces a fully functional test payload. The native +hook binaries are copied straight from the vcxproj output. + +`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. + +### Path C — Installer build (~5 min — only when you need an installer) + +For producing an installable package (testing install/upgrade flows, or +shipping a build). This is the only correct use of `Build.bat`. + +```powershell +# Build.bat takes (configuration, version, verbosity). The 0. prefix on the +# version tells GVFS to treat this as a development build and skip the +# server-side version check. +$v = & { $n = [DateTime]::Now; "0.2.$($n.ToString('yy'))$($n.DayOfYear.ToString('D3')).$([int]($n.TimeOfDay.TotalSeconds / 2))" } +src\scripts\Build.bat Debug $v minimal +``` + +Installer output: `out\GVFS.Installers\bin\Debug\win-x64\SetupGVFS..exe`. + +## Native C++ projects (need MSBuild, not `dotnet build`) + +These five projects are `.vcxproj` and require Visual Studio MSBuild with +the C++ workload. `Build.bat` invokes MSBuild for them automatically; if +you need to rebuild them outside `Build.bat`, use `msbuild`, not +`dotnet build`. + +- `GVFS\GitHooksLoader\GitHooksLoader.vcxproj` +- `GVFS\GVFS.NativeTests\GVFS.NativeTests.vcxproj` +- `GVFS\GVFS.PostIndexChangedHook\GVFS.PostIndexChangedHook.vcxproj` +- `GVFS\GVFS.ReadObjectHook\GVFS.ReadObjectHook.vcxproj` +- `GVFS\GVFS.VirtualFileSystemHook\GVFS.VirtualFileSystemHook.vcxproj` + +These only need to be (re)built when their own sources change; they don't +participate in the C# inner-loop paths above. + +## Running tests + +### NUnit filter syntax — `--test`, NEVER `--where` + +> **⚠️ This codebase uses NUnitLite, which supports ONLY `--test` for name +> filtering. The `--where` filter (from NUnit Console) is silently ignored +> and runs every test.** + +```powershell +# ✅ Correct +& "out\GVFS.UnitTests\bin\...\GVFS.UnitTests.exe" --test "GVFS.UnitTests.Common.WorktreeInfoTests" +src\scripts\RunFunctionalTests-Dev.ps1 Debug --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 Debug --where "cat == Smoke" +``` + +For unit tests, `--where` is merely annoying (the whole suite runs in +~10 seconds). For functional tests, it's a disaster: each test provisions +its own fresh enlistment, so accidentally running the full suite eats +hours and masks whichever failure you were actually investigating. + +### Fully qualified names required + +`--test` matches against the fully qualified name (`Namespace.Class.Method` +or `Namespace.Class`). Short names like `--test=ReproCherryPickRestoreCorruption` +silently match nothing and the runner reports "0 tests selected" without +making the typo obvious. + +## vcpkg caching + +`Build.bat` checks for `out\vcpkg_installed\dynamic\x64-windows-dynamic\bin\ +git2.dll` as a "vcpkg already installed" marker and skips the vcpkg step +if present. The vcpkg step is the slowest part of a from-scratch build +(several minutes of native compilation), so this caching matters. + +Do not manually delete or re-run vcpkg unless you've changed an overlay +port. If you've copied `out\` from another enlistment as a build-time +shortcut, vcpkg results come along with it. + +## Coding standards + +See [CONTRIBUTING.md](CONTRIBUTING.md) for StyleCop rules, error-handling +patterns (`TryXxx` over exceptions, "fail fast" on data-loss risks), +tracing/logging conventions (Error level reserved for unrecoverable +failures), and the `mock:\\` / `mock://` URL convention for unit tests. diff --git a/Readme.md b/Readme.md index 6267980ba..c72ae98d5 100644 --- a/Readme.md +++ b/Readme.md @@ -1,12 +1,5 @@ # VFS for Git -**Notice:** With the release of VFS for Git 2.32, VFS for Git is in maintenance mode. Only required updates as a reaction to critical security vulnerabilities will prompt a release. - -|Branch|Unit Tests|Functional Tests|Large Repo Perf|Large Repo Build| -|:--:|:--:|:--:|:--:|:--:| -|**master**|[![Build status](https://dev.azure.com/gvfs/ci/_apis/build/status/CI%20-%20Windows?branchName=master)](https://dev.azure.com/gvfs/ci/_build/latest?definitionId=7&branchName=master)|[![Build status](https://dev.azure.com/gvfs/ci/_apis/build/status/CI%20-%20Windows%20-%20Full%20Functional%20Tests?branchName=master)](https://dev.azure.com/gvfs/ci/_build/latest?definitionId=6&branchName=master)|[![Build status](https://dev.azure.com/mseng/AzureDevOps/_apis/build/status/GVFS/GitHub%20VFSForGit%20Large%20Repo%20Perf%20Tests?branchName=master)](https://dev.azure.com/mseng/AzureDevOps/_build/latest?definitionId=7179&branchName=master)|[![Build status](https://dev.azure.com/mseng/AzureDevOps/_apis/build/status/GVFS/GitHub%20VFSForGit%20Large%20Repo%20Build?branchName=master)](https://dev.azure.com/mseng/AzureDevOps/_build/latest?definitionId=7180&branchName=master)| -|**shipped**|[![Build status](https://dev.azure.com/gvfs/ci/_apis/build/status/CI%20-%20Windows?branchName=releases%2Fshipped)](https://dev.azure.com/gvfs/ci/_build/latest?definitionId=7&branchName=releases%2Fshipped)|[![Build status](https://dev.azure.com/gvfs/ci/_apis/build/status/CI%20-%20Windows%20-%20Full%20Functional%20Tests?branchName=releases%2Fshipped)](https://dev.azure.com/gvfs/ci/_build/latest?definitionId=6&branchName=releases%2Fshipped)|[![Build status](https://dev.azure.com/mseng/AzureDevOps/_apis/build/status/GVFS/GitHub%20VFSForGit%20Large%20Repo%20Perf%20Tests?branchName=releases%2Fshipped)](https://dev.azure.com/mseng/AzureDevOps/_build/latest?definitionId=7179&branchName=releases%2Fshipped)|[![Build status](https://dev.azure.com/mseng/AzureDevOps/_apis/build/status/GVFS/GitHub%20VFSForGit%20Large%20Repo%20Build?branchName=releases%2Fshipped)](https://dev.azure.com/mseng/AzureDevOps/_build/latest?definitionId=7180&branchName=releases%2Fshipped)| - ## What is VFS for Git? VFS stands for Virtual File System. VFS for Git virtualizes the file system @@ -46,22 +39,22 @@ If you'd like to build your own VFS for Git Windows installer: * Include the following workloads: * .NET desktop development * Desktop development with C++ - * .NET Core cross-platform development * Include the following additional components: - * .NET Core runtime * Windows 10 or 11 SDK (10.0+) -* Install the .NET Core 8 SDK (https://www.microsoft.com/net/download/dotnet-core/8) -* Install [`nuget.exe`](https://www.nuget.org/downloads) +* Install the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) +* Install [`vcpkg`](https://learn.microsoft.com/vcpkg/get-started/get-started) (or use the copy bundled with Visual Studio's C++ workload) * Create a folder to clone into, e.g. `C:\Repos\VFSForGit` * Clone this repo into the `src` subfolder, e.g. `C:\Repos\VFSForGit\src` -* Run `\src\Scripts\BuildGVFSForWindows.bat` +* Run `src\scripts\Build.bat` (defaults to a Debug build) * You can also build in Visual Studio by opening `src\GVFS.sln` (do not upgrade any projects) and building. However, the very first build will fail, and the second and subsequent builds will succeed. This is because the build requires a prebuild code generation step. For details, see the build script in the previous step. Visual Studio 2022 will [automatically prompt you to install these dependencies](https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/) when you open the solution. The .vsconfig file that is present in the root of the repository specifies all required components. -The installer can now be found at `C:\Repos\VFSForGit\BuildOutput\GVFS.Installer.Windows\bin\x64\[Debug|Release]\SetupGVFS..exe` +The installer can now be found at `C:\Repos\VFSForGit\out\GVFS.Installers\bin\[Debug|Release]\win-x64\SetupGVFS..exe` + +AI coding assistants working in this repo: see [AGENTS.md](AGENTS.md) for project-specific build/test guidance. ## Trying out VFS for Git