¿Qué hace git-coda — Ship de un solo clic?
git-coda es el nombre del proyecto; coda (final) es la sección de cierre de una pieza musical, que condensa toda la historia de desarrollo en una sola nota y la devuelve a main. El verbo del flujo de trabajo sigue siendo ship.
Objetivo y criterio de éxito
Tomar los cambios del directorio de trabajo actual y recorrer completamente esta ruta:
Cambios actuales → crear nueva rama desde el último main → commit → PR → squash merge → volver a main
Cuando el usuario invoca ship, otorga autorización para ejecutar todo el flujo de trabajo. El proceso debe completarse de forma continua, sin solicitar confirmación sobre el nombre de la rama, el mensaje de commit, el título del PR, el cuerpo del PR, la solución de conflictos, la verificación o si debe continuar.
Esta autorización incluye:
- Modificar el código funcional actual para que sea compatible con la funcionalidad en línea del último
main. - Modificar los problemas de tests, lint, tipos, compilación y CI causados por este cambio o por conflictos.
- Crear los commits de reparación necesarios y volver a subir.
- Sincronizar el último
mainantes de fusionar, resolver nuevos conflictos y volver a validar.
El flujo solo se considera completo cuando se cumplen TODAS las condiciones siguientes:
- El PR se ha fusionado exitosamente en
main. "PR creado" o "fusión automática habilitada" no se consideran completos. - Las comprobaciones obligatorias han pasado, o el repositorio no tiene comprobaciones ejecutables.
- Localmente se vuelve a
mainy se avanza rápidamente (fast-forward) hasta el commit fusionado.
Principios de ejecución centrales
- El resultado predeterminado de
shipes "publicación exitosa", no "encontrar un problema y devolvérselo al usuario". - Cuando un comando falla, primero diagnostica la causa y restaura el flujo; no repitas mecánicamente el mismo comando fallido.
- Usa la capacidad en línea actual de
origin/mainy el objetivo del producto de los cambios actuales como restricciones comunes; prioriza conservar ambas. - Repara la causa raíz, no fabriques aprobaciones falsas saltándote tests, eliminando aserciones, desactivando reglas o usando
--no-verify. - No uses force push,
reset --hard, descartar commits o sobrescribir cambios del usuario. - Solo detente y explica la única acción necesaria del usuario cuando falte autenticación/permisos, se requiera aprobación de otros, la plataforma o red esté persistentemente caída, o la intención de los requisitos no pueda determinarse a partir del código y el contexto.
Paso 0: Recopilación de información
Antes de comenzar, verifica el estado actual:
git status --short --branch
git branch --show-current
git diff --stat
git diff --cached --stat
git remote -v
gh auth status
Registra la rama actual, los cambios sin commit y los commits sin subir para evitar perder el trabajo del usuario. Si no hay cambios sin commit, verifica si la rama actual tiene commits por publicar en relación con origin/main; si no hay ninguno, indica que no hay contenido que publicar y detente.
Determina automáticamente la siguiente información:
1. Nombre de la rama
- Si el usuario ya lo ha proporcionado, úsalo directamente.
- De lo contrario, infiérelo según el contenido de los cambios, con el formato
<type>/<short-desc>. - Sigue los prefijos o reglas de nomenclatura de ramas existentes en el repositorio de destino; si no hay reglas, usa un nombre semántico.
- Si ya existe una rama local o remota con el mismo nombre, añade automáticamente un sufijo corto para evitar interrupciones por conflicto de nombres.
2. Mensaje de commit
- Si el usuario ya lo ha proporcionado, úsalo directamente.
- De lo contrario, genera un formato Conventional Commits basado en el diff completo:
<type>(<scope>): <description>.
3. Título y cuerpo del PR
- El título del PR usa por defecto el mensaje de commit.
- El cuerpo del PR se genera automáticamente a partir del diff, con 2-3 puntos de resumen, una vista general de los archivos modificados y los resultados de verificación.
- No preguntes por separado el nombre o el cuerpo del PR.
Después de determinar estos datos, informa brevemente al usuario la rama y el commit que se usarán, y continúa inmediatamente sin esperar respuesta.
Paso 1: Sincronizar la rama principal
Cuando haya cambios en el área de trabajo, crea primero un stash con un identificador único y registra la referencia correspondiente; si no hay cambios, no crees un stash vacío.
git stash push --include-untracked -m "git-coda: <timestamp>"
git fetch --prune origin
Después de fetch, verifica los commits por publicar usando la rama original y el HEAD original registrados en el paso 0 como referencia. Si la rama de características original ya tiene commits, conserva esa rama, fusiona directamente origin/main y luego restaura el stash actual; no decidas creando primero una rama desde main. Solo cuando la rama original no tenga commits por publicar, crea una rama de publicación desde origin/main.
Primero verifica la rama principal de destino desde el HEAD remoto o la configuración del repositorio; en adelante, main es un nombre provisional. Si el repositorio usa master u otro nombre, reemplázalo en todas partes por la rama real.
Informa al usuario del hash del commit de la rama principal más reciente.
Si el main local no puede hacer fast-forward:
- Verifica los commits exclusivos locales; no los elimines ni sobrescribas.
- Crea la rama de publicación directamente desde el último
origin/mainy continúa el flujo de publicación. - Al volver a
main, conserva estos commits locales e indica explícitamente que elmainlocal no ha sido sobrescrito; esto no afecta la fusión en línea ya completada.
Paso 2: Crear la rama
git checkout -b <branch-name> origin/main
Si el trabajo actual ya está en una rama de características con commits por publicar, puedes continuar usándola; primero fusiona el último origin/main y resuelve los problemas según el "Flujo de manejo de conflictos". No vuelvas a hacer commit de los mismos cambios.
Paso 3: Restaurar cambios y hacer commit
git stash apply <recorded-stash>
git add -A
git commit -m "<commit-message>"
Si stash apply produce conflictos, resuélvelos según el "Flujo de manejo de conflictos". Una vez que confirmes que todos los cambios han sido restaurados y confirmados, elimina el stash creado; no elimines por error stashes existentes del usuario.
Si el hook de commit falla, es una falla de verificación: repara la causa raíz, vuelve a preparar y a hacer commit. No uses --no-verify.
Flujo de manejo de conflictos
Este flujo aplica para: stash apply, fusión del último main, rama remota no fast-forward, y conflictos de fusión de PR.
-
Obtén los hechos:
git status git diff --name-only --diff-filter=U git log --oneline --left-right origin/main...HEAD -
Revisa uno por uno los archivos en conflicto, sus versiones base, la rama actual y la rama remota, y lee las funciones, tests, tipos, configuraciones y commits recientes relacionados. No mires solo las marcas de conflicto ni elijas ciegamente
oursotheirspara todo el archivo. -
Determina la intención de ambas partes:
origin/mainrepresenta el comportamiento en línea actual; a menos que esta funcionalidad lo reemplace explícitamente, debe conservarse.- La rama actual representa el objetivo de esta funcionalidad; no se debe eliminar silenciosamente para resolver el conflicto.
- Cuando ambas partes añadan capacidades válidas, integra interfaces, flujos de datos y condiciones de contorno para que ambas coexistan.
- Los conflictos de tests se actualizan según el comportamiento final del producto; los archivos de bloqueo y archivos generados se regeneran con la herramienta especificada por el repositorio.
-
Edita hasta que no haya marcas de conflicto, ejecuta
git addy confirma quegit diff --name-only --diff-filter=Uesté vacío. -
Ejecuta la verificación mínima relacionada con los archivos en conflicto y luego la verificación completa requerida por el repositorio.
-
Crea un commit de fusión o reparación y continúa con el flujo original.
Si no puedes determinar la solución solo con los bloques de conflicto, continúa recopilando evidencia de la implementación, tests, cadena de llamadas, historial de commits y documentación del proyecto. Solo cuando los dos comportamientos sean mutuamente excluyentes y la intención del producto aún sea indeterminable, pregunta al usuario, presentando opciones, impacto y recomendación de una sola vez.
Paso 3.5: Verificación local
Basándote en los cambios actuales y la documentación del repositorio, busca comandos de verificación existentes:
- Lee primero
AGENTS.md,CONTRIBUTING.mdyREADME.md. - Luego revisa archivos del proyecto como
package.json,pyproject.toml,Makefile, configuración de CI, etc. - Si es necesario, instala dependencias usando el gestor de paquetes existente del proyecto según el archivo de bloqueo; no actualices dependencias por iniciativa propia.
- Primero ejecuta las verificaciones directamente relacionadas con el alcance de los cambios, luego ejecuta lint, typecheck, test o build según lo requerido por el repositorio.
- Si no encuentras comandos confiables, informa claramente al usuario qué verificaciones se omitieron y por qué; no inventes comandos.
Ciclo de reparación de fallos de verificación
No te detengas ante fallos de verificación. Sigue este ciclo:
- Conserva la salida completa del error, localiza la primera causa raíz; no solo repares el último error en cadena.
- Determina si el fallo proviene del código del producto, expectativas de tests, tipos, formato, dependencias, configuración o entorno.
- Realiza la corrección mínima correcta que satisfaga la funcionalidad en línea y la funcionalidad actual:
- Prioriza el formateador existente del repositorio o el autofix de lint, luego maneja los problemas restantes.
- Corrige defectos de código.
- Actualiza tests solo cuando esta funcionalidad cambie intencionalmente el comportamiento y la expectativa original esté obsoleta; no debilites, omitas ni elimines tests válidos.
- Si falta una dependencia del entorno, restáurala según el archivo de bloqueo del proyecto; no realices actualizaciones no relacionadas.
- Vuelve a ejecutar primero la verificación mínima fallida, luego todas las verificaciones obligatorias.
- Si aparecen nuevos fallos, continúa diagnosticando y reparando hasta que todos pasen.
Las reparaciones antes del primer push pueden incluirse en el commit actual; las reparaciones después del primer push crean un nuevo commit y se suben normalmente. No uses force push para reorganizar el historial. Mientras cada ronda tenga nuevas pruebas o progreso sustancial, continúa avanzando; no te rindas por el número de fallos.
Paso 4: Subir y crear PR
git push -u origin <branch-name>
Cuando el push sea rechazado, clasifica y maneja:
- Si la rama remota con el mismo nombre no está relacionada: cambia automáticamente a un nombre de rama único y sube.
- Si la rama remota con el mismo nombre pertenece a la misma funcionalidad y tiene nuevos commits: después de fetch, fusiona la rama remota, resuelve conflictos, verifica y vuelve a subir.
- Si hay un fallo temporal de red o de GitHub: reintenta brevemente y verifica la recuperación del servicio.
- Si falta autenticación o permisos de escritura: conserva el trabajo completo y pide al usuario que complete la autorización.
Usa gh pr create para crear el PR:
- base:
main - head: la nueva rama
- título: el mensaje de commit
- cuerpo: incluye 2-3 puntos de resumen, una vista general de los archivos modificados, resultados de verificación y
🤖 Finale via git-coda
Si el PR ya existe, reutilízalo; no crees uno duplicado. Después de crearlo, muestra la URL del PR al usuario y continúa sin esperar respuesta.
Paso 5: Esperar CI y reparar
Usa comandos disponibles como gh pr checks <pr-number> --watch para esperar las comprobaciones obligatorias.
Cuando las comprobaciones fallen:
- Usa comandos como
gh pr checksogh run view --log-failedpara leer las tareas fallidas y sus registros. - Si se puede reproducir localmente, hazlo primero y luego repara la causa raíz siguiendo el "Ciclo de reparación de fallos de verificación".
- Haz commit de la reparación y sube normalmente; espera nuevamente la CI.
- Repite hasta que todas las comprobaciones obligatorias pasen.
Si las comprobaciones están pendientes durante mucho tiempo, verifica el workflow, la cola de concurrencia y el estado de GitHub; si puedes volver a ejecutar tareas fallidas, hazlo tú mismo. Solo pide intervención del usuario si las tareas requieren aprobación de alguien con permisos o si el servicio externo está persistentemente caído.
Paso 6: Sincronizar el último main y hacer squash merge
Antes de fusionar, sincroniza de nuevo la rama principal:
git fetch origin main
git merge --no-edit origin/main
Si hay conflictos, resuélvelos según el "Flujo de manejo de conflictos", vuelve a ejecutar la verificación local, sube y espera la CI. Luego fusiona directamente:
gh pr merge <pr-number> --squash --delete-branch
Si al fusionar se indica que la base se ha actualizado o hay conflictos, repite el ciclo de sincronización, resolución, verificación, subida y espera de CI, y vuelve a fusionar. Si el repositorio admite cola de fusión, espera en la cola hasta confirmar que el PR se ha fusionado realmente.
No omitas la protección de rama. Si faltan aprobaciones obligatorias, firmas o permisos, es un bloqueo externo: muestra la información exacta devuelta por GitHub, indica los pasos ya completados y la única acción que debe realizar el usuario.
Paso 7: Volver a main y confirmar el resultado
git checkout main
git pull --ff-only origin main
git status --short --branch
gh pr view <pr-number> --json state,mergedAt,mergeCommit,url
Confirma que el estado del PR es "merged" e imprime el hash final del commit de main. Si el main local tiene commits exclusivos preexistentes que impiden el fast-forward, consérvalos; no realices acciones destructivas. Aun así, confirma que el PR remoto se ha fusionado y explica claramente el estado local.
Imprime el estado final:
🚀 ¡Ship completado!
✓ La rama <branch-name> se ha fusionado en main
✓ Verificación local y CI obligatoria aprobadas
✓ Actualmente en main, sincronizado con el último código (<commit-hash>)
✓ PR: <pr-url>
Principios de manejo de errores
- Antes de cada paso, indica brevemente lo que se está haciendo.
- Cuando un comando falle, primero diagnostica, repara y reintenta, siempre con el objetivo de fusionar con éxito.
- No uses force push,
reset --hardu otros métodos destructivos de restauración. - Resuelve conflictos de forma proactiva, protegiendo tanto la funcionalidad en línea más reciente como el objetivo de la funcionalidad actual.
- Repara de forma proactiva fallos en tests, lint, type-checking, compilación, hooks de commit y CI.
- No solicites confirmación sobre el nombre de la rama inferido, el mensaje de commit, el título del PR, el cuerpo del PR o la continuación del flujo.
- No consideres fallos reparables, depuración de múltiples rondas o demoras en el flujo como bloqueos.
- Solo detente ante condiciones externas que el entorno actual no pueda resolver; conserva la rama, los commits y los registros para que el trabajo pueda continuar.
- Al detenerte, proporciona solo la acción de usuario clara, mínima y ejecutable; una vez completada, puedes continuar desde la misma posición.
Casos límite comunes
| Situación | Manejo |
|---|---|
| Estás en una rama que no es main y solo hay cambios en el área de trabajo | stash → crear rama desde origin/main → apply → resolver conflictos |
| La rama actual ya tiene commits por publicar | Conservar los commits, fusionar el último origin/main y continuar |
| No hay cambios sin commit | Verificar commits por publicar respecto a origin/main; detenerse solo si no hay ninguno |
| El nombre de la rama ya existe | Generar automáticamente un sufijo único; si la rama remota es para la misma funcionalidad, reutilizar e integrar |
Conflicto en stash apply o fusión | Analizar la intención funcional de ambas partes, integrar la implementación, verificar y continuar |
| Falla de lint/test/typecheck/build | Reparar la causa raíz y repetir verificación cíclicamente; no pasar la falla al usuario |
| Falla de CI | Leer registros, reproducir localmente, reparar, subir y esperar la siguiente ronda de CI |
| main se actualiza antes de fusionar | Fusionar el último origin/main, resolver conflictos y volver a pasar por el ciclo de verificación |
gh no ha iniciado sesión | Indicar que ejecute gh auth login |
| Se requiere aprobación humana o no tienes permisos de escritura | Conservar el estado, explicar la única acción externa que debe completar el usuario |
El usuario especifica --no-squash | Usar --merge |