GitLab 工作流程技能 是做什麼的?
使用 glab CLI 管理 GitLab 合併請求、議題,並遵循 Git 最佳實務。
多個 GitLab 實例
glab 會從你的 git remote 自動偵測 GitLab 主機。當你在儲存庫內工作時,不需要設定 GITLAB_HOST。對於非 origin 的 remote(例如作為次要 remote 新增的本機 GDK 實例),請使用 glab config set remote_alias <remote>。僅在 Git 儲存庫外部執行指令,或針對特定實例執行一次性指令時,才設定 GITLAB_HOST。關於非 origin remote 的設定以及從 remote URL 推斷主機名稱的詳細資訊,請參閱 references/multi-host.md。
⚠️ 訊息跳脫——常見陷阱
如果你的訊息包含反引號 (`)、$ 或其他 Shell 特殊字元,千萬不要直接將它們內嵌在 -m "..." 中。 Shell 會將反引號解讀為指令替換,默默地破壞你的訊息,並產生類似 /bin/bash: line 1: client_name: command not found 的錯誤。
這已經導致過真實的生產事故:代理程式在 GitLab MR/Issue 上發布了格式錯誤的評論,緊接著又發送道歉修正的訊息。
❌ 不要這樣做——在雙引號的 -m 中內嵌反引號
# 錯誤:Shell 嘗試將 `client_name` 作為指令執行
glab mr note 100 -m "Use `client_name` and `wor/` here." -R org/repo
# 錯誤訊息:/bin/bash: line 1: client_name: command not found
# 評論被發布為:"Use and here."(識別符號被無聲地移除)
# 同樣錯誤:在巢狀/腳本環境中,反斜線跳脫的反引號會失效
glab mr note 100 -m "Use \`client_name\`" -R org/repo
# 在簡單情況下可行,但當指令被呼叫者用雙引號括起來時則會失敗:
# bash -c "glab mr note 100 -m \"Use \`client_name\`\"" → 仍然會執行 client_name
✅ 正確做法——先寫入檔案,再透過 $(cat ...) 傳遞
為你的環境選擇一個合適的路徑(mktemp 的結果、限定了作用範圍的工作區暫存檔,任何適合的方式都可以——這個技能不會指定特定路徑;代理程式應選擇一個在其調用中是唯一的路徑,以避免與平行執行衝突):
# MSG = 你選擇的路徑(例如 mktemp、~/workspace/tmp/note-$$.md 等)
MSG=<代理程式選擇>
cat > "$MSG" << 'EOF'
Use `client_name` and `wor/` here. The `glab` tool handles this.
EOF
glab mr note 100 -m "$(cat "$MSG")" -R org/repo
使用單引號括起來的 'EOF' heredoc 分隔符,可以在寫入檔案時防止所有變數/反引號擴展。由於檔案內容已經是逐字寫入的,因此 $(cat "$MSG") 替換是安全的。在 <<'EOF' heredoc 內部使用三重反引號程式碼區塊 (```) 也是安全的——無需跳脫;只有單一反引號和 $ 會觸發指令替換。
✅ 同樣安全——使用 -f 旗標的 glab api
glab api --method POST "projects/org%2Frepo/merge_requests/100/notes" \
-f "body=$(cat "$MSG")"
⚠️ 未引號的 heredoc 仍會解譯反引號
# 錯誤:EOF 分隔符未引號——主體中的反引號仍會被解譯
cat > "$MSG" << EOF
Use `client_name` here. # ← 寫入檔案時,Shell 會執行 client_name
EOF
⚠️ Heredoc 內嵌 Heredoc 會破壞 Shell 解析
如果你的內容本身包含一個帶有未縮排的 EOF 終止符的 heredoc 範例,那麼位於第 0 欄位的內部 EOF 會提前關閉外層的 heredoc:
# 錯誤:內部的 EOF 位於第 0 欄位——它會提前關閉外層的 HEREDOC
cat > "$OUTER" << 'EOF'
Here is the safe pattern:
cat > "$MSG" << 'EOF'
Use `client_name` here.
EOF
# ↑ 這個 EOF 終止了外層的 heredoc——下面的行會作為 Shell 指令執行!
echo "more content..."
EOF
# ↑ 這個多餘的 EOF 會變成一個指令:"EOF: command not found"
修復方式——為外層 heredoc 使用不同的分隔符:
cat > "$OUTER" << 'OUTEREOF'
Here is the safe pattern:
cat > "$MSG" << 'EOF'
Use `client_name` here.
EOF
OUTEREOF
或者分塊寫入檔案——第一塊使用 >,後續塊使用 >>,每個塊使用自己的分隔符。
經驗法則: 如果訊息包含 `, $, !, 或 \——總是先使用 << 'EOF' 寫入檔案。如果內容本身包含 heredoc 語法,請使用一個不會在主體中出現的唯一外層分隔符(例如 OUTEREOF, MSGEOF)。
建立合併請求
總是傳遞 --push 和 -H <owner/repo>。沒有 --push,分支可能尚未存在於任何 remote。沒有 -H,glab 可能會選錯 remote(例如安全性鏡像)作為來源專案,從而從錯誤的 fork 建立 MR。
第二個同家族的 remote? 在一個同時有
origin(gitlab-org/gitlab) 和security鏡像 (gitlab-org/security/gitlab) 的檢出 (checkout) 中,以非互動模式執行glab mr create(無 TTY,代理程式就是這樣運行的)會默默地選擇securityfork 作為來源,並因400 {source_branch: [does not exist]}而失敗。持久修復方式,每個檢出設定一次:git config remote.origin.glab-resolved-head head。對於新檢出的每次指令備用方案:傳遞-H <owner/repo>(例如-H gitlab-org/gitlab)。-R無法修復這個問題——它只固定了基礎儲存庫,而不是來源。
# 簡單 MR
glab mr create --push -H <owner/repo> --title "Add feature" --description "Brief description" --assignee <username>
# 複雜 MR - 先將描述寫入檔案(自己選擇路徑)
glab mr create --push -H <owner/repo> --title "Add feature" --description "$(cat "$DESC")" --assignee <username>
範本: 檢查 .gitlab/merge_request_templates/ 目錄以找尋專案特定的範本。
完整旗標列表(Claude Code 會自動注入;其他代理程式應自行執行):
!glab mr create --help
更新合併請求
glab mr update <number> --description "$(cat "$DESC")"
glab mr view <number> -R <owner>/<repo>
議題管理
完整且最新的旗標列表(Claude Code 會自動注入;其他代理程式應自行執行):
!glab issue --help
view, note, list, create, update 這些指令如預期般運作。--help 不會警告你的非顯而易見的陷阱:
# List 預設為開啟,且沒有 --state 旗標——改用 --closed / --all
glab issue list --closed -R <owner>/<repo>
glab issue list --all -R <owner>/<repo>
# 標籤——使用 --label / --unlabel,絕不使用 +label 或 -label 語法
glab issue update 123 --label "new-label"
glab issue update 123 --unlabel "old-label"
# 範圍標籤會在其範圍內自動替換——不需要 --unlabel:
glab issue update 123 --label "status::doing" # 移除任何現有的 status:: 標籤
# 包含反引號/$ 的訊息——先寫入檔案(參閱上方的訊息跳脫章節)
glab issue note <number> -m "$(cat "$MSG")" -R <owner>/<repo>
關於議題狀態轉換(透過 API 關閉/重新開啟)以及透過 glab api 發布評論:references/issue-api.md
工作項目
GitLab 正在將議題遷移到工作項目。URL 顯示 /work_items/<iid>,但 REST API 是相同的。
# ✅ 使用 issues API——相同的 IID,相同的端點
glab api "projects/org%2Fproject/issues/<iid>"
# ❌ /work_items/ REST 端點不存在
glab api "projects/org%2Fproject/work_items/<iid>" # → 404
URL 解析:https://gitlab.com/org/project/-/work_items/539076
→ glab api "projects/org%2Fproject/issues/539076"
完整詳細資訊、GraphQL 替代方案、群組層級工作項目以及代理計劃 (Workplan) 小工具:references/work-items.md
MR 審查
從 glab v1.94.0 開始,glab mr note 可以處理所有常見的 MR 評論形式(列表、一般、差異行、回覆、解決/重新開啟),而無需使用原始 glab api 呼叫或手動建構 position 物件。對於任何單一評論的工作流程,優先使用它。MR IID 是位置引數(不是 --mr);省略它以從當前分支自動偵測。
# ✅ 使用 glab mr note 處理讀/寫/回覆/解決——每個操作一個指令
glab mr note list 123 -F json # 讀取討論
glab mr note create 123 -m "comment" # 一般評論
glab mr note create 123 --file main.go --line 42 -m "..." # 差異行評論
glab mr note create 123 --reply abc12345 -m "..." # 回覆
glab mr note resolve 123 abc12345 # 解決討論串
# ❌ 不要對上述操作使用 glab api .../discussions
glab api "projects/<id>/merge_requests/123/discussions" # 改用 mr note list
glab api --method PUT ".../discussions/<id>" -f resolved=true # 改用 mr note resolve
上述子指令的完整旗標列表(Claude Code 會自動注入;其他代理程式應自行執行):
!glab mr note --help
僅在需要批次草稿審查(透過 bulk_publish 同時發布多個內嵌評論)時,才退回到使用原始 glab api .../draft_notes——glab mr note 沒有草稿模式。
完整參考資料(所有旗標、程式碼建議、草稿/批次備用方案、position 物件):references/mr-review.md
議題連結、史詩與巢狀群組
- 議題連結 (
blocked_by,relates_to):references/issue-links.md - 史詩 CRUD(建立、列出、更新、關閉):references/epics.md
- 史詩評論(GraphQL 讀/寫、分頁——REST 回傳 404):references/epic-comments.md
- 巢狀群組(
%2F編碼):references/nested-groups.md
MR 列表與過濾
完整旗標列表(Claude Code 會自動注入;其他代理程式應自行執行):
!glab mr list --help
注意: glab mr list 預設列出開啟的 MR,且沒有 --state 或 --status 旗標——改用 --all、--merged 或 --closed 來變更狀態過濾器。
搜尋
完整的搜尋範例(實例 / 群組 / 專案、範圍表、分頁):references/search.md
快速參考:
glab api "search?scope=issues&search=<query>" | jq '.[] | {iid, title}'
glab api "groups/<group>/search?scope=merge_requests&search=<query>" | jq '.[]'
glab api "projects/<org>%2F<repo>/search?scope=issues&search=<query>" | jq '.[]'
Git 與提交規範
當存在時,請遵循儲存庫自身的 git 規範(專案可能會記錄規範並透過提交檢查工具執行)。GitLab 預設值:
git checkout -b feature/description # 功能分支
git checkout -b fix/description # 錯誤修復分支
- 使用大寫開頭的祈使句作為提交標題(例如 "Add feature",而非 "Added feature" 或 "feat: add feature");GitLab 不使用 conventional-commit 規範。
- 使用完整 URL 引用議題/MR:
Closes https://gitlab.com/org/project/-/issues/123。 - 對包含特殊字元的提交訊息使用單引號:
git commit -m 'Add note from https://gitlab.com/org/project/-/merge_requests/123'。
代理指南
以上章節涵蓋了常見的工作流程。以下是不易從 glab <cmd> --help 發現的非顯而易見的陷阱和 API 特性:
- 先讀取上下文 — 在實作前先執行
glab issue view/glab mr view;檢查.gitlab/issue_templates/和.gitlab/merge_request_templates/目錄中的範本 --jq僅作用於子指令,不作用於glab api—glab issue list/glab mr list/glab ci list接受一個全域--jq旗標(過濾 JSON 輸出);glab api不支援——改將其輸出透過管道傳給| jq '...'- 沒有
--body旗標 — glab 使用--description,而不是--body(後者是gh的旗標);它們不可互換 - 工作項目使用 issues API —
/work_items/<iid>URLs →projects/.../issues/<iid>;/work_items/REST 端點會回傳 404 - 史詩評論需要 GraphQL — REST
/notes的 GET 和 POST 都會回傳 404(即使在 GitLab 19.1 上也是如此);將body/noteableId作為 GraphQL 變數傳遞,絕不要使用字串插值。請參閱 references/epic-comments.md - 群組層級 API 不要使用
-R—-R需要OWNER/REPO格式;群組端點應直接使用glab api "groups/..." - 巢狀群組 REST:使用
%2F—groups/org%2Fsubgroup/epics;未編碼的斜線會導致 404 - GraphQL iid 是字串 —
workItem(iid: "16428")而非workItem(iid: 16428) groups/<id>/work_items會回傳 404 — 使用groups/<id>/epics(REST)或 GraphQLproject公開的是workItems(複數),而非workItem— 在project下使用workItems(first: 1, iid: "IID"),不要加上filter:參數;單數的workItem(iid:)欄位僅存在於group/namespace下- 透過 REST 關閉/重新開啟史詩 — 在
PUT groups/<id>/epics/<iid>上使用state_event=close/reopen即可;不需要 GraphQL - 範圍標籤會自動替換 —
--label "status::doing"會移除任何現有的status::*標籤;不需要--unlabel(這是一個平台事實,通常透過 API 都是如此,不僅限於 glab) - 冪等評論 → 使用
--unique—glab mr note create -m "..." --unique若已存在相同的內文則跳過發布;僅比對內文,因此不同差異行上的相同內文仍會發布 - 非 origin remote → 使用
remote_alias— 如果origin指向一個實例,但你希望 glab 以另一個 remote 為目標(例如以gdk名稱新增的本機 GDK),請執行glab config set remote_alias gdk,而不是每次都設定GITLAB_HOST。請參閱 references/multi-host.md - 訊息中的反引號 → 先寫入檔案 — 絕不要將
`/$內嵌在-m "..."或--description "..."中;使用<< 'EOF'(單引號括起來的分隔符,至關重要)寫入一個你自訂名稱的檔案(每個調用是唯一的),然後透過$(cat "$FILE")傳遞。請參閱上方的訊息跳脫章節。 - 第二個同家族 remote 會使
mr create誤判來源 — 當存在security鏡像以及origin時,非互動式mr create(無 TTY)會默默地選擇該 fork 作為來源。一次性的修復方式:git config remote.origin.glab-resolved-head head;每次指令的備用方案:-H <owner/repo>(-R無法修復)。請參閱「建立合併請求」章節。 glab api評論內文: 檔案 →-F "body=@file"
…
[已截斷以利翻譯]