OpenResearch orx-git 技能实战:用 Git worktree 与 orx/<slug> 分支管理实验代码的版本与不可变历史
2026/9/20 2:57:01 网站建设 项目流程
  • 人工智能
  • AI Agent
  • 深度研究
  • 自主智能体
  • Agent 编排

【免费下载链接】OpenResearch

Turn your coding agents into research agents

项目地址:https://gitcode.com/GitHub_Trending/op/OpenResearch
点击查看免费下载

OpenResearch(orx)把 Git 当作"实验历史的数据库":每一个实验节点都对应一条本地orx/<slug>分支,每一次运行都从这条分支的已提交 commit 构建不可变源码归档,GitHub 发布仅用于协作者可见性、从不参与计算传输。本文以agent-skills/orx-git/SKILL.md为骨架,结合仓库源码(src/local/git.rssrc/local/experiments.rssrc/compute.rssrc/local/localrun.rs等)深入讲解会话工作树模型、分支协作规则、提交即运行机制、父子实验对比以及"历史不可变"纪律。读完后,你将能在多 Agent 并行会话中安全地操作实验代码、避免重复劳动与分支冲突,并能准确理解"已提交内容才是可复现结果"这条底层契约。

一、核心原则:Git 记录实验,但 Git 不是计算传输通道

orx-git技能的第一条纪律是定位问题:

  • Git 记录每一个实验:分支与提交是实验节点事实状态的唯一来源,任何一次运行都要能精确回溯到"跑的是哪一段代码"。
  • GitHub 发布是可选项:发布(publication)可能被启用,目的是让协作者看到进展,它绝不参与计算传输(compute transport)。计算后端拿到的是从已记录 commit 构建出的源码归档,而不是远程仓库。
  • 遵守项目 playbook 的发布状态:不要仅仅为了启动计算而push;同时不要从论文的上游仓库fetch,也不要把结果发布回论文的上游仓库——实验仓库与论文源仓库是两个互相隔离的宇宙。

这一原则在源码里被反复落实。例如 src/local/git.rs 中的github_publicationremote_matches_publication会检查githuboriginupstream三个 remote 的 fetch/push URL 是否都指向项目声明的owner/repo,只有完全匹配才算"发布已配置";而 src/compute.rs 的模块注释则直接写明:本地 Git 是实验历史数据库,启动运行时"绝不要求远端后端克隆这段历史,而是把精确记录的 commit 归档一次、按 SHA-256 寻址、交给选定的提供方适配器"。计算传输的单元是内容寻址的源码归档,不是 git clone。

二、多会话协作模型:同一克隆上的兄弟工作树

2.1 会话工作树从哪来

orx up的本地会话中,每个聊天会话(chat session)都工作在同一个克隆的**兄弟工作树(sibling worktree)**里。源码层面,src/local/git.rs 给出了目录约定:

  • 共享克隆:<data>/repos/<owner>/<repo>
  • 会话工作树:<data>/worktrees/<project_id>/<session_id>

ensure_session_worktree(src/local/git.rs)的注释精确描述了这套设计的收益:工作树共享 hub 的对象存储和 refs——在一个工作树里创建的分支,其他所有工作树立即可见;一次fetch更新所有人;git 本身会拒绝在两个工作树同时检出同一个分支。这正是技能文档要求"开工前先勘察现场"的原因。

2.2 开工前的现场勘察

因为其他会话可能正在同一个克隆的兄弟工作树里工作,动手前必须先回答"别人在做什么":

# 查看所有分支(本地 + 远端跟踪),了解谁占了哪些 orx/<slug> git branch -a # 查看项目最近运行记录,避免重复跑已经回答过的问题 orx runs <projectId> # 查看相关实验节点的备注,读取兄弟会话留下的上下文 orx exp desc <expId>
  • orx runs <projectId>的实现见 src/commands/runs.rs,它把项目运行记录渲染成表格(含状态、时长、commit 短 SHA)。
  • orx exp desc <expId>支持--set "<text>"写备注、cat notes.md | orx exp desc <expId> --stdin从文件灌入,实现位于 src/plane/local_plane.rs。技能强调"边学边记":让实验备注保持最新,兄弟会话才能据此定位

