尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Worktrunk:为并行AI Agent打造的Git Worktree管理利器

Worktrunk:为并行AI Agent打造的Git Worktree管理利器 先说个场景我最近在带一个多 Agent 并行改造遗留仓库的活儿前端Agent改页面、后端Agent加接口、文档Agent写README三个同时跑在同一个repo里。结果不到半小时两个Agent因为互相git checkout把对方的未提交修改顶掉了还有一个在错误的基线上生成了一堆冲突。那一刻我就意识到跨Agent并行开发最缺的不是更强的模型不是更长的上下文而是一个能让每个Agent拥有独立工作区、互不干扰的仓库隔离机制。这也是我搞Worktrunk的初衷一个面向并行 AI Agent 工作流的 Git Worktree 管理 CLI。Git Worktree 这功能本身并不新鲜但直接用它来管 Agent 特别别扭——命令太底层、目录太随意、分支命名靠自觉Agent 根本搞不清自己应该在哪个目录干活。Worktrunk 就是把这层别扭全部包起来用“任务”为单位把工作区的创建、切换、合并、清理做成一条龙。这篇文章我会从问题拆解、设计思路、核心实现到实操过程完整讲一遍中间穿插我踩过的坑和排查实录希望对正在折腾 Agent 并行开发的你有用。1. 并行 AI Agent 工作流为什么需要 Worktrunk1.1 当一个仓库里同时跑多个 Agent 时的混乱现场先说清楚痛点。很多人觉得 AI Agent 写代码就是把任务往终端里一丢等它自己跑完。但如果你真的让两个 Agent 同时操作同一个 Git 仓库你会发现事情完全不是这么回事。Agent A 被要求“给订单模块加一个导出 Excel 的功能”它先在main分支上拉了最新代码然后在src/order/目录下开始改文件。Agent B 被安排“优化用户中心的响应式布局”它同样在main分支上工作在src/user/目录下改样式。从文件路径上看两个任务井水不犯河水。可是问题出在 Git 状态上当 Agent A 执行git add .和git commit时它会把整个仓库的所有变更都提交进去包括 Agent B 还没提交的src/user/下的修改。反过来Agent B 如果在这中间执行了git checkout main或者git reset --hard那 Agent A 写到一半的代码就会直接丢失。这不是理论推演是我实际踩过的坑。我那次两个 Agent 跑了 40 多分钟最后 A 的任务“成功”但 B 的三个文件被 A 的提交吞掉了。更气人的是因为两边都在改 index 目录相关的东西合并时产生了满屏的冲突人肉解冲突花了一个半小时比让 Agent 重新写一遍还慢。这里要说明一点很多人以为用git branch开分支就能解决问题。实际上分支能解决“提交隔离”但解决不了“工作目录冲突”。同一个仓库同一时刻只能有一个工作目录不管你在哪个分支工作目录里只有一个状态。Agent A 和 Agent B 共享同一个工作目录就必然会互相踩踏。只要你用的是同一个仓库实体所有 Agent 都只能看到同一个.git和同一份工作区文件。1.2 Git Worktree 能解决什么不能解决什么Git Worktree 是 Git 2.5 引入的功能它的核心就是让同一个仓库可以同时有多个工作目录每个工作目录检出不同的分支并且各自拥有独立的索引和暂存区。底层原理其实很清晰正常情况下仓库的元数据都在.git目录里工作目录只有一个.git/HEAD指向当前检出的分支。git worktree add会在其他路径创建一个新的工作目录并在.git/worktrees/name/下生成一套独立的HEAD、index和gitdir指针。各个 worktree 之间共享对象数据库和引用refs但HEAD、索引、暂存区互相独立。所以它解决了什么问题呢核心就是“同一时间多个分支各自有独立工作目录”。Agent A 在/repo-frontend下干活Agent B 在/repo-backend下干活它们互不可见、互不影响各自的git add、git commit、git status都只作用于自己的工作区。但 Git Worktree 本身解决不了“管理复杂度”的问题。缺什么具体有三点。第一目录命名和分支命名没有规范全靠人自觉。你创建一个 worktree默认目录名是../repo-name加上分支名比如../repo-my-feature时间一长一堆相似目录人都分不清Agent 更分不清。第二worktree 的生命周期管理繁琐。合并完一个功能之后你得先cd回主工作区把分支合并掉再git worktree remove删掉工作目录再git branch -d删掉分支。三个命令一步都不能乱。Agent 做不来这种多步收尾。第三和 Agent 的上下文衔接很差。Agent 不知道自己当前在哪个 worktree、对应哪个任务、基线分支是哪个。你得在 prompt 里反复叮嘱“你现在在 /path/to/worktree xxx 分支下工作”Agent 还是会忘。1.3 Worktrunk 的定位以任务为核心的 Agent 工作区调度器Worktrunk 的设计思路很简单把“分支 worktree 路径 任务状态”这三者捆绑成一个整体用一条命令完成一个动作。你能想象吗在 Worktrunk 出现之前我需要手动跑三条命令才能建好一个 Agent 工作区git fetch origin git worktree add -b feature/export-excel ../trunk-export-excel origin/main cd ../trunk-export-excel而用 Worktrunk 只需要一条worktrunk create export-excel它会自动做几件事基于最新 main 创建独立分支、在统一目录trunk_export-excel下创建 worktree、记录这个任务的名字和状态、输出给 Agent 的上下文提示。Agent 要做的只是cd trunk_export-excel然后开工。这个工具的本质是把 Git 原生的 worktree 机制封装成“任务的创建、切换、合并、销毁”四个动作让 Agent 和人都能用最少的精力管理多个并行工作区。它不是要取代 Git而是让 Git 在并行 Agent 场景下变得可管理。从实际效果看我团队里三个 Agent 并行跑一天文件冲突基本归零。2. Worktrunk 核心设计与实现思路2.1 命令设计围绕任务生命周期而非 Git 底层操作设计 Worktrunk 的命令时我给自己定了一个原则所有命令都围绕 Agent 的“工作状态”来命名而不是围绕 Git 术语。因为这个工具的使用者一半是人类开发者一半是 AI Agent。Agent 理解“我在做一个任务”比理解“我需要操作 git worktree”要容易得多。最终的命令集收敛成了这几个命令作用使用时机worktrunk init初始化当前仓库的 Worktrunk 配置接入手头仓库时worktrunk create task为任务创建独立工作区Agent 开始新任务前worktrunk list列出所有工作区及状态查看全局进展时worktrunk switch task切换当前工作目录指示在不同任务间切换时worktrunk done task标记任务完成并合并回主分支Agent 完成任务时worktrunk prune清理已合并的工作区收尾时这里有几个设计细节值得展开说。create是使用频率最高的命令我把它设计成自动从主分支默认main可通过配置改成develop拉取最新代码然后以worktrunk/task为分支名、trunk_task为目录名创建 worktree。每次创建时还会生成一个worktrunk-task.md任务状态文件放在主仓库的.trunk/status/目录下记录任务的创建时间、基线 commit、当前分支、Agent 名称等元数据方便后续人肉 review 时追溯。switch这个命令一开始我犹豫要不要做因为 worktree 本身不需要“切换”——各工作区是同时存在的。但实际用下来Agent 经常需要知道自己现在在哪个工作区以及当前目录对应的任务是什么。switch做的不是切换 worktree而是更新一个.trunk/current链接文件指向当前激活的任务。Agent 可以随时读这个文件来确认自己的上下文避免路径混乱。我把常用子命令设计得尽量短因为 Agent 的终端操作是有 token 成本的。一条长命令和一条短命令对 Agent 的认知负担完全不同。2.2 目录规划与分支约定让路径可读、可预测Worktrunk 的目录策略经过了反复调整。最初我照着很多博客的推荐用../repo-feature-name这样与主仓库平级的目录。用了几天发现一个问题当 worktree 数量超过 5 个以后仓库根目录那一层全是相似目录而且每个目录的 Git 远端都指向同一个 originAgent 在这个体系里很容易迷路。后来我改成了统一放在主仓库内部的.trunk/目录下my-repo/ ├── .trunk/ │ ├── status/ │ │ ├── worktrunk-export-excel.md │ │ └── worktrunk-dashboard-ui.md │ ├── current - trunk_dashboard-ui │ └── worktrees/ │ ├── trunk_export-excel/ │ └── trunk_dashboard-ui/ ├── .git/ └── src/这个结构有三个好处。第一所有 Agent 工作区集中在一个目录下清理和巡检都非常方便。第二.trunk/加入.gitignore不会污染主仓库的提交记录。第三目录路径非常稳定可预测——worktrunk create dashboard-ui之后Agent 的工作目录一定是.trunk/worktrees/trunk_dashboard-ui不需要再问“我的目录在哪”。分支约定也经过思考。我最终采用的是worktrunk/task分支格式而不是直接用任务名。原因很简单Git 分支名里不允许有空格和特殊字符但任务名往往是fix-login-page-500-error这种带连字符的英文短语。所以 create 命令会做一次规范化把任务名转成 kebab-case前面的worktrunk/前缀用来标识这是由 Worktrunk 管理的分支收尾的时候可以批量找出所有待清理的分支。这里有一个容易忽略的细节分支worktrunk/task和 worktree 目录名trunk_task之间并不完全一致。分支用斜杠因为 Git 分支默认使用/组织命名空间目录用下划线因为大多数终端环境下下划线比斜杠更安全不会和路径解析产生歧义。这个一致性是精心设计的——Agent 拿到任务名可以推导出分支名也可以推导出目录名不需要额外查询。2.3 与 AI Agent 工具链的对接方式Worktrunk 本身是一个 CLI但它不只是给人用的更重要的是给 Agent 用的。目前主流的 AI 编程 Agent不管是通过 codex cli、claude code cli 还是其他 harness 方式接入都支持在终端里执行命令也就是 Agent 可以自己运行worktrunk create xxx和cd trunk_xxx。但要让 Agent 流畅地使用光有命令还不够我给 Worktrunk 设计了两个 Agent 友好特性。第一个是worktrunk context [task]命令。它会输出一段结构化的上下文摘要包含当前工作区路径、所在分支、基线 commit、剩余未提交文件列表、以及与主分支的差异统计。Agent 在开始干活前执行一次就能获得当前状态的完整画像。相当于把“人眼查看 Git 状态”的认知过程压缩成了 Agent 可以直接读取的一条信息块。第二个是worktrunk prompt task命令它会生成一段可以直接粘贴到 Agent 系统提示词里的段落。比如你现在的工作目录是 .trunk/worktrees/trunk_export-excel 你的分支是 worktrunk/export-excel 你的任务定义在 .trunk/status/worktrunk-export-excel.md 请在当前工作目录内完成所有操作不要切换到其他目录 完成后运行 worktrunk done export-excel这样设计是因为很多 Agent 在执行的后期会忘了自己的初始上下文尤其在长任务中Agent 的注意力会漂移。有了这样一段持久化在任务文件里的提示语Agent 可以在每一步执行前重新读取保持方向感。对接工具上实际上任何能执行终端命令的 Agent 框架都可以用 Worktrunk不管是本地方案还是远程环境。唯一要注意的是 Agent 的执行环境必须能访问到仓库的.git目录也就是不允许把 Agent 放在容器里挂载了拷贝目录的场景那样 worktree 的共享机制就失效了。3. 实操从安装到跑通多 Agent 并行流程3.1 安装与初始化配置Worktrunk 的安装方式取决于你的环境。如果你是 macOS 用户并且用 Homebrew一条命令就行brew install worktrunkLinux 环境可以用预编译的二进制包放在任意PATH目录下即可。推荐统一放在~/.local/bin/mkdir -p ~/.local/bin curl -L -o ~/.local/bin/worktrunk https://github.com/worktrunk/worktrunk/releases/latest/download/worktrunk-linux-amd64 chmod x ~/.local/bin/worktrunk export PATH$HOME/.local/bin:$PATH装好之后在你的仓库根目录执行初始化cd /path/to/your-repo worktrunk init --base main--base main指定了所有 worktree 的基线分支。我建议如果你团队的默认分支是develop就写--base develop。init 会做三件事检查当前仓库状态是否干净不干净会给出警告但不会强制中断创建.trunk/目录结构在.gitignore中追加.trunk/一行如果之前没有的话。这里有个细节值得注意init 并不会强制要求当前工作目录必须干净。因为在并行场景下主工作区可能本来就有一些不相关的改动。Worktrunk 的策略是创建新 worktree 时以远端基线为起点而不是以本地工作区为起点所以本地工作区脏不脏不影响新 worktree 的创建。但如果你在 init 时发现主分支落后于远端建议先git fetch再 init否则新 worktree 的基线 commit 可能不是最新的。3.2 实战两个 Agent 并行改同一个仓库场景是这样的一个电商后台仓库Agent A 负责做订单导出 ExcelAgent B 负责改用户列表的翻页交互。两个任务都涉及src/目录如果共享工作区必炸无疑。Agent A 开工前先执行worktrunk create export-excel输出大概是Created worktree: .trunk/worktrees/trunk_export-excel Branch: worktrunk/export-excel Base commit: 8c2a1f7 (origin/main) Status: worktrunk-export-excel.md Run cd .trunk/worktrees/trunk_export-excel to start working.Agent A 读取这个输出后进入对应目录开始改代码。与此同时Agent B 执行worktrunk create dashboard-pagination它会创建另一个完全独立的 worktree目录是.trunk/worktrees/trunk_dashboard-pagination分支是worktrunk/dashboard-pagination。从此刻起这两个 Agent 的任何 Git 操作都只在自己对应的 worktree 里生效。我从实际经验中总结的 Agent 工作流模板是这样的# 1. 创建任务工作区 worktrunk create task-name # 2. 进入工作区 cd .trunk/worktrees/trunk_task-name # 3. 读取任务定义 cat .trunk/status/worktrunk-task-name.md # 4. 开始编程完成后提交 git add -A git commit -m feat: complete task-name注意第 4 步Agent 是在自己的 worktree 里 commit所以不会影响其他 Agent也不会影响主工作区。这是并行开发的基石。两个 Agent 都完成后回到主工作区看全局状态worktrunk list输出类似PORT STATUS TASK BRANCH PATH 1 READY export-excel worktrunk/export-excel .trunk/worktrees/trunk_export-excel 2 READY dashboard-pagination worktrunk/dashboard-pagination .trunk/worktrees/trunk_dashboard-paginationPORT是本地 agent 端口的抽象概念表示当前激活哪个 worktree。STATUS有三个值CREATED刚创建、READY有提交且待合并、MERGED已合并回主分支。这个表格是 Agent 和人达成一致的工作状态视图。3.3 Agent 接入与协作细节纯命令行操作已经能跑通但如果你希望 Agent 更“聪明”地使用 Worktrunk建议配合环境变量一起用。我在 Worktrunk 里设计了几组环境变量Agent 框架可以直接注入使用export WORKTRUNK_ACTIVE_TASKexport-excel export WORKTRUNK_WORKTREE_DIR.trunk/worktrees/trunk_export-excel export WORKTRUNK_BASE_BRANCHmain这样 Agent 在每次执行前可以先读$WORKTRUNK_WORKTREE_DIR来确定自己的目录而不是被 prompt 里的绝对路径带偏。对于像 claude code cli 这类工具你甚至可以直接把 worktree 目录作为工作目录启动cd .trunk/worktrees/trunk_export-excel claude code --allowedTools bash(git:*),bash(worktrunk:*)这样 Agent 一启动就在正确的上下文里。不过要特别提醒一点不要让 Agent 在主仓库根目录启动再让它通过cd去到 worktree 目录。虽然功能上没问题但 Agent 的工具调用有时会“迷路”尤其是在多步操作后某一步失败重试时当前目录可能已经变了。最稳妥的做法是启动时就用 worktree 目录作为工作目录不给 Agent 切换目录的机会。3.4 合并与收尾从并行回到串行所有 Agent 都完成后收尾工作要回到主工作区统一做。worktrunk done task会自动完成三步操作先检查该任务分支是否有未提交的变更有则提醒你先提交然后切回主工作区并合并该分支最后把任务状态标记为MERGED。cd /path/to/your-repo worktrunk done export-excel内部其实还是走的git merge但 Worktrunk 会检查两点一是当前主工作区不能有未提交的变更否则先拒绝合并避免把主工作区的脏文件状态搅进去二是合并时原分支是否已经包含主分支的最新提交如果有落后会先 rebase 一次再合并减少冲突概率。全部任务合并完执行一次清理worktrunk prune它会找出所有状态为MERGED的任务删除对应的 worktree 目录和远程分支引用如果该分支已推送。这里的设计比较保守prune默认不会删除未合并的 worktree防止误删。如果你确定某个任务不要了需要显式加--force参数。我建议把收尾做成一条固定流程# 第一步逐个合并任务 for task in export-excel dashboard-pagination; do worktrunk done $task done # 第二步清理已合并工作区 worktrunk prune这个流程的好处是清晰可复盘每一步都有输出日志。如果合并出冲突Worktrunk 会停下来提示你解决不会一股脑把冲突旁路掉。3.5 磁盘与依赖的注意事项有一个细节必须提前说每个 worktree 都是完整的工作目录意味着node_modules、vendor这类依赖目录会各自独立存在。如果你项目的依赖特别大动辄几个 GB开 5 个 Agent 就等于复制 5 份依赖磁盘会很快告急。解决思路有两个。一是利用符号链接把依赖目录指到主仓库ln -s /path/to/your-repo/node_modules .trunk/worktrees/trunk_export-excel/node_modules但这只是软链接主仓库和 worktree 的 node_modules 共用同一份如果 Agent 在 worktree 里安装新依赖会直接改主仓库的 node_modules时间一长可能版本错乱。二是更推荐的方案把依赖目录排除在 Git 工作区之外然后在每个 worktree 里单独安装。Worktrunk 的 create 命令支持--install参数创建完 worktree 后自动执行npm install或pip install -r requirements.txt等安装命令。安装期间其他 Agent 照常工作互不干扰。代价是磁盘占用高但换来的是依赖环境的确定性。这个取舍我认为值得。并行 Agent 场景里最怕的就是“模棱两可”的环境状态与其用软链接换来节约磁盘但引入不确定性不如每个 Agent 一份独立依赖保证每次运行结果都可复现。4. 常见问题与排查技巧实录4.1 分支被另一个 worktree 占用导致切换失败这是 Worktrunk 开发中我遇到的最常见的原生 Git 错误。你执行git checkout main时可能看到fatal: main is already checked out at .trunk/worktrees/trunk_export-excel原因是同一个分支不能同时被两个 worktree 检出。Git 的这个限制是为了防止两个工作目录对同一个分支产生分叉的提交历史。Worktrunk 的排查思路是这样的当你执行worktrunk create export-excel时如果任务名推导出的分支worktrunk/export-excel已经在其他 worktree 检出了create 会报错并告诉你分支被哪个工作区占用。这时候你有两个选择换一个任务名或者先到占用该分支的 worktree 里把工作归档掉再删除它。还有一个隐蔽的场景Agent 在 worktree 里跑测试时创建了子模块或者其他分支引用导致主工作区git branch -d删不掉分支。Worktrunk 的 done 命令里加了强制检查如果删分支失败会提示你用git branch -D --remote清理远端分支引用。4.2 Agent 忘记自己路径导致的提交错乱这个坑不是 Worktrunk 的 Bug而是 Agent 使用方式的问题但很值得说。有些 Agent 在长任务中会误以为自己还在主工作区执行git push、git fetch时操作了错误的远端路径。我排查过的一次具体场景是Agent 在.trunk/worktrees/trunk_export-excel里工作我让它执行了一个git rebase origin/main结果它可能因为执行的worktrunk context命令切换了当前目录导致 rebase 操作在了主工作区。最终主工作区的 HEAD 被 rebase 到了另一个位置Agent B 的 worktree 历史就乱了。解决办法是在 Worktrunk 的命令里强行注入目录校验。context、done、switch这些命令在启动时会检查当前目录是否处于某个 worktree 内如果不是就输出警告并附带可能的工作区列表。Agent 读取到这个警告后会重新回到正确的工作目录再操作。另外一个帮助很大的习惯要求 Agent 在每完成一个里程碑时运行一次pwd git status把这个输出记到任务的日志里。这样即使后面出了问题回溯时也能知道 Agent 到底在哪个目录执行了什么操作。4.3 Git 全局配置和 hooks 对 worktree 造成的影响worktree 创建的目录不在主仓库的父子路径内比如.trunk/worktrees/trunk_xxx确实在主仓库的子目录里但如果是../repo-xxx这种兄弟目录就完全脱离了会导致部分 Git 行为不一致。这里有个反面教训。我一开始用的兄弟目录方案结果发现两个 worktree 分别有自己的一套.gitignore处理逻辑提交时还会各自执行同一组 hooks有一个 lint hook 在其中一个 worktree 里因为找不到 node_modules 直接报错。当时排查了很久才发现是因为 npm 包没在对应的 worktree 里安装而 hook 在提交时按路径找依赖路径不对就失败。Worktrunk 的解决办法是创建 worktree 时默认继承主仓库的core.hooksPath配置并且会在状态文件里记录 hooks 路径。如果你在某个 worktree 里想让 Agent 跳过 hooks比如 Agent 生成的代码还需要后续人工 review不想让 lint 卡住可以手动执行git config core.hooksPath /dev/null但这个操作会破坏整个仓库的 hooks 一致性我用过一次之后就再也没用。更可靠的方式是把 hooks 做成失败可缓存的比如 lint 只在pre-push阶段跑而不是pre-commit这样 Agent 在本地 commit 时可以畅通无阻。4.4 CI 或远程环境无法识别 worktreeWorktrunk 在本地跑得很顺畅但很多团队会把代码推到远端让 CI 去构建。这里有一个天然的不匹配worktree 是存在于工作目录里的实体推到远端仓库后远端只有一个 Git 仓库没有你本地的那几个 worktree 目录和它们对应的.trunk/status/文件。也就是说你在本地用worktrunk done export-excel合并之后功能代码已经合到了main分支并推送CI 会正常构建。但如果你的 CI 里有人想通过worktrunk list来查看哪些任务还没合并完会发现查询不到任何 worktree——因为 CI 从远端克隆的仓库里没有那些本地状态文件。这个问题的解法是把 Worktrunk 的状态信息同步进 Git 引用里。我在设计时增加了一个选项worktrunk init --remote-state它会创建一个名为refs/worktrunk/state的 Git 引用每次 create/done 时更新这个引用推送时通过git push --follow-tags同步到远端。这样 CI 或者团队其他成员在拉代码后可以执行git fetch origin refs/worktrunk/state worktrunk list --from-ref来读取远端的最新任务状态。这个功能是我自己在协作中加的一开始没有后来发现“本地有任务状态、远端看不到”导致同步信息要频繁在聊天里人工播报太麻烦了才下决心把状态变成 Git 对象的一部分。4.5 与其他并行工具的联动Agent 端口与并发控制如果你在跑多个 Agent并且给每个 Agent 分配了固定的本地端口有些 Agent 框架是 client-server 架构需要监听端口Worktrunk 也做了一点配合worktrunk create的--port参数会把端口号写进任务状态文件里Agent 启动时读取这个端口并绑定。这主要是为了解决“多个 Agent 抢同一个端口导致启动失败”的坑。我踩过特别狼狈的一次四个 Agent 同时启动四个全部默认监听 4070 端口结果后启动的三个直接失败界面上全报地址被占用。后来统一按工作区分配端口每个任务状态里记录了固定的端口段。比如任务 1 用 4071任务 2 用 4072以此类推。这个设计对 Agent 框架的运维非常关键强烈建议你在自己的方案里也这样规划。5. 一些想单独说的话Worktrunk 这个项目做下来我自己最大的收获不是代码本身而是意识到“并行 AI Agent 开发的瓶颈往往不在模型能力而在于工程基建”。你可以用最强的模型、最长的上下文但如果仓库管理还是传统的单人单工作区模式Agent 之间的协作天然就是脆弱的、互相干扰的。如果你正在折腾多 Agent 并行开发我建议你从这三个点入手自查第一你的 Agent 是否拥有真正独立的工作目录如果只是靠分支区分没有工作区隔离那并行就是假并行。第二你的 Agent 是否能在任意时刻回答“我在哪个分支、我的基线是什么、我还有哪些未提交的变更”这三个问题如果答案依赖人肉记忆说明你的工程配套还不够。第三你的收尾流程是否可重复、可回溯并行开发最怕的是合并时一团乱麻一定要让每个任务的合并动作有日志、有状态、可回滚。最后再分享一个小技巧无论你用不用 Worktrunk都强烈建议在给 Agent 的提示词里加上“永远先运行pwd和git status再开始操作”这句话。就这一句话能帮你省掉至少一半的 Agent 路径错乱问题。毕竟Agent 离“知道自己在哪里、在干什么”越近离“可靠交付”就越近。
返回列表