Skip to content

Commit 073d7e9

Browse files
Tyrie Vellatyrielv
authored andcommitted
Set checkout.workers config on gvfs clone and mount
Enable parallel checkout by setting checkout.workers=0 (auto-detect based on CPU count) in the required git config settings. Refactored the duplicated required-settings dictionary out of GVFSVerb and InProcessMount into a shared RequiredGitConfig class in GVFS.Common.Git, so future config additions only need one change. Also set checkout.workers=0 on the functional test control repo to match the GVFS enlistment config and keep error output in sync. AB#61609189 Assisted-by: Claude Opus 4.6 Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
1 parent ff944c1 commit 073d7e9

4 files changed

Lines changed: 178 additions & 219 deletions

File tree

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
5+
namespace GVFS.Common.Git
6+
{
7+
/// <summary>
8+
/// Single source of truth for the git config settings required by GVFS.
9+
/// These settings are enforced during clone, mount, and repair.
10+
/// </summary>
11+
public static class RequiredGitConfig
12+
{
13+
/// <summary>
14+
/// Returns the dictionary of required git config settings for a GVFS enlistment.
15+
/// These settings override any existing local configuration values.
16+
/// </summary>
17+
public static Dictionary<string, string> GetRequiredSettings(Enlistment enlistment)
18+
{
19+
string expectedHooksPath = Path.Combine(enlistment.WorkingDirectoryBackingRoot, GVFSConstants.DotGit.Hooks.Root);
20+
expectedHooksPath = Paths.ConvertPathToGitFormat(expectedHooksPath);
21+
22+
string gitStatusCachePath = null;
23+
if (!GVFSEnlistment.IsUnattended(tracer: null) && GVFSPlatform.Instance.IsGitStatusCacheSupported())
24+
{
25+
gitStatusCachePath = Path.Combine(
26+
enlistment.EnlistmentRoot,
27+
GVFSPlatform.Instance.Constants.DotGVFSRoot,
28+
GVFSConstants.DotGVFS.GitStatusCache.CachePath);
29+
30+
gitStatusCachePath = Paths.ConvertPathToGitFormat(gitStatusCachePath);
31+
}
32+
33+
string coreGVFSFlags = Convert.ToInt32(
34+
GitCoreGVFSFlags.SkipShaOnIndex |
35+
GitCoreGVFSFlags.BlockCommands |
36+
GitCoreGVFSFlags.MissingOk |
37+
GitCoreGVFSFlags.NoDeleteOutsideSparseCheckout |
38+
GitCoreGVFSFlags.FetchSkipReachabilityAndUploadPack |
39+
GitCoreGVFSFlags.BlockFiltersAndEolConversions)
40+
.ToString();
41+
42+
return new Dictionary<string, string>
43+
{
44+
// When running 'git am' it will remove the CRs from the patch file by default. This causes the patch to fail to apply because the
45+
// file that is getting the patch applied will still have the CRs. There is a --keep-cr option that you can pass the 'git am' command
46+
// but since we always want to keep CRs it is better to just set the config setting to always keep them so the user doesn't have to
47+
// remember to pass the flag.
48+
{ "am.keepcr", "true" },
49+
50+
// Update git settings to enable optimizations in git 2.20
51+
// Set 'checkout.optimizeNewBranch=true' to enable optimized 'checkout -b'
52+
{ "checkout.optimizenewbranch", "true" },
53+
54+
// Enable parallel checkout by auto-detecting the number of workers based on CPU count.
55+
{ "checkout.workers", "0" },
56+
57+
// We don't support line ending conversions - automatic conversion of LF to Crlf by git would cause un-necessary hydration. Disabling it.
58+
{ "core.autocrlf", "false" },
59+
60+
// Enable commit graph. https://devblogs.microsoft.com/devops/supercharging-the-git-commit-graph/
61+
{ "core.commitGraph", "true" },
62+
63+
// Perf - Git for Windows uses this to bulk-read and cache lstat data of entire directories (instead of doing lstat file by file).
64+
{ "core.fscache", "true" },
65+
66+
// Turns on all special gvfs logic. https://github.com/microsoft/git/blob/be5e0bb969495c428e219091e6976b52fb33b301/gvfs.h
67+
{ "core.gvfs", coreGVFSFlags },
68+
69+
// Use 'multi-pack-index' builtin instead of 'midx' to match upstream implementation
70+
{ "core.multiPackIndex", "true" },
71+
72+
// Perf - Enable parallel index preload for operations like git diff
73+
{ "core.preloadIndex", "true" },
74+
75+
// VFS4G never wants git to adjust line endings (causes un-necessary hydration of files)- explicitly setting core.safecrlf to false.
76+
{ "core.safecrlf", "false" },
77+
78+
// Possibly cause hydration while creating untrackedCache.
79+
{ "core.untrackedCache", "false" },
80+
81+
// This is to match what git init does.
82+
{ "core.repositoryformatversion", "0" },
83+
84+
// Turn on support for file modes on Mac & Linux.
85+
{ "core.filemode", GVFSPlatform.Instance.FileSystem.SupportsFileMode ? "true" : "false" },
86+
87+
// For consistency with git init.
88+
{ "core.bare", "false" },
89+
90+
// For consistency with git init.
91+
{ "core.logallrefupdates", "true" },
92+
93+
// Git to download objects on demand.
94+
{ GitConfigSetting.CoreVirtualizeObjectsName, "true" },
95+
96+
// Configure hook that git calls to get the paths git needs to consider for changes or untracked files
97+
{ GitConfigSetting.CoreVirtualFileSystemName, Paths.ConvertPathToGitFormat(GVFSConstants.DotGit.Hooks.VirtualFileSystemPath) },
98+
99+
// Ensure hooks path is configured correctly.
100+
{ "core.hookspath", expectedHooksPath },
101+
102+
// Hostname is no longer sufficent for VSTS authentication. VSTS now requires dev.azure.com/account to determine the tenant.
103+
// By setting useHttpPath, credential managers will get the path which contains the account as the first parameter. They can then use this information for auth appropriately.
104+
{ GitConfigSetting.CredentialUseHttpPath, "true" },
105+
106+
// Turn off credential validation(https://github.com/microsoft/Git-Credential-Manager-for-Windows/blob/master/Docs/Configuration.md#validate).
107+
// We already have logic to call git credential if we get back a 401, so there's no need to validate the PAT each time we ask for it.
108+
{ "credential.validate", "false" },
109+
110+
// This setting is not needed anymore, because current version of gvfs does not use index.lock.
111+
// (This change was introduced initially to prevent `git diff` from acquiring index.lock file.)
112+
// Explicitly setting this to true (which also is the default value) because the repo could have been
113+
// cloned in the past when autoRefreshIndex used to be set to false.
114+
{ "diff.autoRefreshIndex", "true" },
115+
116+
// In Git 2.24.0, some new config settings were created. Disable them locally in VFS for Git repos in case a user has set them globally.
117+
// https://github.com/microsoft/VFSForGit/pull/1594
118+
// This applies to feature.manyFiles, feature.experimental and fetch.writeCommitGraph settings.
119+
{ "feature.manyFiles", "false" },
120+
{ "feature.experimental", "false" },
121+
{ "fetch.writeCommitGraph", "false" },
122+
123+
// Turn off of git garbage collection. Git garbage collection does not work with virtualized object.
124+
// We do run maintenance jobs now that do the packing of loose objects so in theory we shouldn't need
125+
// this - but it is not hurting anything and it will prevent a gc from getting kicked off if for some
126+
// reason the maintenance jobs have not been running and there are too many loose objects
127+
{ "gc.auto", "0" },
128+
129+
// Prevent git GUI from displaying GC warnings.
130+
{ "gui.gcwarning", "false" },
131+
132+
// Update git settings to enable optimizations in git 2.20
133+
// Set 'index.threads=true' to enable multi-threaded index reads
134+
{ "index.threads", "true" },
135+
136+
// index parsing code in VFSForGit currently only supports version 4.
137+
{ "index.version", "4" },
138+
139+
// Perf - avoid un-necessary blob downloads during a merge.
140+
{ "merge.stat", "false" },
141+
142+
// Perf - avoid un-necessary blob downloads while git tries to search and find renamed files.
143+
{ "merge.renames", "false" },
144+
145+
// Don't use bitmaps to determine pack file contents, because we use MIDX for this.
146+
{ "pack.useBitmaps", "false" },
147+
148+
// Update Git to include sparse push algorithm
149+
{ "pack.useSparse", "true" },
150+
151+
// Stop automatic git GC
152+
{ "receive.autogc", "false" },
153+
154+
// Update git settings to enable optimizations in git 2.20
155+
// Set 'reset.quiet=true' to speed up 'git reset <foo>"
156+
{ "reset.quiet", "true" },
157+
158+
// Configure git to use our serialize status file - make git use the serialized status file rather than compute the status by
159+
// parsing the index file and going through the files to determine changes.
160+
{ "status.deserializePath", gitStatusCachePath },
161+
162+
// The GVFS Protocol forbids submodules, so prevent a user's
163+
// global config of "status.submoduleSummary=true" from causing
164+
// extreme slowness in "git status"
165+
{ "status.submoduleSummary", "false" },
166+
167+
// Generation number v2 isn't ready for full use. Wait for v3.
168+
{ "commitGraph.generationVersion", "1" },
169+
170+
// Disable the builtin FS Monitor in case it was enabled globally.
171+
{ "core.useBuiltinFSMonitor", "false" },
172+
};
173+
}
174+
}
175+
}

