Como remover ramificações de rastreamento locais que não existem mais no controle remoto

Com git remote prune origin remoção git remote prune origin posso remover as ramificações locais que não estão mais no remoto.

Mas eu também quero remover as ramificações locais que foram criadas a partir dessas ramificações remotas (uma verificação se elas estão desimpedidas seria boa).

Como posso fazer isso?

Após a remoção, você pode obter a lista de ramificações remotas com git branch -r . A lista de ramificações com sua ramificação de rastreamento remoto pode ser recuperada com git branch -vv . Portanto, usando essas duas listas, você pode encontrar as ramificações de rastreamento remotas que não estão na lista de remotos.

Esta linha deve fazer o truque (requer bash ou zsh , não funciona com shell Bourne padrão):

git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 < (git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d

Esta cadeia de caracteres obtém a lista de ramificações remotas e as transmite para o egrep por meio da input padrão. E filtra as ramificações que têm uma ramificação de rastreamento remoto (usando git branch -vv e filtragem para aquelas que têm origin ) e então obtendo a primeira coluna dessa saída que será o nome da ramificação. Finalmente passando todos os nomes das ramificações para o comando delete branch.

Como ele está usando a opção -d , ele não excluirá ramificações que não foram mescladas na ramificação em que você está quando executa este comando.

Lembre-se também que você precisará executar git fetch --prune first , caso contrário git branch -r ainda verá os branches remotos.

Se você quiser excluir todas as ramificações locais que já estão mescladas no mestre, use o seguinte comando:

 git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d 

Mais informações .

Em meio às informações apresentadas pelo git help fetch , há este pequeno item:

  -p, --prune After fetching, remove any remote-tracking branches which no longer exist on the remote. 

Então, talvez, git fetch -p é o que você está procurando?

EDIT: Ok, para aqueles que ainda estão a debater esta resposta 3 anos após o fato, aqui está um pouco mais informações sobre o porquê de apresentar esta resposta …

Primeiro, o OP diz que eles querem “remover também as filiais locais que foram criadas a partir dessas filiais remotas [que não estão mais no controle remoto]”. Isto não é inequivocamente possível no git . Aqui está um exemplo.

Digamos que eu tenha um repo em um servidor central e tenha dois ramos, chamados A e B Se eu clonar esse repository para o meu sistema local, meu clone terá referências locais (não filiais reais ainda) chamadas origin/A e origin/B Agora digamos que eu faça o seguinte:

 git checkout -b A origin/A git checkout -b Z origin/B git checkout -b C  

Os fatos pertinentes aqui são que eu por algum motivo escolhi criar um branch no meu repository local que tem um nome diferente de sua origem, e eu também tenho um branch local que (ainda) não existe no repository de origem.

Agora, digamos que eu remova as ramificações A e B no repository remoto e atualize meu repository local ( git fetch of some form), o que faz com que minhas referências locais origin/A e origin/B desapareçam. Agora, meu repository local ainda tem três filiais, A , Z e C Nenhum destes tem um ramo correspondente no repository remoto. Dois deles foram “criados a partir de … filiais remotas”, mas mesmo que eu saiba que costumava haver uma ramificação chamada B na origem, não tenho como saber que Z foi criado a partir de B , porque foi renomeado em o processo, provavelmente por um bom motivo. Então, na verdade, sem algum processo externo registrando metadados de origem de ramificação, ou um humano que conheça o histórico, é impossível dizer qual dos três ramos, se algum, o OP está almejando para remoção. Sem algumas informações externas que o git não mantém automaticamente para você, git fetch -p é o mais próximo que você pode chegar, e qualquer método automático para literalmente tentar o que o OP perguntou corre o risco de deletar muitos branches, ou perder algum que o OP desejaria excluir.

Existem outros cenários também, como se eu criasse três ramificações separadas da origin/A para testar três abordagens diferentes para algo, e então a origin/A desaparece. Agora eu tenho três ramificações, que obviamente não podem ser compatíveis com o nome, mas elas foram criadas a partir da origin/A e, portanto, uma interpretação literal da pergunta dos OPs exigiria a remoção de todas as três. No entanto, isso pode não ser desejável, se você puder encontrar uma maneira confiável de combiná-los …

Isso excluirá as ramificações locais para as quais as ramificações de rastreamento remoto foram removidas. (Certifique-se de estar no ramo master !)

 git checkout master git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d 

Detalhes:

  • git branch -vv exibe “gone” para branches locais que o remote foi removido.

     mybranch abc1234 [origin/mybranch: gone] commit comments 
  • -d irá verificar se foi mesclado ( -D irá excluí-lo independentemente)

     error: The branch 'mybranch' is not fully merged. 

Pode-se configurar o Git para remover automaticamente as referências às ramificações remotas excluídas ao buscar:

 git config --global fetch.prune true 

Ao chamar git fetch ou git pull depois, as referências às ramificações remotas excluídas são removidas automaticamente.

Há um pacote NPM puro que faz isso para você (e deve funcionar em várias plataformas).

Instale-o com: npm install -g git-removed-branches

E então git removed-branches mostrará todos os branches locais obsoletos e git removed-branches --prune para realmente apagá-los.

Mais informações aqui.

Ele listará as filiais locais cuja ramificação de rastreamento remoto é excluída do remoto

 $ git remote prune origin --dry-run 

Se você quiser desreferenciar essas ramificações locais do local que não foi rastreado

 $ git remote prune origin 

Se estiver usando o Windows e o Powershell, você poderá usar o seguinte para excluir todas as ramificações locais que foram mescladas na ramificação atualmente retirada:

 git branch --merged | ? {$_[0] -ne '*'} | % {$_.trim()} | % {git branch -d $_} 

Explicação

  • Lista a ramificação atual e as ramificações que foram mescladas nela
  • Filtra o ramo atual
  • Limpa todos os espaços iniciais ou finais da saída do git para cada nome de ramificação restante
  • Exclui as ramificações locais mescladas

Vale a pena executar o git branch --merged por si só, apenas para ter certeza de que apenas removerá o que você espera.

(Portado / automatizado de http://railsware.com/blog/2014/08/11/git-housekeeping-tutorial-clean-up-outdated-branches-in-local-and-remote-repositories/ .)

Solução do Windows

Para o Microsoft Windows Powershell:

git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Split(" ")[0]} | % {git branch -d $_}

Explicação

git checkout master muda para o branch master

git remote update origin --prune poda ramais remotos

git branch -vv obtém uma saída detalhada de todas as ramificações ( referência git )

Select-String -Pattern ": gone]" obtém apenas os registros em que foram removidos do controle remoto.

% { $_.toString().Split(" ")[0]} obtém o nome da ramificação

% {git branch -d $_} exclui o ramo

Não tenho certeza de como fazer tudo de uma vez, mas o git git branch -d irá apagar APENAS uma ramificação local se ela estiver completamente mesclada. Observe o d minúsculo.

git branch -D (observe a maiúscula D) irá deletar uma ramificação local independente de seu status mesclado.

Eu queria algo que limpasse todas as ramificações locais que estavam rastreando uma ramificação remota, na origin , onde a ramificação remota foi excluída ( gone ). Eu não queria excluir as ramificações locais que nunca foram configuradas para rastrear uma ramificação remota (isto é: minhas ramificações dev locais). Além disso, eu queria um simples one-liner que apenas usasse o git , ou outras ferramentas CLI simples, ao invés de escrever scripts customizados. Eu acabei usando um pouco de grep e awk para fazer este comando simples, então o adicionei como um alias no meu ~/.gitconfig .

 [alias] prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D 

Aqui está um comando git config --global ... para facilmente adicionar isto como git prune-branches :

 git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d' 

NOTA: O uso do sinalizador -D para git branch pode ser muito perigoso. Então, no comando config acima eu uso a opção -d para git branch vez de -D ; Eu uso -D na minha configuração real. Eu uso -D porque eu não quero ouvir o Git reclamar sobre twigs desimpedidos, eu só quero que eles desapareçam. Você também pode querer essa funcionalidade. Em caso afirmativo, simplesmente use -D vez de -d no final desse comando de configuração.

Mesmo uma linha mais curta e mais segura:

 git branch -d $(git branch --merged | cut -c 3-) 

Certifique-se de fazer o checkout para o ramo que ainda não foi mesclado, antes de executá-lo. Porque você não pode excluir a ramificação que está atualmente registrada.

Usando uma variante na resposta do @ wisbucky, adicionei o seguinte como um alias ao meu arquivo ~/.gitconfig :

 pruneitgood = "!f() { \ git remote prune origin; \ git branch -vv | perl -nae 'system(qw(git branch -d), $F[0]) if $F[3] eq q{gone]}'; \ }; f" 

Com isso, um simples git pruneitgood as ramificações locais e remotas que não são mais necessárias após as mesclagens.

Com base nas respostas acima, eu vim com esta solução de uma linha:

 git remote prune origin; git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 < (git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d 

A variante de Schleis não funciona para mim (Ubuntu 12.04), então deixe-me propor minhas variantes (claras e shinys :):

Variante 1 (eu preferiria essa opção):

 git for-each-ref --format='%(refname:short) %(upstream)' refs/heads/ | awk '$2 !~/^refs\/remotes/' | xargs git branch -D 

Variante 2:

uma. Funcionamento a seco:

 comm -23 < ( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | awk '{print "git branch -D " $1}' 

b. Remover ramos:

 comm -23 < ( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | xargs git branch -D 

Eu transformei a resposta aceita em um script robusto. Você o encontrará no meu repository de extensões de git .

 $ git-prune --help Remove old local branches that do not exist in  any more. With --test, only print which local branches would be deleted. Usage: git-prune [-t|--test|-f|--force]  

A seguir, uma adaptação da resposta do @ wisbucky para usuários do Windows:

for /f "tokens=1" %i in ('git branch -vv ^| findstr ": gone]"') DO git branch %i -d

Eu uso o posh-git e, infelizmente, o PS não gosta do naked, então criei um script simples de comando chamado PruneOrphanBranches.cmd:

 @ECHO OFF for /f "tokens=1" %%i in ('git branch -vv ^| findstr ": gone]"') DO CALL :ProcessBranch %%i %1 GOTO :EOF :ProcessBranch IF /I "%2%"=="-d" ( git branch %1 %2 ) ELSE ( CALL :OutputMessage %1 ) GOTO :EOF :OutputMessage ECHO Will delete branch [%1] GOTO :EOF :EOF 

Chame-o sem parâmetros para ver uma lista e, em seguida, chame-o com “-d” para executar a exclusão real ou “-D” para todas as ramificações que não estejam totalmente mescladas, mas que você deseja excluir de qualquer maneira.

Tente isso no git bash, para buscar e remover referências para as ramificações excluídas e, em seguida, apague as ramificações locais que estavam acompanhando as removidas:

 git fetch -p && git branch -d `git branch -vv | grep ': gone]' | awk '{print $1}' | xargs` 

Lembre-se de verificar primeiro uma ramificação que não será excluída, para que não bloqueie a exclusão da ramificação.

Você pode usar este comando:

 git branch --merged master | grep -v "\* master" | xargs -n 1 git branch -d 

Git Clean: Excluir ramificações já mescladas, incluindo quebra de comando

A versão Powershell do git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d

git branch --merged master | %{ if($_ -notmatch '\*.*master'){ git branch -d "$($_.Trim())" }}

Isso removerá todas as ramificações locais que foram mescladas no mestre, enquanto você estiver na ramificação principal .

git checkout master para alternar.

Exclua qualquer ramo que não esteja atualizado com o mestre

 git co master && git branch | sed s/\*/\ / | xargs git branch -d 2> /dev/null 

Se você está removendo do seu computador local , aqui está o meu caminho direto :

Basta ir para: C:\Repo\your-project\.git\refs\heads

Cada filial é um arquivo criado sob esta pasta, basta remover os arquivos que correspondem aos nomes das suas filiais

É difícil encontrar um método no Windows, estou usando o sourcetree e não quero excluir um por um. Acabei de descobrir isso e me salvou no meu Windows.

Tenho certeza de que git remote prune origin é o que você deseja.

Você pode executá-lo como git remote prune origin --dry-run para ver o que faria sem fazer qualquer alteração.

Usando a GUI? Procedimento manual, mas rápido e fácil.

 $ git gui 

Selecione “Filial -> Excluir”. Você pode selecionar vários ramos com o botão Ctrl pressionado (windows) e remover todos eles.