Exclua todos os ramos git locais

323

Sigo um processo de desenvolvimento em que crio uma nova filial local para cada novo recurso ou cartão de história. Quando terminar, mesclo o ramo no mestre e empurro.

O que tende a acontecer com o tempo devido a uma combinação de preguiça ou esquecimento é que acabo com uma grande lista de filiais locais, algumas das quais (como picos) podem não ter sido mescladas.

Eu sei como listar todos os meus ramos locais e sei como remover um único ramo, mas queria saber se havia um comando git que me permita excluir todos os meus ramos locais?

Abaixo está a saída do git branch --mergedcomando.

user@machine:~/projects/application[master]$ git branch --merged
  STORY-123-Short-Description
  STORY-456-Another-Description
  STORY-789-Blah-Blah
* master

Todas as tentativas de excluir ramificações listadas com grep -v \*(conforme as respostas abaixo) resultam em erros:

error: branch 'STORY-123-Short-Description' not found.
error: branch 'STORY-456-Another-Description' not found.
error: branch 'STORY-789-Blah-Blah' not found.

Estou usando:
git 1.7.4.1
ubuntu 10.04
GNU bash, versão 4.1.5 (1) -release
GNU grep 2.5.4

Louth
fonte
7
Peço que aceite a resposta de @Andrew!
Robert Siemer
@ GiulioCaccin A pergunta também se refere a ramificações que podem não ter sido mescladas e atualizei a pergunta para refletir isso explicitamente.
Louth

Respostas:

384

O subcomando 'git branch -d' pode excluir mais de um ramo. Então, simplificando a resposta do @ sblom, mas adicionando um xargs crítico:

git branch -D `git branch --merged | grep -v \* | xargs`

ou, ainda mais simplificado para:

git branch --merged | grep -v \* | xargs git branch -D 

Importante, como observado por @AndrewC, usar git branch de scripts é desencorajado. Para evitá-lo, use algo como:

git for-each-ref --format '%(refname:short)' refs/heads | grep -v master | xargs git branch -D

Cuidado garantido em exclusões!

$ mkdir br
$ cd br; git init
Initialized empty Git repository in /Users/ebg/test/br/.git/
$ touch README; git add README; git commit -m 'First commit'
[master (root-commit) 1d738b5] First commit
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README
$ git branch Story-123-a
$ git branch Story-123-b
$ git branch Story-123-c
$ git branch --merged
  Story-123-a
  Story-123-b
  Story-123-c
* master
$ git branch --merged | grep -v \* | xargs
Story-123-a Story-123-b Story-123-c
$ git branch --merged | grep -v \* | xargs git branch -D
Deleted branch Story-123-a (was 1d738b5).
Deleted branch Story-123-b (was 1d738b5).
Deleted branch Story-123-c (was 1d738b5).
GoZoner
fonte
Este comando ainda relata os mesmos erros mencionados nos comentários para a resposta abaixo. error:branch 'STORY-123-Short-Description' not found.para cada uma das ramificações listadas.
Louth
1
Funciona para mim; veja acima com detalhes adicionados.
GoZoner
1
Então, o uso do git 1.7.10 resolveu seu problema ou você prefere trabalhar diretamente no repositório .git?
GoZoner
1
Se você receber um error:branch 'STORY-123-Short-Description' not found.erro, isso provavelmente ocorre devido às configurações de cores do git. Isso funcionou para mim (note a --no-coloropção):git branch --no-color --merged | grep -v \* | xargs git branch -D
Marcok
3
A única resposta em SO que eu achei que funciona. Obrigado!
precisa
140

Encontrei uma maneira melhor em um comentário sobre esse problema no github :

git branch --merged master --no-color | grep -v master | grep -v stable | xargs git branch -d

edit: opção sem cor adicionada e exclusão de ramificação estável (adicione outras ramificações conforme necessário no seu caso)

