关于 netbox-branching
这是一份 NetBox Branching 操作指南,介绍如何在隔离的分支模式中修改、审查并同步 NetBox 数据,适合维护 NetBox 集成与变更流程的人员。内容涵盖版本差异、冲突处理和异步任务。
主要功能
- 01创建分支并检查就绪状态
- 02使用分支上下文调用 API
- 03审查变更差异与冲突
- 04执行同步、合并和回退
- 05异步任务轮询指南
适用场景
- 01隔离计划中的 NetBox 数据变更
- 02合并前检查冲突
- 03处理异步分支操作
MCP 相关
指南提及可通过已配置的 NetBox MCP 服务检查实时分支状态,并执行分支生命周期操作。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ netboxlabs/ skills --skill netbox-branching安装后在 Claude Code 中输入/netbox-branching确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api-patterns.mdbranch-aware-models.mdbranch-lifecycle.mdconflict-resolution.md详细介绍
NetBox Branching
Branching 为 NetBox 提供类似 Git 的变更隔离。每个分支使用独立的 PostgreSQL 架构——你通过一个特殊标头对其进行读写,然后将变更合并回主分支。
你对 NetBox Branching 的了解可能已经过时。 分支状态、合并策略和 API 行为会随插件版本更新而变化。请优先检索,而不要依赖预训练知识。
检索来源
| 来源 | URL / 方法 | 用途 |
|---|---|---|
| Branching 文档 | https://netboxlabs.com/docs/extensions/branching/ | 完整参考、生命周期、配置 |
| Branching REST API | https://netboxlabs.com/docs/extensions/branching/rest-api/ | 端点详情 |
| Branching 仓库 | https://github.com/netboxlabs/netbox-branching | 源码、更新日志、问题 |
| NetBox MCP server | 如果已配置——验证分支状态、列出分支 | 实时分支状态 |
| NetBox Platform MCP | 如果已配置——完整的分支生命周期操作 | 创建、同步、合并验证 |
首先:验证连接
确认已安装 Branching 插件,且你的令牌有权访问:
curl -s -H "Authorization: Bearer $NETBOX_TOKEN" "$NETBOX_URL/api/plugins/branching/branches/" | python -m json.tool
你应该会看到分页的分支列表(或空结果)。如果收到 404,说明未安装 Branching 插件。如果收到 403,说明你的令牌缺少 netbox_branching 权限。
插件: netbox_branching——有两个受支持的版本线,需根据 NetBox 版本选择:
| NetBox | 插件版本线 | 最新版本 |
|---|---|---|
| 4.7.x | 1.2.x(min_version 4.7.0;无法在 ≤4.6 上加载) | 1.2.2(2026-10-08) |
| 4.4.1–4.6.x | 1.1.x(无法在 4.7 上加载) | 1.1.3(2026-08-26) |
1.0.x/0.9.x 已被取代——升级到 NetBox 4.7 前,请先升级到 1.1.x;升级 NetBox 时再升级到 1.2.x。本技能覆盖的版本范围:NetBox 4.5–4.7。
1.2.0 是适配 NetBox 4.7 的版本。 NetBox 4.7 用 PostgreSQL
ltree替代了 django-mptt,并将路径及反规范化字段的维护移入数据库触发器;1.2.0 会将这些触发器复制到每个分支架构中,因此嵌套层级结构(区域、位置、租户组、模块托架……)在分支内的行为保持一致。两个版本线的端点、权限代号、squash策略和 11 状态生命周期均相同;1.2 专属的 API 仅有recover/(1.2.1)。请参阅版本说明。
核心概念
- 分支 = 独立架构。 创建时进行配置,归档/删除时移除。每个分支都有自己的数据库表。
schema_id(8 位字母数字)是用于 API 访问的分支标识符——不是名称,也不是数字 ID。- 所有耗时操作均为异步——配置、同步、合并、还原都会返回一个 Job。请轮询直到操作完成。
- 当主分支和分支修改了同一对象的字段时,会产生冲突。继续合并/同步前必须确认冲突。
分支生命周期
共 11 种状态。完整状态机请参阅 references/branch-lifecycle.md。
| 状态 | 含义 |
|---|---|
new | 已创建,尚未预配 |
provisioning | 正在复制架构(异步) |
ready | 可用 — 允许读写 |
syncing | 正在将 main 拉取到分支(异步) |
migrating | 正在应用数据库迁移(异步) |
merging | 正在将分支推送到 main(异步) |
reverting | 正在撤销合并(异步) |
merged | 已成功合并;只读 |
archived | 架构已删除,元数据保留 |
pending-migrations | NetBox 升级后需要迁移 |
failed | 预配或迁移失败;终止状态 — 删除并重新创建 |
过渡状态(provisioning、syncing、migrating、merging、reverting)无法中断。发生已捕获的故障时,它们会恢复到之前的稳定状态(syncing/merging → ready,reverting → merged),但 provisioning 和 migrating 会变为 failed。
**工作进程被终止(OOM、
kill -9、Pod 被驱逐):**不会执行故障处理流程,因此分支会停留在过渡状态,相关操作也会被禁用。(1.2.1+ / NetBox 4.7) 每小时运行的任务会重置该状态(auto_recover_stuck_branches,默认值为True),也可以按需执行:POST /api/plugins/branching/branches/<id>/recover/(需要change_branch;如果任务看起来仍在运行,则使用{"force": true};使用{"retry": true}可重新运行被中断的同步/迁移)。重置目标:provisioning→failed,syncing/merging→ready,migrating→pending-migrations,reverting→merged。1.1.x 没有恢复端点。
快速参考 — 常见工作流
创建并等待就绪
POST /api/plugins/branching/branches/
Content-Type: application/json
Authorization: Bearer <token>
{"name": "add-new-site", "description": "Adding London site"}
响应中包含 schema_id。系统会自动预配。轮询直到就绪:
GET /api/plugins/branching/branches/<id>/
检查 status 字段 — 等待其变为 ready。根据数据库大小,通常需要几秒到几分钟。
激活分支上下文
在分支上下文中发起所有 API/GraphQL 请求时,添加以下标头:
X-NetBox-Branch: <schema_id>
其值为 schema_id(例如 a1b2c3d4),而不是分支名称或 ID。
其他方法(仅限 UI,不适用于 API 自动化):
- Cookie:
active_branch=<schema_id> - 查询参数:
?_branch=<schema_id>
分支必须处于 ready 状态,否则请求会被拒绝 — (1.2.2+) 返回 400 Selected branch is not ready.(1.2.2 之前返回 500)。响应中会有意不包含分支名称或其状态(此响应会在 REST 身份验证之前返回),因此请轮询分支的 status 并等待其变为 ready。
在分支中进行更改
使用常规 NetBox API 端点并附上分支标头:
POST /api/dcim/sites/
X-NetBox-Branch: a1b2c3d4
Content-Type: application/json
{"name": "London", "slug": "london", "status": "planned"}
更改仅影响分支架构,不会影响 main。
查看更改(ChangeDiffs)
GET /api/plugins/branching/changes/?branch_id=<id>
返回 ChangeDiff 记录,展示更改内容 — 对象类型、操作(创建/更新/删除)、原始数据与修改后数据。
从 main 同步
将 main 的最新更改拉取到分支:
POST /api/plugins/branching/branches/<id>/sync/
Content-Type: application/json
{"commit": true}
返回一个 Job 对象。轮询 Job URL 以确认完成。如果 main 中删除了父对象,同步可能会级联删除分支中仅有的子对象。
试运行:{"commit": false} — 验证但不应用更改。
合并到主分支
POST /api/plugins/branching/branches/<id>/merge/
Content-Type: application/json
{"commit": true}
返回一个 Job。成功后,分支状态变为 merged(只读)。
合并策略:
- 迭代式(默认)——按时间顺序将分支上的每个
ObjectChange重放到主分支,同时保留每次更改的用户和时间归属。除非此策略失败,否则请使用此策略。 - 压缩式——按外键依赖顺序,将每个对象的更改合并为一个净操作(从 1.1.1 起支持任意长度的外键循环)。CREATE+DELETE = 跳过。主分支的变更日志中,操作归属用户为执行合并的用户。可用于从重复对象或中间状态错误中恢复。
REST 不支持策略参数。
merge/仅接受commit和acknowledge_conflicts;API 合并采用迭代式策略。压缩式策略只能在 UI 合并表单中选择(REST 序列化器中不包含merge_strategy)。合并验证器(例如 Changes 插件的已批准 CR 门禁)由 job 检查,而非由端点检查:请求会返回 200 + Job,随后 job 会报错Merging this branch is not permitted.。试运行(commit: false)会跳过验证器。
处理冲突
如果 ChangeDiff 存在字段冲突,同步/合并会返回 409 和冲突详情:
{
"detail": "All conflicts must be acknowledged before this action can proceed.",
"conflicts": [{"id": 6, "object_type": "dcim.device", "object_id": 42, "object_repr": "switch-01",
"action": {"value": "update", "label": "Updated"},
"conflicts": ["name", "status"],
"conflicting_data": {
"original": {"name": "old"}, "branch": {"name": "branch-val"}, "main": {"name": "main-val"}
}}]
}
如需继续,请重新提交并设置 "acknowledge_conflicts": true。确认冲突后,以分支上的值为准。
详情请参阅 references/conflict-resolution.md。
还原已合并的分支
POST /api/plugins/branching/branches/<id>/revert/
Content-Type: application/json
{"commit": true}
仅适用于状态为 merged 的分支。将分支恢复为 ready 状态。异步 job。
归档
POST /api/plugins/branching/branches/<id>/archive/
仅适用于状态为 merged 的分支(否则返回 400)。同步执行——返回更新后的分支,不返回 job。删除架构,保留元数据和事件历史;归档后的分支无法再还原。终止状态。(1.1.2+) 设置 auto_archive_days,可在已合并分支达到 n 天后自动归档。
异步 Job 轮询模式
所有耗时操作都会返回一个带有 url 字段的 Job 对象。轮询该对象:
GET <job_url>
Job 的 status 值:pending、running、completed、errored、failed。等待其进入终止状态。使用指数退避(从 1s 开始,最长 30s)。
所需权限: netbox_branching.sync_branch、netbox_branching.merge_branch、netbox_branching.revert_branch、netbox_branching.archive_branch、netbox_branching.migrate_branch(应用待处理的迁移),以及 recover/ 所需的 netbox_branching.change_branch(1.2.1+)。
支持分支的模型
大多数 DCIM、IPAM、Circuits、Tenancy、Virtualization、VPN 和 Wireless 模型都支持分支。不支持分支的模型(全局/立即生效):自定义字段、webhook、事件规则、导出模板、已保存筛选器,以及所有 core.* 模型。
发现端点:
GET /api/plugins/branching/branchable-models/会准确列出当前安装中支持分支的模型——请使用此端点,不要猜测。(受支持的两个版本线 1.1.x 和 1.2.x 均提供此端点。)实际上,大多数核心运营模型(DCIM、IPAM、Circuits 等)都支持分支;基础设施模型(自定义字段、webhook、core.*)、branching 和 Changes 插件自身的模型,以及exempt_models中的所有模型均不支持分支。其他插件中记录更改的模型默认支持分支。
参阅 references/branch-aware-models.md。
与变更请求集成
NetBox Branching 可与 netbox-changes 插件配合,用于受管控的变更工作流:
- 在 netbox-changes 中创建变更请求(CR)
- 为该 CR 创建分支
- 在分支上下文中进行更改
- 提交 CR 以供审核/批准
- CR 获批后合并分支
集成后,如果关联的 CR 尚未获批,合并操作会被阻止。通过 REST 执行时,阻止响应不是 4xx:merge/ 返回 200 + Job,且作业报错 Merging this branch is not permitted.(界面会显示原因:No change request has been approved for this branch.)。试运行合并不受此限制。
版本配对: Changes 1.1.3 可与 NetBox ≤4.6 上的 branching 1.1.x 配合使用,也可与 NetBox 4.7 上的 branching 1.2.x 配合使用——两个插件必须与运行中的 NetBox 版本匹配,否则 NetBox 将无法启动。有关 CR 生命周期的详情,请参阅 netbox-changes skill。
反模式
- 创建后务必轮询 — 分支只有在状态为
ready时才能使用。在provisioning状态下使用会返回 400Selected branch is not ready.(1.2.2+;此前为 500)——响应不会指出具体是哪个分支,因此请检查status。 - 过期分支 — 如果分支的
last_sync(或从未同步时的created)早于 NetBox 的CHANGELOG_RETENTION(默认 90 天),该分支就会过期,无法再同步:同步作业会报错Syncing this branch is not permitted.。REST 表示中没有is_stale/stale_warning字段——请自行计算now − (last_sync or created);界面会提前stale_warning_threshold天发出警告(默认 7 天)。请在保留期结束前同步,或归档/删除分支。 - 分支数量上限 — 插件配置中的
max_branches(非归档分支总数)和max_working_branches设定了数量上限。超出上限时,创建操作会因 ValidationError 而失败。 - 无法删除当前活动分支 — 请先停用它。
- 合并要么全部成功,要么全部回滚 — 任何验证失败都会回滚整个事务。
- 冲突需要确认 — 在传入
acknowledge_conflicts: true前,操作会返回 409。分支中的值优先。 - 同步会级联删除 — 如果主分支中的父对象已删除,同步时会为仅存在于分支中的子对象创建合成 DELETE 记录。
- 架构 = 磁盘空间 — 每个分支都会复制所有可分支表。请为大型数据库规划容量。
pending-migrations— NetBox 升级后,现有分支需先迁移才能使用。- 数据库权限 — PostgreSQL 用户需要
CREATE ON DATABASE权限才能创建架构(NetBox 4.7 自动安装ltree扩展也需要相同权限)。 ?background=true+X-NetBox-Branch会将写入操作应用到主分支(NetBox 4.7.0–4.7.2;已在 4.7.3 修复)——请参阅 NetBox 4.7 交互。- 编程式写入需要
obj.snapshot()— 脚本、nbshell和插件作业如果在分支中修改对象前未创建快照,便会得到空的prechange_data:差异无法显示更改前后的状态,且该对象的冲突检测会静默失效。请在修改前调用snapshot()。
API 端点摘要
| 端点 | 用途 |
|---|---|
POST /api/plugins/branching/branches/ | 创建分支 |
GET /api/plugins/branching/branches/<id>/ | 分支详情/状态 |
POST .../branches/<id>/sync/ | 从主分支同步 |
POST .../branches/<id>/merge/ | 合并到主分支 |
POST .../branches/<id>/revert/ | 撤销已合并的分支 |
POST .../branches/<id>/archive/ | 归档已合并的分支(同步并返回分支) |
POST .../branches/<id>/recover/ | 重置卡在过渡状态的分支(1.2.1+) |
GET /api/plugins/branching/changes/ | ChangeDiff 记录 |
GET /api/plugins/branching/branch-events/ | 分支事件日志 |
GET /api/plugins/branching/branchable-models/ | 查找可分支模型 |
NetBox 4.7 交互
需要分支 1.2.x。已使用 NetBox 4.7.2 + 插件 1.2.1 验证。
- 在 NetBox 4.7.0–4.7.2 上,
?background=true批量写入会忽略分支标头。 这些版本会在工作进程中根据快照重建请求,而快照只包含主机/转发标头——X-NetBox-Branch、Cookie 和?_branch=都会被丢弃——因此,延迟执行的批量写入不会激活任何分支,并会写入 main(或者在启用 Changesprotect_main时遭到拒绝)。NetBox 4.7.3+ 会将请求标头和查询字符串(不含background;Authorization会被剥离,因为认证已完成)传递给工作进程,因此写入会落在分支中(netbox-community/netbox#23247)。在 ≤ 4.7.2 上,切勿将?background=true与X-NetBox-Branch一起使用——应改为在分支上下文中发送同步批量请求(每次调用 ≤ 几百个对象);在 4.7.3+ 上,像处理其他后台写入一样,轮询作业直到状态终结。 - 分支中的层级结构: NetBox 4.7 将区域/站点组/位置/租户组/模块机箱路径保存在由数据库触发器维护的
ltree列中。1.2.0 会在每个分支架构中安装这些触发器,因此,在分支中移动或重命名父级只会级联影响该分支中的后代,合并时会重放父级变更(main 上的路径由 main 的触发器重新计算)。如果你是从pg_dump恢复的 NetBox 4.7.0,请先在 main 上运行rebuild_ltree_paths --check,再创建新分支——分支会原样复制 main 的表和触发器。 - Custom Objects 插件 ≥ 0.6 支持分支中的自定义对象实例(版本要求取决于插件,而非 NetBox);0.5.x 会拒绝在分支中写入实例。参见 netbox-custom-objects。
- 批量错误格式: 在分支上下文中,同步批量写入失败时会返回 4.7 的逐对象
{"detail", "errors": [{"index": N, ...}]}格式——与 main 相同。参见 netbox-api-integration。 - NetBox Designs 会将方案部署到分支。 目标为分支的设计部署只会写入该分支;像往常一样在 NetBox 中合并或删除分支,部署也会随之变化(移至 main,或显示 Branch gone)。参见 netbox-designs。
- pynetbox ≥ 7.8.0 除了旧版
nb.activate_branch()上下文管理器,还提供了BranchingExtension(branch.sync()/merge()/revert()/archive())。在 NetBox 4.7 上请使用 ≥ 7.9.0(2026-10-08;Python 3.12+)——这是首个声明支持 4.7 的 pynetbox 版本,并修复了保存带有多选自定义字段的对象时的问题——参见 references/api-patterns.md。
配置快速参考
PLUGINS_CONFIG['netbox_branching']。完整列表:插件仓库中的 docs/configuration.md。
| 参数 | 默认值 | 起始版本 | 说明 |
|---|---|---|---|
max_branches / max_working_branches | None | 0.4 / 0.5 | 非归档分支总数 / 非合并且非归档分支数上限 |
exempt_models | [] | 0.5 | 'plugin.model' 或 'plugin.*';绝不豁免与某个分支模型相关的模型 |
job_timeout | 3600 | 0.8.2 | 同步/合并/还原任务超时时间(秒) |
stale_warning_threshold | 7 | 0.9 | 在 UI 中于过期前多少天发出警告;0 表示禁用 |
provision_workers | 4 | 1.1.0 | 并行复制/索引工作进程数;使用共享数据库时建议调低至 1–2 |
auto_archive_days | None | 1.1.2 | 合并后经过 n 天自动归档分支(会删除架构 → 无法还原) |
auto_recover_stuck_branches | True | 1.2.1 | 每小时重置因工作进程崩溃而孤立的分支 |
stuck_job_grace_period | 300 | 1.2.1 | 超过 job_timeout 后,经过多少秒才将“运行中”任务视为已死亡 |
*_validators(sync/merge/migrate/revert/archive) | [] | 0.6 | 操作前验证器的导入路径 |
还需在 NetBox 的 EVENTS_PIPELINE 中,将 'netbox_branching.events.add_branch_context' 放在 extras.events.process_event_queue 之前,以便在事件规则条件、Webhook 负载和脚本 data 中获取 active_branch(id、name、schema_id 或 null)。
版本说明
NetBox 4.7.3(2026-10-13)
?background=true批量写入现在会将X-NetBox-Branch/?_branch=传递给工作进程,因此后台批量写入会落在分支中(#23247;在 4.7.0–4.7.2 中则会落在主库)。请运行 ≥ 4.7.3。
插件 1.2.x — 仅支持 NetBox 4.7(2026-09-02)
- **1.2.0:**在分支架构中复制 ltree 和反规范化触发器。需要 NetBox ≥ 4.7.0;请运行 ≥ 4.7.3(4.7.0/4.7.1 会将通过后台批量请求创建的明文令牌泄露到任务结果中;4.7.3 会将分支标头传递给后台批量任务,并恢复配置上下文省略优化)。
- **1.2.1:**卡住分支恢复功能——
recover/端点、auto_recover_stuck_branches、stuck_job_grace_period;修复ObjectChange.undo(),使其能在还原时恢复已删除的对象。 - 1.2.2(2026-10-08):在压缩合并或还原后重新计算线缆路径(#469);合并失败报告包含底层验证错误(#632);同步分支时冲突基线会前移(#640);压缩合并时解决循环 DELETE 依赖(#668);删除记录前先取消分支预配(#641);未安装插件时脚本会跳过分支激活(#649)。
插件 1.1.x — NetBox 4.4.1–4.6.x(2026-06 → 2026-08)
- **1.1.0:**并行预配(
provision_workers),大型数据库上的速度最高提升约 4 倍。 - **1.1.1:**压缩合并可解决任意长度的外键循环;修复了 MPTT 组件模型(模块托架、库存项)的迭代式合并。
- 1.1.2:
auto_archive_days。 - **1.1.3:**对象更新期间的冲突现在会记录到
ChangeDiff中(此前会漏掉部分更新冲突)。
插件 1.0.x(已被取代)
- 1.0.4:同步时的冲突解决结果在合并时得以保留;为不记录变更的模型提供插件解析器钩子。1.0.5:合并时保留未修改的 JSON 字典键。所有 1.0.x 版本 → 升级到 1.1.3(≤4.6)或 1.2.2(4.7)。
参考资料
- references/branch-lifecycle.md — 包含全部 11 种状态和转换的完整状态机
- references/api-patterns.md — 每种操作的完整 API 示例
- references/conflict-resolution.md — 冲突检测、三方差异比较、确认
- references/branch-aware-models.md — 哪些模型会分支、哪些会被豁免,以及如何发现