Después de una semana de trabajo en una feature branch, tu historial de commits se ve más o menos así:
fix typo
WIP
fix test
WIP again
fix linter
listo ahora sí
Estos commits son útiles mientras trabajas — pero son ruido en el historial de la rama principal. Un squash merge colapsa todos en un único commit descriptivo antes de que lleguen a main.
Qué hace realmente un squash merge
Un squash merge toma todos los cambios de una feature branch y los prepara como un único commit en la rama destino. El historial de commits de la rama original se descarta — solo sobrevive el diff.
El resultado: main se mantiene legible, y cada entrada en git log representa una unidad de trabajo completa y deployable.
main
├── feat: agregar autenticación de usuario (#42)
├── feat: rediseño del flujo de pago (#38)
└── chore: actualizar dependencias (#35)
En vez de:
main
├── fix test
├── WIP
├── fix typo
├── WIP
├── implementación inicial de auth
└── ...
El enfoque manual
Git soporta squash merging de forma nativa:
# Asegúrate de que main esté actualizado
git checkout main
git pull origin main
# Merge con squash — prepara todos los cambios, no hace commit
git merge --squash feature/mi-rama
# Escribe un único mensaje de commit descriptivo
git commit -m "feat: implementar autenticación de usuario"
# Limpia la feature branch
git branch -d feature/mi-rama
git push origin --delete feature/mi-rama
El flag --squash es la clave: prepara todo sin crear un commit de merge, dándote control total sobre el mensaje final.
Automatizando con un script
Hacer esto repetidamente en docenas de feature branches se vuelve tedioso. Un script reutilizable se encarga de la mecánica:
#!/bin/bash
# git_squash.sh — hace merge de una feature branch con un squash commit
set -e
FEATURE_BRANCH=$1
TARGET_BRANCH=$2
if [ -z "$FEATURE_BRANCH" ] || [ -z "$TARGET_BRANCH" ]; then
echo "Uso: git-squash <feature-branch> <target-branch>"
exit 1
fi
echo "→ Squash merging $FEATURE_BRANCH en $TARGET_BRANCH"
# Backup de la feature branch
git branch "${FEATURE_BRANCH}_backup"
# Cambiar al target y actualizar
git checkout "$TARGET_BRANCH"
git pull origin "$TARGET_BRANCH"
# Squash merge
git merge --squash "$FEATURE_BRANCH"
# Commit (abre el editor para el mensaje)
git commit
# Push al remoto
git push origin "$TARGET_BRANCH"
# Limpieza
git branch -d "$FEATURE_BRANCH"
git branch -d "${FEATURE_BRANCH}_backup"
echo "✓ Listo. $FEATURE_BRANCH mergeado en $TARGET_BRANCH."
Configurar el alias
Guarda el script en algún lugar permanente y hazlo ejecutable:
chmod +x ~/scripts/git_squash.sh
Agrega un alias a tu perfil de shell (.zshrc, .bashrc, o .profile):
alias git-squash="~/scripts/git_squash.sh"
Recarga el perfil:
source ~/.zshrc
Ahora puedes hacer squash-merge de cualquier rama con:
git-squash feature-123 main
Cuándo usar squash merges
El squash merge es el default correcto cuando:
- La feature branch tiene muchos commits pequeños o de fixup que no aportan valor histórico
- El equipo acordó una estrategia de historial lineal
- Estás aplicando conventional commits en
mainy quieres control total sobre el mensaje
No es la opción correcta cuando:
- Quieres preservar el historial individual de commits para debugging (
git bisectse beneficia de commits granulares) - Varias personas colaboraron en la rama y la atribución importa
- Los commits ya son limpios y descriptivos
La alternativa: rebase interactivo
Si quieres aplastar selectivamente algunos commits pero mantener otros, git rebase -i es más quirúrgico:
git rebase -i main
Esto abre un editor donde marcas los commits como pick, squash, o fixup. Más control, un poco más de fricción.
Conclusiones
git merge --squashcolapsa todos los commits de la rama en un único diff preparado — tú escribes el mensaje final- Un historial limpio en
mainfacilita significativamentegit log, las code reviews y el debugging de incidentes - El script agrega una rama
--backupcomo red de seguridad antes de operaciones destructivas - El squash merge es una convención de equipo — acuérdala de antemano y aplícala mediante reglas de branch protection en GitHub/GitLab