GVFS/GVFS.FunctionalTests/Tools/ControlGitRepo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public void Initialize()
5555
GitProcess.Invoke(this.RootPath, "config merge.renames false");
5656
GitProcess.Invoke(this.RootPath, "config advice.statusUoption false");
5757
GitProcess.Invoke(this.RootPath, "config core.abbrev 40");
58+
GitProcess.Invoke(this.RootPath, "config checkout.workers 0");
5859
GitProcess.Invoke(this.RootPath, "config core.useBuiltinFSMonitor false");
5960
GitProcess.Invoke(this.RootPath, "config pack.useSparse true");
6061
GitProcess.Invoke(this.RootPath, "config reset.quiet true");

GVFS/GVFS.Mount/InProcessMount.cs

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,69 +1357,7 @@ private bool TryCreateAlternatesFile(PhysicalFileSystem fileSystem, out string e
13571357

13581358
private bool TrySetRequiredGitConfigSettings()
13591359
{
1360-
string expectedHooksPath = Path.Combine(this.enlistment.WorkingDirectoryBackingRoot, GVFSConstants.DotGit.Hooks.Root);
1361-
expectedHooksPath = Paths.ConvertPathToGitFormat(expectedHooksPath);
1362-
1363-
string gitStatusCachePath = null;
1364-
if (!GVFSEnlistment.IsUnattended(tracer: null) && GVFSPlatform.Instance.IsGitStatusCacheSupported())
1365-
{
1366-
gitStatusCachePath = Path.Combine(
1367-
this.enlistment.EnlistmentRoot,
1368-
GVFSPlatform.Instance.Constants.DotGVFSRoot,
1369-
GVFSConstants.DotGVFS.GitStatusCache.CachePath);
1370-
1371-
gitStatusCachePath = Paths.ConvertPathToGitFormat(gitStatusCachePath);
1372-
}
1373-
1374-
string coreGVFSFlags = Convert.ToInt32(
1375-
GitCoreGVFSFlags.SkipShaOnIndex |
1376-
GitCoreGVFSFlags.BlockCommands |
1377-
GitCoreGVFSFlags.MissingOk |
1378-
GitCoreGVFSFlags.NoDeleteOutsideSparseCheckout |
1379-
GitCoreGVFSFlags.FetchSkipReachabilityAndUploadPack |
1380-
GitCoreGVFSFlags.BlockFiltersAndEolConversions)
1381-
.ToString();
1382-
1383-
Dictionary<string, string> requiredSettings = new Dictionary<string, string>
1384-
{
1385-
{ "am.keepcr", "true" },
1386-
{ "checkout.optimizenewbranch", "true" },
1387-
{ "core.autocrlf", "false" },
1388-
{ "core.commitGraph", "true" },
1389-
{ "core.fscache", "true" },
1390-
{ "core.gvfs", coreGVFSFlags },
1391-
{ "core.multiPackIndex", "true" },
1392-
{ "core.preloadIndex", "true" },
1393-
{ "core.safecrlf", "false" },
1394-
{ "core.untrackedCache", "false" },
1395-
{ "core.repositoryformatversion", "0" },
1396-
{ "core.filemode", GVFSPlatform.Instance.FileSystem.SupportsFileMode ? "true" : "false" },
1397-
{ "core.bare", "false" },
1398-
{ "core.logallrefupdates", "true" },
1399-
{ GitConfigSetting.CoreVirtualizeObjectsName, "true" },
1400-
{ GitConfigSetting.CoreVirtualFileSystemName, Paths.ConvertPathToGitFormat(GVFSConstants.DotGit.Hooks.VirtualFileSystemPath) },
1401-
{ "core.hookspath", expectedHooksPath },
1402-
{ GitConfigSetting.CredentialUseHttpPath, "true" },
1403-
{ "credential.validate", "false" },
1404-
{ "diff.autoRefreshIndex", "true" },
1405-
{ "feature.manyFiles", "false" },
1406-
{ "feature.experimental", "false" },
1407-
{ "fetch.writeCommitGraph", "false" },
1408-
{ "gc.auto", "0" },
1409-
{ "gui.gcwarning", "false" },
1410-
{ "index.threads", "true" },
1411-
{ "index.version", "4" },
1412-
{ "merge.stat", "false" },
1413-
{ "merge.renames", "false" },
1414-
{ "pack.useBitmaps", "false" },
1415-
{ "pack.useSparse", "true" },
1416-
{ "receive.autogc", "false" },
1417-
{ "reset.quiet", "true" },
1418-
{ "status.deserializePath", gitStatusCachePath },
1419-
{ "status.submoduleSummary", "false" },
1420-
{ "commitGraph.generationVersion", "1" },
1421-
{ "core.useBuiltinFSMonitor", "false" },
1422-
};
1360+
Dictionary<string, string> requiredSettings = RequiredGitConfig.GetRequiredSettings(this.enlistment);
14231361

14241362
GitProcess git = new GitProcess(this.enlistment);
14251363

0 commit comments

Comments
 (0)