CommunityRedacción y edicióngithub.com

Flujo de Trabajo GitLab (GitLab Workflow Skill)

Gestión del flujo de trabajo de GitLab usando la CLI `glab` para solicitudes de fusión, incidencias y mejores prácticas de Git.

¿Qué es Flujo de Trabajo GitLab (GitLab Workflow Skill)?

Esta habilidad proporciona una guía completa para que los agentes de IA gestionen los flujos de trabajo de GitLab de manera efectiva utilizando la herramienta de línea de comandos `glab`. Cubre tareas esenciales como la creación y actualización de solicitudes de fusión (Merge Requests), la gestión de incidencias (issues) y la revisión de código, destacando reglas y trampas comunes para evitar errores costosos. Un enfoque principal es el manejo seguro de caracteres especiales del shell (como backticks y `$`) en los mensajes para evitar la sustitución de comandos y comentarios corruptos. La habilidad también aborda configuraciones complejas de múltiples instancias de GitLab, etiquetas con alcance, enlaces de incidencias, epopeyas (epics), grupos anidados y estrategias de búsqueda. Está diseñada principalmente para Claude Code, pero sus pautas son aplicables a cualquier agente que interactúe con la API de GitLab a través de `glab`, proporcionando tanto comandos de acceso directo como alternativas de API sin procesar para flujos de trabajo avanzados.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add BINGWU2003/skills

Installed? Explore more Redacción y edición skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Habilidad de Flujo de Trabajo GitLab (GitLab Workflow Skill)

Gestión del flujo de trabajo de GitLab utilizando la CLI glab para solicitudes de fusión (merge requests), incidencias (issues) y las mejores prácticas de Git.

Múltiples Instancias de GitLab

glab detecta automáticamente el host de GitLab a partir de tu remoto de git. No se necesita GITLAB_HOST cuando se trabaja dentro de un repositorio. Para remotos que no sean origin (por ejemplo, una instancia local de GDK añadida como remoto secundario), usa glab config set remote_alias <remote>. Establece GITLAB_HOST solo cuando se ejecute fuera de un repositorio de git o para un comando único dirigido a una instancia específica. Consulta references/multi-host.md para la configuración de remotos no origin y la derivación del nombre de host a partir de las URL de los remotos.

⚠️ Escape de Mensajes — Trampa Común

Si tu mensaje contiene backticks (`), $ u otros caracteres especiales del shell, NUNCA los coloques directamente en -m "...". El shell interpreta los backticks como sustitución de comandos, mutilando silenciosamente tu mensaje y produciendo errores como /bin/bash: line 1: client_name: command not found.

Esto ha causado fallos reales en producción: agentes publicando comentarios malformados en solicitudes de fusión/incidencias de GitLab, seguidos de notas correctivas de disculpa.

❌ NO HACER — backticks en línea en -m con comillas dobles

# ROTO: el shell intenta ejecutar `client_name` como un comando
glab mr note 100 -m "Use `client_name` and `wor/` here." -R org/repo
# Error: /bin/bash: line 1: client_name: command not found
# El comentario se publica como: "Use  and  here." (los identificadores se eliminan silenciosamente)

# También ROTO: los backticks escapados con barra invertida fallan en contextos anidados/scripted
glab mr note 100 -m "Use \`client_name\`" -R org/repo
# Funciona en casos simples pero falla cuando el comando está entre comillas dobles por un llamante:
# bash -c "glab mr note 100 -m \"Use \`client_name\`\""  → aún así ejecuta client_name

✅ SÍ HACER — escribir primero en un archivo, luego pasar vía $(cat ...)

Elige una ruta adecuada para tu entorno (un resultado de mktemp, un archivo tmp del espacio de trabajo con alcance, lo que sea conveniente — la habilidad no prescribe una ruta específica; los agentes eligen una que sea única para su invocación para evitar la sobrescritura en ejecuciones paralelas):

# MSG = ruta que elijas (ej. mktemp, ~/workspace/tmp/note-$$.md, etc.)
MSG=<el agente elige>

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

El delimitador de heredoc con comillas simples 'EOF' evita TODA expansión de variables/backticks al escribir el archivo. La sustitución $(cat "$MSG") es segura porque el contenido del archivo ya está escrito literalmente. Los bloques de código de triple backtick (` `` ``) también son seguros dentro de los heredocs <<'EOF' — no se necesita escapar; solo los backticks simples y $ activan la sustitución de comandos.

