Si llevas unos meses en un proyecto, seguramente git branch te devuelve una lista eterna: fix-login, feature/pagos, prueba-2... La mayoría ya se fusionaron hace tiempo, pero nadie se atreve a borrarlas por miedo a perder trabajo. En este tutorial vamos a construir un script pequeño que las limpia de forma segura.
La idea clave: --merged
Git ya sabe qué ramas están fusionadas. Una rama está "fusionada" en main cuando su último commit es alcanzable desde main, es decir, borrarla no hace que se pierda ningún commit.
git branch --merged main
Ese comando funciona, pero su salida está pensada para humanos (marca la rama actual con * y añade espacios). Para scripts es mejor git for-each-ref, que permite elegir el formato exacto:
git for-each-ref --merged=main --format='%(refname:short)' refs/heads/
Ahora tenemos un nombre por línea, sin adornos.
Proteger las ramas importantes
Nunca queremos borrar main, develop ni la rama en la que estamos. Un truco limpio en Bash es rodear la lista con espacios y comparar con un patrón:
#!/usr/bin/env bash
set -euo pipefail
BASE="main"
PROTEGIDAS="main master develop staging production"
actual="$(git symbolic-ref --short -q HEAD || true)"
es_protegida() {
[[ "$1" == "$BASE" || "$1" == "$actual" || " $PROTEGIDAS " == *" $1 "* ]]
}
locales=()
while IFS= read -r rama; do
es_protegida "$rama" || locales+=("$rama")
done < <(git for-each-ref --merged="$BASE" --format='%(refname:short)' refs/heads/)
echo "Ramas fusionadas en $BASE (${#locales[@]}):"
if [[ ${#locales[@]} -gt 0 ]]; then printf ' %s\n' "${locales[@]}"; fi
Algunos detalles que vale la pena entender:
-
set -euo pipefailhace que el script se detenga ante errores, variables sin definir o fallos dentro de una tubería. -
|| trueensymbolic-refevita que el script muera si estás en "HEAD separado". -
< <(...)(sustitución de procesos) permite que el arraylocalessiga existiendo después del bucle; con una tubería| whilese perdería, porque el bucle correría en un subshell.
Borrar, pero con red de seguridad
El último paso es borrar. Hay dos decisiones importantes:
-
Dry-run por defecto: el script solo lista. Para borrar hay que pasar
--ejecutary además confirmar. -
Usar
git branch -d, no-D: la-dminúscula se niega a borrar una rama que no esté fusionada. Aunque nuestra lógica fallara, git nos frena.
read -r -p "¿Borrar estas ramas? [s/N] " resp || resp=""
[[ "$resp" =~ ^[sS]$ ]] || { echo "Cancelado."; exit 0; }
for rama in "${locales[@]}"; do
git branch -d -- "$rama"
done
El -- antes del nombre indica a git que lo que sigue no es una opción, por si alguna rama tuviera un nombre raro que empiece con guion.
Un aviso sobre squash y rebase
Si tu equipo fusiona los pull requests con "Squash and merge" o "Rebase and merge" en GitHub, los commits originales de la rama no llegan a main, así que git no las detecta como fusionadas. Esas ramas tendrás que revisarlas a mano (o con git cherry). No es un fallo del script: es la forma en que funcionan esos tipos de merge.
Con estas pocas líneas puedes pasar de 40 ramas a 5 en un minuto, sin el miedo de perder trabajo.
¿Te sirvió? Este script es parte del Pack 12 Scripts Bash para Desarrolladores (Linux): paga lo que quieras, desde 2 USD. Más recursos gratis en GitHub.
Top comments (0)