diff --git a/.azure-pipelines/release.yml b/.azure-pipelines/release.yml index d098c5a70..f754ce9d1 100644 --- a/.azure-pipelines/release.yml +++ b/.azure-pipelines/release.yml @@ -28,7 +28,7 @@ jobs: displayName: Install .NET SDK inputs: packageType: sdk - version: 5.0.201 + version: 8.0.413 - task: CmdLine@2 displayName: Build VFS for Git diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 2dc811ea4..79a4e4cc8 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -5,11 +5,38 @@ on: branches: [ master, releases/shipped ] push: branches: [ master, releases/shipped ] + workflow_dispatch: + inputs: + git_version: + description: 'Microsoft Git version tag to include in the build (leave empty for default)' + required: false + type: string + +env: + GIT_VERSION: ${{ github.event.inputs.git_version || 'v2.50.1.vfs.0.1' }} jobs: + validate: + runs-on: windows-2025 + name: Validation + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Validate Microsoft Git version + shell: pwsh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + & "$env:GITHUB_WORKSPACE\.github\workflows\scripts\validate_release.ps1" ` + -Repository microsoft/git ` + -Tag $env:GIT_VERSION && ` + Write-Host ::notice title=Validation::Using microsoft/git version $env:GIT_VERSION + build: - runs-on: windows-2019 + runs-on: windows-2025 name: Build and Unit Test + needs: validate strategy: matrix: @@ -24,7 +51,7 @@ jobs: - name: Install .NET SDK uses: actions/setup-dotnet@v4 with: - dotnet-version: 5.0.201 + dotnet-version: 8.0.413 - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@v2.0.0 @@ -41,6 +68,13 @@ jobs: shell: cmd run: src\scripts\CreateBuildArtifacts.bat ${{ matrix.configuration }} artifacts + - name: Download microsoft/git installers + shell: cmd + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release download %GIT_VERSION% --repo microsoft/git --pattern "Git*.exe" --dir artifacts\GVFS.Installers + - name: Upload functional tests drop uses: actions/upload-artifact@v4 with: @@ -59,20 +93,15 @@ jobs: name: Installers_${{ matrix.configuration }} path: artifacts\GVFS.Installers - - name: Upload NuGet packages - uses: actions/upload-artifact@v4 - with: - name: NuGetPackages_${{ matrix.configuration }} - path: artifacts\NuGetPackages - functional_test: - runs-on: windows-2019 + runs-on: ${{ matrix.architecture == 'arm64' && 'windows-11-arm' || 'windows-2025' }} name: Functional Tests needs: build strategy: matrix: configuration: [ Debug, Release ] + architecture: [ x86_64, arm64 ] steps: - name: Download installers @@ -103,7 +132,7 @@ jobs: if: always() uses: actions/upload-artifact@v4 with: - name: InstallationLogs_${{ matrix.configuration }} + name: InstallationLogs_${{ matrix.configuration }}_${{ matrix.architecture }} path: install\logs - name: Run functional tests @@ -117,14 +146,14 @@ jobs: if: always() uses: actions/upload-artifact@v4 with: - name: FunctionalTests_Results_${{ matrix.configuration }} + name: FunctionalTests_Results_${{ matrix.configuration }}_${{ matrix.architecture }} path: TestResult.xml - name: Upload Git trace2 output if: always() uses: actions/upload-artifact@v4 with: - name: GitTrace2_${{ matrix.configuration }} + name: GitTrace2_${{ matrix.configuration }}_${{ matrix.architecture }} path: C:\temp\git-trace2.log - name: ProjFS details (post-test) diff --git a/.github/workflows/scripts/validate_release.ps1 b/.github/workflows/scripts/validate_release.ps1 new file mode 100644 index 000000000..b9ee8c04d --- /dev/null +++ b/.github/workflows/scripts/validate_release.ps1 @@ -0,0 +1,124 @@ +param( + [Parameter(Mandatory=$true)] + [string]$Tag, + + [Parameter(Mandatory=$true)] + [string]$Repository +) + +function Write-GitHubActionsCommand { + param( + [Parameter(Mandatory=$true)] + [string]$Command, + + [Parameter(Mandatory=$true)] + [string]$Message, + + [Parameter(Mandatory=$true)] + [string]$Title + ) + + Write-Host "::$Command title=$Title::$Message" +} + + +function Write-GitHubActionsWarning { + param( + [Parameter(Mandatory=$true)] + [string]$Message, + + [Parameter(Mandatory=$false)] + [string]$Title = "Warning" + ) + + if ($env:GITHUB_ACTIONS -eq "true") { + Write-GitHubActionsCommand -Command "warning" -Message $Message -Title $Title + } else { + Write-Host "! Warning: $Message" -ForegroundColor Yellow + } +} + +function Write-GitHubActionsError { + param( + [Parameter(Mandatory=$true)] + [string]$Message, + + [Parameter(Mandatory=$false)] + [string]$Title = "Error" + ) + + if ($env:GITHUB_ACTIONS -eq "true") { + Write-GitHubActionsCommand -Command "error" -Message $Message -Title $Title + } else { + Write-Host "x Error: $Message" -ForegroundColor Red + } +} + +if ([string]::IsNullOrWhiteSpace($Tag)) { + Write-GitHubActionsError -Message "Tag parameter is required" + exit 1 +} + +if ([string]::IsNullOrWhiteSpace($Repository)) { + Write-GitHubActionsError -Message "Repository parameter is required" + exit 1 +} + +Write-Host "Validating $Repository release '$Tag'..." + +# Prepare headers for GitHub API +$headers = @{ + 'Accept' = 'application/vnd.github.v3+json' + 'User-Agent' = 'VFSForGit-Build' +} + +if ($env:GITHUB_TOKEN) { + $headers['Authorization'] = "Bearer $env:GITHUB_TOKEN" +} + +# Check if the tag exists in microsoft/git repository +try { + $releaseResponse = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/$Repository/releases/tags/$Tag" ` + -Headers $headers + + Write-Host "✓ Tag '$Tag' found in $Repository" -ForegroundColor Green + Write-Host " Release : $($releaseResponse.name)" + Write-Host " Published : $($releaseResponse.published_at.ToString('u'))" + + # Check if this a pre-release + if ($releaseResponse.prerelease -eq $true) { + Write-GitHubActionsWarning ` + -Message "Using a pre-released version of $Repository" ` + -Title "Pre-release $Repository version" + } + + # Get the latest release for comparison + try { + $latestResponse = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/$Repository/releases/latest" ` + -Headers $headers + $latestTag = $latestResponse.tag_name + + # Check if this is the latest release + if ($Tag -eq $latestTag) { + Write-Host "✓ Using the latest release" -ForegroundColor Green + exit 0 + } + + # Not the latest! + $warningTitle = "Outdated $Repository release" + $warningMsg = "Not using latest release of $Repository (latest: $latestTag)" + Write-GitHubActionsWarning -Message $warningMsg -Title $warningTitle + } catch { + Write-GitHubActionsWarning -Message "Could not check latest release info for ${Repository}: $($_.Exception.Message)" + } +} catch { + if ($_.Exception.Response.StatusCode -eq 404) { + Write-GitHubActionsError -Message "Tag '$Tag' does not exist in $Repository" + exit 1 + } else { + Write-GitHubActionsError -Message "Error validating release '$Tag': $($_.Exception.Message)" + exit 1 + } +} diff --git a/.vsconfig b/.vsconfig index e91f31e69..095606afa 100644 --- a/.vsconfig +++ b/.vsconfig @@ -2,12 +2,13 @@ "version": "1.0", "components": [ "Microsoft.Component.MSBuild", - "Microsoft.VisualStudio.Workload.NativeDesktop" + "Microsoft.Net.Component.4.7.1.TargetingPack", + "Microsoft.Net.Component.4.7.1.SDK", + "Microsoft.Net.Core.Component.SDK.8.0", + "Microsoft.VisualStudio.Component.VC.v143.x86.x64", + "Microsoft.VisualStudio.Component.Windows11SDK.26100", + "Microsoft.VisualStudio.Workload.NativeDesktop", "Microsoft.VisualStudio.Workload.ManagedDesktop", - "Microsoft.VisualStudio.Workload.NetCoreTools", - "Microsoft.Net.Core.Component.SDK.2.1", - "Microsoft.VisualStudio.Component.VC.v141.x86.x64", - "Microsoft.Net.Component.4.6.1.TargetingPack", - "Microsoft.Net.Component.4.6.1.SDK", + "Microsoft.VisualStudio.Workload.NetCoreTools" ] } \ No newline at end of file diff --git a/GVFS/FastFetch/FastFetch.csproj b/GVFS/FastFetch/FastFetch.csproj index 1a2bdaae9..df25afb5b 100644 --- a/GVFS/FastFetch/FastFetch.csproj +++ b/GVFS/FastFetch/FastFetch.csproj @@ -2,7 +2,7 @@ Exe - net461 + net471 x64 true diff --git a/GVFS/GVFS.Common/Enlistment.cs b/GVFS/GVFS.Common/Enlistment.cs index 3f061257f..090a81c9e 100644 --- a/GVFS/GVFS.Common/Enlistment.cs +++ b/GVFS/GVFS.Common/Enlistment.cs @@ -109,5 +109,18 @@ public virtual GitProcess CreateGitProcess() { return new GitProcess(this); } + + public bool GetTrustPackIndexesConfig() + { + var gitProcess = this.CreateGitProcess(); + bool trustPackIndexes = true; + if (gitProcess.TryGetFromConfig(GVFSConstants.GitConfig.TrustPackIndexes, forceOutsideEnlistment: false, out var valueString) + && bool.TryParse(valueString, out var trustPackIndexesConfig)) + { + trustPackIndexes = trustPackIndexesConfig; + } + + return trustPackIndexes; + } } } diff --git a/GVFS/GVFS.Common/GVFS.Common.csproj b/GVFS/GVFS.Common/GVFS.Common.csproj index e19e8ee2e..daacd2ca2 100644 --- a/GVFS/GVFS.Common/GVFS.Common.csproj +++ b/GVFS/GVFS.Common/GVFS.Common.csproj @@ -1,7 +1,7 @@  - net461 + net471 true @@ -13,6 +13,7 @@ + diff --git a/GVFS/GVFS.Common/Git/GitObjects.cs b/GVFS/GVFS.Common/Git/GitObjects.cs index 6614bd573..e21d4a1d1 100644 --- a/GVFS/GVFS.Common/Git/GitObjects.cs +++ b/GVFS/GVFS.Common/Git/GitObjects.cs @@ -135,12 +135,7 @@ public virtual bool TryDownloadPrefetchPacks(GitProcess gitProcess, long latestT * pack file and an index file that do not match. * Eventually we will make this the default, but it has a high performance cost for the first prefetch after * cloning a large repository, so it must be explicitly enabled for now. */ - bool trustPackIndexes = true; - if (gitProcess.TryGetFromConfig(GVFSConstants.GitConfig.TrustPackIndexes, forceOutsideEnlistment: false, out var valueString) - && bool.TryParse(valueString, out var trustPackIndexesConfig)) - { - trustPackIndexes = trustPackIndexesConfig; - } + bool trustPackIndexes = this.Enlistment.GetTrustPackIndexesConfig(); metadata.Add("trustPackIndexes", trustPackIndexes); long requestId = HttpRequestor.GetNewRequestId(); diff --git a/GVFS/GVFS.Common/Git/GitRepo.cs b/GVFS/GVFS.Common/Git/GitRepo.cs index 4aa4b945a..ee9d8b96d 100644 --- a/GVFS/GVFS.Common/Git/GitRepo.cs +++ b/GVFS/GVFS.Common/Git/GitRepo.cs @@ -4,6 +4,7 @@ using System.IO; using System.IO.Compression; using System.Linq; +using static GVFS.Common.Git.LibGit2Repo; namespace GVFS.Common.Git { @@ -60,9 +61,9 @@ public void OpenRepo() this.libgit2RepoInvoker?.InitializeSharedRepo(); } - public bool TryGetIsBlob(string sha, out bool isBlob) + public bool TryGetObjectType(string sha, out Native.ObjectTypes? objectType) { - return this.libgit2RepoInvoker.TryInvoke(repo => repo.IsBlob(sha), out isBlob); + return this.libgit2RepoInvoker.TryInvoke(repo => repo.GetObjectType(sha), out objectType); } public virtual bool TryCopyBlobContentStream(string blobSha, Action writeAction) @@ -86,10 +87,12 @@ public virtual bool TryCopyBlobContentStream(string blobSha, Action repo.CommitAndRootTreeExists(commitSha), out output); + string treeShaLocal = null; + this.libgit2RepoInvoker.TryInvoke(repo => repo.CommitAndRootTreeExists(commitSha, out treeShaLocal), out output); + rootTreeSha = treeShaLocal; return output; } diff --git a/GVFS/GVFS.Common/Git/GitVersion.cs b/GVFS/GVFS.Common/Git/GitVersion.cs index aecd02465..a3c6461a7 100644 --- a/GVFS/GVFS.Common/Git/GitVersion.cs +++ b/GVFS/GVFS.Common/Git/GitVersion.cs @@ -1,15 +1,18 @@ using System; -using System.Text; namespace GVFS.Common.Git { public class GitVersion { public GitVersion(int major, int minor, int build, string platform = null, int revision = 0, int minorRevision = 0) + : this(major, minor, build, null, platform, revision, minorRevision) { } + + public GitVersion(int major, int minor, int build, int? releaseCandidate = null, string platform = null, int revision = 0, int minorRevision = 0) { this.Major = major; this.Minor = minor; this.Build = build; + this.ReleaseCandidate = releaseCandidate; this.Platform = platform; this.Revision = revision; this.MinorRevision = minorRevision; @@ -18,6 +21,7 @@ public GitVersion(int major, int minor, int build, string platform = null, int r public int Major { get; private set; } public int Minor { get; private set; } public int Build { get; private set; } + public int? ReleaseCandidate { get; private set; } public string Platform { get; private set; } public int Revision { get; private set; } public int MinorRevision { get; private set; } @@ -37,31 +41,12 @@ public static bool TryParseGitVersionCommandResult(string input, out GitVersion return TryParseVersion(input, out version); } - public static bool TryParseInstallerName(string input, string installerExtension, out GitVersion version) - { - // Installer name is of the form - // Git-2.14.1.gvfs.1.1.gb16030b-64-bit.exe - - version = null; - - if (!input.StartsWith("Git-", StringComparison.InvariantCultureIgnoreCase)) - { - return false; - } - - if (!input.EndsWith("-64-bit" + installerExtension, StringComparison.InvariantCultureIgnoreCase)) - { - return false; - } - - return TryParseVersion(input.Substring(4, input.Length - 15), out version); - } - public static bool TryParseVersion(string input, out GitVersion version) { version = null; int major, minor, build, revision = 0, minorRevision = 0; + int? releaseCandidate = null; string platform = null; if (string.IsNullOrWhiteSpace(input)) @@ -73,10 +58,10 @@ public static bool TryParseVersion(string input, out GitVersion version) int numComponents = parsedComponents.Length; // We minimally accept the official Git version number format which - // consists of three components: "major.minor.build". + // consists of three components: "major.minor.build[.rcN]". // // The other supported formats are the Git for Windows and Microsoft Git - // formats which look like: "major.minor.build.platform.revision.minorRevision" + // formats which look like: "major.minor.build[.rcN].platform.revision.minorRevision" // 0 1 2 3 4 5 // len 1 2 3 4 5 6 // @@ -103,25 +88,54 @@ public static bool TryParseVersion(string input, out GitVersion version) return false; } - // Take the platform component verbatim + // Release candidate and/or platform + // Both of these are optional, but the release candidate is expected to be of the format 'rcN' + // where N is a number, helping us distinguish it from a platform string. + int platformIdx = 3; if (numComponents >= 4) { - platform = parsedComponents[3]; + string tag = parsedComponents[3]; + + // Release candidate 'rcN' + if (tag.StartsWith("rc", StringComparison.OrdinalIgnoreCase) && + tag.Length > 2 && int.TryParse(tag.Substring(2), out int rc) && rc >= 0) + { + releaseCandidate = rc; + + // The next component will now be the (optional) platform. + // Subsequent components will be revision and minor revision so we need to adjust + // the platform index to account for the release candidate. + platformIdx = 4; + if (numComponents >= 5) + { + platform = parsedComponents[4]; + } + } + else // Platform string only + { + platform = tag; + } } // Platform revision - if (numComponents < 5 || !TryParseComponent(parsedComponents[4], out revision)) + if (numComponents > platformIdx + 1) { - revision = 0; + if (!TryParseComponent(parsedComponents[platformIdx + 1], out revision)) + { + revision = 0; + } } // Minor platform revision - if (numComponents < 6 || !TryParseComponent(parsedComponents[5], out minorRevision)) + if (numComponents > platformIdx + 2) { - minorRevision = 0; + if (!TryParseComponent(parsedComponents[platformIdx + 2], out minorRevision)) + { + minorRevision = 0; + } } - version = new GitVersion(major, minor, build, platform, revision, minorRevision); + version = new GitVersion(major, minor, build, releaseCandidate, platform, revision, minorRevision); return true; } @@ -142,7 +156,12 @@ public bool IsLessThan(GitVersion other) public override string ToString() { - return string.Format("{0}.{1}.{2}.{3}.{4}.{5}", this.Major, this.Minor, this.Build, this.Platform, this.Revision, this.MinorRevision); + if (ReleaseCandidate is null) + { + return $"{Major}.{Minor}.{Build}.{Platform}.{Revision}.{MinorRevision}"; + } + + return $"{Major}.{Minor}.{Build}.rc{ReleaseCandidate}.{Platform}.{Revision}.{MinorRevision}"; } private static bool TryParseComponent(string component, out int parsedComponent) @@ -182,6 +201,18 @@ private int CompareVersionNumbers(GitVersion other) return this.Build.CompareTo(other.Build); } + if (this.ReleaseCandidate != other.ReleaseCandidate) + { + if (this.ReleaseCandidate.HasValue && other.ReleaseCandidate.HasValue) + { + return this.ReleaseCandidate.Value.CompareTo(other.ReleaseCandidate.Value); + } + + // If one version has a release candidate and the other does not, + // the one without a release candidate is considered "greater than" the one with. + return other.ReleaseCandidate.HasValue ? 1 : -1; + } + if (this.Revision != other.Revision) { return this.Revision.CompareTo(other.Revision); diff --git a/GVFS/GVFS.Common/Git/LibGit2Repo.cs b/GVFS/GVFS.Common/Git/LibGit2Repo.cs index c1056def3..0849dd6b7 100644 --- a/GVFS/GVFS.Common/Git/LibGit2Repo.cs +++ b/GVFS/GVFS.Common/Git/LibGit2Repo.cs @@ -41,24 +41,17 @@ protected LibGit2Repo() protected ITracer Tracer { get; } protected IntPtr RepoHandle { get; private set; } - public bool IsBlob(string sha) + public Native.ObjectTypes? GetObjectType(string sha) { IntPtr objHandle; if (Native.RevParseSingle(out objHandle, this.RepoHandle, sha) != Native.SuccessCode) { - return false; + return null; } try { - switch (Native.Object.GetType(objHandle)) - { - case Native.ObjectTypes.Blob: - return true; - - default: - return false; - } + return Native.Object.GetType(objHandle); } finally { @@ -91,9 +84,9 @@ public virtual string GetTreeSha(string commitish) return null; } - public virtual bool CommitAndRootTreeExists(string commitish) + public virtual bool CommitAndRootTreeExists(string commitish, out string treeSha) { - string treeSha = this.GetTreeSha(commitish); + treeSha = this.GetTreeSha(commitish); if (treeSha == null) { return false; diff --git a/GVFS/GVFS.FunctionalTests.LockHolder/GVFS.FunctionalTests.LockHolder.csproj b/GVFS/GVFS.FunctionalTests.LockHolder/GVFS.FunctionalTests.LockHolder.csproj index 290a12b46..bb03a4171 100644 --- a/GVFS/GVFS.FunctionalTests.LockHolder/GVFS.FunctionalTests.LockHolder.csproj +++ b/GVFS/GVFS.FunctionalTests.LockHolder/GVFS.FunctionalTests.LockHolder.csproj @@ -1,7 +1,7 @@  - net461 + net471 Exe diff --git a/GVFS/GVFS.FunctionalTests/GVFS.FunctionalTests.csproj b/GVFS/GVFS.FunctionalTests/GVFS.FunctionalTests.csproj index 0a64e7440..f170451f4 100644 --- a/GVFS/GVFS.FunctionalTests/GVFS.FunctionalTests.csproj +++ b/GVFS/GVFS.FunctionalTests/GVFS.FunctionalTests.csproj @@ -1,7 +1,7 @@  - net461 + net471 Exe diff --git a/GVFS/GVFS.FunctionalTests/Tools/GitHelpers.cs b/GVFS/GVFS.FunctionalTests/Tools/GitHelpers.cs index 8aacac84a..76a77eb64 100644 --- a/GVFS/GVFS.FunctionalTests/Tools/GitHelpers.cs +++ b/GVFS/GVFS.FunctionalTests/Tools/GitHelpers.cs @@ -63,19 +63,55 @@ public static ProcessResult InvokeGitAgainstGVFSRepo( string command, Dictionary environmentVariables = null, bool removeWaitingMessages = true, - bool removeUpgradeMessages = true) + bool removeUpgradeMessages = true, + bool removePartialHydrationMessages = true, + bool removeFSMonitorMessages = true) { ProcessResult result = GitProcess.InvokeProcess(gvfsRepoRoot, command, environmentVariables); - string errors = result.Errors; + string output = FilterMessages(result.Output, false, false, false, removePartialHydrationMessages, removeFSMonitorMessages); + string errors = FilterMessages(result.Errors, true, removeWaitingMessages, removeUpgradeMessages, removePartialHydrationMessages, removeFSMonitorMessages); - if (!string.IsNullOrEmpty(errors) && (removeWaitingMessages || removeUpgradeMessages)) + return new ProcessResult( + output, + errors, + result.ExitCode); + } + + private static IEnumerable SplitLinesKeepingNewlines(string input) + { + for (int start = 0; start < input.Length; ) { - IEnumerable errorLines = errors.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); - IEnumerable filteredErrorLines = errorLines.Where(line => + int nextLine = input.IndexOf('\n', start) + 1; + + if (nextLine == 0) { - if (string.IsNullOrWhiteSpace(line) || + // No more newlines, yield the rest + nextLine = input.Length; + } + + yield return input.Substring(start, nextLine - start); + start = nextLine; + } + } + + private static string FilterMessages( + string input, + bool removeEmptyLines, + bool removeWaitingMessages, + bool removeUpgradeMessages, + bool removePartialHydrationMessages, + bool removeFSMonitorMessages) + { + if (!string.IsNullOrEmpty(input) && (removeWaitingMessages || removeUpgradeMessages || removePartialHydrationMessages || removeFSMonitorMessages)) + { + IEnumerable lines = SplitLinesKeepingNewlines(input); + IEnumerable filteredLines = lines.Where(line => + { + if ((removeEmptyLines && string.IsNullOrWhiteSpace(line)) || (removeUpgradeMessages && line.StartsWith("A new version of VFS for Git is available.")) || - (removeWaitingMessages && line.StartsWith("Waiting for "))) + (removeWaitingMessages && line.StartsWith("Waiting for ")) || + (removePartialHydrationMessages && line.StartsWith("You are in a partially-hydrated checkout with ")) || + (removeFSMonitorMessages && line.TrimEnd().EndsWith(" is incompatible with fsmonitor"))) { return false; } @@ -85,13 +121,10 @@ public static ProcessResult InvokeGitAgainstGVFSRepo( } }); - errors = filteredErrorLines.Any() ? string.Join(Environment.NewLine, filteredErrorLines) : string.Empty; + return filteredLines.Any() ? string.Join("", filteredLines) : string.Empty; } - return new ProcessResult( - result.Output, - errors, - result.ExitCode); + return input; } public static void ValidateGitCommand( diff --git a/GVFS/GVFS.GVFlt/GVFS.GVFlt.csproj b/GVFS/GVFS.GVFlt/GVFS.GVFlt.csproj index a436520f9..97e2973e3 100644 --- a/GVFS/GVFS.GVFlt/GVFS.GVFlt.csproj +++ b/GVFS/GVFS.GVFlt/GVFS.GVFlt.csproj @@ -1,7 +1,7 @@ - net461 + net471 diff --git a/GVFS/GVFS.Hooks/GVFS.Hooks.csproj b/GVFS/GVFS.Hooks/GVFS.Hooks.csproj index efe7842a7..23dd6ea97 100644 --- a/GVFS/GVFS.Hooks/GVFS.Hooks.csproj +++ b/GVFS/GVFS.Hooks/GVFS.Hooks.csproj @@ -2,7 +2,7 @@ Exe - net461 + net471 diff --git a/GVFS/GVFS.Installers/GVFS.Installers.csproj b/GVFS/GVFS.Installers/GVFS.Installers.csproj index bf0c5ec7f..4470aeaba 100644 --- a/GVFS/GVFS.Installers/GVFS.Installers.csproj +++ b/GVFS/GVFS.Installers/GVFS.Installers.csproj @@ -1,7 +1,7 @@ - net461 + net471 false $(RepoOutPath)GVFS.Payload\bin\$(Configuration)\win-x64\ @@ -13,8 +13,6 @@ - - @@ -24,13 +22,8 @@ - - - @@ -44,10 +37,6 @@ - - - - diff --git a/GVFS/GVFS.Installers/GVFS.Installers.template.nuspec b/GVFS/GVFS.Installers/GVFS.Installers.template.nuspec deleted file mode 100644 index 8991bd81e..000000000 --- a/GVFS/GVFS.Installers/GVFS.Installers.template.nuspec +++ /dev/null @@ -1,15 +0,0 @@ - - - - GVFS.Installers - $version$ - Microsoft - false - GVFS and G4W installers - - - - - - - diff --git a/GVFS/GVFS.Installers/info.bat b/GVFS/GVFS.Installers/info.bat index b068f9c69..ba61fbc7a 100644 --- a/GVFS/GVFS.Installers/info.bat +++ b/GVFS/GVFS.Installers/info.bat @@ -9,19 +9,31 @@ SET VFS_BUND_PROJFSLIB=C:\Program Files\VFS for Git\ProjFS\ProjectedFSLib.dll SET VFS_EXEC=C:\Program Files\VFS for Git\GVFS.exe SET GIT_EXEC=C:\Program Files\Git\cmd\git.exe +REM Lookup the current Windows version +FOR /F "tokens=*" %%i IN ('powershell -Command "(Get-CimInstance -ClassName Win32_OperatingSystem).Version"') DO SET OS_VER=%%i + +ECHO Print system information... +ECHO OS version: %OS_VER% +ECHO CPU architecture: %PROCESSOR_ARCHITECTURE% + +ECHO. ECHO Checking ProjFS Windows feature... powershell -Command "Get-WindowsOptionalFeature -Online -FeatureName Client-ProjFS" +ECHO. ECHO Checking ProjFS and GVFS services... ECHO GVFS.Service: sc query GVFS.Service +ECHO. ECHO Test.GVFS.Service: sc query Test.GVFS.Service +ECHO. ECHO prjflt: sc query prjflt +ECHO. ECHO Checking ProjFS files... IF EXIST "%SYS_PRJFLT%" ( ECHO [ FOUND ] %SYS_PRJFLT% diff --git a/GVFS/GVFS.Installers/install.bat b/GVFS/GVFS.Installers/install.bat index c629c75bc..8375be193 100644 --- a/GVFS/GVFS.Installers/install.bat +++ b/GVFS/GVFS.Installers/install.bat @@ -1,8 +1,18 @@ @ECHO OFF SETLOCAL +REM Determine the correct architecture for the installer +IF "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( + SET GIT_ARCH=64-bit +) ELSE IF "%PROCESSOR_ARCHITECTURE%"=="ARM64" ( + SET GIT_ARCH=arm64 +) ELSE ( + ECHO Unknown architecture: %PROCESSOR_ARCHITECTURE% + exit 1 +) + REM Lookup full paths to Git and VFS for Git installers -FOR /F "tokens=* USEBACKQ" %%F IN ( `where /R %~dp0 Git*.exe` ) DO SET GIT_INSTALLER=%%F +FOR /F "tokens=* USEBACKQ" %%F IN ( `where /R %~dp0 Git*-%GIT_ARCH%.exe` ) DO SET GIT_INSTALLER=%%F FOR /F "tokens=* USEBACKQ" %%F IN ( `where /R %~dp0 SetupGVFS*.exe` ) DO SET GVFS_INSTALLER=%%F REM Create new empty directory for logs @@ -12,7 +22,7 @@ IF EXIST %LOGDIR% ( ) mkdir %LOGDIR% -ECHO Installing Git for Windows... +ECHO Installing Git (%GIT_ARCH%)... %GIT_INSTALLER% /LOG="%LOGDIR%\git.log" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /ALLOWDOWNGRADE=1 ECHO Installing VFS for Git... diff --git a/GVFS/GVFS.Mount/GVFS.Mount.csproj b/GVFS/GVFS.Mount/GVFS.Mount.csproj index 6e41c0008..83d89be63 100644 --- a/GVFS/GVFS.Mount/GVFS.Mount.csproj +++ b/GVFS/GVFS.Mount/GVFS.Mount.csproj @@ -2,7 +2,7 @@ Exe - net461 + net471 diff --git a/GVFS/GVFS.Mount/InProcessMount.cs b/GVFS/GVFS.Mount/InProcessMount.cs index a6f9710a8..a9dd95b70 100644 --- a/GVFS/GVFS.Mount/InProcessMount.cs +++ b/GVFS/GVFS.Mount/InProcessMount.cs @@ -14,8 +14,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Text; using System.Threading; +using static GVFS.Common.Git.LibGit2Repo; namespace GVFS.Mount { @@ -44,6 +46,9 @@ public class InProcessMount private HeartbeatThread heartbeat; private ManualResetEvent unmountEvent; + private readonly Dictionary treesWithDownloadedCommits = new Dictionary(); + private DateTime lastCommitPackDownloadTime = DateTime.MinValue; + // True if InProcessMount is calling git reset as part of processing // a folder dehydrate request private volatile bool resetForDehydrateInProgress; @@ -504,7 +509,21 @@ private void HandleDownloadObjectRequest(NamedPipeMessages.Message message, Name else { Stopwatch downloadTime = Stopwatch.StartNew(); - if (this.gitObjects.TryDownloadAndSaveObject(objectSha, GVFSGitObjects.RequestSource.NamedPipeMessage) == GitObjects.DownloadAndSaveObjectResult.Success) + + /* If this is the root tree for a commit that was was just downloaded, assume that more + * trees will be needed soon and download them as well by using the download commit API. + * + * Otherwise, or as a fallback if the commit download fails, download the object directly. + */ + if (this.ShouldDownloadCommitPack(objectSha, out string commitSha) + && this.gitObjects.TryDownloadCommit(commitSha)) + { + this.DownloadedCommitPack(objectSha: objectSha, commitSha: commitSha); + response = new NamedPipeMessages.DownloadObject.Response(NamedPipeMessages.DownloadObject.SuccessResult); + // FUTURE: Should the stats be updated to reflect all the trees in the pack? + // FUTURE: Should we try to clean up duplicate trees or increase depth of the commit download? + } + else if (this.gitObjects.TryDownloadAndSaveObject(objectSha, GVFSGitObjects.RequestSource.NamedPipeMessage) == GitObjects.DownloadAndSaveObjectResult.Success) { response = new NamedPipeMessages.DownloadObject.Response(NamedPipeMessages.DownloadObject.SuccessResult); } @@ -513,15 +532,59 @@ private void HandleDownloadObjectRequest(NamedPipeMessages.Message message, Name response = new NamedPipeMessages.DownloadObject.Response(NamedPipeMessages.DownloadObject.DownloadFailed); } - bool isBlob; - this.context.Repository.TryGetIsBlob(objectSha, out isBlob); - this.context.Repository.GVFSLock.Stats.RecordObjectDownload(isBlob, downloadTime.ElapsedMilliseconds); + + Native.ObjectTypes? objectType; + this.context.Repository.TryGetObjectType(objectSha, out objectType); + this.context.Repository.GVFSLock.Stats.RecordObjectDownload(objectType == Native.ObjectTypes.Blob, downloadTime.ElapsedMilliseconds); + + if (objectType == Native.ObjectTypes.Commit + && !this.PrefetchHasBeenDone() + && !this.context.Repository.CommitAndRootTreeExists(objectSha, out var treeSha) + && !string.IsNullOrEmpty(treeSha)) + { + /* If a commit is downloaded, it wasn't prefetched. + * If any prefetch has been done, there is probably a commit in the prefetch packs that is close enough that + * loose object download of missing trees will be faster than downloading a pack of all the trees for the commit. + * Otherwise, the trees for the commit may be needed soon depending on the context. + * e.g. git log (without a pathspec) doesn't need trees, but git checkout does. + * + * Save the tree/commit so if the tree is requested soon we can download all the trees for the commit in a batch. + */ + this.treesWithDownloadedCommits[treeSha] = objectSha; + } } } connection.TrySendResponse(response.CreateMessage()); } + private bool PrefetchHasBeenDone() + { + var prefetchPacks = this.gitObjects.ReadPackFileNames(this.enlistment.GitPackRoot, GVFSConstants.PrefetchPackPrefix); + return prefetchPacks.Length > 0; + } + + private bool ShouldDownloadCommitPack(string objectSha, out string commitSha) + { + + if (!this.treesWithDownloadedCommits.TryGetValue(objectSha, out commitSha) + || this.PrefetchHasBeenDone()) + { + return false; + } + + /* This is a heuristic to prevent downloading multiple packs related to git history commands, + * since commits downloaded close together likely have similar trees. */ + var timePassed = DateTime.UtcNow - this.lastCommitPackDownloadTime; + return (timePassed > TimeSpan.FromMinutes(5)); + } + + private void DownloadedCommitPack(string objectSha, string commitSha) + { + this.lastCommitPackDownloadTime = DateTime.UtcNow; + this.treesWithDownloadedCommits.Remove(objectSha); + } + private void HandlePostFetchJobRequest(NamedPipeMessages.Message message, NamedPipeServer.Connection connection) { NamedPipeMessages.RunPostFetchJob.Request request = new NamedPipeMessages.RunPostFetchJob.Request(message); diff --git a/GVFS/GVFS.NativeTests/GVFS.NativeTests.vcxproj b/GVFS/GVFS.NativeTests/GVFS.NativeTests.vcxproj index 87352d611..ae216cfae 100644 --- a/GVFS/GVFS.NativeTests/GVFS.NativeTests.vcxproj +++ b/GVFS/GVFS.NativeTests/GVFS.NativeTests.vcxproj @@ -17,19 +17,19 @@ {3771C555-B5C1-45E2-B8B7-2CEF1619CDC5} Win32Proj GVFSNativeTests - 10.0.16299.0 + 10.0 DynamicLibrary true - v142 + v143 NotSet DynamicLibrary false - v142 + v143 true NotSet diff --git a/GVFS/GVFS.Payload/GVFS.Payload.csproj b/GVFS/GVFS.Payload/GVFS.Payload.csproj index 1df5a3210..1311bc87d 100644 --- a/GVFS/GVFS.Payload/GVFS.Payload.csproj +++ b/GVFS/GVFS.Payload/GVFS.Payload.csproj @@ -1,7 +1,7 @@  - net461 + net471 false diff --git a/GVFS/GVFS.Payload/layout.bat b/GVFS/GVFS.Payload/layout.bat index de1c0df81..ebdae19c2 100644 --- a/GVFS/GVFS.Payload/layout.bat +++ b/GVFS/GVFS.Payload/layout.bat @@ -39,7 +39,7 @@ SET OUTPUT=%5 SET ROOT=%~dp0..\.. SET BUILD_OUT="%ROOT%\..\out" -SET MANAGED_OUT_FRAGMENT=bin\%CONFIGURATION%\net461\win-x64 +SET MANAGED_OUT_FRAGMENT=bin\%CONFIGURATION%\net471\win-x64 SET NATIVE_OUT_FRAGMENT=bin\x64\%CONFIGURATION% ECHO Copying files... diff --git a/GVFS/GVFS.PerfProfiling/GVFS.PerfProfiling.csproj b/GVFS/GVFS.PerfProfiling/GVFS.PerfProfiling.csproj index de092f981..bf3ce6850 100644 --- a/GVFS/GVFS.PerfProfiling/GVFS.PerfProfiling.csproj +++ b/GVFS/GVFS.PerfProfiling/GVFS.PerfProfiling.csproj @@ -2,7 +2,7 @@ Exe - net461 + net471 diff --git a/GVFS/GVFS.Platform.Windows/GVFS.Platform.Windows.csproj b/GVFS/GVFS.Platform.Windows/GVFS.Platform.Windows.csproj index 5cbd7e174..f8fb56597 100644 --- a/GVFS/GVFS.Platform.Windows/GVFS.Platform.Windows.csproj +++ b/GVFS/GVFS.Platform.Windows/GVFS.Platform.Windows.csproj @@ -1,7 +1,7 @@ - net461 + net471 diff --git a/GVFS/GVFS.PostIndexChangedHook/GVFS.PostIndexChangedHook.vcxproj b/GVFS/GVFS.PostIndexChangedHook/GVFS.PostIndexChangedHook.vcxproj index 0537dfaf1..3808ff027 100644 --- a/GVFS/GVFS.PostIndexChangedHook/GVFS.PostIndexChangedHook.vcxproj +++ b/GVFS/GVFS.PostIndexChangedHook/GVFS.PostIndexChangedHook.vcxproj @@ -14,7 +14,7 @@ {24D161E9-D1F0-4299-BBD3-5D940BEDD535} Win32Proj GVFSPostIndexChangedHook - 10.0.16299.0 + 10.0 GVFS.PostIndexChangedHook GVFS.PostIndexChangedHook @@ -22,13 +22,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/GVFS/GVFS.ReadObjectHook/GVFS.ReadObjectHook.vcxproj b/GVFS/GVFS.ReadObjectHook/GVFS.ReadObjectHook.vcxproj index 613e9d9a7..09e9e6616 100644 --- a/GVFS/GVFS.ReadObjectHook/GVFS.ReadObjectHook.vcxproj +++ b/GVFS/GVFS.ReadObjectHook/GVFS.ReadObjectHook.vcxproj @@ -14,7 +14,7 @@ {5A6656D5-81C7-472C-9DC8-32D071CB2258} Win32Proj readobject - 10.0.16299.0 + 10.0 GVFS.ReadObjectHook GVFS.ReadObjectHook @@ -22,13 +22,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/GVFS/GVFS.Service.UI/GVFS.Service.UI.csproj b/GVFS/GVFS.Service.UI/GVFS.Service.UI.csproj index 90589d933..48e5c1605 100644 --- a/GVFS/GVFS.Service.UI/GVFS.Service.UI.csproj +++ b/GVFS/GVFS.Service.UI/GVFS.Service.UI.csproj @@ -2,7 +2,7 @@ Exe - net461 + net471 diff --git a/GVFS/GVFS.Service/GVFS.Service.csproj b/GVFS/GVFS.Service/GVFS.Service.csproj index 821141326..c24eb6505 100644 --- a/GVFS/GVFS.Service/GVFS.Service.csproj +++ b/GVFS/GVFS.Service/GVFS.Service.csproj @@ -2,7 +2,7 @@ Exe - net461 + net471 true diff --git a/GVFS/GVFS.Tests/GVFS.Tests.csproj b/GVFS/GVFS.Tests/GVFS.Tests.csproj index c02954c26..c8c173ebf 100644 --- a/GVFS/GVFS.Tests/GVFS.Tests.csproj +++ b/GVFS/GVFS.Tests/GVFS.Tests.csproj @@ -1,7 +1,7 @@ - net461 + net471 diff --git a/GVFS/GVFS.UnitTests/Common/GitVersionTests.cs b/GVFS/GVFS.UnitTests/Common/GitVersionTests.cs index a69bd8f7e..3d349ad00 100644 --- a/GVFS/GVFS.UnitTests/Common/GitVersionTests.cs +++ b/GVFS/GVFS.UnitTests/Common/GitVersionTests.cs @@ -1,5 +1,4 @@ -using GVFS.Common; -using GVFS.Common.Git; +using GVFS.Common.Git; using GVFS.Tests.Should; using NUnit.Framework; @@ -8,14 +7,6 @@ namespace GVFS.UnitTests.Common [TestFixture] public class GitVersionTests { - [TestCase] - public void TryParseInstallerName() - { - this.ParseAndValidateInstallerVersion("Git-1.2.3.gvfs.4.5.gb16030b-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension); - this.ParseAndValidateInstallerVersion("git-1.2.3.gvfs.4.5.gb16030b-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension); - this.ParseAndValidateInstallerVersion("Git-1.2.3.gvfs.4.5.gb16030b-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension); - } - [TestCase] public void Version_Data_Null_Returns_False() { @@ -118,6 +109,46 @@ public void Compare_Version_Minor_Greater() version1.IsEqualTo(version2).ShouldEqual(false); } + [TestCase] + public void Compare_ReleaseCandidate_Less() + { + GitVersion version1 = new GitVersion(1, 2, 3, 1, "test", 4, 1); + GitVersion version2 = new GitVersion(1, 2, 3, 2, "test", 4, 1); + + version1.IsLessThan(version2).ShouldEqual(true); + version1.IsEqualTo(version2).ShouldEqual(false); + } + + [TestCase] + public void Compare_ReleaseCandidate_Greater() + { + GitVersion version1 = new GitVersion(1, 2, 3, 2, "test", 4, 1); + GitVersion version2 = new GitVersion(1, 2, 3, 1, "test", 4, 1); + + version1.IsLessThan(version2).ShouldEqual(false); + version1.IsEqualTo(version2).ShouldEqual(false); + } + + [TestCase] + public void Compare_ReleaseCandidate_NonRC_Less() + { + GitVersion version1 = new GitVersion(1, 2, 3, 0, "test", 4, 1); + GitVersion version2 = new GitVersion(1, 2, 3, null, "test", 4, 1); + + version1.IsLessThan(version2).ShouldEqual(true); + version1.IsEqualTo(version2).ShouldEqual(false); + } + + [TestCase] + public void Compare_ReleaseCandidate_NonRC_Greater() + { + GitVersion version1 = new GitVersion(1, 2, 3, null, "test", 4, 1); + GitVersion version2 = new GitVersion(1, 2, 3, 0, "test", 4, 1); + + version1.IsLessThan(version2).ShouldEqual(false); + version1.IsEqualTo(version2).ShouldEqual(false); + } + [TestCase] public void Compare_Version_Build_Less() { @@ -187,6 +218,7 @@ public void Allow_Blank_Minor_Revision() version.Major.ShouldEqual(1); version.Minor.ShouldEqual(2); version.Build.ShouldEqual(3); + version.ReleaseCandidate.ShouldEqual(null); version.Platform.ShouldEqual("test"); version.Revision.ShouldEqual(4); version.MinorRevision.ShouldEqual(0); @@ -201,21 +233,23 @@ public void Allow_Invalid_Minor_Revision() version.Major.ShouldEqual(1); version.Minor.ShouldEqual(2); version.Build.ShouldEqual(3); + version.ReleaseCandidate.ShouldEqual(null); version.Platform.ShouldEqual("test"); version.Revision.ShouldEqual(4); version.MinorRevision.ShouldEqual(0); } - private void ParseAndValidateInstallerVersion(string installerName) + [TestCase] + public void Allow_ReleaseCandidates() { GitVersion version; - bool success = GitVersion.TryParseInstallerName(installerName, GVFSPlatform.Instance.Constants.InstallerExtension, out version); - success.ShouldBeTrue(); + GitVersion.TryParseVersion("1.2.3.rc2.test.4.5", out version).ShouldEqual(true); version.Major.ShouldEqual(1); version.Minor.ShouldEqual(2); version.Build.ShouldEqual(3); - version.Platform.ShouldEqual("gvfs"); + version.ReleaseCandidate.ShouldEqual(2); + version.Platform.ShouldEqual("test"); version.Revision.ShouldEqual(4); version.MinorRevision.ShouldEqual(5); } diff --git a/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj b/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj index fe7648aac..890714857 100644 --- a/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj +++ b/GVFS/GVFS.UnitTests/GVFS.UnitTests.csproj @@ -1,7 +1,7 @@  - net461 + net471 Exe true @@ -21,6 +21,11 @@ + + + + + diff --git a/GVFS/GVFS.UnitTests/Mock/Git/MockLibGit2Repo.cs b/GVFS/GVFS.UnitTests/Mock/Git/MockLibGit2Repo.cs index c2494ba3f..990199561 100644 --- a/GVFS/GVFS.UnitTests/Mock/Git/MockLibGit2Repo.cs +++ b/GVFS/GVFS.UnitTests/Mock/Git/MockLibGit2Repo.cs @@ -12,8 +12,9 @@ public MockLibGit2Repo(ITracer tracer) { } - public override bool CommitAndRootTreeExists(string commitish) + public override bool CommitAndRootTreeExists(string commitish, out string treeSha) { + treeSha = string.Empty; return false; } diff --git a/GVFS/GVFS.VirtualFileSystemHook/GVFS.VirtualFileSystemHook.vcxproj b/GVFS/GVFS.VirtualFileSystemHook/GVFS.VirtualFileSystemHook.vcxproj index 8fb0cdb17..9390120db 100644 --- a/GVFS/GVFS.VirtualFileSystemHook/GVFS.VirtualFileSystemHook.vcxproj +++ b/GVFS/GVFS.VirtualFileSystemHook/GVFS.VirtualFileSystemHook.vcxproj @@ -14,7 +14,7 @@ {2D23AB54-541F-4ABC-8DCA-08C199E97ABB} Win32Proj GVFSVirtualFileSystemHook - 10.0.16299.0 + 10.0 GVFS.VirtualFileSystemHook GVFS.VirtualFileSystemHook @@ -22,13 +22,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/GVFS/GVFS.Virtualization/GVFS.Virtualization.csproj b/GVFS/GVFS.Virtualization/GVFS.Virtualization.csproj index bc5fa77f8..91772d269 100644 --- a/GVFS/GVFS.Virtualization/GVFS.Virtualization.csproj +++ b/GVFS/GVFS.Virtualization/GVFS.Virtualization.csproj @@ -1,7 +1,7 @@ - net461 + net471 true diff --git a/GVFS/GVFS/CommandLine/CloneVerb.cs b/GVFS/GVFS/CommandLine/CloneVerb.cs index 47d7d3f97..e81030837 100644 --- a/GVFS/GVFS/CommandLine/CloneVerb.cs +++ b/GVFS/GVFS/CommandLine/CloneVerb.cs @@ -215,20 +215,40 @@ public override void Execute() { if (!this.NoPrefetch) { - ReturnCode result = this.Execute( - enlistment, - verb => + bool trustPackIndexes = enlistment.GetTrustPackIndexesConfig(); + /* If pack indexes are not trusted, the prefetch can take a long time. + * We will run the prefetch command in the background. + */ + if (trustPackIndexes) + { + ReturnCode result = this.Execute( + enlistment, + verb => + { + verb.Commits = true; + verb.SkipVersionCheck = true; + verb.ResolvedCacheServer = cacheServer; + verb.ServerGVFSConfig = serverGVFSConfig; + }); + + if (result != ReturnCode.Success) { - verb.Commits = true; - verb.SkipVersionCheck = true; - verb.ResolvedCacheServer = cacheServer; - verb.ServerGVFSConfig = serverGVFSConfig; - }); + this.Output.WriteLine("\r\nError during prefetch @ {0}", fullEnlistmentRootPathParameter); + exitCode = (int)result; + } + } - if (result != ReturnCode.Success) + else { - this.Output.WriteLine("\r\nError during prefetch @ {0}", fullEnlistmentRootPathParameter); - exitCode = (int)result; + Process.Start(new ProcessStartInfo( + fileName: "gvfs", + arguments: "prefetch --commits") + { + UseShellExecute = true, + WindowStyle = ProcessWindowStyle.Hidden, + WorkingDirectory = enlistment.EnlistmentRoot + }); + this.Output.WriteLine("\r\nPrefetch of commit graph has been started as a background process. Git operations involving history may be slower until prefetch has completed.\r\n"); } } @@ -247,7 +267,7 @@ public override void Execute() verb.SkipVersionCheck = true; verb.ResolvedCacheServer = cacheServer; verb.DownloadedGVFSConfig = serverGVFSConfig; - }); + }); } } else diff --git a/GVFS/GVFS/CommandLine/GVFSVerb.cs b/GVFS/GVFS/CommandLine/GVFSVerb.cs index cdf9e920e..a9fcb9587 100644 --- a/GVFS/GVFS/CommandLine/GVFSVerb.cs +++ b/GVFS/GVFS/CommandLine/GVFSVerb.cs @@ -663,7 +663,7 @@ protected bool TryDownloadCommit( out string error, bool checkLocalObjectCache = true) { - if (!checkLocalObjectCache || !repo.CommitAndRootTreeExists(commitId)) + if (!checkLocalObjectCache || !repo.CommitAndRootTreeExists(commitId, out _)) { if (!gitObjects.TryDownloadCommit(commitId)) { diff --git a/GVFS/GVFS/GVFS.csproj b/GVFS/GVFS/GVFS.csproj index 6d9d579f9..892bc1386 100644 --- a/GVFS/GVFS/GVFS.csproj +++ b/GVFS/GVFS/GVFS.csproj @@ -2,7 +2,7 @@ Exe - net461 + net471 diff --git a/GVFS/GitHooksLoader/GitHooksLoader.vcxproj b/GVFS/GitHooksLoader/GitHooksLoader.vcxproj index 78a51bf7f..0c4d4fbdf 100644 --- a/GVFS/GitHooksLoader/GitHooksLoader.vcxproj +++ b/GVFS/GitHooksLoader/GitHooksLoader.vcxproj @@ -14,19 +14,19 @@ {798DE293-6EDA-4DC4-9395-BE7A71C563E3} Win32Proj GitHooksLoader - 10.0.16299.0 + 10.0 Application true - v142 + v143 Unicode Application false - v142 + v143 true Unicode diff --git a/Readme.md b/Readme.md index 2ee0517b9..e388634e5 100644 --- a/Readme.md +++ b/Readme.md @@ -42,15 +42,15 @@ will notify you when new versions are available. ## Building VFS for Git If you'd like to build your own VFS for Git Windows installer: -* Install Visual Studio 2017 Community Edition or higher (https://www.visualstudio.com/downloads/). +* Install Visual Studio 2022 Community Edition or higher (https://www.visualstudio.com/downloads/). * 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 SDK (10.0.10240.0) -* Install the .NET Core 2.1 SDK (https://www.microsoft.com/net/download/dotnet-core/2.1) + * 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) * Create a folder to clone into, e.g. `C:\Repos\VFSForGit` * Clone this repo into the `src` subfolder, e.g. `C:\Repos\VFSForGit\src` @@ -59,13 +59,7 @@ If you'd like to build your own VFS for Git Windows installer: 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. -You can also use Visual Studio 2019. There are a couple of options for getting all the dependencies. -* You can install Visual Studio 2017 side by side with Visual Studio 2019, and make sure that you have all the dependencies from Visual Studio 2017 installed -* Alternatively, if you only want to have Visual Studio 2019 installed, install the following extra dependencies: - * MSVC v141 VS 2017 C++ build tools via the optional components in the Visual Studio 2019 installer. It is under the "Desktop Development with C++" heading. - * Windows 10 SDK (10.0.10240.0) via the archived SDK page: https://developer.microsoft.com/en-us/windows/downloads/sdk-archive - -Visual Studio 2019 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 _except_ the Windows 10 SDK (10.0.10240.0) as this component is no longer shipped with VS2019 - **you'll still need to install that separately**. +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` diff --git a/Version.props b/Version.props index 1547245ce..d1f6f341b 100644 --- a/Version.props +++ b/Version.props @@ -5,10 +5,8 @@ 0.2.173.2 - 2.20220414.4 v2.31.0.vfs.0.1 diff --git a/scripts/CreateBuildArtifacts.bat b/scripts/CreateBuildArtifacts.bat index a7ba9795e..797ed0bf9 100644 --- a/scripts/CreateBuildArtifacts.bat +++ b/scripts/CreateBuildArtifacts.bat @@ -14,13 +14,6 @@ IF "%~2"=="" ( SET OUTROOT=%2 ) -REM Check NuGet is on the PATH -where /q nuget.exe -IF ERRORLEVEL 1 ( - ECHO ERROR: Could not find nuget.exe on the PATH - EXIT /B 1 -) - IF EXIST %OUTROOT% ( rmdir /s /q %OUTROOT% ) @@ -49,7 +42,7 @@ ECHO ^************************ ECHO Collecting FastFetch... mkdir %OUTROOT%\FastFetch xcopy /S /Y ^ - %VFS_OUTDIR%\FastFetch\bin\%CONFIGURATION%\net461\win-x64 ^ + %VFS_OUTDIR%\FastFetch\bin\%CONFIGURATION%\net471\win-x64 ^ %OUTROOT%\FastFetch\ || GOTO ERROR ECHO ^*********************************** @@ -57,22 +50,9 @@ ECHO ^* Collecting GVFS.FunctionalTests * ECHO ^*********************************** mkdir %OUTROOT%\GVFS.FunctionalTests xcopy /S /Y ^ - %VFS_OUTDIR%\GVFS.FunctionalTests\bin\%CONFIGURATION%\net461\win-x64 ^ + %VFS_OUTDIR%\GVFS.FunctionalTests\bin\%CONFIGURATION%\net471\win-x64 ^ %OUTROOT%\GVFS.FunctionalTests\ || GOTO ERROR -ECHO ^************************************* -ECHO ^* Creating Installers NuGet Package * -ECHO ^************************************* -mkdir %OUTROOT%\NuGetPackages -nuget.exe pack ^ - %VFS_OUTDIR%\GVFS.Installers\bin\%CONFIGURATION%\win-x64\GVFS.Installers.nuspec ^ - -BasePath %VFS_OUTDIR%\GVFS.Installers\bin\%CONFIGURATION%\win-x64 ^ - -OutputDirectory %OUTROOT%\NuGetPackages || GOTO ERROR - -REM Move the nuspec file to the NuGetPackages artifact directory -move %OUTROOT%\GVFS.Installers\GVFS.Installers.nuspec ^ - %OUTROOT%\NuGetPackages - GOTO :EOF :USAGE diff --git a/scripts/RunFunctionalTests.bat b/scripts/RunFunctionalTests.bat index 80ab7e1e4..ef86a74f8 100644 --- a/scripts/RunFunctionalTests.bat +++ b/scripts/RunFunctionalTests.bat @@ -27,7 +27,7 @@ IF NOT %ERRORLEVEL% == 0 ( ECHO error: unable to locate Git on the PATH (has it been installed?) ) -%VFS_OUTDIR%\GVFS.FunctionalTests\bin\%CONFIGURATION%\net461\win-x64\GVFS.FunctionalTests.exe /result:TestResult.xml %2 %3 %4 %5 +%VFS_OUTDIR%\GVFS.FunctionalTests\bin\%CONFIGURATION%\net471\win-x64\GVFS.FunctionalTests.exe /result:TestResult.xml %2 %3 %4 %5 SET error=%ERRORLEVEL% CALL %VFS_SCRIPTSDIR%\StopAllServices.bat diff --git a/scripts/RunUnitTests.bat b/scripts/RunUnitTests.bat index f9f684580..3424825ca 100644 --- a/scripts/RunUnitTests.bat +++ b/scripts/RunUnitTests.bat @@ -5,6 +5,6 @@ IF "%1"=="" (SET "CONFIGURATION=Debug") ELSE (SET "CONFIGURATION=%1") SET RESULT=0 -%VFS_OUTDIR%\GVFS.UnitTests\bin\%CONFIGURATION%\net461\win-x64\GVFS.UnitTests.exe || SET RESULT=1 +%VFS_OUTDIR%\GVFS.UnitTests\bin\%CONFIGURATION%\net471\win-x64\GVFS.UnitTests.exe || SET RESULT=1 EXIT /b %RESULT%