GitHub 預檢
推送新儲存庫時,常因一些單調重複的問題而失敗,且錯誤訊息往往誤導方向。src refspec main does not match any 聽起來像是分支問題,但通常只是沒有提交。一個在非預設帳戶下默默成功的推送,看起來與正確推送一模一樣。本技能能在使用者浪費一次推送之前,就找出這些問題。
指導原則:診斷,但不修改。 報告發現結果,並提供可複製貼上的修復指令。由使用者自己執行。使用者之所以保留多個帳戶,正是因為他們在意哪個帳戶在運作,因此主動執行 git config 或 git remote set-url 反而是完全錯誤的直覺。
執行方式
bash <skill-dir>/scripts/preflight.sh [儲存庫路徑] [遠端名稱]
兩個參數皆為可選——預設為當前目錄及 origin。此腳本僅執行唯讀操作:git config --get、ls-remote、ssh -T、push --dry-run。絕不寫入任何內容。
如果腳本因某些原因無法執行,以下檢查均可透過單行指令直接執行,並以相同方式解讀。
檢查項目的含義
腳本會輸出 PASS / WARN / FAIL 行。解讀比原始輸出更重要,因此請翻譯而非直接貼上:
儲存庫 / 檔案 / 提交。 空目錄或無提交的儲存庫在推送時會產生 src refspec <分支> does not match any。Git 無法從無中建立提交。這是首次推送失敗最常見的原因,因此當此狀況發生時,應首先提出。
分支。 全新的 git init 可能落在 master 分支,而遠端預期是 main。在首次提交之後重命名是安全的(git branch -M main)——在未誕生分支上還沒有東西可重新命名,這也是為什麼指令順序錯誤會浪費一個步驟。
有效遠端 URL。 必須精確知道,因為很容易檢查錯誤:git remote get-url 已經會展開 url.<base>.insteadOf,git ls-remote --get-url 也是如此。因此比較兩者無法檢測出差異。原始值只存在於 git config --get remote.<name>.url 中,所以腳本會將此值與 git remote get-url --push 進行比較(--push 形式額外涵蓋了 pushurl 和 pushInsteadOf,這正是推送實際使用的)。當兩者不同時,使用者設定的 URL 並非 Git 真正連線的目標。經典陷阱是全域設定的 url."https://github.com/".insteadOf = [email protected]:,它會將 SSH 無聲地重導至 HTTPS,因此使用的是 credential helper 持有的帳戶——通常不是使用者預期的帳戶。務必報告有效 URL,並明確標示出差異。
認證帳戶。 對於 SSH,腳本透過 ssh -G 解析主機(因此主機別名如 github-personal 會追蹤到其實際主機名稱和金鑰),然後直接用 ssh -T 詢問 GitHub。GitHub 回應 Hi <使用者名稱>! 並退出碼為 1——在此退出碼 1 是成功情況,並非失敗。對於 HTTPS,則讀取當前 gh 帳戶。將該帳戶與 URL 的所有者部分進行比較:不匹配表示推送會得到 403,或落到錯誤的名稱空間。
提交身份。 從全域設定繼承的 user.email 是無聲的失敗。推送以一個帳戶認證,而每個提交卻以另一個地址署名——且後續修正需透過修訂或改寫歷史。對於遠端屬於不同所有者的儲存庫,若身份設定為全域範圍,應視為 WARN 並重點提出,即使技術上尚未損壞。
遠端狀態。 空的遠端表示首次推送是乾淨的。已存在的引用表示普通推送會被拒絕為非快進,使用者需要先拉取/變基——在他們遇到拒絕之前就告知此情況。此處的錯誤通常表示儲存庫不存在或帳戶缺乏存取權限;GitHub 會刻意將兩者都回報為「找不到」,因此應同時提供兩種可能的解釋,而非猜測。
乾運行推送。 只有在存在提交後才可能進行。這是真正的端到端檢查——它會測試認證與引用協商,但不會寫入。請注意其盲點:它不會捕捉伺服器端的拒絕(例如 GH007 電子郵件隱私),因為這些是在實際接收時才評估的。
報告
給出一個簡短的檢查表格,然後——僅針對失敗或警告的項目——給出可修復它們的精確指令,並按可執行順序排列。不要將通過的檢查作為文字段落列出;使用者想知道的是哪裡有問題以及該輸入什麼。
當需要設定身份時,偏好使用儲存庫本地設定而非修改全域設定,因為重點就在於此儲存庫與機器的預設不同:
git config user.name "<帳戶>"
git config user.email "<電子郵件>"
如果多個儲存庫需要相同處理,請提及 includeIf 作為持久修復方式:
[includeIf "gitdir:~/personal/"]
path = ~/.gitconfig-personal
如果推送被 GH007 拒絕,請指向 GitHub → Settings → Emails 中的 @users.noreply.github.com 地址,而非猜測個人地址——關鍵註解和本地設定只是標籤,並非帳戶實際接受的證明。