Skip to content

Commit efec513

Browse files
config: use --show-scope instead of --show-origin in cache
Context: The config cache path already gates on Git 2.54.0+ (or microsoft/git 2.53.0.vfs.0.1+) to use 'git config list --type=<X>'. These versions also support --show-scope, which directly reports the scope (system, global, local) as a simple string rather than a file path. Justification: The --show-origin approach required heuristic path matching to guess the scope from origin paths like 'file:/etc/gitconfig' or 'file:~/.gitconfig'. This was fragile: it could fail on non-standard install prefixes or platform-specific paths (e.g., Windows). Since --show-scope is available at the same Git versions we already require, we can use it for reliable scope detection with no guesswork. Implementation: - Replace --show-origin with --show-scope in the git config list call - Replace DetermineLevel() path heuristic with ParseScope() that does a direct string match on 'system', 'global', 'local' - Remove the now-unused Origin property from ConfigCacheEntry - Rename origin variables to scope throughout ConfigCache.Load() Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3125246 commit efec513

1 file changed

Lines changed: 22 additions & 35 deletions

File tree

src/shared/Core/GitConfiguration.cs

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -114,46 +114,33 @@ public interface IGitConfiguration
114114
/// </summary>
115115
internal class ConfigCacheEntry
116116
{
117-
public string Origin { get; set; }
118117
public string Value { get; set; }
119118
public GitConfigurationLevel Level { get; set; }
120119

121-
public ConfigCacheEntry(string origin, string value)
120+
public ConfigCacheEntry(string scope, string value)
122121
{
123-
Origin = origin;
124122
Value = value;
125-
Level = DetermineLevel(origin);
123+
Level = ParseScope(scope);
126124
}
127125

128-
private static GitConfigurationLevel DetermineLevel(string origin)
126+
private static GitConfigurationLevel ParseScope(string scope)
129127
{
130-
if (string.IsNullOrEmpty(origin))
131-
return GitConfigurationLevel.Unknown;
132-
133-
// Origins look like: "file:/path/to/config", "command line:", "standard input:"
134-
if (!origin.StartsWith("file:"))
135-
return GitConfigurationLevel.Unknown;
136-
137-
string path = origin.Substring(5); // Remove "file:" prefix
138-
139-
// System config is typically in /etc/gitconfig or $(prefix)/etc/gitconfig
140-
if (path.Contains("/etc/gitconfig") || path.EndsWith("/gitconfig"))
141-
return GitConfigurationLevel.System;
142-
143-
// Global config is typically in ~/.gitconfig or ~/.config/git/config
144-
if (path.Contains("/.gitconfig") || path.Contains("/.config/git/config"))
145-
return GitConfigurationLevel.Global;
146-
147-
// Local config is typically in .git/config within a repository
148-
if (path.Contains("/.git/config"))
149-
return GitConfigurationLevel.Local;
150-
151-
return GitConfigurationLevel.Unknown;
128+
switch (scope)
129+
{
130+
case "system":
131+
return GitConfigurationLevel.System;
132+
case "global":
133+
return GitConfigurationLevel.Global;
134+
case "local":
135+
return GitConfigurationLevel.Local;
136+
default:
137+
return GitConfigurationLevel.Unknown;
138+
}
152139
}
153140
}
154141

155142
/// <summary>
156-
/// Cache for Git configuration entries loaded from 'git config list --show-origin -z'.
143+
/// Cache for Git configuration entries loaded from 'git config list --show-scope -z'.
157144
/// </summary>
158145
internal class ConfigCache
159146
{
@@ -168,26 +155,26 @@ public void Load(string data, ITrace trace)
168155
{
169156
var entries = new Dictionary<string, List<ConfigCacheEntry>>(GitConfigurationKeyComparer.Instance);
170157

171-
var origin = new StringBuilder();
158+
var scope = new StringBuilder();
172159
var key = new StringBuilder();
173160
var value = new StringBuilder();
174161

175162
int i = 0;
176163
while (i < data.Length)
177164
{
178-
origin.Clear();
165+
scope.Clear();
179166
key.Clear();
180167
value.Clear();
181168

182-
// Read origin (NUL terminated)
169+
// Read scope (NUL terminated)
183170
while (i < data.Length && data[i] != '\0')
184171
{
185-
origin.Append(data[i++]);
172+
scope.Append(data[i++]);
186173
}
187174

188175
if (i >= data.Length)
189176
{
190-
trace.WriteLine("Invalid Git configuration output. Expected null terminator (\\0) after origin.");
177+
trace.WriteLine("Invalid Git configuration output. Expected null terminator (\\0) after scope.");
191178
break;
192179
}
193180

@@ -225,7 +212,7 @@ public void Load(string data, ITrace trace)
225212
i++;
226213

227214
string keyStr = key.ToString();
228-
var entry = new ConfigCacheEntry(origin.ToString(), value.ToString());
215+
var entry = new ConfigCacheEntry(scope.ToString(), value.ToString());
229216

230217
if (!entries.ContainsKey(keyStr))
231218
{
@@ -398,7 +385,7 @@ private void EnsureCacheLoaded(GitConfigurationType type)
398385
return;
399386
}
400387

401-
using (ChildProcess git = _git.CreateProcess($"config list --show-origin -z {typeArg}"))
388+
using (ChildProcess git = _git.CreateProcess($"config list --show-scope -z {typeArg}"))
402389
{
403390
git.Start(Trace2ProcessClass.Git);
404391
// To avoid deadlocks, always read the output stream first and then wait

0 commit comments

Comments
 (0)