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:
@@ -108,20 +108,20 @@ var hookManagerPatterns = []hookManagerPattern{
|
|||||||
// DetectActiveHookManager reads the git hooks to determine which manager installed them.
|
// DetectActiveHookManager reads the git hooks to determine which manager installed them.
|
||||||
// This is more reliable than just checking for config files when multiple managers exist.
|
// This is more reliable than just checking for config files when multiple managers exist.
|
||||||
func DetectActiveHookManager(path string) string {
|
func DetectActiveHookManager(path string) string {
|
||||||
// Get git dir
|
// Get common git dir (hooks are shared across worktrees)
|
||||||
cmd := exec.Command("git", "rev-parse", "--git-dir")
|
cmd := exec.Command("git", "rev-parse", "--git-common-dir")
|
||||||
cmd.Dir = path
|
cmd.Dir = path
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
gitDir := strings.TrimSpace(string(output))
|
gitCommonDir := strings.TrimSpace(string(output))
|
||||||
if !filepath.IsAbs(gitDir) {
|
if !filepath.IsAbs(gitCommonDir) {
|
||||||
gitDir = filepath.Join(path, gitDir)
|
gitCommonDir = filepath.Join(path, gitCommonDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for custom hooks path (core.hooksPath)
|
// Check for custom hooks path (core.hooksPath)
|
||||||
hooksDir := filepath.Join(gitDir, "hooks")
|
hooksDir := filepath.Join(gitCommonDir, "hooks")
|
||||||
hooksPathCmd := exec.Command("git", "config", "--get", "core.hooksPath")
|
hooksPathCmd := exec.Command("git", "config", "--get", "core.hooksPath")
|
||||||
hooksPathCmd.Dir = path
|
hooksPathCmd.Dir = path
|
||||||
if hooksPathOutput, err := hooksPathCmd.Output(); err == nil {
|
if hooksPathOutput, err := hooksPathCmd.Output(); err == nil {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ var bdHooksRunPattern = regexp.MustCompile(`\bbd\s+hooks\s+run\b`)
|
|||||||
// CheckGitHooks verifies that recommended git hooks are installed.
|
// CheckGitHooks verifies that recommended git hooks are installed.
|
||||||
func CheckGitHooks() DoctorCheck {
|
func CheckGitHooks() DoctorCheck {
|
||||||
// Check if we're in a git repository using worktree-aware detection
|
// Check if we're in a git repository using worktree-aware detection
|
||||||
gitDir, err := git.GetGitDir()
|
hooksDir, err := git.GetGitHooksDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DoctorCheck{
|
return DoctorCheck{
|
||||||
Name: "Git Hooks",
|
Name: "Git Hooks",
|
||||||
@@ -45,8 +45,6 @@ func CheckGitHooks() DoctorCheck {
|
|||||||
"post-merge": "Imports updated JSONL after git pull/merge",
|
"post-merge": "Imports updated JSONL after git pull/merge",
|
||||||
"pre-push": "Exports database to JSONL before push",
|
"pre-push": "Exports database to JSONL before push",
|
||||||
}
|
}
|
||||||
|
|
||||||
hooksDir := filepath.Join(gitDir, "hooks")
|
|
||||||
var missingHooks []string
|
var missingHooks []string
|
||||||
var installedHooks []string
|
var installedHooks []string
|
||||||
|
|
||||||
@@ -60,13 +58,7 @@ func CheckGitHooks() DoctorCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get repo root for external manager detection
|
// Get repo root for external manager detection
|
||||||
repoRoot := filepath.Dir(gitDir)
|
repoRoot := git.GetRepoRoot()
|
||||||
if filepath.Base(gitDir) != ".git" {
|
|
||||||
// Worktree case - gitDir might be .git file content
|
|
||||||
if cwd, err := os.Getwd(); err == nil {
|
|
||||||
repoRoot = cwd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for external hook managers (lefthook, husky, etc.)
|
// Check for external hook managers (lefthook, husky, etc.)
|
||||||
externalManagers := fix.DetectExternalHookManagers(repoRoot)
|
externalManagers := fix.DetectExternalHookManagers(repoRoot)
|
||||||
@@ -364,8 +356,8 @@ func CheckSyncBranchHookCompatibility(path string) DoctorCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sync-branch is configured - check pre-push hook version
|
// sync-branch is configured - check pre-push hook version
|
||||||
// Get actual git directory (handles worktrees where .git is a file)
|
// Get common git directory for hooks (shared across worktrees)
|
||||||
cmd := exec.Command("git", "rev-parse", "--git-dir")
|
cmd := exec.Command("git", "rev-parse", "--git-common-dir")
|
||||||
cmd.Dir = path
|
cmd.Dir = path
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -375,14 +367,13 @@ func CheckSyncBranchHookCompatibility(path string) DoctorCheck {
|
|||||||
Message: "N/A (not a git repository)",
|
Message: "N/A (not a git repository)",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gitDir := strings.TrimSpace(string(output))
|
gitCommonDir := strings.TrimSpace(string(output))
|
||||||
if !filepath.IsAbs(gitDir) {
|
if !filepath.IsAbs(gitCommonDir) {
|
||||||
gitDir = filepath.Join(path, gitDir)
|
gitCommonDir = filepath.Join(path, gitCommonDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use standard .git/hooks location for consistency with CheckGitHooks (issue #799)
|
// Hooks are shared across worktrees and live in the common git directory
|
||||||
// Note: core.hooksPath is intentionally NOT checked here to match CheckGitHooks behavior.
|
hookPath := filepath.Join(gitCommonDir, "hooks", "pre-push")
|
||||||
hookPath := filepath.Join(gitDir, "hooks", "pre-push")
|
|
||||||
|
|
||||||
hookContent, err := os.ReadFile(hookPath) // #nosec G304 - path is controlled
|
hookContent, err := os.ReadFile(hookPath) // #nosec G304 - path is controlled
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -24,12 +24,11 @@ func CheckSyncBranchQuick() string {
|
|||||||
// Checks all beads hooks: pre-commit, post-merge, pre-push, post-checkout.
|
// Checks all beads hooks: pre-commit, post-merge, pre-push, post-checkout.
|
||||||
// cliVersion is the current CLI version to compare against.
|
// cliVersion is the current CLI version to compare against.
|
||||||
func CheckHooksQuick(cliVersion string) string {
|
func CheckHooksQuick(cliVersion string) string {
|
||||||
// Get actual git directory (handles worktrees where .git is a file)
|
// Get hooks directory from common git dir (hooks are shared across worktrees)
|
||||||
gitDir, err := git.GetGitDir()
|
hooksDir, err := git.GetGitHooksDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "" // Not a git repo, skip
|
return "" // Not a git repo, skip
|
||||||
}
|
}
|
||||||
hooksDir := filepath.Join(gitDir, "hooks")
|
|
||||||
|
|
||||||
// Check if hooks dir exists
|
// Check if hooks dir exists
|
||||||
if _, err := os.Stat(hooksDir); os.IsNotExist(err) {
|
if _, err := os.Stat(hooksDir); os.IsNotExist(err) {
|
||||||
@@ -94,19 +93,19 @@ func CheckSyncBranchHookQuick(path string) string {
|
|||||||
return "" // sync-branch not configured, nothing to check
|
return "" // sync-branch not configured, nothing to check
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get git directory
|
// Get common git directory for hooks (shared across worktrees)
|
||||||
cmd := exec.Command("git", "rev-parse", "--git-dir")
|
cmd := exec.Command("git", "rev-parse", "--git-common-dir")
|
||||||
cmd.Dir = path
|
cmd.Dir = path
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "" // Not a git repo, skip
|
return "" // Not a git repo, skip
|
||||||
}
|
}
|
||||||
gitDir := strings.TrimSpace(string(output))
|
gitCommonDir := strings.TrimSpace(string(output))
|
||||||
if !filepath.IsAbs(gitDir) {
|
if !filepath.IsAbs(gitCommonDir) {
|
||||||
gitDir = filepath.Join(path, gitDir)
|
gitCommonDir = filepath.Join(path, gitCommonDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find pre-push hook (check shared hooks first)
|
// Find pre-push hook (check shared hooks first via core.hooksPath)
|
||||||
var hookPath string
|
var hookPath string
|
||||||
hooksPathCmd := exec.Command("git", "config", "--get", "core.hooksPath")
|
hooksPathCmd := exec.Command("git", "config", "--get", "core.hooksPath")
|
||||||
hooksPathCmd.Dir = path
|
hooksPathCmd.Dir = path
|
||||||
@@ -117,7 +116,8 @@ func CheckSyncBranchHookQuick(path string) string {
|
|||||||
}
|
}
|
||||||
hookPath = filepath.Join(sharedHooksDir, "pre-push")
|
hookPath = filepath.Join(sharedHooksDir, "pre-push")
|
||||||
} else {
|
} else {
|
||||||
hookPath = filepath.Join(gitDir, "hooks", "pre-push")
|
// Hooks are in the common git directory, not the worktree-specific one
|
||||||
|
hookPath = filepath.Join(gitCommonDir, "hooks", "pre-push")
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := os.ReadFile(hookPath) // #nosec G304 - path is controlled
|
content, err := os.ReadFile(hookPath) // #nosec G304 - path is controlled
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ func CheckGitHooks() []HookStatus {
|
|||||||
hooks := []string{"pre-commit", "post-merge", "pre-push", "post-checkout", "prepare-commit-msg"}
|
hooks := []string{"pre-commit", "post-merge", "pre-push", "post-checkout", "prepare-commit-msg"}
|
||||||
statuses := make([]HookStatus, 0, len(hooks))
|
statuses := make([]HookStatus, 0, len(hooks))
|
||||||
|
|
||||||
// Get actual git directory (handles worktrees)
|
// Get hooks directory from common git dir (hooks are shared across worktrees)
|
||||||
gitDir, err := git.GetGitDir()
|
hooksDir, err := git.GetGitHooksDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Not a git repo - return all hooks as not installed
|
// Not a git repo - return all hooks as not installed
|
||||||
for _, hookName := range hooks {
|
for _, hookName := range hooks {
|
||||||
@@ -67,7 +67,7 @@ func CheckGitHooks() []HookStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if hook exists
|
// Check if hook exists
|
||||||
hookPath := filepath.Join(gitDir, "hooks", hookName)
|
hookPath := filepath.Join(hooksDir, hookName)
|
||||||
versionInfo, err := getHookVersion(hookPath)
|
versionInfo, err := getHookVersion(hookPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Hook doesn't exist or couldn't be read
|
// Hook doesn't exist or couldn't be read
|
||||||
@@ -319,19 +319,17 @@ var hooksListCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func installHooks(embeddedHooks map[string]string, force bool, shared bool, chain bool) error {
|
func installHooks(embeddedHooks map[string]string, force bool, shared bool, chain bool) error {
|
||||||
// Get actual git directory (handles worktrees where .git is a file)
|
|
||||||
gitDir, err := git.GetGitDir()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var hooksDir string
|
var hooksDir string
|
||||||
if shared {
|
if shared {
|
||||||
// Use versioned directory for shared hooks
|
// Use versioned directory for shared hooks
|
||||||
hooksDir = ".beads-hooks"
|
hooksDir = ".beads-hooks"
|
||||||
} else {
|
} else {
|
||||||
// Use standard .git/hooks directory
|
// Use common git directory for hooks (shared across worktrees)
|
||||||
hooksDir = filepath.Join(gitDir, "hooks")
|
var err error
|
||||||
|
hooksDir, err = git.GetGitHooksDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create hooks directory if it doesn't exist
|
// Create hooks directory if it doesn't exist
|
||||||
@@ -401,12 +399,11 @@ func configureSharedHooksPath() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func uninstallHooks() error {
|
func uninstallHooks() error {
|
||||||
// Get actual git directory (handles worktrees)
|
// Get hooks directory from common git dir (hooks are shared across worktrees)
|
||||||
gitDir, err := git.GetGitDir()
|
hooksDir, err := git.GetGitHooksDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hooksDir := filepath.Join(gitDir, "hooks")
|
|
||||||
hookNames := []string{"pre-commit", "post-merge", "pre-push", "post-checkout", "prepare-commit-msg"}
|
hookNames := []string{"pre-commit", "post-merge", "pre-push", "post-checkout", "prepare-commit-msg"}
|
||||||
|
|
||||||
for _, hookName := range hookNames {
|
for _, hookName := range hookNames {
|
||||||
@@ -442,13 +439,13 @@ func uninstallHooks() error {
|
|||||||
// runChainedHook runs a .old hook if it exists. Returns the exit code.
|
// runChainedHook runs a .old hook if it exists. Returns the exit code.
|
||||||
// If the hook doesn't exist, returns 0 (success).
|
// If the hook doesn't exist, returns 0 (success).
|
||||||
func runChainedHook(hookName string, args []string) int {
|
func runChainedHook(hookName string, args []string) int {
|
||||||
// Get the hooks directory
|
// Get the hooks directory from common dir (hooks are shared across worktrees)
|
||||||
gitDir, err := git.GetGitDir()
|
hooksDir, err := git.GetGitHooksDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0 // Not a git repo, nothing to chain
|
return 0 // Not a git repo, nothing to chain
|
||||||
}
|
}
|
||||||
|
|
||||||
oldHookPath := filepath.Join(gitDir, "hooks", hookName+".old")
|
oldHookPath := filepath.Join(hooksDir, hookName+".old")
|
||||||
|
|
||||||
// Check if the .old hook exists and is executable
|
// Check if the .old hook exists and is executable
|
||||||
info, err := os.Stat(oldHookPath)
|
info, err := os.Stat(oldHookPath)
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ var preCommitFrameworkPattern = regexp.MustCompile(`(?i)(pre-commit\s+run|prek\s
|
|||||||
|
|
||||||
// hooksInstalled checks if bd git hooks are installed
|
// hooksInstalled checks if bd git hooks are installed
|
||||||
func hooksInstalled() bool {
|
func hooksInstalled() bool {
|
||||||
gitDir, err := git.GetGitDir()
|
hooksDir, err := git.GetGitHooksDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
preCommit := filepath.Join(gitDir, "hooks", "pre-commit")
|
preCommit := filepath.Join(hooksDir, "pre-commit")
|
||||||
postMerge := filepath.Join(gitDir, "hooks", "post-merge")
|
postMerge := filepath.Join(hooksDir, "post-merge")
|
||||||
|
|
||||||
// Check if both hooks exist
|
// Check if both hooks exist
|
||||||
_, err1 := os.Stat(preCommit)
|
_, err1 := os.Stat(preCommit)
|
||||||
@@ -81,11 +81,10 @@ type hookInfo struct {
|
|||||||
|
|
||||||
// detectExistingHooks scans for existing git hooks
|
// detectExistingHooks scans for existing git hooks
|
||||||
func detectExistingHooks() []hookInfo {
|
func detectExistingHooks() []hookInfo {
|
||||||
gitDir, err := git.GetGitDir()
|
hooksDir, err := git.GetGitHooksDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
hooksDir := filepath.Join(gitDir, "hooks")
|
|
||||||
hooks := []hookInfo{
|
hooks := []hookInfo{
|
||||||
{name: "pre-commit", path: filepath.Join(hooksDir, "pre-commit")},
|
{name: "pre-commit", path: filepath.Join(hooksDir, "pre-commit")},
|
||||||
{name: "post-merge", path: filepath.Join(hooksDir, "post-merge")},
|
{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)
|
// installGitHooks installs git hooks inline (no external dependencies)
|
||||||
func installGitHooks() error {
|
func installGitHooks() error {
|
||||||
gitDir, err := git.GetGitDir()
|
hooksDir, err := git.GetGitHooksDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hooksDir := filepath.Join(gitDir, "hooks")
|
|
||||||
|
|
||||||
// Ensure hooks directory exists
|
// Ensure hooks directory exists
|
||||||
if err := os.MkdirAll(hooksDir, 0750); err != nil {
|
if err := os.MkdirAll(hooksDir, 0750); err != nil {
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ func runReset(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
force, _ := cmd.Flags().GetBool("force")
|
force, _ := cmd.Flags().GetBool("force")
|
||||||
|
|
||||||
// Check if we're in a git repo
|
// Get common git directory (for hooks and beads-worktrees, which are shared across worktrees)
|
||||||
gitDir, err := git.GetGitDir()
|
gitCommonDir, err := git.GetGitCommonDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if jsonOutput {
|
if jsonOutput {
|
||||||
outputJSON(map[string]interface{}{
|
outputJSON(map[string]interface{}{
|
||||||
@@ -73,7 +73,7 @@ func runReset(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Collect what would be deleted
|
// Collect what would be deleted
|
||||||
items := collectResetItems(gitDir, beadsDir)
|
items := collectResetItems(gitCommonDir, beadsDir)
|
||||||
|
|
||||||
if !force {
|
if !force {
|
||||||
// Dry-run mode: show what would be deleted
|
// Dry-run mode: show what would be deleted
|
||||||
@@ -82,7 +82,7 @@ func runReset(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Actually perform the reset
|
// Actually perform the reset
|
||||||
performReset(items, gitDir, beadsDir)
|
performReset(items, gitCommonDir, beadsDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
type resetItem struct {
|
type resetItem struct {
|
||||||
@@ -91,7 +91,7 @@ type resetItem struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectResetItems(gitDir, beadsDir string) []resetItem {
|
func collectResetItems(gitCommonDir, beadsDir string) []resetItem {
|
||||||
var items []resetItem
|
var items []resetItem
|
||||||
|
|
||||||
// Check for running daemon
|
// Check for running daemon
|
||||||
@@ -106,9 +106,9 @@ func collectResetItems(gitDir, beadsDir string) []resetItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for git hooks
|
// Check for git hooks (hooks are in common git dir, shared across worktrees)
|
||||||
hookNames := []string{"pre-commit", "post-merge", "pre-push", "post-checkout"}
|
hookNames := []string{"pre-commit", "post-merge", "pre-push", "post-checkout"}
|
||||||
hooksDir := filepath.Join(gitDir, "hooks")
|
hooksDir := filepath.Join(gitCommonDir, "hooks")
|
||||||
for _, hookName := range hookNames {
|
for _, hookName := range hookNames {
|
||||||
hookPath := filepath.Join(hooksDir, hookName)
|
hookPath := filepath.Join(hooksDir, hookName)
|
||||||
if _, err := os.Stat(hookPath); err == nil {
|
if _, err := os.Stat(hookPath); err == nil {
|
||||||
@@ -141,8 +141,8 @@ func collectResetItems(gitDir, beadsDir string) []resetItem {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for sync branch worktrees
|
// Check for sync branch worktrees (in common git dir, shared across worktrees)
|
||||||
worktreesDir := filepath.Join(gitDir, "beads-worktrees")
|
worktreesDir := filepath.Join(gitCommonDir, "beads-worktrees")
|
||||||
if info, err := os.Stat(worktreesDir); err == nil && info.IsDir() {
|
if info, err := os.Stat(worktreesDir); err == nil && info.IsDir() {
|
||||||
items = append(items, resetItem{
|
items = append(items, resetItem{
|
||||||
Type: "worktrees",
|
Type: "worktrees",
|
||||||
|
|||||||
@@ -118,13 +118,15 @@ func GetGitCommonDir() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetGitHooksDir returns the path to the Git hooks directory.
|
// GetGitHooksDir returns the path to the Git hooks directory.
|
||||||
// This function is worktree-aware and handles both regular repos and worktrees.
|
// This function is worktree-aware: hooks are shared across all worktrees
|
||||||
|
// and live in the common git directory (e.g., /repo/.git/hooks), not in
|
||||||
|
// the worktree-specific directory (e.g., /repo/.git/worktrees/feature/hooks).
|
||||||
func GetGitHooksDir() (string, error) {
|
func GetGitHooksDir() (string, error) {
|
||||||
gitDir, err := GetGitDir()
|
commonDir, err := GetGitCommonDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return filepath.Join(gitDir, "hooks"), nil
|
return filepath.Join(commonDir, "hooks"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGitRefsDir returns the path to the Git refs directory.
|
// GetGitRefsDir returns the path to the Git refs directory.
|
||||||
|
|||||||
Reference in New Issue
Block a user