2.3 一分支一 owner:检出冲突的处理规则

分支和 remote 是共享的,工作树目录是私有的。因此一条分支只有一个工作树 owner

  • 如果git checkout报"branch is already checked out",只有当错误信息里列出的路径就是你自己的工作树时才继续操作;
  • 否则,把那条分支留给它的 owner 会话,不要抢占。

这背后是 git worktree 的硬约束:同一分支只能在一个工作树中被检出。正是利用这一点,OpenResearch 才能放心让多个 Agent 并行——冲突在 git 层就被拒之门外。

2.4 工作树以 detached 状态起步

会话工作树默认从 baseline 以 detached HEAD 起步(src/local/git.rs 的注释:直接检出 baseline 分支本身会"认领"它、堵死所有兄弟会话),所以:

  • 进入会话后第一件事是git checkout orx/<slug>切到自己的实验分支;
  • 在编辑之前完成切换,避免把改动落在游离的 HEAD 上。

底层命令是git worktree add --detach <path> <start_ref>(见ensure_worktree_from,src/local/git.rs),start_ref 默认取项目的 baseline 分支。这也是为什么技能里说"check out the experiment branch before editing"。

三、一个实验节点 = 一条 orx/ 分支

3.1 分支如何创建

每个实验节点都有自己的一条本地orx/<slug>分支orx create-experiment负责从父节点创建它:

orx create-experiment <projectId> --title "<title>" [--parent <experimentId>] [--description "<text>"] [--run-command "<cmd>"]

用法定义在 src/commands/create_experiment.rs,形状选择规则见该文件头部注释:

  • --parent <id>→ 从该父实验分支出去的子实验;
  • --baseline→ 新建一条 baseline(根节点),项目可持有多个 baseline;
  • 不带参数 → 取项目最老的根节点(树为空时新建 baseline)。

slug由标题派生并去重。实现位于 src/local/experiments.rs:unique_slug扫描项目里所有已有实验的 slug 与全部本地分支的orx/前缀,生成basebase-2base-3…… 这样第一个可用值;随后用git branch --no-track <new> <parent>(src/local/git.rs)从父分支的本地 tip拉出orx/<slug>。注意--no-track:实验分支不绑定上游跟踪,避免与远端发布互相干扰。

3.2 标准工作流:编辑 → 提交

在每个会话工作树里,只做"这一个实验"的改动,然后:

git checkout orx/<slug> git status --short # 确认起点干净 git add <changed files> git commit -m "describe the experiment change"

提交信息应当描述实验变更本身(如调整的学习率、换用的数据集、修改的损失函数),而不是泛泛的 "update"。

3.3 边界情况:baseline 之前的老根实验

