fix: Auto-repair stale merge driver configs with invalid placeholders

Old bd versions (<0.24.0) installed merge driver with invalid %L/%R
placeholders. Git only supports %O (base), %A (current), %B (other).

Changes:
- mergeDriverInstalled() now detects %L/%R and returns false to trigger repair
- bd init automatically fixes stale configs during initialization
- bd doctor --fix also repairs stale configs
- Added comprehensive test coverage for auto-repair

Fixes: bd-3sz0
Epic: bd-tbz3 (all sub-issues now complete)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-11-23 19:56:20 -08:00
parent 49830f7fbb
commit 1c8dd49f17
2 changed files with 66 additions and 1 deletions

View File

@@ -752,7 +752,7 @@ exit 0
return nil
}
// mergeDriverInstalled checks if bd merge driver is configured
// mergeDriverInstalled checks if bd merge driver is configured correctly
func mergeDriverInstalled() bool {
// Check git config for merge driver
cmd := exec.Command("git", "config", "merge.beads.driver")
@@ -761,6 +761,14 @@ func mergeDriverInstalled() bool {
return false
}
// Check if using old invalid placeholders (%L/%R from versions <0.24.0)
// Git only supports %O (base), %A (current), %B (other)
driverConfig := strings.TrimSpace(string(output))
if strings.Contains(driverConfig, "%L") || strings.Contains(driverConfig, "%R") {
// Stale config with invalid placeholders - needs repair
return false
}
// Check if .gitattributes has the merge driver configured
gitattributesPath := ".gitattributes"
content, err := os.ReadFile(gitattributesPath)

View File

@@ -791,6 +791,63 @@ func TestInitMergeDriverAutoConfiguration(t *testing.T) {
t.Errorf("Expected merge.beads.name to contain 'bd', got %q", name)
}
})
t.Run("auto-repair stale merge driver with invalid placeholders", 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)
}
// Configure stale merge driver with old invalid placeholders (%L/%R)
// This simulates a user who initialized with bd version <0.24.0
if err := runCommandInDir(tmpDir, "git", "config", "merge.beads.driver", "bd merge %L %R"); err != nil {
t.Fatalf("Failed to set stale git config: %v", err)
}
// Create .gitattributes with merge driver
gitattrsPath := filepath.Join(tmpDir, ".gitattributes")
if err := os.WriteFile(gitattrsPath, []byte(".beads/beads.jsonl merge=beads\n"), 0644); err != nil {
t.Fatalf("Failed to create .gitattributes: %v", err)
}
// Run bd init - should detect stale config and repair it
rootCmd.SetArgs([]string{"init", "--prefix", "test", "--quiet"})
if err := rootCmd.Execute(); err != nil {
t.Fatalf("Init failed: %v", err)
}
// Verify merge driver was updated to correct placeholders
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 be repaired to %q, got %q", expected, driver)
}
// Verify it no longer contains invalid placeholders
if strings.Contains(driver, "%L") || strings.Contains(driver, "%R") {
t.Errorf("Merge driver should not contain invalid %%L or %%R placeholders, got %q", driver)
}
})
}
// TestReadFirstIssueFromJSONL_ValidFile verifies reading first issue from valid JSONL