
一臺機器上同時伺候 Gitee 和 GitHub幾乎是每個國內(nèi)開發(fā)者繞不開的日常。我最早的做法很簡單哪個平臺用得多就把git config --global的user.email設(shè)成哪個remote 地址復(fù)制粘貼push 的時候彈出密碼框就輸一次能跑就行。直到有一天一個倉庫的提交記錄里混進了另一個平臺的郵箱代碼評審時被人指出來才發(fā)現(xiàn)這套能跑就行的配置其實一直在埋雷。后來幫幾個朋友處理過類似問題也見過有人把兩把私鑰覆蓋成一把握手失敗才意識到這件事值得單獨寫一篇。這篇內(nèi)容講的是同一臺機器、同一套 Git 環(huán)境里讓 Gitee 和 GitHub 各自用各自的密鑰、各自的提交身份、互不干擾的完整配置方法。適合已經(jīng)用過 Git 基本命令、但在多平臺切換時總遇到權(quán)限報錯或者提交信息錯亂的朋友剛接觸 Git 的新手也能照著步驟走我會把每一步為什么這么做講清楚而不是只丟一串命令讓你抄。1. 兩平臺共存的真實痛點與配置總思路1.1 一個 remote 地址背后其實藏著三件事很多人以為配置兩個平臺就是加兩個 remote真出問題時才發(fā)現(xiàn)一個遠(yuǎn)程倉庫地址背后至少綁著三件互相獨立的事認(rèn)證憑據(jù)決定你有沒有權(quán)限推拉代碼提交身份決定別人看到的作者是誰遠(yuǎn)程地址的解析方式?jīng)Q定 Git 到底往哪臺服務(wù)器發(fā)請求。這三件事在單平臺時代被默認(rèn)配置糊在一起一旦變成雙平臺任何一件沒拆開都會出亂子。舉個最常見的場景你用 SSH 方式克隆了 Gitee 的倉庫又克隆了 GitHub 的倉庫兩邊的 remote 都是gitxxx.com:user/repo.git這種形式。Git 本身不區(qū)分域名背后的身份它只認(rèn) SSH 握手時遞過去的那把私鑰。如果你的~/.ssh目錄里只有一把id_rsa那么兩個平臺收到的都是同一把公鑰其中一個平臺沒登記過這把公鑰握手就會直接失敗報Permission denied (publickey)。這不是網(wǎng)絡(luò)問題也不是賬號被封純粹是密鑰沒分家。提交身份的問題更隱蔽。Git 在提交時會讀取user.name和user.email如果全局配置只寫了一個郵箱那么你在另一個平臺提交的代碼作者信息依然是那個郵箱。平臺側(cè)通常會用郵箱去匹配賬號匹配不上就顯示成一個沒有頭像、沒有主頁的陌生提交者。短期看只是不好看長期看會影響貢獻統(tǒng)計、代碼歸屬甚至在團隊協(xié)作時引發(fā)這段代碼到底誰寫的的爭議。所以配置雙平臺的核心不是記住幾條命令而是把認(rèn)證、身份、地址這三條線分別理清楚。1.2 兩條技術(shù)路線SSH 多密鑰與 HTTPS 憑據(jù)分流真正落地時主流做法就兩條路線選哪條取決于你的使用習(xí)慣和所在網(wǎng)絡(luò)環(huán)境。我把它們的差異整理成一張表你可以對著自己的情況選。對比維度SSH 多密鑰方案HTTPS 憑據(jù)分流方案認(rèn)證載體本地私鑰文件賬號密碼或訪問令牌是否需要每次輸入配置 ssh-agent 后免輸入首次輸入后由憑據(jù)助手緩存多平臺區(qū)分方式靠 SSH config 里的 Host 段匹配靠 URL 域名匹配憑據(jù)條目網(wǎng)絡(luò)適應(yīng)性需要 22 端口可通走 443 端口適應(yīng)性更廣遷移成本拷貝密鑰并重新授權(quán)重新登錄并緩存令牌常見故障密鑰權(quán)限、config 匹配錯誤令牌過期、憑據(jù)緩存串號SSH 方案的優(yōu)勢是一次配好、長期安靜適合經(jīng)常在同一臺機器上長期開發(fā)的人。它的門檻在于要理解 SSH config 的匹配邏輯尤其是 Host 別名和 HostName 的區(qū)別很多人卡在這里。HTTPS 方案的優(yōu)勢是對網(wǎng)絡(luò)環(huán)境更寬容公司內(nèi)網(wǎng)、臨時網(wǎng)絡(luò)都能用代價是要管理訪問令牌令牌一過期就得重新配而且憑據(jù)助手如果配置不當(dāng)兩個平臺的賬號容易互相覆蓋。我的建議是主力開發(fā)機用 SSH臨時環(huán)境或者受限網(wǎng)絡(luò)用 HTTPS。兩者不沖突可以同時存在后面我會講混用時要注意什么。關(guān)鍵是先把其中一條走通再考慮另一條不要一上來就兩套一起配出問題時排查面會翻倍。1.3 配置分層全局、倉庫、條件包含Git 的配置是分層覆蓋的理解這個層次比記住命令更重要。最底層是系統(tǒng)級配置一般不用動中間是全局配置--global存在用戶目錄下的.gitconfig最上層是倉庫級配置--local存在倉庫的.git/config里。上層會覆蓋下層的同名配置項這就是我們做雙平臺隔離的基礎(chǔ)。舉個實際例子全局配置里寫user.email meexample.com某個 GitHub 倉庫里寫user.email megithub.example那么在這個倉庫里提交就用后者其他倉庫仍然用全局值。這個機制讓我們可以做到默認(rèn)身份 特例覆蓋不需要每次提交都手動指定。再往上一層是條件包含也就是includeIf。它允許你按目錄路徑自動加載某段配置比如所有放在~/work/gitee-projects/下的倉庫自動使用 Gitee 的身份放在~/work/github-projects/下的自動使用 GitHub 的身份。這個功能很多人不知道但它是長期維護雙平臺配置最省心的方式。我一般建議目錄規(guī)劃和includeIf一起做前期多花十分鐘后面幾年都不用再想這件事。2. 動手前的環(huán)境盤點和基礎(chǔ)準(zhǔn)備2.1 先確認(rèn) Git 版本和配置來源動手改配置之前先花兩分鐘看清楚當(dāng)前環(huán)境。不同版本的 Git 對includeIf、credential.helper的支持程度不完全一樣尤其是老版本可能存在行為差異。先跑這兩條命令git --version git config --list --show-origin第一條確認(rèn)版本建議在 2.20 以上includeIf的目錄匹配在較新版本里更穩(wěn)定。第二條會列出所有生效的配置項并且標(biāo)注每一項來自哪個文件。這一步非常關(guān)鍵因為很多人改了半天沒生效最后發(fā)現(xiàn)是某個配置文件里有重復(fù)項或者某個倉庫的.git/config里殘留了舊值??摧敵鰰r重點盯三類信息user.name和user.email出現(xiàn)在哪個文件、credential.helper當(dāng)前是什么值、有沒有已經(jīng)存在的url.*.insteadOf重寫規(guī)則。最后這個規(guī)則很容易被忽略它會把某個前綴的地址自動替換成另一個如果你之前配過但忘了后面改 remote 地址時會發(fā)現(xiàn)怎么改都不對。提示--show-origin這個參數(shù)值得養(yǎng)成習(xí)慣排查任何配置問題都先看它。沒有來源信息的配置列表等于看一本沒有頁碼的書。2.2 舊密鑰的清理要謹(jǐn)慎先備份再動手很多人一上來就rm -rf ~/.ssh這是最危險的操作。舊密鑰可能還綁著其他服務(wù)刪掉之后恢復(fù)不了只能重新授權(quán)。正確做法是先列目錄、看內(nèi)容、做備份ls -la ~/.ssh cat ~/.ssh/config 2/dev/null看看現(xiàn)有文件里有沒有id_rsa、id_ed25519、config、known_hosts。known_hosts不要刪它記錄的是你信任過的服務(wù)器指紋刪了之后首次連接會重新詢問雖然不影響使用但會多一道確認(rèn)。備份建議把整個.ssh目錄復(fù)制一份到安全位置命名帶上日期比如ssh-backup-20240115。備份時注意權(quán)限目錄本身應(yīng)該是700私鑰文件是600。如果你在 Windows 上權(quán)限模型不一樣但原則相同私鑰文件不要被其他用戶可讀。我見過有人把私鑰放在共享目錄里結(jié)果被同步工具傳到了不該去的地方這種事故排查起來非常麻煩。如果確實要重新生成密鑰也不要直接覆蓋同名文件。ssh-keygen在目標(biāo)文件已存在時會詢問是否覆蓋手快一回車舊密鑰就沒了。我的習(xí)慣是給新密鑰起帶平臺后綴的名字從源頭上避免覆蓋。2.3 目錄與命名約定為后面的自動化打基礎(chǔ)命名約定看起來是小節(jié)實際上是整套方案能不能長期維護的關(guān)鍵。我的建議是密鑰文件帶平臺標(biāo)識倉庫目錄按平臺分文件夾配置文件和這兩者保持一致的命名邏輯。密鑰文件我一般這樣命名id_ed25519_gitee和id_ed25519_gitee.pubid_ed25519_github和id_ed25519_github.pub倉庫目錄這樣分~/projects/gitee/放 Gitee 相關(guān)倉庫~/projects/github/放 GitHub 相關(guān)倉庫這樣命名的好處是SSH config 里的IdentityFile和includeIf里的路徑都能一眼對應(yīng)上出問題時不需要回憶這個文件到底是干嘛的。而且以后寫腳本做批量操作比如批量檢查 remote 地址、批量切換提交身份有規(guī)律的命名能讓腳本簡單很多。目錄規(guī)劃還有一個隱性收益它讓身份錯亂這類問題在物理層面就很難發(fā)生。你在這個目錄下新建倉庫條件配置自動生效不需要每次手動檢查git config user.email。人都會忘讓目錄結(jié)構(gòu)替你記住比靠自律靠譜。3. SSH 多密鑰方案一次配置長期省心3.1 生成兩把獨立密鑰參數(shù)怎么選生成密鑰用ssh-keygen關(guān)鍵是給每把密鑰獨立的文件名和注釋。注釋-C建議寫清楚用途它會出現(xiàn)在公鑰末尾方便你在平臺側(cè)辨認(rèn)。ssh-keygen -t ed25519 -C gitee-dev-machine -f ~/.ssh/id_ed25519_gitee ssh-keygen -t ed25519 -C github-dev-machine -f ~/.ssh/id_ed25519_github這里選ed25519而不是默認(rèn)的rsa原因是 ed25519 密鑰更短、簽名更快現(xiàn)代平臺基本都支持。如果你維護的是很老的系統(tǒng)可能只支持 RSA那就用-t rsa -b 4096。算法選擇不用糾結(jié)太多關(guān)鍵是兩把密鑰必須獨立不能一把通吃兩個平臺。執(zhí)行過程中會詢問是否設(shè)置口令。設(shè)口令的好處是私鑰文件即使泄露攻擊者也需要口令才能用壞處是每次使用都要輸入除非配合 ssh-agent。我的建議是開發(fā)機設(shè)口令并配置 ssh-agent臨時環(huán)境可以不設(shè)。如果你選擇不設(shè)口令直接回車兩次即可但要確保私鑰文件權(quán)限嚴(yán)格。生成完成后你會得到四個文件兩把私鑰、兩個公鑰。公鑰以.pub結(jié)尾內(nèi)容可以公開私鑰沒有后綴內(nèi)容絕對不能外傳。下一步的 config 文件里引用的是私鑰路徑登記到平臺的是公鑰內(nèi)容別搞反了。3.2 config 文件的關(guān)鍵字段與匹配邏輯~/.ssh/config是 SSH 客戶端的行為說明書它按順序匹配 Host 段找到第一個匹配的就用那段配置。理解這一點就能明白為什么有時候配置寫了卻不生效——可能是前面的通配段先匹配上了。一個可用的雙平臺配置大概長這樣Host gitee.com HostName gitee.com User git IdentityFile ~/.ssh/id_ed25519_gitee IdentitiesOnly yes Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github IdentitiesOnly yes逐字段解釋一下。Host是你連接時使用的名字也是匹配的鍵HostName是真實服務(wù)器地址User對這兩個平臺固定是git不是你的賬號名這一點新手最容易寫錯IdentityFile指定私鑰路徑IdentitiesOnly yes表示只使用這里指定的密鑰不要讓 SSH 挨個嘗試默認(rèn)密鑰。最后這個參數(shù)很關(guān)鍵沒有它SSH 可能先拿id_rsa去試試失敗了才輪到你指定的密鑰某些服務(wù)器會因為嘗試次數(shù)過多直接拒絕。還有一種寫法是用別名區(qū)分比如Host gitee-work配HostName gitee.com這樣 remote 地址就要寫成gitgitee-work:user/repo.git。別名適合需要為同一平臺配置多套身份的場景比如個人號和工作號。但如果只是兩個平臺各一套直接用域名做 Host 更直觀remote 地址和平臺官網(wǎng)給的完全一致復(fù)制粘貼不會錯。注意config 文件里的縮進不是必須的但建議統(tǒng)一用四個空格方便閱讀。文件名必須是config放在~/.ssh/下權(quán)限建議600。權(quán)限過寬時 SSH 會忽略這個文件而且不一定報錯排查起來很隱蔽。3.3 公鑰登記與文件權(quán)限的一次性檢查公鑰登記在兩個平臺的操作路徑不同但邏輯一樣找到 SSH 公鑰設(shè)置頁粘貼.pub文件的完整內(nèi)容保存。粘貼時注意不要帶多余的空格或換行有些終端復(fù)制會帶上換行符導(dǎo)致平臺側(cè)解析失敗。建議用cat命令輸出后整體選中復(fù)制cat ~/.ssh/id_ed25519_gitee.pub cat ~/.ssh/id_ed25519_github.pub登記完成后做一次權(quán)限檢查。這一步很多人跳過結(jié)果遇到密鑰明明對卻認(rèn)證失敗的怪問題。Linux 和 macOS 下執(zhí)行chmod 700 ~/.ssh chmod 600 ~/.ssh/id_ed25519_gitee ~/.ssh/id_ed25519_github chmod 644 ~/.ssh/id_ed25519_gitee.pub ~/.ssh/id_ed25519_github.pub chmod 600 ~/.ssh/config權(quán)限的原則是目錄只允許自己進入私鑰只允許自己讀寫公鑰和 config 可以稍微寬松但也不建議放開。Windows 下沒有這套權(quán)限模型但要確保密鑰文件不在同步盤或者共享目錄里。我見過因為把.ssh放進了會自動同步的文件夾導(dǎo)致私鑰被傳到云端的情況這類問題不是權(quán)限命令能解決的得從存放位置入手。3.4 連接測試與首次握手的確認(rèn)流程配置寫完后用ssh -T測試。兩個平臺返回的提示文案不一樣但成功時都會表明身份認(rèn)證通過ssh -T gitgitee.com ssh -T gitgithub.com如果看到類似歡迎你某某或者successfully authenticated的提示說明認(rèn)證通了。如果看到Permission denied (publickey)先別急著改配置按下面的順序排查公鑰是否完整粘貼、IdentityFile路徑是否正確、文件權(quán)限是否合規(guī)、IdentitiesOnly是否加上。這四個點覆蓋了絕大多數(shù)情況。首次連接還會詢問是否信任服務(wù)器指紋輸入yes回車即可。這個指紋會被寫入known_hosts以后不再詢問。如果你在自動化腳本里跑可以用-o StrictHostKeyCheckingaccept-new參數(shù)但手動操作時建議還是看一眼指紋再確認(rèn)養(yǎng)成習(xí)慣沒壞處。測試通過后別忘了把私鑰加入 ssh-agent這樣設(shè)了口令的密鑰不用每次輸入eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519_gitee ssh-add ~/.ssh/id_ed25519_githubmacOS 可以把密鑰存入鑰匙串用ssh-add --apple-use-keychain參數(shù)Linux 桌面環(huán)境一般配合自啟動腳本。Windows 的 Git Bash 里 agent 行為略有不同建議單獨確認(rèn)。這一步不做也能用只是每次 push 都要輸口令時間長了容易煩最后干脆把口令去掉反而降低安全性。4. 倉庫級身份與遠(yuǎn)程地址的正確寫法4.1 遠(yuǎn)程地址到底該用別名還是原域名這是雙平臺配置里最容易出錯的地方因為 remote 地址必須和 SSH config 里的Host對得上。如果你 config 里寫的是Host gitee.com那么 remote 就用gitgitee.com:user/repo.git如果你寫的是Host gitee-workremote 就必須用gitgitee-work:user/repo.git寫成原域名反而匹配不到你指定的密鑰。我傾向于直接用原域名做 Host理由是平臺文檔、復(fù)制按鈕、同事分享的地址都是原域名形式不需要二次轉(zhuǎn)換減少出錯機會。只有在需要多套身份時才用別名比如同一個 GitHub 賬號既有個人倉庫又有組織倉庫但要求不同的提交郵箱這時候用別名區(qū)分會更清晰。修改已有倉庫的 remote 地址用git remote set-urlgit remote set-url origin gitgitee.com:user/repo.git git remote -v改完一定要用git remote -v確認(rèn)別只看命令有沒有報錯。我遇到過改了一個 remote、另一個同名 remote 還在的情況push 的時候 Git 選了錯的那個排查了半天。remote -v會把 fetch 和 push 兩個地址都列出來如果它們不一致說明之前配過單獨的 push 地址需要一并處理。4.2 用局部配置覆蓋提交身份認(rèn)證解決的是能不能推身份解決的是推上去是誰。全局配置只能有一個默認(rèn)身份所以每個倉庫要單獨設(shè)置cd ~/projects/gitee/some-repo git config --local user.name 你的顯示名 git config --local user.email 你的 Gitee 綁定郵箱 cd ~/projects/github/another-repo git config --local user.name 你的顯示名 git config --local user.email 你的 GitHub 綁定郵箱郵箱必須和平臺賬號綁定的郵箱一致否則提交不會關(guān)聯(lián)到你的賬號。有些人用隱私郵箱比如 GitHub 提供的xxxusers.noreply.github.com形式這也是可以的但要確保平臺側(cè)開啟了相應(yīng)選項。用錯郵箱的后果不是提交失敗而是提交成功但不歸屬你這種靜默錯誤最難發(fā)現(xiàn)。顯示名可以兩個平臺用同一個不影響歸屬判斷歸屬主要看郵箱。但如果你的工作身份和個人身份需要區(qū)分顯示名也可以不同比如工作倉庫用真實姓名個人倉庫用昵稱。這些都屬于倉庫級配置互不干擾。4.3 用 includeIf 按目錄自動切換身份倉庫多了之后每個都手動git config --local太累而且容易漏。includeIf可以按目錄自動加載配置一勞永逸。先在全局.gitconfig里加兩段[includeIf gitdir:~/projects/gitee/] path ~/.gitconfig-gitee [includeIf gitdir:~/projects/github/] path ~/.gitconfig-github然后分別建兩個文件。~/.gitconfig-gitee內(nèi)容[user] name 你的顯示名 email 你的 Gitee 綁定郵箱~/.gitconfig-github內(nèi)容類似郵箱換成 GitHub 的。這樣放在對應(yīng)目錄下的倉庫會自動使用對應(yīng)身份新建倉庫也不用再手動設(shè)。這里有幾個細(xì)節(jié)要注意。gitdir:后面的路徑建議用絕對路徑用~時不同 Git 版本展開行為可能不一致。路徑末尾的斜杠表示目錄前綴匹配加上它~/projects/gitee/下的所有子目錄都會命中。如果你只想匹配特定后綴可以用gitdir:~/projects/**/gitee-*這種通配寫法但通配越復(fù)雜越容易出意外建議先從簡單的前綴匹配開始。驗證是否生效進入一個倉庫執(zhí)行g(shù)it config user.email git config --show-origin user.email第二條會告訴你這個值來自哪個文件。如果顯示的是includeIf加載的那個文件說明配置生效了。如果還是全局值檢查路徑拼寫、斜杠、以及全局配置里includeIf段的位置——它應(yīng)該放在[user]段之后因為后面的配置會覆蓋前面的。4.4 克隆與存量倉庫的改造步驟新克隆倉庫時直接按目錄放好身份配置會自動生效cd ~/projects/gitee git clone gitgitee.com:user/repo.git cd ~/projects/github git clone gitgithub.com:user/repo.git存量倉庫的改造分三步移目錄、改 remote、驗身份。移目錄用mv即可Git 倉庫對路徑不敏感移完照樣能用。改 remote 用前面說的set-url。驗身份就是git config user.email加一次測試提交。測試提交建議用git commit --allow-empty -m test identity不產(chǎn)生實際文件改動推上去看一眼作者信息對不對確認(rèn)沒問題再刪除這條提交記錄。直接拿真實代碼試也行但萬一身份錯了還得改寫歷史成本更高??仗峤贿@個小技巧在驗證配置時很好用值得記住。5. HTTPS 憑據(jù)分流與混合使用場景5.1 credential.helper 的選擇與差異HTTPS 方式下Git 需要知道把賬號密碼存在哪、怎么取。這就是credential.helper的作用。常見取值有store、cache、manager幾類。store把憑據(jù)明文存在文件里簡單但不安全cache存在內(nèi)存里有過期時間manager是跨平臺的憑據(jù)管理器Windows 上常見安全性更好。查看當(dāng)前值git config --global credential.helper如果沒有輸出說明沒配每次操作都會詢問。設(shè)置成store的話憑據(jù)會寫到用戶目錄下的.git-credentials文件格式是https://user:tokenhost。這個文件是明文的機器多人共用時要注意。我在個人開發(fā)機上用store在共享環(huán)境里一律用cache或者系統(tǒng)的憑據(jù)管理器。需要強調(diào)的是現(xiàn)在兩個平臺基本都不建議用賬號密碼直接認(rèn)證而是用訪問令牌。令牌有獨立的作用域和過期時間泄露了可以單獨撤銷比密碼安全。配置時把令牌當(dāng)密碼用即可但要注意令牌權(quán)限別開太大只給倉庫讀寫就夠不要給賬號管理權(quán)限。5.2 按域名區(qū)分憑據(jù)條目的寫法HTTPS 方式下兩個平臺的憑據(jù)是按域名存的。store模式下.git-credentials文件里會有兩行分別對應(yīng)兩個域名。正常情況下 Git 會根據(jù) remote 地址的域名自動選對應(yīng)的條目不需要手動干預(yù)。但有兩種情況會串號一是域名寫錯比如把gitee.com寫成www.gitee.com匹配不上就會用錯條目二是憑據(jù)助手緩存了錯誤的值需要手動清除。清除單個域名的緩存不同助手命令不同。store模式直接編輯文件刪對應(yīng)行cache模式用git credential-cache exit清空系統(tǒng)憑據(jù)管理器則要在系統(tǒng)設(shè)置里刪。清完之后下次操作會重新詢問輸入正確的令牌即可。還有一種更精細(xì)的控制方式用credential.url.helper給特定域名單獨指定助手git config --global credential.https://gitee.com.helper store git config --global credential.https://github.com.helper store這種寫法適合你想讓某個平臺用不同存儲策略的場景比如一個用內(nèi)存緩存、一個用持久存儲。配置項里的 URL 要帶協(xié)議匹配是按前綴來的。5.3 SSH 與 HTTPS 混用的注意事項同一個倉庫里 SSH 和 HTTPS 混用是允許的比如 fetch 用 SSH、push 用 HTTPS但不建議這么做?;煊脮屌挪樽儚?fù)雜認(rèn)證失敗時你分不清是密鑰問題還是令牌問題日志里的錯誤信息也不一樣。我的原則是一個倉庫只用一種協(xié)議要換就整體換。如果確實需要混用比如公司網(wǎng)絡(luò)限制 22 端口只能用 HTTPS push那就把 remote 的 fetch 和 push 地址分開設(shè)置git remote set-url origin gitgithub.com:user/repo.git git remote set-url --push origin https://github.com/user/repo.git git remote -vremote -v會顯示兩行不同地址這是正常的。但要記得HTTPS push 需要憑據(jù)SSH fetch 需要密鑰兩套配置都得對。換機器時也容易漏掉其中一套遷移前最好把git remote -v的輸出記下來。6. 常見問題與排查速查6.1 Permission denied 的幾類原因與定位順序Permission denied (publickey)是最高頻的報錯原因至少有五類。按下面的順序排查基本能覆蓋排查項檢查方法典型現(xiàn)象公鑰是否登記平臺設(shè)置頁對照公鑰指紋平臺側(cè)顯示未使用過的密鑰私鑰路徑是否正確ssh -vT githost看加載了哪個文件日志顯示嘗試了錯誤的密鑰文件權(quán)限是否合規(guī)ls -l ~/.ssh權(quán)限過寬導(dǎo)致密鑰被忽略Host 是否匹配ssh -G githost看最終配置實際生效的配置與預(yù)期不符是否被其他規(guī)則攔截檢查url.*.insteadOf請求發(fā)到了意料之外的地址ssh -vT的-v會輸出詳細(xì)握手過程重點看Offering public key和Server accepts key這兩行。如果提供的密鑰根本不對說明 config 匹配或路徑有問題如果提供了正確的密鑰但服務(wù)器不接受說明平臺側(cè)沒登記或者登記的不是這把。還有一個容易忽略的點有些網(wǎng)絡(luò)環(huán)境會攔截 22 端口表現(xiàn)也是連接超時或者拒絕但錯誤信息不同。區(qū)分方法是看報錯是Connection refused還是Permission denied前者是網(wǎng)絡(luò)層后者是認(rèn)證層。網(wǎng)絡(luò)層的問題不在本文討論范圍但知道這個區(qū)分能讓你少走彎路。6.2 提交作者信息錯亂的修復(fù)思路發(fā)現(xiàn)提交作者不對先確認(rèn)是哪個環(huán)節(jié)錯了。用git log -1 --format%an %ae看最近一次提交的作者如果這里就錯了說明提交時的配置不對如果這里對但平臺上顯示不對說明平臺沒匹配上郵箱。修復(fù)最近一次提交的作者用git commit --amend --author顯示名 正確郵箱 --no-edit這只改最近一次。如果錯了好幾次需要交互式變基或者批量改寫操作前一定先備份分支。改寫歷史會影響已經(jīng)推送的提交團隊協(xié)作的倉庫要謹(jǐn)慎改完需要強制推送并且通知其他人重新拉取。個人倉庫隨便改團隊倉庫建議先溝通。預(yù)防比修復(fù)重要。我現(xiàn)在的習(xí)慣是新建倉庫后第一件事就是確認(rèn)git config user.email配合includeIf之后這一步基本可以省略但第一次在新目錄建倉庫時還是會掃一眼。這個動作花不了十秒鐘能省掉后面改寫歷史的麻煩。6.3 遠(yuǎn)程地址寫錯與 remote 管理git remote -v是排查 remote 問題的第一命令沒有之一。地址寫錯的表現(xiàn)通常是推到了錯誤的倉庫或者提示倉庫不存在。常見錯誤包括用戶名拼錯、倉庫名大小寫不一致、協(xié)議和配置不匹配、多了或少了.git后綴。修改用set-url刪除用remove重命名用rename。一個倉庫可以有多個 remote比如origin指向自己的 forkupstream指向原倉庫。多 remote 場景下 push 要指定名字git push origin main和git push upstream main去的是不同地方別順手就推。還有一個細(xì)節(jié)insteadOf重寫規(guī)則會改變實際請求的地址但remote -v顯示的還是你寫的地址。如果懷疑被重寫用git config --get-regexp url\..*\.insteadof查一下有沒有相關(guān)規(guī)則。這個規(guī)則一般在遷移平臺或者統(tǒng)一協(xié)議時才會配平時不會有但接手別人機器時值得看一眼。6.4 換機遷移時哪些要帶走、哪些不能帶換機器時.ssh目錄下的私鑰、公鑰、config、known_hosts 都可以帶走但要注意新機器的權(quán)限設(shè)置要重做一遍。.gitconfig和兩個條件配置文件也要帶走否則身份配置全丟。倉庫目錄直接拷貝即可Git 倉庫是自包含的。不能隨便帶的是憑據(jù)緩存文件。store模式下的.git-credentials里是明文令牌拷貝過程如果經(jīng)過不安全渠道等于泄露。建議到新機器重新登錄一次讓憑據(jù)助手重新生成。令牌本身也要檢查有效期遷移前順手輪換一次是個好習(xí)慣。遷移后按這個順序驗證ssh -T測兩個平臺、進一個倉庫看git config user.email、做一次空提交測試推送。三步都過說明環(huán)境完整。少做一步可能在幾天后某個 push 時才暴露問題到時候還得回頭查。7. 實操心得與長期維護建議7.1 我踩過的幾個坑你可以直接跳過第一個坑是密鑰覆蓋。早期我用ssh-keygen不加-f參數(shù)默認(rèn)生成id_rsa第二次生成時提示覆蓋我習(xí)慣性回車結(jié)果把第一次的密鑰覆蓋了另一個平臺瞬間失去訪問權(quán)限。后來改成帶平臺后綴的命名再也沒出過這個問題。這個習(xí)慣的成本幾乎為零收益是避免一次很難恢復(fù)的事故。第二個坑是IdentitiesOnly沒加。有段時間某個平臺總是間歇性認(rèn)證失敗重試幾次又能過。后來用ssh -vT看日志發(fā)現(xiàn) SSH 在挨個嘗試所有密鑰嘗試次數(shù)多了被服務(wù)器限流。加上IdentitiesOnly yes之后問題消失。這個參數(shù)不會讓配置變得更好看但能讓行為變得確定。第三個坑是郵箱不一致。我在一個倉庫里用了備用郵箱提交平臺沒關(guān)聯(lián)上貢獻統(tǒng)計少了一大塊。發(fā)現(xiàn)時已經(jīng)過去兩個月只能改寫歷史。從那以后我在includeIf的配置文件里寫死郵箱不再依賴記憶。第四個坑是權(quán)限。有次在 Linux 上把.ssh目錄權(quán)限改成了755結(jié)果 SSH 直接忽略 config 文件而且不報錯只是行為不對。查了半天才發(fā)現(xiàn)是權(quán)限問題?,F(xiàn)在我的檢查清單里權(quán)限是必查項。7.2 讓配置長期穩(wěn)定的幾個習(xí)慣配置這件事配好只是開始能不能長期穩(wěn)定取決于習(xí)慣。我總結(jié)了幾條自己一直在用的新機器先跑一遍git config --list --show-origin確認(rèn)沒有意外的全局配置新建倉庫先看user.email確認(rèn)條件配置生效改完 remote 一定用remote -v復(fù)核定期檢查令牌和密鑰的有效期別等到過期那天才發(fā)現(xiàn)。還有一條是文檔化。我會在~/.ssh/下放一個簡單的說明文件記錄每把密鑰對應(yīng)哪個平臺、什么時候生成的、公鑰指紋是什么。這個文件不含任何私密內(nèi)容只有索引信息。換機器或者幫別人排查時看一眼就能對上號。很多人覺得這是多余動作但真出問題時能快速確認(rèn)這把鑰匙是開哪扇門的價值很高。最后說一個觀念上的轉(zhuǎn)變。雙平臺配置的目標(biāo)不是配一次就永遠(yuǎn)不管而是讓日常操作不需要思考。密鑰分家、身份分層、目錄規(guī)劃這些動作的本質(zhì)都是把需要記憶的事情變成環(huán)境的一部分。環(huán)境對了人就不會錯靠人記住遲早會錯。我現(xiàn)在的狀態(tài)是新建倉庫直接克隆到對應(yīng)目錄提交、推送全程不需要想我現(xiàn)在在哪個平臺這套配置才算真正配好了。