Mount: self-heal stale hook configurations#2010
Open
tyrielv wants to merge 1 commit into
Open
Conversation
b85c1d6 to
0d66177
Compare
0d66177 to
3ea8ab9
Compare
Two related fixes that together let `gvfs mount` succeed against an
enlistment whose pre-command hook is stale - typically because the GVFS
install location baked into .git/hooks/pre-command.hooks at clone time
has since moved (re-install, version-junction swap, system-to-user
migration, etc.).
Before this change, a stale .hooks text file causes every git invocation
that fires the pre-command hook to fail with:
fatal: pre-command hook aborted command
which makes the mount path unrecoverable.
Changes:
HooksInstaller.TryUpdateHooks
Also refresh the .hooks text files. Previously TryUpdateHooks only
refreshed the .exe copies of GitHooksLoader; the .hooks text file
(containing the absolute path of GVFS.Hooks.exe that the loader
execs) was only written at clone time by InstallHooks. When the
GVFS install moves, the .exe copies stay valid but the .hooks
path goes stale - and gvfs.mount.exe's existing TryUpdateHooks
call didn't repair it.
The new TryInstallGitCommandHooks calls are idempotent: when the
GVFS install path hasn't changed, the file is rewritten with the
same content.
GitProcess
Pass usePreCommandHook:false on all git operations that run during
the mount bootstrap path. These calls happen before gvfs.mount.exe
reaches TryUpdateHooks, so without this flag they trip over the
very stale-hook config we're trying to repair.
Affected: SetInLocalConfig, AddInLocalConfig, DeleteFromLocalConfig,
TryGetAllConfig, TryGetConfigUrlMatch, TryGetCredential,
TryGetCertificatePassword, TryDeleteCredential, TryStoreCredential.
GetFromConfig, GetFromLocalConfig and IsValidRepo also gain the
flag (some via the existing GetOriginUrl pattern, some new). None
of these operations mutate the working tree, so pre-command hook
is semantically inappropriate anyway - skipping it is correct
independent of the stale-hook scenario.
The mechanism: usePreCommandHook:false sets the COMMAND_HOOK_LOCK
environment variable, which Microsoft Git itself reads to suppress
pre-command hook invocation. So the failure is bypassed at the
git layer, not just inside GVFS.Hooks.exe.
Testing:
- 818/818 unit tests pass
- Manually verified end-to-end with a real enlistment whose
pre-command.hooks was corrupted to point at a non-existent path
(C:\NonExistent\Path\GVFS.Hooks.exe). Before this change, `gvfs
mount` failed with "pre-command hook aborted command". After this
change, mount succeeds and the .hooks file is rewritten to point
at the currently-running GVFS install.
Assisted-by: Claude Opus 4.7
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
3ea8ab9 to
da65668
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Regression fix from 9d3a09b3 ("Move pre-mount validation from gvfs.exe to gvfs.mount.exe").
Two related fixes that together let
gvfs mountsucceed against an enlistment whose pre-command hook is stale - typically because the GVFS install location baked into.git/hooks/pre-command.hooksat clone time has since moved (re-install, version-junction swap, system-to-user migration, etc.).Before this change, a stale
.hookstext file causes every git invocation that fires the pre-command hook to fail with:which makes the mount path unrecoverable.
Root cause
Commit 9d3a09b did two things that combined to break the self-heal path:
MountVerb.InstallHooks. Before 9d3a09b,MountVerb.ExecutecalledHooksInstaller.InstallHooks(which refreshes both the.exeloader copies AND the.hookstext files) early in execution. 9d3a09b dropped that call when consolidating most pre-mount work intogvfs.mount.exe.TrySetRequiredGitConfigSettings,LogEnlistmentInfoAndSetConfigValues, andTryCallGitCredentialall moved intoInProcessMount, where they now run before the existingTryUpdateHookscall at line 269.InProcessMount.TryUpdateHooksonly refreshed the.exeloader copies, never the.hookstext files - so even after it ran, a stale.hookspath persisted. And the bootstrap git calls now fire the (broken) pre-command hook beforeTryUpdateHooksever gets a chance.Changes
HooksInstaller.TryUpdateHooksAlso refresh the
.hookstext files. Previously this method only refreshed the.execopies ofGitHooksLoader; the.hookstext file (containing the absolute path ofGVFS.Hooks.exethat the loader execs) was only written at clone time byInstallHooks. The newTryInstallGitCommandHookscalls are idempotent: when the GVFS install path hasn't changed, the file is rewritten with the same content. This restores the self-heal behaviorMountVerb.InstallHooksused to provide.GitProcessPass
usePreCommandHook:falseon all git operations that run during the mount bootstrap path. These calls happen beforegvfs.mount.exereachesTryUpdateHooks, so without this flag they trip over the very stale-hook config we're trying to repair.Affected:
SetInLocalConfig,AddInLocalConfig,DeleteFromLocalConfig,TryGetAllConfig,TryGetConfigUrlMatch,TryGetCredential,TryGetCertificatePassword,TryDeleteCredential,TryStoreCredential.GetFromConfig,GetFromLocalConfigandIsValidRepoalso gain the flag (some via the existingGetOriginUrlpattern, some new). None of these operations mutate the working tree, so pre-command hook is semantically inappropriate anyway - skipping it is correct independent of the stale-hook scenario.The mechanism:
usePreCommandHook:falsesets theCOMMAND_HOOK_LOCKenvironment variable, which Microsoft Git itself reads to suppress pre-command hook invocation. The failure is bypassed at the git layer, not just insideGVFS.Hooks.exe.Testing
pre-command.hookswas corrupted to point at a non-existent path (C:\NonExistent\Path\GVFS.Hooks.exe). Before this change, mount failed with the "pre-command hook aborted command" error chain. After this change, mount succeeds and the.hooksfile is rewritten to point at the currently-running GVFS install.