镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Read gvfs.* booleans with git when the environment changes config - #2179

Open
Tyrie Vella (tyrielv) wants to merge 1 commit into
masterfrom
tyrielv/libgit2-config-env-fallback
Open

Tyrie Vella (tyrielv) wants to merge 1 commit into
masterfrom
tyrielv/libgit2-config-env-fallback

Conversation

@tyrielv

@tyrielv Tyrie Vella (tyrielv) commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Problem and Context

libgit2 does not read the config that GIT_CONFIG_GLOBAL, GIT_CONFIG_SYSTEM, GIT_CONFIG_NOSYSTEM, GIT_CONFIG, GIT_CONFIG_COUNT, or GIT_CONFIG_PARAMETERS select or supply. RetryConfig already detects these variables with LibGit2Repo.EnvironmentChangesGitConfig() and reads its settings with git.exe. The boolean gvfs.* settings did not. They read the user's real config and ignored the value from the environment.

This affects gvfs.trust-pack-indexes, gvfs.prefetch-offload, gvfs.prefetch-use-idx, gvfs.enable-packfile-recovery, gvfs.background-cache-auth, gvfs.mount-progress, and gvfs.show-hydration-status. Git sets GIT_CONFIG_PARAMETERS for every git -c <key>=<value> command, so the hooks see these variables often. For example, CloneNetworkTests sets gvfs.trust-pack-indexes through GIT_CONFIG_GLOBAL. The clone ignores that value. The test passes only because its value matches the default.

Changes

  • When EnvironmentChangesGitConfig() is true, read boolean settings with git config --type=bool. Git normalizes the value, exits with 1 when the key is unset, and fails when the value is not a boolean. When the environment does not change config, the reads still use libgit2.
  • Add the LibGit2Repo.TryReadConfigBoolWithGit delegate. The static LibGit2Repo.GetConfigBoolOrDefault and every LibGit2RepoInvoker constructor require it. Remove the invoker constructors that took no reader.
  • Keep the failure policy of each read path. The static helper logs the failure and returns the default. The invoker throws when git cannot read the key, as its libgit2 read does. Thus an invalid gvfs.enable-packfile-recovery value stops maintenance instead of enabling pack recovery.
  • Add GitProcess.TryGetBoolFromConfig. GitRepo, CloneVerb, PrefetchVerb, BlobPrefetcher, and InProcessMount pass it as the reader. GitRepo supplies the reader that PrefetchStep, PackfileMaintenanceStep, and GitStatusCache use. gvfs.mount-progress now uses the static helper instead of its own LibGit2Repo read.
  • In GVFS.Hooks, read gvfs.show-hydration-status with the parent Git executable, as the alias check does. The query sets COMMAND_HOOK_LOCK, and it does not search the current directory or PATH for git. The alias check and this read share the config query and retry code.
  • Close the redirected standard input of every ProcessHelper.Run child. No caller writes to it. With GIT_CONFIG=-, git reads config from standard input, and a hook query waited for input forever.
  • Parse the git output in LibGit2Repo, because GVFS.Hooks compiles LibGit2Repo.cs but not GitProcess.cs.
  • Add unit tests for the git route, the libgit2 route, an unset key, a failed git read through the static helper and through the invoker, a git reader that throws, the output parser, the git config command lines in GitProcess and the hook, and the closed standard input in ProcessHelper.

Known gaps and deliberate decisions

  • No functional test with a non-default value. The new unit tests verify the routing and the parser. No functional test yet runs a GVFS command with an environment-supplied value that differs from the default. Deferred to keep this change focused. No follow-up is planned yet.
  • Relative config paths in GitProcess. GitProcess runs git from Environment.SystemDirectory. Thus a relative GIT_CONFIG_GLOBAL or GIT_CONFIG path resolves against that directory, and git reports the key as unset. RetryConfig and every other GitProcess config read already behave this way. Deferred to a separate change.
  • libgit2 string and multi-value reads. GitRepo.TryGetConfigValue (gvfs.max-active-enumerations), GetConfigString, and ForEachMultiVarConfig still ignore these environment variables. This change covers only boolean settings.
  • Other hook launches. The hooks still launch git and gvfs by name for the worktree and prefetch commands. Windows searches the current directory before PATH for those names. This change does not alter those launches.

@tyrielv
Tyrie Vella (tyrielv) force-pushed the tyrielv/libgit2-config-env-fallback branch from b1fce40 to 4d33e28 Compare November 12, 2026 16:52
@tyrielv
Tyrie Vella (tyrielv) force-pushed the tyrielv/libgit2-config-env-fallback branch 2 times, most recently from e58e786 to b49332f Compare November 12, 2026 18:00
@tyrielv
Tyrie Vella (tyrielv) marked this pull request as ready for review November 12, 2026 18:24
libgit2 does not read the config that GIT_CONFIG_GLOBAL, GIT_CONFIG_SYSTEM,
GIT_CONFIG_NOSYSTEM, GIT_CONFIG, GIT_CONFIG_COUNT, or GIT_CONFIG_PARAMETERS
select or supply. RetryConfig already reads its settings with git.exe in
that case. The boolean gvfs.* settings did not. For example,
gvfs.trust-pack-indexes, gvfs.prefetch-offload, and
gvfs.show-hydration-status ignored a value that came from one of these
variables, and the read used the user's real config instead.

When LibGit2Repo.EnvironmentChangesGitConfig() is true, read these
settings with "git config --type=bool". Git normalizes the value, exits
with 1 when the key is unset, and fails when the value is not a boolean.

- Add the LibGit2Repo.TryReadConfigBoolWithGit delegate. The static
  LibGit2Repo.GetConfigBoolOrDefault and every LibGit2RepoInvoker
  constructor require it. Remove the invoker constructors that took no
  reader.
- Keep the failure policy of each read path. The static helper logs the
  failure and returns the default. The invoker throws when git cannot
  read the key, as its libgit2 read does. This keeps an invalid
  gvfs.enable-packfile-recovery value from enabling pack recovery.
- Add GitProcess.TryGetBoolFromConfig. GitRepo, CloneVerb, PrefetchVerb,
  BlobPrefetcher, and InProcessMount pass it as the reader. Read
  gvfs.mount-progress through the static helper.
- In GVFS.Hooks, read gvfs.show-hydration-status with the parent Git
  executable, as the alias check does. Share the config query and retry
  code between the two reads.
- Close the redirected standard input in ProcessHelper. With
  GIT_CONFIG=-, git reads config from standard input, and a hook query
  waited for input forever.
- Add unit tests for the git route, the libgit2 route, an unset key, a
  failed git read through each path, a git reader that throws, the
  output parser, the git command lines, and the closed standard input.

Assisted-by: Claude Opus 5.5
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv
Tyrie Vella (tyrielv) force-pushed the tyrielv/libgit2-config-env-fallback branch from b49332f to d619851 Compare November 12, 2026 18:39

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the end-to-end validation requested in the inline comment.

IDictionary environment,
int configReadMaxAttempts = GitConfigReadRetry.MaxAttempts)
{
if (EnvironmentChangesGitConfig(environment))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an end-to-end test where an environment-supplied boolean disagrees with local gvfs.* config and assert actual GVFS behavior. For example, with a completed prefetch baseline, override gvfs.prefetch-offload in both directions and assert mount offload versus direct execution. The mock-based routing tests do not prove the compiled runtime path honors the effective value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants