bd vc:用 Git 式工作流管理 Beads 问题库的版本控制(commit / merge / status)
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
Beads 是一款为编码 Agent 提供"记忆升级"的数据库工具,它把 issue 数据存放在基于 Dolt 的存储引擎中。bd vc是 Beads 内置的版本控制命令组,让开发者可以用类似 Git 的心智模型——分支、合并、提交、历史——来管理问题数据。读完本文,你将掌握bd vc commit、bd vc merge、bd vc status三个子命令的完整用法,理解冲突产生的机制与--strategy解决策略的底层原理,并学会用 JSON 输出把版本控制操作接入自动化脚本。
bd vc 是什么:面向问题数据的版本控制命令组
bd vc(Version Control)在命令注册中被归入sync分组(cmd/bd/vc.go),其官方定位是:
Version control operations for the beads database. These commands provide git-like version control for your issue data, including branching, merging, and viewing history.
也就是说,Beads 的问题库本质上是一套拥有完整版本历史的数据库:每次bd create、bd edit等写操作都会改变工作集内容,而bd vc负责把这些变更固化成提交、在分支之间合并、并查看当前状态。
需要特别说明的是,Beads 刻意保留了"快捷访问"入口:bd history、bd diff、bd branch三个命令本身就覆盖了历史查看、差异对比和分支管理,而bd vc则补充了它们没有的操作——commit(提交)与 merge(合并)。如果你的诉求是快速看一眼历史或分支,直接用bd history/bd diff/bd branch(对应文档见 history.md、diff.md、branch.md)更顺手;要做提交与合并,就进入bd vc的子命令体系。
bd vc的基本用法:
bd vc [flags]其下共三个子命令:bd vc commit、bd vc merge、bd vc status。三者均不支持 proxied-server 模式(源码中usesProxiedServer()会直接返回 "not supported in proxied-server mode" 错误),因为代理服务器模式下工作集由服务端独占,本地无从谈起提交与合并。
bd vc status:查看分支、提交与未提交变更
bd vc status是最轻量的健康检查命令,用于回答三个问题:当前在哪个分支、HEAD 提交是什么、工作集里有没有未提交的变更。
bd vc status [flags]运行示例:
bd vc status其文本输出格式如下(源码见 cmd/bd/vc.go):
📊 Version Control Status Branch: main Commit: a1b2c3d4从实现看,它依次调用存储层的CurrentBranch(ctx)与GetCurrentCommit(ctx):前者在 Dolt 后端走versioncontrolops.CurrentBranch(internal/storage/dolt/store.go),后者读取当前 HEAD 哈希(internal/storage/dolt/versioned.go)。如果读取提交哈希失败,会降级显示(unknown)而不是直接报错,保证了命令的健壮性。
JSON 输出(脚本化)
所有bd vc子命令都支持全局--json标志。status的 JSON 负载包含两个键:
{"branch": "main", "commit": "a1b2c3d4..."}测试用例(cmd/bd/vc_embedded_test.go)验证了bd vc status --json的分支名必须是main且提交哈希非空——bd init之后仓库默认位于main分支,这一点可以作为脚本断言依据。
bd vc commit:一次性提交全部当前变更
bd vc commit把当前工作集中的所有变更打包成一条新的 Dolt 提交。它等价于一条"全量提交":不需要像 Git 那样先add再commit,写操作产生的所有改动(包括bd create创建的新 issue、bd edit修改的字段等)都会被包含。
bd vc commit [flags]Flags:
-m, --message string Commit message --stdin Read commit message from stdin三种提交消息来源
1. 命令行直接指定:
bd vc commit -m "Added new feature issues" bd vc commit --message "Fixed priority on several issues"2. 从 stdin 读取(支持多行):
echo "Multi-line message" | bd vc commit --stdin--stdin会读取全部标准输入并去除末尾换行符(strings.TrimRight(string(b), "\n"))。
3. 缺失时的行为:如果既没有-m/--message也没有--stdin,命令直接报错commit message is required (use -m, --message, or --stdin)(测试 cmd/bd/vc_embedded_test.go 专门验证了这一点)。--stdin与-m/--message同时指定也会报错:cannot specify both --stdin and -m/--message。
空提交的诚实反馈
与 Git 的nothing to commit类似,bd vc commit在干净工作集上不会伪造提交,而是输出:
Nothing to commit这是由存储层的CommitAll返回值驱动的:DoltStore.CommitAll在底层执行CALL DOLT_COMMIT('-Am', ?, '--author', ?),当捕获到 Dolt 的 "nothing to commit" 错误时返回(false, nil),命令据此判定无需提交(internal/storage/dolt/store.go)。需要注意的是,由于 Beads 的写操作(如bd create)默认自动提交,显式执行bd vc commit时常常已经"无物可提",这是正常现象,两种结果(committed=true/false)都是合法输出。
提交成功后输出新提交哈希的前 8 位:
Created commit a1b2c3d4JSON 模式下的负载结构为{"committed": bool, "hash": "...", "message": "..."},其中committed=false时 message 固定为"nothing to commit"。测试 cmd/bd/vc_embedded_test.go 验证了--json输出中committed字段必然存在。
并发安全:为什么是"原子信号"而非"比较 HEAD"
值得关注的是CommitAll的设计。早期实现用"提交前后 HEAD 比较"来判断是否真的产生了提交,这在并发写入场景下会把其他进程的提交误记到自己头上。现在的实现让CommitAll返回一个committed bool作为原子信号(见 cmd/bd/vc.go 中的注释,关联缺陷跟踪号 mybd-z9h7j),彻底消除了并发写者误归属的竞态。并发测试 cmd/bd/vc_embedded_test.go 用 10 个 worker 同时bd create+bd vc commit,断言所有 worker 要么成功、要么收到预期的 "one writer at a time" 或 "nothing to commit" 提示,且绝不 panic。
bd vc merge:把分支合并进当前分支
bd vc merge把指定分支合并到当前分支,这是协作场景的核心操作——例如把feature-xyz分支上的 issue 改动合回main。
bd vc merge <branch> [flags]Flags:
--strategy string Conflict resolution strategy: 'ours' or 'theirs'基础用法
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合并成功时输出Successfully merged feature-xyz;JSON 模式输出{"merged": "feature-xyz", "conflicts": 0}。
无冲突合并的底层链路
不带--strategy时,命令调用存储层的store.Merge(ctx, branch)。在 Dolt 后端,这最终执行CALL DOLT_MERGE('--author', ?, ?)(internal/storage/versioncontrolops/version_control.go),即一次裸的 autocommit 模式 DOLT_MERGE。合并成功且无冲突后,Dolt 存储层还会做一件关键收尾:重算is_blocked反规范化列(internal/storage/dolt/store.go)。
这是因为分支合并会引入一批"绕过本地钩子"写入的数据:被合并进来的 issue 的阻塞状态(blocked state)从未经过本分支的钩子计算,直接沿用旧值可能过期。所以Merge在合并前记录 pre-merge HEAD,合并成功后调用recomputeBlockedAfterPull(ctx, preHead),只对自 preHead 以来变化的行重算阻塞状态并提交结果,避免全图重算的开销。这一机制同样适用于后续的冲突解决流程(RecomputeBlockedAfterMerge,见 internal/storage/dolt/store.go)。
冲突发生时的表现
问题数据的合并不可能永远一帆风顺:当两个分支修改了同一条 issue 的同一字段时,冲突就产生了。bd vc merge对冲突的处理分两种情况:
1. 不带--strategy:裸 DOLT_MERGE 在 autocommit 下遇到真实冲突会被 Dolt 直接拒绝(Error 1105:"@autocommit must be disabled so that merge conflicts can be resolved ...")。Merge会检测这种冲突形态的错误(通过消息同时包含 "merge conflict" 和 "autocommit" 判定,internal/storage/versioncontrolops/version_control.go),并读取dolt_conflicts表把冲突返回给 CLI。CLI 随后打印冲突字段列表,并给出明确提示:
!! Merge completed with conflicts: - title - priority Resolve conflicts with: bd vc merge feature-xyz --strategy [ours|theirs]JSON 模式下输出{"merged": "feature-xyz", "conflicts": [冲突字段...]}。
2. 带--strategy:这是解决冲突的逃生通道。MergeWithStrategy不再走共享连接池的裸合并,而是固定单条连接跑完"合并 → 解析 → 修复 → 提交"整个序列(internal/storage/dolt/store.go)。原因很微妙:Dolt 的冲突容忍会话标志(@@dolt_allow_commit_conflicts、@@dolt_force_transaction_commit)是会话级状态,共享连接池可能把后续语句分给另一条连接,导致策略设置失效。固定单连接后,versioncontrolops.MergeWithStrategy才能把ours/theirs真正送达 DOLT_CONFLICTS_RESOLVE。
--strategy的合法值只有两个,存储层做了严格校验(internal/storage/versioncontrolops/conflicts.go):
ours:冲突时保留**当前分支(我方)**的修改;theirs:冲突时采用**被合并分支(对方)**的修改。
用策略合并时,即使产生冲突也会完成合并并提交。输出会报告被策略解决的冲突数量:
Merged feature-xyz with 2 conflicts resolved using 'ours' strategy对应 JSON:{"merged": "feature-xyz", "conflicts": 2, "resolved_with": "ours"}。测试 cmd/bd/vc_embedded_test.go 验证了合并分支后--json输出的merged字段与分支名一致。
注意:策略合并不是万能的
并非所有存储后端都支持--strategy合并。代码在调用MergeWithStrategy前会断言存储层是否实现storage.StrategicMerger接口,不支持时返回错误storage backend %T does not support --strategy merges。此外,--strategy解决的是行级字段冲突,对于**表结构冲突(schema conflict)与约束冲突(constraint violation)**这两类 Dolt 冲突,ours/theirs并不适用——它们没有对应的两方取舍语义,需要另走手工处理路径。
冲突的进阶处理:bd conflicts 命令族
bd vc merge提示里的--strategy只是"整表/整条合并"维度的快刀。当合并因为复杂冲突停摆时,Beads 还提供了专门的bd conflicts命令族(cmd/bd/conflicts.go),它是合并停滞后的运维面:把 Dolt 原始的冲突表变成"按 issue、按字段"的问题导向界面,无需钻进.beads/dolt/<db>目录敲原生 dolt CLI。
核心子命令:
bd conflicts list # 哪些表、哪些 issue 存在冲突 bd conflicts show # 逐字段展示每个冲突行(base/ours/theirs) bd conflicts show bd-1234 # 只看某一条 issue bd conflicts resolve bd-1234 --ours # 保留我方这一条 issue 的修改 bd conflicts resolve --all --theirs # 全部采用对方修改 bd conflicts resolve --conclude # 提交一个已经解析完毕的合并bd conflicts show会把冲突行按字段三栏展示(base / ours / theirs),且默认只显示发生分歧的字段,--all-fields才显示全部列。bd conflicts resolve支持按 issue 逐行解析(bd conflicts resolve bd-1234 --ours)或整表解析(--all),只有在所有冲突都清空后才提交合并——部分解析会保留合并打开状态,供下一轮继续。--no-commit可以只解析不提交,--conclude则用来收尾一个"冲突已清零但合并未提交"的中间态。
这一命令族与bd vc merge --strategy共享同一个is_blocked重算钩子(commitMergeResolution与vc merge都调用blockedAfterMergeRecomputerFor定位具体存储实现,cmd/bd/conflicts.go),保证无论走哪条冲突解决路径,合并进来的数据最终都会重算阻塞状态,bd ready不会因过期数据给出错误结果。
自动化友好:JSON 输出约定
三个bd vc子命令都支持全局--json标志,负载键位稳定,适合 CI 与 Agent 脚本消费:
| 子命令 | JSON 键 | 说明 |
|---|---|---|
bd vc status --json | branch/commit | 当前分支与 HEAD 哈希 |
bd vc commit --json | committed/hash/message | committed=false表示无物可提 |
bd vc merge --json | merged/conflicts/resolved_with | 无策略时无resolved_with;conflicts 为数字(策略模式)或字段数组(无策略模式) |
一个可落地的脚本模式:先bd vc status --json确认分支,再bd vc commit --json -m "..."并检查committed是否为 true,最后bd vc merge <branch> --json检查conflicts是否非零,非零则按需重跑--strategy。注意 proxied-server 模式下三个子命令均不可用,脚本应先行探测运行模式。
测试验证:行为被测试锁定的证据
bd vc的行为有完整的测试覆盖(cmd/bd/vc_embedded_test.go,需BEADS_TEST_EMBEDDED_DOLT=1环境变量启用嵌入式 Dolt 测试):
- status:断言默认分支为
main、提交哈希非空(文本与 JSON 两种模式); - commit:覆盖
-m提交、--stdin提交、--json负载结构、"干净工作集必须报 nothing to commit"(而不是伪造提交)、缺失消息必须报错; - merge:覆盖无冲突合并成功、
--json的merged字段; - 并发:10 个 worker 并发创建 + 提交,验证无 panic、无意外错误,验证
CommitAll的原子信号设计。
另有 cmd/bd/vc_test.go 覆盖非嵌入式路径的 CLI 行为。这些测试共同构成了bd vc的契约:提交必须诚实(不伪造空提交)、合并必须报告冲突(不静默吞掉)、并发必须安全(不误归属提交)。
小结:什么时候用什么
- 快速查看:
bd history/bd diff/bd branch; - 固化变更:
bd vc commit -m "..."(工作集全量提交,空集时诚实报告); - 合入分支:
bd vc merge <branch>(无冲突直接合并;有冲突给字段列表和--strategy提示); - 处理停滞的合并:
bd vc merge <branch> --strategy ours|theirs或bd conflicts list/show/resolve命令族; - 脚本接入:所有子命令加
--json,消费稳定键位。
bd vc的价值在于把数据库级别的版本控制能力以 Git 的心智模型暴露给 Agent 与开发者:分支隔离实验、合并汇聚成果、提交保留可回溯的检查点。其底层以 Dolt 为存储引擎,上层封装了is_blocked重算、冲突策略合并、诚实空提交等大量细节,让"问题数据版本控制"这件事在命令行上保持简洁可信。
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考