# 并行 Vibe Coding 的密钥管理：一个 .envrc 搞定所有 Worktree

- **HTML:** <https://blog.asuk.app/zh/p/direnv-worktree-secrets>
- **Language:** `zh`
- **Author:** Asuka
- **Published:** `2026-03-07T00:00:00.000Z`
- **Updated:** `2026-10-13T10:42:39.000Z`
- **Tags:** Claude, Git, DevOps, Workflow

> 使用 direnv 在 Git Worktree 并行开发场景下自动加载密钥，并对比 Claude Code 的 .worktreeinclude 方案，减少每次手动复制 .env 文件的麻烦。

## Content

用 Claude Code 等 Vibe Coding 工具做开发时，经常需要同时开多个 Agent 并行工作。最常见的做法是通过 Git Worktree 为每个 Agent 创建独立的工作目录——每个 worktree 有自己的文件和分支，互不干扰。

问题在于：每个新创建的 worktree 都是一个「干净」的工作目录，项目运行所需的密钥文件（API keys、OAuth tokens、各种 credentials）通常都不存在。于是每次创建 worktree 之后，都得手动把 `.env`、`.env.local` 或其他密钥文件复制过去。手动维护这些密钥会严重阻塞工作流程，也容易出错。

目前有两条比较实用的路线：

1. 用 **direnv** 在 worktree 的公共父目录自动加载环境变量。
2. 用 Claude Code 官方支持的 **`.worktreeinclude`** 自动复制 gitignored 文件。

这篇文章重点介绍 direnv 方案，同时解释它和 `.worktreeinclude` 的取舍。


## direnv 如何工作