mBardos
fonte
2
Finalmente, a solução que eu tenho precisado
Código Whisperer
1
Eu tentei isso, mas continuo recebendo error: branch 'my-branch-name' not found.para cada ramo. Usando a versão 1.8.3.4 do git (Apple Git-47). Alguma idéia do porquê?
wheresrhys
tente 'git branch --merged master | grep -v master | xargs echo 'para depurar o que exatamente ele está tentando excluir? não têm idéias melhores ...
mBardos
2
Assim. git for-each-ref --format '%(refname:short)' refs/heads/ | grep -v master | xargs git branch -d
Павел Тявин
1
Uso xargs aprendido junto com isso. Obrigado
Volem 12/04/19
105

A análise da saída de git branchnão é recomendada e não é uma boa resposta para futuros leitores no Stack Overflow.

  1. git branché o que é conhecido como comando de porcelana. Os comandos de porcelana não foram projetados para serem analisados ​​pela máquina e a saída pode mudar entre diferentes versões do Git.
  2. Existem opções de configuração do usuário que alteram a saída de git branchuma maneira que dificulta a análise (por exemplo, colorização). Se um usuário configurou color.branch, você receberá códigos de controle na saída, o que levará a isso error: branch 'foo' not found.se você tentar canalizá-lo para outro comando. Você pode ignorar isso com o --no-colorsinalizador para git branch, mas quem sabe quais outras configurações de usuário podem quebrar as coisas.
  3. git branch pode fazer outras coisas que são irritantes para analisar, como colocar um asterisco ao lado da ramificação com check-out atualmente

O mantenedor do git tem a dizer sobre scripts em torno da git branchsaída

Para descobrir qual é a ramificação atual, os usuários casuais / descuidados podem ter script em torno da ramificação git, o que está errado. Nós desencorajamos ativamente o uso de qualquer comando Porcelain, incluindo o git branch, nos scripts, porque a saída do comando está sujeita a alterações para ajudar no caso de uso do consumo humano.

Respostas que sugerem a edição manual de arquivos no diretório .git diretório (como .git / refs / heads) são igualmente problemáticas (as refs podem estar em .git / embal-refs ou o Git pode alterar seu layout interno no futuro).

Git fornece o for-each-ref comando para recuperar uma lista de ramificações.

O Git 2.7.X apresentará a --mergedopção para que você possa fazer algo como o abaixo para encontrar e excluir todos os ramos mescladosHEAD

for mergedBranch in $(git for-each-ref --format '%(refname:short)' --merged HEAD refs/heads/)
do
    git branch -d ${mergedBranch}
done

Git 2.6.X e mais antigo, você precisará listar todas as ramificações locais e testá-las individualmente para verificar se elas foram mescladas (o que será significativamente mais lento e um pouco mais complicado).

for branch in $(git for-each-ref --format '%(refname:short)' refs/heads/)
do
    git merge-base --is-ancestor ${branch} HEAD && git branch -d ${branch}
done
Andrew C
fonte
git branch --no-color 2>/dev/null?
#
5
É uma melhoria, com certeza. Você sempre terá o problema de filtrar o *, e isso fará coisas divertidas se alguém o executar com uma cabeça desanexada. O principal problema, porém, é git branchum comando de porcelana, e não há garantia de que a saída não seja alterada em alguma versão futura do git.
Andrew C
Obrigado @AndrewC - essas são as duas respostas à pergunta sobre os misteriosos erros "ramo não encontrado" e fornecem uma solução funcional usando um comando mais apropriado! 👍
Jason
2
Como são identificados os comandos GIT 'Porcelain' e 'non Porcelain'?
GoZoner 23/03
1
Provavelmente, seria um aprimoramento útil para excluir 'dev' e 'master' por padrão?
PandaWood
66

A maneira mais simples de excluir todas as ramificações, mas mantendo outras como "develop" e "master" é a seguinte:

git branch | grep -v "develop" | grep -v "master" | xargs git branch -D

muito útil !

geoom
fonte
8
Você ressuscitou um tópico antigo e postou uma resposta praticamente idêntica a uma já existente, que é de buggy e está faltando as alterações de segurança que ela teve. Esta não é uma boa resposta.
Andrew C
6
Essa resposta é clara na saída do canal do git branch, modificando-o e passando para o git branch -D. Não precisa ser mau.
Pam
Esta solução funcionou para mim. Excluídas todas as ramificações locais.
Prad
1
Isso não excluirá qualquer ramificação que contenha palavra develop ou master como 'develop_feature' ou 'master_feature'.
django
Esta é a resposta que eu estava procurando --🏻
Konrad G
62

