版本管理
大约 4 分钟
版本管理
分支管理、版本保存、分支合并、冲突解决的完整指南。
概念
版本结构
图纸 (mapid/version)
├── main 分支
│ ├── base (初始版本)
│ ├── patch-001
│ ├── patch-002
│ └── patch-003 (当前)
└── feature-xxx 分支
├── base (从 main 分叉)
└── patch-001Patch 版本链
base → patch-001 → patch-002 → patch-003每个 Patch 记录相对于父版本的增量变更:
- 新增的实体
- 修改的实体
- 删除的实体 ID
- 图层变更
- 元数据(作者、时间、备注等)
创建分支
命令方式
// 打开图纸浏览器
await Engine.editor.executerWithOp('OPENFROMSERVER');
// 在版本上右键选择「创建分支」API 方式
const { DrawingManagerService, BranchCreateDialog, message } = vjcad;
const drawingManager = new DrawingManagerService();
// 方式1:通过对话框创建
const dialog = new BranchCreateDialog();
const result = await dialog.showDialog({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
fromBranchName: 'main',
fromPatchId: 'base'
});
if (result && result.action === 'create') {
const createResult = await drawingManager.createBranch({
type: result.type,
mapid: result.mapid,
version: result.version,
sourceBranch: result.fromBranchName,
sourcePatchId: result.fromPatchId,
branchName: result.newBranchName
});
if (createResult.status) {
message.info(`分支 "${result.newBranchName}" 创建成功!`);
}
}
// 方式2:直接调用 API
const createResult = await drawingManager.createBranch({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
sourceBranch: 'main',
sourcePatchId: 'base',
branchName: 'feature-new-layer'
});保存版本(Patch)
命令方式
await Engine.editor.executerWithOp('SAVESERVER');API 方式
const { DrawingManagerService, Engine } = vjcad;
const drawingManager = new DrawingManagerService();
// 1. 从服务器打开图纸(获取原始数据)
const openResult = await drawingManager.openDrawing({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
branch: 'main',
patchId: 'base'
});
// 2. 加载到编辑器
const virtualFile = new File([openResult.webcadJson], 'doc', { type: 'application/json' });
await Engine.view.openDbDoc(virtualFile, openResult.webcadData);
// 保存原始数据(用于 diff 计算)
await Engine.currentDoc.setOriginalJson(openResult.webcadJson);
// 3. 编辑图纸...
// (添加、修改、删除实体)
// 4. 保存(计算 diff 生成 patch)
const currentDoc = Engine.currentDoc;
const currentJson = JSON.stringify(currentDoc.toDb());
const originalJson = await currentDoc.getOriginalJson();
const saveResult = await drawingManager.saveDrawing({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
branchName: 'main',
originalJson: originalJson,
currentJson: currentJson,
parentId: openResult.latestPatchId || 'base',
drawingName: '我的修改',
author: '用户名',
remark: '添加了新图层'
});
if (saveResult.status) {
if (saveResult.patchId === 'no_change') {
console.log('没有需要保存的修改');
} else {
console.log(`保存成功! Patch ID: ${saveResult.patchId}`);
// 更新本地原始数据
await currentDoc.setOriginalJson(currentJson);
}
} else if (saveResult.conflict && saveResult.conflict.hasConflict) {
console.warn('检测到与其他用户的修改冲突');
} else {
console.error(`保存失败: ${saveResult.error}`);
}合并分支
API 方式
const { DrawingManagerService, message } = vjcad;
const drawingManager = new DrawingManagerService();
// 将 feature 分支合并到 main
const mergeResult = await drawingManager.mergeBranch({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
sourceBranch: 'feature-new-layer',
targetBranch: 'main',
remark: '合并新图层功能'
});
if (mergeResult.status) {
message.info(`合并成功!Patch ID: ${mergeResult.patchId}`);
} else if (mergeResult.conflict && mergeResult.conflict.hasConflict) {
message.warn('检测到冲突,需要手动解决');
// 处理冲突...
} else {
message.error(`合并失败: ${mergeResult.error}`);
}查看版本历史
API 方式
const { DrawingManagerService } = vjcad;
const drawingManager = new DrawingManagerService();
// 获取分支列表(包含各分支的 patch 信息)
const branches = await drawingManager.listBranches({
type: 'imports',
mapid: 'drawing-123',
version: 'v1'
});
console.log('分支列表:', branches.map(b => b.name));
// 获取 main 分支的 patch 列表
const mainBranch = branches.find(b => b.name === 'main');
const patches = mainBranch ? mainBranch.patches : [];
console.log(`共 ${patches.length} 个版本`);
// 显示版本详情
for (const patch of patches) {
console.log(`- ${patch.id}: ${patch.remark || '(无备注)'} by ${patch.author}`);
}打开特定版本
// 打开指定 Patch 版本
const result = await drawingManager.openDrawing({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
branch: 'main',
patchId: 'patch-001' // 指定版本
});删除版本/分支
删除 Patch
const deleteResult = await drawingManager.deletePatch({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
branch: 'main',
patchId: 'patch-003'
});
if (deleteResult.status) {
console.log('Patch 已删除');
}删除分支
const deleteResult = await drawingManager.deleteBranch({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
branchName: 'feature-old'
});
if (deleteResult.status) {
console.log('分支已删除');
}冲突处理
当两个分支修改了同一个实体时,合并会产生冲突。
检测冲突
const mergeResult = await drawingManager.mergeBranch({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
sourceBranch: 'feature-a',
targetBranch: 'main'
});
if (mergeResult.conflict && mergeResult.conflict.hasConflict) {
// 存在冲突
const conflicts = mergeResult.conflict.entities;
console.log(`冲突实体数: ${conflicts.length}`);
for (const conflict of conflicts) {
console.log(`实体 ${conflict.id}:`);
console.log(` - 源分支版本: ${JSON.stringify(conflict.source)}`);
console.log(` - 目标分支版本: ${JSON.stringify(conflict.target)}`);
}
}解决冲突
冲突解决策略:
- 选择源分支版本 - 使用功能分支的修改
- 选择目标分支版本 - 保留主分支的修改
- 手动合并 - 人工决定最终结果
// 使用源分支版本解决冲突
const resolveResult = await drawingManager.resolveConflict({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
sourceBranch: 'feature-a',
targetBranch: 'main',
resolution: 'source' // 'source' | 'target' | 'manual'
});完整工作流示例
const { DrawingManagerService, Engine, LineEnt, CircleEnt, message } = vjcad;
const drawingManager = new DrawingManagerService();
// === 1. 创建功能分支 ===
const createResult = await drawingManager.createBranch({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
sourceBranch: 'main',
sourcePatchId: 'base',
branchName: 'feature-new-layer'
});
if (!createResult.status) {
throw new Error(`创建分支失败: ${createResult.error}`);
}
message.info('功能分支创建成功');
// === 2. 在功能分支上编辑 ===
const openResult = await drawingManager.openDrawing({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
branch: 'feature-new-layer',
patchId: 'base'
});
const virtualFile = new File([openResult.webcadJson], 'doc', { type: 'application/json' });
await Engine.view.openDbDoc(virtualFile, openResult.webcadData);
await Engine.currentDoc.setOriginalJson(openResult.webcadJson);
// 添加新图形
const circle = new CircleEnt([100, 100], 50);
circle.setDefaults();
circle.color = 1;
Engine.addEntities(circle);
// === 3. 保存修改 ===
const currentJson = JSON.stringify(Engine.currentDoc.toDb());
const saveResult = await drawingManager.saveDrawing({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
branchName: 'feature-new-layer',
originalJson: openResult.webcadJson,
currentJson: currentJson,
parentId: openResult.latestPatchId || 'base',
drawingName: '新功能',
author: '开发者',
remark: '添加红色圆形'
});
message.info(`保存成功: ${saveResult.patchId}`);
// === 4. 合并到主分支 ===
const mergeResult = await drawingManager.mergeBranch({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
sourceBranch: 'feature-new-layer',
targetBranch: 'main',
remark: '合并新功能'
});
if (mergeResult.status) {
message.info('合并成功!');
// === 5. 清理功能分支(可选)===
await drawingManager.deleteBranch({
type: 'imports',
mapid: 'drawing-123',
version: 'v1',
branchName: 'feature-new-layer'
});
message.info('功能分支已删除');
} else if (mergeResult.conflict?.hasConflict) {
message.warn('存在冲突,需要手动解决');
}API 参考
DrawingManagerService
| 方法 | 说明 |
|---|---|
createBranch(params) | 创建分支 |
deleteBranch(params) | 删除分支 |
listBranches(params) | 获取分支列表 |
mergeBranch(params) | 合并分支 |
saveDrawing(params) | 保存版本(Patch) |
deletePatch(params) | 删除版本 |
openDrawing(params) | 打开图纸 |
分支操作参数
| 参数 | 说明 |
|---|---|
type | 图纸类型:'imports' | 'designs' |
mapid | 图纸 ID |
version | 版本号(如 'v1') |
branchName | 分支名称 |
sourceBranch | 源分支 |
targetBranch | 目标分支 |
sourcePatchId | 源 Patch ID |