He usado la respuesta de Adam por años. Dicho esto, hay algunos casos en los que no se comportó como esperaba:
- se ignoraron las ramas que contenían la palabra "maestro", por ejemplo, "no maestro" o "maestro", en lugar de solo la rama maestra
- las ramas que contenían la palabra "dev" fueron ignoradas, por ejemplo, "dev-test", en lugar de solo la rama dev
- eliminar ramas a las que se puede acceder desde el HEAD de la rama actual (es decir, no necesariamente maestro)
- en estado HEAD separado, eliminando cada rama accesible desde el commit actual
1 y 2 fueron fáciles de abordar, con solo un cambio en la expresión regular. 3 depende del contexto de lo que desee (es decir, solo elimine las ramas que no se han fusionado en el maestro o en su rama actual). 4 tiene el potencial de ser desastroso (aunque recuperable con git reflog
), si accidentalmente ejecutó esto en estado HEAD separado.
Finalmente, quería que todo esto estuviera en una línea que no requiriera un script separado (Bash | Ruby | Python).
TL; DR
Cree un "barrido" de alias de git que acepte una marca opcional -f
:
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
e invocarlo con:
git sweep
o:
git sweep -f
La respuesta larga y detallada
Fue más fácil para mí crear un ejemplo de repositorio de git con algunas ramas y se compromete a probar el comportamiento correcto:
Crea un nuevo repositorio de git con un solo commit
mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"
Crea algunas ramas nuevas
git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
bar
develop
foo
* master
masterful
notmaster
Comportamiento deseado: seleccione todas las ramas fusionadas excepto: maestro, desarrollo o actual
La expresión regular original pierde las ramas "maestra" y "no maestra":
git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
bar
Con la expresión regular actualizada (que ahora excluye "desarrollar" en lugar de "dev"):
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Cambie a la sucursal foo, realice una nueva confirmación, luego revise una nueva rama, foobar, basada en foo:
echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"
Mi rama actual es foobar, y si vuelvo a ejecutar el comando anterior para enumerar las ramas que quiero eliminar, la rama "foo" se incluye aunque no se haya fusionado en master:
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
masterful
notmaster
Sin embargo, si ejecuto el mismo comando en master, la rama "foo" no está incluida:
git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Y esto se debe simplemente a que el valor git branch --merged
predeterminado es HEAD de la rama actual si no se especifica lo contrario. Al menos para mi flujo de trabajo, no quiero eliminar sucursales locales a menos que se hayan fusionado con master, por lo que prefiero la siguiente variante:
git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Estado HEAD separado
Confiar en el comportamiento predeterminado de git branch --merged
tiene consecuencias aún más significativas en el estado HEAD separado:
git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
foobar
masterful
notmaster
Esto habría eliminado la rama en la que estaba, "foobar" junto con "foo", lo que casi seguro no es el resultado deseado. Con nuestro comando revisado, sin embargo:
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Una línea, incluida la eliminación real
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d
Todo envuelto en un "barrido" de alias git:
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
El alias acepta una -f
bandera opcional . El comportamiento predeterminado es eliminar solo las ramas que se han fusionado en el maestro, pero el -f
indicador eliminará las ramas que se han fusionado en la rama actual.
git sweep
Deleted branch bar (was 9a56952).
Deleted branch masterful (was 9a56952).
Deleted branch notmaster (was 9a56952).
git sweep -f
Deleted branch foo (was 2cea1ab).
git branch -D
elimina cualquier rama, ya sea que se haya fusionado o no.