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

@@ -32,18 +32,21 @@ func TestGetEmbeddedHooks(t *testing.T) {
}
func TestInstallHooks(t *testing.T) {
// Create temp directory with fake .git
// Create temp directory and init git repo
tmpDir := t.TempDir()
gitDir := filepath.Join(tmpDir, ".git", "hooks")
if err := os.MkdirAll(gitDir, 0755); err != nil {
t.Fatalf("Failed to create test git dir: %v", err)
}
// Change to temp directory
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
// 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", "hooks")
// Get embedded hooks
hooks, err := getEmbeddedHooks()
if err != nil {
@@ -78,18 +81,21 @@ func TestInstallHooks(t *testing.T) {
}
func TestInstallHooksBackup(t *testing.T) {
// Create temp directory with fake .git
// Create temp directory and init git repo
tmpDir := t.TempDir()
gitDir := filepath.Join(tmpDir, ".git", "hooks")
if err := os.MkdirAll(gitDir, 0755); err != nil {
t.Fatalf("Failed to create test git dir: %v", err)
}
// Change to temp directory
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
// 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", "hooks")
// Create an existing hook
existingHook := filepath.Join(gitDir, "pre-commit")
existingContent := "#!/bin/sh\necho old hook\n"
@@ -125,18 +131,21 @@ func TestInstallHooksBackup(t *testing.T) {
}
func TestInstallHooksForce(t *testing.T) {
// Create temp directory with fake .git
// Create temp directory and init git repo
tmpDir := t.TempDir()
gitDir := filepath.Join(tmpDir, ".git", "hooks")
if err := os.MkdirAll(gitDir, 0755); err != nil {
t.Fatalf("Failed to create test git dir: %v", err)
}
// Change to temp directory
// Change to temp directory first, then init
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
// 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", "hooks")
// Create an existing hook
existingHook := filepath.Join(gitDir, "pre-commit")
if err := os.WriteFile(existingHook, []byte("old"), 0755); err != nil {
@@ -162,18 +171,21 @@ func TestInstallHooksForce(t *testing.T) {
}
func TestUninstallHooks(t *testing.T) {
// Create temp directory with fake .git
// Create temp directory and init git repo
tmpDir := t.TempDir()
gitDir := filepath.Join(tmpDir, ".git", "hooks")
if err := os.MkdirAll(gitDir, 0755); err != nil {
t.Fatalf("Failed to create test git dir: %v", err)
}
// Change to temp directory
// Change to temp directory first, then init
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
// 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", "hooks")
// Get embedded hooks and install them
hooks, err := getEmbeddedHooks()
if err != nil {
@@ -199,18 +211,19 @@ func TestUninstallHooks(t *testing.T) {
}
func TestHooksCheckGitHooks(t *testing.T) {
// Create temp directory with fake .git
// Create temp directory and init git repo
tmpDir := t.TempDir()
gitDir := filepath.Join(tmpDir, ".git", "hooks")
if err := os.MkdirAll(gitDir, 0755); err != nil {
t.Fatalf("Failed to create test git dir: %v", err)
}
// Change to temp directory
// Change to temp directory first, then init
oldWd, _ := os.Getwd()
defer os.Chdir(oldWd)
os.Chdir(tmpDir)
// 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)
}
// Initially no hooks installed
statuses := CheckGitHooks()