Skill de Fluxo de Trabalho GitLab
Gerenciamento de fluxo de trabalho GitLab usando a CLI glab para merge requests, issues e melhores práticas Git.
Múltiplas Instâncias GitLab
glab detecta automaticamente o host GitLab a partir do seu remote git. GITLAB_HOST não é necessário quando trabalhando dentro de um repositório. Para remotes que não são origin (por exemplo, uma instância GDK local adicionada como um remote secundário), use glab config set remote_alias <remote>. Defina GITLAB_HOST apenas ao executar fora de um repositório git ou para um comando único visando uma instância específica. Consulte references/multi-host.md para configuração de remote não-origin e derivação de hostname a partir de URLs remotas.
⚠️ Escape de Mensagens — Armadilha Comum
Se sua mensagem contiver crases (`), $ ou outros caracteres especiais do shell, NUNCA os coloque diretamente em -m "...". O shell interpreta crases como substituição de comando, silenciosamente corrompendo sua mensagem e produzindo erros como /bin/bash: line 1: client_name: command not found.
Isso já causou falhas de produção reais: agentes postando comentários malformados em MRs/issues do GitLab, seguidos de notas corretivas de desculpas.
❌ NÃO FAÇA — colocar crases inline em -m com aspas duplas
# QUEBRADO: o shell tenta executar `client_name` como um comando
glab mr note 100 -m "Use `client_name` e `wor/` aqui." -R org/repo
# Erro: /bin/bash: line 1: client_name: command not found
# O comentário é postado como: "Use e aqui." (identificadores removidos silenciosamente)
# Também QUEBRADO: crases escapadas com barra invertida quebram em contextos aninhados/de script
glab mr note 100 -m "Use \`client_name\`" -R org/repo
# Funciona em casos simples, mas falha quando o comando é entre aspas duplas por um chamador:
# bash -c "glab mr note 100 -m \"Use \`client_name\`\"" → ainda executa client_name
✅ FAÇA — escreva em um arquivo primeiro, depois passe via $(cat ...)
Escolha um caminho apropriado para seu ambiente (um resultado mktemp, um arquivo tmp no workspace, o que for adequado — o skill não prescreve um caminho específico; agentes escolhem um único para sua invocação para evitar conflitos em execuções paralelas):
# MSG = caminho que você escolher (ex.: mktemp, ~/workspace/tmp/note-$$.md, etc.)
MSG=<agente escolhe>
cat > "$MSG" << 'EOF'
Use `client_name` e `wor/` aqui. A ferramenta `glab` lida com isso.
EOF
glab mr note 100 -m "$(cat "$MSG")" -R org/repo
O delimitador heredoc com aspas simples 'EOF' impede TODA expansão de variável/crase ao escrever o arquivo. A substituição $(cat "$MSG") é segura porque o conteúdo do arquivo já foi escrito literalmente. Blocos de código com crases triplas (```) também são seguros dentro de heredocs <<'EOF' — nenhum escape é necessário; apenas crases simples e $ acionam substituição de comando.
✅ Também seguro — glab api com flag -f
glab api --method POST "projects/org%2Frepo/merge_requests/100/notes" \
-f "body=$(cat "$MSG")"
⚠️ Heredoc sem aspas ainda interpreta crases
# QUEBRADO: delimitador EOF sem aspas — crases no corpo ainda são interpretados
cat > "$MSG" << EOF
Use `client_name` aqui. # ← o shell executa client_name ao escrever o arquivo
EOF
⚠️ Heredoc dentro de heredoc quebra a análise do shell
Se seu conteúdo contiver um exemplo de heredoc com um terminador EOF sem indentação, o EOF interno na coluna 0 fecha o heredoc externo prematuramente:
# QUEBRADO: o EOF interno está na coluna 0 — ele fecha o heredoc EXTERNO prematuramente
cat > "$OUTER" << 'EOF'
Aqui está o padrão seguro:
cat > "$MSG" << 'EOF'
Use `client_name` aqui.
EOF
# ↑ Este EOF termina o heredoc EXTERNO — as linhas abaixo são executadas como comandos shell!
echo "mais conteúdo..."
EOF
# ↑ Este EOF solto se torna um comando: "EOF: command not found"
Correção — use um delimitador diferente para o heredoc externo:
cat > "$OUTER" << 'OUTEREOF'
Aqui está o padrão seguro:
cat > "$MSG" << 'EOF'
Use `client_name` aqui.
EOF
OUTEREOF
Ou escreva o arquivo em partes — a primeira parte usa >, as partes subsequentes usam >>, cada uma com seu próprio delimitador.
Regra prática: Se a mensagem contiver `, $, ! ou \ — escreva em um arquivo com << 'EOF' primeiro, sempre. Se o conteúdo em si contiver sintaxe heredoc, use um delimitador externo único (ex.: OUTEREOF, MSGEOF) que não apareça no corpo.
Criando Merge Requests
Sempre passe --push e -H <owner/repo>. Sem --push, o branch pode não existir em nenhum remote ainda. Sem -H, glab pode escolher o remote errado (ex.: um mirror de segurança) como o projeto de origem, criando o MR do fork errado.
Segundo remote da mesma família? Em um checkout com ambos
origin(gitlab-org/gitlab) e um mirrorsecurity(gitlab-org/security/gitlab),glab mr createexecutado não interativamente (sem TTY, como agentes executam) silenciosamente escolhe o forksecuritycomo head e falha com400 {source_branch: [does not exist]}. Correção durável, definida uma vez por checkout:git config remote.origin.glab-resolved-head head. Fallback por comando para checkouts novos: passe-H <owner/repo>(ex.:-H gitlab-org/gitlab).-Rnão corrige isso — ele fixa apenas o repositório base, não o head.
# MR simples
glab mr create --push -H <owner/repo> --title "Adicionar funcionalidade" --description "Breve descrição" --assignee <username>
# MR complexo — escreva a descrição em um arquivo primeiro (escolha seu próprio caminho)
glab mr create --push -H <owner/repo> --title "Adicionar funcionalidade" --description "$(cat "$DESC")" --assignee <username>
Modelos: Verifique .gitlab/merge_request_templates/ para modelos específicos do projeto.
Lista completa de flags (Claude Code injeta isso automaticamente; outros agentes devem executar):
!glab mr create --help
Atualizando Merge Requests
glab mr update <número> --description "$(cat "$DESC")"
glab mr view <número> -R <owner>/<repo>
Gerenciamento de Issues
A lista completa e sempre atual de flags (Claude Code injeta isso automaticamente; outros agentes devem executar):
!glab issue --help
view, note, list, create, update funcionam como esperado. As armadilhas não óbvias que
--help não irá alertar:
# Lista é aberta por padrão e NÃO tem flag --state — use --closed / --all
glab issue list --closed -R <owner>/<repo>
glab issue list --all -R <owner>/<repo>
# Labels — use --label / --unlabel, NUNCA sintaxe +label ou -label
glab issue update 123 --label "new-label"
glab issue update 123 --unlabel "old-label"
# Labels com escopo se auto-substituem dentro do seu escopo — não é necessário --unlabel:
glab issue update 123 --label "status::doing" # remove qualquer label status:: existente
# Mensagens com crases/$ — escreva em um arquivo primeiro (veja Escape de Mensagens acima)
glab issue note <número> -m "$(cat "$MSG")" -R <owner>/<repo>
Para transições de estado de issues (fechar/reabrir via API) e postagem de notas via glab api: references/issue-api.md
Itens de Trabalho
O GitLab está migrando issues para itens de trabalho. A URL mostra /work_items/<iid> mas a API REST é a mesma.
# ✅ Use a API de issues — mesmo IID, mesmos endpoints
glab api "projects/org%2Fproject/issues/<iid>"
# ❌ Endpoint REST /work_items/ não existe
glab api "projects/org%2Fproject/work_items/<iid>" # → 404
Análise de URL: https://gitlab.com/org/project/-/work_items/539076
→ glab api "projects/org%2Fproject/issues/539076"
Detalhes completos, alternativa GraphQL, itens de trabalho em nível de grupo e o widget do plano do agente (Workplan): references/work-items.md
Revisão de MR
Desde glab v1.94.0, glab mr note lida com todas as formas comuns de comentário em MR (lista, geral, linha de diff, resposta, resolver/reabrir) sem chamadas raw glab api ou objetos position construídos manualmente. Prefira-o para qualquer fluxo de trabalho de comentário único. O IID do MR é um argumento posicional (não --mr); omita-o para detecção automática a partir do branch atual.
# ✅ Use glab mr note para leitura/escrita/resposta/resolução — comando único por operação
glab mr note list 123 -F json # ler discussões
glab mr note create 123 -m "comentário" # geral
glab mr note create 123 --file main.go --line 42 -m "..." # comentário de diff
glab mr note create 123 --reply abc12345 -m "..." # resposta
glab mr note resolve 123 abc12345 # resolver thread
# ❌ NÃO use glab api .../discussions para essas operações
glab api "projects/<id>/merge_requests/123/discussions" # use mr note list
glab api --method PUT ".../discussions/<id>" -f resolved=true # use mr note resolve
Lista completa de flags para os subcomandos acima (Claude Code injeta isso automaticamente; outros agentes devem executar):
!glab mr note --help
Recorra ao raw glab api .../draft_notes apenas para revisões de rascunho em lote (múltiplos comentários inline publicados juntos via bulk_publish) — glab mr note não tem modo de rascunho.
Referência completa (todas as flags, sugestões de código, fallback de rascunhos/lote, objetos position): references/mr-review.md
Links de Issues, Épicos e Grupos Aninhados
- Links de issues (
blocked_by,relates_to): references/issue-links.md - CRUD de épicos (criar, listar, atualizar, fechar): references/epics.md
- Comentários de épicos (GraphQL leitura/escrita, paginação — REST retorna 404): references/epic-comments.md
- Grupos aninhados (codificação
%2F): references/nested-groups.md
Listagem e Filtragem de MR
Lista completa de flags (Claude Code injeta isso automaticamente; outros agentes devem executar):
!glab mr list --help
Nota: glab mr list lista MRs abertos por padrão e não tem flag --state ou --status —
use --all, --merged ou --closed para alterar o filtro de estado.
Pesquisa
Para exemplos completos de pesquisa (instância/grupo/projeto, tabela de escopo, paginação): references/search.md
Referência rápida:
glab api "search?scope=issues&search=<consulta>" | jq '.[] | {iid, title}'
glab api "groups/<grupo>/search?scope=merge_requests&search=<consulta>" | jq '.[]'
glab api "projects/<org>%2F<repo>/search?scope=issues&search=<consulta>" | jq '.[]'
Convenções de Git e Commits
Siga as próprias convenções do repositório quando presentes (um projeto pode documentá-las e aplicá-las com um linter de commits). Padrões do GitLab:
git checkout -b feature/description # branches de funcionalidade
git checkout -b fix/description # correções de bugs
- Assuntos de commit capitalizados e imperativos ("Adicionar funcionalidade", não "Funcionalidade adicionada" ou "feat: adicionar funcionalidade"); GitLab não usa assuntos de commit convencionais.
- Referencie issues/MRs com URLs completas:
Closes https://gitlab.com/org/project/-/issues/123. - Coloque mensagens de commit com aspas simples contendo caracteres especiais:
git commit -m 'Adicionar nota de https://gitlab.com/org/project/-/merge_requests/123'.
Diretrizes para Agentes
As seções acima cobrem os fluxos de trabalho comuns. Estas são as armadilhas não óbvias e
peculiaridades da API que são fáceis de errar e não são descobertas a partir de glab <cmd> --help:
- Leia o contexto primeiro —
glab issue view/glab mr viewantes de implementar; verifique.gitlab/issue_templates/e.gitlab/merge_request_templates/por modelos --jqfunciona em subcomandos, não emglab api—glab issue list/glab mr list/glab ci listaceitam uma flag global--jq(filtra saída JSON);glab apinão — pipie sua saída através de| jq '...'- Sem flag
--body— glab usa--description, não--body(que é uma flaggh); eles não são intercambiáveis - Itens de trabalho usam a API de issues — URLs
/work_items/<iid>→projects/.../issues/<iid>; o endpoint REST/work_items/é um 404 - Comentários de épicos precisam de GraphQL — GET+POST REST
/notesambos → 404 (ainda verdadeiro no GitLab 19.1); passebody/noteableIdcomo variáveis GraphQL, nunca interpolando strings. Veja references/epic-comments.md - Sem
-Rpara API de nível de grupo —-ResperaOWNER/REPO; endpoints de grupo usamglab api "groups/..."diretamente - Grupos aninhados REST:
%2F—groups/org%2Fsubgroup/epics; barras sem codificação → 404 - GraphQL iid é uma String —
workItem(iid: "16428")nãoworkItem(iid: 16428) groups/<id>/work_itemsé 404 — usegroups/<id>/epics(REST) ou GraphQLprojectexpõeworkItems(plural), nãoworkItem— sobprojectuseworkItems(first: 1, iid: "IID")sem argumentofilter:; o campo singularworkItem(iid:)existe apenas sobgroup/namespace- Fechar/reabrir épico via REST —
state_event=close/reopenemPUT groups/<id>/epics/<iid>funciona; não precisa de GraphQL - Labels com escopo se auto-substituem —
--label "status::doing"remove qualquer labelstatus::*existente; não é necessário--unlabel(isso é um fato da plataforma, verdadeiro via API em geral, não apenas glab) - Comentários idempotentes →
--unique—glab mr note create -m "..." --uniquepula a postagem se um corpo idêntico já existir; corresponde apenas ao corpo, então corpos idênticos em linhas de diff diferentes ainda são postados - Remotes não-origin →
remote_alias— seoriginaponta para uma instância, mas você quer que glab atinja outro remote (ex.: um GDK local adicionado comogdk), executeglab config set remote_alias gdkem vez de definirGITLAB_HOSTpor comando. Veja references/multi-host.md - Crases em mensagens → escreva em um arquivo primeiro — nunca coloque inline
`/$em-m "..."ou--description "..."; escreva em um arquivo que você nomeia (único por invocação) usando<< 'EOF'(delimitador com aspas simples, crítico), depois passe via$(cat "$ARQUIVO"). Veja a seção Escape de Mensagens acima. - Segundo remote da mesma família direciona mal
mr create— com um mirrorsecurityjunto comorigin,mr createnão interativo (sem TTY) silenciosamente escolhe o fork como head. Correção única por checkout:git config remote.origin.glab-resolved-head head; fallback por comando:-H <owner/repo>(-Rnão corrige isso). Veja a seção "Criando Merge Requests". glab apicorpo de nota: arquivo →-F "body=@file"