Beads 与 GitLab 双向同步实战:bd gitlab命令全解
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
Beads 是一个为 Coding Agent 提供记忆升级的 issue 追踪与管理工具,而bd gitlab是其中将 Beads 本地 issue 数据库与 GitLab 项目/群组双向同步的官方集成入口。本篇技术指南基于 docs/cli-reference/gitlab.md 展开,结合 cmd/bd/gitlab.go 与 internal/gitlab 包源码,完整讲解配置方式、五个子命令(projects、pull、push、status、sync)的用法、字段映射规则、冲突解决策略与底层同步引擎原理,帮助你把 GitLab 变成 Beads 的可视化协作前台。
概览:bd gitlab是什么
bd gitlab是 Beads CLI 中负责 GitLab 集成的一级命令,其官方定位是 “Commands for syncing issues between beads and GitLab”。它通过 GitLab REST API v4(以及用于 work item 层级的 GraphQL API)完成:
- Pull:把 GitLab 上新创建/更新的 issue 导入 Beads 本地数据库;
- Push:把 Beads 本地 issue 推送到 GitLab;
- 双向同步:默认同时执行 Pull 与 Push,保证两端内容收敛。
命令根节点定义在 cmd/bd/gitlab.go,其 Long 描述同时给出了全部配置项。在仓库的 docs/cli-reference 目录下,你可以找到与之平行的 GitHub、GitLab、Jira、Linear、Notion、ADO 等各外部追踪器的同步命令参考,bd gitlab是其中面向 GitLab 实例的完整实现。
一、配置 GitLab 连接
同步前必须先配置连接信息。bd gitlab支持两种配置来源:bd config与同名环境变量,二者等价。
配置键(bd config set使用) | 环境变量 | 含义 |
|---|---|---|
gitlab.url | GITLAB_URL | GitLab 实例地址(如https://gitlab.com或自建实例地址) |
gitlab.token | GITLAB_TOKEN | Personal access token(个人访问令牌) |
gitlab.project_id | GITLAB_PROJECT_ID | 项目 ID 或 URL 编码后的项目路径(如group/project) |
gitlab.group_id | GITLAB_GROUP_ID | 群组 ID(用于群组级同步,可选) |
gitlab.default_project_id | GITLAB_DEFAULT_PROJECT_ID | 群组模式下创建 issue 时使用的默认项目 |
示例:
bd config set gitlab.url https://gitlab.example.com bd config set gitlab.token glpat-xxxxxxxxxxxx bd config set gitlab.project_id 42或使用环境变量:
export GITLAB_URL=https://gitlab.example.com export GITLAB_TOKEN=glpat-xxxxxxxxxxxx export GITLAB_PROJECT_ID=42 bd gitlab status项目模式与群组模式
从源码看,配置校验逻辑(validateGitLabConfig,见 cmd/bd/gitlab.go)要求gitlab.url与gitlab.token必填,gitlab.project_id与gitlab.group_id至少配置其一:
- 项目模式:仅设置
gitlab.project_id,同步范围为单个项目; - 群组模式:设置
gitlab.group_id,通过/groups/:id/issues端点拉取群组内所有项目的 issue;此时gitlab.default_project_id用于指定新 issue 的创建归属项目。若未显式设置,代码会在Init阶段回退使用project_id(见 internal/gitlab/tracker.go)。
安全约束与密钥存储
两个值得注意的安全设计:
- 强制 HTTPS:
validateGitLabConfig会拒绝非 HTTPS 的gitlab.url(仅放行http://localhost与http://127.0.0.1用于本地开发测试),防止 token 明文传输; - 密钥不落库:
gitlab.token属于 yaml-only 键,只从config.yaml或环境变量读取,绝不写入 Dolt 数据库,避免数据库被推送到远端时泄露密钥。这一逻辑在 cmd/bd/gitlab.go 与 internal/gitlab/tracker.go 中均有体现。
二、检查连接:bd gitlab status
bd gitlab status [flags]该命令展示当前 GitLab 配置与同步状态,输出类似:
GitLab Configuration ==================== URL: https://gitlab.example.com Token: glpat**** Project ID: 42 Sync Mode: project Status: ✓ Configured关键行为(见 cmd/bd/gitlab.go):
- Token 只显示前 4 位(
maskGitLabToken),避免泄露; - 群组模式下会额外输出
Sync Mode: group与Default Project ID; - 若通过配置键
gitlab.filter_labels、gitlab.filter_project、gitlab.filter_milestone、gitlab.filter_assignee设置了过滤条件,会一并展示; - 配置缺失时输出
Status: ❌ Not configured及具体缺项提示。
三、枚举项目:bd gitlab projects
bd gitlab projects [flags]列出当前 token 有权限访问的所有 GitLab 项目,输出每个项目的ID、Name、Path(namespace 路径)与URL。底层调用Client.ListProjects,走/projects?membership=true端点(见 internal/gitlab/client.go)。该命令常用来确认project_id的正确取值,尤其在自建实例上。
四、双向同步:bd gitlab sync
bd gitlab sync [flags]sync是核心命令。默认执行双向同步:从 GitLab 拉取新建/更新的 issue 到 Beads,同时把 Beads 本地 issue 推送到 GitLab。使用--pull-only或--push-only可以限定方向(二者互斥,同时使用会报错,见 cmd/bd/gitlab.go)。
完整 Flags 说明
| Flag | 说明 |
|---|---|
--assignee string | 按指派者用户名过滤(assignee_username参数) |
--dry-run | 只展示将要同步的内容,不做任何更改 |
--exclude-type string | 排除指定类型不同步(逗号分隔) |
--issues string | 只同步指定的 Beads ID(逗号分隔,如bd-abc,bd-def),与--parent互斥 |
--label string | 按标签过滤(逗号分隔,AND 逻辑) |
--milestone string | 按里程碑标题过滤 |
--no-ephemeral | 推送时排除 ephemeral/wisp 类 issue(默认开启,--no-ephemeral=false可关闭) |
--parent string | 仅推送该 Beads issue 及其全部子孙(仅推送方向),与--issues互斥 |
--prefer-gitlab | 冲突时采用 GitLab 版本 |
--prefer-local | 冲突时保留本地 Beads 版本 |
--prefer-newer | 冲突时采用更新版本(默认策略) |
--project string | 群组模式下按项目 ID 过滤(客户端侧过滤) |
--pull-only | 仅从 GitLab 拉取 |
--push-only | 仅推送到 GitLab |
--type string | 只同步指定类型(逗号分隔,如epic,feature,task) |
冲突解决策略
三个--prefer-*flag 互斥,同时指定多个会被拒绝(getConflictStrategy,见 cmd/bd/gitlab.go):
--prefer-newer(默认):比较本地与远端updated_at,保留更新的版本,对应底层tracker.ConflictTimestamp;--prefer-local:始终保留本地 Beads 版本,对应tracker.ConflictLocal;--prefer-gitlab:始终采用 GitLab 版本,对应tracker.ConflictExternal。
三种策略在 internal/tracker/types.go 中定义,由 internal/tracker/engine.go 的同步引擎消费。
类型过滤与默认排除
--type与--exclude-type均接受逗号分隔的类型列表。值得注意的默认行为(见 cmd/bd/gitlab.go):当用户既未指定--type也未指定--exclude-type时,推送方向会默认排除三类内部协调型 issue:molecule、message、event,避免把 Beads 的内部工作产物同步到 GitLab。此外--no-ephemeral默认排除 ephemeral/wisp 类 issue。
选择性同步:--issues与--parent
--issues bd-abc,bd-def:按 Beads ID 精确圈定同步范围,Pull 方向会对每个 ID 走定向FetchIssue而非全量拉取(见 internal/tracker/types.go);--parent bd-xyz:仅推送该 issue 及其通过 parent-child 依赖连接的整棵子树(buildGitLabDescendantSet广度优先遍历,见 cmd/bd/gitlab.go)。
两 flag 互斥(applySelectiveSyncFlags,见 cmd/bd/sync_flags.go),且--parent只允许用于推送方向。
依赖链接与里程碑同步(附加推送通道)
除了 issue 本体,sync/push在推送阶段还会执行一个独立的依赖链接同步通道pushGitLabDependencyLinks(见 cmd/bd/gitlab.go):
- 把 Beads 内的
blocks/related依赖转换为 GitLab issue links(relates_to、blocks、is_blocked_by)。注意方向反转:Beads 的 A blocks B 在 GitLab API 中存为 BblocksA(见 internal/gitlab/links.go); - 为史诗(epic)下的非 epic issue 修复里程碑归属(
PushEpicMilestones),保证即便 issue 内容未变化、主推送循环被跳过时层级关系仍正确; - 链接同步是增量追加的:远端已有的陈旧链接不会被删除;
- 若 GitLab 实例许可证缺少 issue-blocking 功能(需要 Premium/Ultimate),
blocks/is_blocked_by链接会被识别并计入 LicenseSkipped,输出一句明确的降级提示,而relates_to与里程碑仍正常应用(internal/gitlab/links.go)。
输出与 JSON 模式
非 dry-run 时输出概要统计:
✓ Pulled 12 issues (10 created, 2 updated) ✓ Pushed 5 issues → Resolved 1 conflicts使用全局--json输出时,会返回结构化结果,字段包括dry_run、pulled、pushed、created、updated、skipped、conflicts、errors、links_pushed、milestones_updated、warnings等(结构体定义见 cmd/bd/gitlab.go),便于脚本与 Agent 消费。
五、单方向操作:bd gitlab pull与bd gitlab push
bd gitlab pull [refs...] [flags] # 等价于 bd gitlab sync --pull-only --issues <refs> bd gitlab push [bead-ids...] [flags] # 等价于 bd gitlab sync --push-only --issues <ids>pull接受 Beads ID 或外部引用(external reference,如 GitLab issue URL)作为位置参数,仅从 GitLab 拉取;push接受 Beads ID 作为位置参数,仅推送到 GitLab;- 两者都支持
--dry-run预演。
当不传位置参数时,pull/push等价于不带--issues的--pull-only/--push-only全量同步。
六、字段映射:Beads 与 GitLab 的语义桥梁
双向同步的核心是把两套数据模型映射起来,映射实现集中在 internal/gitlab/mapping.go 与 internal/gitlab/types.go。
标签体系(Scoped Labels)
Push 方向(Beads → GitLab)按以下规则生成标签(BeadsIssueToGitLabFields):
- 类型:
type::<type>,如type::bug、type::feature; - 优先级:
priority::<level>,映射表critical(0)/high(1)/medium(2)/low(3)/none(4),对应 Beads 的 P0–P4; - 状态:
in_progress/blocked/deferred等非 open/closed 状态会附加status::<state>标签(open/closed 由 GitLab 原生 issue state 表达); - 普通标签原样透传。
Pull 方向(GitLab → Beads)反向解析:typeFromLabels同时识别type::xxx作用域标签与裸标签(如bug),缺省视为task;priorityFromLabels缺省为medium(优先级 2);状态解析中GitLab 的 closed 状态优先级最高,其次看status::标签,最后回落到 state 映射(opened→open、closed→closed、reopened→open)。
状态与时间
state_event字段在创建/更新时写入close或reopen使两端状态一致。一个实现细节:GitLab 的POST /issues会忽略state_event,因此关闭状态的 Beads issue 创建时先生成 "opened",再用一次 follow-up 更新关闭;若关闭失败会保留 warning(internal/gitlab/tracker.go)。
估算与权重
Beads 的EstimatedMinutes与 GitLab 的weight相互换算:weight1 约等于 1 小时(Pull 方向weight * 60分钟,Push 方向minutes / 60)。注意weight是 GitLab Premium 功能。
类型映射:epic → 里程碑,task → work item
Beads 的 issue 类型与 GitLab 实体并非一一对应:
- epic:映射为 GitLab milestone(创建走
CreateMilestone,标题/描述/开闭状态均同步),因此 epic 的 URL 形如/-/milestones/<id>; - task:当配置了
gitlab.project_path(对应GITLAB_PROJECT_PATH)且 task 存在 story/feature 父级时,通过 GraphQL 以 work item 形式创建为父 issue 的子项(workItemCreatemutation),并在同一项目内共享 IID 空间;findParentEpicMilestone会向上遍历最多 5 层父子链,把 epic 对应的里程碑挂到子孙 issue 上。
外部引用(external_ref)识别同时支持完整 URL(/issues/42、/work_items/42、/-/milestones/5)与gitlab:<iid>简写(internal/gitlab/tracker.go)。
七、底层同步引擎
bd gitlab并不自己实现同步循环,而是通过gitlab.Tracker(实现tracker.IssueTracker接口,注册名"gitlab",见 internal/gitlab/tracker.go)接入统一的tracker.Engine(internal/tracker/engine.go)。CLI 侧仅负责:读取配置 → 构建客户端 → 装配 Pull/Push Hooks → 调用engine.Sync(ctx, opts)。
同步选项tracker.SyncOptions(internal/tracker/types.go)承载了Pull、Push、DryRun、TypeFilter、ExcludeTypes、ExcludeEphemeral、ParentID、IssueIDs等全部控制位,与 CLI flags 一一对应。
客户端层面(internal/gitlab/client.go)的几个健壮性设计值得了解:
- 请求超时 30 秒,限流(429)与 5xx 自动重试,最多 3 次,指数退避并叠加随机抖动,若响应带
Retry-After则优先尊重服务端指定延迟; - 分页拉取每页 100 条,最大 1000 页,依赖
X-Next-Page头,并带防死循环护栏;响应体上限 50MB 防止异常响应导致 OOM; - 支持增量拉取(
updated_after参数),Tracker.FetchIssues每次还会为每个 issue 补充拉取其 issue links 以还原依赖关系。
八、推荐工作流
首次接入先预演:
bd gitlab status # 确认配置正确 bd gitlab projects # 确认 project_id bd gitlab sync --dry-run # 预览将要同步的变更日常双向同步:
bd gitlab sync只同步部分范围:
# 只同步两个指定的 Beads issue bd gitlab sync --issues bd-abc,bd-def # 只推送某 epic 及其子树 bd gitlab sync --push-only --parent bd-epic-001 # 群组模式下只看某项目 bd gitlab sync --project 42处理冲突:默认--prefer-newer通常足够;若想人工仲裁,先用--dry-run查看冲突数量,再按需选择--prefer-local或--prefer-gitlab。
九、适用范围与限制
- 所有
bd gitlab子命令在 proxied-server 模式下均不支持(返回明确错误,见 cmd/bd/gitlab.go 等),需在直接模式(embedded/direct)下使用; - 依赖链接中的
blocks/is_blocked_by需要 GitLab Premium/Ultimate 许可证,Free 版实例会自动降级为仅同步relates_to与里程碑并给出提示; weight为 GitLab Premium 功能,Free 版拉取/推送时该字段可能不可用;- 跨项目 issue 链接不受支持,
CreateIssueLink仅限同一项目内。
以上全部行为均可在 docs/cli-reference/gitlab.md 的 CLI 参考、cmd/bd/gitlab.go 的命令实现与 internal/gitlab 包的源码与测试(如 internal/gitlab/tracker_test.go、internal/gitlab/links_test.go)中找到对应依据,可作为深入阅读与二次开发的起点。
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考