From c5103e90b11b7a20a0155201b02001aa00dec1b5 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Tue, 25 Nov 2025 17:44:50 -0800 Subject: [PATCH] fix(sync): commit all .beads/ files before pull MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bd sync was only committing beads.jsonl, leaving other tracked files like metadata.json unstaged. This caused 'git pull --rebase' to fail with 'You have unstaged changes' error. Now checks and commits the entire .beads/ directory to ensure a clean worktree before pulling. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- cmd/bd/sync.go | 52 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/cmd/bd/sync.go b/cmd/bd/sync.go index da871164..a6f5a653 100644 --- a/cmd/bd/sync.go +++ b/cmd/bd/sync.go @@ -206,8 +206,8 @@ Use --merge to merge the sync branch back to main branch.`, } } - // Step 2: Check if there are changes to commit - hasChanges, err := gitHasChanges(ctx, jsonlPath) + // Step 2: Check if there are changes to commit (check entire .beads/ directory) + hasChanges, err := gitHasBeadsChanges(ctx) if err != nil { fmt.Fprintf(os.Stderr, "Error checking git status: %v\n", err) os.Exit(1) @@ -218,7 +218,7 @@ Use --merge to merge the sync branch back to main branch.`, fmt.Println("→ [DRY RUN] Would commit changes to git") } else { fmt.Println("→ Committing changes to git...") - if err := gitCommit(ctx, jsonlPath, message); err != nil { + if err := gitCommitBeadsDir(ctx, message); err != nil { fmt.Fprintf(os.Stderr, "Error committing: %v\n", err) os.Exit(1) } @@ -363,14 +363,14 @@ Use --merge to merge the sync branch back to main branch.`, } // Step 4.6: Commit the re-export if it created changes - hasPostImportChanges, err := gitHasChanges(ctx, jsonlPath) + hasPostImportChanges, err := gitHasBeadsChanges(ctx) if err != nil { fmt.Fprintf(os.Stderr, "Error checking git status after re-export: %v\n", err) os.Exit(1) } if hasPostImportChanges { fmt.Println("→ Committing DB changes from import...") - if err := gitCommit(ctx, jsonlPath, "bd sync: apply DB changes after import"); err != nil { + if err := gitCommitBeadsDir(ctx, "bd sync: apply DB changes after import"); err != nil { fmt.Fprintf(os.Stderr, "Error committing post-import changes: %v\n", err) os.Exit(1) } @@ -501,6 +501,20 @@ func gitHasChanges(ctx context.Context, filePath string) (bool, error) { return len(strings.TrimSpace(string(output))) > 0, nil } +// gitHasBeadsChanges checks if any tracked files in .beads/ have uncommitted changes +func gitHasBeadsChanges(ctx context.Context) (bool, error) { + beadsDir := findBeadsDir() + if beadsDir == "" { + return false, fmt.Errorf("no .beads directory found") + } + cmd := exec.CommandContext(ctx, "git", "status", "--porcelain", beadsDir) + output, err := cmd.Output() + if err != nil { + return false, fmt.Errorf("git status failed: %w", err) + } + return len(strings.TrimSpace(string(output))) > 0, nil +} + // gitCommit commits the specified file func gitCommit(ctx context.Context, filePath string, message string) error { // Stage the file @@ -524,6 +538,34 @@ func gitCommit(ctx context.Context, filePath string, message string) error { return nil } +// gitCommitBeadsDir stages and commits all tracked files in .beads/ +func gitCommitBeadsDir(ctx context.Context, message string) error { + beadsDir := findBeadsDir() + if beadsDir == "" { + return fmt.Errorf("no .beads directory found") + } + + // Stage all tracked changes in .beads/ + addCmd := exec.CommandContext(ctx, "git", "add", beadsDir) + if err := addCmd.Run(); err != nil { + return fmt.Errorf("git add failed: %w", err) + } + + // Generate message if not provided + if message == "" { + message = fmt.Sprintf("bd sync: %s", time.Now().Format("2006-01-02 15:04:05")) + } + + // Commit + commitCmd := exec.CommandContext(ctx, "git", "commit", "-m", message) + output, err := commitCmd.CombinedOutput() + if err != nil { + return fmt.Errorf("git commit failed: %w\n%s", err, output) + } + + return nil +} + // hasGitRemote checks if a git remote exists in the repository func hasGitRemote(ctx context.Context) bool { cmd := exec.CommandContext(ctx, "git", "remote")