源码里还处理了一个历史遗留问题:src/local/experiments.rs 的legacy_root_warning会警告:在 baseline 拥有自己的orx/*分支之前创建的根实验,是骑在项目 base 分支上的。遇到这类节点时把它当作"base 分支上的根实验"处理,不要误解成"分支丢失"。

四、提交即运行:不可变源码归档

4.1 运行只认已提交的 commit

runner 从记录的 commit 构建不可变源码归档(immutable source archive),已提交的内容在所有后端上都是充分的(sufficient)。未提交的文件永远不会被包含进一次运行。

具体机制在 src/compute.rs 的SourceSnapshot::create

  1. git rev-parse取实验分支的 HEAD 作为revisionlocal_head_sha,见 src/local/git.rs);
  2. 调用git archive --format=tar <revision>archive函数,src/compute.rs)把该 commit 的完整树打成 tar;
  3. 对 tar 计算 SHA-256 摘要,按<digest>.tar内容寻址存放于<data>/source-snapshots/,权限收紧到 0600/0700;
  4. 运行记录里写入commit_shaStoredRun.commit_sha,见 src/local/localrun.rs)。

因为快照按内容寻址,同样的代码只归档一次;install_content_addressed(src/compute.rs)还会在复用缓存时做 digest+size 双校验,防止缓存被篡改。运行侧的脚本(snapshot_script,src/compute.rs)则是:

set -eo pipefail; mkdir -p repo; tar -xf <archive> -C repo; cd repo; <run-command>

即:从归档解出精确的 commit 树,在独立的运行目录里执行,绝不动 Agent 的工作树(src/local/localrun.rs 的注释:"the run extracts the recorded revision into its own run dir, never the agent's worktree")。远程后端同理——src/local/k8s.rs 的注释强调代码"在记录的 revision 上被读取,与 job 收到的 commit 完全一致"。这也解释了为什么每个后端(HF、Modal、K8s、Ray、Slurm、SSH、OpenResearch、Local/Tinker)的启动代码里都带着source_digest/source_path字段(见 src/jobs/mod.rs 与各src/local/*.rsBackendDescriptor构造)。

4.2 启动前检查

因此,在启动一次运行之前,务必确认:

git status --short # 必须为空:未提交改动不会进运行 git show --stat --oneline HEAD # 核对将要被归档的 commit 内容

git show --stat --oneline HEAD让你在按下运行键之前,用眼睛确认"将要运行的就是这条提交"。一次干净的git status --short+ 一条符合预期的git show,是"我的运行是可复现的"的最小证明。

4.3 备注信息与运行命令的继承

orx exp desc <expId>的备注、--run-command都会随节点保存;运行命令解析遵循"实验自带 > 项目默认"的优先级(src/local/localrun.rs、src/local/experiments.rs)。运行记录(StoredRun)里同时保存了commit_shacommandstatus等,供orx runsorx exp status <expId>展示(后者会打印"last run: … commit …",见 src/plane/local_plane.rs)。

五、对比子实验与父实验:只使用本地 refs

要弄清"子实验相对于父实验改了什么",只使用本地 ref,不要上网:

# 三点 diff:merge-base 语义,累计展示父分支与子分支之间的全部差异 git diff <parent-branch>...orx/<child-slug> # 仅列出子分支上多出的提交(<parent>..<child>) git log --oneline <parent-branch>..orx/<child-slug>

这套命令与仓库内部实现完全一致:diff_range使用base...head(三点、merge-base 语义,src/local/git.rs),list_commits_between使用base..head(src/local/git.rs),且都通过resolve_commitish(src/local/git.rs)优先解析本地 ref、其次回退到refs/remotes/origin/。原因很直接:Agent 的工作先提交到本地orx/<slug>分支,本地 ref 才是最新、最权威的对比基准;远端可能还没 push,甚至不该 push。

六、历史不可变:永不 merge / rebase 实验分支

一次运行回答了某个实验之后,该分支及其历史就是不可变的(immutable)。它精确记录着"当时跑过的那段代码",任何改写都会让历史失去证词价值。因此:

  • 绝不merge 或 rebase 一条已完成的实验分支;
  • 需要并入其他工作成果时,创建子实验,把 merge commit 放在子分支上
  • 绝不rebase 实验历史——它记录的是实际运行过的精确代码。

这条纪律在 UI 和模型层同样有呼应:例如 UI 中的文件版本/分支变更视图(ui/src/components/BranchChanges.tsx、ui/src/components/GitDiff.tsx)都围绕"分支 + commit"呈现,而非工作区草稿;运行记录的 diff 上限(MAX_DIFF_BYTES,src/local/git.rs)也保证了任何被展示的 diff 都源于 git 对象库,可追溯。

七、GitHub 发布:只推 baseline 与 orx/*

发布用于协作者可见性,遵循项目 playbook 的发布状态即可。仓库实现的发布边界非常清晰:

  • 只推送 baseline 分支和orx/前缀的分支push_all(src/local/git.rs)过滤branch == baseline_branch || branch.starts_with("orx/"),按 baseline 优先排序后逐条git push -u <remote> <branch>
  • 发布 remote 按githuboriginupstream顺序识别publication_remote,src/local/git.rs),要求 fetch 与全部 push URL 都指向项目声明的仓库;
  • 推送走认证通道authenticated_git_command(src/local/git.rs)显式禁用交互提示(GIT_TERMINAL_PROMPT=0ssh -oBatchMode=yes),并把凭据 helper 限定为!gh auth git-credential,避免把用户的全局 git 配置卷进来;
  • 发布状态可查询publication_sync_status(src/local/git.rs)会对比本地与远端的 heads,返回not configured/not pushed/local changes to push/synced之一。

与论文上游仓库的关系要始终保持"只读隔离":不要fetch论文上游、更不要发布回上游。涉及论文仓库导入时,仓库还做了浅克隆重定根(reroot_shallow_repositoryprepare_shallow_repository_for_publication,src/local/git.rs)与克隆时对 URL 的严格校验(public_clone_url,src/local/git.rs),目的都是保证"论文源仓库"与"实验仓库"两条线互不污染。

八、常见故障与边界情况速查

现象处理方式源码依据
checkout报分支已被检出仅当列出的路径是自己的工作树时才继续,否则留给 owner 会话ensure_session_worktree注释(src/local/git.rs)
工作树处于 detached HEAD编辑前先git checkout orx/<slug>git worktree add --detach(src/local/git.rs)
想启动运行但git status --short非空先提交,未提交文件不会进归档SourceSnapshot::create(src/compute.rs)
想确认将运行的代码git show --stat --oneline HEADsnapshot_script(src/compute.rs)
老根实验警告按"base 分支上的根实验"理解,无需修复legacy_root_warning(src/local/experiments.rs)
手动删除了工作树目录导致worktree add失败仓库会自动git worktree prune清理陈旧注册ensure_worktree_from(src/local/git.rs)
克隆/发布遇到认证发布走gh auth git-credential,克隆优先 ssh、回退 https,均禁交互authenticated_git_commandensure_clone(src/local/git.rs)
运行记录的源码归档缺失按 digest 校验失败会明确报错,不会静默降级SourceSnapshot::from_run(src/compute.rs)

九、总结:orx-git 的三条纪律

agent-skills/orx-git/SKILL.md浓缩成三条纪律,也就把握住了 OpenResearch 实验版本管理的全部精髓:

  1. 先勘察、后动手git branch -a+orx runs+orx exp desc三连,尊重"一分支一 owner",避免与兄弟会话互相踩踏。
  2. 提交即事实:运行只认orx/<slug>分支上已提交的 commit;源码归档按 SHA-256 内容寻址、跨后端一致;启动前用git status --shortgit show --stat --oneline HEAD自检。
  3. 历史是证词,不可改写:已回答的实验分支永不 merge/rebase,需要合并就开子分支;发布只推 baseline 与orx/*,且与论文上游仓库彻底隔离。

遵循这三条纪律,多 Agent 并行研究会话就能在同一克隆上互不干扰地工作,而每一行跑过的代码都能精确回溯——这正是"把编码 Agent 变成研究 Agent"的版本管理地基。相关实现可继续深入 src/local/git.rs、src/local/experiments.rs、src/compute.rs 与 src/local/localrun.rs 阅读。

  • 人工智能
  • AI Agent
  • 深度研究
  • 自主智能体
  • Agent 编排

【免费下载链接】OpenResearch

Turn your coding agents into research agents

项目地址:https://gitcode.com/GitHub_Trending/op/OpenResearch
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询