From 035b006e2515318124ee6357a271aca8faed987e Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sun, 23 Nov 2025 20:07:15 -0800 Subject: [PATCH] fix: Support both canonical and legacy JSONL filenames in merge driver check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mergeDriverInstalled() function was only checking for the legacy "beads.jsonl" filename, but installMergeDriver() writes the canonical "issues.jsonl" filename. This caused false negatives where users with the correct canonical configuration would be incorrectly flagged as "not installed", potentially triggering unnecessary reinstalls. Changes: - Update mergeDriverInstalled() to check for both filenames - Add test for canonical issues.jsonl filename detection - Ensure existing correct configs are not unnecessarily overwritten This fixes the inconsistency found during code review of bd-3sz0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- cmd/bd/init.go | 7 ++++-- cmd/bd/init_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/cmd/bd/init.go b/cmd/bd/init.go index f715f749..78fcf36b 100644 --- a/cmd/bd/init.go +++ b/cmd/bd/init.go @@ -776,9 +776,12 @@ func mergeDriverInstalled() bool { return false } - // Look for beads JSONL merge attribute - return strings.Contains(string(content), ".beads/beads.jsonl") && + // Look for beads JSONL merge attribute (either canonical or legacy filename) + hasCanonical := strings.Contains(string(content), ".beads/issues.jsonl") && strings.Contains(string(content), "merge=beads") + hasLegacy := strings.Contains(string(content), ".beads/beads.jsonl") && + strings.Contains(string(content), "merge=beads") + return hasCanonical || hasLegacy } // installMergeDriver configures git to use bd merge for JSONL files diff --git a/cmd/bd/init_test.go b/cmd/bd/init_test.go index 5f3fc2e4..6aeb426c 100644 --- a/cmd/bd/init_test.go +++ b/cmd/bd/init_test.go @@ -848,6 +848,66 @@ func TestInitMergeDriverAutoConfiguration(t *testing.T) { t.Errorf("Merge driver should not contain invalid %%L or %%R placeholders, got %q", driver) } }) + + t.Run("detect canonical issues.jsonl filename in gitattributes", func(t *testing.T) { + // Reset global state + origDBPath := dbPath + defer func() { dbPath = origDBPath }() + dbPath = "" + + tmpDir := t.TempDir() + originalWd, err := os.Getwd() + if err != nil { + t.Fatalf("Failed to get working directory: %v", err) + } + defer os.Chdir(originalWd) + + if err := os.Chdir(tmpDir); err != nil { + t.Fatalf("Failed to change to temp directory: %v", err) + } + + // Initialize git repo + if err := runCommandInDir(tmpDir, "git", "init"); err != nil { + t.Fatalf("Failed to init git: %v", err) + } + + // Pre-configure correct merge driver and canonical filename in .gitattributes + if err := runCommandInDir(tmpDir, "git", "config", "merge.beads.driver", "bd merge %A %O %A %B"); err != nil { + t.Fatalf("Failed to set git config: %v", err) + } + + // Create .gitattributes with canonical filename (issues.jsonl, not beads.jsonl) + gitattrsPath := filepath.Join(tmpDir, ".gitattributes") + if err := os.WriteFile(gitattrsPath, []byte(".beads/issues.jsonl merge=beads\n"), 0644); err != nil { + t.Fatalf("Failed to create .gitattributes: %v", err) + } + + // Run bd init - should detect existing correct config and NOT reinstall + rootCmd.SetArgs([]string{"init", "--prefix", "test", "--quiet"}) + if err := rootCmd.Execute(); err != nil { + t.Fatalf("Init failed: %v", err) + } + + // Verify merge driver is still correct (not reinstalled unnecessarily) + driver, err := runCommandInDirWithOutput(tmpDir, "git", "config", "merge.beads.driver") + if err != nil { + t.Fatalf("Failed to get merge.beads.driver: %v", err) + } + driver = strings.TrimSpace(driver) + expected := "bd merge %A %O %A %B" + if driver != expected { + t.Errorf("Expected merge driver to remain %q, got %q", expected, driver) + } + + // Verify .gitattributes still has canonical filename (not overwritten) + content, err := os.ReadFile(gitattrsPath) + if err != nil { + t.Fatalf("Failed to read .gitattributes: %v", err) + } + if !strings.Contains(string(content), ".beads/issues.jsonl merge=beads") { + t.Errorf(".gitattributes should still contain canonical filename pattern") + } + }) } // TestReadFirstIssueFromJSONL_ValidFile verifies reading first issue from valid JSONL