Fix git hooks not working in worktrees (#1126)

Git hooks are shared across all worktrees and live in the common git
directory (e.g., /repo/.git/hooks), not the worktree-specific directory
(e.g., /repo/.git/worktrees/feature/hooks).

The core issue was in GetGitHooksDir() which used GetGitDir() instead
of GetGitCommonDir(). This caused hooks to be installed to/read from
the wrong location when running in a worktree.

Additionally, several places in the codebase manually constructed
hooks paths using gitDir + "hooks" instead of calling GetGitHooksDir().
These have been updated to use the proper worktree-aware path.

Affected areas:
- GetGitHooksDir() now uses GetGitCommonDir()
- CheckGitHooks() uses GetGitHooksDir()
- installHooks/uninstallHooks use GetGitHooksDir()
- runChainedHook() uses GetGitHooksDir()
- Doctor checks use git-common-dir for hooks paths
- Reset command uses GetGitCommonDir() for hooks and beads-worktrees

Symptoms that this fixes:
- Chained hooks (pre-commit.old) not running in worktrees
- bd hooks install not finding/installing hooks correctly in worktrees
- bd hooks list showing incorrect status in worktrees
- bd doctor reporting incorrect hooks status in worktrees

Co-authored-by: Zain Rizvi <4468967+ZainRizvi@users.noreply.github.com>
This commit is contained in:
Zain Rizvi
2026-01-16 14:01:43 -06:00
committed by GitHub
parent 493b7008a2
commit e723417168
7 changed files with 58 additions and 70 deletions

View File

@@ -21,12 +21,12 @@ var preCommitFrameworkPattern = regexp.MustCompile(`(?i)(pre-commit\s+run|prek\s
// hooksInstalled checks if bd git hooks are installed
func hooksInstalled() bool {
gitDir, err := git.GetGitDir()
hooksDir, err := git.GetGitHooksDir()
if err != nil {
return false
}
preCommit := filepath.Join(gitDir, "hooks", "pre-commit")
postMerge := filepath.Join(gitDir, "hooks", "post-merge")
preCommit := filepath.Join(hooksDir, "pre-commit")
postMerge := filepath.Join(hooksDir, "post-merge")
// Check if both hooks exist
_, err1 := os.Stat(preCommit)
@@ -81,11 +81,10 @@ type hookInfo struct {
// detectExistingHooks scans for existing git hooks
func detectExistingHooks() []hookInfo {
gitDir, err := git.GetGitDir()
hooksDir, err := git.GetGitHooksDir()
if err != nil {
return nil
}
hooksDir := filepath.Join(gitDir, "hooks")
hooks := []hookInfo{
{name: "pre-commit", path: filepath.Join(hooksDir, "pre-commit")},
{name: "post-merge", path: filepath.Join(hooksDir, "post-merge")},
@@ -137,11 +136,10 @@ func promptHookAction(existingHooks []hookInfo) string {
// installGitHooks installs git hooks inline (no external dependencies)
func installGitHooks() error {
gitDir, err := git.GetGitDir()
hooksDir, err := git.GetGitHooksDir()
if err != nil {
return err
}
hooksDir := filepath.Join(gitDir, "hooks")
// Ensure hooks directory exists
if err := os.MkdirAll(hooksDir, 0750); err != nil {