GitLab ワークフロースキル は何をしますか?
glab CLI を使用した GitLab ワークフロー管理(マージリクエスト、Issue、Git ベストプラクティス)。
複数の GitLab インスタンス
glab は、git リモートから GitLab ホストを自動検出します。リポジトリ内で作業している場合、GITLAB_HOST は不要です。origin 以外のリモート(例:セカンダリリモートとして追加されたローカル GDK インスタンス)の場合は、glab config set remote_alias <remote> を使用します。GITLAB_HOST は、git リポジトリ外で実行する場合、または特定のインスタンスを対象とした 1 回限りのコマンドの場合にのみ設定してください。非 origin リモートのセットアップとリモート URL からのホスト名導出については、references/multi-host.md を参照してください。
⚠️ メッセージエスケープ — よくある落とし穴
メッセージにバッククォート(`)、$、またはその他のシェル特殊文字が含まれている場合は、決して -m "..." に直接インライン化しないでください。 シェルはバッククォートをコマンド置換として解釈し、メッセージを静かに壊し、/bin/bash: line 1: client_name: command not found のようなエラーを生成します。
これは実際に本番環境で障害を引き起こしています。エージェントが誤ったコメントを GitLab MR/Issue に投稿し、その後謝罪の訂正ノートを投稿するという問題が発生しました。
❌ やってはいけないこと — バッククォートをダブルクォートの -m にインライン化する
# 壊れています: シェルが `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 の結果、スコープ付きワークスペースの tmp ファイルなど、何でも構いません)を選択してください。このスキルは特定のパスを規定しません。エージェントは、並列実行時の上書きを避けるために、その呼び出しに固有のパスを選択します。
# MSG = 選択したパス(例: mktemp、~/workspace/tmp/note-$$.md など)
MSG=<エージェントが選択>
cat > "$MSG" << 'EOF'
ここで `client_name` と `wor/` を使用します。`glab` ツールがこれを処理します。
EOF
glab mr note 100 -m "$(cat "$MSG")" -R org/repo
シングルクォートされた 'EOF' ヒアドキュメント区切り文字は、ファイル書き込み時にすべての変数/バッククォート展開を防ぎます。$(cat "$MSG") 置換は安全です。ファイルの内容は既にリテラルとして書き込まれているためです。トリプルバッククォートコードブロック(```)も <<'EOF' ヒアドキュメント内では安全です — エスケープは不要で、シングルバッククォートと $ のみがコマンド置換をトリガーします。
✅ これも安全 — glab api と -f フラグの使用
glab api --method POST "projects/org%2Frepo/merge_requests/100/notes" \
-f "body=$(cat "$MSG")"
⚠️ 引用符で囲まれていないヒアドキュメントはバッククォートを解釈します
# 壊れています: 引用符で囲まれていない EOF 区切り文字 — 本文内のバッククォートが解釈されます
cat > "$MSG" << EOF
ここで `client_name` を使用します。 # ← シェルがファイル書き込み時に client_name を実行します
EOF
⚠️ ヒアドキュメント内のヒアドキュメントはシェルの解析を壊します
コンテンツ自体にインデントされていない EOF ターミネータを持つヒアドキュメントの例が含まれている場合、0 列目の内部 EOF が外部ヒアドキュメントを早期に閉じます。
# 壊れています: 内部の EOF が 0 列目にあります — 外部のヒアドキュメントを早期に閉じます
cat > "$OUTER" << 'EOF'
安全なパターンは次のとおりです:
cat > "$MSG" << 'EOF'
ここで `client_name` を使用します。
EOF
# ↑ この EOF が外部ヒアドキュメントを終了させます — 以下の行はシェルコマンドとして実行されます!
echo "more content..."
EOF
# ↑ この残った EOF はコマンドになります: "EOF: command not found"
修正方法 — 外部ヒアドキュメントには異なる区切り文字を使用します:
cat > "$OUTER" << 'OUTEREOF'
安全なパターンは次のとおりです:
cat > "$MSG" << 'EOF'
ここで `client_name` を使用します。
EOF
OUTEREOF
または、ファイルをチャンクに分割して書き込みます。最初のチャンクは >、後続のチャンクは >> を使用し、それぞれに独自の区切り文字を指定します。
経験則: メッセージに `、$、!、または \ が含まれている場合 — 最初に << 'EOF' でファイルに書き込み、常に行います。コンテンツ自体にヒアドキュメント構文が含まれている場合は、本文に出現しない一意の外部区切り文字(例:OUTEREOF、MSGEOF)を使用します。
マージリクエストの作成
常に --push と -H <owner/repo> を渡します。--push がないと、ブランチがまだどのリモートにも存在しない可能性があります。-H がないと、glab が誤ったリモート(セキュリティミラーなど)をソースプロジェクトとして選択し、間違ったフォークから MR を作成する可能性があります。
2 番目の同ファミリーリモートはありますか?
origin(gitlab-org/gitlab)とsecurityミラー(gitlab-org/security/gitlab)の両方がチェックアウトされている場合、glab mr createを非対話的に(TTY なし、エージェントの実行方法)実行すると、securityフォークをヘッドとして静かに選択し、400 {source_branch: [does not exist]}で失敗します。永続的な修正(チェックアウトごとに 1 回設定):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 "簡単な説明" --assignee <username>
# 複雑な MR - 最初に説明をファイルに書き込みます(自分のパスを選択)
glab mr create --push -H <owner/repo> --title "機能を追加" --description "$(cat "$DESC")" --assignee <username>
テンプレート: プロジェクト固有のテンプレートについては、.gitlab/merge_request_templates/ を確認してください。
完全なフラグリスト(Claude Code はこれを自動的に注入します。その他のエージェントは実行する必要があります):
!glab mr create --help
マージリクエストの更新
glab mr update <番号> --description "$(cat "$DESC")"
glab mr view <番号> -R <owner>/<repo>
Issue 管理
完全で常に最新のフラグリスト(Claude Code はこれを自動的に注入します。その他のエージェントは実行する必要があります):
!glab issue --help
view、note、list、create、update は期待通りに機能します。--help では警告されない非自明な落とし穴:
# リストはデフォルトで開いており、--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 <番号> -m "$(cat "$MSG")" -R <owner>/<repo>
Issue 状態遷移(API 経由のクローズ/再オープン)と glab api を介したノートの投稿については、references/issue-api.md を参照してください。
ワークアイテム
GitLab は Issue をワークアイテムに移行しています。URL は /work_items/<iid> を示していますが、REST API は同じです。
# ✅ Issue 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 は、生の glab api 呼び出しや手動の position オブジェクトなしで、一般的な MR コメントの形状(リスト、一般、差分行、返信、解決/再オープン)をすべて処理します。単一コメントのワークフローにはこちらを優先してください。MR IID は位置引数です(--mr ではありません)。省略すると、現在のブランチから自動検出されます。
# ✅ 読み取り/書き込み/返信/解決には glab mr note を使用します — 操作ごとに 1 コマンド
glab mr note list 123 -F json # ディスカッションを読む
glab mr note create 123 -m "コメント" # 一般
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
Issue リンク、エピック、ネストされたグループ
- Issue リンク(
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 # バグ修正
- 大文字で始まる命令形のコミット件名(「Added feature」や「feat: add feature」ではなく「Add feature」)。GitLab は conventional-commit 件名を使用しません。
- Issue/MR を完全な URL で参照します:
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 は--body(ghのフラグ)ではなく--descriptionを使用します。これらは互換性がありません。- ワークアイテムは Issue API を使用します —
/work_items/<iid>URL →projects/.../issues/<iid>。/work_items/REST エンドポイントは 404 です。 - エピックコメントには GraphQL が必要です — REST
/notesGET+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)または GraphQL を使用します。projectはworkItems(複数形)を公開し、workItemは公開しません —projectの下では、filter:引数なしでworkItems(first: 1, iid: "IID")を使用します。単数形の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_alias—originが 1 つのインスタンスを指しているが、glab に別のリモート(例えば、gdkとして追加されたローカル GDK)をターゲットにさせたい場合は、コマンドごとにGITLAB_HOSTを設定するのではなく、glab config set remote_alias gdkを実行します。references/multi-host.md を参照してください。 - メッセージ内のバッククォート → 最初にファイルに書き込む —
`/$を-m "..."または--description "..."にインライン化しないでください。<< 'EOF'(シングルクォートされた区切り文字、重要)を使用して、自分で名前を付けたファイル(呼び出しごとに一意)に書き込み、$(cat "$FILE")で渡します。上記の「メッセージエスケープ」セクションを参照してください。 - 2 番目の同ファミリーリモートが
mr createを誤ルーティングする —originと共にsecurityミラーがある場合、非対話型のmr create(TTY なし)は、静かにフォークをヘッドとして選択します。チェックアウトごとに 1 回の修正:git config remote.origin.glab-resolved-head head。コマンドごとのフォールバック:-H <owner/repo>(-Rは修正しません)。「マージリクエストの作成」セクションを参照してください。 glab apiノート本文: ファイル →-F "body=@<file>"形式は-F "body=$(cat <file>)"よりも信頼性が高く、特に本文にシェル特殊文字が含まれる場合に有効です。glab config setは二重引用符を必要とします — 値に中括弧や特殊文字が含まれている場合:glab config set glab-resolved-head "head"(単一引用符は値の一部として保存される可能性があります)。- 出力が期待と異なる場合は
-F jsonを使用します — 特に MR リストと Issue リストでは、デフォルトのテーブルビューが一部のフィールドを切り詰めます。パイプ処理の前に-F jsonを追加すると、完全なデータが得られます。 glab ci listはデフォルトで最新の 25 パイプラインを表示します —--page 1 --per-page 100でさらに表示できます。