メインコンテンツへスキップ

GitとGitHub CLIの複数アカウントを、cdするだけで自動切り替えする

GitとGitHub CLIの複数アカウントを、cdするだけで自動切り替えするのアイキャッチ画像
目次

TL;DR

2026年1月 更新: 層3のghコマンド切り替え方式を改善しました。以前のchpwdフック + gh auth switch方式から、関数ラッパー + GH_TOKEN環境変数方式に変更しています。複数ターミナルウィンドウでの並行作業に対応しました。

背景・課題

解決したかった問題

「仕事用と個人用のGitHubアカウントを使い分けたい」

これは多くの開発者が直面する課題です。手動で切り替えることもできますが、以下の問題がありました。

理想の状態

「ディレクトリを移動するだけで、すべてが自動で切り替わる」

具体的には、~/work/配下に移動したら仕事用、それ以外は個人用として、以下がすべて自動で切り替わる状態を目指しました。

検討した選択肢

選択肢A: 手動で都度設定

各リポジトリで git config user.email を手動設定する方法です。

メリット:

デメリット:

選択肢B: direnv + GH_TOKEN

direnvを使って、ディレクトリごとに環境変数を設定する方法です。

# ~/work/.envrc
export GH_TOKEN="ghp_xxxx"
export GIT_AUTHOR_EMAIL="work@example.com"

メリット:

デメリット:

選択肢C: includeIf + insteadOf + gh関数ラッパー(採用)

Gitの標準機能とシェル関数を組み合わせる方法です。

メリット:

デメリット:

比較表

観点手動設定direnvincludeIf+α(採用)
初期設定の手間なし
日常の手間なし
追加ツール不要direnv不要
セキュリティ-トークンをファイルに保存OSキーチェーン
設定忘れのリスクなし
複数ウィンドウでの並行作業-対応対応

最終判断

採用: includeIf + insteadOf + gh関数ラッパー

決め手となった理由:

  1. 追加ツール不要: GitとZshの標準機能だけで実現できる
  2. 設定忘れがない: ディレクトリ構造に基づいて自動で判定される
  3. セキュリティ: gh CLIのトークンはOSのキーチェーンに保存される
  4. 複数ウィンドウ対応: 環境変数でプロセスごとに認証するため、他のターミナルに影響しない

受け入れたトレードオフ:

なぜ「3層」が必要なのか

ここからが本題です。GitとGitHubのアカウント切り替えには、3つの異なる設定が必要です。

┌─────────────────────────────────────────────────────┐
│                   あなたのPC                        │
├─────────────────────────────────────────────────────┤
│                                                     │
│  [層1] Gitのuser設定                                │
│    → コミットに記録される名前・メールアドレス       │
│    → .gitconfig の includeIf で切り替え            │
│                                                     │
│  [層2] SSHキー                                      │
│    → GitHubへpush/pullするときの認証               │
│    → SSH Hostエイリアス + insteadOf で切り替え     │
│                                                     │
│  [層3] gh CLIのアカウント                           │
│    → gh pr create などGitHub操作時のアカウント      │
│    → gh関数ラッパー + GH_TOKEN で切り替え          │
│                                                     │
└─────────────────────────────────────────────────────┘


              ┌─────────────────────┐
              │      GitHub         │
              │  (個人 or 仕事用)   │
              └─────────────────────┘

なぜ別々に設定が必要なのか

それぞれが異なるタイミングで使われるからです。

いつ使われるか何を識別するか
層1git commitコミットの作者(Author)
層2git push/pullGitHubへの接続認証
層3gh pr createGitHub APIの操作者

例えば、層1だけ設定しても、push時に間違ったSSHキーが使われてしまいます。3層すべてを正しく設定して初めて、完全な切り替えが実現します。

各層の設定方法

以下、~/work/配下を仕事用、それ以外を個人用として設定する例を示します。

層1: includeIfによるuser設定の自動切り替え

includeIfは、条件に応じて別の設定ファイルを読み込むGitの機能です。

~/.gitconfig(メインの設定ファイル)

# デフォルト(個人用)の設定
[user]
    name = Your Personal Name
    email = personal@example.com

# ~/work/ 配下では仕事用設定を追加で読み込む
[includeIf "gitdir:~/work/"]
    path = ~/.gitconfig-work

~/.gitconfig-work(仕事用の設定ファイル)

[user]
    name = Your Work Name
    email = work@company.com

解説

重要なポイント:

動作確認

# 個人用ディレクトリで確認
cd ~/personal/some-repo
git config user.email
# → personal@example.com

# 仕事用ディレクトリで確認
cd ~/work/some-project
git config user.email
# → work@company.com

設定が正しく読み込まれているかは、以下のコマンドで詳しく確認できます。

git config --list --show-origin

これにより、各設定がどのファイルから来ているかが表示されます。

層2: SSH Hostエイリアス + insteadOfによるSSHキー切り替え

SSHキーの切り替えは2つの設定を組み合わせます。

ステップ1: SSH設定ファイルでHostエイリアスを定義

~/.ssh/config に以下を追加します。

# 個人用(デフォルト)
Host github.com
    IdentityFile ~/.ssh/id_ed25519_personal

# 仕事用(エイリアス)
Host github-work
    HostName github.com
    IdentityFile ~/.ssh/id_ed25519_work

解説

