1. はじめに

GitHub Copilot app で new working tree を選ぶと、メインチェックアウトにはある .env が新しいセッションに見当たらないことがあります。原因は、.env が通常 .gitignore の対象であり、git worktree のチェックアウトに含まれないためです。

アプリの基本的な使い方は別記事「GitHub Copilot app で日常タスクを自動化する — Copilot automations 入門」で扱いました。本記事はその続きとして、セッションを増やしても .env を毎回コピーしなくて済む状態 をどう作るかに絞って解説します。

この記事の目的は次の 2 つです。

  1. なぜ引き継がれないのか を git の仕様レベルで説明する
  2. 実測できた .worktreeinclude と symlink 共有を、注意点を含めて再現できるようにする

本記事の情報の性質について: .worktreeinclude は、2026-08-02 時点で公式ドキュメントにない未文書化の実装です。挙動は Copilot app 1.1.2 の実測に基づき、公式情報とは区別して記載します。

2. なぜ new working tree に .env が引き継がれないのか

2.1 new working tree を選んだセッションの仕組み(公式)

公式ドキュメントでは、並列セッションごとに専用の git worktree とブランチを使うと説明されています[^app-concept]。本記事の対象は、実行場所に new working tree を選んだローカルセッションです[^app-sessions]。

2.2 ignored ファイルはチェックアウトされない

git worktree はコミットに含まれるファイルを展開します。.env.example は tracked なら現れますが、.gitignore された .env はチェックアウトされません。

Git worktree では Git 管理下のファイルだけが展開され、gitignore 対象の .env はコピーされない仕組み

2.3 git に「untracked をコピー」するオプションは無い

git worktree add には、untracked / ignored ファイルをコピーするオプションがありません[^git-worktree]。そこで Copilot app 側の .worktreeinclude を使います。

3. 2 つの共有方法

方法挙動向くケース
.worktreeinclude(§4)作成時に通常ファイルとしてコピーワークツリーごとに値を独立させたい
.worktreeinclude × 共有元 symlink(§5)全ワークツリーで同じ実体を参照変更を既存ワークツリーへ反映したい

どちらもエージェントから値を読めるため、共有するのは開発用の認証情報に限定します。本番相当の値にはシークレットマネージャーなどの実行時注入を使ってください。

4. 最短解: .worktreeinclude でコピーさせる

4.1 .worktreeinclude とは(重要な但し書きつき)

Copilot app 1.1.2 では、新しいワークツリーを作るときに、指定したファイルをメインチェックアウトからコピーする挙動を実測できました。設定に使ったのは、リポジトリ直下の .worktreeinclude ファイルです。

重要: 2026-08-02 時点の公式カスタマイズ文書には .worktreeinclude の記載がありません[^customize-docs]。設定画面でのサポート表示に触れたコミュニティ投稿はありますが、公式回答ではありません[^issue-comment]。以下はすべて Copilot app 1.1.2 の実測結果であり、利用中のバージョンで再確認が必要です。

4.2 書き方

リポジトリのルート(メインチェックアウト直下)に .worktreeinclude を作ります。実測した literal・ディレクトリ・glob は .gitignore に似たパターンで動きました。

gitignore
# <リポジトリルート>/.worktreeinclude
# 新しいワークツリーに持っていきたい、gitignore 済みのファイルを列挙する

.env
.env.local

# ディレクトリ指定も可(再帰的にコピーされる)
secrets/

