Prompts para Commits, Mensajes de Git y Ramas con IA
10 prompts para escribir commits y mensajes de Git con IA: Conventional Commits, mensajes útiles, changelogs y nombres de ramas. Adiós al 'fix'.
Tabla de contenidos
“Dije que arreglaba una cosa y acabé arreglando media vida”. Es la frase que escuchas en cada repositorio cuando alguien hace git log --oneline y ve lo que hay. Commit, fix, wip, update, cosas varias. Ciento cuarenta commits y nadie sabe qué cambió entre la versión 2.3 y la 2.4.
El problema de fix no es que sea corto. Es que no contiene información. Cuando algo se rompe en producción, git bisect te lleva al commit fix, abres el diff y hay tres archivos cambiados sin explicación. Tiempo perdido. En un equipo, tiempo perdido de todos.
Con la IA esto se arregla fácil, porque escribir un buen mensaje de commit es exactamente el tipo de tarea donde un modelo rinde: tiene el diff delante, solo hay que traducirlo a lenguaje humano. Eso sí, hay que hacerlo con un prompt que obligue a mirar el código de verdad.
Si quieres repasar los comandos base antes de nada, tienes los comandos de Git esenciales. Y si el problema que tienes no es escribir el mensaje sino resolver el conflicto, mira qué hacer con los merge conflicts cuando el código lo ha escrito una IA.
Cuatro reglas antes de tocar el prompt
1. Pasa siempre el diff. Ni una descripción oral, ni “he arreglado un bug en el login”. El diff. Si no le das el diff, la IA no puede inventar datos y tú no te fías.
2. El mensaje describe el porqué, el diff ya está. Escribir “añade validación al email” repite lo que se ve en el código. Lo útil es el porqué: qué rotura provoca, qué caso concreto falla, qué restricción obliga a hacerlo así.
3. Un commit, un cambio. Si el diff toca cinco archivos por dos razones distintas, son dos commits. Esto no es esthetismo: es lo que te deja revertir una parte sin tirar la otra.
4. Si no puedes explicarlo en una línea, quizá no deberías commitear todavía. Y si sí puedes pero no quieres, casi siempre es porque el código no está terminado. Un wip honesto vale más que un mensaje inventado.
Los prompts
1. El mensaje de commit a partir de un diff
Este es el prompt base. Guárdalo, es el que más vas a usar.
Voy a hacer commit. Aquí tienes el diff:
[pegar salida de `git diff --staged`]
Contexto de la tarea: [qué estaba intentando hacer, en una frase].
Escribe el mensaje de commit con este formato exacto:
<tipo>([ámbito opcional]): <asunto en imperativo, máx. 50 caracteres>
<parrafo en blanco>
<cuerpo: qué cambia, por qué cambia y qué problema resuelve,
entre 3 y 6 líneas, envuelto a 72 columnas>
Reglas:
- El asunto empieza en imperativo: "añade", no "añadido" ni "agregado".
- Sin punto final en el asunto.
- El cuerpo DEBE mencionar al menos un archivo o función concreto
del diff. Si no puedes citar ninguno, el mensaje está mal.
- No inventes motivos. Todo lo que afirmes debe poder deducirse del diff.
- Si el diff mezcla varios cambios sin relación, dímelo en lugar de
escribir un mensaje.
- Tono: conciso, el de un senior que no tiene tiempo para adivinar.
Devuelve solo el mensaje, entre triple backtick.
Por qué funciona: el triple backtick evita que la IA meta sus explicaciones alrededor, y la instrucción de citar archivos concretos es la que impide que se invente el motivo. Ese “si no puedes citar ninguno, el mensaje está mal” es el tipo de restricción que convierte un copiloto en un revisor.
Ejemplo real de salida dado un diff de tres archivos:
fix(auth): rejects tokens with mismatched issuer
El endpoint /refresh validaba la firma del token pero no el campo
`iss`, así que un token emitido por otro proveedor con la misma clave
se aceptaba como válido. Se añadió la comprobación en
`verifyToken()` (src/auth/token.ts:64) y se cubre con dos casos en
`token.test.ts` que antes fallaban.
Cierra la incidencia reportada por el equipo de pagos.
Fíjate en el cuerpo: cita el archivo, la línea aproximada y el síntoma. Eso es lo que hace que seis meses después alguien entienda el commit sin abrir el diff.
2. Decidir el tipo correcto (Conventional Commits)
Mucha gente escribe feat para todo. El prefijo mal puesto rompe el changelog automático y las versiones, así que merece su propio prompt.
Tengo estos cambios staged:
[pegar `git diff --staged`]
Y este era el objetivo: [descripción de la tarea].
Clasifícalo con Conventional Commits. Los tipos válidos son:
feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert.
Reglas de clasificación:
- `feat`: funcionalidad nueva visible para el usuario final.
- `fix`: corrige un comportamiento que estaba roto.
- `refactor`: cambia la estructura interna sin cambiar el comportamiento.
Si dices refactor y el diff cambia lógica, es otro tipo. Dímelo.
- `perf`: solo si hay una mejora de rendimiento medible.
- `chore`: mantenimiento sin efecto (deps, formateo, gitignore).
- `test`: solo tests.
- `ci`: solo workflows y configuración de CI.
Ámbito: la parte del sistema más pequeña que toca el cambio
(un archivo, un módulo, un endpoint). Si dudas entre dos, elige la
más específica.
Devuelve: tipo, ámbito, y una frase de justificación de por qué ese
tipo y no el otro.
Por qué funciona: la diferencia entre feat y refactor está en si el comportamiento observable cambia. La IA sabe mirarlo si se lo preguntas en el formato “por qué este y no el otro”. Ese razonamiento es justo lo que tú no quieres hacer a las 23:00.
| Prefijo | Cuándo usarlo | Ejemplo | Rompe la API pública |
|---|---|---|---|
feat | Funcionalidad nueva para el usuario | feat(api): add cursor pagination | Sí |
fix | Comportamiento roto que ya existía | fix(api): return 404 on missing tenant | No |
refactor | Estructura interna, mismo comportamiento | refactor(auth): extract token verifier | No |
perf | Ganancia medida de rendimiento | perf(db): add index on orders.customer_id | No |
test | Solo tests | test(auth): cover expired token path | No |
docs | Documentación | docs(readme): document local setup | No |
ci | Workflows y config de CI | ci: cache pnpm store between runs | No |
chore | Mantenimiento sin efecto funcional | chore: bump eslint to v9.18 | No |
revert | Reversión de algo anterior | revert: feat(api): add cursor pagination | Igual que el original |
3. El cuerpo del commit: el porqué
Casi todo el mundo escribe el asunto y deja el cuerpo vacío. El cuerpo es donde vive la información que de verdad importa.
Este es el diff de mi commit:
[pegar `git diff --staged`]
Ya tengo el asunto: `[asunto]`.
Ayúdame a escribir el CUERPO del mensaje. Quiero responder a estas
preguntas, en este orden, omittingiendo la que no aplique:
1. Qué cambia, en términos de comportamiento observable.
2. Qué problema resolvía (bug, limitación, petición) y quién lo sufría.
3. Qué alternativas descartaste y por qué (solo si es relevante).
4. Qué riesgos tiene y cómo se ha verificado.
Reglas:
- Entre 3 y 6 líneas, envolviendo a 72 columnas.
- Cita archivos y funciones concretos.
- Nada de "se ha mejorado el código" ni "refactor general".
- Si no sabes la respuesta a la pregunta 2, pregúntamelo en lugar de
inventarlo. Es preferible un hueco que una excusa.
Por qué funciona: decirle que pregunte en vez de inventar es la pieza clave. Sin esa instrucción, la IA rellena el “por qué” con una explicación verosímil pero falsa, que es el peor resultado posible porque no la vas a leer con atención.
4. Dividir un diff que mezcla dos cosas
Este diff mezcla varios cambios que deberían ser commits separados:
[pegar `git diff`]
Y este es mi objetivo: [qué estaba haciendo].
Analiza el diff y propón cómo dividirlo en commits coherentes.
Para cada uno:
- Qué archivos (o hunks) incluye.
- Cuál sería su mensaje con Conventional Commits.
- En qué orden deberían aplicarse para que cada commit compile y
los tests pasen.
Señala también cualquier archivo que no debería estar en ningún commit
por ser temporal (logs, .env, ficheros generados).
No ejecutes nada, solo el plan. Después lo aplico yo.
Por qué funciona: la mayoría de herramientas de split diff trabajan a nivel de archivo, pero un archivo puede contener tres cambios lógicos. Un modelo con el diff completo ve los hunks y propone la partición lógica, que es la que cuesta tiempo.
Si el proceso de trocear el cambio te está haciendo perder horas, antes de eso quizá merece la pena revisar la guía de prompts para programar con IA.
5. Mensajes de merge
Voy a hacer merge de la rama [nombre-rama] en [rama destino].
Commits de la rama:
[pegar `git log --oneline destino..rama`]
Archivos tocados con más cambios:
[pegar `git diff --stat destino...rama`]
Escribe el mensaje de merge en formato:
- Tipo: `merge` o el tipo convencional del cambio principal.
- Asunto: [qué aporta la rama, máx. 50 caracteres].
- Cuerpo: resumen de 2 a 4 líneas de lo que cambia respecto a la rama
destino. Menciona los cambios que rompen compatibilidad si los hay.
Reglas:
- Un mensaje de merge no repite la lista de commits. La resume.
- Si la rama es un PR completo, empieza por el objetivo ("adds"), no
por los detalles.
Por qué funciona: el mensaje de merge es el único mensaje que mucha gente lee entero. Un buen mensaje de merge responde “¿qué trae esto al repositorio?” en menos de cuatro líneas. Al darle la lista de commits y el diffstat, puede distinguir entre “añade la feature X” y “cambia 40 archivos sin propósito claro”.
6. Nombres de rama
Voy a crear una rama. El trabajo es: [descripción de la tarea].
Tipo de cambio: [feat / fix / refactor / hotfix / chore].
Número de ticket: [JIRA-123 o ninguno].
Proponme 3 nombres de rama y elige el mejor.
Formato: [tipo]/[descripcion-en-kebab-case]
- Máximo 4 palabras en la descripción.
- En inglés, minúsculas, separadas por guiones.
- Sin números de ticket en el repositorio, ponlos delante:
`jira-123/fix/token-issuer-check`.
- Que se entienda el trabajo a simple vista.
Devuelve el nombre elegido y por qué encaja con el formato del
repositorio.
Por qué funciona: los nombres de rama son un índice de búsqueda. Un feature/lo-de-la-semana-que-vino no aparece en ningún git log --all --grep. Cuando le das formato y longitud, la IA propone nombres buscables sin que tengas que pensarlo.
7. Generar el changelog desde los commits
Genera el changelog de la versión [1.4.0] a partir de estos commits:
[pegar `git log --pretty=format:"%s" v1.3.0..v1.4.0`]
[pegar `git log --pretty=format:"%b" v1.3.0..v1.4.0` si hay cuerpos]
Formato de salida: Keep a Changelog, en inglés.
Reglas:
- Agrupa por tipo: Added, Fixed, Changed, Deprecated, Removed,
Security.
- Traduce al inglés y reescribe para un lector externo. No es una
traducción literal: "arreglado el bug del login" no vale.
- Une commits relacionados en una línea. No listes 40 entradas.
- Si detectas un breaking change (por `!` o por `BREAKING CHANGE` en
el cuerpo), ponlo arriba en una sección propia con las instrucciones
de migración.
- Cada línea empieza en pasado: "Added", "Fixed", no "Adds".
- Máximo 6 líneas por categoría. Si hay más, agrupa por subsistema.
Devuelve solo el Markdown del changelog.
Por qué funciona: un changelog escrito a mano se queda sin actualizar, y ahí está el valor real de los commits estructurados. Al pedir agrupación y traducción, la IA convierte treinta commits en doce líneas legibles por alguien que no ha visto el repositorio.
8. El mensaje de error del commit hook
Aquí es donde la IA es especialmente útil, porque casi nadie invierte en estos mensajes y son los que más tiempo ahorran.
Este es el hook de pre-commit que tengo en [husky / lint-staged /
simple-git-hooks]:
[pegar el script o config]
Y este es el mensaje que sale ahora cuando falla:
[pegar la salida del error]
Reescribe el mensaje de error para que le indique a quien lo lee:
1. Qué ha fallado exactamente (regla concreta, no "error de lint").
2. En qué archivo y línea está.
3. Cómo arreglarlo, con un comando o un ejemplo.
4. Cómo saltarse la comprobación si es legítimo, con el comando real
de mi setup.
Máximo 8 líneas. Que no haya emojis ni mayúsculas sostenidas. Que sea
copiable si se puede.
Por qué funciona: los hooks por defecto escupen una salida de máquina. Traducir eso a lenguaje humano es una tarea puramente mecánica que los modelos hacen bien, porque la información ya está en el error: solo hay que organizarla.
9. Mensajes de revert y de hotfix
Voy a revertir [hash] porque [motivo: regresión en producción /
commit incorrecto / funcionalidad retirada].
Commit original:
[pegar `git show --stat [hash]`]
Escribe el mensaje de revert y el cuerpo explicativo.
Reglas:
- Formato Conventional Commits: `revert: <asunto del commit original>`.
- Cuerpo: por qué se revierte, qué impacto tenía, y si queda algún
trabajo pendiente.
- Si el revert requiere pasos manuales (migración de datos, cambios de
config), enuméralos al final del cuerpo.
Por qué funciona: el problema del revert mal documentado aparece meses después, cuando alguien pregunta por qué una funcionalidad desapareció del producto. Meter el impacto y los pasos manuales en el mensaje es lo que evita esa pregunta.
10. Revisar la serie de commits antes de abrir el PR
Antes de abrir el PR, revisa mi serie de commits:
[pegar `git log --oneline main..HEAD`]
[pegar `git diff main...HEAD --stat`]
Revísalo como si fueras el revisor del PR y busca:
- Commits con mensajes vagos (fix, update, cambios, wip).
- Cambios de comportamiento sin test que lo cubra.
- Cambios de comportamiento que no aparecen en ningún mensaje.
- Commits que deberían ser uno (mismo archivo, mismo objetivo).
- Migraciones de base de datos sin rollback.
- Cualquier cosa que rompa la API pública sin avisar.
Devuelve una tabla: commit | problema | gravedad | qué haría yo.
Si la serie está bien, dilo también.
Por qué funciona: es una revisión de tu propio trabajo antes de que la haga otra persona. La lista de comprobación la pone el prompt y el análisis lo hace el modelo, así que tardas 20 segundos en lugar de esperar dos horas a que alguien te deje un comentario.
Anti-patrones
❌ El commit que no dice nada
$ git log --oneline
a3f21bc fix
8d4e1a0 update
c9b2f77 changes
1e5f90a wip
Cuatro commits, cero información. Ahora haz git bisect y la suerte es tuya. Cada mensaje debería responder a “qué y por qué”.
✅ La misma serie con mensajes que sirven
$ git log --oneline
a3f21bc fix(auth): reject tokens with mismatched issuer
8d4e1a0 feat(api): add cursor pagination to /orders
c9b2f77 refactor(db): extract order repository from service
1e5f90a test(api): cover pagination edge cases
Ahora git bisect start a3f21bc HEAD te lleva a un commit con nombre propio, y git log --grep="pagination" te devuelve lo relacionado.
❌ Un commit que hace cuatro cosas
git add -A
git commit -m "feat(api): updates"
Cuatro archivos, un refactor, un fix y un formateo. Cuando algo falle en staging no puedes revertir solo la parte peligrosa.
✅ Partirlo antes de commitear
git diff --staged
# "Propónme cómo dividir este diff en commits coherentes"
❌ Asustar a quien lee el historial
git commit -m "WIP no funciona, lo dejo así"
git commit -m "ahora sí"
Esto en un repositorio compartido bloquea a todo el mundo. Un wip con fecha es aceptable; un wip con miedo no.
✅ Ser explícito incluso cuando está roto
git commit -m "feat(api): add rate limit middleware (tests pending)
El middleware está integrado pero falta cubrir el caso de la ventana
de rate limit reseteada. No desplegar hasta cerrar #482."
El mensaje dice qué falta, así que nadie despliega por error.
Errores frecuentes
“La IA se inventa el motivo del cambio”. Siempre que no le pases el diff. Si solo le dices “arreglé el fallo del login”, te va a escribir un motivo verosímil que puede no ser el real. Con el diff delante y la instrucción de citar archivos, el invento es detectable.
“Me pone en modo humano y me pasa el mensaje a 40 líneas”. Me ha pasado: le pedía “explica el porqué” y me devolvía medio párrafo por commit. Se arregla poniendo el límite de palabras en el prompt y recordándole que hay gente que lee cien commits al día.
“Uso Conventional Commits y el prettier me parte las líneas”. Si tienes un formateador con longitud de línea, el cuerpo del commit se reformatea. Configura el formateador para que no toque los ficheros de mensaje de commit, o genera el mensaje fuera del editor.
“Mi equipo no usa Conventional Commits”. Perfecto, los prompts funcionan igual. Quita el paso del tipo y quédate con el cuerpo. El prefijo es útil, no obligatorio.
“Los commits generados se ven demasiado mecánicos”. Si todos empiezan igual y suenan idénticos, usa el prompt 1 para el asunto y el prompt 3 para el cuerpo por separado. Salen más naturales porque cada parte se genera con su propia instrucción.
“Me genera mensajes larguísimos”. Añade al final del prompt: “máximo 50 caracteres en el asunto, máximo 5 líneas en el cuerpo”. Sin eso, los modelos tienden a explicar de más, igual que hacemos nosotros cuando tenemos sueño.
El flujo completo
Cambios en el working tree
│
▼
┌───────────────┐
│ git add -A │
└───────┬───────┘
│ git diff --staged
▼
┌───────────────┐ ¿mezcla cambios?
│ Prompt #4 │──────────────┐
└───────┬───────┘ │ sí: partir en varios commits
│ no │
▼ ▼
┌───────────────┐ (repetir)
│ Prompt #2 │ elegir tipo + ámbito
└───────┬───────┘
│
▼
┌───────────────┐
│ Prompt #1 │ asunto imperativo, máx. 50 car.
└───────┬───────┘
│
▼
┌───────────────┐ ¿sabes el porqué?
│ Prompt #3 │──────────────┐
└───────┬───────┘ │ no: te pregunta, respondes
│ sí ▼
▼ (responde y repite)
┌───────────────┐
│ git commit │
└───────┬───────┘
│
▼
┌───────────────┐
│ Prompt #10 │ revisión de la serie antes del PR
└───────┬───────┘
│
▼
┌───────────┐
│ PR open │──► Prompt #7 changelog de la release
└───────────┘
La idea detrás de todos estos prompts es la misma que se explica en los mejores prompts para programar con IA: la IA es un ejecutor de instrucciones precisas. Cuanto más estructurado le des el trabajo, menos te sorprende.
Cuando el commit es parte de un pipeline y lo que falla es el build, el salto natural es a los prompts para crear y depurar pipelines de CI con IA. Y si lo que te pasa es que no entiendes ni el código que estás commiteando, empieza por los prompts para entender código ajeno.
Para montar el prompt de otra tarea sin partir de cero, la herramienta generadora de prompts te lo deja listo para copiar.
Artículos relacionados
¿Te aparece este error?
You are in 'detached HEAD' state Solución: Git detached HEAD — cómo salir sin perder los commits
CONFLICT (content): Merge conflict in archivo.js Solución: resolver conflictos de merge en Git sin romper el código
error: failed to push some refs — Updates were rejected