graphify 从 GitHub URL 到跨仓库知识图谱:clone、extract 与 merge-graphs 完整实战指南
本指南对应 graphify 技能参考文档中的核心工作流之一。当你把一或多个
https://github.com/...的仓库链接丢给 graphify,或想把本地多个子目录(monorepo/多服务布局)合并成一张可查询的图谱时,本指南就是操作手册:先讲透graphify clone的克隆语义与缓存复用,再分别演示「单仓库图谱」「多仓库跨仓库图谱」「多本地子目录图谱」三条生产级路径,最后结合仓库源码解释合并图为何会带repo属性、节点 ID 如何被改写,以及合并完成后如何用快速路径直接graphify query。读完你就能把任意多个代码库的graph.json合并为一张带仓库来源标签、可过滤可查询的统一图谱。
在 graphify 的 8 份按需加载参考文档中,github-and-merge.md 是唯一一份专门处理「输入来源」的参考:它决定了一张图的原材料从哪里来、以什么目录结构落地、又在何时被合并成更大的统一图。该参考是全部平台的共享片段,经 skillgen 渲染后逐平台发布,例如本文分析的 Windows 平台成品 与它的单一事实来源片段 fragments/references/shared/github-and-merge.md。graphify 每次把代码库(连同文档、SQL schema、配置与 PDF)解析为可查询知识图谱后,graph.json 就是后续一切查询的入口——而如何让多份 graph.json 各归其位、最后合成一张,正是本文主题。
Step 0:从 GitHub URL 克隆仓库(仅在收到 URL 时执行)
当用户只给了代码库的本地路径时,本步骤整段跳过;只有用户明确传入了 https://github.com/... 形式的 URL,才需要先把它落到本地磁盘。clone 子命令的定位很明确——看 graphify/main.py 的帮助文案,它被描述为 "clone a GitHub repo locally and print its path for /graphify":克隆完成后把本地路径打到标准输出,供后续所有步骤当作目标路径使用。
单仓库:一行拿到可扫描的本地路径
LOCAL_PATH=$(graphify clone <github-url> [--branch <branch>])
# Use LOCAL_PATH as the target for all subsequent steps
关键点:
- 命令替换:
graphify clone会把克隆落地路径打印到 stdout,所以用$(...)捕获后,LOCAL_PATH就是后续/graphify、graphify extract的目标; --branch <branch>:可选,指定要检出的分支;不传则用仓库默认分支;- 完整用法还支持
[--out <dir>],即自定义克隆目录,见下节。
仓库落地约定:为什么重复运行不会重复克隆
graphify 默认把仓库克隆进 ~/.graphify/repos/<owner>/<repo>,且重复运行同一 URL 时复用已有克隆。这一点有明确的源码实现依据:查看 graphify/cli.py 中 clone 的底层实现,其 docstring 写明 "Clones into ~/.graphify/repos/<owner>/<repo> by default so repeated runs on the same URL reuse the existing clone (git pull instead of clone)"——也就是说首次运行执行真正的 git clone,后续运行走增量更新逻辑,而不是把整个仓库再拉一遍。底层命令形态如下(cli.py 中实际构造的 git 命令):
git clone --depth 1 [--branch <branch>] -- <git_url> <dest>
其中 --depth 1 表示浅克隆(只取最近一次提交历史),这对建立知识图谱而言足够——graphify 分析的是代码结构与语义,不需要完整 git 历史。
落地目录规律:<owner> 与 <repo> 取自 GitHub URL,因此两个不同 owner 下同名仓库、或同一 owner 下不同仓库,天然落在互不冲突的目录里,不会互相覆盖。
多仓库(跨仓库图谱):先各自建图,再 merge
跨仓库图谱的标准姿势是「分治 → 合并」三段式:逐个克隆 → 对每个本地路径跑完整管线产出各自的 graph.json → 用 merge-graphs 合并。参考文档给出的完整流程:
# Clone each repo, run the full pipeline on each, then merge
graphify clone <url1> # → ~/.graphify/repos/<owner1>/<repo1>
graphify clone <url2> # → ~/.graphify/repos/<owner2>/<repo2>
# Run /graphify on each local path to produce their graph.json files
# Then merge:
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 clone <url1> 注释里标注的目标路径——clone 输出的是克隆根目录(如 ~/.graphify/repos/<owner1>/<repo1>),而真正喂给 merge-graphs 的是每个克隆内部的 graphify-out/graph.json。也就是说,每个仓库需要先经历完整抽取管线(AST 解析 + 语义标注 + 建图),才会产生可供合并的图文件。
merge-graphs 的 CLI 约束也很直接,在 graphify/cli.py 的对应分支实现中:必须提供 2 个及以上输入图路径,输出路径通过 --out 指定,默认值是 graphify-out/merged-graph.json(_GRAPHIFY_OUT 目录下的 merged-graph.json)。换句话说,--out 是可选的,不写也有安全的默认落点;写成 graphify-out/cross-repo-graph.json 只是为产物起一个语义更清晰的名字。
多本地子目录(monorepo / 多服务布局):绕过输出目录冲突
当用户不是给 GitHub URL,而是点名了几个本地子文件夹要合并成一张图时,参考文档给出了一个极其重要、容易踩坑的背景知识:
技能管线会把所有中间产物与最终产物写到当前工作目录的
graphify-out/。如果对每个子文件夹分别跑一遍技能,它们会互相覆盖同一个输出目录。
也就是说,若在仓库根目录跑 /graphify ./core、再跑 /graphify ./service,两次都写根目录的 graphify-out/,前一次结果会被后一次冲掉。这正是文档建议「绕过技能,直接用 CLI」的原因——CLI 的 graphify extract <path> 会把 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
# Add --backend gemini|kimi|openai|deepseek|claude-cli depending on which API key you have set
# Then merge at the project root:
graphify merge-graphs \
./core/graphify-out/graph.json \
./service/graphify-out/graph.json \
./platform/graphify-out/graph.json \
--out graphify-out/graph.json
要点拆解:
- 输出就地隔离:
./core/的产物落在./core/graphify-out/graph.json,./service/的落在./service/graphify-out/graph.json……彼此零冲突,这是多个 extract 能并行/串行各自安全完成的前提; - 合并发生在项目根:三个子图就绪后,在项目根目录执行
merge-graphs,把三份图合成graphify-out/graph.json——此时根目录这份才是后续统一查询的总图; extract是无头完整抽取:看 graphify/main.py 中extract的说明,它是 "headless full extraction (AST + semantic LLM) for CI/scripts",即不依赖交互式技能、适合脚本与 CI 的完整抽取入口。它和技能管线的区别只是输入输出位置的组织方式,抽取深度一致。
--backend:语义阶段用哪个 LLM
extract 默认会自动探测("default: whichever API key is set"),但显式指定更可控。文档示例注释中给出的选择是 gemini|kimi|openai|deepseek|claude-cli——核心依据是你现在配了哪家 API key。结合 CLI 帮助文本(graphify/main.py),extract --backend 实际可接受的名字集合还包括 claude 与 ollama(其中 openai 后端还可以通过 OPENAI_BASE_URL 指向 llama.cpp、vLLM、LM Studio 等自托管 OpenAI 兼容服务)。实践建议:结构抽取(AST 部分)始终本地免费执行,--backend 只决定文档/论文/图片等内容的语义标注由哪家模型完成,按你环境里实际生效的 key 选即可。
合并图的底层语义:repo 属性、ID 前缀与来源过滤
参考文档承诺了一个关键行为,而它由源码逐条兑现:
Each node in the merged graph carries a
repoattribute so you can filter by origin.
这意味着合并后你随时可以回答「这条依赖关系属于哪个仓库」这类溯源问题。真实实现比「加一个属性」更细致,可拆成三层来看:
第一层:合并前先给每个输入图打上唯一的 repo 标签。 在 graphify/build.py 中,merge-graphs 会为每个输入图计算一个 "unique, human-meaningful repo tag"。这里还有个隐蔽的坑:不能直接用 graphify-out 的父目录名当标签——src/graphify-out 与 frontend/src/graphify-out 的父目录同名时标签就撞车了,因此有专门的 distinct_repo_tags 逻辑保证每个输入图拿到互不相同的标签。
第二层:节点 ID 全量加前缀。 同一个函数在 graphify/build.py 里把每个节点的 ID 改写成 <repo_tag>::<原ID> 形式,同时:
- 保留原始标签(label)不变,仅用于展示;
- 为每个节点附加
local_id属性,以便从带前缀的 ID 还原出原始 ID; - 边及边的方向属性(
_src/_tgt)同步改写以匹配新的带前缀 ID; repo属性被设置到每个节点上——这就是过滤与溯源的锚点。
第三层:跨仓库类型有机会再缝合。 前缀化之后,两个服务各自声明的同名契约类型会以「两个独立节点」的形式出现在合并图中——这在消息总线架构里恰恰是价值所在:生产者在一个仓库引用事件类型、消费者在另一个仓库实现它。合并图并不会自动把它们糊在一起,而是提供再加工的空间,相关逻辑见 graphify/cross_repo_types.py 的模块说明("Join the same declared type across repositories in a merged graph")。
什么时候更该走 merge 而不是单目录直扫? 连 graphify 自己的去重模块都在提示你:当同一路径下的抽取会把「名字相同但实体不同」的节点误判为重复时,graphify/dedup.py 会直接建议 "run 'graphify extract' per subfolder and merge with 'graphify merge-graphs'"——这正是本文这套多子目录工作流的另一大适用场景:让每个子目录先独立成图、保留各自实体,再由 merge 阶段统一按需关联。
合并完成后的快速路径:免重抽取直接 query
整份参考文档在结尾给出一个让「后续所有对话都变快」的机制:
Once
graphify-out/graph.jsonexists, the fast path above takes over: any codebase question runsgraphify querydirectly on the merged graph — no re-extraction, no size gate.
翻译成实际操作就是:合并完成后,一旦目标路径(根目录的 graphify-out/graph.json)已经存在,后续任何关于代码库的问题都直接走 graphify query 查询这张合并图——不再重新抽取,也不再受仓库体量门槛限制。这对跨仓库场景是决定性的体验提升:你不需要在每次提问时重新 AST 解析三个仓库,一次抽取 + 一次合并的成本被摊薄到此后无数次查询中。
命令速查与语义对照
| 场景 | 命令形态 | 产物位置 |
|---|---|---|
| 克隆单个 GitHub 仓库 | graphify clone <url> [--branch <b>] [--out <dir>] |
默认 ~/.graphify/repos/<owner>/<repo>,stdout 打印路径 |
| 克隆仓库(指定分支) | graphify clone <url> --branch main |
同上,检出指定分支 |
| 单仓库本地抽取 | graphify extract <LOCAL_PATH> |
<LOCAL_PATH>/graphify-out/graph.json |
| 多子目录分别抽取 | graphify extract ./core/ ./service/ ./platform/(各自单独执行) |
./core/graphify-out/graph.json 等,互不覆盖 |
| 合并多份图 | graphify merge-graphs <g1> <g2> [...] --out <out>.json |
默认 graphify-out/merged-graph.json;需 ≥ 2 个输入图 |
| 合并后查询 | graphify query(基于已存在的 graphify-out/graph.json) |
免重抽取、无体量门槛 |
补充一个与本文主题呼应的仓库内旁证:graphify/__main__.py 的 CLI 帮助里还有一条 merge-driver——一个用于 git 三方合并时对两份 graph.json 做 union-merge 的合并驱动。它和本文的 merge-graphs 分属不同场景(前者服务 git merge 钩子、后者服务知识图谱的显式合并),说明「图文件合并」是 graphify 中一等公民的操作,既有面向用户的命令入口,也有面向版本控制集成的底层支持。
适用前提与边界说明
- 本文全部命令以当前仓库代码为准,克隆与合并的落地目录、默认输出路径随版本可能演进,动手前可用
graphify --help与graphify extract --help复核; graphify clone依赖本机git可用;--depth 1浅克隆意味着不携带完整历史,若你的分析依赖历史提交信息,需要自行调整克隆策略;- 合并图的
repo过滤依赖合并时附加的属性与 ID 前缀,因此请始终使用merge-graphs合并、而不要手工拼接graph.json; --backend的可选模型列表以 graphify/main.py 的帮助文本为准,实际生效值取决于你环境中配置的 API key。
通过这套工作流,你可以把「N 个 GitHub 仓库」或「monorepo 里的 N 个服务目录」稳定地折叠成一张带来源标签的统一知识图谱,再用 graphify query 享受随问随答的快速路径——这正是 graphify 跨仓库代码理解能力的入口所在。
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 StartedRust0626
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