Adds Dolt auto-commit functionality for write commands and sets explicit commit authors. Includes fix for race condition in commandDidWrite (converted to atomic.Bool). Original PR: #1267 by @coffeegoddd Co-authored-by: Dustin Brown <dustin@dolthub.com>
209 lines
5.8 KiB
Go
209 lines
5.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/spf13/cobra"
|
|
"github.com/steveyegge/beads/internal/storage"
|
|
"github.com/steveyegge/beads/internal/ui"
|
|
)
|
|
|
|
var vcCmd = &cobra.Command{
|
|
Use: "vc",
|
|
GroupID: "sync",
|
|
Short: "Version control operations (requires Dolt backend)",
|
|
Long: `Version control operations for the beads database.
|
|
|
|
These commands require the Dolt storage backend. They provide git-like
|
|
version control for your issue data, including branching, merging, and
|
|
viewing history.
|
|
|
|
Note: 'bd history', 'bd diff', and 'bd branch' also work for quick access.
|
|
This subcommand provides additional operations like merge and commit.`,
|
|
}
|
|
|
|
var vcMergeStrategy string
|
|
|
|
var vcMergeCmd = &cobra.Command{
|
|
Use: "merge <branch>",
|
|
Short: "Merge a branch into the current branch",
|
|
Long: `Merge the specified branch into the current branch.
|
|
|
|
If there are merge conflicts, they will be reported. You can resolve
|
|
conflicts with --strategy.
|
|
|
|
Examples:
|
|
bd vc merge feature-xyz # Merge feature-xyz into current branch
|
|
bd vc merge feature-xyz --strategy ours # Merge, preferring our changes on conflict
|
|
bd vc merge feature-xyz --strategy theirs # Merge, preferring their changes on conflict`,
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
ctx := rootCtx
|
|
branchName := args[0]
|
|
|
|
// Check if storage supports versioning
|
|
vs, ok := storage.AsVersioned(store)
|
|
if !ok {
|
|
FatalErrorRespectJSON("merge requires Dolt backend (current backend does not support versioning)")
|
|
}
|
|
|
|
// Perform merge
|
|
conflicts, err := vs.Merge(ctx, branchName)
|
|
if err != nil {
|
|
FatalErrorRespectJSON("failed to merge branch: %v", err)
|
|
}
|
|
|
|
// Handle conflicts
|
|
if len(conflicts) > 0 {
|
|
if vcMergeStrategy != "" {
|
|
// Auto-resolve conflicts with specified strategy
|
|
for _, conflict := range conflicts {
|
|
table := conflict.Field // Field contains table name from GetConflicts
|
|
if table == "" {
|
|
table = "issues" // Default to issues table
|
|
}
|
|
if err := vs.ResolveConflicts(ctx, table, vcMergeStrategy); err != nil {
|
|
FatalErrorRespectJSON("failed to resolve conflicts: %v", err)
|
|
}
|
|
}
|
|
if jsonOutput {
|
|
outputJSON(map[string]interface{}{
|
|
"merged": branchName,
|
|
"conflicts": len(conflicts),
|
|
"resolved_with": vcMergeStrategy,
|
|
})
|
|
return
|
|
}
|
|
fmt.Printf("Merged %s with %d conflicts resolved using '%s' strategy\n",
|
|
ui.RenderAccent(branchName), len(conflicts), vcMergeStrategy)
|
|
return
|
|
}
|
|
|
|
// Report conflicts without auto-resolution
|
|
if jsonOutput {
|
|
outputJSON(map[string]interface{}{
|
|
"merged": branchName,
|
|
"conflicts": conflicts,
|
|
})
|
|
return
|
|
}
|
|
|
|
fmt.Printf("\n%s Merge completed with conflicts:\n\n", ui.RenderAccent("!!"))
|
|
for _, conflict := range conflicts {
|
|
fmt.Printf(" - %s\n", conflict.Field)
|
|
}
|
|
fmt.Printf("\nResolve conflicts with: bd vc merge %s --strategy [ours|theirs]\n\n", branchName)
|
|
return
|
|
}
|
|
|
|
if jsonOutput {
|
|
outputJSON(map[string]interface{}{
|
|
"merged": branchName,
|
|
"conflicts": 0,
|
|
})
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Successfully merged %s\n", ui.RenderAccent(branchName))
|
|
},
|
|
}
|
|
|
|
var vcCommitMessage string
|
|
|
|
var vcCommitCmd = &cobra.Command{
|
|
Use: "commit",
|
|
Short: "Create a commit with all staged changes",
|
|
Long: `Create a new Dolt commit with all current changes.
|
|
|
|
Examples:
|
|
bd vc commit -m "Added new feature issues"
|
|
bd vc commit --message "Fixed priority on several issues"`,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
ctx := rootCtx
|
|
|
|
if vcCommitMessage == "" {
|
|
FatalErrorRespectJSON("commit message is required (use -m or --message)")
|
|
}
|
|
|
|
// Check if storage supports versioning
|
|
vs, ok := storage.AsVersioned(store)
|
|
if !ok {
|
|
FatalErrorRespectJSON("commit requires Dolt backend (current backend does not support versioning)")
|
|
}
|
|
|
|
// We are explicitly creating a Dolt commit; avoid redundant auto-commit in PersistentPostRun.
|
|
commandDidExplicitDoltCommit = true
|
|
if err := vs.Commit(ctx, vcCommitMessage); err != nil {
|
|
FatalErrorRespectJSON("failed to commit: %v", err)
|
|
}
|
|
|
|
// Get the new commit hash
|
|
hash, err := vs.GetCurrentCommit(ctx)
|
|
if err != nil {
|
|
hash = "(unknown)"
|
|
}
|
|
|
|
if jsonOutput {
|
|
outputJSON(map[string]interface{}{
|
|
"committed": true,
|
|
"hash": hash,
|
|
"message": vcCommitMessage,
|
|
})
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Created commit %s\n", ui.RenderMuted(hash[:8]))
|
|
},
|
|
}
|
|
|
|
var vcStatusCmd = &cobra.Command{
|
|
Use: "status",
|
|
Short: "Show current branch and uncommitted changes",
|
|
Long: `Show the current branch, commit hash, and any uncommitted changes.
|
|
|
|
Examples:
|
|
bd vc status`,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
ctx := rootCtx
|
|
|
|
// Check if storage supports versioning
|
|
vs, ok := storage.AsVersioned(store)
|
|
if !ok {
|
|
FatalErrorRespectJSON("status requires Dolt backend (current backend does not support versioning)")
|
|
}
|
|
|
|
currentBranch, err := vs.CurrentBranch(ctx)
|
|
if err != nil {
|
|
FatalErrorRespectJSON("failed to get current branch: %v", err)
|
|
}
|
|
|
|
currentCommit, err := vs.GetCurrentCommit(ctx)
|
|
if err != nil {
|
|
currentCommit = "(unknown)"
|
|
}
|
|
|
|
if jsonOutput {
|
|
outputJSON(map[string]interface{}{
|
|
"branch": currentBranch,
|
|
"commit": currentCommit,
|
|
})
|
|
return
|
|
}
|
|
|
|
fmt.Printf("\n%s Version Control Status\n\n", ui.RenderAccent("📊"))
|
|
fmt.Printf(" Branch: %s\n", ui.StatusInProgressStyle.Render(currentBranch))
|
|
fmt.Printf(" Commit: %s\n", ui.RenderMuted(currentCommit[:8]))
|
|
fmt.Println()
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
vcMergeCmd.Flags().StringVar(&vcMergeStrategy, "strategy", "", "Conflict resolution strategy: 'ours' or 'theirs'")
|
|
vcCommitCmd.Flags().StringVarP(&vcCommitMessage, "message", "m", "", "Commit message")
|
|
|
|
vcCmd.AddCommand(vcMergeCmd)
|
|
vcCmd.AddCommand(vcCommitCmd)
|
|
vcCmd.AddCommand(vcStatusCmd)
|
|
rootCmd.AddCommand(vcCmd)
|
|
}
|