Para excluir todas as ramificações, exceto a que você fez check-out no momento:

for b in `git branch --merged | grep -v \*`; do git branch -D $b; done

Eu recomendaria mudar git branch -D $bpara echo $bas primeiras vezes para garantir que ele exclua os ramos que você pretende.

sblom
fonte
1
com este comando eu recebo error:branch 'a_branch_name' not found.eu posso ver o que você está tentando fazer e eu fui brincar com o comando, mas por algum motivo git não parece como os nomes do ramo fornecido ...
Louth
hmmm. Para ajudar a resolver, seria útil para ver alguns exemplos de saída degit branch --merged
sblom
meus nomes do ramo são do formatoSTORY-123-Short-Description
Louth
e quando você corre git branch --merged, você recebe uma lista com um desses em cada linha?
Sblom 16/05/12
1
diz literalmente error:branch 'a_branch_name' not found.? Ou se queixa de um dos nomes de ramificação da sua git branchsaída acima?
Sblom 16/05/12
52

O comando abaixo excluirá todos os ramos locais, exceto o ramo mestre.

git branch | grep -v "master" | xargs git branch -D

O comando acima

  1. listar todos os ramos
  2. Na lista, ignore a ramificação principal e pegue as demais ramificações
  3. excluir o ramo
Caçador
fonte
4
Eu usaria git branch | grep -v "master" | xargs git branch -dprimeiro para não excluir ramos não imersos, apenas para garantir. Mas boa resposta!
Jonas Lomholdt
3
Aqui está uma versão do PowerShell,@(git branch | Select-String -Pattern "[^(*?)\s? master]") | ForEach-Object{$_.Line.Trim()} | %{git branch -D $_}
Jonas Lomholdt
1
@baklazan isso só funcionaria na linha de comando do Windows 10 se você tiver algumas ferramentas instaladas. Você provavelmente tem MINGW ou algo parecido e não sabe disso.
KthProg
42

Apenas uma observação, eu atualizaria para o git 1.7.10. Você pode estar recebendo respostas aqui que não funcionarão na sua versão. Meu palpite é que você teria que prefixar o nome do ramo refs/heads/.

CUIDADO, continue com o seguinte apenas se tiver feito uma cópia da sua pasta de trabalho e do diretório .git.

Às vezes, apenas vou em frente e apago os ramos dos quais não quero diretamente .git/refs/heads. Todas essas ramificações são arquivos de texto que contêm os 40 caracteres sha-1 da confirmação para a qual apontam. Você terá informações estranhas no seu, .git/configse você tiver configurado um rastreamento específico para qualquer um deles. Você pode excluir essas entradas manualmente também.

Adam Dymitruk
fonte
Finalmente, uma opção simples e pragmática. Eu gosto: D
Melvyn
2
Isso não funcionará se você tiver compactado referências, ou mesmo se tiver clonado de um servidor remoto às vezes (o que fornecerá arquivos compactados). Se você refs estiver empacotado, eles não serão armazenados em .git / refs / heads, eles serão armazenados em um arquivo chamado "empacotado-refs". Consulte git-scm.com/docs/git-pack-refs .
Alexander Bird
1
Parece uma péssima idéia remover o ramo que você fez check-out no momento
Moberg
@Moberg Basta fazer o check-out antecipado de um commit, e seu HEAD desanexado flutuará bem.
RomainValeri
34

Experimente o seguinte comando shell:

git branch | grep -v "master" | xargs git branch -D

Explicação:

  • 🛒 Obter todas as ramificações via git branch | grep -v "master"comando
  • Every Selecione todos os ramos com o xargscomando
  • 💦 Excluir ramificação com xargs git branch -D
Pravin
fonte
3
Embora isso possa ser uma resposta correta. Uma linha de código não é muito útil sem uma explicação sobre o que e como resolve a questão original. Forneça detalhes para sua resposta.
RyanNerd 27/09/19
28

Para excluir todas as filiais locais no linux, exceto a que você está

// hard delete

