graphify 跨仓库知识图谱实战:从 GitHub Clone、多仓库抽取到 merge-graphs 统一合并
这篇指南讲解 graphify(vscode skill 参考文档 github-and-merge.md 定义的)"克隆 + 跨仓库合并"工作流:当你给出一到多个 https://github.com/... 仓库地址、或几个需要合并为同一张图谱的本地子目录时,如何把每个仓库先转成独立的 graph.json,再用 graphify merge-graphs 合并成一张带来源标记(repo 属性)的统一图谱,并从此对合并图谱直接运行 graphify query。读完你既能照抄单仓库与 monorepo/多服务场景的可运行命令,也能理解 merge-graphs 在源码层如何做节点前缀、去碰撞、社区编号偏移与跨仓库类型连接。
这份参考文档在什么场景下被加载
本文件是 graphify 各 Agent Skill 公共参考之一,位于 github-and-merge.md。在主 Skill 文件(如 skill-vscode.md)中,/graphify 系列斜杠命令支持三种携带仓库的场景,分别对应:
/graphify https://github.com/<owner>/<repo>—— 先克隆再跑完整流水线;/graphify https://github.com/<owner>/<repo> --branch <branch>—— 克隆指定分支;/graphify <url1> <url2> ...—— 克隆多个仓库、各自建图、最后合并为一张跨仓库图谱。
当用户消息中出现以上任一形态(或"给出多个本地子目录待合并"),Skill 才加载本参考文档执行 Step 0;纯本地单目录路径会直接跳过此步骤。
单仓库:用 graphify clone 得到本地路径
当输入是单个 GitHub URL 时,先克隆再以克隆结果为后续所有步骤的扫描目标。推荐写法是捕获 graphify clone 输出到变量:
LOCAL_PATH=$(graphify clone <github-url> [--branch <branch>])
# 后续所有步骤都以 $LOCAL_PATH 为目标
该子命令的完整签名(源码位于 cli.py)为:
graphify clone <github-url> [--branch <branch>] [--out <dir>]
底层 _clone_repo 的实现细节(cli.py)决定了如下行为,可直接作为使用依据:
- 默认缓存位置是
~/.graphify/repos/<owner>/<repo>:URL 中github.com后的owner/repo会被正则提取出来拼出目标目录; - 重复运行复用已有克隆:若目标目录已存在,不重复 clone,而是执行
git pull拉取最新(带分支时拉取该分支),并打印Repo already cloned at ... - pulling latest...; - 首次克隆是浅克隆:底层执行
git clone --depth 1 [--branch <branch>] -- <url> <dest>; - URL 会被规范化:末尾多余的
/会被去掉,缺少.git后缀时自动补齐; --out <dir>可覆盖默认目录,把克隆放到你指定的位置;- 命令末尾会把最终可用路径打印到标准输出(
print(local_path)),这正是LOCAL_PATH=$(graphify clone ...)能拿到路径的原因; - 分支名以
-开头会被判定非法并报错退出,避免参数注入。
多仓库:每个仓库独立建图后再交叉合并
一次处理多个 GitHub 仓库时,参考文档给出的流程是:分别克隆 → 对每个本地路径各跑一次完整 /graphify 流水线产出各自的 graph.json → 最后用 merge-graphs 合并:
# 克隆每个仓库(clone 会自动复用已有克隆)
graphify clone <url1> # → ~/.graphify/repos/<owner1>/<repo1>
graphify clone <url2> # → ~/.graphify/repos/<owner2>/<repo2>
# 对每个本地路径运行 /graphify,分别产出各自的 graph.json
# (或在命令行使用 graphify extract,见下文"本地多子目录"一节)
# 然后合并:
graphify merge-graphs \
~/.graphify/repos/<owner1>/<repo1>/graphify-out/graph.json \
~/.graphify/repos/<owner2>/<repo2>/graphify-out/graph.json \
--out graphify-out/cross-repo-graph.json
合并结果的两个关键约定(文档明示、源码可印证):
- 克隆目录可复用:默认落入
~/.graphify/repos/<owner>/<repo>,反复跑同一 URL 会执行增量git pull而非重复克隆; - 每个节点带
repo属性:合并图中的每个节点都带有repo标签,因此你可以按来源仓库过滤、追溯每个符号究竟来自哪个仓库。
本地多子目录(monorepo / 多服务):先分目录 extract 再在根目录合并
当要合并的不是多个远程仓库、而是同一项目树下的多个本地子目录(monorepo 或多服务布局)时,参考文档特别提醒了一个输出目录冲突陷阱:Skill 流水线会把全部中间产物与最终结果写到当前工作目录的 graphify-out/;若分别对每个子文件夹各跑一次 Skill,就会反复覆写同一个输出目录。
解决办法是改为对每个子目录直接调用 CLI graphify extract——它的输出目录 graphify-out/ 会落在被扫描路径内部,彼此天然隔离:
graphify extract ./core/ # → ./core/graphify-out/graph.json
graphify extract ./service/ # → ./service/graphify-out/graph.json
graphify extract ./platform/ # → ./platform/graphify-out/graph.json
# 按你已配置的 API key 追加后端参数:
# --backend gemini|kimi|openai|deepseek|claude-cli
# 最后在项目根目录合并:
graphify merge-graphs \
./core/graphify-out/graph.json \
./service/graphify-out/graph.json \
./platform/graphify-out/graph.json \
--out graphify-out/graph.json
graphify extract 是专为 CI/脚本准备的"无头完整流水线"子命令(见 cli.py),它串起 detect → 代码 AST 抽取 → 文档/论文/图片的语义 LLM 抽取 → merge → build → cluster → 写出结果,与 Skill 内部流程等价但直接调用抽取核心。其完整参数面包括 --mode deep、--no-dedup、--code-only、--no-cluster、--max-workers、--token-budget 等;后端名称以 --backend 枚举,源码(cli.py 第 3013 行)所示列表为 gemini|kimi|claude|openai|deepseek|ollama,不同版本间名称可能存在细微出入,运行 graphify extract 不带参数可看到你当前版本的确切取值。
merge-graphs 的底层原理:前缀、去碰撞与跨仓库连接
合并并非简单的 JSON 拼接。从源码看(cli.py),graphify merge-graphs <graph1.json> <graph2.json> [...] [--out merged.json] 至少需要两个输入图,缺省时输出到当前工作目录 graphify-out/ 下的 merged-graph.json(可通过 --out 覆盖),完成后打印 Merged N graphs -> X nodes, Y edges 与写出位置。其内部依次执行了以下关键步骤,理解这些有助于你判断合并结果是否合理:
- 加载并容错:逐个读取
graph.json;兼容老版本可能用edges键而非links键的写法;保存并恢复每条边真实的_src/_tgt方向标记;从嵌套graph.hyperedges槽位或顶层hyperedges键中取回超边; - 图类型归一:不同来源的图可能是
DiGraph/MultiGraph/MultiDiGraph,而合并后的跨仓库视图本身是无向的,因此统一归一为普通的无向Graph,避免nx.compose因类型不一致崩溃; - 节点加 repo 前缀:通过 build.py 的
prefix_graph_for_global,把所有节点 ID 改写为repo_tag::原ID,同时:repo属性标记来源仓库;local_id属性保留可还原的原始 ID;边与超边成员同步改写;超边 ID 同样加前缀防止不同仓库同名超边互相冲突; - 仓库标签去碰撞:朴素的标签取
graphify-out的父目录名,但src/graphify-out与frontend/src/graphify-out会得到相同的src,导致不同仓库同名节点被错误合并。distinct_repo_tags(build.py)在发生碰撞时用上级目录加宽(如frontend_src)、必要时追加序号后缀,保证每个图有唯一前缀; - 社区编号偏移:每个输入图都从 0 开始给自己的社区编号,直接合并会把互不相关的社区在聚合视图里融合成一个 meta 节点,因此合并时把后加入图的社区 ID 偏移到共享编号空间(
local_community保留各自原始划分); - 超边重挂:修正历史版本中
nx.compose只保留最后一个输入超边列表的问题,收集全部输入的超边并在 compose 之后重新去重挂接; - 跨仓库同类型声明建链:所有 ID 都被前缀化后,两个仓库各自声明的同一契约类型会成为两个互不相连的节点。
link_shared_type_declarations(cross_repo_types.py)按"命名空间 + 类型名"找跨仓库匹配,为它们补same_type_as边(关系上下文记为cross_repo,置信度INFERRED、confidence_score=0.9),从而允许图谱遍历跨过仓库边界——例如一个仓库生产SyncProductUpsertToSearchEvent、另一个仓库实现IConsumer<SyncProductUpsertToSearchEvent>的消息总线代码,正是需要这一步来打通的关键一跳。它只加边、不合并节点,让两侧各自保留成员、文件与出处,避免掩盖契约漂移。
合并完成后的快速路径:直接 query,无需重新抽取
参考文档最后强调:一旦 graphify-out/graph.json 存在,快速路径即刻接管——任何关于代码库的问题都可以直接在合并图上运行查询,不需要重新抽取、也没有规模门槛:
graphify query "你的问题"
query 子命令的用法(cli.py)为:
graphify query "<question>" [--dfs] [--context C] [--budget N] [--graph path]
其中 --graph path 可指向任何自定义位置的结果图;对跨仓库合并场景,把 --out 写到的合并图路径(如上面的 graphify-out/cross-repo-graph.json)传给它即可,配合每个节点上的 repo 属性,就能在一个查询里追溯跨仓库调用、依赖与共享契约的完整链路。
使用要点与边界(基于当前仓库源码)
- 合并至少需要 2 个输入图;输入文件不存在时
merge-graphs会直接报错退出(error: not found: <path>); - 合并产出的跨仓库视图是无向图,边方向信息依靠
_src/_tgt标记在写出时还原; clone目前识别github.com的 HTTP(S) 地址形态(含:owner/repo.git式 SSH 写法中的路径段),无法识别的 URL 会报not a recognised GitHub URL;- 已有 Skill 参考中另有一个 git 合并驱动
graphify merge-driver <base> <current> <other>(cli.py),用于在 git 层面自动三方合并graph.json,并对超大/损坏输入设了保护上限后安全退出,与本工作流互补,适合把图谱文件纳入版本管理后使用。
相关文件索引
- 本文依据:本参考文档 github-and-merge.md,以及承载它的主 Skill 文件 skill-vscode.md;
- CLI 入口与子命令实现:cli.py(
merge-graphs、clone、extract、query均在其中); - 合并核心:前缀化与仓库标签生成 build.py;
- 跨仓库共享类型建链:cross_repo_types.py。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00