✅ También seguro — glab api con la bandera -f

glab api --method POST "projects/org%2Frepo/merge_requests/100/notes" \
  -f "body=$(cat "$MSG")"

⚠️ El heredoc sin comillas aún interpreta los backticks

# ROTO: delimitador EOF sin comillas — los backticks en el cuerpo aún se interpretan
cat > "$MSG" << EOF
Use `client_name` here.    # ← el shell ejecuta client_name al escribir el archivo
EOF

⚠️ El heredoc-dentro-de-heredoc rompe el análisis del shell

Si tu contenido contiene un ejemplo de heredoc con un terminador EOF sin sangría, el EOF interno en la columna 0 cierra el heredoc externo antes de tiempo:

# ROTO: el EOF interno está en la columna 0 — cierra el heredoc EXTERNO antes de tiempo
cat > "$OUTER" << 'EOF'
Here is the safe pattern:
cat > "$MSG" << 'EOF'
Use `client_name` here.
EOF
# ↑ Este EOF termina el heredoc EXTERNO — ¡las líneas siguientes se ejecutan como comandos del shell!
echo "more content..."
EOF
# ↑ Este EOF suelto se convierte en un comando: "EOF: command not found"

Solución — usa un delimitador diferente para el heredoc externo:

cat > "$OUTER" << 'OUTEREOF'
Here is the safe pattern:
  cat > "$MSG" << 'EOF'
  Use `client_name` here.
  EOF
OUTEREOF

O escribe el archivo en fragmentos — el primer fragmento usa >, los fragmentos siguientes usan >>, cada uno con su propio delimitador.