[direnv](https://direnv.net/) 是一个 shell 扩展，用 Go 编写，支持 bash、zsh、fish、nushell、PowerShell 等多种 shell。它的工作方式很简单：

1. 在每次 shell prompt 刷新前，direnv 检查当前目录及 **父目录** 中是否存在 `.envrc` 文件。
2. 如果存在且已授权，就在一个 bash 子进程中执行 `.envrc`，把导出的环境变量注入当前 shell。
3. 离开该目录时，自动卸载这些环境变量。

「父目录继承」这个特性正好适用于 worktree 场景：只要在 worktree 的公共父目录放一个 `.envrc`，所有子目录中的 worktree 都能自动获取到密钥配置。

**安装和配置**：

```bash
# macOS
brew install direnv

# 在 ~/.zshrc 末尾添加 hook（zsh 为例）
eval "$(direnv hook zsh)"
```

安装完成后重启 shell 即可。direnv 有一个安全机制：新的或修改过的 `.envrc` 文件需要执行 `direnv allow` 才能生效，防止恶意目录注入环境变量。


## 路径一：VS Code GitLens Worktree

使用 VS Code 的 [GitLens](https://www.gitkraken.com/gitlens) 插件时，通过 Create Worktree 命令可以从当前仓库创建 worktree。假设当前仓库目录是 `foo`，新创建的分支是 `feature/bar`，GitLens 通常会将 worktree 放在与 `foo` 同级的 `foo.worktree/feature-bar/` 下（分支名中的 `/` 会被替换成 `-`）。

目录结构如下：

```text
foo/                          # 主仓库
foo.worktree/                 # GitLens worktree 根目录
├── .envrc                    # ← direnv 配置，所有 worktree 自动继承
├── feature-bar/              # feature/bar 分支的 worktree
├── feature-baz/              # feature/baz 分支的 worktree
└── bugfix-123/               # bugfix/123 分支的 worktree
```

只需要在 `foo.worktree/` 目录下创建一个 `.envrc` 文件：

```bash
# foo.worktree/.envrc
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
export DATABASE_URL="postgres://..."
```

然后授权一次：

```bash
cd foo.worktree
direnv allow
```

之后无论创建多少个 worktree，进入任何一个子目录时 direnv 都会自动加载这些环境变量。不需要在每个 worktree 里再复制 `.env` 文件。


## 路径二：Claude Code 的 `--worktree` 参数

[Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) 提供了内置 worktree 支持。通过 `--worktree`（或 `-w`）参数可以直接创建一个隔离的 Git worktree 并在其中启动 Claude：

```bash
# 指定名称创建 worktree
claude --worktree feature-auth

# 简写形式
claude -w feature-auth

# 不指定名称，自动生成随机名（如 bright-running-fox）
claude --worktree
```

默认情况下，worktree 会创建在 `<repo>/.claude/worktrees/<name>/` 下，分支命名为 `worktree-<name>`。Claude Code 官方文档建议把 `.claude/worktrees/` 加入 `.gitignore`，避免 worktree 内容作为主仓库的 untracked files 出现。

同样的思路，可以在 `.claude/worktrees/` 目录下放一个 `.envrc`：

```text
my-project/
├── .claude/
│   └── worktrees/
│       ├── .envrc             # ← direnv 配置
│       ├── feature-auth/      # claude --worktree feature-auth 创建
│       ├── bugfix-login/      # claude --worktree bugfix-login 创建
│       └── bright-running-fox/# claude --worktree 自动生成
├── src/
└── ...
```

```bash
cd .claude/worktrees
cat > .envrc << 'EOF'
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
EOF
direnv allow
```

之后所有通过 `claude --worktree` 创建的 worktree 都会自动继承这些环境变量。

Claude Code 的 subagent 也支持 worktree 隔离。可以在对话里要求 Claude “use worktrees for your agents”，也可以在自定义 subagent 的 frontmatter 中设置：

```yaml
isolation: worktree
```

这样 subagent 会在独立 worktree 中工作。只要这些 worktree 仍然位于 `.claude/worktrees/` 下，它们也能享受到父目录 `.envrc` 的自动加载。


## 官方替代方案：`.worktreeinclude`

Claude Code 现在也提供了更直接的方式：在项目根目录创建 `.worktreeinclude` 文件，让 Claude 创建 worktree 时自动复制指定的 gitignored 文件。

例如：

```text
# .worktreeinclude
.env
.env.local
config/secrets.json
```

官方设计里，`.worktreeinclude` 使用类似 `.gitignore` 的语法；只有同时满足下面两个条件的文件才会被复制：

1. 匹配 `.worktreeinclude` 中的规则。
2. 本身是 gitignored 文件。

这意味着 tracked 文件不会被意外复制，主要目标就是解决 `.env`、`.env.local`、本地 secrets config 这类文件在新 worktree 中缺失的问题。


## direnv 和 `.worktreeinclude` 怎么选

两种方案解决的是相似问题，但适用场景不完全一样。


### 适合用 direnv 的情况

- 你不想在每个 worktree 中生成任何密钥文件。
- 你希望所有 worktree 共享同一组本地环境变量。
- 你的工具链主要从 shell 环境变量读取密钥。
- 你希望在 GitLens、自建 worktree、Claude Code worktree 等多种路径下复用同一套机制。


### 适合用 `.worktreeinclude` 的情况

- 你的项目必须读取 `.env` 或 `.env.local` 文件。
- 你希望 worktree 创建后就像一个完整项目副本。
- 你只关心 Claude Code 创建的 worktree。
- 你愿意在每个 worktree 中保留一份本地密钥文件副本。


### 可以混合使用吗？

可以，但要小心重复和冲突。

一种比较稳妥的做法是：

- 通用的 API key、模型 key 放在父目录 `.envrc` 中。
- 项目确实依赖的 `.env.local`、本地配置文件用 `.worktreeinclude` 复制。
- 避免同一个变量既在 `.envrc` 里定义，又在 `.env.local` 里定义，除非你明确知道加载顺序。


## 关于 IDE 和非交互环境

direnv 的自动加载依赖 shell hook。也就是说，它最稳定的使用场景是：你在终端里 `cd` 到 worktree，然后从这个终端启动开发命令、测试命令或 Claude Code。

如果你直接从 IDE、GUI App、后台任务或非交互脚本启动进程，它们未必会自动继承 direnv 注入的变量。此时可以考虑：

- 使用 IDE 的 direnv 插件或集成。
- 从已经加载 direnv 的终端启动 IDE。
- 在脚本里显式使用 `direnv exec <dir> <command>`。
- 对 Claude Code worktree 使用 `.worktreeinclude` 复制必要的 `.env` 文件。


## 关于安全性

需要注意的是：direnv 加载的环境变量会直接出现在 shell 环境中。Agent 执行 `env` 或 `printenv` 就能看到所有密钥的值。这个方案 **并不能阻止 Agent 访问密钥**。

`.worktreeinclude` 也一样，它只是自动复制密钥文件，并不提供运行时隔离。Agent 如果有读取文件权限，仍然可以读取这些文件。

因此，这两种方案真正解决的问题是：

- **减少重复操作**：不需要每次创建 worktree 后手动复制密钥文件。
- **减少误提交风险**：密钥文件仍然保持 gitignored；direnv 方案甚至可以不在每个 worktree 中生成 `.env` 文件。
- **降低配置漂移**：多个并行 worktree 更容易使用同一组开发密钥。
- **保留基本授权审查**：direnv 的 `.envrc` 必须通过 `direnv allow` 明确授权才会生效。如果文件内容被修改，需要重新授权。

如果需要更严格的密钥隔离，应该考虑 vault、1Password CLI、AWS/GCP/Azure secret manager、短期 token、CI/CD 注入、容器隔离或最小权限账号，而不是依赖本地环境变量或复制 `.env` 文件。

对于日常的 Vibe Coding 并行开发场景，direnv 在便利性和安全性之间取得了不错的平衡；而 `.worktreeinclude` 则是 Claude Code 官方提供的、更直接的“复制本地配置文件”方案。


## `.gitignore` 配置

使用 Claude Code 的 `--worktree` 时，建议在 `.gitignore` 中添加：

```gitignore
.claude/worktrees/
```

这样 worktree 的内容不会出现在主仓库的 untracked files 中。`.envrc` 文件如果放在 `.claude/worktrees/` 下，也会被一并忽略，不用担心被提交。

对于 GitLens 的方式，`foo.worktree/` 目录通常在主仓库外面，天然不会被 Git 追踪。不过如果你自定义了 worktree 目录位置，仍然建议检查一下 `git status`，确认密钥文件或 worktree 目录没有出现在待提交列表里。


## 推荐配置

如果你主要使用 Claude Code，并且项目依赖 `.env.local`，最简单的配置是：

```text
# .worktreeinclude
.env.local
```

如果你同时使用 Claude Code、GitLens 和手动 `git worktree add`，并且密钥主要通过环境变量读取，更通用的配置是：

```bash
# 公共 worktree 父目录下的 .envrc
export ANTHROPIC_API_KEY="sk-ant-..."
export OPENAI_API_KEY="sk-..."
```

然后执行：

```bash
direnv allow
```

如果两者都需要，就把不敏感或项目必须读取的本地配置交给 `.worktreeinclude`，把跨项目通用的开发密钥交给 direnv。重点不是追求“绝对安全”，而是减少重复复制、降低误提交概率，并让多个 Agent 并行工作时的环境足够一致。


## 参考

- [direnv 官方文档](https://direnv.net/)
- [Git worktree 官方文档](https://git-scm.com/docs/git-worktree)
- [Claude Code Worktrees 文档](https://code.claude.com/docs/en/worktrees)
