Limpando galhos remotos antigos do git

694

Trabalho em dois computadores diferentes (A e B) e armazeno um controle remoto comum do git no diretório dropbox.

Digamos que eu tenha dois ramos, mestre e desenvolvimento. Ambos estão rastreando suas origens / mestre e origem / desenvolvimento de suas contrapartes remotas.

Agora, enquanto estiver no computador A, excluo o branch devel, no local e no remoto.

git push origin :heads/devel
git branch -d devel

Executando git branch -ano computador A, recebo a seguinte lista de ramificações.

  • mestre
  • origem / CABEÇA
  • origem / mestre

Executando git fetchno computador B, posso remover o ramo de desenvolvimento local com git branch -d devel, mas não consigo remover o ramo de desenvolvimento remoto.

git push origin :heads/devel retorna as seguintes mensagens de erro.

erro: não é possível enviar por push para um destino não qualificado: heads / proxy3d
O refspec de destino não corresponde a uma ref existente no controle remoto nem começa com refs /, e não podemos adivinhar um prefixo com base na ref de origem.
fatal: A extremidade remota desligou inesperadamente

git branch -a ainda lista origem / desenvolvimento nos ramos remotos.

Como posso limpar as ramificações remotas do computador B?

Jayesh
fonte
4
Alguém me disse que os repositórios git nas pastas do Dropbox são um pouco frágeis (mas sem detalhes adicionais).
Thorbjørn Ravn Andersen
5
@ ThorbjørnRavnAndersen provavelmente porque você precisa esperar para garantir a sincronização completa sempre que se comprometer, antes de ter certeza de que é seguro usá-lo em outra máquina (e outra sincronização necessária ainda).
ataulm

Respostas:

1239

Primeiro, qual é o resultado da git branch -amáquina B?

Segundo, você já tiver eliminado heads/develem origin, então é por isso que você não pode excluí-lo da máquina B.

Tentar

git branch -r -d origin/devel

ou

git remote prune origin

ou

git fetch origin --prune

e sinta-se à vontade para adicionar --dry-runao final da sua gitdeclaração o resultado de executá-lo sem executá-lo.

Documentos para git remote prunee git branch.

Jakub Narębski
fonte
50
git remote prune origintrabalhou para mim => * [pruned] origin/my-old-branch
Hari Karam Singh
126
git remote prune origin --dry-runmostra o que seria excluído sem realmente fazer isso.
Wolfram Arnold 28/05
30
git fetch origin --prunefoi perfeito para remover ramos excluídos
Sébastien Barbieri
10
Se você tiver uma filial local rastreando um controle remoto que não está mais funcionando, isso não excluirá nada. Para aqueles, parece git branch -vvseguido git branch -D branchnamee finalmente a ameixa é o melhor caminho.
Roman Starkov 31/03
7
Você pode configurar a poda acontecer automaticamente no pull / buscar definindo a seguinte opção:git config remote.origin.prune true
Patrick James McDougle
99

Considere executar:

git fetch --prune

Regularmente em cada repositório para remover ramificações locais que rastrearam uma ramificação remota que foi excluída (não existe mais no repositório GIT remoto).

Isso pode ser simplificado ainda mais por

git config remote.origin.prune true

essa é uma per-repoconfiguração que fará com que qualquer futuro git fetch or git pullseja removido automaticamente .

Para configurar isso para o seu usuário, você também pode editar o .gitconfig global e adicionar

[fetch]
    prune = true

No entanto, é recomendável que isso seja feito usando o seguinte comando:

git config --global fetch.prune true

ou aplicá-lo em todo o sistema (não apenas para o usuário)

git config --system fetch.prune true
Arif
fonte
14

Aqui está o script bash que pode fazer isso por você. É a versão modificada do script http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git . Minha modificação permite suportar diferentes locais remotos.

#!/bin/bash

current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
  echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching merged branches...\n"

git remote update --prune
remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
  echo "No existing branches have been merged into $current_branch."
else
  echo "This will remove the following branches:"
  if [ -n "$remote_branches" ]; then
echo "$remote_branches"
  fi
  if [ -n "$local_branches" ]; then
