多重 SSH Keys 與 Github 帳號

Updated at [2017-12-27 水 16:58]

後來覺得這篇文章原本講的方法實在太麻煩了,而且當你有用 submodule 時會有問題 (總不能直接改 submodule 的 git repo URL 吧),剛好發現一個好辦法:使用環境變數 GIT_SSH_COMMAND ,如下:

1
GIT_SSH_COMMAND="ssh -i ~/.ssh/COMPANY_KEY" git clone git@github.com:foo/bar

但這樣每次都要打前面那一串很麻煩,不如直接 export ,例如我自己是寫了個簡單的 alias 到 ~/.zshrc 裡面:

1
2
alias set-company-git-ssh='export GIT_SSH_COMMAND="ssh -i ~/.ssh/COMPANY_KEY";
export PS1="${PS1}COMPANY ==> "'

這樣下了 set-company-git-ssh 後就可以安心使用 git ,連 zsh 的 $PS1 (prompt) 都會變,一目了然。

順帶一提,npm install 自己也會去吃 GIT_SSH_COMMAND ,很方便。

使用情境

工作上需要用公司的 email 申請一個新的 Github 帳號,這樣一來我的系統上就有兩個 Github 帳號用於開發…orz,總之今天摸索了一下多重 SSH key / GitHub 帳號時的應對方式。

需求

  1. 透過 SSH 而不是 HTTPS 來 clone / fetch / push (這樣就不需要每次 push 都輸入 GitHub 帳號密碼)
  2. 兩個帳號:
    1. 平常自己用的 GitHub 帳號
    2. 公司用的 Github 帳號 (以下假設為 `YOU@COMPANY.com`)
  3. 在 clone 時就決定用哪個帳號來 clone
  4. 以後 git push 時,根據 clone 時選的帳號,來自動選擇正確的 SSH key。
協定 長怎樣 需要 Github 密碼
SSH `git@github.com:USERNAME/REPONAME.git` 不用
HTTPS https://github.com/USERNAME/REPONAME.git 每次 push 都要

1. 建立新的 SSH key 並綁定該 Key 給 Github 帳號

因為現在一組 SSH key 只能綁一個 Github 帳號(就算可以綁多個我也不太建議,你會很混亂),所以我們要建立一個新的:

這個很少會做,很多細節都忘光了,所以還是寫一下筆記。

cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "YOU@COMPANY.com"

這裡假設建立了一個叫 COMPANY 的 SSH key。做完後,這會在 ~/.ssh/ 下產生兩個新的檔案。 .pub 結尾的是 public key,另一個則是 private key。

這時打開 Github web 界面中的帳號設定,選 SSH key 那一頁,然後把 public key 整個檔案的內容 copy 下來貼進去。

  • 給不知道非對稱加密 的基本概念的人:public key 是公開給別人看的,private key 則是打死不能給任何人看的,不要搞錯了。我遇過很有趣的一次是對方把他的 private key 貼給我了…
  • 給不知道 Passphrase 是什麼東西的人:passphrase 跟 Github 密碼毫無關係,這只是讓 private key 多一層保障。在建立 SSH key 時如果有指定 passphrase,以後就算有人拿到你的 private key 檔案也沒辦法用他。缺點是會導致每次 push 都要輸入 passphrase(雖然是不用輸入 Github 的帳號密碼了)。

2. 設定 Bash/Zsh alias 方便 clone

為了以後方便選用不同帳號 git clone 在 ~/.zshrc~/.bashrc 內加入:

alias company-git-clone='git clone --config user.name="YOUR NAME" --config user.email=YOU@COMPANY.com $@'

以後就只要輸入 company-git-clone REPO-SSH-URL,效果就等同於:

git clone REPO-SSH-URL
cd REPO
git config user.name "YOUR NAME"
git config user.email YOU@COMPANY.com.tw

注意!其實這部份跟 SSH key 之間並沒有關聯。設定 user.name 跟 user.email 其實就只是以後你在該 repository 下 commit 時,會在 commit log 中顯示的名子跟電子郵件而已。所以當然,(如果公司沒有特別規定的話)你也可以在這裡填自己常用的 email 而不是公司的 email。

你可能會記得,你生平第一次使用 git 前應該有設定過類似這樣的東西:

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

這裡因為有用 --global ,所以這是寫入到你的家目錄下 ~/.gitconfig 設定檔中。如果不加 --global 參數,就變成寫入目前 $PWD 所在的 git repository 的 .git/config 設定檔中。
現在你應該能夠明白上面這個 alias 在幹麻。總之就是如果 repo/.git/config 沒有特別指定 user,就會直接用 ~/.gitconfig 裡的。

3. 建立 ~/.ssh/config

現在建立 ~/.ssh/config 這個檔案,加入如下內容

#自己私人用的 GitHub 帳號,id_rsa 就是我自己原本用的 ssh key
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa

#公司工作用的 GitHub 帳號,此處的 COMPANY 你可以自行取名
Host github.com-COMPANY
    HostName github.com
    User git
    IdentityFile ~/.ssh/COMPANY

4. 如何使用?

拿我的一個小玩具 repo kuanyui/takahashi.js 當作例子:

指令 用了 ~/.ssh/ 下的哪個 key 會用哪個 git user (commit log 顯示哪組 name/email)
V git clone git@github.com:kuanyui/takahashi.js.git id_rsa ~/.gitconfig 內的設定
company-git-clone git@github.com:kuanyui/takahashi.js.git id_rsa takahashi.js/.git/config 內的設定
git clone git@github-COMPANY.com:kuanyui/takahashi.js.git COMPANY ~/.gitconfig 內的設定
V company-git-clone git@github-COMPANY.com:kuanyui/takahashi.js.git COMPANY takahashi.js/.git/config 內的設定

我們要用的就是打 V 的那兩個。

只要用這種方法,以後 push 時 git 就會自動選擇要用哪個 ssh key、push 到哪個 GitHub 帳號了。

你可以試著做上面的動作,仔細觀察每次 clone REPO 下來後, REPO/.git/config 的內容差異,一旦了解它們是差在哪,你就會很難忘記這些概念了。