⚙️

複数のGitHubアカウントをWSL経由のDevcontainerで使う

に公開

Webエンジニアの4096mgです。
複数のGitHubアカウントをWSL経由のDevcontainerで使うときに設定していることを備忘録として残しておきます。

仕事用と個人用で複数のGitHubアカウントを使い分けたいという需要は大きいと思いますが、Windowsに対応した情報はあまり見つからず、Devcontainerがどの認証情報を参照するかもわかりにくく、ハマりやすいポイントだと思います。

Windowsでは

  • WindowsからそのままGitHubに接続したいとき
  • WSLからGitHubに接続したいとき
  • WSL経由のDevcontainerからGitHubに接続したいとき

の3つの接続パターンがあると思いますが、「Windowsから接続したいとき」「Devcontainerから接続したいとき」に問題なく動作するようにするのが目標です。

ここでは name1name2 の2つのアカウントを運用する想定でメモを残していきますが、3つ以上に増えても対応できると思います。
とりあえず説明を省いて作業手順を書き残しています。具体的に何故、何を設定しているのかといったことは記事の終わりに載せておきますので、知りたい方をそちらをご確認ください。

前提

  • WindowsにGitがインストールされている
  • WindowsでOpenSSHが有効化されている (最近ではデフォルトで有効)
  • WindowsにWSL2とそのディストリビューションがインストールされている
  • WindowsにVS Codeがインストールされている
  • WSL経由でDevcontainerを立ち上げる用意が整っている (Dockerの導入など)

GitHubとSSHの設定

SSH Keyの作成と登録

まずは一般的なベストプラクティス通りに、GitHub登録用の鍵を2つ作成し、GitHubに登録します。
操作は Windows のターミナルアプリから行っています。
もし、 Windows Powershell がデフォルトになっている場合は、 Microsoft の推奨に従ってPowershell7をインストールし、デフォルト設定を切り替えることをおすすめします。(必須ではありません)

$ ssh-keygen -t ed25519 -f [name1]-github -C "[name1-gitHub-public-email]@users.noreply.github.com"
$ ssh-keygen -t ed25519 -f [name2]-github -C "[name2-gitHub-public-email]@users.noreply.github.com"

パスフレーズは設定してもしなくてもどちらでも問題ありません。お好みや社内規定に従ってください。
区別しやすいようにコメントには GitHub Public Email を書いています。

GitHub Public Email とは?
Git で使用する Email は一般に公開されます。スパム対策などのために GitHub では公開用のエイリアスが使えます。
メールアドレスは 数字+ユーザー名@users.noreply.github.com のようなフォーマットになっています。
GitHub の Settings の Email SettingsPrimary email address のセクションで確認できます。

作成後、 GitHub の Settings の SSH and GPG keys セクションから各アカウントに SSH Key を登録します。

SSH Configの設定

次に、各アカウントの SSH Config を設定します。 C:\Users\[Windows Username]\.ssh\config を編集します。

Host [name1]-github
  HostName github.com
  User git
  Port 22
  IdentityFile "~/.ssh/[name1]-github"
  ForwardAgent yes
  TCPKeepAlive yes
  IdentitiesOnly yes
  AddKeysToAgent yes

Host [name2]-github
  HostName github.com
  User git
  Port 22
  IdentityFile "~/.ssh/[name2]-github"
  ForwardAgent yes
  TCPKeepAlive yes
  IdentitiesOnly yes
  AddKeysToAgent yes

設定更新後、 ssh コマンドを使って各アカウントの疎通確認を行います。近年の Windows では OpenSSH が自動で有効化されているはずですが、もしインストールや有効化が必要な場合はあわせて行います。

$ ssh -T [name1]-github
Hi name1! You've successfully authenticated, but GitHub does not provide shell access.

$ ssh -T [name2]-github
Hi name2! You've successfully authenticated, but GitHub does not provide shell access.

GitHub はシェル操作を許可していないため、挨拶メッセージが1行表示されるだけですが、きちんと表示されれば問題ないはずです。

各GitHubアカウント用のディレクトリを設定する

次に、WSL内部に各GitHubアカウント用のディレクトリを作成します。
Windowsのストレージに作成するのではなく、必ずWSL内部に作成するようにします。これによってパフォーマンスの問題が大幅に改善されます。
ディストリビューションなど、各自違うと思いますので、作成コマンドなどは乗せません。

自分はエクスプローラーのアドレスバーに \\wsl$ と入力してWSLの内部にアクセスし、ユーザーの home ディレクトリの中に作成しています。
ここでは \\wsl.localhost\Ubuntu\home\[WSL Username]\github-storage 内に name1name2 のディレクトリ作成したという前提で進めていきますが、ディストリビューションやユーザー名によってパスは異なりますので、適宜書き換えてください。

Gitconfig を設定する

グローバルのGitconfigを設定

次に、WindowsのグローバルのGitconfig ( C:\Users\[Windows Username]\.gitconfig ) を以下のように設定します。
もし、グローバルでコミット時の名前やメールアドレスが設定されていればそれも消去します。

[user]
	useconfigonly = true
[includeif "gitdir://wsl.localhost/Ubuntu/home/[WSL Username]/github-storage/name1/"]
	path = //wsl.localhost/Ubuntu/home/[WSL Username]/github-storage/name1/.gitconfig
[includeif "gitdir://wsl.localhost/Ubuntu/home/[WSL Username]/github-storage/name2/"]
	path = //wsl.localhost/Ubuntu/home/[WSL Username]/github-storage/name2/.gitconfig
[safe]
	directory = %(prefix)///wsl.localhost/Ubuntu/home/[WSL Username]/github-storage/*