echo "$local_branches"
  fi
  read -p "Continue? (y/n): " -n 1 choice
  echo
  if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
    remotes=`echo "$remote_branches" | sed 's/\(.*\)\/\(.*\)/\1/g' | sort -u`
# Remove remote branches
for remote in $remotes
do
        branches=`echo "$remote_branches" | grep "$remote/" | sed 's/\(.*\)\/\(.*\)/:\2 /g' | tr -d '\n'`
        git push $remote $branches 
done

# Remove local branches
git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
  else
echo "No branches removed."
  fi
fi
Alex Amiryan
fonte
1
Isso quebrou em um ramo chamado "origem / recurso / mybranch", não sei por que.
Stavros Korokithakis
O problema está nos dois seds. Substituir sed 's/\(.*\)\/\(.*\)/\1/g'porsed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoît Latinier
14

Este comando "executar a seco" excluirá todas as originramificações remotas ( ) mescladas, além de master. Você pode alterar isso ou adicionar ramificações adicionais após o mestre:grep -v for-example-your-branch-here |

git branch -r --merged | 
  grep origin | 
  grep -v '>' | 
  grep -v master | 
  xargs -L1 | 
  awk '{sub(/origin\//,"");print}'| 
  xargs git push origin --delete --dry-run

Se parecer bom, remova o --dry-run. Além disso, você pode testar isso primeiro em um garfo.

weston
fonte
Agradável. Meu tweak usando perl em vez do primeiro xargs + awk: git branch -r --merged | origem grep | grep -v '>' | grep -v master | perl -lpe '($ lixo, $ _) = divisão (/ \ //, $ _, 2)' | xargs git push origem --delete
Andrew
6

Se git branch -rmostrar muitas ramificações de rastreamento remoto nas quais você não está interessado e deseja removê-las apenas da local, use o seguinte comando:

git branch -r | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Uma versão mais segura seria remover apenas as versões mescladas:

git branch -r --merged | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Isso pode ser útil para projetos grandes, nos quais você não precisa das ramificações de recursos de outros colegas de equipe, mas há muitas ramificações de rastreamento remoto buscadas no clone inicial.

No entanto, essa etapa por si só não é suficiente, porque as ramificações de rastreamento remoto excluídas retornariam a seguir git fetch.

Para parar de buscar essas ramificações de rastreamento remoto, você precisa especificar explicitamente os refs para buscar em .git / config :

