§1Bối cảnh
Mình đang sử dụng khá nhiều tài khoản git, cả github và gitlab. Cá nhân mình cũng có nhiều profile, và cũng có profile riêng cho công việc ở công ty. Trong quá trình làm việc có một số rắc rối như sau:
- Mỗi lần chuyển repo là phải remove ssh key để add lại cho đúng
- Với các project mới cần phải thiết lập lại user.name và user.email cho đúng với tài khoản
Mình muốn mọi thứ tự động: repo nào thì dùng đúng key và đúng tên/email tương ứng, không cần nhớ hay đổi tay nữa.
§2Giải pháp
1. Sử dụng SSH config: host match
SSH hỗ trợ config ssh key theo từng host, nếu chỉ có 2 tài khoản ở hai host khác nhau thì chỉ cần thiết lập host là đáp ứng được yêu cầu:
Match Host github.com
IdentityFile ~/.ssh/id_rsa_github
IdentitiesOnly yes
Match Host gitlab.com
IdentityFile ~/.ssh/id_rsa_gitlab
IdentitiesOnly yes2. Sử dụng SSH config: host alias
Trong trường hợp có nhiều tài khoản của cùng một host thì phương án trên không khả thi, mình cần sử dụng phương án mới: host alias.
# Tài khoản cá nhân
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_personal
IdentitiesOnly yes
# Tài khoản công ty
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_work
IdentitiesOnly yesSau đó mình sẽ clone git về với alias host github-personal, github-work thay vì github.com
# Repo công ty
git clone git@github-work:company/project.git
# Repo cá nhân
git clone git@github-personal:me/my-repo.gitSSH sau đó sẽ tự động chọn ssh key dựa trên host mình đã đặt.
3. Sử dụng SSH config: custom match
Với phương án trên vấn đề được giải quyết ổn thoả, tuy nhiên dần dần mình cảm thấy phiền với việc phải đổi host cho remote url. Mình chuyển qua sử dụng phương án mới:
Match Exec "[[ $(git config --get remote.origin.url) =~ .*[email protected]:my-username.* ]]"
IdentityFile ~/.ssh/hailerity_rsa
IdentitiesOnly yesTrên đây sử dụng Match Exec để thực hiện câu lệnh check xem git remote url khớp với một tài khoản không, nếu khớp sẽ dùng ssh key tương ứng, không khớp sẽ bỏ qua.
Cách này rất linh hoạt, và không cần phải đổi remote url host. Tuy nhiên có một hạn chế với phương án này là không thể áp dụng cho câu lệnh git clone: lúc clone, repo chưa tồn tại nên git config --get remote.origin.url chưa trả về gì. Mục 5 bên dưới giải quyết hạn chế này.
4. Sử dụng Git config để tự chọn user/email
Sau nhiều lần commit project dùng sai user.name và user.email, mình tìm cách thiết lập để tránh sai lầm đó.
Git có hỗ trợ set config file theo điều kiện trong ~/.gitconfig:
[user]
name = Tram Dev
email = [email protected]
[includeIf "gitdir:~/Workspaces/personal/**"]
path = ~/Workspaces/personal/.gitconfig
[includeIf "gitdir:~/Workspaces/work/**"]
path = ~/Workspaces/work/.gitconfigVới config trên, các project ở trong ~/Workspaces/personal sẽ sử dụng file gitconfig ở trong thư mục đó, tương tự với ~/Workspaces/work. Như vậy mình chỉ cần viết .gitconfig cho từng thư mục và đặt project vào đúng thư mục là được.
Ví dụ ~/Workspaces/work/.gitconfig:
[user]
name = Tram Dev
email = [email protected]5. Gộp SSH key vào Git config theo thư mục
Mục 4 đã chọn đúng user/email theo thư mục. Git cũng có core.sshCommand để chỉ định lệnh SSH, nên mình đặt luôn SSH key vào cùng file .gitconfig của thư mục đó:
# ~/Workspaces/work/.gitconfig
[user]
name = Tram Dev
email = [email protected]
[core]
sshCommand = ssh -i ~/.ssh/id_ed25519_work -o IdentitiesOnly=yes# ~/Workspaces/personal/.gitconfig
[user]
name = Tram Dev
email = [email protected]
[core]
sshCommand = ssh -i ~/.ssh/id_ed25519_personal -o IdentitiesOnly=yesBây giờ key và email cùng đi theo thư mục. Repo nằm trong ~/Workspaces/work dùng key công ty, repo trong ~/Workspaces/personal dùng key cá nhân, remote url vẫn giữ nguyên [email protected]:.... Cách này thay được cả mục 2 và mục 3.
Điều mình quan tâm nhất là git clone có dùng đúng key không. Với git 2.50, includeIf "gitdir:..." được áp dụng ngay trong lúc clone nếu thư mục đích nằm trong ~/Workspaces/work, nên lệnh clone dùng đúng core.sshCommand của thư mục đó:
cd ~/Workspaces/work
git clone [email protected]:company/project.gitĐể chắc chắn trên máy của bạn, bật GIT_TRACE khi clone. Git in ra lệnh SSH thực sự được chạy, trong đó có đường dẫn key:
cd ~/Workspaces/work
GIT_TRACE=1 git clone [email protected]:company/project.git 2>&1 | grep run_command
# trace: run_command: ... ssh -i ~/.ssh/id_ed25519_work -o IdentitiesOnly=yes ... [email protected]Hoặc kiểm tra repo đã clone đang nhận cấu hình nào:
cd ~/Workspaces/work/project
git config --show-origin core.sshCommandNếu dùng phiên bản git cũ hơn mà clone không nhận cấu hình, có thể chỉ định key ngay trong lệnh clone. Option -c cũng được ghi vào config của repo mới, nên các lần pull/push sau vẫn dùng đúng key:
git clone -c core.sshCommand="ssh -i ~/.ssh/id_ed25519_work -o IdentitiesOnly=yes" \
[email protected]:company/project.gitNếu tạo key mới, mình dùng Ed25519 thay cho RSA vì key ngắn hơn và được GitHub, GitLab hỗ trợ đầy đủ:
ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519_work