PlantUML 图随 git 演化:重命名、迁移、archive 策略

puml.online

写完 .puml 不是结束。3 个月后 service 重命名、架构拆分、组件废弃——图跟代码同源演化才能避免「文档说 A,代码里早就叫 B」的尴尬。这篇是 rename migration 工具、archive 策略、git log 跟图同步。

重命名的两个层级

层级 1:文件名重命名——user-service.pumlidentity-service.puml(service 改叫 identity)

层级 2:图内引用重命名——component "user-service"component "identity-service",且所有 --> us 改成 --> identity

两个都要同步——只改文件名不改图内引用,git diff 看不出来;只改图内引用不改文件名,git history 断了。

工具 1:git mv 跟 sed 组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 文件重命名
git mv docs/diagrams/user-service.puml docs/diagrams/identity-service.puml

# 2. 全文 grep 引用
grep -rl "user-service\|user_service\|us-" docs/diagrams/*.puml

# 3. 替换
find docs/diagrams -name "*.puml" -exec sed -i 's/user-service/identity-service/g; s/user_service/identity_service/g; s/us-/identity-/g' {} +

# 4. 提交
git add -A
git commit -m "refactor(diagrams): rename user-service to identity-service

- git mv user-service.puml -> identity-service.puml
- sed replace all 'user-service' / 'us-' across diagrams
- verified with hexo generate"

git mv 比手动 mv 跟 add 强在 git 会检测到这是 rename(就算你重命名后改了内容,git rename detection 仍然能识别)。

工具 2:用 mvdan/sh 重命名脚本

更稳的写法——加 dry-run、错误处理、grep 验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
# rename-component.sh
set -euo pipefail

OLD="$1"
NEW="$2"

# 1. 文件名重命名(假设文件名包含组件名)
if ls docs/diagrams/*"${OLD}"*.puml >/dev/null 2>&1; then
git mv docs/diagrams/*"${OLD}"*.puml docs/diagrams/*"${NEW}"*.puml 2>/dev/null || true
fi

# 2. 替换图内文本
find docs/diagrams -name "*.puml" -exec sed -i \
"s/component \"${OLD}\"/component \"${NEW}\"/g; \
s/as ${OLD}/as ${NEW##*_}/g" \
{} +

# 3. 验证
if grep -q "${OLD}" docs/diagrams/*.puml; then
echo "WARN: leftover '${OLD}' references found:"
grep -l "${OLD}" docs/diagrams/*.puml
exit 1
fi

echo "Renamed '${OLD}' → '${NEW}' successfully"
1
2
chmod +x rename-component.sh
./rename-component.sh user-service identity-service

工具 3:PlantUML !define 间接引用

预防胜于治疗——一开始就用 !define 抽名字:

1
2
3
4
5
!define USER_SVC identity-service

component USER_SVC as us
order-service --> USER_SVC
@enduml

要改 service 名时只改 !define 一行——但这种约定在团队里需要遵守,否则新人直接写 identity-service 文字,绕过 define。

工具 4:CI 检测「代码 vs 图」漂移

架构图最常见的腐烂——代码改了 service 名,图没改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# tests/test_architecture_drift.py
import re, pathlib, yaml

PUML_TEXT = pathlib.Path("docs/diagrams/architecture.puml").read_text()

# 从代码里读 service 列表(假设按目录)
services_in_code = {
p.name for p in pathlib.Path("services").iterdir() if p.is_dir()
}

# 从图里读 component 名
services_in_diagram = set(re.findall(r'component\s+"([^"]+)"', PUML_TEXT))

# 检测
missing_in_diagram = services_in_code - services_in_diagram
stale_in_diagram = services_in_diagram - services_in_code

assert not missing_in_diagram, f"Code has services not in diagram: {missing_in_diagram}"
assert not stale_in_diagram, f"Diagram has services not in code: {stale_in_diagram}"

CI 跑测试——代码改了 service 但图没改 → fail

架构拆分的图演化

服务从 monolith 拆成微服务,图要跟着演。

阶段 1:monolith

1
2
3
4
5
6
7
8
@startuml
package "Monolith" {
[User]
[Order]
[Payment]
[Inventory]
}
@enduml

阶段 2:拆出 User 服务

1
2
3
4
5
6
7
8
9
10
11
12
@startuml
package "User Service" {
[User]
}
package "Monolith" {
[Order]
[Payment]
[Inventory]
}

User --> Monolith : HTTP
@enduml

新旧图同时存在——architecture-v1-monolith.puml(归档)+ architecture.puml(当前)。

阶段 3:再拆出 Order

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@startuml
package "User Service" as user_svc {
[User]
}
package "Order Service" as order_svc {
[Order]
}
package "Monolith" {
[Payment]
[Inventory]
}

user_svc --> order_svc : HTTP
order_svc --> Monolith : HTTP
@enduml

演进过程留 trace 在 git 里——新人能从 git log 看架构演化史

Archive 策略

老图不该直接删——放 archive/ 目录,加日期前缀:

1
2
3
4
5
6
7
docs/
├── diagrams/
│ ├── architecture.puml # 当前
│ ├── sequence-login.puml # 当前
│ └── archive/
│ ├── 2025-03-monolith.puml # 3 月架构
│ └── 2025-09-monolith-with-user.puml # 9 月拆分

_config.ymlskip_render 防止 archive 渲染:

1
2
skip_render:
- 'diagrams/archive/**'

archive 目录不进 CI 流程,但 git 历史里能查到。

跨版本引用:用 git 历史当图元数据

PlantUML 不支持图内 git 引用——但可以用 %load_json 读 git log:

1
2
3
# 生成 diagrams/git-history.json
git log --format='{"date":"%ai","message":"%s","author":"%an"}' \
docs/diagrams/architecture.puml > docs/diagrams/git-history.json
1
2
3
4
5
6
7
8
9
10
@startuml
!include docs/diagrams/git-history.json

note as N1
Recent commits:
!foreach $commit in %json()
* $commit.date: $commit.message
!endforeach
end note
@enduml

图里显示最近改这个图的 commits——谁改的、什么时候改的、改了什么。

文档跟代码同步的 git hooks

客户端 hook 在 commit 时自动同步图:

1
2
3
4
5
6
7
8
9
10
# .git/hooks/pre-commit
#!/bin/bash

CHANGED_FILES=$(git diff --cached --name-only -- 'services/**/*.go')