# glob も使える
certs/*.pem

このファイル自体はリポジトリにコミットできます。 中身がパターンだけなら秘密は含まれません。コミットするとチームで同じパターンを共有できますが、各メンバーのメインチェックアウトにコピー元ファイルがあり、対応する Copilot app バージョンを使っていることが前提です。

あとは新しいセッションを作るだけで、ファイルが自動的にコピーされます。実機のログでも確認できます(実測)。

text
github_app::git::worktree_include: copied include
    src=/Users/you/programs/myapp/.env
    dst=/Users/you/programs/copilot-worktrees/myapp/you-session-c/.env
console
$ ls -la ~/programs/copilot-worktrees/myapp/you-session-c/
-rw-r--r--  1 you  staff   28  8  2 21:08 .env          ← コピーされた
-rw-r--r--  1 you  staff   19  8  2 21:40 .env.example
-rw-r--r--  1 you  staff   96  8  2 21:40 .git
-rw-r--r--  1 you  staff   82  8  2 21:40 .worktreeinclude
drwxr-xr-x  3 you  staff   96  8  2 21:40 secrets       ← ディレクトリもコピーされた

4.3 実測した挙動

検証用プロジェクトで各パターンを試した結果です。すべて筆者の実測であり、公式仕様ではありません。

項目実測結果確認方法
置き場所メインチェックアウト直下の .worktreeincludeログの path=<repo>/.worktreeinclude
構文.gitignore に似たパターン形式literal・secrets/certs/*.pem が期待どおり動作
動作コピー(ファイル単位)ログの動詞が copied include
ディレクトリ指定node_modules/ は配下を再帰的にコピーnode_modules/pkg/index.js が個別にコピーされた
symlinkリンクのまま複製される(リンク先は解決されない)コピー後も lrwxr-xr-x ... -> /tmp/external-shared.env
既存ファイル検証した tracked の通常ファイルは上書きされない§4-4 の 1 ケースを参照
ファイル種別通常ファイルと symlink を確認。それ以外は未確認
git への影響.gitignore 対象なら git status はクリーンなままgit status --porcelain が空

! による否定パターンなど、.gitignore の全構文との互換性は未検証です。同じ構文だと仮定せず、利用するパターンごとに新しいテスト用ワークツリーで確認してください。

4.4 検証した既存ファイルは上書きされなかった

.worktreeinclude に書いたパターンが、git 管理下のファイルを壊さないか」は重要な確認事項です。テストしました。

  1. .env.example をコミットする(内容: COMMITTED_VERSION=yes
  2. メインチェックアウト側だけ書き換える(内容: MAIN_LOCAL_EDIT=yes、未コミット)
  3. .worktreeinclude.env.example を追加して新セッションを作る

結果はこうなりました。

console
$ cat <新しいワークツリー>/.env.example
API_KEY=replace-me
COMMITTED_VERSION=yes          ← コミット済みの内容のまま。上書きされていない

$ git status --porcelain
                               ← クリーン

この検証では、tracked の通常ファイルに対して git のチェックアウト結果が優先されました。これは 1 ケースの実測結果であり、競合条件や他のファイル種別まで含む一般的な上書き保証ではありません。

4.5 弱点 — コピーなので更新が伝播しない

.worktreeincludeコピー です。ここから 2 つの弱点が生まれます。

  1. キーをローテーションしても、既存のワークツリーには反映されない。 メインチェックアウトの .env を更新しても、作成済みのワークツリーは古い値を持ち続けます。
  2. 平文の秘密がワークツリーの数だけ増える。 10 セッションあれば .env が 10 個。削除漏れやバックアップへの混入リスクが増えます。

この 2 つを同時に解決するのが次章です。

5.1 考え方

.worktreeincludesymlink をリンクのまま複製する(§4-3)という性質を利用します。

  1. .env実体をリポジトリの外に置く — 例: ~/.config/myapp/.env
  2. メインチェックアウトの .env は、その共有元を指す symlink にする
  3. .worktreeinclude.env と書く

すると新しいワークツリーには「共有元を指す symlink」が複製され、全ワークツリーが同一の実体を参照します。更新の反映漏れと平文ファイルの複製を減らせる一方、誤更新の影響も全ワークツリーへ広がります。

worktreeinclude が symlink を複製し、すべてのワークツリーが一つの共有 .env を参照する構成

5.2 セットアップ手順

bash
#!/usr/bin/env bash
set -euo pipefail

repo_root="$HOME/programs/myapp"
repo_env="$repo_root/.env"
shared_dir="$HOME/.config/myapp"
shared_env="$shared_dir/.env"

# 1. 共有元ディレクトリを作る
mkdir -p "$shared_dir"
chmod 700 "$shared_dir"

# 2. 上書きやリンクの取り違えを避けて .env の実体を移す
if [[ ! -f "$repo_env" || -L "$repo_env" ]]; then
  echo "通常ファイルの $repo_env が必要です" >&2
  exit 1
fi
if [[ -e "$shared_env" || -L "$shared_env" ]]; then
  echo "$shared_env は既に存在します。内容を確認してください" >&2
  exit 1
fi
mv "$repo_env" "$shared_env"

# 3. 偶発的な上書きへの抑止として読み取り専用にする
chmod 400 "$shared_env"

# 4. メインチェックアウトには symlink を置く
ln -s "$shared_env" "$repo_env"

# 5. .worktreeinclude に重複なく登録してコミット
cd "$repo_root"
grep -qxF '.env' .worktreeinclude 2>/dev/null || printf '.env\n' >> .worktreeinclude
git add -- .worktreeinclude
if ! git diff --cached --quiet -- .worktreeinclude; then
  git commit --only -m "chore: share .env across worktrees" -- .worktreeinclude
fi

chmod 400 は、同じ OS ユーザーによる偶発的な > リダイレクトを止めるためのガードです。同じユーザーは権限を戻せるため、秘密へのアクセスを分離するセキュリティ境界にはなりません。

.gitignore.env が入っていることも確認しておきます。

console
$ git check-ignore -v .env
.gitignore:1:.env	.env

5.3 動作確認(実測)

新しいセッションを作ると、ワークツリーには symlink が複製されています。

console
$ ls -l <新しいワークツリー>/.env
lrwxr-xr-x  1 you  staff  47  8  2 21:41 .env -> /Users/you/.config/myapp/.env

$ node --env-file=.env -e 'console.log("API_KEY =", process.env.API_KEY)'
API_KEY = vault-managed-key

共有元を更新すると、既存のワークツリーにも即座に反映されます

console
$ chmod 600 ~/.config/myapp/.env
$ printf 'API_KEY=rotated-2026-08\n' > ~/.config/myapp/.env
$ chmod 400 ~/.config/myapp/.env

$ cd <新しいワークツリー>
$ node --env-file=.env -e 'console.log("API_KEY =", process.env.API_KEY)'
API_KEY = rotated-2026-08        ← 即反映

$ git status --porcelain
                                 ← クリーンなまま

キーをローテーションしたとき、10 個のワークツリーを回って直す必要がありません。一方、誤った値も同時に反映されるため、更新前のバックアップと更新後の動作確認をセットで行ってください。

6. 注意点

§5 の構成では、ワークツリー側の .env へ書き込むと共有元が変わり、全ワークツリーへ影響します。

console
$ printf 'API_KEY=OVERWRITTEN\n' > .env
$ cat ~/.config/myapp/.env
API_KEY=OVERWRITTEN

chmod 400 は偶発的な上書きを抑止しますが、同じ OS ユーザーは権限を戻せます。セキュリティ境界としては扱わないでください。ワークツリー固有の値が必要なら、symlink を削除して通常ファイルへ置き換えます。

6.2 共有元を移動するとリンクが切れる

共有元を移動・削除すると、すべての .env が dangling symlink になります。アプリが「ファイルがない」と報告したら、ls -l .env でリンク先を確認してください。

6.3 エージェントから値を読める

コピーでも symlink でも、.env はエージェントから参照できます。共有するのは開発用の値に限定し、次を併用します。

  1. git check-ignore -v .env.gitignore の対象になっていることを確認する
  2. GitHub の push protectionsecret scanning を有効にする
  3. 本番相当の値はシークレットマネージャーなどから実行時に注入する

6.4 アプリ更新後に再検証する

.worktreeinclude は未文書化機能です。アプリ更新後は新しいセッションを 1 つ作り、ls -l .envgit status --porcelain を確認してください。機能が変わった場合に備え、README には手動セットアップ手順も残します。

7. 導入チェックリスト

  • .env.gitignore の対象であることを git check-ignore -v .env で確認する
  • リポジトリ直下の .worktreeinclude.env を追加する
  • 新しいセッションで ls -l .envgit status --porcelain を確認する
  • 即時反映が必要な場合だけ共有元 symlink を使う
  • 共有する値を開発用に限定する
  • アプリ更新後に新しいセッションで再検証する

8. まとめ

  • new working tree には ignored の .env が通常のチェックアウトでは引き継がれません。
  • Copilot app 1.1.2 では、.worktreeinclude に指定したファイル・ディレクトリ・glob のコピーを実測できました。
  • symlink を指定すると共有元の変更を既存ワークツリーへ反映できますが、誤更新も全体へ波及します。
  • .worktreeinclude は未文書化機能です。開発用の値に限定し、アプリ更新後に挙動を確認してください。

9. 参考情報

[^app-concept]: About the GitHub Copilot app — GitHub Docs(確認日: 2026-08-02)

[^app-sessions]: Working with agent sessions in the GitHub Copilot app — GitHub Docs(確認日: 2026-08-02)

[^git-worktree]: git-worktree — Git Documentation(確認日: 2026-08-02)

[^customize-docs]: Customizing the GitHub Copilot app — GitHub Docs(確認日: 2026-08-02)

[^issue-comment]: Feature request: Built-in git worktree lifecycle management — GitHub community comment(確認日: 2026-08-02)