feat(storage): add VersionedStorage interface with history/diff/branch operations

Extends Storage interface with Dolt-specific version control capabilities:

- New VersionedStorage interface in storage/versioned.go with:
  - History queries: History(), AsOf(), Diff()
  - Branch operations: Branch(), Merge(), CurrentBranch(), ListBranches()
  - Commit operations: Commit(), GetCurrentCommit()
  - Conflict resolution: GetConflicts(), ResolveConflicts()
  - Helper types: HistoryEntry, DiffEntry, Conflict

- DoltStore implements VersionedStorage interface

- New CLI commands:
  - bd history <id> - Show issue version history
  - bd diff <from> <to> - Show changes between commits/branches
  - bd branch [name] - List or create branches
  - bd vc merge <branch> - Merge branch to current
  - bd vc commit -m <msg> - Create a commit
  - bd vc status - Show current branch/commit

- Added --as-of flag to bd show for time-travel queries

- IsVersioned() helper for graceful SQLite backend detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
quartz
2026-01-17 01:54:55 -08:00
committed by gastown/crew/dennis
parent a7cd9136d8
commit 94581ab233
11 changed files with 1031 additions and 10 deletions
+12 -4
View File
@@ -28,6 +28,8 @@ import (
// Import Dolt driver
_ "github.com/dolthub/driver"
"github.com/steveyegge/beads/internal/storage"
)
// DoltStore implements the Storage interface using Dolt
@@ -342,13 +344,19 @@ func (s *DoltStore) Checkout(ctx context.Context, branch string) error {
return nil
}
// Merge merges the specified branch into the current branch
func (s *DoltStore) Merge(ctx context.Context, branch string) error {
// Merge merges the specified branch into the current branch.
// Returns any merge conflicts if present. Implements storage.VersionedStorage.
func (s *DoltStore) Merge(ctx context.Context, branch string) ([]storage.Conflict, error) {
_, err := s.db.ExecContext(ctx, "CALL DOLT_MERGE(?)", branch)
if err != nil {
return fmt.Errorf("failed to merge branch %s: %w", branch, err)
// Check if the error is due to conflicts
conflicts, conflictErr := s.GetConflicts(ctx)
if conflictErr == nil && len(conflicts) > 0 {
return conflicts, nil
}
return nil, fmt.Errorf("failed to merge branch %s: %w", branch, err)
}
return nil
return nil, nil
}
// CurrentBranch returns the current branch name