if [ -n "$CHANGED_FILES" ]; then
echo "Detected service code changes — auto-regenerating architecture diagram..."
python tools/gen_architecture_diagram.py
git add docs/diagrams/architecture.puml
fi

提交 service 代码时,架构图自动重新生成并加入 commit——开发者不用手动改图。

跨年大重构的图迁移

遇到 service 大批重命名(比如从 user-service 改成 identity-service 同时改 30 个 service):

步骤:

  1. 冻结图编辑——README 写「服务重命名进行中,图暂停更新」
  2. 批量改代码 + 图——一次 PR 全部改完,不要分多次
  3. CI 验证——drift 测试跑过才合并
  4. 删旧图 + archive——重命名完成后,旧 user-service.puml 移到 archive/
  5. 更新文档——README 引用新 service 名

反过来——如果图已经过时了(3 个月没维护):

  1. 承认过时——README 顶部加 ⚠️ 「图与代码有差异,以代码为准」
  2. 派单重建——专门写一个 ticket 重画
  3. 加 drift 测试——避免下次再腐烂

实战踩坑

  • git rename detection 不生效——你改了文件 50% 以上,git 就当是 delete + add,不显示 rename重命名 + 替换同步做(单 commit 内),rename detection 才能识别。
  • PlantUML alias us 跟 user-service 改 identity 不一致——alias 是语法糖,改不改不影响渲染,但 grep 检查「us」引用会搜到「us-east-1」之类的无关词。用 grep 加边界正则:grep -E "(as|component) +us\b"
  • 跨语言引用——Java 服务叫 UserService,Go 叫 user-service,PlantUML 用 user-service——统一用 kebab-case 是最简单约定。
  • CI 测试飘红——drift 测试要求 service 目录跟图严格同步,但有时故意图里加「future service」——// future: 注释标记:
    1
    // future: payment-service (not yet deployed)
    测试跳过带 future: 注释的 component。

总结

场景 工具
Service 重命名 git mv + sed
架构拆分 archive 旧图 + 新图分阶段
防止腐烂 CI drift 测试
自动同步 git pre-commit hook 调 Python 脚本
跨年大改 单 PR 全改,避免中间状态

核心原则:图跟代码同源演化——图要么自动生成(drift 测试兜底),要么人工改但有 CI 提醒。没有自动化就没有长期维护的图

  • 标题: PlantUML 图随 git 演化:重命名、迁移、archive 策略
  • 作者: puml.online
  • 创建于 : 2026-07-30 17:15:00
  • 更新于 : 2026-08-14 21:34:29
  • 链接: https://puml.online/blog/plantuml-versioning-renaming/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。