首页
/ Beads 合并冲突完全指南:基于 Dolt 存储的检测、解决与验证实战

Beads 合并冲突完全指南:基于 Dolt 存储的检测、解决与验证实战

2026-09-10 18:20:22作者:董灵辛Dennis

导读:Beads 以 Dolt 作为存储后端,把 issue 数据保存在一个类似 Git 的 SQL 数据库中,因此多端同步(bd dolt pull / bd dolt pushbd sync)天然会面临三路合并(three-way merge)产生的行级冲突。本文以仓库中的 .agent/workflows/resolve-beads-conflict.md 为核心骨架,结合 cmd/bd 下的真实实现,系统讲解冲突的检测入口、SQL 级解决方案、仓库内置的 bd conflicts 操作面、验证与收尾流程,以及遗留 JSONL 设置的迁移路径。读完你将掌握一套可复制、可自动化、有源码依据的 Beads 冲突处理工作流。

Beads 使用 Dolt 作为存储后端。Dolt 像 Git 一样原生支持三路合并(three-way merge):它把每次写入提交成带哈希的历史,pull 时以本地、远端与共同祖先(merge base)三方比对,自动合并无冲突的改动;只有同一行的同一字段被双方分别修改时,才会产生真正的冲突。理解这一点是后续所有排查工作的前提——绝大多数 pull 并不会冲突,冲突恰恰说明两端在同步间隔内对同一批 issue 做了互相矛盾的修改。

1. 冲突检测:两条互补的检查入口

原文档给出的第一步是两条命令:

bd doctor
bd dolt pull

1.1 bd doctor:结构化健康扫描