各アカウント用のディレクトリを設定

そして、各GitHubアカウント用のディレクトリにも個別のGitconfigを設定し、Git Hooksファイルも作成します。
ここでは [name1] アカウントのものを記載しますが、 name2 にも同様の設定をします。

まずは、 .gitconfig を作成します。 パスは //wsl.localhost/Ubuntu/home/[WSL Username]/github-storage/[name1]/.gitconfig です。

[core]
	hooksPath = //wsl.localhost/Ubuntu/home/[WSL Username]/github-storage/[name1]/.git-hooks
[url "git@[name1]-github:"]
	insteadof = git@github.com:

次に、Git Hooksファイル github-storage/[name1]/.git-hooks/post-checkout を作成します。

#!/bin/sh

GIT_USER_NAME="name1"
GIT_USER_EMAIL="[name1-gitHub-public-email]@users.noreply.github.com"

MARKER_FILE=$(git rev-parse --git-dir)/.initialized

if [ ! -f "$MARKER_FILE" ]; then
  echo "Running setup for the first clone..."

  git config user.name "$GIT_USER_NAME"
  git config user.email "$GIT_USER_EMAIL"

  echo "Git user.name and user.email have been set for this repository:"
  git config user.name
  git config user.email

  touch "$MARKER_FILE"
fi

設定をすると、

  • 名前とメールアドレスをリポジトリごとに設定する
  • 指定したディレクトリ内にリポジトリを設置する

このどちらかを行わない限り、コミットできないようになります。
コミット時に名前やメールアドレスが別のアカウントのものになってしまうといった事故は複数のGitアカウントを運用するうえでとても恐ろしいです。

SSH Agent を自動永続起動にする

次に、Windowsで管理者権限のPowershellを起動し、SSH Agent の自動永続起動の設定をします。

$ Get-Service ssh-agent
// stoppedになっていることを確認

$ Set-Service -Name ssh-agent -StartupType 'Automatic'
$ Start-Service ssh-agent

これで、すべての設定は完了です。

作業手順の解説

なぜ、こんな回りくどい設定をしなければいけないのかなど、理由を書いておきますので、興味があればご確認ください。

SSH Agent と Git Hooks を利用している理由

複数のGitHubアカウントを運用するうえで、事故を防ぐため、グローバルのユーザー設定を使わないということはマストだと考えています。
そのために グローバルの .gitconfiguseconfigonly = true を設定し、 [includeif] で指定したディレクトリの内部だけに設定を適用させるという手法はよく見られます。

しかし、これはDevcontainer内部では機能しません。

VS Code の Devcontainer は、立ち上げ時にユーザーホームにある .gitconfig を自動でマウントしてくれます。
ですが、 .gitconfig 内の [includeif] で指定したディレクトリのコンフィグまでは読み取ってくれません。
ディレクトリごとの名前とメールアドレスの設定というものは、 Devcontainer の内部では利用できません。
結局、Devcontainer 内用に、リポジトリごとの個別設定は必須になってしまいます。
ですので、最初に Windowsで git clone を実行したときに、自動でユーザー設定を行うようにしてあります。

また、 Devcontainer では SSH Agent の鍵情報は参照してくれますが、SSH Configは参照してくれません。
そのため、git clone git@[name1]-github:[name1]/hello-world.git のように、ベストプラクティスとしてあげられているような、 Gitのパスにある github.com をSSH Configのものに書き換える手法は機能しません。
そこで、パスの設定は通常通り github.com にして、 Windows側 から接続するときだけ、 Gitconfigを使ってパスを書き換えています。

SSH鍵のパスフレーズへの対応ですが、こちらはSSH Agentを使って対応しています。一度Windowsでパスフレーズを入力すれば、SSH Agentを参照している Devcontainer 内でも利用が可能になります。別のアカウントの Devcontainer に接続するときだけ、鍵情報を消去する必要がありますが、手間としては許容範囲内だと考えています。

WindowsはWSL周りで無駄に複雑、GitHubはマルチアカウントまわりの規約が厳しいという経緯もあってマルチアカウント運用に弱い、Devcontainerは何がマウントされているのかわかりにくい、ということで最初は大変かと思いますが、一度設定してしまえば快適です。

まとめ

設定がすべて完了したら、あとは、

  1. リポジトリをWindows側で初回だけ git checkout しておく( git clone コマンドを実行すれば自動でcheckoutも実行されます)
  2. Windowsを起動後、Devcontainerを立ち上げる前に ssh -T [name1]-github して SSH Agent に鍵を登録する
  3. 鍵を登録後、別アカウントのDevcontainerに切り替えるときは、 ssh-add -D で鍵を消去してから 2 を再度実行する

この3つを守るだけで事故なくエラーなく開発できるようになるので、すごく快適です。

Windows側からGit Cloneなどの操作を行うときは、

PS > cd "\\wsl.localhost\Ubuntu\[WSL Username]\github-storage\[name1]"
PS > git clone git@github.com:[name1]/hello-world.git

のように、各アカウント用のディレクトリに移動してからgitコマンドを使用すれば、gitのパスをssh設定に合わせて書き換えることなく、リポジトリへの接続ができます。

また、VS Code上でも、最近 GitHub の複数アカウントのログイン に対応したため、こちらを活用していけば拡張機能なども不自由なく使えると思います。

最小限の労力で事故のない開発を目指して、設定を工夫していければ幸せですね。

最後に、この記事の執筆にあたって、 こちらのGist を参考にさせていただきました。感謝申し上げます。

chot Inc. tech blog

Discussion