fix(sync): handle .beads/redirect in git status checks (bd-arjb)

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 <targetRepoDir>.

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 <noreply@anthropic.com>
This commit is contained in:
beads/crew/wolf
2026-01-05 19:57:19 -08:00
committed by Steve Yegge
parent ffd2e2273c
commit a61cbde692

View File

@@ -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()