Eu tenho usado a resposta de Adam há anos. Dito isto, há alguns casos em que não estava se comportando como eu esperava:
- ramificações que continham a palavra "mestre" foram ignoradas, por exemplo, "notmaster" ou "masterful", em vez de apenas a ramificação mestre
- ramificações que continham a palavra "dev" foram ignoradas, por exemplo, "dev-test", em vez de apenas a ramificação dev
- exclusão de ramificações acessíveis do HEAD da ramificação atual (ou seja, não necessariamente mestre)
- no estado HEAD desanexado, excluindo todos os ramos alcançáveis da confirmação atual
1 e 2 foram diretos, com apenas uma alteração no regex. 3 depende do contexto do que você deseja (ou seja, exclua apenas os ramos que não foram mesclados no mestre ou no ramo atual). 4 tem o potencial de ser desastroso (embora recuperável com git reflog
), se você o executou acidentalmente no estado HEAD desanexado.
Finalmente, eu queria que tudo isso estivesse em uma linha única que não exigisse um script separado (Bash | Ruby | Python).
TL; DR
Crie um alias do git "sweep" que aceite um -f
sinalizador opcional :
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
e invoque-o com:
git sweep
ou:
git sweep -f
A resposta longa e detalhada
Para mim, foi mais fácil criar um exemplo de repositório git com algumas ramificações e se comprometer a testar o comportamento correto:
Crie um novo repositório git com um único commit
mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"
Crie algumas novas ramificações
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 desejado: selecione todas as ramificações mescladas, exceto: mestre, desenvolvimento ou atual
O regex original perde os ramos "masterful" e "notmaster":
git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
bar
Com o regex atualizado (que agora exclui "develop" em vez de "dev"):
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Alterne para o ramo foo, faça um novo commit e faça o checkout de um novo ramo, foobar, com base no foo:
echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"
Minha ramificação atual é foobar, e se eu executar novamente o comando acima para listar as ramificações que desejo excluir, a ramificação "foo" será incluída mesmo que não tenha sido mesclada no master:
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
masterful
notmaster
No entanto, se eu executar o mesmo comando no mestre, o ramo "foo" não será incluído:
git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
E isso é simplesmente porque o git branch --merged
padrão é o HEAD do ramo atual, se não especificado de outra forma. Pelo menos para o meu fluxo de trabalho, não desejo excluir ramificações locais, a menos que tenham sido mescladas para mestre, por isso prefiro a seguinte variante:
git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Estado HEAD desanexado
Confiar no comportamento padrão de git branch --merged
tem consequências ainda mais significativas no estado HEAD desanexado:
git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
foobar
masterful
notmaster
Isso teria excluído o ramo em que eu estava, "foobar" junto com "foo", que quase certamente não é o resultado desejado. Com nosso comando revisado, no entanto:
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Uma linha, incluindo a exclusão real
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d
Tudo embrulhado em um apelido git "varredura":
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
O alias aceita um -f
sinalizador opcional . O comportamento padrão é excluir apenas as ramificações que foram mescladas no mestre, mas o -f
sinalizador excluirá as ramificações que foram mescladas na ramificação atual.
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
exclui qualquer ramificação, mesclada ou não.