From a61cbde6926f92a5c45b4e10865290e262deb5b1 Mon Sep 17 00:00:00 2001 From: beads/crew/wolf Date: Mon, 5 Jan 2026 19:57:19 -0800 Subject: [PATCH] fix(sync): handle .beads/redirect in git status checks (bd-arjb) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running from a crew directory with .beads/redirect pointing to a shared beads directory in another repo, git status commands would fail with: fatal: /path/to/mayor/rig/.beads: is outside repository The fix detects when beadsDir is redirected and runs git commands from the directory containing the actual .beads/ using git -C . Updated functions: - gitHasBeadsChanges(): checks redirect and runs git from target repo - gitHasUncommittedBeadsChanges(): same fix for pre-flight check 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- cmd/bd/sync_git.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/cmd/bd/sync_git.go b/cmd/bd/sync_git.go index e2e68f0d..5ee0662f 100644 --- a/cmd/bd/sync_git.go +++ b/cmd/bd/sync_git.go @@ -90,6 +90,8 @@ func getRepoRootForWorktree(_ context.Context) string { // gitHasBeadsChanges checks if any tracked files in .beads/ have uncommitted changes // This function is worktree-aware and handles bare repo worktree setups (GH#827). +// It also handles redirected beads directories (bd-arjb) by running git commands +// from the directory containing the actual .beads/. func gitHasBeadsChanges(ctx context.Context) (bool, error) { // Get the absolute path to .beads directory beadsDir := beads.FindBeadsDir() @@ -97,6 +99,22 @@ func gitHasBeadsChanges(ctx context.Context) (bool, error) { return false, fmt.Errorf("no .beads directory found") } + // Check if beads directory is redirected (bd-arjb) + // When redirected, beadsDir points outside the current repo, so we need to + // run git commands from the directory containing the actual .beads/ + redirectInfo := beads.GetRedirectInfo() + if redirectInfo.IsRedirected { + // beadsDir is the target (e.g., /path/to/mayor/rig/.beads) + // We need to run git from the parent of .beads (e.g., /path/to/mayor/rig) + targetRepoDir := filepath.Dir(beadsDir) + statusCmd := exec.CommandContext(ctx, "git", "-C", targetRepoDir, "status", "--porcelain", beadsDir) //nolint:gosec // G204: beadsDir from beads.FindBeadsDir() + statusOutput, err := statusCmd.Output() + if err != nil { + return false, fmt.Errorf("git status failed: %w", err) + } + return len(strings.TrimSpace(string(statusOutput))) > 0, nil + } + // Run git status with absolute path from current directory. // This is more robust than using -C with a repo root, because: // 1. In bare repo worktree setups, GetMainRepoRoot() returns the parent @@ -451,6 +469,7 @@ func restoreBeadsDirFromBranch(ctx context.Context) error { // This detects the failure mode where a previous sync exported but failed before commit. // Returns true if the JSONL file has staged or unstaged changes (M or A status). // GH#885: Pre-flight safety check to detect incomplete sync operations. +// Also handles redirected beads directories (bd-arjb). func gitHasUncommittedBeadsChanges(ctx context.Context) (bool, error) { beadsDir := beads.FindBeadsDir() if beadsDir == "" { @@ -459,6 +478,20 @@ func gitHasUncommittedBeadsChanges(ctx context.Context) (bool, error) { jsonlPath := filepath.Join(beadsDir, "issues.jsonl") + // Check if beads directory is redirected (bd-arjb) + // When redirected, beadsDir points outside the current repo, so we need to + // run git commands from the directory containing the actual .beads/ + redirectInfo := beads.GetRedirectInfo() + if redirectInfo.IsRedirected { + targetRepoDir := filepath.Dir(beadsDir) + cmd := exec.CommandContext(ctx, "git", "-C", targetRepoDir, "status", "--porcelain", jsonlPath) //nolint:gosec // G204: jsonlPath from internal beads.FindBeadsDir() + output, err := cmd.Output() + if err != nil { + return false, fmt.Errorf("git status failed: %w", err) + } + return parseGitStatusForBeadsChanges(string(output)), nil + } + // Check git status for the JSONL file specifically cmd := exec.CommandContext(ctx, "git", "status", "--porcelain", jsonlPath) //nolint:gosec // G204: jsonlPath from internal beads.FindBeadsDir() output, err := cmd.Output()