[remote "origin"]
  # fetch = +refs/heads/*:refs/remotes/origin/*    ### don't fetch everything
  fetch = +refs/heads/master:refs/remotes/origin/master
  fetch = +refs/heads/develop:refs/remotes/origin/develop
  fetch = +refs/heads/release/*:refs/remotes/origin/release/*

No exemplo acima, nós só buscar master, develope liberar ramos, sinta-se livre para se adaptar como você precisa.

ryenus
fonte
1
Obrigado, o primeiro comando funcionou para mim. Você também pode buscar apenas uma ramificação git fetch origin branchnameou criar um alias, como ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"buscar apenas a ramificação atual (o meu favorito). Felicidades.
GiovanyMoreno
Talvez OT, mas o que significa a -rbandeira? Eu vejo que xargstem uma -Rdiscussão, mas não encontrei nada -r. Quero dizer, em teoria, se me lembro corretamente como xargsfunciona, mesmo sem -rele deve funcionar.
Aldo 'xoen' Giambelluca 11/01/19
Eu gosto desta resposta. Algumas notas (afirmando o óbvio realmente). É possível "visualizar" quais ramificações serão excluídas removendo o último canal e o último comando | xargs git branch -d. Além disso, removendo a -ropção ( --remotes) de git branch -dapenas limpamos as ramificações locais (o que pode ser suficiente, considerando que, por padrão git branch, não mostra ramificações remotas).
Aldo 'xoen' Giambelluca 11/01/19
Obrigado! Era exatamente isso que eu precisava. Outras soluções sugerem enviar ramificações locais removidas para o controle remoto para removê-las também, mas isso não ajuda quando o controle remoto foi removido ou não existe mais. Essa abordagem removeu as referências locais às ramificações remotas às quais não tenho mais acesso.
cautionbug 16/09/19
@ aldo, sobre xargs -r, a saber --no-run-if-empty, é uma extensão GNU, aqui está uma boa explicação .
ryenus
4

A exclusão é sempre uma tarefa desafiadora e pode ser perigosa !!! Portanto, primeiro execute o seguinte comando para ver o que acontecerá:

git push --all --prune --dry-run

Ao fazer o procedimento acima, gitvocê fornecerá uma lista do que aconteceria se o comando abaixo fosse executado.

Em seguida, execute o seguinte comando para remover todas as ramificações do repositório remoto que não estão no repositório local:

git push --all --prune
Timothy LJ Stewart
fonte
10
Este comando parece ser perigoso ... Ele conseguiu excluir o que eu queria (e não podia fazer com pelo menos quatro das respostas acima). Mas também excluiu outros quatro dev-branches. Git absolutamente é uma porcaria ...
jww 30/09/16
2
Esses ramos não devem estar no seu local. No entanto, nem tudo está perdido. Git commit, Git reflog e git reset --hard <checksum>. Você pode literalmente fazer qualquer commit (também conhecido como save) e outros com isso. A ramificação é apenas um rótulo. A exclusão do rótulo não exclui o salvamento ... ele sempre terá uma soma de verificação. Deixe-me saber se eu posso ajudar
Timothy LJ Stewart
3
Obviamente, você desejará recuperá-los rapidamente, uma vez que o coletor de lixo do git acabará por remover confirmações não referenciadas por ramos.
Andrew
1
É bom adicionar -n(execução a seco) a este comando para que você possa visualizar as alterações e, se estiver tudo bem, chame-o novamente sem -n.
mati865
1
Concorde com @GuiWeinmann - Isso é muito perigoso, especialmente sem uma frase de destaque específica para pelo menos executá-la primeiro a seco.
Vivek M. Chawla
2

Aqui está como fazer isso com o SourceTree (v2.3.1):
1. Clique em Buscar
2. Marque "Remover ramos de rastreamento ..."
3. Pressione OK
4. 😀

insira a descrição da imagem aqui

coco
fonte
1

Vou ter que adicionar uma resposta aqui, porque as outras respostas não estão cobrindo meu caso ou são desnecessariamente complicadas. Eu uso o github com outros desenvolvedores e só quero que todas as ramificações locais cujos controles remotos foram (possivelmente mesclados e) excluídos de um PR do github sejam excluídos de uma só vez da minha máquina. Não, coisas como git branch -r --mergednão abrangem os ramos que não foram mesclados localmente ou os que não foram mesclados (abandonados) etc., portanto, é necessária uma solução diferente.

Enfim, o primeiro passo que recebi de outras respostas:

git fetch --prune

Uma execução seca git remote prune originparecia fazer a mesma coisa no meu caso, então fui com a versão mais curta para simplificar.

Agora, a git branch -vdeve marcar os ramos cujos controles remotos são excluídos como [gone]. Portanto, tudo o que preciso fazer é:

git branch -v|grep \\[gone\\]|awk '{print $1}'|xargs -I{} git branch -D {}

Tão simples como isso, exclui tudo o que desejo para o cenário acima.

A xargssintaxe menos comum é que ele também funciona em Mac e BSD, além do Linux. Cuidado, esse comando não é executado a seco, portanto, forçará a exclusão de todos os ramos marcados como [gone]. Obviamente, sendo esse git, nada se foi para sempre, se você ver os ramos excluídos que você lembra que queria manter, sempre poderá desfazê-los (o comando acima terá listado seu hash na exclusão, portanto, é simples git checkout -b <branch> <hash>.

Equador
fonte
0
# First use prune --dry-run to filter+delete the local branches
git remote prune origin --dry-run \
  | grep origin/ \
  | sed 's,.*origin/,,g' \
  | xargs git branch -D

# Second delete the remote refs without --dry-run
git remote prune origin

Podar as mesmas ramificações de referências locais e remotas (no meu exemplo de origin).

Jan Winter
fonte