git branch -D $(git branch)
Ashish Yadav
fonte
2
Este parece mais seguro do que entrar no .git e remover coisas.
Nelsontruran
25

Achei mais fácil usar apenas o editor de texto e o shell.

  1. Digite git checkout <TAB>shell. Mostrará todas as filiais locais.
  2. Copie-os para um editor de texto e remova aqueles que você precisa manter.
  3. Substitua quebras de linha por espaços. (No SublimeText é super fácil.)
  4. Shell aberto, tipo git branch -D <PASTE THE BRANCHES NAMES HERE>.

É isso aí.

culebrón
fonte
Não acho que você possa remover o ramo em que está.
Dong Thang
@ Dong Há um * ao lado desse ramo, para você removê-lo da lista copiada!
Melanie
12

Eu tive um tipo semelhante de situação e recentemente achei o seguinte comando útil.

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep>/) printf "%s", $0 }'`

Se você deseja manter várias ramificações,

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep1>|<Branch_You_Want_to_Keep2>/) printf "%s", $0 }'`

espero que isso ajude alguém.

4u.Ans
fonte
1
Bom, mas eu precisava de backticks para fazê-lo funcionar - Na git branch -D `git branch | awk '{ if ($0 !~ /master/) printf "%s", $0 }'` verdade, acho que você os tinha originalmente, mas eles se perderam na formatação SO.
Tassinari
10

Na Linha de Comando do Windows, exclua todos, exceto o ramo com check-out atual usando:

for /f "tokens=*" %f in ('git branch ^| find /v "*"') do git branch -D %f
kiewic
fonte
7

Se você não precisar passar pelo próprio Git, também poderá excluir as cabeças em .git / refs / heads manualmente ou programaticamente. O seguinte deve funcionar com ajustes mínimos no Bash:

shopt -s extglob
rm -rf .git/refs/heads/!(master)

Isso excluirá todas as ramificações locais, exceto a ramificação principal. Como suas ramificações upstream são armazenadas em .git / refs / remotes , elas permanecem intocadas.

Se você não está usando o Bash, ou deseja recolocar muitos repositórios Git de uma só vez, pode fazer algo semelhante com o GNU find:

find . \
    -path remotes -path logs -prune -o \
    -wholename \*.git/refs/heads/\* \! -name master -print0 |
xargs -0 rm -rf

A solução de localização é provavelmente mais portátil, mas caminhos de remoção e nomes de arquivos são complicados e potencialmente mais propensos a erros.

Todd A. Jacobs
fonte
Legal. Visual delete :)
sandalone,
5

Nenhuma das respostas atendeu totalmente minhas necessidades, então vamos lá:

git branch --merged | grep -E "(feature|bugfix|hotfix)/" | xargs git branch -D && git remote prune origin

Isso excluirá todas as ramificações locais que são mescladas e iniciadas com feature/, bugfix/ou hotfix/. Posteriormente, o controle remoto originé removido (talvez seja necessário digitar uma senha).

Funciona no Git 1.9.5.

user4401817
fonte
5

Com base em uma combinação de várias respostas aqui - se você deseja manter todas as ramificações existentes no controle remoto, mas excluir as demais , o seguinte oneliner fará o truque:

git for-each-ref --format '%(refname:short)' refs/heads | grep -Ev `git ls-remote --quiet --heads origin | awk '{print substr($2, 12)}'| paste -sd "|" -` | xargs git branch -D
Srishan Bhattarai
fonte
3

Embora essa não seja uma solução de linha de comando, estou surpreso que a GUI do Git ainda não tenha sido sugerida.

Eu uso a linha de comando 99% do tempo, mas, neste caso, é muito lento (daí a pergunta original), ou você não sabe o que está prestes a excluir ao recorrer a uma manipulação de shell longa e inteligente.

A interface do usuário resolve esse problema, pois você pode rapidamente desmarcar as ramificações que deseja remover e lembrar as que deseja manter, sem precisar digitar um comando para cada ramificação.

Na interface do usuário, vá para Ramificação -> Excluir e Ctrl + Clique nas ramificações que deseja excluir para que elas sejam destacadas. Se você quiser ter certeza de que eles estão mesclados em uma ramificação (como dev), em Excluir apenas se mesclado em, defina Ramificação local como dev. Caso contrário, defina-o como Sempre para ignorar esta verificação.

