Gemini CLI Git Worktree 实战:为每个并行会话分配独立代码副本
Gemini CLI 提供实验性的 Git Worktree 支持,让你在处理多个任务时,为每个 Gemini 会话自动创建独立的 Git worktree 工作目录——每个目录拥有独立文件和分支,但共享同一份仓库历史,从而避免不同会话的改动相互冲突。本文基于官方文档 docs/cli/git-worktrees.md,并结合 packages/core/src/services/worktreeService.ts、packages/cli/src/utils/worktreeSetup.ts 等源码,完整讲解该功能的开启方式、--worktree 命令用法、会话退出策略、恢复流程与手动管理命令。
一、为什么需要 Git Worktree 并行工作
当你在同一仓库上同时推进多个任务(例如一个会话修 bug、另一个会话开发新功能)时,两个会话会读写同一份工作区:A 会话修改的文件可能被 B 会话的模型误读,未提交的改动也会互相"污染"上下文。
Git worktree 的原生能力是创建一个独立的目录(working directory),每个目录有自己的文件状态与分支,而所有 worktree 共享同一个仓库历史(.git 对象库)。Gemini CLI 在此基础上做了自动化封装:启动时自动建 worktree、自动 chdir、记录基准提交(base SHA)、退出时保留现场,把原本需要手敲多条 git worktree 命令的流程压缩成一个 --worktree 标志。
需要注意:这是处于活跃开发中的实验性功能,当前仓库 schemas/settings.schema.json 中该配置项标注为 Requires restart: yes,修改设置后需重启 CLI 才生效。
二、开启 Git Worktrees
Worktrees 默认关闭,需要显式启用。有两种方式:
方式 1:交互式设置
- 在 CLI 中执行
/settings命令; - 搜索 Enable Git Worktrees,将其设置为
true。
方式 2:编辑 settings.json
{
"experimental": {
"worktrees": true
}
}
这一配置在源码中的定义位于 packages/cli/src/config/settingsSchema.ts(第 2234-2243 行):
worktrees: {
type: 'boolean',
label: 'Enable Git Worktrees',
category: 'Experimental',
requiresRestart: true,
default: false,
description: 'Enable automated Git worktree management for parallel work.',
showInDialog: true,
},
可以看到:分类为 Experimental、默认值 false、requiresRestart: true(即 /settings 中该开关标注"需要重启")。showInDialog: true 解释了为什么它会在 /settings 对话框中被搜索到。设置读取逻辑在 packages/cli/src/config/settings.ts 中通过 settings.merged.experimental.worktrees 从用户、项目等多层合并后的配置中取值。
三、使用 --worktree 启动隔离会话
启用后,使用 --worktree(简写 -w)标志创建隔离的 worktree 并在其中启动 Gemini CLI。
3.1 指定名称启动
传入的值会同时成为 worktree 目录名(位于 .gemini/worktrees/ 下)和分支名的组成部分:
gemini --worktree feature-search
3.2 随机名称启动
省略名称时,Gemini 会自动生成一个随机名称(例如 worktree-a1b2c3d4 风格的名称):
gemini --worktree
从源码可以确认命名与落盘的具体规则。packages/core/src/services/worktreeService.ts 中 setup() 在未收到名称时,用 ISO 时间戳 + 4 位随机后缀生成名称(第 33-42 行):
if (!worktreeName) {
const now = new Date();
const timestamp = now
.toISOString()
.replace(/[:.]/g, '-')
.replace('T', '-')
.replace('Z', '');
const randomSuffix = Math.random().toString(36).substring(2, 6);
worktreeName = `${timestamp}-${randomSuffix}`;
}
随后 createWorktree()(第 121-134 行)完成三件关键事:
const worktreePath = getWorktreePath(projectRoot, name); // <projectRoot>/.gemini/worktrees/<name>
const branchName = `worktree-${name}`; // 分支名 = "worktree-" + 名称
await execa('git', ['worktree', 'add', worktreePath, '-b', branchName], {
cwd: projectRoot,
env: getSafeGitEnv(),
});
即:目录固定位于 <项目根>/.gemini/worktrees/<名称>,分支名固定为 worktree-<名称>。这与后文手动清理命令中 git branch -D worktree-feature-search 的分支名来源一致。创建前还会先用 git rev-parse HEAD 抓取基准提交 baseSha,返回 WorktreeInfo { name, path, baseSha },供后续判断 worktree 是否产生过改动。
项目根的解析由 getProjectRootForWorktree()(第 96-115 行)完成:执行 git rev-parse --git-common-dir,取 .git 目录的父目录作为项目根;若解析失败则退化为当前工作目录。
3.2 启动流程中的防嵌套保护
CLI 入口 packages/cli/src/gemini.tsx(第 380-388 行)在启动早期就调用 setupWorktree(),并用启动性能分析器打点 setup_worktree:
// If a worktree is requested and enabled, set it up early.
let worktreeInfo: WorktreeInfo | undefined;
...
worktreeInfo = await setupWorktree(requestedWorktree || undefined);
packages/cli/src/utils/worktreeSetup.ts 中有一个重要的防重入设计:
export async function setupWorktree(
worktreeName: string | undefined,
): Promise<WorktreeInfo | undefined> {
if (process.env['GEMINI_CLI_WORKTREE_HANDLED'] === '1') {
return undefined;
}
...
process.chdir(worktreeInfo.path);
process.env['GEMINI_CLI_WORKTREE_HANDLED'] = '1';
...
}
即:worktree 创建成功后立即 process.chdir() 切入新目录,并设置环境变量 GEMINI_CLI_WORKTREE_HANDLED=1。该守卫确保当 CLI 因内存分配等目的重新拉起自身进程时,不会在 worktree 里再嵌套创建一层 worktree。对应测试见 packages/cli/src/utils/worktreeSetup.test.ts。
此外,参数校验位于 packages/cli/src/config/config.ts(第 269-270 行):如果传了 --worktree 但 experimental.worktrees 未启用,会直接报错:
The --worktree flag is only available when experimental.worktrees is enabled in your settings.
-w 选项的官方描述为:"Start Gemini in a new git worktree. If no name is provided, one is generated automatically."(见 config.ts 第 313-318 行)。
注意(继承自官方文档):每个新 worktree 都是一个全新的代码副本,需要按项目规范初始化开发环境——例如运行依赖安装(
npm install、yarn)、配置虚拟环境,或执行项目标准构建流程。
四、退出 worktree 会话:现场完整保留
当通过 /quit 或 Ctrl+C 退出 worktree 会话时,Gemini 的退出策略是优先保证快速与安全:
- 保留 worktree 不删除:包括所有未提交改动(修改过的文件、已暂存改动、未跟踪文件)以及你在新分支上产生的任何提交;
- 不自动删除分支:worktree 和分支都由你自行清理;
- 打印退出指引:退出时界面会显示如何恢复工作、以及如何手动删除 worktree 的指令。
这条退出提示的实现位于 packages/cli/src/ui/components/SessionSummaryDisplay.tsx(第 39-43 行):当配置中存在 worktree 信息时,底部提示会替换为:
footer =
`To resume work in this worktree: cd ${escapeShellArg(worktreeSettings.path, shell)} && gemini --resume ${footerSessionId}\n` +
`To remove manually: git worktree remove ${escapeShellArg(worktreeSettings.path, shell)}`;
即输出"恢复工作"与"手动删除"两条可直接复制的命令,且路径、会话 ID 会按当前 shell(Windows 下 PowerShell、其他平台 bash)做转义。测试用例 packages/cli/src/ui/components/SessionSummaryDisplay.test.tsx(第 199-218 行)验证了这两条提示确实渲染在退出页面上。
源码中已有的自动清理能力
值得说明的是,核心层已经实现了改动检测与条件清理逻辑。packages/core/src/services/worktreeService.ts 中:
hasWorktreeChanges(dirPath, baseSha)(第 151-184 行):先用git status --porcelain检查未提交改动,再比较当前HEAD是否偏离基准 SHA;若任何 git 命令失败则保守地视为有改动("assume the worktree is dirty to be safe"),防止误删用户工作;maybeCleanup(info)(第 62-84 行):当 worktree 无任何改动时,自动执行git worktree remove --force并git branch -D删除分支,有改动则保留并记录调试日志。
从源码结构看,maybeCleanup 的调用方目前主要见于 packages/core/src/services/worktreeService.test.ts 的单元测试(第 271-304 行);在 CLI 退出路径上,当前版本遵循文档所述"不自动删除"的策略。也就是说,条件自动清理能力已在核心层具备并有测试覆盖,属于该实验性功能的演进方向。
五、恢复 worktree 中的会话
worktree 被完整保留后,恢复工作只需进入对应目录并用 --resume 加上会话 ID 启动:
cd .gemini/worktrees/feature-search
gemini --resume <session_id>
会话 ID 即退出提示中 gemini --resume 后面的参数(与退出页打印的完全一致)。更多会话管理细节可参考 docs/cli/session-management.md。
六、手动管理 Git Worktrees
如果你希望完全控制 worktree 的位置与分支命名,或需要清理被保留下来的 worktree,可以直接使用 Git 命令:
清理被保留的 worktree(分支名遵循 worktree-<名称> 约定):
git worktree remove .gemini/worktrees/feature-search --force
git branch -D worktree-feature-search
手动创建 worktree(放到任意目录、使用任意分支名,然后在该目录启动 gemini):
git worktree add ../project-feature-search -b feature-search
cd ../project-feature-search && gemini
手动创建时的一个细节:CLI 侧的 WorktreeService 内部还带有 isGeminiWorktree()(worktreeService.ts 第 136-149 行),通过 realpath 比对判断某目录是否位于 <项目根>/.gemini/worktrees/ 之下——只有 Gemini 托管的 worktree 才走其自动管理逻辑,你手动放在别处的 worktree 完全不受干预。另外,所有 git 子进程都通过 getSafeGitEnv()(packages/core/src/utils/gitUtils.ts)构造安全的环境变量执行,避免宿主机 git 配置异常影响 worktree 操作。
七、小结与相关资源
- 开启:
/settings中设置 Enable Git Worktrees =true,或settings.json写入{"experimental": {"worktrees": true}}(Experimental 分类,默认关闭,修改后需重启); - 启动:
gemini --worktree <名称>或gemini --worktree(自动生成随机名称),目录落在.gemini/worktrees/<名称>,分支为worktree-<名称>; - 退出:worktree 与分支完整保留,界面打印
cd ... && gemini --resume <id>与git worktree remove ...两条后续指令; - 清理:
git worktree remove <路径> --force+git branch -D worktree-<名称>。
延伸阅读与代码入口:
| 内容 | 路径 |
|---|---|
| 官方文档 | docs/cli/git-worktrees.md |
| Worktree 核心服务(创建/改动检测/清理) | packages/core/src/services/worktreeService.ts |
| 核心服务单元测试 | packages/core/src/services/worktreeService.test.ts |
| CLI 启动期 worktree 装配 | packages/cli/src/utils/worktreeSetup.ts |
| 配置项定义 | packages/cli/src/config/settingsSchema.ts |
| 命令行参数解析与校验 | packages/cli/src/config/config.ts |
| 退出提示(恢复/清理指令) | packages/cli/src/ui/components/SessionSummaryDisplay.tsx |
| 设置参考 | docs/cli/settings.md |
| 会话管理 | docs/cli/session-management.md |
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 StartedRust0622
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