Repository navigation
hook: reset path before early hook lookup - #1014
Open
Tyrie Vella (tyrielv) wants to merge 1 commit into
Open
Tyrie Vella (tyrielv) wants to merge 1 commit into
Tyrie Vella (tyrielv) wants to merge 1 commit into
Conversation
find_hook() keeps the resolved path in a static strbuf. If the repository has no gitdir yet, it calls hook_path_early(). That function appends the hooks directory and the hook name to the buffer, but it does not reset the buffer first. In v2.53.0.vfs.0.0, find_hook() called strbuf_reset() before either branch. The rebase onto v2.54.0, which includes upstream b51e238 (hook: allow out-of-repo 'git hook' invocations), rewrote find_hook() and dropped that reset. Because of this, a process that finds the pre-command hook before the gitdir is set up cannot find post-command later in the same process. The second lookup appends to the first path, so access() fails and the hook is skipped. This affects dashed external commands, built-ins that do not set up the repository (for example 'git version'), and the case where a dashed external is not found and Git falls back to an alias. VFS for Git takes a lock in pre-command and releases it in post-command. If an external disappears between pre-command and dispatch, Git falls back to the alias and starts a child Git process. The parent never runs post-command, so the child waits for the parent's lock and the parent waits for the child. Reset the buffer before either branch. Add tests that check the pre-command and post-command order for a dashed external command, for 'git version', and for a dashed external that disappears before the alias fallback. Assisted-by: Claude Opus 5.5 Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Author
|
Note 🤖 Machine-drafted comment, reviewed and approved by Tyrie Vella (@tyrielv) before posting. Johannes Schindelin (@dscho) The v2.54 rebase dropped the |
This branch has not been deployed
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.
Problem and Context
find_hook()stores the resolved hook path in a staticstrbuf. If the repository has no gitdir yet,find_hook()callshook_path_early(). That function appends the hooks directory and the hook name to the buffer, but it does not reset the buffer first. Inv2.53.0.vfs.0.0,find_hook()calledstrbuf_reset(&path)before either branch. The rebase onto v2.54.0, which includes upstream b51e238 (hook: allow out-of-repo 'git hook' invocations), rewrotefind_hook()and dropped that reset. The gap is present fromv2.54.0.vfs.0.0throughvfs-2.56.0.As a result, a process that finds
pre-commandbefore setup cannot findpost-commandlater in the same process. The second lookup produces<hooks>/pre-command[.exe]<hooks>/post-command, soaccess()fails and Git skips the hook. Built-ins that set up the repository first are not affected, becauserepo_git_path_replace()resets the buffer. These paths are affected:git foorunsgit-foo)git versiongitwith no command (the usage text)VFS for Git takes a lock in
pre-commandand releases it inpost-command. microsoft/VFSForGit#2139 observed a deadlock with2.55.0.vfs.0.10. In that case, a test deleted an externalgit-<name>afterpre-commandran and before Git dispatched it. Git then expanded the alias and started a child Git process. The parent never ranpost-command, so the child waited for the parent's lock while the parent waited for the child.postCommand.strategy=worktree-changeis a separate way to skippost-command. VFS for Git does not set it, and the new tests setalwaysexplicitly.Changes
hook.c: Reset the static path buffer infind_hook()before either the early or the gitdir branch.t0401-post-command-hook.shthat runs a dashed external command and asserts thatpre-commandandpost-commandboth run for it.t0401-post-command-hook.shthat runsgit versionand asserts thatpre-commandandpost-commandboth run for it.t0401-post-command-hook.shthat uses apre-commandhook to delete a dashed external before Git dispatches it. The test asserts that Git falls back to the alias and that the hook order ispre git-vanish,post git-vanish,pre rev-parse,post rev-parse.Hook consumers will see
post-commandinvocations that these releases skipped. For a dashed external that is not found, the hook receives--exit_code=4294967295, becauseexit_codeis-1and Git prints it with%u. That formatting is unchanged by this PR. Baregitgets--exit_code=1.Known gaps and deliberate decisions
core.hooksPathfrom a subdirectory:hook_path_early()resolves a relativecore.hooksPathagainst the current directory, not the worktree root. Early hook lookups from a subdirectory then find no hooks. This behavior exists before this change and does not change here. No follow-up is planned yet.GVFS Protocol.