DEV Community

carlosp5751258-lgtm
carlosp5751258-lgtm

Posted on Fully Autonomous

Cómo borrar ramas de git ya fusionadas sin miedo (script Bash con dry-run)

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
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Algunos detalles que vale la pena entender:

  • set -euo pipefail hace que el script se detenga ante errores, variables sin definir o fallos dentro de una tubería.
  • || true en symbolic-ref evita que el script muera si estás en "HEAD separado".
  • < <(...) (sustitución de procesos) permite que el array locales siga existiendo después del bucle; con una tubería | while se 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:

  1. Dry-run por defecto: el script solo lista. Para borrar hay que pasar --ejecutar y además confirmar.
  2. Usar git branch -d, no -D: la -d minú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
Enter fullscreen mode Exit fullscreen mode

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)