fix: support git worktrees in hooks installation

Use `git rev-parse --git-dir` instead of hardcoded `.git` path to find
the actual git directory. In worktrees, `.git` is a file containing a
gitdir pointer, not a directory.

Changes:
- Add getGitDir() helper in hooks.go
- Update installHooks(), uninstallHooks(), CheckGitHooks() to use it
- Update hooksInstalled(), detectExistingHooks(), installGitHooks() in init.go
- Update checkHooksQuick() in doctor.go
- Update GitHooks() in doctor/fix/hooks.go
- Update tests to use real git repos via `git init`

Fixes bd-63l

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-11-29 23:19:57 -08:00
parent fa9285a663
commit 0b13a0df3c
7 changed files with 127 additions and 58 deletions

View File

@@ -2,6 +2,7 @@ package main
import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
@@ -20,12 +21,13 @@ func TestDetectExistingHooks(t *testing.T) {
t.Fatal(err)
}
// Initialize a git repository
// Initialize a real git repo (required for git rev-parse)
if err := exec.Command("git", "init").Run(); err != nil {
t.Skipf("Skipping test: git init failed: %v", err)
}
gitDir := filepath.Join(tmpDir, ".git")
hooksDir := filepath.Join(gitDir, "hooks")
if err := os.MkdirAll(hooksDir, 0750); err != nil {
t.Fatal(err)
}
tests := []struct {
name string
@@ -118,12 +120,13 @@ func TestInstallGitHooks_NoExistingHooks(t *testing.T) {
t.Fatal(err)
}
// Initialize a git repository
// Initialize a real git repo (required for git rev-parse)
if err := exec.Command("git", "init").Run(); err != nil {
t.Skipf("Skipping test: git init failed: %v", err)
}
gitDir := filepath.Join(tmpDir, ".git")
hooksDir := filepath.Join(gitDir, "hooks")
if err := os.MkdirAll(hooksDir, 0750); err != nil {
t.Fatal(err)
}
// Note: Can't fully test interactive prompt in automated tests
// This test verifies the logic works when no existing hooks present
@@ -164,12 +167,13 @@ func TestInstallGitHooks_ExistingHookBackup(t *testing.T) {
t.Fatal(err)
}
// Initialize a git repository
// Initialize a real git repo (required for git rev-parse)
if err := exec.Command("git", "init").Run(); err != nil {
t.Skipf("Skipping test: git init failed: %v", err)
}
gitDir := filepath.Join(tmpDir, ".git")
hooksDir := filepath.Join(gitDir, "hooks")
if err := os.MkdirAll(hooksDir, 0750); err != nil {
t.Fatal(err)
}
// Create an existing pre-commit hook
preCommitPath := filepath.Join(hooksDir, "pre-commit")