Ho usato la risposta di Adam per anni ormai. Detto questo, ci sono alcuni casi in cui non si stava comportando come mi aspettavo:
- rami che contenevano la parola "maestro" sono stati ignorati, ad esempio "notmaster" o "masterful", piuttosto che solo il ramo master
- rami che contenevano la parola "dev" venivano ignorati, ad esempio "dev-test", piuttosto che solo il ramo dev
- eliminazione di rami raggiungibili dall'HEAD del ramo corrente (ovvero, non necessariamente master)
- nello stato HEAD distaccato, eliminando tutti i rami raggiungibili dal commit corrente
1 e 2 erano semplici da affrontare, con solo una modifica alla regex. 3 dipende dal contesto di ciò che si desidera (ovvero eliminare solo i rami che non sono stati uniti in master o rispetto al ramo corrente). 4 ha il potenziale per essere disastroso (anche se recuperabile con git reflog
), se lo hai eseguito involontariamente in stato HEAD distaccato.
Alla fine, volevo che tutto questo fosse in una riga che non richiedeva uno script separato (Bash | Ruby | Python).
TL; DR
Crea un alias git "sweep" che accetta un -f
flag opzionale :
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
e invocalo con:
git sweep
o:
git sweep -f
La risposta lunga e dettagliata
È stato più semplice per me creare un repository git di esempio con alcuni rami e si impegna a testare il comportamento corretto:
Crea un nuovo repository git con un unico commit
mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"
Crea alcuni nuovi rami
git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
bar
develop
foo
* master
masterful
notmaster
Comportamento desiderato: selezionare tutti i rami uniti tranne: master, sviluppo o corrente
Il regex originale manca i rami "magistrale" e "notmaster":
git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
bar
Con il regex aggiornato (che ora esclude "sviluppo" anziché "dev"):
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Passa al ramo foo, effettua un nuovo commit, quindi verifica un nuovo ramo, foobar, basato su foo:
echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"
Il mio ramo attuale è foobar, e se riesco a eseguire nuovamente il comando sopra per elencare i rami che voglio eliminare, il ramo "pippo" è incluso anche se non è stato unito al master:
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
masterful
notmaster
Tuttavia, se eseguo lo stesso comando sul master, il ramo "pippo" non è incluso:
git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
E questo semplicemente perché il git branch --merged
valore predefinito è HEAD del ramo corrente se non diversamente specificato. Almeno per il mio flusso di lavoro, non voglio eliminare i rami locali a meno che non siano stati uniti al master, quindi preferisco la seguente variante:
git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Stato HEAD distaccato
Affidarsi al comportamento predefinito di git branch --merged
ha conseguenze ancora più significative nello stato HEAD distaccato:
git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
foobar
masterful
notmaster
Ciò avrebbe cancellato il ramo in cui mi trovavo, "foobar" insieme a "foo", che non è quasi certamente il risultato desiderato. Con il nostro comando rivisto, tuttavia:
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Una riga, incluso l'eliminazione effettiva
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d
Tutto racchiuso in una "spazzata" 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'
L'alias accetta un -f
flag opzionale . Il comportamento predefinito consiste nell'eliminare solo i rami che sono stati uniti nel master, ma il -f
flag eliminerà i rami che sono stati uniti nel ramo corrente.
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 qualsiasi ramo che sia stato unito o meno.