Regla general: Si el mensaje contiene `, $, ! o \ — escribe primero en un archivo con << 'EOF'. Si el contenido en sí mismo contiene sintaxis de heredoc, usa un delimitador externo único (ej. OUTEREOF, MSGEOF) que no aparezca en el cuerpo.

Creación de Solicitudes de Fusión (Merge Requests)

Pasa siempre --push y -H <owner/repo>. Sin --push, es posible que la rama aún no exista en ningún remoto. Sin -H, glab puede elegir el remoto incorrecto (ej. un espejo de seguridad) como proyecto de origen, creando la solicitud de fusión desde el fork equivocado.

¿Segundo remoto de la misma familia? En un clon con tanto origin (gitlab-org/gitlab) como un espejo security (gitlab-org/security/gitlab), glab mr create ejecutado de forma no interactiva (sin TTY, como ejecutan los agentes) elige silenciosamente el fork security como cabeza y falla con 400 {source_branch: [does not exist]}. Solución duradera, establecer una vez por clon: git config remote.origin.glab-resolved-head head. Alternativa por comando para clones nuevos: pasa -H <owner/repo> (ej. -H gitlab-org/gitlab). -R no soluciona esto — solo fija el repositorio base, no la cabeza.

# Solicitud de fusión simple
glab mr create --push -H <owner/repo> --title "Add feature" --description "Brief description" --assignee <username>

# Solicitud de fusión compleja - escribir la descripción en un archivo primero (elige tu propia ruta)
glab mr create --push -H <owner/repo> --title "Add feature" --description "$(cat "$DESC")" --assignee <username>

Plantillas: Revisa .gitlab/merge_request_templates/ para plantillas específicas del proyecto.

Lista completa de banderas (Claude Code la inyecta automáticamente; otros agentes deben ejecutarla):

!glab mr create --help

Actualización de Solicitudes de Fusión

glab mr update <number> --description "$(cat "$DESC")"
glab mr view <number> -R <owner>/<repo>

Gestión de Incidencias (Issues)

La lista de banderas completa y siempre actualizada (Claude Code la inyecta automáticamente; otros agentes deben ejecutarla):

!glab issue --help

view, note, list, create, update funcionan como se espera. Las trampas no obvias sobre las que --help no te advertirá:

# La lista es abierta por defecto y NO tiene bandera --state — usa --closed / --all en su lugar
glab issue list --closed -R <owner>/<repo>
glab issue list --all    -R <owner>/<repo>

# Etiquetas — usa --label / --unlabel, NUNCA la sintaxis +label o -label
glab issue update 123 --label "new-label"
glab issue update 123 --unlabel "old-label"
# Las etiquetas con ámbito se reemplazan automáticamente dentro de su ámbito — no se necesita --unlabel:
glab issue update 123 --label "status::doing"   # elimina cualquier etiqueta status:: existente

# Mensajes con backticks/$ — escribe primero en un archivo (ver Escape de Mensajes arriba)
glab issue note <number> -m "$(cat "$MSG")" -R <owner>/<repo>

Para transiciones de estado de incidencias (cerrar/reabrir vía API) y publicación de notas usando glab api: references/issue-api.md

Elementos de Trabajo (Work Items)

GitLab está migrando las incidencias a elementos de trabajo. La URL muestra /work_items/<iid> pero la API REST es la misma.

# ✅ Usa la API de issues — mismo IID, mismos endpoints
glab api "projects/org%2Fproject/issues/<iid>"

# ❌ El endpoint REST /work_items/ no existe
glab api "projects/org%2Fproject/work_items/<iid>"   # → 404

Análisis de URL: https://gitlab.com/org/project/-/work_items/539076 → glab api "projects/org%2Fproject/issues/539076"

Detalles completos, alternativa GraphQL, elementos de trabajo a nivel de grupo y el widget de plan de agente (Workplan): references/work-items.md

Revisión de Solicitudes de Fusión (MR Review)

Desde glab v1.94.0, glab mr note maneja todas las formas comunes de comentarios en solicitudes de fusión (lista, general, en línea de diferencia, respuesta, resolver/reabrir) sin necesidad de llamadas directas a glab api u objetos position construidos manualmente. Prefiérelo para cualquier flujo de trabajo de un solo comentario. El IID de la solicitud de fusión es un argumento posicional (no --mr); omítelo para que se detecte automáticamente desde la rama actual.

# ✅ Usa glab mr note para leer/escribir/responder/resolver — un solo comando por operación
glab mr note list 123 -F json                                       # leer discusiones
glab mr note create 123 -m "comment"                                # general
glab mr note create 123 --file main.go --line 42 -m "..."           # comentario de diferencia
glab mr note create 123 --reply abc12345 -m "..."                   # respuesta
glab mr note resolve 123 abc12345                                   # resolver hilo

# ❌ NO uses glab api .../discussions para estas operaciones
glab api "projects/<id>/merge_requests/123/discussions"             # usa mr note list
glab api --method PUT ".../discussions/<id>" -f resolved=true       # usa mr note resolve

Lista completa de banderas para los subcomandos anteriores (Claude Code la inyecta automáticamente; otros agentes deben ejecutarla):

!glab mr note --help

Recurre a glab api .../draft_notes sin procesar solo para revisiones borrador por lotes (múltiples comentarios en línea publicados juntos vía bulk_publish) — glab mr note no tiene modo borrador.

Referencia completa (todas las banderas, sugerencias de código, alternativa de borradores/lotes, objetos position): references/mr-review.md

Enlaces de Incidencias, Epopeyas y Grupos Anidados

Listado y Filtrado de Solicitudes de Fusión

Lista completa de banderas (Claude Code la inyecta automáticamente; otros agentes deben ejecutarla):

!glab mr list --help

Nota: glab mr list lista las solicitudes de fusión abiertas por defecto y no tiene bandera --state o --status — usa --all, --merged o --closed para cambiar el filtro de estado.

Búsqueda

Para ejemplos completos de búsqueda (instancia / grupo / proyecto, tabla de ámbito, paginación): references/search.md

Referencia rápida:

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 '.[]'

Convenciones de Git y Commits

Sigue las propias convenciones de git del repositorio cuando estén presentes (un proyecto puede documentarlas y aplicarlas con un linter de commits). Valores predeterminados de GitLab:

git checkout -b feature/description   # ramas de características
git checkout -b fix/description       # correcciones de errores
  • Asuntos de commit en imperativo y con mayúscula inicial ("Add feature", no "Added feature" ni "feat: add feature"); GitLab no usa asuntos de commit convencionales.
  • Referencia a incidencias/solicitudes de fusión con URL completas: Closes https://gitlab.com/org/project/-/issues/123.
  • Usa comillas simples en los mensajes de commit que contengan caracteres especiales: git commit -m 'Add note from https://gitlab.com/org/project/-/merge_requests/123'.

Pautas para el Agente

Las secciones anteriores cubren los flujos de trabajo comunes. Estas son las trampas no obvias y peculiaridades de la API que son fáciles de equivocar y no se pueden descubrir desde glab <cmd> --help:

  1. Lee el contexto primero — glab issue view / glab mr view antes de implementar; revisa .gitlab/issue_templates/ y .gitlab/merge_request_templates/ en busca de plantillas
  2. --jq funciona en subcomandos, no en glab api — glab issue list/glab mr list/glab ci list aceptan una bandera global --jq (filtra la salida JSON); glab api no — canaliza su salida a través de | jq '...'
  3. No hay bandera --body — glab usa --description, no --body (que es una bandera de gh); no son intercambiables
  4. Los elementos de trabajo usan la API de issues — URLs /work_items/<iid> → projects/.../issues/<iid>; el endpoint REST /work_items/ es un 404
  5. Los comentarios de epopeyas necesitan GraphQL — REST /notes GET+POST ambos → 404 (aún cierto en GitLab 19.1); pasa body/noteableId como variables de GraphQL, nunca interpoles cadenas. Ver references/epic-comments.md
  6. No hay -R para API a nivel de grupo — -R espera OWNER/REPO; los endpoints de grupo usan glab api "groups/..." directamente
  7. Grupos anidados REST: %2F — groups/org%2Fsubgroup/epics; barras sin codificar → 404
  8. El iid de GraphQL es una Cadena — workItem(iid: "16428") no workItem(iid: 16428)
  9. groups/<id>/work_items es 404 — usa groups/<id>/epics (REST) o GraphQL
  10. project expone workItems (plural), no workItem — bajo project usa workItems(first: 1, iid: "IID") sin argumento filter:; el campo singular workItem(iid:) existe solo bajo group/namespace
  11. Cerrar/reabrir epopeyas vía REST — state_event=close/reopen en PUT groups/<id>/epics/<iid> funciona; no se necesita GraphQL
  12. Las etiquetas con ámbito se reemplazan automáticamente — --label "status::doing" elimina cualquier etiqueta status::* existente; no se necesita --unlabel (esto es un hecho de la plataforma, cierto en general a través de la API, no solo de glab)
  13. Comentarios idempotentes → --unique — glab mr note create -m "..." --unique omite la publicación si ya existe un cuerpo idéntico; coincide solo con el cuerpo, por lo que cuerpos idénticos en líneas de diferencia diferentes aún se publican
  14. Remotos no origin → remote_alias — si origin apunta a una instancia pero quieres que glab apunte a otro remoto (ej. un GDK local añadido como gdk), ejecuta glab config set remote_alias gdk en lugar de configurar GITLAB_HOST por comando. Ver references/multi-host.md
  15. Backticks en mensajes → escribe primero en un archivo — nunca coloques `/$ en línea en -m "..." o --description "..."; escribe en un archivo que nombres (único por invocación) usando << 'EOF' (delimitador entre comillas simples, crítico), luego pasa vía $(cat "$FILE"). Ver la sección de Escape de Mensajes arriba.
  16. El segundo remoto de la misma familia desvía mr create — con un espejo security junto a origin, mr create no interactivo (sin TTY) elige silenciosamente el fork como cabeza. Solución única por clon: git config remote.origin.glab-resolved-head head; alternativa por comando: -H <owner/repo> (-R no lo soluciona). Ver la sección "Creación de Solicitudes de Fusión".
  17. Cuerpo de nota glab api: archivo → `-F "body=@file"

Skills relacionados