{"record":{"id":"0b960bb690506d49","repo":"gastownhall/beads","slug":"merge-branch-s-w-resolve-with-bd-vc-merge-s","errorCode":null,"errorMessage":"merge branch %s: %w (resolve with: bd vc merge %s --strategy ours|theirs)","messagePattern":"merge branch (.+?): %w \\(resolve with: bd vc merge (.+?) --strategy ours\\|theirs\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/versioncontrolops/version_control.go","lineNumber":115,"sourceCode":"//\n// This runs as a bare DOLT_MERGE under autocommit, so a real conflict makes\n// Dolt reject the implicit transaction (Error 1105: \"@autocommit must be\n// disabled so that merge conflicts can be resolved ...\") before dolt_conflicts\n// can even be inspected — conflicts = error here, same as plain `dolt merge`\n// with no further flags. Callers that want the flag Dolt's error names —\n// resolve-then-commit on conflict — must use MergeWithStrategy instead, which\n// runs the merge on a pinned session with the conflict-tolerant flags set\n// (#4992).\nfunc Merge(ctx context.Context, db DBConn, branch, author string) ([]storage.Conflict, error) {\n\t_, err := db.ExecContext(ctx, \"CALL DOLT_MERGE('--author', ?, ?)\", author, branch)\n\tif err != nil {\n\t\t// Check if the error is due to conflicts.\n\t\tconflicts, conflictErr := GetConflicts(ctx, db)\n\t\tif conflictErr == nil && len(conflicts) > 0 {\n\t\t\treturn conflicts, nil\n\t\t}\n\t\tif isMergeConflictAutocommitError(err) {\n\t\t\treturn nil, fmt.Errorf(\"merge branch %s: %w (resolve with: bd vc merge %s --strategy ours|theirs)\", branch, err, branch)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"merge branch %s: %w\", branch, err)\n\t}\n\treturn nil, nil\n}\n\n// isMergeConflictAutocommitError reports whether err is Dolt's autocommit\n// rejection of a conflicted merge (Error 1105, \"@autocommit must be disabled\n// so that merge conflicts can be resolved ...\"). It is the shape Merge\n// produces for every real conflict, since it runs under autocommit with\n// neither dolt_allow_commit_conflicts nor a pinned session (#4992) — matched\n// on message because the embedded engine and the MySQL driver report it as\n// different error types.\nfunc isMergeConflictAutocommitError(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tmsg := strings.ToLower(err.Error())","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/versioncontrolops/version_control.go#L97-L133","documentation":"Merge wraps Dolt's autocommit rejection of a conflicted merge (Error 1105: \"@autocommit must be disabled so that merge conflicts can be resolved...\") with actionable advice: \"merge branch <branch>: <err> (resolve with: bd vc merge <branch> --strategy ours|theirs)\". The library throws this shape when DOLT_MERGE ran under autocommit on a plain session, hit real conflicts, dolt_conflicts could not be inspected (or was empty), and isMergeConflictAutocommitError matched the error. Because the bare Merge cannot resolve conflicts itself, the message routes the operator to the strategy-based path.","triggerScenarios":"Calling Merge (not MergeWithStrategy) on a branch whose merge produces row-level conflicts; GetConflicts returns nothing readable because Dolt rejected the implicit transaction; the session lacks the conflict-tolerant flags (dolt_allow_commit_conflicts / pinned session).","commonSituations":"Two machines edited the same issues offline then merged; scripting bd vc merge without --strategy when both sides touched identical rows; older automation written before the strategy flag existed.","solutions":["Re-run with a strategy: bd vc merge <branch> --strategy ours (keep local) or --strategy theirs (take incoming), or call MergeWithStrategy in code.","Alternatively resolve out-of-band: inspect dolt_conflicts, run DOLT_CONFLICTS_RESOLVE('--ours'|'--theirs', table) per table, then commit.","If conflicts should have been auto-resolved, ensure you are on a version with MergeAndSettle/TryAutoResolveMergeConflicts and use the Pull path that routes through it.","Avoid bare Merge for branches known to conflict; default automation to the strategy variant."],"exampleFix":"// before\nconflicts, err := versioncontrolops.Merge(ctx, db, \"feature\", \"BD <bd@local>\") // Error 1105 autocommit rejection\n// after\nconflicts, err := versioncontrolops.MergeWithStrategy(ctx, db, \"feature\", \"\", \"ours\") // conflicts resolved as ours","handlingStrategy":"fallback","validationCode":"// prefer the strategy-aware merge when conflicts are possible\n// (bare Merge cannot resolve conflicts under autocommit)\nuseStrategyMerge := true\n_ = useStrategyMerge","typeGuard":"func isAutocommitConflictErr(err error) bool {\n    if err == nil { return false }\n    m := strings.ToLower(err.Error())\n    return strings.Contains(m, \"merge conflict\") && strings.Contains(m, \"autocommit\")\n}","tryCatchPattern":"conflicts, err := versioncontrolops.Merge(ctx, db, branch, author)\nif err != nil && isAutocommitConflictErr(err) {\n    // fall back to the strategy path the error message recommends\n    _, err = versioncontrolops.MergeWithStrategy(ctx, db, branch, author, \"ours\")\n    if err != nil { return fmt.Errorf(\"merge with strategy failed: %w\", err) }\n    return nil\n}\nif err != nil { return err }","preventionTips":["Default to MergeWithStrategy (or bd vc merge --strategy ours|theirs) in any automated flow; reserve bare Merge for known-fast-forward merges.","Fetch and pull before merging long-lived branches to shrink the conflict window.","Parse the actionable suffix '(resolve with: bd vc merge ... --strategy ...)' in tooling instead of failing silently.","Keep sessions conflict-tolerant (pinned session / dolt_allow_commit_conflicts) when you need to inspect dolt_conflicts after a failed merge."],"tags":["git","dolt","merge","conflict","autocommit"],"backgroundTag":"merge-conflict","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}