これにより、git@github-work:org/repo.gitにアクセスすると、仕事用のSSHキーが使われます。

ステップ2: GitのinsteadOfでURLを自動変換

仕事用リポジトリでは、github.comへのアクセスを自動的にgithub-workに書き換えます。

~/.gitconfig-work に以下を追加します。

[user]
    name = Your Work Name
    email = work@company.com

# SSH形式のURLを変換
[url "git@github-work:"]
    insteadOf = git@github.com:

# HTTPS形式のURLも変換
[url "git@github-work:"]
    insteadOf = https://github.com/

解説

動作確認

# 仕事用リポジトリでリモートURLを確認
cd ~/work/some-project
git remote -v
# → origin  git@github.com:company/repo.git (fetch)
#    ↑ 表示はgithub.comのまま

# 実際に使われるURLを確認
git config --get-regexp 'url.*'
# → url.git@github-work:.insteadof git@github.com:

層3: gh関数ラッパーによるgh CLIアカウント切り替え

GitHub CLI(gh)は、v2.40.0から複数アカウントのサポートが追加されました。

事前準備: 両方のアカウントでログイン

# 1つ目のアカウントでログイン
gh auth login

# 2つ目のアカウントでログイン(追加される)
gh auth login

# ログイン状況を確認
gh auth status

gh auth statusを実行すると、ログイン済みの全アカウントと、現在アクティブなアカウントが表示されます。

~/.zshrcへの設定追加

########################################
# GitHub CLI アカウント切り替え(関数ラッパー方式)
# ~/work 配下では仕事用、それ以外は個人用
# アカウント名は ~/.zshrc.local で設定:
#   GH_PERSONAL_ACCOUNT="your-personal"
#   GH_WORK_ACCOUNT="your-work"
########################################
gh() {
  local token
  if [[ "$PWD" == "$HOME/work"* ]]; then
    token=$(command gh auth token --user "$GH_WORK_ACCOUNT" 2>/dev/null)
  else
    token=$(command gh auth token --user "$GH_PERSONAL_ACCOUNT" 2>/dev/null)
  fi

  if [[ -n "$token" ]]; then
    GH_TOKEN="$token" command gh "$@"
  else
    command gh "$@"
  fi
}

~/.zshrc.local でアカウント名を設定

# GitHubのユーザー名を設定
GH_PERSONAL_ACCOUNT="your-personal-username"
GH_WORK_ACCOUNT="your-work-username"

解説

関数ラッパー方式とは:

シェル関数でghコマンドをラップし、実行時にディレクトリをチェックして適切なトークンを使用します。

要素説明
gh auth token --user指定アカウントのトークンを取得
GH_TOKEN="..." command gh環境変数をそのコマンドにのみ渡す(プロセスローカル)
command gh関数ではなく実際のghコマンドを呼ぶ

commandキーワードのポイント:

command gh "$@"

シェル関数内でghを呼ぶと再帰的に自分自身が呼ばれてしまいます。commandキーワードを使うことで、関数ではなく実際のコマンドを呼び出します。

なぜこの方式を採用したか:

以前はchpwdフック + gh auth switch方式を使用していましたが、複数のターミナルウィンドウで並行作業する際に問題がありました。

なぜ~/.zshrc.localにアカウント名を書くのか:

動作確認

# 仕事用ディレクトリで確認
cd ~/work/some-project
gh api user --jq '.login'
# → work-username

# 個人用ディレクトリで確認
cd ~/personal/my-repo
gh api user --jq '.login'
# → personal-username

注意: gh auth statusはグローバル設定を表示するため、関数ラッパー方式では現在の状態を正確に反映しません。実際に使用されるアカウントを確認するには、上記のようにgh api userを使用してください。

全体の動作確認

設定が完了したら、以下の手順で確認します。

# 1. 個人用ディレクトリで確認
cd ~/personal/my-repo
git config user.email          # → personal@example.com
gh api user --jq '.login'      # → personal-username

# 2. 仕事用ディレクトリで確認
cd ~/work/company-project
git config user.email          # → work@company.com
gh api user --jq '.login'      # → work-username

# 3. 実際にpushできるか確認(仕事用リポジトリで)
git push --dry-run             # 仕事用SSHキーで認証される

採用後の結果

うまくいったこと

改善の経緯

当初はchpwdフック + gh auth switch方式を採用していましたが、複数のターミナルウィンドウで並行作業する際に問題が発生しました。gh auth switchはグローバル設定を変更するため、片方のウィンドウでの切り替えがもう片方にも影響してしまいます。

そこで関数ラッパー + GH_TOKEN環境変数方式に変更しました。この方式では:

学んだこと

1. GitとGitHubの認証は別物

「Git設定を変えればOK」と思いがちですが、実際にはSSH認証、GitHub API認証など複数のレイヤーがあります。それぞれを理解して設定する必要があります。

2. 標準機能の組み合わせで実現できる

includeIfinsteadOf、シェル関数はすべて標準機能です。新しいツールを追加しなくても、既存の仕組みの組み合わせで目的を達成できました。

3. UXを追求する価値

「cdするだけ」という体験にこだわりました。設定は複雑ですが、日常の操作はシンプルになります。初期投資と日常のコストのバランスを考えて判断することが重要です。

参考

公式ドキュメント

関連記事

ZSL
ZSL

AIエンジニア

生成AIを活用した開発ワークフローの研究・実践をしています。