GitUI: excluir ramificações locais

Dane Bouchie
fonte
1

Para o PowerShell, isso funcionará:

git branch --format '%(refname:lstrip=2)' --merged `
    | Where-Object { $_ -ne 'master' } `
    | ForEach-Object { git branch -d $_ }
Lucas
fonte
0

O script a seguir exclui ramificações. Use-o e modifique-o por sua conta e risco, etc. etc.

Com base nas outras respostas desta pergunta, acabei escrevendo um script bash rápido para mim. Eu chamei de "gitbd" (git branch -D), mas se você usá-lo, poderá renomeá-lo para o que quiser.

gitbd() {
if [ $# -le 1 ]
  then
    local branches_to_delete=`git for-each-ref --format '%(refname:short)' refs/heads/ | grep "$1"`
    printf "Matching branches:\n\n$branches_to_delete\n\nDelete? [Y/n] "
    read -n 1 -r # Immediately continue after getting 1 keypress
    echo # Move to a new line
    if [[ ! $REPLY == 'N' && ! $REPLY == 'n' ]]
      then
        echo $branches_to_delete | xargs git branch -D
    fi
else
  echo "This command takes one arg (match pattern) or no args (match all)"
fi
}

Ele oferecerá a exclusão de quaisquer ramificações que correspondam a um argumento padrão, se passadas, ou todas as ramificações locais quando chamadas sem argumentos. Também fornecerá uma etapa de confirmação, já que, você sabe, estamos excluindo coisas, então isso é legal.

É meio idiota - se não há galhos que correspondam ao padrão, ele não percebe.

Um exemplo de execução de saída:

$ gitbd test
Matching branches:

dummy+test1
dummy+test2
dummy+test3

Delete? [Y/n] 
dherman
fonte
0

Escrevi um script de shell para remover todos os ramos locais, exceto develop

branches=$(git branch | tr -d " *")
output=""
for branch in $branches 
do
  if [[ $branch != "develop" ]]; then
    output="$output $branch"
  fi
done
git branch -d $output
nhp
fonte
0

As respostas acima funcionam bem. Aqui está outra abordagem quando temos muitas ramificações no repositório local e temos que excluir muitas ramificações, exceto algumas que estão na máquina local.

Primeiro git branch, listará todas as ramificações locais.

Para transpor a coluna de nomes de ramificação para uma única linha no arquivo, executando um comando unix
git branch > sample.txt
Isso o salvará no arquivo sample.txt . E execute o
awk 'BEGIN { ORS = " " } { print }' sample.txt
comando no shell. Isso transformará a coluna em linha e copiará a lista de nomes de ramificações em uma única linha.

E então corra
git branch -D branch_name(s).
Isso excluirá todos os ramos listados presentes no local

Deepak G
fonte
0

A maneira mais pragmática: verifique se você não possui trabalho não mastercomprometido, confirme / envie, se necessário, clone uma nova cópia do repositório e exclua a antiga.

Patrick Sanan
fonte
0

Para esse fim, você pode usar git-extras

$ git delete-merged-branches
Deleted feature/themes (was c029ab3).
Deleted feature/live_preview (was a81b002).
Deleted feature/dashboard (was 923befa).
Andriy Orehov
fonte
0

Eu não tenho grep ou outro unix na minha caixa, mas isso funcionou no terminal do VSCode:

git branch -d $(git branch).trim()

Eu uso o d minúsculo para que ele não exclua ramificações não imersas.

Eu também estava no master quando o fiz, por * masterisso não existe e não tente excluir o master.

Ron Newcomb
fonte
Confirmado: Se não estiver ativado master, este comando será excluído master.
Brett Rowberry
-1

Certifique-se de fazer isso primeiro

git fetch

Depois de ter todas as informações de ramificações remotas, use o comando a seguir para remover todas as ramificações, exceto as mestre

 git branch -a | grep -v "master" | grep remotes | sed 's/remotes\/origin\///g' | xargs git push origin --delete
Meng
fonte