J'utilise la réponse d'Adam depuis des années maintenant. Cela dit, il y a des cas où il ne s'est pas comporté comme je m'y attendais:
- les branches qui contenaient le mot "master" ont été ignorées, par exemple "notmaster" ou "masterful", plutôt que seulement la branche master
- les branches qui contenaient le mot "dev" ont été ignorées, par exemple "dev-test", plutôt que seulement la branche dev
- suppression des branches accessibles depuis la TETE de la branche actuelle (c'est-à-dire pas nécessairement maître)
- dans l'état HEAD détaché, en supprimant toutes les branches accessibles depuis la validation actuelle
1 et 2 étaient simples à aborder, avec juste un changement de l'expression rationnelle. 3 dépend du contexte de ce que vous voulez (c.-à-d. Supprimer uniquement les branches qui n'ont pas été fusionnées en maître ou contre votre branche actuelle). 4 a le potentiel d'être désastreux (bien que récupérable avec git reflog
), si vous l'avez involontairement exécuté en état HEAD détaché.
Enfin, je voulais que tout cela soit dans une seule ligne qui ne nécessite pas de script séparé (Bash | Ruby | Python).
TL; DR
Créez un "balayage" d'alias git qui accepte un -f
indicateur optionnel :
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
et l'invoquer avec:
git sweep
ou:
git sweep -f
La réponse longue et détaillée
Il m'a été plus facile de créer un exemple de dépôt git avec quelques branches et de valider le bon comportement:
Créer un nouveau dépôt git avec un seul commit
mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"
Créez de nouvelles succursales
git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
bar
develop
foo
* master
masterful
notmaster
Comportement souhaité: sélectionnez toutes les branches fusionnées sauf: master, develop ou current
Le regex original manque les branches "masterful" et "notmaster":
git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
bar
Avec la regex mise à jour (qui exclut désormais "développer" plutôt que "dev"):
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Basculez vers la branche foo, faites un nouveau commit, puis extrayez une nouvelle branche, foobar, basée sur foo:
echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"
Ma branche actuelle est foobar, et si je réexécute la commande ci-dessus pour répertorier les branches que je veux supprimer, la branche "foo" est incluse même si elle n'a pas été fusionnée dans master:
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
masterful
notmaster
Cependant, si j'exécute la même commande sur master, la branche "foo" n'est pas incluse:
git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Et c'est tout simplement parce que la valeur par git branch --merged
défaut est HEAD de la branche actuelle, sauf indication contraire. Au moins pour mon flux de travail, je ne veux pas supprimer les branches locales sauf si elles ont été fusionnées pour devenir master, donc je préfère la variante suivante:
git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
État HEAD détaché
S'appuyer sur le comportement par défaut de git branch --merged
a des conséquences encore plus importantes dans l'état HEAD détaché:
git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
foobar
masterful
notmaster
Cela aurait supprimé la branche sur laquelle j'étais, "foobar" avec "foo", ce qui n'est certainement pas le résultat souhaité. Avec notre commande révisée, cependant:
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Une ligne, y compris la suppression réelle
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d
Le tout enveloppé dans un alias git "sweep":
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
L'alias accepte un -f
indicateur facultatif . Le comportement par défaut consiste à supprimer uniquement les branches qui ont été fusionnées dans le maître, mais l' -f
indicateur supprimera les branches qui ont été fusionnées dans la branche actuelle.
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
supprimez toute branche, qu'elle ait été fusionnée ou non.