bd doctor 是 Beads 的体检工具,会从多个维度检查数据库健康状态,其中专门包含对 Dolt 合并冲突的检查。在 cmd/bd/doctor/validation.go 中可以看到两条路径:

  • Dolt 后端checkDoltConflicts 直接查询 Dolt 的系统表 dolt_conflicts,按表汇总冲突数量(SELECT \table`, num_conflicts FROM dolt_conflicts),一旦发现未解决的冲突,会给出修复建议 Resolve conflicts with 'bd dolt conflicts resolve' or 'dolt conflicts resolve --ours/--theirs'`(见 cmd/bd/doctor/validation.go)。
  • 遗留 JSONL 后端CheckGitConflicts 扫描 .beads/ 目录下的 JSONL 文件,检测 Git 冲突标记(<<<<<<<=======>>>>>>>),发现后提示“Resolve merge conflicts in .beads/ files, then commit”(见 cmd/bd/doctor/validation.go)。

建议先跑 bd doctor 而不是直接 pull:它能把你尚未意识到的存量冲突一次性列出来,避免 pull 在冲突基础上叠加更多合并动作。

1.2 bd dolt pull:拉取即探测

bd dolt pull

bd dolt pull 从配置的 Dolt remote 拉取提交并执行合并(实现位于 cmd/bd/dolt.go)。如果远端没有新提交,命令输出 Pull complete.;如果拉取的改动与本地改动发生碰撞,Dolt 会在返回信息中列出发生冲突的表与行。

需要区分两种行为模式(源码注释明确说明,见 cmd/bd/dolt.go):

  • 嵌入式存储(embedded,进程内默认模式)bd dolt pull 可以带 --strategy ours|theirs 让 Dolt 的自动解析器直接按策略解决它不敢自动处理的冲突(例如两端同时修改了同一个 issue),而不是中止 pull 等待人工处理(功能编号 #4992)。
  • 服务端模式(sql-server / server-mode)--strategy 不被支持,pull 报告冲突后应使用 bd conflicts resolve 解决。

另外,pull 在尝试合并前会先检查 dolt.local-only 配置(bd config unset dolt.local-only 可重新启用远端同步),并且当 rig 完全没有配置 remote 时,bd dolt pull 会打印提示并安全退出 0,而不是报错——这是“没有 remote 是合法配置”的刻意设计(见 cmd/bd/dolt.go)。

2. 解决冲突:从 SQL 原语到 bd conflicts 操作面

2.1 SQL 级解决(Dolt 原生方案)

Dolt 为冲突提供了 SQL 化的解决接口。原文档给出的是最直接的方案:

# 查看冲突
bd sql "SELECT * FROM dolt_conflicts"

# 按“保留己方”或“采用对方”解决
bd sql "CALL dolt_conflicts_resolve('--ours')"
# 或者
bd sql "CALL dolt_conflicts_resolve('--theirs')"

dolt_conflicts 是 Dolt 的系统表,pull 合并后任何未解决的行冲突都会出现在其中;CALL dolt_conflicts_resolve('--ours')CALL dolt_conflicts_resolve('--theirs') 则是表级(table-level)的批量解决过程——前者保留本地一侧的值,后者采用远端一侧的值。这是 Dolt 引擎自带的能力,因此无论通过 bd sql 还是裸 dolt CLI 执行都有效。

注意语义差异--ours/--theirs 的方向取决于合并发生的方向。pull 合并时,“ours”指你本地工作区所在的分支(通常是 master),"theirs" 指刚拉下来的远端分支;而在 push 失败后的同步里方向可能相反。批量解决前先用 dolt_conflicts 看清每个表冲突了哪些行,再决定策略。

2.2 面向 issue 的现代方案:bd conflicts 子命令

裸 Dolt CLI 的冲突命令(dolt conflicts cat issuesdolt conflicts resolve --ours issuesdolt add -A && dolt commit)旗标面与 Git 略有差异,容易踩坑。为此 Beads 在 CLI 中内置了面向 issue 的冲突操作面(源码注释见 cmd/bd/conflicts.go),它读取的是 live working set,并且可以把解决粒度从“整张表”细化到“单个 issue 的单个字段”:

# 列出哪些表、哪些 issue 处于冲突状态
bd conflicts list

# 逐字段查看所有冲突行(base/ours/theirs 三方对照)
bd conflicts show
# 只看某一个 issue
bd conflicts show bd-1234
# 只看有分歧的字段(默认),或显示全部列
bd conflicts show --all-fields

# 逐行解决:保留己方 / 采用对方
bd conflicts resolve bd-1234 --ours
bd conflicts resolve bd-1234 bd-5678 --theirs

# 整表解决(Dolt 的表级解析)
bd conflicts resolve --all --ours
bd conflicts resolve --all --table config --theirs

# 收尾:提交一个冲突已全部解决的合并
bd conflicts resolve --conclude

关键行为(均有 cmd/bd/conflicts.go 源码背书):

  • 默认只显示分歧字段bd conflicts show 只展示 base/ours/theirs 三方不一致的字段,--all-fields 才展开全部列,便于聚焦真正的分叉点。
  • 冲突类别提示conflictKind 会区分“both sides deleted(双方删除)”“we deleted / they modified(我方删除、对方修改)”“we modified / they deleted(我方修改、对方删除)”“both sides added(双方新增)”“both sides modified(双方修改)”五类,帮助判断该选 --ours 还是 --theirs(见 cmd/bd/conflicts.go)。
  • 策略互斥校验--ours--theirs 不能同时传;--strategy ours|theirs 与旗标冲突会直接报错(见 cmd/bd/conflicts.go)。
  • 部分解决不提交:resolve 后只有当 dolt_conflicts 中不再有任何冲突行、且本次确实解决了内容时,才会自动提交合并(shouldCommitResolution 的判定逻辑见 cmd/bd/conflicts.go)。残留冲突时输出 N conflict(s) remain; the merge is not committed yet.,下一次 bd conflicts list 继续排查。
  • schema 冲突与约束违反不会被 dolt_conflicts 列出bd conflicts list/resolve 会额外检查 schema 冲突和约束违反(mergeBlockers),并给出人工处理指引——schema 冲突需要中止合并(dolt merge --abort)后在本地应用对方 ALTER TABLE 再重新合并,约束违反需要清理 dolt_constraint_violations_<table> 中的违规行(见 cmd/bd/conflicts.go)。
  • 并发保护bd conflicts 在 proxied-server 模式下不被支持(requireConflictSupport),因为它由代理服务器独立持有 working set。

2.3 自动化场景:bd sync 的冲突语义

如果你的工作流使用 bd sync(定时同步循环),需要注意它定义的三类退出语义(见 cmd/bd/sync.go):正常同步、合并冲突导致同步中止且未推送syncStatusConflict,不会被自动解决)、以及推送竞争(push race)类瞬时问题(下一轮会自动重试)。bd sync 采用正向冲突检测——从结构化冲突数据(合并捕获的冲突 + dolt_conflicts 存活行)判断,而不是从 pull 的退出码猜测,避免把网络错误误报成冲突、或漏掉“pull 成功但留下冲突行”的情况。对 CI 而言,收到冲突语义的退出码后,应当路由到人工或 bd conflicts resolve 流程,而不是盲目重试。

3. 验证与收尾:确认解决结果并推送

冲突解决后,必须验证结果并推送,才算完成一轮同步:

# 验证解决结果:列出所有 issue,确认数据符合预期
bd list --json | head

# 推送解决后的状态到远端
bd dolt push

bd list --json 输出结构化 JSON,便于 grep 或管道到 jq 校验关键 issue 的字段值。bd dolt push 的实现细节(见 cmd/bd/dolt.go):

  • 支持 --force 覆盖远端工作集(当远端存在未提交改动时使用),以及 --remote <name> 指定推送到某个命名 remote。
  • 若 rig 配置了 no-push: truedolt.local-only=true,push 会明确提示“skipping push / Remote sync is disabled”并跳过,而不是报错。
  • 没有配置任何 remote 时,Beads 会在征得同意(交互确认或 --yes)后尝试从 git origin 派生并采用一个 Dolt remote(adoptGitOriginRemoteForPush),用 --no-adopt 或环境变量 BD_NO_REMOTE_ADOPT=1 可完全禁用自动采用。
  • 若本地与远端历史分叉(无共同祖先,常见于多个 agent 各自 bd init 后推同一 remote),会打印三种恢复选项:bd bootstrap 重克隆(保留远端)、bd dolt push --force(以本地为准)、或删除 .beads/doltbd bootstrap 手动重建(见 cmd/bd/dolt.go)。

Hosted Dolt 场景需要为 push/pull 设置认证环境变量:DOLT_REMOTE_USERDOLT_REMOTE_PASSWORD(见 cmd/bd/dolt.go)。

4. 冲突后的状态一致性:is_blocked 重算与合并收尾

一个容易被忽略的细节:合并进来的写入会绕过常规的 is_blocked 计算。因此在 bd conflicts resolve 提交合并后,Beads 会调用 RecomputeBlockedAfterMerge 按解决前的 HEAD 重新计算 is_blocked 状态(见 cmd/bd/conflicts.go),保证 bd ready 等依赖该字段的查询不会在合并后返回过期结果。若存储后端不支持重算,会打印警告提示稍后运行 bd recompute-blocked。这意味着:解决冲突 ≠ 任务完成,还需要确认 bd ready 队列恢复正常,才不会把已解决的 issue 误判为仍被阻塞。

5. 遗留设置:JSONL 合并冲突的处理

如果项目还停留在旧版基于 Git 的 JSONL 设置(.beads/issues.jsonl),冲突形态完全不同——它不是 Dolt 行级冲突,而是 Git 文本冲突标记。原文档给出的流程是:

# 先在编辑器中手动解决 .beads/issues.jsonl 里的 Git 冲突标记,然后:
bd import -i .beads/issues.jsonl
git add .beads/issues.jsonl
git merge --continue

要点:

  1. 手动解决:Git 会把两端修改以 <<<<<<< HEAD / ======= / >>>>>>> 标记包裹在同一文件里,需要人工决定保留哪一端的 issue 行(必要时合并字段)。
  2. 重新导入bd import -i .beads/issues.jsonl 将解决后的文件重新导入 Beads 数据库,确保内存中的存储与文件一致。
  3. 收尾 Git 合并git add 标记已解决,git merge --continue 完成合并提交。

这也正是 bd doctorCheckGitConflicts 扫描 JSONL 冲突标记的原因——旧项目升级后,doctor 会同时覆盖 Dolt 与 JSONL 两种冲突形态,避免“Dolt 没冲突但 Git 合并卡住”的夹生状态。

6. 完整实战流程图

bd doctor / bd dolt pull
        │
        ▼
有冲突? ──否──► 直接同步:bd dolt push / bd sync
        │是
        ▼
bd conflicts list            # 哪些表、哪些 issue 冲突
bd conflicts show [issue-id] # 逐字段看 base/ours/theirs
        │
        ├─ 行冲突 ──► bd conflicts resolve <id> --ours|--theirs
        │                 (或 --all 整表解决;schema 冲突需
        │                  dolt merge --abort 后手动 ALTER TABLE)
        ▼
bd conflicts list            # 确认 remaining == 0
        │
        ▼
bd list --json | head        # 验证解决结果
bd dolt push                 # 推送(必要时 --force)

7. 预防冲突的工程建议

从源码可以提炼出几条预防性结论(均出自 cmd/bd/dolt.gocmd/bd/sync.go 的注释与行为):

  • 多 agent 场景用 bd bootstrap 而非各自 bd init:历史分叉(“no common ancestor”)正是多个 agent 独立初始化后推同一 remote 造成的,bd bootstrap 从既有 remote 克隆可根治(见 cmd/bd/dolt.go)。
  • 避免两端在同步间隔内同时编辑同一 issue:冲突本质是“同一行同一字段双写”。agent 职责分区、编辑后尽快 bd sync 能显著降低冲突概率。
  • schema 变更(升级 bd 触发迁移)时先收敛再升级:两端分别升级 bd 并各自跑迁移,可能造成主键集不同的 schema 分叉(isAncestorPKMismatchErr,见 cmd/bd/dolt.go),这类冲突无法自动解决、重试无效,只能选一个权威 clone 用 bd dolt push --force 确立远端,其余 clone 导出本地改动后重新 bd bootstrap(完整恢复指引见 cmd/bd/dolt.go)。

相关资源索引

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.16 K
2.78 K
kernelkernel
deepin linux kernel
C
34
18
docsdocs
暂无描述
Markdown
904
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
933
1.86 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
862
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.96 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.38 K
1.47 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
535
606
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
549
398
leetcodeleetcode
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Markdown
77
23